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    }