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 }