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