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 variable selection criterion.
014     * <br><br>
015     * In case that all variables are assigned, one of the variables is selected randomly. In case of MPP, 
016     * the random selection is made among the variables which have not assigned initial values.
017     * <br><br>
018     * When there are unassigned variables, a variable is selected randomly among all 
019     * unassigned variables (when Variable.RandomSelection is true) or the following roulette 
020     * wheel selection takes place (MPP):<ul>
021     * <li> one point for a variable with no initial assignment
022     * <li> 3 * ( 1 + number of conflicts with the initial assignment) for a variable with an initial assignment
023     * </ul>
024     * <br>
025     * If {@link MacPropagation} is used and Variable.UnassignWhenNoGood parameter is true, while
026     * there is a variable with an empty domain: <ul>
027     * <li> with Variable.UnassignWhenNoGoodRandomWalk probabilty an arbitrary assigned variable is selected
028     * <li> otherwise, one variable with empty domain is picked, one of its original values is picked and 
029     * one of the variables from the explanation of that value is then returned. If the explanation is 
030     * empty, another variable and value is tried (up to ten times).
031     * </ul>
032     * <br>
033     * Parameters:
034     * <br>
035     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
036     * <tr><td>Variable.RandomSelection</td><td>{@link Boolean}</td><td>if true, an unassigned variable is picked randomly</td></tr>
037     * <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>
038     * <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>
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    public class GeneralVariableSelection implements VariableSelection {
065        private boolean iUnassignWhenNotGood = false;
066        private double iUnassignWhenNotGoodRandWalk = 0.02;
067        private boolean iRandomSelection = true;
068        
069        private MacPropagation iProp = null;
070        
071        /** Constructor
072         * @param properties input configuration
073         */
074        public GeneralVariableSelection(DataProperties properties) {
075            iUnassignWhenNotGood = properties.getPropertyBoolean("Variable.UnassignWhenNoGood", iUnassignWhenNotGood);
076            iUnassignWhenNotGoodRandWalk = properties.getPropertyDouble("Variable.UnassignWhenNoGoodRandomWalk", iUnassignWhenNotGoodRandWalk);
077            iRandomSelection = properties.getPropertyBoolean("Variable.RandomSelection", iRandomSelection);
078        }
079        
080        public GeneralVariableSelection() {
081        }
082    
083        /** Initialization */
084        public void init(Solver solver) {
085            for (Enumeration i = solver.getExtensions().elements(); i.hasMoreElements(); ) {
086                Extension extension = (Extension)i.nextElement();
087                if (extension instanceof MacPropagation) iProp = (MacPropagation)extension;
088            }
089        }
090    
091        /** Variable selection */
092        public Variable selectVariable(Solution solution) {
093            if (solution.getModel().nrUnassignedVariables()==0) {
094                if (!solution.getModel().perturbVariables().isEmpty())
095                    return (Variable)ToolBox.random(solution.getModel().perturbVariables());
096                else
097                    return (Variable)ToolBox.random(solution.getModel().assignedVariables());
098            } else {
099                if (iProp != null && iUnassignWhenNotGood) {
100                    Vector noGoodVariables = new FastVector();
101                    for (Enumeration i1 = solution.getModel().unassignedVariables().elements(); i1.hasMoreElements();) {
102                        Variable variable = (Variable)i1.nextElement();
103                        if (iProp.goodValues(variable).isEmpty())
104                            noGoodVariables.addElement(variable);
105                    }
106                    if (!noGoodVariables.isEmpty()) {
107                        if (ToolBox.random() < iUnassignWhenNotGoodRandWalk)
108                            return (Variable)ToolBox.random(solution.getModel().assignedVariables());
109                        for (int attempt = 0; attempt < 10; attempt++) {
110                            Variable noGoodVariable = (Variable)ToolBox.random(noGoodVariables);
111                            Value noGoodValue = (Value)ToolBox.random(noGoodVariable.values());
112                            Set noGood = iProp.noGood(noGoodValue);
113                            if (noGood!=null && !noGood.isEmpty())
114                                return ((Value)ToolBox.random(noGood)).variable();
115                        }
116                    }
117                }
118                if (iRandomSelection)
119                    return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
120                Vector points = new FastVector();
121                int totalPoints = 0;
122                for (Enumeration i = solution.getModel().unassignedVariables().elements(); i.hasMoreElements(); ) {
123                    Variable variable = (Variable)i.nextElement();
124                    int pointsThisVariable = (variable.getInitialAssignment()!=null ? 3*(1+solution.getModel().conflictValues(variable.getInitialAssignment()).size()):1);
125                    totalPoints += pointsThisVariable;
126                    points.addElement(new Integer(totalPoints));
127                }
128                int rndPoints = ToolBox.random(totalPoints);
129                Enumeration x = solution.getModel().unassignedVariables().elements();
130                for (int i = 0; x.hasMoreElements() && i < points.size(); i++) {
131                    Variable variable = (Variable)x.nextElement();
132                    int tp = ((Integer)points.elementAt(i)).intValue();
133                    if (tp > rndPoints) return variable;
134                }
135                return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
136            }
137        }
138        
139    }