001    package net.sf.cpsolver.ifs.dbt;
002    
003    
004    import java.util.*;
005    
006    import net.sf.cpsolver.ifs.extension.*;
007    import net.sf.cpsolver.ifs.heuristics.*;
008    import net.sf.cpsolver.ifs.model.*;
009    import net.sf.cpsolver.ifs.solution.*;
010    import net.sf.cpsolver.ifs.solver.*;
011    import net.sf.cpsolver.ifs.util.*;
012    
013    /**
014     * Selection of a value for dynamic backtracking.
015     * <br><br>
016     * <li>Returns null if all values of the selected variable are nogood.
017     * <li>Selected the best good value (according to the parameters) of the selected variable.
018     * <br><br>
019     * It is based on a weighted sum of several criteria.
020     * <br><br>
021     * This IFS solver value selection heuristics is to be used only in case of dynamic backtracking and it has the following parameters:
022     * <br>
023     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
024     * <tr><td>General.MPP</td><td>{@link Boolean}</td><td>Minimal Perturbation Problem</td></tr>
025     * <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>
026     * <tr><td>Value.InitialSelectionProb</td><td>{@link Double}</td><td>Probability of selection of initial value (only in case of MPP)</td></tr>
027     * <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>
028     * <tr><td>Value.RandomWalkProb</td><td>{@link Double}</td><td>Probability of random selection of a good value</td></tr>
029     * <tr><td>Value.WeightNrAssignments</td><td>{@link Double}</td><td>Weight of the number of previous assignments of the value</td></tr>
030     * <tr><td>Value.WeightValue</td><td>{@link Double}</td><td>Weight of the value itself (e.g., for minCSP)</td></tr>
031     * </table>
032     * <br>
033     *
034     * @version
035     * IFS 1.1 (Iterative Forward Search)<br>
036     * Copyright (C) 2006 Tomáš Müller<br>
037     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
038     * Lazenska 391, 76314 Zlin, Czech Republic<br>
039     * <br>
040     * This library is free software; you can redistribute it and/or
041     * modify it under the terms of the GNU Lesser General Public
042     * License as published by the Free Software Foundation; either
043     * version 2.1 of the License, or (at your option) any later version.
044     * <br><br>
045     * This library is distributed in the hope that it will be useful,
046     * but WITHOUT ANY WARRANTY; without even the implied warranty of
047     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
048     * Lesser General Public License for more details.
049     * <br><br>
050     * You should have received a copy of the GNU Lesser General Public
051     * License along with this library; if not, write to the Free Software
052     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
053     */
054    public class DbtValueSelection implements ValueSelection {
055        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(GeneralValueSelection.class);
056        private double iRandomWalkProb = 0.0;
057        private double iInitialSelectionProb = 0.0;
058        private int    iMPPLimit = -1;
059        
060        private double iWeightDeltaInitialAssignment = 0.0;
061        private double iWeightNrAssignments = 0.5;
062        private double iWeightValue = 0.0;
063        
064        private boolean iMPP = false;
065        private DbtPropagation iProp = null;
066        private ViolatedInitials iViolatedInitials = null;
067        
068        public DbtValueSelection(DataProperties properties) {
069            iMPP = properties.getPropertyBoolean("General.MPP", false);
070            
071            if (iMPP) {
072                iMPPLimit = properties.getPropertyInt("Value.MPPLimit", -1);
073                iInitialSelectionProb = properties.getPropertyDouble("Value.InitialSelectionProb",0.75);
074                iWeightDeltaInitialAssignment = properties.getPropertyDouble("Value.WeightDeltaInitialAssignments",0.0);
075            }
076            
077            iRandomWalkProb = properties.getPropertyDouble("Value.RandomWalkProb",0.0);
078            iWeightNrAssignments = properties.getPropertyDouble("Value.WeightNrAssignments",0.5);
079            iWeightValue = properties.getPropertyDouble("Value.WeightValue", 0.0);
080        }
081        
082        /** 
083         * Heuristics initialization
084         *
085         * @see ValueSelection#init(Solver)
086         */
087        public void init(Solver solver) {
088            for (Enumeration i = solver.getExtensions().elements(); i.hasMoreElements();) {
089                Extension extension = (Extension) i.nextElement();
090                
091                if (extension instanceof DbtPropagation) {
092                    iProp = (DbtPropagation) extension;
093                }
094                if (extension instanceof ViolatedInitials) {
095                    iViolatedInitials = (ViolatedInitials) extension;
096                }
097            }
098        }
099        
100        /** 
101         * Value selection
102         *
103         * @see ValueSelection#selectValue(Solution, Variable)
104         */
105        public Value selectValue(Solution solution, Variable selectedVariable) {
106            Vector values = null;
107            
108            if (iProp != null) {
109                values = new FastVector(iProp.goodValues(selectedVariable).size());
110                for (Enumeration i1 = selectedVariable.values().elements(); i1.hasMoreElements();) {
111                    Value value = (Value) i1.nextElement();
112                    
113                    if (!iProp.isGood(value)) {
114                        continue;
115                    }
116                    Collection conf = solution.getModel().conflictValues(value);
117                    
118                    if (!conf.isEmpty()) {
119                        HashSet noGood = new HashSet(2 * conf.size());
120                        
121                        for (Iterator i2 = conf.iterator(); i2.hasNext();) {
122                            noGood.add((Value) i2.next());
123                        }
124                        iProp.setNoGood(value, noGood);
125                        sLogger.debug(value+" become nogood ("+noGood+")");
126                    } else {
127                        if (!solution.isBestComplete() || solution.getBestValue()> solution.getModel().getTotalValue()+value.toDouble()) {
128                            values.add(value);
129                        }
130                    }
131                }
132            } else {
133                values = new FastVector(selectedVariable.values().size());
134                for (Enumeration i1 = selectedVariable.values().elements(); i1.hasMoreElements();) {
135                    Value value = (Value) i1.nextElement();
136                    
137                    if (solution.getModel().conflictValues(value).isEmpty()) {
138                        if (solution.isBestComplete() && solution.getBestValue()>solution.getModel().getTotalValue()+value.toDouble()) {
139                            values.add(value);
140                        }
141                    }
142                }
143            }
144            if (values.isEmpty()) {
145                return null;
146            }
147            
148            if (iMPP) {
149                if (iMPPLimit>=0 && solution.isBestComplete() && solution.getModel().getBestPerturbations()>=0 && solution.getModel().getBestPerturbations() <= iMPPLimit) {
150                    iMPPLimit = solution.getModel().getBestPerturbations() - 1;
151                    sLogger.debug("MPP Limit decreased to "+iMPPLimit);
152                }
153                
154                int nrPerts = solution.getModel().perturbVariables().size();
155                
156                if (iMPPLimit>=0 && iMPPLimit < nrPerts) {
157                    return null;
158                }
159                if (iMPPLimit>=0 && iMPPLimit==nrPerts && selectedVariable.getInitialAssignment() != null) {
160                    if (values.contains(selectedVariable.getInitialAssignment())) {
161                        return selectedVariable.getInitialAssignment();
162                    } else {
163                        return null;
164                    }
165                }
166                
167                if (selectedVariable.getInitialAssignment() != null && ToolBox.random() <= iInitialSelectionProb) {
168                    if (values.contains(selectedVariable.getInitialAssignment())) {
169                        return selectedVariable.getInitialAssignment();
170                    }
171                }
172            }
173            
174            if (values.size()==1) {
175                return (Value) values.firstElement();
176            }
177            
178            if (ToolBox.random() <= iRandomWalkProb) {
179                return (Value) ToolBox.random(values);
180            }
181            
182            Vector bestValues = null;
183            double bestWeightedSum = 0;
184            
185            if (iWeightDeltaInitialAssignment==0.0 && iWeightNrAssignments==0.0 && iWeightValue==0.0) {
186                return (Value) ToolBox.random(values);
187            }
188            
189            for (Enumeration i1 = values.elements(); i1.hasMoreElements();) {
190                Value value = (Value) i1.nextElement();
191                
192                long deltaInitialAssignments = 0;
193                
194                if (iWeightDeltaInitialAssignment != 0.0) {
195                    if (iViolatedInitials != null) {
196                        Set violations = iViolatedInitials.getViolatedInitials(value);
197                        
198                        if (violations != null) {
199                            for (Iterator it1 = violations.iterator(); it1.hasNext();) {
200                                Value aValue = (Value) it1.next();
201                                
202                                if (aValue.variable().getAssignment()==null || aValue.variable().getAssignment().equals(aValue)) {
203                                    deltaInitialAssignments += 2;
204                                }
205                            }
206                        }
207                    }
208                    if (selectedVariable.getInitialAssignment() != null && !selectedVariable.getInitialAssignment().equals(value)) {
209                        deltaInitialAssignments++;
210                    }
211                    if (iMPPLimit>=0 && (solution.getModel().perturbVariables().size()+deltaInitialAssignments)>iMPPLimit) {
212                        continue;
213                    }
214                }
215                
216                double weightedSum = 
217                      (iWeightDeltaInitialAssignment * deltaInitialAssignments)
218                    + (iWeightNrAssignments * value.countAssignments())
219                    + (iWeightValue * value.toDouble());
220                
221                if (bestValues==null || bestWeightedSum>weightedSum) {
222                    bestWeightedSum = weightedSum;
223                    if (bestValues==null) {
224                        bestValues = new FastVector();
225                    } else {
226                        bestValues.clear();
227                    }
228                    bestValues.addElement(value);
229                } else if (bestWeightedSum==weightedSum) {
230                    bestValues.addElement(value);
231                }
232            }
233            return (bestValues==null ? null : (Value) ToolBox.random(bestValues));
234        }
235    }