001 package ifs.heuristics;
002
003 import ifs.extension.*;
004 import ifs.model.*;
005 import ifs.solution.*;
006 import ifs.solver.*;
007 import ifs.util.*;
008
009 import java.util.*;
010
011 /**
012 * General implementation of variable selection criterion.
013 * <br><br>
014 * In case that all variables are assigned, one of the variables is selected randomly. In case of MPP,
015 * the random selection is made among the variables which have not assigned initial values.
016 * <br><br>
017 * When there are unassigned variables, a variable is selected randomly among all
018 * unassigned variables (when Variable.RandomSelection is true) or the following roulette
019 * wheel selection takes place (MPP):<ul>
020 * <li> one point for a variable with no initial assignment
021 * <li> 3 * ( 1 + number of conflicts with the initial assignment) for a variable with an initial assignment
022 * </ul>
023 * <br>
024 * If {@link MacPropagation} is used and Variable.UnassignWhenNoGood parameter is true, while
025 * there is a variable with an empty domain: <ul>
026 * <li> with Variable.UnassignWhenNoGoodRandomWalk probabilty an arbitrary assigned variable is selected
027 * <li> otherwise, one variable with empty domain is picked, one of its original values is picked and
028 * one of the variables from the explanation of that value is then returned. If the explanation is
029 * empty, another variable and value is tried (up to ten times).
030 * </ul>
031 * <br>
032 * Parameters:
033 * <br>
034 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
035 * <tr><td>Variable.RandomSelection</td><td>{@link Boolean}</td><td>if true, an unassigned variable is picked randomly</td></tr>
036 * <tr><td>Variable.UnassignWhenNoGood</td><td>{@link Boolean}</td><td>if true and if {@link MacPropagation} is used: if there is a variable with empty domain, assigned variable (which is present in some explanation for a vairable with empty domain) is selected (for reassignment)</td></tr>
037 * <tr><td>Variable.UnassignWhenNoGoodRandomWalk</td><td>{@link Double}</td><td>if Variable.UnassignWhenNoGood is true and if {@link MacPropagation} is used: if there is a variable with empty domain, with the given probability an arbitrary assigned variable is selected</td></tr>
038 * </table>
039 *
040 * @see VariableSelection
041 * @see Solver
042 *
043 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
044 * @version 1.0
045 **/
046 public class GeneralVariableSelection implements VariableSelection {
047 private boolean iUnassignWhenNotGood = false;
048 private double iUnassignWhenNotGoodRandWalk = 0.02;
049 private boolean iRandomSelection = true;
050
051 private boolean iMPP = false;
052 private MacPropagation iProp = null;
053
054 /** Constructor
055 * @param properties input configuration
056 */
057 public GeneralVariableSelection(DataProperties properties) {
058 iUnassignWhenNotGood = properties.getPropertyBoolean("Variable.UnassignWhenNoGood", iUnassignWhenNotGood);
059 iUnassignWhenNotGoodRandWalk = properties.getPropertyDouble("Variable.UnassignWhenNoGoodRandomWalk", iUnassignWhenNotGoodRandWalk);
060 iRandomSelection = properties.getPropertyBoolean("Variable.RandomSelection", iRandomSelection);
061 }
062
063 public GeneralVariableSelection() {
064 }
065
066 /** Initialization */
067 public void init(Solver solver) {
068 for (Enumeration i = solver.getExtensions().elements(); i.hasMoreElements(); ) {
069 Extension extension = (Extension)i.nextElement();
070 if (extension instanceof MacPropagation) iProp = (MacPropagation)extension;
071 }
072 }
073
074 /** Variable selection */
075 public Variable selectVariable(Solution solution) {
076 if (solution.getModel().unassignedVariables().isEmpty()) {
077 if (!solution.getModel().perturbVariables().isEmpty())
078 return (Variable)ToolBox.random(solution.getModel().perturbVariables());
079 else
080 return (Variable)ToolBox.random(solution.getModel().assignedVariables());
081 } else {
082 if (iProp != null && iUnassignWhenNotGood) {
083 Vector noGoodVariables = new FastVector();
084 for (Enumeration i1 = solution.getModel().unassignedVariables().elements(); i1.hasMoreElements();) {
085 Variable variable = (Variable)i1.nextElement();
086 if (iProp.goodValues(variable).isEmpty())
087 noGoodVariables.addElement(variable);
088 }
089 if (!noGoodVariables.isEmpty()) {
090 if (ToolBox.random() < iUnassignWhenNotGoodRandWalk)
091 return (Variable)ToolBox.random(solution.getModel().assignedVariables());
092 for (int attempt = 0; attempt < 10; attempt++) {
093 Variable noGoodVariable = (Variable)ToolBox.random(noGoodVariables);
094 Value noGoodValue = (Value)ToolBox.random(noGoodVariable.values());
095 Set noGood = iProp.noGood(noGoodValue);
096 if (noGood!=null && !noGood.isEmpty())
097 return ((Value)ToolBox.random(noGood)).variable();
098 }
099 }
100 }
101 if (iRandomSelection)
102 return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
103 Vector points = new FastVector();
104 int totalPoints = 0;
105 for (Enumeration i = solution.getModel().unassignedVariables().elements(); i.hasMoreElements(); ) {
106 Variable variable = (Variable)i.nextElement();
107 int pointsThisVariable = (variable.getInitialAssignment()!=null ? 3*(1+solution.getModel().conflictValues(variable.getInitialAssignment()).size()):1);
108 totalPoints += pointsThisVariable;
109 points.addElement(new Integer(totalPoints));
110 }
111 int rndPoints = ToolBox.random(totalPoints);
112 Enumeration x = solution.getModel().unassignedVariables().elements();
113 for (int i = 0; x.hasMoreElements() && i < points.size(); i++) {
114 Variable variable = (Variable)x.nextElement();
115 int tp = ((Integer)points.elementAt(i)).intValue();
116 if (tp > rndPoints) return variable;
117 }
118 return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
119 }
120 }
121
122 }