001 package net.sf.cpsolver.ifs.heuristics; 002 003 004 import java.util.*; 005 006 import net.sf.cpsolver.ifs.extension.*; 007 import net.sf.cpsolver.ifs.model.*; 008 import net.sf.cpsolver.ifs.solution.*; 009 import net.sf.cpsolver.ifs.solver.*; 010 import net.sf.cpsolver.ifs.util.*; 011 012 /** 013 * General implementation of value selection criterion. 014 * <br><br> 015 * Value selection criterion is based on weighted sum of various criteria. It also allows random walk technique and 016 * tabu search. 017 * <br> 018 * Parameters: 019 * <br> 020 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 021 * <tr><td>General.MPP</td><td>{@link Boolean}</td><td>if true, MPP is being solved</td></tr> 022 * <tr><td>Value.MPPLimit</td><td>{@link Integer}</td><td>MPP: limitation of the number of allowed perturbations. If a solution within this limit is gound, it is decreased.</td></tr> 023 * <tr><td>Value.InitialSelectionProb</td><td>{@link Double}</td><td>MPP: probability of selection of the initial value</td></tr> 024 * <tr><td>Value.RandomWalkProb</td><td>{@link Double}</td><td>Random Walk: probability of selection of a value randomly among all the values</td></tr> 025 * <tr><td>Value.Tabu</td><td>{@link Integer}</td><td>Tabu Search: length of the tabu-list</td></tr> 026 * <tr><td>Value.GoodSelectionProb</td><td>{@link Double}</td><td>In case of {@link MacPropagation}, with this probability (1.0 means always), the selection is made only among good values (not removed from the domain).</td></tr> 027 * </table> 028 * <br> 029 * Following weights are used in the weighted sum (computed for all values). The value with the lowest weighted sum is selected. 030 * If there are more than one of such values, one of them is selected randomly. 031 * <br> 032 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 033 * <tr><td>Value.WeightDeltaInitialAssignments</td><td>{@link Double}</td><td>MPP: Difference in the number of assigned initial values if the value is assigned to the variable (weighted by this Value.WeightDeltaInitialAssignments): -1 if the value is initial, 0 otherwise, increased by the number of initial values assigned to variables with hard conflicts with the value</td></tr> 034 * <tr><td>Value.WeightWeightedConflicts</td><td>{@link Double}</td><td>When {@link ConflictStatistics} is used: weighted number of conflicting variables</td></tr> 035 * <tr><td>Value.WeightPotentialConflicts</td><td>{@link Double}</td><td>When {@link ConflictStatistics} is used: weighted number of potentially conflicting variables</td></tr> 036 * <tr><td>Value.WeightConflicts</td><td>{@link Double}</td><td>Number of conflicting variables {@link Model#conflictValues(Value)}.</td></tr> 037 * <tr><td>Value.WeightNrAssignments</td><td>{@link Double}</td><td>Number of previous assignments of the value</td></tr> 038 * <tr><td>Value.WeightValue</td><td>{@link Double}</td><td>Value {@link Value#toDouble()}</td></tr> 039 * </table> 040 * 041 * @see VariableSelection 042 * @see Solver 043 * 044 * @version 045 * IFS 1.1 (Iterative Forward Search)<br> 046 * Copyright (C) 2006 Tomáš Müller<br> 047 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 048 * Lazenska 391, 76314 Zlin, Czech Republic<br> 049 * <br> 050 * This library is free software; you can redistribute it and/or 051 * modify it under the terms of the GNU Lesser General Public 052 * License as published by the Free Software Foundation; either 053 * version 2.1 of the License, or (at your option) any later version. 054 * <br><br> 055 * This library is distributed in the hope that it will be useful, 056 * but WITHOUT ANY WARRANTY; without even the implied warranty of 057 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 058 * Lesser General Public License for more details. 059 * <br><br> 060 * You should have received a copy of the GNU Lesser General Public 061 * License along with this library; if not, write to the Free Software 062 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 063 **/ 064 065 public class GeneralValueSelection implements ValueSelection { 066 private double iRandomWalkProb = 0.0; 067 private double iInitialSelectionProb = 0.0; 068 private double iGoodSelectionProb = 0.0; 069 private int iMPPLimit = -1; 070 071 private double iWeightDeltaInitialAssignment = 0.0; 072 private double iWeightPotentialConflicts = 0.0; 073 private double iWeightWeightedCoflicts = 0.0; 074 private double iWeightCoflicts = 1.0; 075 private double iWeightNrAssignments = 0.5; 076 private double iWeightValue = 0.0; 077 078 protected int iTabuSize = 0; 079 protected ArrayList iTabu = null; 080 protected int iTabuPos = 0; 081 082 private boolean iMPP = false; 083 private ConflictStatistics iStat = null; 084 private MacPropagation iProp = null; 085 private ViolatedInitials iViolatedInitials = null; 086 087 public GeneralValueSelection() {} 088 089 /** Constructor 090 * @param properties input configuration 091 */ 092 public GeneralValueSelection(DataProperties properties) { 093 iMPP = properties.getPropertyBoolean("General.MPP", false); 094 if (iMPP) { 095 iMPPLimit = properties.getPropertyInt("Value.MPPLimit", -1); 096 iInitialSelectionProb = properties.getPropertyDouble("Value.InitialSelectionProb", 0.75); 097 iWeightDeltaInitialAssignment = properties.getPropertyDouble("Value.WeightDeltaInitialAssignments", 0.0); 098 } 099 iGoodSelectionProb = properties.getPropertyDouble("Value.GoodSelectionProb", 0.00); 100 iWeightWeightedCoflicts = properties.getPropertyDouble("Value.WeightWeightedConflicts", 1.0); 101 iWeightPotentialConflicts = properties.getPropertyDouble("Value.WeightPotentialConflicts", 0.0); 102 103 iRandomWalkProb = properties.getPropertyDouble("Value.RandomWalkProb", 0.0); 104 iWeightCoflicts = properties.getPropertyDouble("Value.WeightConflicts", 1.0); 105 iWeightNrAssignments = properties.getPropertyDouble("Value.WeightNrAssignments", 0.5); 106 iWeightValue = properties.getPropertyDouble("Value.WeightValue", 0.0); 107 iTabuSize = properties.getPropertyInt("Value.Tabu", 0); 108 if (iTabuSize > 0) 109 iTabu = new ArrayList(iTabuSize); 110 } 111 112 /** Initialization */ 113 public void init(Solver solver) { 114 for (Enumeration i = solver.getExtensions().elements(); i.hasMoreElements();) { 115 Extension extension = (Extension)i.nextElement(); 116 if (extension instanceof ConflictStatistics) 117 iStat = (ConflictStatistics)extension; 118 if (extension instanceof MacPropagation) 119 iProp = (MacPropagation)extension; 120 if (extension instanceof ViolatedInitials) 121 iViolatedInitials = (ViolatedInitials)extension; 122 } 123 } 124 125 /** Value selecion */ 126 public Value selectValue(Solution solution, Variable selectedVariable) { 127 if (iMPP) { 128 if (selectedVariable.getInitialAssignment() != null) { 129 if (solution.getModel().nrUnassignedVariables()==0) { 130 if (solution.getModel().perturbVariables().size() <= iMPPLimit) 131 iMPPLimit = solution.getModel().perturbVariables().size() - 1; 132 } 133 if (iMPPLimit >= 0 && solution.getModel().perturbVariables().size() > iMPPLimit) 134 return selectedVariable.getInitialAssignment(); 135 if (selectedVariable.getInitialAssignment() != null && ToolBox.random() <= iInitialSelectionProb) 136 return selectedVariable.getInitialAssignment(); 137 } 138 } 139 140 Vector values = selectedVariable.values(); 141 if (ToolBox.random() <= iRandomWalkProb) return (Value)ToolBox.random(values); 142 if (iProp != null && selectedVariable.getAssignment() == null && ToolBox.random() <= iGoodSelectionProb) { 143 Collection goodValues = iProp.goodValues(selectedVariable); 144 if (!goodValues.isEmpty()) values = new FastVector(goodValues); 145 } 146 if (values.size() == 1) 147 return (Value)values.firstElement(); 148 149 Vector bestValues = null; 150 double bestWeightedSum = 0; 151 152 for (Enumeration i1 = values.elements(); i1.hasMoreElements();) { 153 Value value = (Value)i1.nextElement(); 154 if (iTabu != null && iTabu.contains(value)) continue; 155 if (selectedVariable.getAssignment() != null && selectedVariable.getAssignment().equals(value)) 156 continue; 157 158 Collection conf = solution.getModel().conflictValues(value); 159 if (conf.contains(value)) continue; 160 161 double weightedConflicts = (iStat == null || iWeightWeightedCoflicts == 0.0 ? 0.0 : iStat.countRemovals(solution.getIteration(), conf, value)); 162 double potentialConflicts = (iStat == null || iWeightPotentialConflicts == 0.0 ? 0.0 : iStat.countPotentialConflicts(solution.getIteration(), value, 3)); 163 164 long deltaInitialAssignments = 0; 165 if (iMPP && iWeightDeltaInitialAssignment != 0.0) { 166 if (iViolatedInitials != null) { 167 Set violations = iViolatedInitials.getViolatedInitials(value); 168 if (violations != null) { 169 for (Iterator it1 = violations.iterator(); it1.hasNext();) { 170 Value aValue = (Value)it1.next(); 171 if (aValue.variable().getAssignment() == null || aValue.variable().getAssignment().equals( aValue)) 172 deltaInitialAssignments += 2; 173 } 174 } 175 } 176 for (Iterator it1 = conf.iterator(); it1.hasNext();) { 177 Value aValue = (Value)it1.next(); 178 if (aValue.variable().getInitialAssignment() != null) 179 deltaInitialAssignments--; 180 } 181 if (selectedVariable.getInitialAssignment() != null && !selectedVariable.getInitialAssignment().equals(value)) { 182 deltaInitialAssignments++; 183 } 184 if (iMPPLimit >= 0 && (solution.getModel().perturbVariables().size() + deltaInitialAssignments) > iMPPLimit) 185 continue; 186 } 187 188 double weightedSum = 189 (iWeightDeltaInitialAssignment * deltaInitialAssignments) 190 + (iWeightPotentialConflicts * potentialConflicts) 191 + (iWeightWeightedCoflicts * weightedConflicts) 192 + (iWeightCoflicts * conf.size()) 193 + (iWeightNrAssignments * value.countAssignments()) 194 + (iWeightValue * value.toDouble()); 195 196 if (bestValues == null || bestWeightedSum > weightedSum) { 197 bestWeightedSum = weightedSum; 198 if (bestValues == null) bestValues = new FastVector(); 199 else bestValues.clear(); 200 bestValues.addElement(value); 201 } else { 202 if (bestWeightedSum == weightedSum) 203 bestValues.addElement(value); 204 } 205 } 206 207 Value selectedValue = (Value)(bestValues==null?null:ToolBox.random(bestValues)); 208 if (selectedValue == null) selectedValue = (Value)ToolBox.random(values); 209 if (iTabu != null) { 210 if (iTabu.size() == iTabuPos) 211 iTabu.add(selectedValue); 212 else 213 iTabu.set(iTabuPos, selectedValue); 214 iTabuPos = (iTabuPos + 1) % iTabuSize; 215 } 216 return (bestValues == null ? null : selectedValue); 217 } 218 219 }