    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
    010    import java.util.*;
    011
    012    import ttsolver.constraint.*;
    013    import ttsolver.model.*;
    014    import ttsolver.*;
    015    import edu.purdue.smas.timetable.serverfwk.ParameterDefinition;
    016
    017    /**
    018     * Lecture (variable) selection.
    019     * <br><br>
    020     * If there are one or more variables unassigned, the variable selection criterion picks one of them randomly. We have
    021     * tried several approaches using domain sizes, number of previous assignments, numbers of constraints in which the
    022     * variable participates, etc., but there was no significant improvement in this timetabling problem towards the random
    023     * selection of an unassigned variable. The reason is, that it is easy to go back when a wrong variable is picked -
    024     * such a variable is unassigned when there is a conflict with it in some of the subsequent iterations.
    025     * <br><br>
    026     * When all variables are assigned, an evaluation is made for each variable according to the above described weights. The
    027     * variable with the worst evaluation is selected. This variable promises the best improvement in optimization.
    028     * <br><br>
    029     * Parameters (selection among unassigned lectures):
    030     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
    031     * <tr><td>Lecture.RouletteWheelSelection</td><td>{@link Boolean}</td><td>Roulette wheel selection</td></tr>
    032     * <tr><td>Lecture.RandomWalkProb</td><td>{@link Double}</td><td>Random walk probability</td></tr>
    033     * <tr><td>Lecture.DomainSizeWeight</td><td>{@link Double}</td><td>Domain size weight</td></tr>
    034     * <tr><td>Lecture.NrAssignmentsWeight</td><td>{@link Double}</td><td>Number of assignments weight</td></tr>
    035     * <tr><td>Lecture.InitialAssignmentWeight</td><td>{@link Double}</td><td>Initial assignment weight</td></tr>
    036     * <tr><td>Lecture.NrConstraintsWeight</td><td>{@link Double}</td><td>Number of constraint weight</td></tr>
    037     * </table>
    038     * <br>
    039     * Parameters (selection among assigned lectures, when the solution is complete):
    040     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
    041     * <tr><td>Lecture.HardStudentConflictWeight</td><td>{@link Double}</td><td>Hard student conflict weight</td></tr>
    042     * <tr><td>Lecture.StudentConflictWeight</td><td>{@link Double}</td><td>Student conflict weight</td></tr>
    043     * <tr><td>Lecture.TimePreferenceWeight</td><td>{@link Double}</td><td>Time preference weight</td></tr>
    044     * <tr><td>Lecture.ContrPreferenceWeight</td><td>{@link Double}</td><td>Group constraint preference weight</td></tr>
    045     * <tr><td>Lecture.RoomPreferenceWeight</td><td>{@link Double}</td><td>Room preference weight</td></tr>
    046     * <tr><td>Lecture.UselessSlotWeight</td><td>{@link Double}</td><td>Useless slot weight</td></tr>
    047     * <tr><td>Lecture.TooBigRoomWeight</td><td>{@link Double}</td><td>Too big room weight</td></tr>
    048     * <tr><td>Lecture.DistanceInstructorPreferenceWeight</td><td>{@link Double}</td><td>Distance (of the rooms of the back-to-back classes) based instructor preferences weight</td></tr>
    049     * <tr><td>Lecture.DeptSpreadPenaltyWeight</td><td>{@link Double}</td><td>Department balancing penalty (see {@link ttsolver.constraint.DepartmentSpreadConstraint})</td></tr>
    050     * </table>
    051     * <br>
    052     * Parameters (selection among subset of lectures (faster)):
    053     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
    054     * <tr><td>Lecture.SelectionSubSet</td><td>{@link Boolean}</td><td>Selection among subset of lectures (faster)</td></tr>
    055     * <tr><td>Lecture.SelectionSubSetMinSize</td><td>{@link Double}</td><td>Minimal subset size</td></tr>
    056     * <tr><td>Lecture.SelectionSubSetPart</td><td>{@link Double}</td><td>Subset size in percentage of all lectures available for selection</td></tr>
    057     * </table>
    058     *
    059     * @see PlacementSelection
    060     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
    061     * @version 1.0
    062     */
    063    public class LectureSelection implements VariableSelection {
    064        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(LectureSelection.class);
    065        private double iRandomWalkProb;
    066        private double iDomainSizeWeight;
    067        private double iGoodValuesWeight;
    068        private double iNrAssignmentsWeight;
    069        private double iConstraintsWeight;
    070        private double iInitialAssignmentWeight;
    071        private boolean iRouletteWheelSelection;
    072        private boolean iUnassignWhenNotGood;
    073
    074        private double iEmptySingleSlotWeight;
    075        private double iTooBigRoomWeight;
    076        private double iTimePreferencesWeight;
    077        private double iStudentConflictWeight;
    078        private double iRoomPreferencesWeight;
    079        private double iConstrPreferencesWeight;
    080        private double iHardStudentConflictWeight;
    081        private double iDistanceInstructorPreferenceWeight;
    082        private double iDeptSpreadPenaltyWeight;
    083
    084        private boolean iSubSetSelection;
    085        private double iSelectionSubSetPart;
    086        private int iSelectionSubSetMinSize;
    087
    088        private boolean iRW = false;
    089        private boolean iMPP = false;
    090        private boolean iSwitchStudents = false;
    091
    092        private ConflictStatistics iStat = null;
    093        private MacPropagation iProp = null;
    094        private ViolatedInitials iViolatedInitials = null;
    095
    096        public LectureSelection(DataProperties properties) {
    097            iRouletteWheelSelection  = properties.getPropertyBoolean("Lecture.RouletteWheelSelection",true);
    098            iUnassignWhenNotGood     = properties.getPropertyBoolean("Lecture.UnassignWhenNotGood",false);
    099            iRW                      = properties.getPropertyBoolean("General.RandomWalk", true);
    100            iRandomWalkProb          = (!iRW?0.0:properties.getPropertyDouble("Lecture.RandomWalkProb",1.00));
    101            iGoodValuesWeight        = properties.getPropertyDouble("Lecture.GoodValueProb",1.0);
    102            iDomainSizeWeight        = properties.getPropertyDouble("Lecture.DomainSizeWeight",30.0);
    103
    104            iNrAssignmentsWeight     = properties.getPropertyDouble("Lecture.NrAssignmentsWeight",10.0);
    105            iConstraintsWeight       = properties.getPropertyDouble("Lecture.NrConstraintsWeight",0.0);
    106            iMPP                     = properties.getPropertyBoolean("General.MPP", false);
    107            iInitialAssignmentWeight = (!iMPP?0.0:properties.getPropertyDouble("Lecture.InitialAssignmentWeight",20.0));
    108
    109            iEmptySingleSlotWeight   = properties.getPropertyDouble("Lecture.UselessSlotWeight",properties.getPropertyDouble("Comparator.UselessSlotWeight",0.0));
    110            iTooBigRoomWeight        = properties.getPropertyDouble("Lecture.TooBigRoomWeight",properties.getPropertyDouble("Comparator.TooBigRoomWeight",0.0));
    111            iTimePreferencesWeight   = properties.getPropertyDouble("Lecture.TimePreferenceWeight",properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0));
    112            iStudentConflictWeight   = properties.getPropertyDouble("Lecture.StudentConflictWeight",properties.getPropertyDouble("Comparator.StudentConflictWeight",0.2));
    113            iRoomPreferencesWeight   = properties.getPropertyDouble("Lecture.RoomPreferenceWeight",properties.getPropertyDouble("Comparator.RoomPreferenceWeight",0.1));
    114            iConstrPreferencesWeight = properties.getPropertyDouble("Lecture.ContrPreferenceWeight",properties.getPropertyDouble("Comparator.ContrPreferenceWeight",1.0));
    115
    116            iSwitchStudents            = properties.getPropertyBoolean("General.SwitchStudents",true);
    117            iHardStudentConflictWeight = (!iSwitchStudents?0.0:properties.getPropertyDouble("Lecture.HardStudentConflictWeight",properties.getPropertyDouble("Comparator.HardStudentConflictWeight",1.0)));
    118            iDistanceInstructorPreferenceWeight = properties.getPropertyDouble("Lecture.DistanceInstructorPreferenceWeight",properties.getPropertyDouble("Comparator.DistanceInstructorPreferenceWeight",1.0));
    119            iDeptSpreadPenaltyWeight = properties.getPropertyDouble("Lecture.DeptSpreadPenaltyWeight",properties.getPropertyDouble("Comparator.DeptSpreadPenaltyWeight",1.0));
    120
    121            iSubSetSelection           = properties.getPropertyBoolean("Lecture.SelectionSubSet",true);
    122            iSelectionSubSetMinSize    = properties.getPropertyInt("Lecture.SelectionSubSetMinSize",10);
    123            iSelectionSubSetPart       = properties.getPropertyDouble("Lecture.SelectionSubSetPart", 0.2);
    124        }
    125
    126        public static Collection parameters() {
    127            Vector ret = new FastVector();
    128
    129            //ParameterDefinition.Dependency mppDep = new ParameterDefinition.Dependency("General.MPP","true");
    130            //ParameterDefinition.Dependency rwDep = new ParameterDefinition.Dependency("General.RandomWalk","true");
    131            //ParameterDefinition.Dependency propDep = new ParameterDefinition.Dependency("General.MAC","true");
    132            //ParameterDefinition.Dependency swDep = new ParameterDefinition.Dependency("General.SwitchStudents","true");
    133            //ParameterDefinition.Dependency deptSpreadDep = new ParameterDefinition.Dependency("General.UseDepartmentSpreadConstraints","false");
    134
    135            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.RouletteWheelSelection", "Roulette-wheel selection", ParameterDefinition.TYPE_BOOLEAN, "true"));
    136            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.UnassignWhenNotGood", "Unassign when no good", ParameterDefinition.TYPE_BOOLEAN, "false").addDependency(propDep));
    137            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.RandomWalkProb", "Random walk probability", ParameterDefinition.TYPE_DOUBLE, "0.02").addDependency(rwDep));
    138            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.GoodValueProb", "Good value selection", ParameterDefinition.TYPE_DOUBLE, "1.00").addDependency(propDep));
    139
    140            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights","Lecture.DomainSizeWeight", "Domain size", ParameterDefinition.TYPE_DOUBLE, "30.0"));
    141            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights","Lecture.NrAssignmentsWeight", "Number of assignments", ParameterDefinition.TYPE_DOUBLE, "10.0"));
    142            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights","Lecture.NrConstraintsWeight", "Number of constraints", ParameterDefinition.TYPE_DOUBLE, "0.0"));
    143            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights","Lecture.InitialAssignmentWeight", "Initial assignment", ParameterDefinition.TYPE_DOUBLE, "20.0").addDependency(mppDep));
    144
    145            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.UselessSlotWeight", "Useless slots", ParameterDefinition.TYPE_DOUBLE, "0.00"));
    146            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.TimePreferenceWeight", "Time preferences", ParameterDefinition.TYPE_DOUBLE, "1.00"));
    147            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.StudentConflictWeight", "Student conflicts", ParameterDefinition.TYPE_DOUBLE, "0.10"));
    148            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.RoomPreferenceWeight", "Room preferences", ParameterDefinition.TYPE_DOUBLE, "0.10"));
    149            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.ContrPreferenceWeight", "Group constraint preferences", ParameterDefinition.TYPE_DOUBLE, "1.00"));
    150            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.HardStudentConflictWeight", "Hard student conflicts", ParameterDefinition.TYPE_DOUBLE, "1.00"));
    151
    152            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.DistanceInstructorPreferenceWeight", "Distance Instructor Preference", ParameterDefinition.TYPE_DOUBLE, "0.10"));
    153            //ret.addElement(new ParameterDefinition("Lecture Selection - Weights (a complete solution found)","Lecture.DeptSpreadPenaltyWeight", "Deparment balancing -- penalty a slot over initial allowance", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(deptSpreadDep));
    154
    155            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.SelectionSubSet", "Subset selection", ParameterDefinition.TYPE_BOOLEAN, "true"));
    156            //ParameterDefinition.Dependency subSetDep = new ParameterDefinition.Dependency("Lecture.SelectionSubSet", "true");
    157            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.SelectionSubSetMinSize", "Subset selection -- subset minimum size", ParameterDefinition.TYPE_INTEGER, "10").addDependency(subSetDep));
    158            //ret.addElement(new ParameterDefinition("Lecture Selection","Lecture.SelectionSubSetPart", "Subset selection -- part", ParameterDefinition.TYPE_DOUBLE, "0.20").addDependency(subSetDep));
    159
    160            return ret;
    161        }
    162
    163        public void init(Solver solver) {
    164            for (Enumeration i=solver.getExtensions().elements();i.hasMoreElements();) {
    165                Extension extension = (Extension)i.nextElement();
    166                if (extension instanceof ConflictStatistics)
    167                    iStat = (ConflictStatistics) extension;
    168                if (extension instanceof MacPropagation)
    169                    iProp = (MacPropagation)extension;
    170                if (extension instanceof ViolatedInitials)
    171                    iViolatedInitials = (ViolatedInitials)extension;
    172            }
    173        }
    174
    175        public Variable selectVariable(Solution solution) {
    176            if (solution.getModel().unassignedVariables().isEmpty()) {
    177                Vector variables = solution.getModel().perturbVariables();
    178                if (variables.isEmpty()) variables = solution.getModel().variables();
    179
    180                //if (iRW && ToolBox.random()<=iRandomWalkProb) return (Variable)ToolBox.random(variables);
    181
    182                Vector selectionVariables = null;
    183                int worstTimePreference = 0;
    184                int worstRoomConstrPreference = 0;
    185
    186                for (Iterator i1=(iSubSetSelection?ToolBox.subSet(variables,iSelectionSubSetPart,iSelectionSubSetMinSize):variables).iterator();i1.hasNext();) {
    187                    Variable selectedVariable = (Variable) i1.next();
    188                    Value value = (Value)selectedVariable.getAssignment();
    189
    190                    int sumStudentConflicts = (iStudentConflictWeight!=0.0?((Lecture)selectedVariable).countStudentConflicts(value):0);
    191                    boolean haveAlternative = (((Lecture)selectedVariable).sameLectures()==null?false:((Lecture)selectedVariable).sameLectures().size()>1);
    192                    int constrPreference = 0;
    193                    int emptySingleHalfHours = 0;
    194                    int sumHardStudentConflicts = 0;
    195                    int distanceInstructorPreferences = 0;
    196                    boolean tooBig = ((Placement)value).getRoomLocation().getRoomSize()>TimetableModel.getMaxCapacity(((Lecture)selectedVariable).countStudents());
    197
    198                    for (Enumeration i2=selectedVariable.constraints().elements();i2.hasMoreElements();) {
    199                        Constraint constraint = (Constraint)i2.nextElement();
    200                        if (iDistanceInstructorPreferenceWeight!=0.0 && constraint instanceof InstructorConstraint) {
    201                            distanceInstructorPreferences += ((InstructorConstraint)constraint).getPreference(value);
    202                        }
    203                        if (iHardStudentConflictWeight!=0.0 && !haveAlternative && constraint instanceof JenrlConstraint) {
    204                            JenrlConstraint jenrl = (JenrlConstraint)constraint;
    205                            Collection anotherSameLectures = ((Lecture)jenrl.another(selectedVariable)).sameLectures();
    206                            if (anotherSameLectures==null || anotherSameLectures.size()==1)
    207                                sumHardStudentConflicts += ((JenrlConstraint)constraint).jenrl(selectedVariable, value);
    208                        } else if (iConstrPreferencesWeight!=0.0 && constraint instanceof GroupConstraint) {
    209                            GroupConstraint gc = (GroupConstraint)constraint;
    210                            constrPreference += gc.getCurrentPreference();
    211                        } else if (iEmptySingleSlotWeight!=0.0 && constraint instanceof RoomConstraint) {
    212                            RoomConstraint rc = (RoomConstraint)constraint;
    213                            for (int i=0; i<((Placement)value).getTimeLocation().getStartSlots().length; i++) {
    214                                int startSlot = ((Placement)value).getTimeLocation().getStartSlots()[i];
    215                                int endSlot = startSlot + ((Placement)value).getTimeLocation().getLength() - 1;
    216                                if (((startSlot%edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY)>=2) && rc.getResource()[startSlot-1]==null && rc.getResource()[startSlot-2]!=null)
    217                                    emptySingleHalfHours++;
    218                                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)
    219                                    emptySingleHalfHours++;
    220                            }
    221                        }
    222                    }
    223
    224                    int roomPreference = ((Placement)value).getRoomLocation().getPreference();
    225                    double deptSpreadPenalty = (iDeptSpreadPenaltyWeight==0.0 || ((Lecture)selectedVariable).getDeptSpreadConstraint()==null?0:((Lecture)selectedVariable).getDeptSpreadConstraint().getPenalty());
    226                    int timePreference = (int)(100.0*(
    227                        (iStudentConflictWeight*sumStudentConflicts)+
    228                        (iHardStudentConflictWeight*sumHardStudentConflicts)+
    229                        (iTimePreferencesWeight*((Placement)value).getTimeLocation().getNormalizedPreference())+
    230                        (iEmptySingleSlotWeight*emptySingleHalfHours)+
    231                        (iRoomPreferencesWeight*roomPreference)+
    232                        (tooBig?iTooBigRoomWeight:0.0)+
    233                        (iConstrPreferencesWeight*constrPreference)+
    234                        (iDistanceInstructorPreferenceWeight*distanceInstructorPreferences)+
    235                        (iDeptSpreadPenaltyWeight*deptSpreadPenalty)
    236                    ));
    237
    238                    if (selectionVariables==null || timePreference>worstTimePreference || (timePreference==worstTimePreference && roomPreference+constrPreference>worstRoomConstrPreference)) {
    239                        if (selectionVariables==null) selectionVariables=new FastVector(); else selectionVariables.clear();
    240                        selectionVariables.addElement(selectedVariable);
    241                        worstTimePreference=timePreference;
    242                        worstRoomConstrPreference=roomPreference+constrPreference;
    243                    } else if (timePreference==worstTimePreference && roomPreference+constrPreference==worstRoomConstrPreference) {
    244                        selectionVariables.addElement(selectedVariable);
    245                    }
    246                }
    247
    248                return (Variable)ToolBox.random(selectionVariables);
    249            } else {
    250                if (ToolBox.random()<=iRandomWalkProb) return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
    251
    252                if (iProp!=null && iUnassignWhenNotGood) {
    253                    int totalPoints = 0;
    254                    Vector noGoodVariables = new FastVector();
    255                    for (Iterator i1=ToolBox.subSet(solution.getModel().unassignedVariables(),iSelectionSubSetPart,iSelectionSubSetMinSize).iterator();i1.hasNext(); ){
    256                        Variable variable = (Variable) i1.next();
    257                        if (iProp.goodValues(variable).isEmpty())
    258                            noGoodVariables.addElement(variable);
    259                    }
    260                    if (!noGoodVariables.isEmpty()) {
    261                        if (ToolBox.random()<0.02) return (Variable)ToolBox.random(solution.getModel().assignedVariables());
    262                        for (int attempt=0;attempt<10;attempt++) {
    263                            Variable noGoodVariable = (Variable)ToolBox.random(noGoodVariables);
    264                            Value noGoodValue = (Value)ToolBox.random(noGoodVariable.values());
    265                            if (!iProp.noGood(noGoodValue).isEmpty()) return ((Value)ToolBox.random(iProp.noGood(noGoodValue))).variable();
    266                        }
    267                    }
    268                }
    269
    270                if (iRouletteWheelSelection) {
    271                    int iMaxDomainSize=0;
    272                    int iMaxGoodDomainSize=0;
    273                    int iMaxConstraints=0;
    274                    long iMaxNrAssignments=0;
    275                    Collection variables = (iSubSetSelection?ToolBox.subSet(solution.getModel().unassignedVariables(),iSelectionSubSetPart,iSelectionSubSetMinSize):solution.getModel().unassignedVariables());
    276                    for (Iterator i=variables.iterator();i.hasNext(); ){
    277                        Variable variable = (Variable) i.next();
    278                        iMaxDomainSize=Math.max(iMaxDomainSize,variable.values().size());
    279                        iMaxGoodDomainSize=(iProp==null?0:Math.max(iMaxGoodDomainSize,iProp.goodValues(variable).size()));
    280                        iMaxConstraints=Math.max(iMaxConstraints,variable.constraints().size());
    281                        iMaxNrAssignments=Math.max(iMaxNrAssignments,variable.countAssignments());
    282                    }
    283
    284                    Vector points = new FastVector();
    285                    int totalPoints = 0;
    286
    287                    for (Iterator i=variables.iterator();i.hasNext(); ){
    288                        Variable variable = (Variable) i.next();
    289
    290                        long pointsThisVariable = Math.round(
    291                            iDomainSizeWeight*(((double)(iMaxDomainSize-variable.values().size()))/((double)iMaxDomainSize))+
    292                            (iProp==null?0.0:iGoodValuesWeight*(((double)(iMaxGoodDomainSize-iProp.goodValues(variable).size()))/((double)iMaxGoodDomainSize)))+
    293                            iNrAssignmentsWeight*(((double)variable.countAssignments())/((double)iMaxNrAssignments))+
    294                            iConstraintsWeight*(((double)(iMaxConstraints-variable.constraints().size()))/((double)iMaxConstraints))+
    295                            iInitialAssignmentWeight*(variable.getInitialAssignment()!=null?solution.getModel().conflictValues(variable.getInitialAssignment()).size():0.0)
    296                            );
    297                        if (pointsThisVariable>0) {
    298                            totalPoints += pointsThisVariable;
    299                            points.addElement(new Integer(totalPoints));
    300                        }
    301                    }
    302
    303                    if (totalPoints>0) {
    304                        int rndPoints = ToolBox.random(totalPoints);
    305                        Iterator x=variables.iterator();
    306                        for (int i=0;x.hasNext() && i<points.size();i++){
    307                            Variable variable = (Variable)x.next();
    308                            int tp = ((Integer)points.elementAt(i)).intValue();
    309                            if (tp>rndPoints) return variable;
    310                        }
    311                    }
    312
    313                } else {
    314
    315                    Vector selectionVariables = null;
    316                    long bestGood = 0;
    317                    for (Iterator i=ToolBox.subSet(solution.getModel().unassignedVariables(),iSelectionSubSetPart,iSelectionSubSetMinSize).iterator();i.hasNext(); ){
    318                        Variable variable = (Variable) i.next();
    319
    320                        long good = (long)(
    321                        iDomainSizeWeight*variable.values().size()
    322                        + iGoodValuesWeight*(iProp==null?0:iProp.goodValues(variable).size())
    323                        + iNrAssignmentsWeight*variable.countAssignments()
    324                        + iConstraintsWeight*variable.constraints().size()
    325                        + iInitialAssignmentWeight*(variable.getInitialAssignment()!=null?solution.getModel().conflictValues(variable.getInitialAssignment()).size():0.0)
    326                        );
    327                        if (selectionVariables==null || bestGood>good) {
    328                            if (selectionVariables==null) selectionVariables = new FastVector(); else selectionVariables.clear();
    329                            bestGood=good;
    330                            selectionVariables.addElement(variable);
    331                        } else if (good==bestGood) {
    332                            selectionVariables.addElement(variable);
    333                        }
    334                    }
    335
    336                    if (!selectionVariables.isEmpty())
    337                        return (Variable)ToolBox.random(selectionVariables);
    338                }
    339                return (Variable)ToolBox.random(solution.getModel().unassignedVariables());
    340            }
    341        }
    342
    343    }