001    package net.sf.cpsolver.ifs.solution;
002    
003    import java.util.*;
004    
005    import net.sf.cpsolver.ifs.model.*;
006    import net.sf.cpsolver.ifs.perturbations.*;
007    import net.sf.cpsolver.ifs.solver.*;
008    import net.sf.cpsolver.ifs.util.*;
009    
010    /**
011     * Generic solution.
012     * <br><br>
013     * It consist from the model and information about current iteration and solution time.
014     * 
015     * @see Model
016     * @see net.sf.cpsolver.ifs.solver.Solver
017     *
018     * @version
019     * IFS 1.1 (Iterative Forward Search)<br>
020     * Copyright (C) 2006 Tomáš Müller<br>
021     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
022     * Lazenska 391, 76314 Zlin, Czech Republic<br>
023     * <br>
024     * This library is free software; you can redistribute it and/or
025     * modify it under the terms of the GNU Lesser General Public
026     * License as published by the Free Software Foundation; either
027     * version 2.1 of the License, or (at your option) any later version.
028     * <br><br>
029     * This library is distributed in the hope that it will be useful,
030     * but WITHOUT ANY WARRANTY; without even the implied warranty of
031     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
032     * Lesser General Public License for more details.
033     * <br><br>
034     * You should have received a copy of the GNU Lesser General Public
035     * License along with this library; if not, write to the Free Software
036     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
037     */
038    
039    public class Solution {
040        private static java.text.DecimalFormat sTimeFormat = new java.text.DecimalFormat("0.00",new java.text.DecimalFormatSymbols(Locale.US));
041        
042        private Model iModel;
043        private long iIteration = 0;
044        private double iTime = 0.0;
045        
046        private boolean iBestComplete = false;
047        private Hashtable iBestInfo = null;
048        private long iBestIteration = -1;
049        private double iBestTime = -1;
050        private double iBestPerturbationsPenaly = -1.0;
051        private double iBestValue = 0;
052    
053        private Vector iSolutionListeners = new FastVector();
054        private PerturbationsCounter iPerturbationsCounter = null;
055    
056        /** Constructor */
057        public Solution(Model model) {
058            this(model, 0, 0.0);
059        }
060    
061        /** Constructor */
062        public Solution(Model model, long iteration, double time) {
063            iModel =  model;
064            iIteration = iteration;
065            iTime = time;
066        }
067        
068        /** Current iteration */
069        public long getIteration() {
070            return iIteration;
071        }
072        
073        /** The model associated with the solution */
074        public Model getModel() {
075            return iModel;
076        }
077        
078        /** Current solution time (time in seconds from the start of the solver) */
079        public double getTime() {
080            return iTime;
081        }
082        
083        /** Update time, increment current iteration */
084        public void update(double time) { 
085            iTime = time; iIteration++;
086            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
087                ((SolutionListener)i.nextElement()).solutionUpdated(this);
088        }
089        
090        /** Initialization */
091        public void init(Solver solver) { 
092            iIteration=0; 
093            iTime=0;
094            if (iModel!=null) iModel.init(solver);
095            iPerturbationsCounter = solver.getPerturbationsCounter();
096        }
097        
098        public String toString() {
099            return "Solution{\n  model="+iModel+",\n  iteration="+iIteration+",\n  time="+iTime+"\n}";
100        }
101        
102        /** Solution information. It consits from info from the model which is associated with the solution, 
103         * time, iteration, speed and infos from all solution listeners.
104         */
105        public Hashtable getInfo() {
106            Hashtable ret=getModel().getInfo();
107            if (getPerturbationsCounter()!=null) getPerturbationsCounter().getInfo(ret,getModel());
108            ret.put("Time",sTimeFormat.format(getTime())+" sec");
109            ret.put("Iteration",String.valueOf(getIteration()));
110            if (getTime()>0) ret.put("Speed",sTimeFormat.format((getIteration())/(double)getTime())+" it/s");
111            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
112                ((SolutionListener)i.nextElement()).getInfo(this, ret);
113            return ret;
114        }
115        
116        /**
117         * Extended solution information. 
118         * Similar to {@link Solution#getInfo()}, but some more information (that is more expensive to compute) might be added.
119         * Also extended model information is added (see {@link Model#getExtendedInfo()}) into the resultant table. 
120         */
121        public Hashtable getExtendedInfo() {
122            Hashtable ret=getModel().getExtendedInfo();
123            if (getPerturbationsCounter()!=null) getPerturbationsCounter().getInfo(ret,getModel());
124            ret.put("Time",sTimeFormat.format(getTime())+" sec");
125            ret.put("Iteration",String.valueOf(getIteration()));
126            if (getTime()>0) ret.put("Speed",sTimeFormat.format((getIteration())/(double)getTime())+" it/s");
127            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
128                ((SolutionListener)i.nextElement()).getInfo(this, ret);
129            return ret;
130        }
131        
132        /** Solution information. It consists from info from the model which is associated with the solution, 
133         * time, iteration, speed and infos from all solution listeners. Only variables from the given set
134         * are included.
135         */
136        public Hashtable getInfo(Vector variables) {
137            Hashtable ret=getModel().getInfo(variables);
138            if (getPerturbationsCounter()!=null) getPerturbationsCounter().getInfo(ret,getModel(),variables);
139            ret.put("Time",sTimeFormat.format(getTime())+" sec");
140            ret.put("Iteration",String.valueOf(getIteration()));
141            if (getTime()>0) ret.put("Speed",sTimeFormat.format((getIteration())/(double)getTime())+" it/s");
142            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
143                ((SolutionListener)i.nextElement()).getInfo(this, ret, variables);
144            return ret;
145        }
146        
147        /** Info of the best ever found solution */
148        public Hashtable getBestInfo() { return iBestInfo; }
149        /** Iteration when the best ever found solution was found */
150        public long getBestIteration() { return (iBestIteration<0?getIteration():iBestIteration); }
151        /** Solution time when the best ever found solution was found */
152        public double getBestTime() { return (iBestTime<0?getTime():iBestTime); }
153        /** Returns true, if all variables of the best ever solution found are assigned */
154        public boolean isBestComplete() { return iBestComplete; }
155        /** Total value of the best ever found solution -- sum of all assigned values (see {@link Value#toDouble()}).*/
156        public double getBestValue() { return iBestValue; }
157        /** Set total value of the best ever found solution */
158        public void setBestValue(double bestValue) { iBestValue = bestValue; }
159        /** Perturbation penalty of the best ever found solution (see {@link PerturbationsCounter}) */
160        public double getBestPerturbationsPenalty() { return iBestPerturbationsPenaly; }
161        
162        /** Returns perturbation counter */
163        public PerturbationsCounter getPerturbationsCounter() { return iPerturbationsCounter; }
164        
165        /** Clear the best ever found solution */
166        public void clearBest() {
167            getModel().clearBest();
168            iBestInfo = null;
169            iBestTime = -1;
170            iBestIteration = -1;
171            iBestComplete = false;
172            iBestValue = 0;
173            iBestPerturbationsPenaly = -1.0;
174            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
175                ((SolutionListener)i.nextElement()).bestCleared(this);
176        }
177        
178        /** Save the current solution as the best ever found solution (it also calls {@link Model#saveBest()}) */
179        public void saveBest() {
180            getModel().saveBest();
181            iBestInfo = getInfo();
182            iBestTime = getTime();
183            iBestIteration = getIteration();
184            iBestComplete = getModel().nrUnassignedVariables()==0;
185            iBestValue = getModel().getTotalValue();
186            iBestPerturbationsPenaly = (iPerturbationsCounter==null?0.0:iPerturbationsCounter.getPerturbationPenalty(getModel()));
187            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
188                ((SolutionListener)i.nextElement()).bestSaved(this);
189        }
190        
191        /** Restore the best ever found solution into the current solution (it also calls {@link Model#restoreBest()})*/
192        public void restoreBest() {
193            if (iBestInfo==null) return;
194            getModel().restoreBest();
195            iTime = iBestTime;
196            iIteration = iBestIteration;
197            for (Enumeration i=iSolutionListeners.elements();i.hasMoreElements();)
198                ((SolutionListener)i.nextElement()).bestRestored(this);
199        }
200    
201        /** Adds solution listner */
202        public void addSolutionListener(SolutionListener listener) {
203            iSolutionListeners.addElement(listener);
204        }
205        /** Removes solution listener */
206        public void removeSolutionListener(SolutionListener listener) {
207            iSolutionListeners.removeElement(listener);
208        }
209    }