    001    package ttsolver.model;
    002
    003
    004    import ifs.model.*;
    005    import ifs.util.*;
    006
    007    import java.util.*;
    008
    009    import ttsolver.*;
    010    import ttsolver.constraint.*;
    011
    012    /**
    013     * Lecture (variable).
    014     *
    015     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
    016     * @version 1.0
    017     */
    018
    019    public class Lecture extends Variable {
    020        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Lecture.class);
    021        private long iClassId;
    022        private String iName;
    023        private String iDept;
    024        private Vector iTimeLocations;
    025        private Vector iRoomLocations;
    026        private String iInstructorId;
    027        private String iInstructorName;
    028        private int iBestRoomPref;
    029        private double iBestTimePref;
    030        private long iNrStudents = -1;
    031        private int iExpectedCapacity;
    032        private Hashtable iSameRoomValues = null;
    033        private String iPattern = null;
    034
    035        private Vector iStudents = new FastVector(1);
    036        private Vector iAllStudents = null;
    037        private Vector iSameLectures = null;
    038        private Vector iCrossListedLectures = null;
    039        private DepartmentSpreadConstraint iDeptSpreadConstrain = null;
    040        private InstructorConstraint iInstructorConstraint = null;
    041
    042        //private Vector iDoneSwaps = new FastVector(1);
    043
    044        private Hashtable iSameStudents = new Hashtable(10);
    045        private Vector iActiveJenrls = new FastVector(10);
    046        private Vector iJenrlConstraints = new FastVector(10);
    047
    048        private static boolean sSaveMemory = false;
    049
    050        /** Constructor
    051         * @param id unique identification
    052         * @param name class name
    053         * @param timeLocations set of time locations
    054         * @param bestTimePref best time preference over all time locations
    055         * @param instructorId instuctor id
    056         * @param roomLocations set of room location
    057         * @param bestRoomPref best room preference over all room locations
    058         * @param initialPlacement initial placement
    059         * @param expectedCapacity expected number of students
    060         * @param inctructorName instructor name
    061         * @param pattern time pattern (e.g., 2x100)
    062         */
    063        public Lecture(long id, String name, Vector timeLocations, double bestTimePref, String instructorId, Vector roomLocations, int bestRoomPref, Placement initialPlacement, int expectedCapacity, String inctructorName, String pattern) {
    064            super(initialPlacement);
    065            iClassId = id;
    066            iTimeLocations = timeLocations;
    067            iInstructorId = instructorId;
    068            iInstructorName = inctructorName;
    069            iRoomLocations = roomLocations;
    070            iName = name;
    071            iBestRoomPref = bestRoomPref;
    072            iBestTimePref = bestTimePref;
    073            iExpectedCapacity = expectedCapacity;
    074            iPattern = pattern;
    075            if (!sSaveMemory)
    076                setValues(computeValues());
    077        }
    078
    079        /** Add active jenrl constraint (active mean that there is at least one student between its classes) */
    080        public void addActiveJenrl(JenrlConstraint constr) { iActiveJenrls.addElement(constr); }
    081        /** Active jenrl constraints (active mean that there is at least one student between its classes) */
    082        public Vector activeJenrls() { return iActiveJenrls; }
    083        /** Remove active jenrl constraint (active mean that there is at least one student between its classes) */
    084        public void removeActiveJenrl(JenrlConstraint constr) { iActiveJenrls.removeElement(constr); }
    085
    086        /** Class id */
    087        public long getClassId() { return iClassId; }
    088        /** Class name */
    089        public String getName() { return iName; }
    090        /** Class id */
    091        public long getId() { return iClassId; }
    092        /** Instructor name */
    093        public String getInstructorName() { return iInstructorName; }
    094        /** Instructor id */
    095        public String getInstructorId() { return iInstructorId; }
    096        /** List of enrolled students */
    097        public Vector students() { return iStudents; }
    098        /** List of enrolled students of this class and of all its cross-listed classes */
    099        public Vector allStudents() { return (iAllStudents==null?iStudents:iAllStudents); }
    100        /** Add an enrolled student */
    101        public void addStudent(String student) {
    102            iStudents.addElement(student);
    103            if (iAllStudents!=null) iAllStudents.addElement(student);
    104        }
    105        /** Add a student enrolled to a cross-listed class */
    106        public void addSameLectureStudent(String student) {
    107            iAllStudents.addElement(student);
    108        }
    109        /** Returns true if the given student is enrolled */
    110        public boolean hasStudent(String student) { return (iAllStudents==null?iStudents:iAllStudents).contains(student);}
    111        /** Set of lectures of the same class (only section is different) */
    112        public void setSameLectures(Vector sameLectures) {  iSameLectures = sameLectures; }
    113        /** Set of lectures of the same class (only section is different) */
    114        public Vector sameLectures() { return iSameLectures; }
    115        /* Set of cross-listed classes */
    116        public Vector crossListedLectures() { return iCrossListedLectures; }
    117        /* Set of cross-listed classes */
    118        public void setCrossListedLectures(Vector crossListedLectures) {
    119            iCrossListedLectures = crossListedLectures;
    120            if (iCrossListedLectures!=null) {
    121                iAllStudents = new FastVector(1);
    122                for (Enumeration e2=iCrossListedLectures.elements();e2.hasMoreElements();)
    123                    ((CrossListedLecture)e2.nextElement()).setLecture(this);
    124            }
    125        }
    126        /** List of students enrolled in this class as well as in the given class */
    127        public Vector sameStudents(Lecture lecture) {
    128            if (iSameStudents.containsKey(lecture)) return (Vector)iSameStudents.get(lecture);
    129            Vector ret = new FastVector();
    130            for (Enumeration e=allStudents().elements(); e.hasMoreElements();) {
    131                String student = (String)e.nextElement();
    132                if (lecture.allStudents().contains(student)) ret.addElement(student);
    133            }
    134            iSameStudents.put(lecture, ret);
    135            return ret;
    136        }
    137        /** List of students which are in conflict with the given two classes */
    138        public Vector conflictStudents(Value value, Variable anotherVariable) {
    139            Vector ret = new FastVector();
    140            if (value==null) return ret;
    141            Lecture lecture = (Lecture)anotherVariable;
    142            if (lecture.getAssignment()==null || lecture.equals(this)) return ret;
    143            if (!JenrlConstraint.isInConflict((Placement)value,(Placement)lecture.getAssignment())) return ret;
    144            return sameStudents(lecture);
    145        }
    146        /** List of students of this class in conflict with the given assignment */
    147        public Vector conflictStudents(Value value) {
    148            Vector ret = new FastVector();
    149            if (value==null) return ret;
    150            if (getAssignment()!=null && value.equals(getAssignment())) {
    151                for (Enumeration i1=activeJenrls().elements(); i1.hasMoreElements();) {
    152                    JenrlConstraint jenrl = (JenrlConstraint) i1.nextElement();
    153                    ToolBox.merge(ret, sameStudents((Lecture)jenrl.another(this)));
    154                }
    155            } else {
    156                for (Enumeration i1=iJenrlConstraints.elements(); i1.hasMoreElements();) { //constraints()
    157                    JenrlConstraint jenrl = (JenrlConstraint)i1.nextElement();// constraint;
    158                    if (jenrl.jenrl(this, value)>0)
    159                        ToolBox.merge(ret, sameStudents((Lecture)jenrl.another(this)));
    160                }
    161            }
    162            return ret;
    163        }
    164
    165        /** List of students of this class which are in conflict with any other assignment */
    166        public Vector conflictStudents() {
    167            Vector ret = new FastVector();
    168            if (getAssignment()==null) return ret;
    169            for (Enumeration i1=activeJenrls().elements(); i1.hasMoreElements();) {
    170                JenrlConstraint jenrl = (JenrlConstraint) i1.nextElement();
    171                ToolBox.merge(ret, sameStudents((Lecture)jenrl.another(this)));
    172            }
    173            return ret;
    174        }
    175
    176        /** Lectures which share the given student, different from this one */
    177        public Vector sameStudentLectures(String student) {
    178            Vector ret = new FastVector();
    179            for (Enumeration it=iJenrlConstraints.elements();it.hasMoreElements();) {//constraints()
    180                JenrlConstraint jenrl = (JenrlConstraint)it.nextElement();
    181                Lecture lect = (Lecture)jenrl.another(this);
    182                if (!lect.equals(this) && lect.allStudents().contains(student)) ret.addElement(lect);
    183            }
    184            return ret;
    185        }
    186        /** Names of lectures different from this one, where it is student conflict of the given student between this and the lecture */
    187        public Vector conflictLecturesNames(String student) {
    188            Vector ret = new FastVector();
    189            if (getAssignment()==null) return ret;
    190            for (Enumeration it=activeJenrls().elements();it.hasMoreElements();) {
    191                JenrlConstraint jenrl = (JenrlConstraint) it.nextElement();
    192                Lecture lect = (Lecture)jenrl.another(this);
    193                if (!lect.equals(this) && lect.allStudents().contains(student)) ret.addElement(lect.getName());
    194            }
    195            return ret;
    196        }
    197        /** Lectures different from this one, where it is student conflict of the given student between this and the lecture */
    198        public Vector conflictLectures(String student) {
    199            Vector ret = new FastVector();
    200            if (getAssignment()==null) return ret;
    201            for (Enumeration it=activeJenrls().elements();it.hasMoreElements();) {
    202                JenrlConstraint jenrl = (JenrlConstraint) it.nextElement();
    203                Lecture lect = (Lecture)jenrl.another(this);
    204                if (lect.allStudents().contains(student)) ret.addElement(lect);
    205            }
    206            return ret;
    207        }
    208        /** Lectures different from this one, which are in a student conflict with the given assignment (of this lecture)*/
    209        public Vector conflictLectures(Value value) {
    210            Vector ret = new FastVector();
    211            for (Enumeration it=iJenrlConstraints.elements();it.hasMoreElements();) {//constraints()
    212                JenrlConstraint jenrl = (JenrlConstraint)it.nextElement();
    213                Lecture lect = (Lecture)jenrl.another(this);
    214                if (jenrl.jenrl(this, value)>0) ret.addElement(lect);
    215            }
    216            return ret;
    217        }
    218        /** Lectures different from this one, which are in a student conflict with the this lecture*/
    219        public Vector conflictLectures() {
    220            Vector ret = new FastVector();
    221            for (Enumeration it=activeJenrls().elements();it.hasMoreElements();) {
    222                JenrlConstraint jenrl = (JenrlConstraint) it.nextElement();
    223                Lecture lect = (Lecture)jenrl.another(this);
    224                ret.addElement(lect.getName());
    225            }
    226            return ret;
    227
    228        }
    229        /** True if this lecture is in a student conflict with the given student */
    230        public int isInConflict(String student) {
    231            if (getAssignment()==null) return 0;
    232            int ret = 0;
    233            for (Enumeration it=activeJenrls().elements();it.hasMoreElements();) {
    234                JenrlConstraint jenrl = (JenrlConstraint) it.nextElement();
    235                Lecture lect = (Lecture)jenrl.another(this);
    236                if (lect.allStudents().contains(student)) ret++;
    237            }
    238            return ret;
    239        }
    240        /** Swap students between this and the same lectures (lectures which differ only in the section) */
    241        public Set swapStudents() {
    242            if (iSameLectures==null || iStudents==null) return null;
    243            if (getAssignment()==null) return null;
    244            int totalConf = countStudentConflicts(getAssignment());
    245            Vector conflictStudents = conflictStudents();
    246            //sLogger.debug("  conflicts:"+totalConf+" "+conflictStudents);
    247            if (totalConf==0) return null;
    248            HashSet ret = new HashSet();
    249            //sLogger.debug("Solution before swap is "+getModel().getInfo()+".");
    250            if (iSameLectures.size()>1) for (Enumeration i1=conflictStudents.elements(); i1.hasMoreElements();) {
    251                String student = (String)i1.nextElement();
    252                int iniDelta=isInConflict(student);
    253                if (iniDelta==0) continue;
    254                int bestDelta=-1;
    255                //sLogger.debug("student:"+student+", confs:"+iniDelta+" "+conflictLecturesNames(student));
    256                Vector bestLecture=null;
    257                Vector bestStudent=null;
    258                for (Enumeration i2=iSameLectures.elements();i2.hasMoreElements();) {
    259                    Lecture sameLecture = (Lecture)i2.nextElement();
    260                    if (sameLecture.equals(this)) continue;
    261                    //if (sameLecture.isInConflict(student)<bestDelta) {
    262                    for (Enumeration i3=sameLecture.allStudents().elements();i3.hasMoreElements();) {
    263                        String anotherStudent = (String)i3.nextElement();
    264                        if (isSwapTabu(student,anotherStudent)) break;
    265                        if (bestDelta<0 && bestLecture!=null && bestLecture.size()>10) break;
    266                        int delta = isInConflict(anotherStudent)+sameLecture.isInConflict(student)-sameLecture.isInConflict(anotherStudent)-iniDelta;
    267                        if (delta<bestDelta) {
    268                            if (bestLecture==null) {
    269                                bestLecture=new FastVector(); bestStudent=new FastVector();
    270                            } else {
    271                                bestLecture.clear(); bestStudent.clear();
    272                            }
    273                            bestLecture.addElement(sameLecture);
    274                            bestStudent.addElement(anotherStudent);
    275                            bestDelta=delta;
    276                        } else if (delta==bestDelta) {
    277                            if (bestLecture==null) {
    278                                bestLecture=new FastVector(); bestStudent=new FastVector();
    279                            }
    280                            bestLecture.addElement(sameLecture);
    281                            bestStudent.addElement(anotherStudent);
    282                        } else continue;
    283                        //sLogger.debug("possible swap with "+anotherStudent+", confs:"+isInConflict(anotherStudent)+"+"+sameLecture.isInConflict(student)+"-"+sameLecture.isInConflict(anotherStudent)+"-"+iniDelta+", best:"+bestDelta);
    284                    }
    285                    if (bestDelta==0 && bestLecture!=null && bestLecture.size()>10) break;
    286                    //}
    287                }
    288                if (bestLecture!=null) {
    289                    int x = ToolBox.random(bestLecture.size());
    290                    //sLogger.debug("Swap "+getName()+" "+student+" <-> "+((Lecture)bestLecture.elementAt(x)).getName()+" "+(String)bestStudent.elementAt(x)+", delta:"+bestDelta);
    291                    //sLogger.debug(" -"+getName()+" "+student+": "+conflictLecturesNames(student));
    292                    //sLogger.debug(" +"+getName()+" "+(String)bestStudent.elementAt(x)+": "+conflictLecturesNames((String)bestStudent.elementAt(x)));
    293                    //sLogger.debug(" -"+((Lecture)bestLecture.elementAt(x)).getName()+" "+(String)bestStudent.elementAt(x)+": "+((Lecture)bestLecture.elementAt(x)).conflictLecturesNames((String)bestStudent.elementAt(x)));
    294                    //sLogger.debug(" +"+((Lecture)bestLecture.elementAt(x)).getName()+" "+student+": "+((Lecture)bestLecture.elementAt(x)).conflictLecturesNames(student));
    295                    swap(student, (Lecture)bestLecture.elementAt(x), (String)bestStudent.elementAt(x), bestDelta);
    296                    ret.add(bestLecture.elementAt(x));
    297                    //sLogger.debug("Solution after swap is "+getModel().getInfo()+".");
    298                } else {
    299                    //sLogger.debug("no swap found");
    300                }
    301            } else for (Enumeration i1=conflictStudents.elements(); i1.hasMoreElements();) { //no same lecture
    302                String student = (String)i1.nextElement();
    303                int iniDelta=isInConflict(student);
    304                if (iniDelta==0) continue;
    305                int bestDelta=iniDelta;
    306                //sLogger.debug("student:"+student+", confs:"+bestDelta+" "+conflictLecturesNames(student));
    307                for (Enumeration i2=conflictLectures(student).elements(); i2.hasMoreElements();) {
    308                    Lecture anotherLecture = (Lecture)i2.nextElement();
    309                    if (!anotherLecture.equals(this) && anotherLecture.getAssignment()!=null && anotherLecture.sameLectures().size()>1) {
    310                        Set lects = anotherLecture.swapStudents();
    311                        if (lects!=null) ret.addAll(lects);
    312                    }
    313                }
    314            }
    315            return ret;
    316        }
    317        /** Prohibited swaps */
    318        public boolean isSwapTabu(String student, String swapStudent) {
    319            return false;
    320            //return iDoneSwaps.contains(student+","+swapStudent);
    321        }
    322        /** Swap two students between this and swapLecture*/
    323        private void justSwap(String student, Lecture swapLecture, String swapStudent) {
    324            Vector source = null, target = null;
    325            if (iAllStudents==null || iStudents.contains(student)) source = iStudents;
    326            else {
    327                for (Enumeration e=iCrossListedLectures.elements();source==null && e.hasMoreElements();) {
    328                    CrossListedLecture sl = (CrossListedLecture)e.nextElement();
    329                    if (sl.students().contains(student)) source=sl.students();
    330                }
    331            }
    332            if (swapLecture.iAllStudents==null || swapLecture.iStudents.contains(swapStudent)) target = swapLecture.iStudents;
    333            else {
    334                for (Enumeration e=swapLecture.iCrossListedLectures.elements();target==null && e.hasMoreElements();) {
    335                    CrossListedLecture sl = (CrossListedLecture)e.nextElement();
    336                    if (sl.students().contains(swapStudent)) target=sl.students();
    337                }
    338            }
    339            target.setElementAt(student, target.indexOf(swapStudent));
    340            source.setElementAt(swapStudent, source.indexOf(student));
    341            if (iAllStudents!=null)
    342                iAllStudents.setElementAt(swapStudent, iAllStudents.indexOf(student));
    343            if (swapLecture.iAllStudents!=null)
    344                swapLecture.iAllStudents.setElementAt(student, swapLecture.iAllStudents.indexOf(swapStudent));
    345            //swapLecture.iStudents.setElementAt(student, swapLecture.iStudents.indexOf(swapStudent));
    346            //iStudents.setElementAt(swapStudent, iStudents.indexOf(student));
    347        }
    348        /** Swap two students between this and swapLecture*/
    349        private void swap(String student, Lecture swapLecture, String swapStudent, int delta) {
    350            //iDoneSwaps.addElement(student+","+swapStudent);
    351            Vector jenrlsToRemove = new FastVector();
    352            for (Enumeration it=iJenrlConstraints.elements();it.hasMoreElements();) {
    353                JenrlConstraint jenrl = (JenrlConstraint)it.nextElement();
    354                for (Enumeration it2=jenrl.variables().elements();it2.hasMoreElements();) {
    355                    Lecture anotherLecture = (Lecture)it2.nextElement();
    356                    if (anotherLecture.equals(this)) continue;
    357                    if (anotherLecture.allStudents().contains(student)) {
    358                        //sLogger.debug(getName()+": jenr-- {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    359                        jenrl.decJenrl();
    360                        if (jenrl.getJenrl()==0) {
    361                            jenrlsToRemove.addElement(jenrl);
    362                            //sLogger.debug(getName()+": remove jenr {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    363                        }
    364                    }
    365                }
    366            }
    367            for (Enumeration it=swapLecture.iJenrlConstraints.elements();it.hasMoreElements();) {
    368                JenrlConstraint jenrl = (JenrlConstraint)it.nextElement();
    369                for (Enumeration it2=jenrl.variables().elements();it2.hasMoreElements();) {
    370                    Lecture anotherLecture = (Lecture)it2.nextElement();
    371                    if (anotherLecture.equals(swapLecture)) continue;
    372                    if (anotherLecture.allStudents().contains(swapStudent)) {
    373                        //sLogger.debug(swapLecture.getName()+": jenr-- {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    374                        jenrl.decJenrl();
    375                        if (jenrl.getJenrl()==0) {
    376                            jenrlsToRemove.addElement(jenrl);
    377                            //sLogger.debug(swapLecture.getName()+": remove jenr {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    378                        }
    379                    }
    380                }
    381            }
    382            if (!jenrlsToRemove.isEmpty()) {
    383                Object[] delete = jenrlsToRemove.toArray();
    384                for (int i=0;i<delete.length;i++) {
    385                    Constraint c = (Constraint)delete[i];
    386                    Object[] vars = c.variables().toArray();
    387                    for (int j=0;j<vars.length;j++)
    388                        c.removeVariable((Variable)vars[j]);
    389                    getModel().removeConstraint(c);
    390                }
    391            }
    392            justSwap(student, swapLecture, swapStudent);
    393            swapLecture.iSameStudents.clear();
    394            iSameStudents.clear();
    395            Vector jenrlsToAdd = new FastVector();
    396            for (Enumeration it=getModel().variables().elements(); it.hasMoreElements();) {
    397                Lecture anotherLecture = (Lecture)it.nextElement();
    398                if (anotherLecture.equals(this) || anotherLecture.equals(swapLecture)) continue;
    399                if (anotherLecture.allStudents().contains(swapStudent)) {
    400                    boolean found = false;
    401                    for (Enumeration itc=iJenrlConstraints.elements();!found && itc.hasMoreElements();) {
    402                        JenrlConstraint jenrl = (JenrlConstraint)itc.nextElement();
    403                        for (Enumeration it2=jenrl.variables().elements();it2.hasMoreElements();) {
    404                            Lecture xLecture = (Lecture)it2.nextElement();
    405                            if (xLecture.equals(anotherLecture)) {
    406                                found = true;
    407                                //sLogger.debug(getName()+": jenr++ {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    408                                jenrl.incJenrl();
    409                            }
    410                        }
    411                    }
    412                    if (!found) {
    413                        JenrlConstraint jenrl = new JenrlConstraint(1, ((TimetableModel)getModel()).getViolatedStudentConflictsCounter());
    414                        jenrl.addVariable(this);
    415                        jenrl.addVariable(anotherLecture);
    416                        //sLogger.debug(getName()+": add jenr {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    417                        jenrlsToAdd.addElement(jenrl);
    418                    }
    419                }
    420                if (anotherLecture.allStudents().contains(student)) {
    421                    boolean found = false;
    422                    for (Enumeration itc=swapLecture.iJenrlConstraints.elements();!found && itc.hasMoreElements();) {
    423                        JenrlConstraint jenrl = (JenrlConstraint)itc.nextElement();
    424                        for (Enumeration it2=jenrl.variables().elements();it2.hasMoreElements();) {
    425                            Lecture xLecture = (Lecture)it2.nextElement();
    426                            if (xLecture.equals(anotherLecture)) {
    427                                found = true;
    428                                //sLogger.debug(swapLecture.getName()+": jenr++ {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    429                                jenrl.incJenrl();
    430                            }
    431                        }
    432                    }
    433                    if (!found) {
    434                        JenrlConstraint jenrl = new JenrlConstraint(1, ((TimetableModel)getModel()).getViolatedStudentConflictsCounter());
    435                        jenrl.addVariable(swapLecture);
    436                        jenrl.addVariable(anotherLecture);
    437                        //sLogger.debug(swapLecture.getName()+": add jenr {conf="+jenrl.isInConflict()+", lect="+anotherLecture.getName()+", jenr="+jenrl+"}");
    438                        jenrlsToAdd.addElement(jenrl);
    439                    }
    440                }
    441            }
    442            if (!jenrlsToAdd.isEmpty()) {
    443                Object[] add = jenrlsToAdd.toArray();
    444                for (int i=0;i<add.length;i++)
    445                    getModel().addConstraint((Constraint)add[i]);
    446            }
    447        }
    448
    449        /** Domain -- all combinations of room and time locations */
    450        public Vector computeValues() {
    451            Vector values = new FastVector();
    452            iSameRoomValues = new Hashtable();
    453            for (Enumeration i2=iRoomLocations.elements();i2.hasMoreElements();) {
    454                RoomLocation roomLocation = (RoomLocation)i2.nextElement();
    455                Vector placements = new FastVector();
    456                for (Enumeration i1=iTimeLocations.elements();i1.hasMoreElements();) {
    457                    TimeLocation timeLocation = (TimeLocation)i1.nextElement();
    458                    Placement p = new Placement(this,timeLocation, roomLocation);
    459                    p.setVariable(this);
    460                    if (getInitialAssignment()!=null && p.equals(getInitialAssignment())) {
    461                        setInitialAssignment(p);
    462                        p.setInitial(true);
    463                    }
    464                    if (getAssignment()!=null && getAssignment().equals(p)) iValue=getAssignment();
    465                    if (getBestAssignment()!=null && getBestAssignment().equals(p)) setBestAssignment(p);
    466                    values.addElement(p);
    467                    placements.addElement(p);
    468                }
    469                iSameRoomValues.put(roomLocation.getId(),placements);
    470            }
    471            return values;
    472        }
    473
    474        /** All values which uses the given room */
    475        public Vector getSameRoomValues(String roomId) {
    476            if (sSaveMemory) {
    477                for (Enumeration i2=iRoomLocations.elements();i2.hasMoreElements();) {
    478                    RoomLocation roomLocation = (RoomLocation)i2.nextElement();
    479                    if (!roomLocation.getId().equals(roomId)) continue;
    480                    Vector placements = new FastVector();
    481                    for (Enumeration i1=iTimeLocations.elements();i1.hasMoreElements();) {
    482                        TimeLocation timeLocation = (TimeLocation)i1.nextElement();
    483                        Placement p = new Placement(this,timeLocation, roomLocation);
    484                        p.setVariable(this);
    485                        if (getInitialAssignment()!=null && p.equals(getInitialAssignment())) {
    486                            setInitialAssignment(p);
    487                            p.setInitial(true);
    488                        }
    489                        if (getAssignment()!=null && getAssignment().equals(p)) iValue=getAssignment();
    490                        if (getBestAssignment()!=null && getBestAssignment().equals(p)) setBestAssignment(p);
    491                        placements.addElement(p);
    492                    }
    493                    return placements;
    494                }
    495            }
    496            return (Vector)iSameRoomValues.get(roomId);
    497        }
    498
    499        /** All values */
    500        public Vector values() {
    501            if (sSaveMemory) {
    502                Vector values = new FastVector(iRoomLocations.size()*iTimeLocations.size());
    503                for (Enumeration i2=iRoomLocations.elements();i2.hasMoreElements();) {
    504                    RoomLocation roomLocation = (RoomLocation)i2.nextElement();
    505                    Vector placements = new FastVector();
    506                    for (Enumeration i1=iTimeLocations.elements();i1.hasMoreElements();) {
    507                        TimeLocation timeLocation = (TimeLocation)i1.nextElement();
    508                        Placement p = new Placement(this,timeLocation, roomLocation);
    509                        p.setVariable(this);
    510                        if (getInitialAssignment()!=null && p.equals(getInitialAssignment())) {
    511                            setInitialAssignment(p);
    512                            p.setInitial(true);
    513                        }
    514                        if (getAssignment()!=null && getAssignment().equals(p)) iValue=getAssignment();
    515                        if (getBestAssignment()!=null && getBestAssignment().equals(p)) setBestAssignment(p);
    516                        values.addElement(p);
    517                    }
    518                }
    519                return values;
    520            } else
    521                return super.values();
    522        }
    523
    524        public boolean equals(Object o) {
    525            try {
    526                return getId()==((Lecture)o).getId();
    527            } catch (Exception e) {
    528                return false;
    529            }
    530        }
    531
    532        /** Best time preference of this lecture */
    533        public double getBestTimePreference() { return iBestTimePref; }
    534        /** Best room preference of this lecture */
    535        public int getBestRoomPreference() { return iBestRoomPref; }
    536
    537        /** Number of student conflicts caused by the given assignment of this lecture */
    538        public int countStudentConflicts(Value value) {
    539            int studentConflictsSum = 0;
    540            for (Enumeration i=jenrlConstraints().elements();i.hasMoreElements();) {
    541                JenrlConstraint jenrl = (JenrlConstraint)i.nextElement();
    542                studentConflictsSum += jenrl.jenrl(this, value);
    543            }
    544            return studentConflictsSum;
    545        }
    546
    547        /** Number of student conflicts caused by the initial assignment of this lecture */
    548        public int countInitialStudentConflicts() {
    549            Value value = getInitialAssignment();
    550            if (value==null) return 0;
    551            int studentConflictsSum = 0;
    552            for (Enumeration i=jenrlConstraints().elements();i.hasMoreElements();) {
    553                JenrlConstraint jenrl = (JenrlConstraint)i.nextElement();
    554                Lecture another = (Lecture)jenrl.another(this);
    555                if (another.getInitialAssignment()!=null)
    556                    if (JenrlConstraint.isInConflict((Placement)value,(Placement)another.getInitialAssignment()))
    557                        studentConflictsSum += jenrl.getJenrl();
    558            }
    559            return studentConflictsSum;
    560        }
    561
    562        /** Table of student conflicts caused by the initial assignment of this lecture in format (another lecture, number)*/
    563        public Hashtable getInitialStudentConflicts() {
    564            Value value = getInitialAssignment();
    565            if (value==null) return null;
    566            Hashtable ret = new Hashtable();
    567            for (Enumeration i=jenrlConstraints().elements();i.hasMoreElements();) {
    568                JenrlConstraint jenrl = (JenrlConstraint)i.nextElement();
    569                Lecture another = (Lecture)jenrl.another(this);
    570                if (another.getInitialAssignment()!=null)
    571                    if (JenrlConstraint.isInConflict((Placement)value,(Placement)another.getInitialAssignment()))
    572                        ret.put(another,new Long(jenrl.getJenrl()));
    573            }
    574            return ret;
    575        }
    576
    577        /** List of student conflicts caused by the initial assignment of this lecture */
    578        public Set initialStudentConflicts() {
    579            Value value = getInitialAssignment();
    580            if (value==null) return null;
    581            HashSet ret = new HashSet();
    582            for (Enumeration i=jenrlConstraints().elements();i.hasMoreElements();) {
    583                JenrlConstraint jenrl = (JenrlConstraint)i.nextElement();
    584                Lecture another = (Lecture)jenrl.another(this);
    585                if (another.getInitialAssignment()!=null)
    586                    if (JenrlConstraint.isInConflict((Placement)value,(Placement)another.getInitialAssignment()))
    587                        ret.addAll(sameStudents(another));
    588            }
    589            return ret;
    590        }
    591
    592        public void addContstraint(Constraint constraint) {
    593            super.addContstraint(constraint);
    594            if (constraint instanceof JenrlConstraint)
    595                iJenrlConstraints.addElement(constraint);
    596            else if (constraint instanceof DepartmentSpreadConstraint)
    597                iDeptSpreadConstrain = (DepartmentSpreadConstraint)constraint;
    598            else if (constraint instanceof InstructorConstraint)
    599                iInstructorConstraint = (InstructorConstraint)constraint;
    600        }
    601        public void removeContstraint(Constraint constraint) {
    602            super.removeContstraint(constraint);
    603            if (iJenrlConstraints.contains(constraint))
    604                iJenrlConstraints.removeElement(constraint);
    605        }
    606
    607        /** All JENRL constraints of this lecture */
    608        public Vector jenrlConstraints() {
    609            return iJenrlConstraints;
    610        }
    611
    612        /** Expected capacity */
    613        public long countStudents() {
    614            return iExpectedCapacity;
    615            /*if (iNrStudents>=0) return iNrStudents;
    616            long ret = 0;
    617            for (Enumeration i=jenrlConstraints().elements();i.hasMoreElements();) {
    618                ret += ((JenrlConstraint)i.nextElement()).getJenrl();
    619            }
    620            iNrStudents = ret;
    621            ToolBox.print("Class "+getName()+" has "+ret+(students()==null?"":" ("+students().size()+")")+" students.");
    622            return ret;*/
    623        }
    624
    625        public String toString() {
    626            return getName()+" ["+getDescription()+"]";//"Lecture{name='"+getName()+"', time="+(getAssignment()==null?"?":String.valueOf(((Placement)getAssignment()).getTimeLocation().getNormalizedPreference()))+"/"+iBestTimePref+", room="+(getAssignment()==null?"?":String.valueOf(((Placement)getAssignment()).getRoomLocation().getPreference()))+"/"+iBestRoomPref+", super="+super.toString()+"}";
    627        }
    628
    629        /** Description */
    630        public String getDescription() {
    631            return (iPattern==null?"":iPattern+", ")+iExpectedCapacity+" exp. students"+
    632                   (iBestTimePref!=0?", "+iBestTimePref+" best time pref.":"")+
    633                   (iBestRoomPref!=0?", "+iBestRoomPref+" best room pref.":"")+
    634                   (getInitialAssignment()==null?"":", initial "+getInitialAssignment().getName())+
    635                   ", "+(values().size()==1?"value "+((Placement)values().firstElement()).getName()+" required":values().size()<=5?"values=["+getValuesString()+"]":values().size()+" values");
    636        }
    637
    638        public String getValuesString() {
    639            StringBuffer sb = new StringBuffer();
    640            for (Enumeration e=values().elements();e.hasMoreElements();) {
    641                Placement p = (Placement)e.nextElement();
    642                sb.append(p.getName()).append(e.hasMoreElements()?", ":"");
    643            }
    644            return sb.toString();
    645        }
    646
    647        /** Department */
    648        public String getDepartment() { return iDept;}
    649        /** Department */
    650        public void setDepartment(String dept) { iDept=dept; }
    651        /** Departmental spreading constraint */
    652        public DepartmentSpreadConstraint getDeptSpreadConstraint() { return iDeptSpreadConstrain; }
    653        /** Instructor constraint */
    654        public InstructorConstraint getInstructorConstraint() { return iInstructorConstraint; }
    655        /** All room locations */
    656        public Vector roomLocations() { return iRoomLocations; }
    657        /** All time locations */
    658        public Vector timeLocations() { return iTimeLocations; }
    659    }