001    package ifs.solution;
002    
003    import ifs.model.*;
004    import ifs.solver.*;
005    import ifs.util.*;
006    import ifs.perturbations.*;
007    import java.util.*;
008    
009    /**
010     * Generic solution.
011     * <br><br>
012     * It consist from the model and information about current iteration and solution time.
013     * 
014     * @see Model
015     * @see ifs.solver.Solver
016     *
017     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
018     * @version 1.0
019     */
020    
021    public class Solution {
022        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Solution.class);
023        private static java.text.DecimalFormat sTimeFormat = new java.text.DecimalFormat("0.00",new java.text.DecimalFormatSymbols(Locale.US));
024        
025        private Model iModel;
026        private long iIteration = 0;
027        private double iTime = 0.0;
028        
029        private boolean iBestComplete = false;
030        private Hashtable iBestInfo = null;
031        private long iBestIteration = -1;
032        private double iBestTime = -1;
033        private double iBestPerturbationsPenaly = -1.0;
034        private int iBestValue = 0;
035        private int iBestPertirbations = -1;
036        
037        private Vector iSolutionListeners = new FastVector();
038        private PerturbationsCounter iPerturbationsCounter = null;
039    
040        /** Constructor */
041        public Solution(Model model) {
042            this(model, 0, 0.0);
043        }
044    
045        /** Constructor */
046        public Solution(Model model, long iteration, double time) {
047            iModel =  model;
048            iIteration = iteration;
049            iTime = time;
050        }
051        
052        /** Current iteration */
053        public long getIteration() {
054            return iIteration;
055        }
056        
057        /** The model associated with the solution */
058        public Model getModel() {
059            return iModel;
060        }
061        
062        /** Current solution time (time in seconds from the start of the solver) */
063        public double getTime() {
064            return iTime;
065        }
066        
067        /** Update time, increment current iteration */
068        public void update(double time) { 
069            iTime = time; iIteration++;
070            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
071                ((SolutionListener)i.nextElement()).solutionUpdated(this);
072        }
073        
074        /** Initialization */
075        public void init(Solver solver) { 
076            iIteration=0; 
077            iTime=0;
078            if (iModel!=null) iModel.init(solver);
079            iPerturbationsCounter = solver.getPerturbationsCounter();
080        }
081        
082        public String toString() {
083            return "Solution{\n  model="+iModel+",\n  iteration="+iIteration+",\n  time="+iTime+"\n}";
084        }
085        
086        /** Solution information. It consits from info from the model which is associated with the solution, 
087         * time, iteration, speed and infos from all solution listeners.
088         */
089        public Hashtable getInfo() {
090            Hashtable ret=getModel().getInfo();
091            if (getPerturbationsCounter()!=null) getPerturbationsCounter().getInfo(ret,this);
092            ret.put("Time",sTimeFormat.format(getTime())+" sec");
093            ret.put("Iteration",String.valueOf(getIteration()));
094            if (getTime()>0) ret.put("Speed",sTimeFormat.format((getIteration())/(double)getTime())+" it/s");
095            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
096                ((SolutionListener)i.nextElement()).getInfo(this, ret);
097            return ret;
098        }
099        
100        /** Info of the best ever found solution */
101        public Hashtable getBestInfo() { return iBestInfo; }
102        /** Iteration when the best ever found solution was found */
103        public long getBestIteration() { return (iBestIteration<0?getIteration():iBestIteration); }
104        /** Solution time when the best ever found solution was found */
105        public double getBestTime() { return (iBestTime<0?getTime():iBestTime); }
106        /** Number of perturbation variables (variables with non-initial value assigned) if the best ever solution found */
107        public int getBestPertirbations() { return iBestPertirbations; }
108        /** Returns true, if all variables of the best ever solution found are assigned */
109        public boolean isBestComplete() { return iBestComplete; }
110        /** Total value of the best ever found solution -- sum of all assigned values (see {@link Value#toInt()}).*/
111        public int getBestValue() { return iBestValue; }
112        /** Perturbation penalty of the best ever found solution (see {@link PerturbationsCounter}) */
113        public double getBestPerturbationsPenalty() { return iBestPerturbationsPenaly; }
114        
115        /** Returns perturbation counter */
116        public PerturbationsCounter getPerturbationsCounter() { return iPerturbationsCounter; }
117        
118        /** Clear the best ever found solution */
119        public void clearBest() {
120            iBestInfo = null;
121            iBestTime = 0;
122            iBestIteration = 0;
123            iBestPertirbations = -1;
124            iBestComplete = false;
125            iBestValue = 0;
126            iBestPerturbationsPenaly = -1.0;
127            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
128                ((SolutionListener)i.nextElement()).bestCleared(this);
129        }
130        
131        /** Save the current solution as the best ever found solution (it also calls {@link Model#saveBest()}) */
132        public void saveBest() {
133            getModel().saveBest();
134            iBestInfo = getInfo();
135            iBestTime = getTime();
136            iBestIteration = getIteration();
137            iBestPertirbations = getModel().perturbVariables().size();
138            iBestComplete = getModel().unassignedVariables().isEmpty();
139            iBestValue = getModel().getTotalValue();
140            iBestPerturbationsPenaly = iPerturbationsCounter.getPerturbationPenalty(this);
141            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
142                ((SolutionListener)i.nextElement()).bestSaved(this);
143        }
144        
145        /** Restore the best ever found solution into the current solution (it also calls {@link Model#restoreBest()})*/
146        public void restoreBest() {
147            if (iBestInfo==null) return;
148            getModel().restoreBest();
149            iTime = iBestTime;
150            iIteration = iBestIteration;
151            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
152                ((SolutionListener)i.nextElement()).bestRestored(this);
153        }
154    
155        /** Adds solution listner */
156        public void addSolutionListener(SolutionListener listener) {
157            iSolutionListeners.addElement(listener);
158        }
159        /** Removes solution listener */
160        public void removeSolutionListener(SolutionListener listener) {
161            iSolutionListeners.removeElement(listener);
162        }
163    }