001    package ttsolver.heuristics;
002    
003    import ifs.extension.*;
004    import ifs.heuristics.*;
005    import ifs.model.*;
006    import ifs.solution.*;
007    import ifs.solver.*;
008    import ifs.util.*;
009    import ifs.perturbations.*;
010    
011    import java.util.*;
012    
013    import ttsolver.constraint.*;
014    import ttsolver.model.*;
015    import ttsolver.*;
016    import edu.purdue.smas.timetable.serverfwk.ParameterDefinition;
017    
018    /**
019     * Placement (value) selection.
020     * <br><br>
021     * We have implemented a hierarchical handling of the value selection criteria (see {@link HeuristicSelector}).
022     * <br><br>
023     * The value selection heuristics also allow for random selection of a value with a given probability 
024     * (random walk, e.g., 2%) and, in the case of MPP, to select the initial value (if it exists) with a given probability (e.g., 70%).
025     * <br><br>
026     * Parameters (general):
027     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
028     * <tr><td>Placement.RandomWalkProb</td><td>{@link Double}</td><td>Random walk probability</td></tr>
029     * <tr><td>Placement.GoodSelectionProb</td><td>{@link Double}</td><td>Good value (not removed from domain) selection probability (MAC related)</td></tr>
030     * <tr><td>Placement.TabuLength</td><td>{@link Integer}</td><td>Tabu-list length (-1 means do not use tabu-list)</td></tr>
031     * <tr><td>Placement.MPP_InitialProb</td><td>{@link Double}</td><td>MPP initial selection probability </td></tr>
032     * <tr><td>Placement.MPP_Limit</td><td>{@link Integer}</td><td>MPP: limit on the number of perturbations (-1 for no limit)</td></tr>
033     * <tr><td>Placement.MPP_PenaltyLimit</td><td>{@link Double}</td><td>MPP: limit on the perturbations penalty (-1 for no limit)</td></tr>
034     * </table>
035     * <br>
036     * Parameters (for each level of selection):
037     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
038     * <tr><td>Placement.NrAssignmentsWeight1<br>Placement.NrAssignmentsWeight2<br>Placement.NrAssignmentsWeight3</td><td>{@link Double}</td><td>Number of previous assignments of the value weight</td></tr>
039     * <tr><td>Placement.NrConflictsWeight1,2,3</td><td>{@link Double}</td><td>Number of conflicts weight</td></tr>
040     * <tr><td>Placement.WeightedConflictsWeight1,2,3</td><td>{@link Double}</td><td>Weighted conflicts weight (Conflict-based Statistics related)</td></tr>
041     * <tr><td>Placement.NrPotentialConflictsWeight1,2,3</td><td>{@link Double}</td><td>Number of potential conflicts weight (Conflict-based Statistics related)</td></tr>
042     * <tr><td>Placement.MPP_DeltaInitialAssignmentWeight1,2,3</td><td>{@link Double}</td><td>Delta initial assigments weight (MPP, violated initials related)</td></tr>
043     * <tr><td>Placement.NrHardStudConfsWeight1,2,3</td><td>{@link Double}</td><td>Hard student conflicts weight (student conflicts between single-section classes)</td></tr>
044     * <tr><td>Placement.NrStudConfsWeight1,2,3</td><td>{@link Double}</td><td>Student conflicts weight</td></tr>
045     * <tr><td>Placement.TimePreferenceWeight1,2,3</td><td>{@link Double}</td><td>Time preference weight</td></tr>
046     * <tr><td>Placement.DeltaTimePreferenceWeight1,2,3</td><td>{@link Double}</td><td>Time preference delta weight (difference between before and after assignemnt of the value)</td></tr>
047     * <tr><td>Placement.ConstrPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Constraint preference weight</td></tr>
048     * <tr><td>Placement.RoomPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Room preference weight</td></tr>
049     * <tr><td>Placement.UselessSlotsWeight1,2,3</td><td>{@link Double}</td><td>Useless slot weight</td></tr>
050     * <tr><td>Placement.TooBigRoomWeight1,2,3</td><td>{@link Double}</td><td>Too big room weight</td></tr>
051     * <tr><td>Placement.DistanceInstructorPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Distance (of the rooms of the back-to-back classes) based instructor preferences weight</td></tr>
052     * <tr><td>Placement.DeptSpreadPenaltyWeight1,2,3</td><td>{@link Double}</td><td>Department spreading: penalty of when a slot over initial allowance is used</td></tr>
053     * <tr><td>Placement.ThresholdKoef1,2</td><td>{@link Double}</td><td>Threshold koeficient of the level</td></tr>
054     * </table>
055     * 
056     * @see PlacementSelection
057     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
058     * @version 1.0
059     */
060    
061    public class PlacementSelection implements ValueSelection {
062        static final int NR_LEVELS = 3;
063        private static final double PRECISION = 1.0;
064        private static final boolean USE_THRESHOLD = true;
065        private boolean iUseThreshold = USE_THRESHOLD;
066        
067        private double iGoodSelectionProb;
068        public static final String GOOD_SELECTION_PROB = "Placement.GoodSelectionProb";
069        private double iRandomWalkProb;
070        public static final String RW_SELECTION_PROB = "Placement.RandomWalkProb";
071        private double iInitialSelectionProb;
072        public static final String INITIAL_SELECTION_PROB = "Placement.MPP_InitialProb";
073        private int iMPPLimit;
074        public static final String NR_MPP_LIMIT = "Placement.MPP_Limit";
075        private double iMPPPenaltyLimit;
076        public static final String NR_MPP_PENALTY_LIMIT = "Placement.MPP_PenaltyLimit";
077        
078        private double[] iNrConflictsWeight = new double[NR_LEVELS];
079        public static final String NR_CONFLICTS_WEIGHT = "Placement.NrConflictsWeight";
080        private double[] iNrPotentialConflictsWeight = new double[NR_LEVELS];
081        public static final String NR_POTENTIAL_CONFLICTS_WEIGHT = "Placement.NrPotentialConflictsWeight";
082        private double[] iNrWeightedConflictsWeight = new double[NR_LEVELS];
083        public static final String WEIGHTED_CONFLICTS_WEIGHT = "Placement.WeightedConflictsWeight";
084        private double[] iDeltaTimePreferenceWeight = new double[NR_LEVELS];
085        public static final String DELTA_TIME_PREFERENCE_WEIGHT = "Placement.DeltaTimePreferenceWeight";
086        private double[] iPerturbationPenaltyWeight = new double[NR_LEVELS];
087        public static final String DELTA_INITIAL_ASSIGNMENT_WEIGHT = "Placement.MPP_DeltaInitialAssignmentWeight";
088        private double[] iNrStudentConflictsWeight = new double[NR_LEVELS];
089        public static final String NR_STUDENT_CONF_WEIGHT = "Placement.NrStudConfsWeight";
090        private double[] iNrHardStudentConflictsWeight = new double[NR_LEVELS];
091        public static final String NR_HARD_STUDENT_CONF_WEIGHT = "Placement.NrHardStudConfsWeight";
092        private double[] iUselessSlotsWeight = new double[NR_LEVELS];
093        public static final String USELESS_SLOTS_WEIGHT = "Placement.UselessSlotsWeight";
094        private double[] iSumConstrPreferencesWeight = new double[NR_LEVELS];
095        public static final String SUM_CONSTR_PREFERENCE_WEIGHT = "Placement.ConstrPreferenceWeight";
096        private double[] iSumRoomPreferencesWeight = new double[NR_LEVELS];
097        public static final String SUM_ROOM_PREFERENCE_WEIGHT = "Placement.RoomPreferenceWeight";
098        private double[] iSumTimePreferencesWeight = new double[NR_LEVELS];
099        public static final String SUM_TIME_PREFERENCE_WEIGHT = "Placement.TimePreferenceWeight";
100        private double[] iNrAssignmentsWeight = new double[NR_LEVELS];
101        public static final String NR_ASSIGNMENTS_WEIGHT = "Placement.NrAssignmentsWeight";
102        private double[] iThresholdKoef = new double[NR_LEVELS];
103        public static final String NR_THRESHOLD_KOEF = "Placement.ThresholdKoef";
104        private double[] iTooBigRoomWeight = new double[NR_LEVELS];
105        public static final String TOO_BIG_ROOM_WEIGHT = "Placement.TooBigRoomWeight";
106        private double[] iDeptSpreadWeight = new double[NR_LEVELS];
107        public static final String DEPT_SPREAD_WEIGHT = "Placement.DeptSpreadPenaltyWeight";
108        private double[] iDistanceInstructorPreferenceWeight = new double[NR_LEVELS];
109        public static final String DISTANCE_INSTRUCTOR_PREFERENCE_WEIGHT = "Placement.DistanceInstructorPreferenceWeight";
110    
111        private int       iTabuSize                  = 0;
112        private ArrayList iTabu                      = null;
113        private int       iTabuPos                   = 0;
114        public static final String TABU_LENGTH       = "Placement.TabuLength";
115    
116        private ConflictStatistics iStat = null;
117        private MacPropagation iProp = null;
118        private ViolatedInitials iViolatedInitials = null;
119        private PerturbationsCounter iPerturbationsCounter = null;
120        
121        private boolean iRW = false;
122        private boolean iMPP = false;
123        private boolean iSW = false;
124    
125        public static Vector parameters() {
126            Vector ret = new FastVector();
127            
128            ParameterDefinition.Dependency mppDep = new ParameterDefinition.Dependency("General.MPP","true");
129            //ParameterDefinition.Dependency rwDep = new ParameterDefinition.Dependency("General.RandomWalk","true");
130            //ParameterDefinition.Dependency propDep = new ParameterDefinition.Dependency("General.MAC","true");
131            ParameterDefinition.Dependency swDep = new ParameterDefinition.Dependency("General.SwitchStudents","true");
132            ParameterDefinition.Dependency deptSpreadDep = new ParameterDefinition.Dependency("General.UseDepartmentSpreadConstraints","true");
133            ParameterDefinition.Dependency autoconfigure = new ParameterDefinition.Dependency("Placement.AutoConfigure", "false");
134            ParameterDefinition.Dependency useCBS = new ParameterDefinition.Dependency("ConflictStatistics.Enabled", "true");
135            ParameterDefinition.Dependency notUseCBS = new ParameterDefinition.Dependency("ConflictStatistics.Enabled", "false");
136            
137            ret.addElement(new ParameterDefinition("Placement Selection",RW_SELECTION_PROB, "Random-walk probability", ParameterDefinition.TYPE_DOUBLE, "0.00"));
138            ret.addElement(new ParameterDefinition("Placement Selection",INITIAL_SELECTION_PROB, "Select initial probability", ParameterDefinition.TYPE_DOUBLE, "0.75").addDependency(mppDep));
139            //ret.addElement(new ParameterDefinition("Placement Selection",GOOD_SELECTION_PROB,"Good placement selection probability", ParameterDefinition.TYPE_DOUBLE, "1.00").addDependency(propDep));
140            ret.addElement(new ParameterDefinition("Placement Selection",NR_MPP_LIMIT, "Added perturbations limit", ParameterDefinition.TYPE_INTEGER, "-1").addDependency(mppDep));
141            ret.addElement(new ParameterDefinition("Placement Selection",NR_MPP_PENALTY_LIMIT, "Perturbations penalty limit", ParameterDefinition.TYPE_DOUBLE, "-1.0").addDependency(mppDep));
142            //ret.addElement(new ParameterDefinition("Placement Selection",TABU_LENGTH, "Tabu-list length", ParameterDefinition.TYPE_INTEGER, "-1"));
143            ret.addElement(new ParameterDefinition("Placement Selection", "Placement.AutoConfigure", "Automatic configuration", ParameterDefinition.TYPE_BOOLEAN, "true"));
144            
145            for (int level=0;level<NR_LEVELS;level++) {
146                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), NR_CONFLICTS_WEIGHT+(level+1), "Hard conflicts", ParameterDefinition.TYPE_DOUBLE, (level==0?"1.0":"0.0")).addDependency(autoconfigure).addDependency(notUseCBS));
147                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), WEIGHTED_CONFLICTS_WEIGHT+(level+1), "Weighted hard conflicts (CBS)", ParameterDefinition.TYPE_DOUBLE, (level==0?"1.0":"0.0")).addDependency(autoconfigure).addDependency(useCBS));
148                //ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), NR_POTENTIAL_CONFLICTS_WEIGHT+(level+1), "Potential hard conflicts", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(autoconfigure));
149                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), DELTA_TIME_PREFERENCE_WEIGHT+(level+1), "Time preferences delta", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.5":"0.0")).addDependency(autoconfigure));
150                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), DELTA_INITIAL_ASSIGNMENT_WEIGHT+(level+1), "Perturbation penalty", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.5":level==1?"1.0":"0.0")).addDependency(mppDep).addDependency(autoconfigure));
151                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), NR_STUDENT_CONF_WEIGHT+(level+1), "Student conflicts", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.1":level==1?"0.2":"0.0")).addDependency(autoconfigure));
152                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), NR_HARD_STUDENT_CONF_WEIGHT+(level+1), "Hard student conflicts", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.5":level==1?"1.0":"0.0")).addDependency(swDep).addDependency(autoconfigure));
153                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), USELESS_SLOTS_WEIGHT+(level+1), "Useless slots", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(autoconfigure));
154                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), SUM_CONSTR_PREFERENCE_WEIGHT+(level+1), "Group constraint preferences", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.0":level==1?"1.0":"0.0")).addDependency(autoconfigure));
155                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), SUM_ROOM_PREFERENCE_WEIGHT+(level+1), "Room preferences", ParameterDefinition.TYPE_DOUBLE, (level==1?"0.1":"0.0")).addDependency(autoconfigure));
156                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), SUM_TIME_PREFERENCE_WEIGHT+(level+1), "Time preferences", ParameterDefinition.TYPE_DOUBLE, (level==1?"1.0":"0.0")).addDependency(autoconfigure));
157                //ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), NR_ASSIGNMENTS_WEIGHT+(level+1), "Number of assignments", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(autoconfigure));
158                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), TOO_BIG_ROOM_WEIGHT+(level+1), "Too big rooms", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(autoconfigure));
159                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), DEPT_SPREAD_WEIGHT+(level+1), "Deparment balancing penalty", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.5":level==1?"1.0":"0.0")).addDependency(deptSpreadDep).addDependency(autoconfigure));
160                ret.addElement(new ParameterDefinition("Placement Selection - Weights Level "+(level+1), DISTANCE_INSTRUCTOR_PREFERENCE_WEIGHT+(level+1), "Distance instructor preference", ParameterDefinition.TYPE_DOUBLE, (level==0?"0.5":level==1?"1.0":"0.0")).addDependency(autoconfigure));
161                if (USE_THRESHOLD) ret.addElement(new ParameterDefinition("Placement Selection", NR_THRESHOLD_KOEF+(level+1), "Threshold koeficient for level "+(level+1), ParameterDefinition.TYPE_DOUBLE, (level==0?"0.1":"0.0")).addDependency(autoconfigure));
162            }
163    
164            return ret;
165        }
166        
167        public void init(Solver solver) {
168            for (Enumeration i=solver.getExtensions().elements();i.hasMoreElements();) {
169                Extension extension = (Extension)i.nextElement();
170                if (extension instanceof ConflictStatistics) 
171                    iStat = (ConflictStatistics) extension;
172                if (extension instanceof MacPropagation)
173                    iProp = (MacPropagation)extension;
174                if (extension instanceof ViolatedInitials)
175                    iViolatedInitials = (ViolatedInitials)extension;
176            }
177            iPerturbationsCounter = solver.getPerturbationsCounter();
178        }
179    
180        public PlacementSelection(DataProperties properties) {
181            iMPP                     = properties.getPropertyBoolean("General.MPP", false);
182            iRW                      = properties.getPropertyBoolean("General.RandomWalk", true);
183            iSW                      = properties.getPropertyBoolean("General.SwitchStudents",true);
184            boolean autoconfigure = properties.getPropertyBoolean("Placement.AutoConfigure", false);
185            iRandomWalkProb = (iRW?properties.getPropertyDouble(RW_SELECTION_PROB,0.00):0.0);
186            iGoodSelectionProb = properties.getPropertyDouble(GOOD_SELECTION_PROB,1.00);
187            iInitialSelectionProb = (iMPP?properties.getPropertyDouble(INITIAL_SELECTION_PROB, 0.75):0.0);
188            iMPPLimit = (iMPP?properties.getPropertyInt(NR_MPP_LIMIT, -1):-1);
189            iMPPPenaltyLimit = (iMPP?properties.getPropertyDouble(NR_MPP_PENALTY_LIMIT, -1.0):-1.0);
190            iTabuSize = properties.getPropertyInt(TABU_LENGTH, -1);
191            if (iTabuSize>0) iTabu=new ArrayList(iTabuSize);
192            iUseThreshold = properties.getPropertyBoolean("Placement.UseThreshold", USE_THRESHOLD);
193            
194            for (int level=0; level<NR_LEVELS; level++) {
195                iNrConflictsWeight[level] = properties.getPropertyDouble(NR_CONFLICTS_WEIGHT+(level+1),(level==0?1.0:0.0));
196                iNrPotentialConflictsWeight[level] = properties.getPropertyDouble(NR_POTENTIAL_CONFLICTS_WEIGHT+(level+1),0.0);
197                iNrWeightedConflictsWeight[level] = properties.getPropertyDouble(WEIGHTED_CONFLICTS_WEIGHT+(level+1),(level==0?1.0:0.0));
198                iDeltaTimePreferenceWeight[level] = properties.getPropertyDouble(DELTA_TIME_PREFERENCE_WEIGHT+(level+1), (level==0?0.5:0.0));
199                iPerturbationPenaltyWeight[level] = (iMPP?properties.getPropertyDouble(DELTA_INITIAL_ASSIGNMENT_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0)):0.0);
200                iNrStudentConflictsWeight[level] = properties.getPropertyDouble(NR_STUDENT_CONF_WEIGHT+(level+1),(level==0?0.1:(level==1?0.2:0.0)));
201                iNrHardStudentConflictsWeight[level] = (iSW?properties.getPropertyDouble(NR_HARD_STUDENT_CONF_WEIGHT+(level+1),(level==0?0.5:level==1?1.0:0.0)):0.0);
202                iUselessSlotsWeight[level] = properties.getPropertyDouble(USELESS_SLOTS_WEIGHT+(level+1), 0.0);
203                iSumConstrPreferencesWeight[level] = properties.getPropertyDouble(SUM_CONSTR_PREFERENCE_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0));
204                iSumRoomPreferencesWeight[level] = properties.getPropertyDouble(SUM_ROOM_PREFERENCE_WEIGHT+(level+1), (level==1?0.1:0.0));
205                iSumTimePreferencesWeight[level] = properties.getPropertyDouble(SUM_TIME_PREFERENCE_WEIGHT+(level+1), (level==1?1.0:0.0));
206                iNrAssignmentsWeight[level] = properties.getPropertyDouble(NR_ASSIGNMENTS_WEIGHT+(level+1), 0.0);
207                iThresholdKoef[level] = (USE_THRESHOLD?properties.getPropertyDouble(NR_THRESHOLD_KOEF+(level+1), (level==0?0.1:0.0)):0.0);
208                iTooBigRoomWeight[level] = properties.getPropertyDouble(TOO_BIG_ROOM_WEIGHT+(level+1), 0.0);
209                iDeptSpreadWeight[level] = properties.getPropertyDouble(DEPT_SPREAD_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0));
210                iDistanceInstructorPreferenceWeight[level] = properties.getPropertyDouble(DISTANCE_INSTRUCTOR_PREFERENCE_WEIGHT+(level+1), (level==0?0.1:level==1?1.0:0.0));
211            }
212            
213            if (autoconfigure) {
214                iNrConflictsWeight[0] = 3.0;
215                iNrPotentialConflictsWeight[0] = 0.0;
216                iNrWeightedConflictsWeight[0] = 3.0;
217                iDeltaTimePreferenceWeight[0] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0)/2.0;
218                iNrAssignmentsWeight[0] = 0.0;
219                iThresholdKoef[0] = 0.1;
220                
221                iNrStudentConflictsWeight[0] = properties.getPropertyDouble("Comparator.StudentConflictWeight",0.2);
222                iNrHardStudentConflictsWeight[0] = properties.getPropertyDouble("Comparator.HardStudentConflictWeight",1.0);
223                iUselessSlotsWeight[0] = properties.getPropertyDouble("Comparator.UselessSlotWeight",0.0);
224                iSumConstrPreferencesWeight[0] = properties.getPropertyDouble("Comparator.ContrPreferenceWeight",1.0);
225                iSumRoomPreferencesWeight[0] = properties.getPropertyDouble("Comparator.RoomPreferenceWeight",0.1);
226                iSumTimePreferencesWeight[0] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0);
227                iTooBigRoomWeight[0] = properties.getPropertyDouble("Comparator.TooBigRoomWeight",0.0);
228                iDeptSpreadWeight[0] = properties.getPropertyDouble("Comparator.DeptSpreadPenaltyWeight",1.0);
229                iDistanceInstructorPreferenceWeight[0] = properties.getPropertyDouble("Comparator.DistanceInstructorPreferenceWeight",1.0);
230                iPerturbationPenaltyWeight[0] = (iMPP?properties.getPropertyDouble("Comparator.PerturbationPenaltyWeight",1.0):0.0);
231    
232                iNrConflictsWeight[1] = 0.0;
233                iNrPotentialConflictsWeight[1] = 0.0;
234                iNrWeightedConflictsWeight[1] = 0.0;
235                iDeltaTimePreferenceWeight[1] = 0.0;
236                iNrAssignmentsWeight[1] = 0.0;
237                iThresholdKoef[1] = 0.0;
238                
239                iNrStudentConflictsWeight[1] = properties.getPropertyDouble("Comparator.StudentConflictWeight",0.2);
240                iNrHardStudentConflictsWeight[1] = properties.getPropertyDouble("Comparator.HardStudentConflictWeight",1.0);
241                iUselessSlotsWeight[1] = properties.getPropertyDouble("Comparator.UselessSlotWeight",0.0);
242                iSumConstrPreferencesWeight[1] = properties.getPropertyDouble("Comparator.ContrPreferenceWeight",1.0);
243                iSumRoomPreferencesWeight[1] = properties.getPropertyDouble("Comparator.RoomPreferenceWeight",0.1);
244                iSumTimePreferencesWeight[1] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0);
245                iTooBigRoomWeight[1] = properties.getPropertyDouble("Comparator.TooBigRoomWeight",0.0);
246                iDeptSpreadWeight[1] = properties.getPropertyDouble("Comparator.DeptSpreadPenaltyWeight",1.0);
247                iDistanceInstructorPreferenceWeight[1] = properties.getPropertyDouble("Comparator.DistanceInstructorPreferenceWeight",1.0);
248                iPerturbationPenaltyWeight[1] = (iMPP?properties.getPropertyDouble("Comparator.PerturbationPenaltyWeight",1.0):0.0);
249    
250                iNrConflictsWeight[2] = 0.0;
251                iNrPotentialConflictsWeight[2] = 0.0;
252                iNrWeightedConflictsWeight[2] = 0.0;
253                iDeltaTimePreferenceWeight[2] = 0.0;
254                iPerturbationPenaltyWeight[2] = 0.0;
255                iNrStudentConflictsWeight[2] = 0.0;
256                iNrHardStudentConflictsWeight[2] = 0.0;
257                iUselessSlotsWeight[2] = 0.0;
258                iSumConstrPreferencesWeight[2] = 0.0;
259                iSumRoomPreferencesWeight[2] = 0.0;
260                iSumTimePreferencesWeight[2] = 0.0;
261                iNrAssignmentsWeight[2] = 0.0;
262                iThresholdKoef[2] = 0.0;
263                iTooBigRoomWeight[2] = 0.0;
264                iDeptSpreadWeight[2] = 0.0;
265                iDistanceInstructorPreferenceWeight[2] = 0.0;
266            }
267        }
268        
269        public Value selectValue(Solution solution, Variable selectedVariable) {
270            /*if (iMPPLimit>=0 && solution.getModel().unassignedVariables().isEmpty() && iMPPLimit>solution.getModel().perturbVariables().size()) {
271                ToolBox.print("A complete solution with "+solution.getModel().perturbVariables().size()+" perturbances found");
272                iMPPLimit = solution.getModel().perturbVariables().size()-1;
273                ToolBox.print("MPP limit decreased to "+iMPPLimit);
274            }*/
275            if (selectedVariable.getInitialAssignment()!=null) {
276                if (iMPPLimit>=0 && solution.getModel().perturbVariables().size()>=iMPPLimit) return checkValue(selectedVariable.getInitialAssignment());
277                if (iMPPPenaltyLimit>=0.0 && solution.getPerturbationsCounter()!=null && solution.getPerturbationsCounter().getPerturbationPenalty(solution)>iMPPPenaltyLimit) return checkValue(selectedVariable.getInitialAssignment());
278                if (selectedVariable.getInitialAssignment()!=null && ToolBox.random()<=iInitialSelectionProb) return checkValue(selectedVariable.getInitialAssignment());
279            }
280            
281            Vector values = selectedVariable.values();
282            if (iRW && ToolBox.random()<=iRandomWalkProb) return checkValue((Value)ToolBox.random(values));
283            if (iProp!=null && selectedVariable.getAssignment()==null && ToolBox.random()<=iGoodSelectionProb) {
284                Collection goodValues = iProp.goodValues(selectedVariable);
285                if (!goodValues.isEmpty()) values=new FastVector(goodValues);
286            }
287            if (values.size()==1) return checkValue((Value)values.firstElement());
288            
289            long[] bestCost = new long[NR_LEVELS];
290            Vector selectionValues = null;
291            
292            
293            HeuristicSelector selector = (iUseThreshold?new HeuristicSelector(iThresholdKoef):null);
294            for (Enumeration i1=values.elements();i1.hasMoreElements();) {
295                Value value = (Value) i1.nextElement();
296                if (iTabu!=null && iTabu.contains(value)) continue;
297                if (selectedVariable.getAssignment()!=null && selectedVariable.getAssignment().equals(value)) continue;
298                ParamRetriever paramRetriever = new ParamRetriever(solution, (Lecture)selectedVariable, (Placement)value);
299                
300                if (iUseThreshold) {
301                    double[] costs = new double[NR_LEVELS];
302                    for (int level=0;level<NR_LEVELS;level++) {
303                        double cost =
304                        (iNrConflictsWeight[level]==0.0?0.0:iNrConflictsWeight[level]*paramRetriever.nrContlicts())+
305                        (iNrWeightedConflictsWeight[level]==0.0?0.0:iNrWeightedConflictsWeight[level]*paramRetriever.weightedConflicts())+
306                        (iNrPotentialConflictsWeight[level]==0.0?0.0:iNrPotentialConflictsWeight[level]*paramRetriever.potentialConflicts(3))+
307                        (iDeltaTimePreferenceWeight[level]==0.0?0.0:iDeltaTimePreferenceWeight[level]*paramRetriever.deltaTimePreference())+
308                        (iPerturbationPenaltyWeight[level]==0.0?0.0:iPerturbationPenaltyWeight[level]*paramRetriever.perturbationsPenalty())+
309                        (iNrStudentConflictsWeight[level]==0.0?0.0:iNrStudentConflictsWeight[level]*paramRetriever.sumStudentConflicts())+
310                        (iNrHardStudentConflictsWeight[level]==0.0?0.0:iNrHardStudentConflictsWeight[level]*paramRetriever.sumHardStudentConflicts())+
311                        (iUselessSlotsWeight[level]==0.0?0.0:iUselessSlotsWeight[level]*paramRetriever.emptySingleHalfHours())+
312                        (iSumConstrPreferencesWeight[level]==0.0?0.0:iSumConstrPreferencesWeight[level]*paramRetriever.constrPreference())+
313                        (iSumRoomPreferencesWeight[level]==0.0?0.0:iSumRoomPreferencesWeight[level]*paramRetriever.roomPreference())+
314                        (iSumTimePreferencesWeight[level]==0.0?0.0:iSumTimePreferencesWeight[level]*paramRetriever.timePreference())+
315                        (iNrAssignmentsWeight[level]==0.0?0.0:iNrAssignmentsWeight[level]*paramRetriever.nrAssignments())+
316                        (iTooBigRoomWeight[level]==0.0?0.0:paramRetriever.tooBig()?iTooBigRoomWeight[level]:0.0)+
317                        (iDeptSpreadWeight[level]==0.0?0.0:iDeptSpreadWeight[level]*paramRetriever.deptSpread())+
318                        (iDistanceInstructorPreferenceWeight[level]==0.0?0.0:iDistanceInstructorPreferenceWeight[level]*paramRetriever.distanceInstructorPreference())
319                        ;
320                        costs[level]=cost;
321                    }
322                    selector.add(costs, value);
323                } else {
324                    boolean fail = false;
325                    boolean best = false;
326                    for (int level=0;!fail && level<1;level++) {
327                        long cost = Math.round( PRECISION * (
328                        (iNrConflictsWeight[level]==0.0?0.0:iNrConflictsWeight[level]*paramRetriever.nrContlicts())+
329                        (iNrWeightedConflictsWeight[level]==0.0?0.0:iNrWeightedConflictsWeight[level]*paramRetriever.weightedConflicts())+
330                        (iNrPotentialConflictsWeight[level]==0.0?0.0:iNrPotentialConflictsWeight[level]*paramRetriever.potentialConflicts(0))+
331                        (iDeltaTimePreferenceWeight[level]==0.0?0.0:iDeltaTimePreferenceWeight[level]*paramRetriever.deltaTimePreference())+
332                        (iPerturbationPenaltyWeight[level]==0.0?0.0:iPerturbationPenaltyWeight[level]*paramRetriever.perturbationsPenalty())+
333                        (iNrStudentConflictsWeight[level]==0.0?0.0:iNrStudentConflictsWeight[level]*paramRetriever.sumStudentConflicts())+
334                        (iNrHardStudentConflictsWeight[level]==0.0?0.0:iNrHardStudentConflictsWeight[level]*paramRetriever.sumHardStudentConflicts())+
335                        (iUselessSlotsWeight[level]==0.0?0.0:iUselessSlotsWeight[level]*paramRetriever.emptySingleHalfHours())+
336                        (iSumConstrPreferencesWeight[level]==0.0?0.0:iSumConstrPreferencesWeight[level]*paramRetriever.constrPreference())+
337                        (iSumRoomPreferencesWeight[level]==0.0?0.0:iSumRoomPreferencesWeight[level]*paramRetriever.roomPreference())+
338                        (iSumTimePreferencesWeight[level]==0.0?0.0:iSumTimePreferencesWeight[level]*paramRetriever.timePreference())+
339                        (iNrAssignmentsWeight[level]==0.0?0.0:iNrAssignmentsWeight[level]*paramRetriever.nrAssignments())+
340                        (iTooBigRoomWeight[level]==0.0?0.0:paramRetriever.tooBig()?iTooBigRoomWeight[level]:0.0)+
341                        (iDeptSpreadWeight[level]==0.0?0.0:iDeptSpreadWeight[level]*paramRetriever.deptSpread())+
342                        (iDistanceInstructorPreferenceWeight[level]==0.0?0.0:iDistanceInstructorPreferenceWeight[level]*paramRetriever.distanceInstructorPreference())
343    /*                    (iNrConflictsWeight[level]*conflicts)+
344                        (iNrWeightedConflictsWeight[level]*weightedConflicts)+
345                        (iDeltaTimePreferenceWeight[level]*deltaTimePreference)+
346                        (iDeltaInitialAssignmentsWeight[level]*deltaInitialAssignments)+
347                        (iNrStudentConflictsWeight[level]*sumStudentConflicts)+
348                        (iNrHardStudentConflictsWeight[level]*sumHardStudentConflicts)+
349                        (iUselessSlotsWeight[level]*emptySingleHalfHours)+
350                        (iSumConstrPreferencesWeight[level]*constrPreference)+
351                        (iSumRoomPreferencesWeight[level]*roomPreference)+
352                        (iSumTimePreferencesWeight[level]*timePrefernce)+
353                        (iNrAssignmentsWeight[level]*nrAssignments)*/
354                        ));
355                        if (selectionValues!=null && !best) {
356                            if (cost>bestCost[level]) { fail=true; }
357                            if (cost<bestCost[level]) { bestCost[level]=cost; selectionValues.clear(); best=true; }
358                        } else {
359                            bestCost[level]=cost;
360                        }
361                    }
362                    if (selectionValues==null) selectionValues = new FastVector(values.size());
363                    if (!fail) selectionValues.addElement(value);
364                }
365                
366            }
367            //ToolBox.print("Best "+selectionValues.size()+" locations for variable "+selectedVariable.getId()+" have "+bestConflicts+" conflicts ("+bestRemovals+" weighted) and "+bestStudentConflicts+" ("+bestOriginalStudentConflicts+" * "+bestKoef+" + "+bestPenalty+") preference.");
368            Value selectedValue = null;
369            if (iUseThreshold) {
370                selectionValues = selector.selection();
371                
372                if (selectedVariable.getInitialAssignment()!=null) {
373                    for (Enumeration e=selectionValues.elements();e.hasMoreElements();) {
374                        Value value = (Value)((HeuristicSelector.Element) e.nextElement()).getObject();
375                        if (value.equals(selectedVariable.getInitialAssignment())) {
376                            selectedValue = value;
377                            break;
378                        }
379                    }
380                    //&& selectionValues.contains(selectedVariable.getInitialAssignment())) return selectedVariable.getInitialAssignment();
381                } 
382                
383                if (selectedValue==null) {
384                    HeuristicSelector.Element selection = (HeuristicSelector.Element)ToolBox.random(selectionValues);
385                    selectedValue = (Value)(selection==null?null:selection.getObject());
386                }
387            } else {
388                if (selectedVariable.getInitialAssignment()!=null && selectionValues.contains(selectedVariable.getInitialAssignment())) return checkValue(selectedVariable.getInitialAssignment());
389                selectedValue = (Value)ToolBox.random(selectionValues);
390            }
391            if (selectedValue!=null && iTabu!=null) {
392                if (iTabu.size()==iTabuPos)
393                    iTabu.add(selectedValue);
394                else
395                    iTabu.set(iTabuPos, selectedValue);
396                iTabuPos = (iTabuPos + 1) % iTabuSize;
397            }
398            return checkValue(selectedValue);
399        }
400        
401        private Value checkValue(Value aValue) {
402            if (aValue==null) return null;
403            DepartmentSpreadConstraint c = ((Lecture)aValue.variable()).getDeptSpreadConstraint();
404            if (c!=null && c.inConflict(aValue)) c.incUnassignmentCounter(aValue);
405            return aValue;
406        }
407        
408        private class ParamRetriever {
409            private Lecture iLecture;
410            private Placement iPlacement;
411            private Solution iSolution;
412            private ParamRetriever(Solution solution, Lecture lecture, Placement placement) {
413                iSolution = solution;
414                iLecture = lecture;
415                iPlacement = placement;
416            }
417            
418            Collection iConf = null;
419            private Collection conf() {
420                if (iConf == null) iConf = iSolution.getModel().conflictValues(iPlacement);
421                return iConf;
422            }
423            
424            public long nrContlicts() {
425                return conf().size();
426            }
427            
428            private Double iWeightedConflicts = null;
429            public double weightedConflicts() {
430                if (iWeightedConflicts==null) 
431                    iWeightedConflicts = new Double(iStat==null?0.0:iStat.countRemovals(iSolution.getIteration(), conf(), iPlacement));
432                return iWeightedConflicts.doubleValue();
433            }
434            
435            private Double iPotentialConflicts = null;
436            public double potentialConflicts(int limit) {
437                if (iPotentialConflicts==null)
438                    iPotentialConflicts = new Double(iStat==null?0.0:iStat.countPotentialConflicts(iSolution.getIteration(),iPlacement, limit));
439                return iPotentialConflicts.doubleValue();
440            }
441             
442            Double iDeltaTimePreference = null;
443            public double deltaTimePreference() {
444                if (iDeltaTimePreference==null) {
445                    double deltaTimePreference = 0;
446                    for (Iterator it1=conf().iterator(); it1.hasNext(); ) {
447                        Placement placement = (Placement)it1.next();
448                        double timePref = placement.getTimeLocation().getNormalizedPreference();
449                        deltaTimePreference -= timePref - ((Lecture)placement.variable()).getBestTimePreference();
450                    }
451                    deltaTimePreference += iPlacement.getTimeLocation().getNormalizedPreference() - iLecture.getBestTimePreference();
452                    iDeltaTimePreference = new Double(deltaTimePreference);
453                }
454                return iDeltaTimePreference.doubleValue();
455            }
456            
457            Double iPerturbationsPenalty = null;
458            public double perturbationsPenalty() {
459                if (iPerturbationsPenalty==null) {
460                    iPerturbationsPenalty = new Double(iPerturbationsCounter.getPerturbationPenalty(iSolution,iPlacement,conf()));
461                }
462                return iPerturbationsPenalty.doubleValue();
463            }
464            
465            Integer iSumStudentConflicts = null;
466            public int sumStudentConflicts() {
467                if (iSumStudentConflicts==null) 
468                    iSumStudentConflicts = new Integer(iLecture.countStudentConflicts(iPlacement));
469                return iSumStudentConflicts.intValue();
470            }
471            
472            Integer iConstrPreference = null;
473            public int constrPreference() {
474                if (iConstrPreference==null) {
475                    int constrPreference = 0;
476                    for (Enumeration i2=iLecture.softConstraints().elements();i2.hasMoreElements();) {
477                        Constraint constraint = (Constraint)i2.nextElement();
478                        if (constraint instanceof GroupConstraint) {
479                            GroupConstraint gc = (GroupConstraint)constraint;
480                            constrPreference += gc.getCurrentPreference(iPlacement);
481                        }
482                    }
483                    iConstrPreference = new Integer(constrPreference);
484                }
485                return iConstrPreference.intValue();
486            }
487            
488            Integer iEmptySingleHalfHours = null;
489            public int emptySingleHalfHours() {
490                if (iEmptySingleHalfHours==null) {
491                    int emptySingleHalfHours = 0;
492                    for (Enumeration i2=iLecture.hardConstraints().elements();i2.hasMoreElements();) {
493                        Constraint constraint = (Constraint)i2.nextElement();
494                        if (constraint instanceof RoomConstraint) {
495                            RoomConstraint rc = (RoomConstraint)constraint;
496                            for (int i=0; i<iPlacement.getTimeLocation().getStartSlots().length; i++) {
497                                int startSlot = iPlacement.getTimeLocation().getStartSlots()[i];
498                                int endSlot = startSlot + iPlacement.getTimeLocation().getLength() - 1;
499                                if (((startSlot%edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY)>=2) && rc.getResource()[startSlot-1]==null && rc.getResource()[startSlot-2]!=null)
500                                    emptySingleHalfHours++;
501                                if (((endSlot%edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY)<edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY-2) && rc.getResource()[startSlot+1]==null && rc.getResource()[startSlot+2]!=null)
502                                    emptySingleHalfHours++;
503                            }
504                        }
505                    }
506                    iEmptySingleHalfHours = new Integer(emptySingleHalfHours);
507                }
508                return iEmptySingleHalfHours.intValue();
509            }
510            
511            Integer iSumHardStudentConflicts = null;
512            public int sumHardStudentConflicts() {
513                if (iSumHardStudentConflicts==null) {
514                    boolean haveAlternative = (iLecture.sameLectures()==null?false:iLecture.sameLectures().size()>1);
515                    int sumHardStudentConflicts = 0;
516                    if (!haveAlternative) for (Enumeration i2=iLecture.jenrlConstraints().elements();i2.hasMoreElements();) {
517                        JenrlConstraint jenrl = (JenrlConstraint)i2.nextElement();
518                        Vector anotherSameLectures = ((Lecture)jenrl.another(iLecture)).sameLectures();
519                        if (anotherSameLectures==null || anotherSameLectures.size()==1)
520                            sumHardStudentConflicts += jenrl.jenrl(iLecture, iPlacement);
521                    }
522                    iSumHardStudentConflicts = new Integer(sumHardStudentConflicts);
523                }
524                return iSumHardStudentConflicts.intValue();
525            }
526    
527            public int roomPreference() {
528                return iPlacement.getRoomLocation().getPreference();
529            }
530            
531            public long nrAssignments() {
532                return iPlacement.countAssignments();
533            }
534            
535            public double timePreference() {
536                return iPlacement.getTimeLocation().getNormalizedPreference();
537            }
538            
539            public boolean tooBig() {
540                return iPlacement.getRoomLocation().getRoomSize()>TimetableModel.getMaxCapacity(iLecture.countStudents());
541            }
542            
543            Integer iDeptSpreadCache = null;
544            public int deptSpread() {
545                if (iLecture.getDeptSpreadConstraint()==null) return 0;
546                if (iDeptSpreadCache==null) 
547                    iDeptSpreadCache = new Integer(iLecture.getDeptSpreadConstraint().getPenalty(iPlacement));
548                return iDeptSpreadCache.intValue();
549            }
550            
551            Integer iDistanceInstructorPreferenceCache = null;
552            public int distanceInstructorPreference() {
553                if (iDistanceInstructorPreferenceCache==null) {
554                    int pref = 0;
555                    if (iPlacement.getInstructorId()!=null) {
556                        for (Enumeration i2=iLecture.constraints().elements();i2.hasMoreElements();) {
557                            Constraint constraint = (Constraint)i2.nextElement();
558                            if (constraint instanceof InstructorConstraint) {
559                                pref += ((InstructorConstraint)constraint).getPreference(iPlacement);
560                                break;
561                            }
562                        }
563                    }
564                    iDistanceInstructorPreferenceCache = new Integer(pref);
565                }
566                return iDistanceInstructorPreferenceCache.intValue();
567            }
568        }
569    }