001    package ifs.dbt;
002    
003    
004    import ifs.extension.*;
005    import ifs.heuristics.*;
006    import ifs.model.*;
007    import ifs.solution.*;
008    import ifs.solver.*;
009    import ifs.util.*;
010    import java.util.*;
011    
012    /**
013     * Selection of a value for dynamic backtracking.
014     * <br><br>
015     * <li>Returns null if all values of the selected variable are nogood.
016     * <li>Selected the best good value (according to the parameters) of the selected variable.
017     * <br><br>
018     * It is based on a weighted sum of several criteria.
019     * <br><br>
020     * This IFS solver value selection heuristics is to be used only in case of dynamic backtracking and it has the following parameters:
021     * <br>
022     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
023     * <tr><td>General.MPP</td><td>{@link Boolean}</td><td>Minimal Perturbation Problem</td></tr>
024     * <tr><td>Value.MPPLimit</td><td>{@link Integer}</td><td>Limit on the number of perturbations (only in case of MPP, i.e., when General.MPP=true). MPP limit is decreased when a complete solution is found. If set to -1, it is no used</td></tr>
025     * <tr><td>Value.InitialSelectionProb</td><td>{@link Double}</td><td>Probability of selection of initial value (only in case of MPP)</td></tr>
026     * <tr><td>Value.WeightDeltaInitialAssignments</td><td>{@link Double}</td><td>Weight of difference in the number of assignments of initial values in case of selection of the value(only in case of MPP)</td></tr>
027     * <tr><td>Value.RandomWalkProb</td><td>{@link Double}</td><td>Probability of random selection of a good value</td></tr>
028     * <tr><td>Value.WeightNrAssignments</td><td>{@link Double}</td><td>Weight of the number of previous assignments of the value</td></tr>
029     * <tr><td>Value.WeightValue</td><td>{@link Double}</td><td>Weight of the value itself (e.g., for minCSP)</td></tr>
030     * </table>
031     * <br>
032     *
033     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
034     * @version 1.0
035     */
036    public class DbtValueSelection implements ValueSelection {
037        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(GeneralValueSelection.class);
038        private double iRandomWalkProb = 0.0;
039        private double iInitialSelectionProb = 0.0;
040        private int    iMPPLimit = -1;
041        
042        private double iWeightDeltaInitialAssignment = 0.0;
043        private double iWeightNrAssignments = 0.5;
044        private double iWeightValue = 0.0;
045        
046        private boolean iMPP = false;
047        private DbtPropagation iProp = null;
048        private ViolatedInitials iViolatedInitials = null;
049        
050        public DbtValueSelection(DataProperties properties) {
051            iMPP = properties.getPropertyBoolean("General.MPP", false);
052            
053            if (iMPP) {
054                iMPPLimit = properties.getPropertyInt("Value.MPPLimit", -1);
055                iInitialSelectionProb = properties.getPropertyDouble("Value.InitialSelectionProb",0.75);
056                iWeightDeltaInitialAssignment = properties.getPropertyDouble("Value.WeightDeltaInitialAssignments",0.0);
057            }
058            
059            iRandomWalkProb = properties.getPropertyDouble("Value.RandomWalkProb",0.0);
060            iWeightNrAssignments = properties.getPropertyDouble("Value.WeightNrAssignments",0.5);
061            iWeightValue = properties.getPropertyDouble("Value.WeightValue", 0.0);
062        }
063        
064        /** 
065         * Heuristics initialization
066         *
067         * @see ValueSelection#init(Solver)
068         */
069        public void init(Solver solver) {
070            for (Enumeration i = solver.getExtensions().elements(); i.hasMoreElements();) {
071                Extension extension = (Extension) i.nextElement();
072                
073                if (extension instanceof DbtPropagation) {
074                    iProp = (DbtPropagation) extension;
075                }
076                if (extension instanceof ViolatedInitials) {
077                    iViolatedInitials = (ViolatedInitials) extension;
078                }
079            }
080        }
081        
082        /** 
083         * Value selection
084         *
085         * @see ValueSelection#selectValue(Solution, Variable)
086         */
087        public Value selectValue(Solution solution, Variable selectedVariable) {
088            Vector values = null;
089            
090            if (iProp != null) {
091                values = new FastVector(iProp.goodValues(selectedVariable).size());
092                for (Enumeration i1 = selectedVariable.values().elements(); i1.hasMoreElements();) {
093                    Value value = (Value) i1.nextElement();
094                    
095                    if (!iProp.isGood(value)) {
096                        continue;
097                    }
098                    Collection conf = solution.getModel().conflictValues(value);
099                    
100                    if (!conf.isEmpty()) {
101                        HashSet noGood = new HashSet(2 * conf.size());
102                        
103                        for (Iterator i2 = conf.iterator(); i2.hasNext();) {
104                            noGood.add((Value) i2.next());
105                        }
106                        iProp.setNoGood(value, noGood);
107                        sLogger.debug(value+" become nogood ("+noGood+")");
108                    } else {
109                        if (!solution.isBestComplete() || solution.getBestValue()> solution.getModel().getTotalValue()+value.toInt()) {
110                            values.add(value);
111                        }
112                    }
113                }
114            } else {
115                values = new FastVector(selectedVariable.values().size());
116                for (Enumeration i1 = selectedVariable.values().elements(); i1.hasMoreElements();) {
117                    Value value = (Value) i1.nextElement();
118                    
119                    if (solution.getModel().conflictValues(value).isEmpty()) {
120                        if (solution.isBestComplete() && solution.getBestValue()>solution.getModel().getTotalValue()+value.toInt()) {
121                            values.add(value);
122                        }
123                    }
124                }
125            }
126            if (values.isEmpty()) {
127                return null;
128            }
129            
130            if (iMPP) {
131                if (iMPPLimit>=0 && solution.isBestComplete() && solution.getBestPertirbations()>=0 && solution.getBestPertirbations() <= iMPPLimit) {
132                    iMPPLimit = solution.getBestPertirbations() - 1;
133                    sLogger.debug("MPP Limit decreased to "+iMPPLimit);
134                }
135                
136                int nrPerts = solution.getModel().perturbVariables().size();
137                
138                if (iMPPLimit>=0 && iMPPLimit < nrPerts) {
139                    return null;
140                }
141                if (iMPPLimit>=0 && iMPPLimit==nrPerts && selectedVariable.getInitialAssignment() != null) {
142                    if (values.contains(selectedVariable.getInitialAssignment())) {
143                        return selectedVariable.getInitialAssignment();
144                    } else {
145                        return null;
146                    }
147                }
148                
149                if (selectedVariable.getInitialAssignment() != null && ToolBox.random() <= iInitialSelectionProb) {
150                    if (values.contains(selectedVariable.getInitialAssignment())) {
151                        return selectedVariable.getInitialAssignment();
152                    }
153                }
154            }
155            
156            if (values.size()==1) {
157                return (Value) values.firstElement();
158            }
159            
160            if (ToolBox.random() <= iRandomWalkProb) {
161                return (Value) ToolBox.random(values);
162            }
163            
164            Vector bestValues = null;
165            double bestWeightedSum = 0;
166            
167            if (iWeightDeltaInitialAssignment==0.0 && iWeightNrAssignments==0.0 && iWeightValue==0.0) {
168                return (Value) ToolBox.random(values);
169            }
170            
171            for (Enumeration i1 = values.elements(); i1.hasMoreElements();) {
172                Value value = (Value) i1.nextElement();
173                
174                long deltaInitialAssignments = 0;
175                
176                if (iWeightDeltaInitialAssignment != 0.0) {
177                    if (iViolatedInitials != null) {
178                        Set violations = iViolatedInitials.getViolatedInitials(value);
179                        
180                        if (violations != null) {
181                            for (Iterator it1 = violations.iterator(); it1.hasNext();) {
182                                Value aValue = (Value) it1.next();
183                                
184                                if (aValue.variable().getAssignment()==null || aValue.variable().getAssignment().equals(aValue)) {
185                                    deltaInitialAssignments += 2;
186                                }
187                            }
188                        }
189                    }
190                    if (selectedVariable.getInitialAssignment() != null && !selectedVariable.getInitialAssignment().equals(value)) {
191                        deltaInitialAssignments++;
192                    }
193                    if (iMPPLimit>=0 && (solution.getModel().perturbVariables().size()+deltaInitialAssignments)>iMPPLimit) {
194                        continue;
195                    }
196                }
197                
198                double weightedSum = 
199                      (iWeightDeltaInitialAssignment * deltaInitialAssignments)
200                    + (iWeightNrAssignments * value.countAssignments())
201                    + (iWeightValue * value.toInt());
202                
203                if (bestValues==null || bestWeightedSum>weightedSum) {
204                    bestWeightedSum = weightedSum;
205                    if (bestValues==null) {
206                        bestValues = new FastVector();
207                    } else {
208                        bestValues.clear();
209                    }
210                    bestValues.addElement(value);
211                } else if (bestWeightedSum==weightedSum) {
212                    bestValues.addElement(value);
213                }
214            }
215            return (bestValues==null ? null : (Value) ToolBox.random(bestValues));
216        }
217    }