001package net.sf.cpsolver.coursett.model;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.Comparator;
006import java.util.HashSet;
007import java.util.HashMap;
008import java.util.Iterator;
009import java.util.List;
010import java.util.Map;
011import java.util.Set;
012
013import net.sf.cpsolver.coursett.Constants;
014import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint;
015import net.sf.cpsolver.coursett.constraint.DepartmentSpreadConstraint;
016import net.sf.cpsolver.coursett.constraint.FlexibleConstraint;
017import net.sf.cpsolver.coursett.constraint.GroupConstraint;
018import net.sf.cpsolver.coursett.constraint.IgnoreStudentConflictsConstraint;
019import net.sf.cpsolver.coursett.constraint.InstructorConstraint;
020import net.sf.cpsolver.coursett.constraint.JenrlConstraint;
021import net.sf.cpsolver.coursett.constraint.RoomConstraint;
022import net.sf.cpsolver.coursett.constraint.SpreadConstraint;
023import net.sf.cpsolver.coursett.criteria.StudentCommittedConflict;
024import net.sf.cpsolver.coursett.criteria.StudentConflict;
025import net.sf.cpsolver.ifs.constant.ConstantVariable;
026import net.sf.cpsolver.ifs.model.Constraint;
027import net.sf.cpsolver.ifs.model.GlobalConstraint;
028import net.sf.cpsolver.ifs.model.Variable;
029import net.sf.cpsolver.ifs.model.WeakeningConstraint;
030import net.sf.cpsolver.ifs.util.DistanceMetric;
031
032/**
033 * Lecture (variable).
034 * 
035 * @version CourseTT 1.2 (University Course Timetabling)<br>
036 *          Copyright (C) 2006 - 2010 Tomáš Müller<br>
037 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
038 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
039 * <br>
040 *          This library is free software; you can redistribute it and/or modify
041 *          it under the terms of the GNU Lesser General Public License as
042 *          published by the Free Software Foundation; either version 3 of the
043 *          License, or (at your option) any later version. <br>
044 * <br>
045 *          This library is distributed in the hope that it will be useful, but
046 *          WITHOUT ANY WARRANTY; without even the implied warranty of
047 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
048 *          Lesser General Public License for more details. <br>
049 * <br>
050 *          You should have received a copy of the GNU Lesser General Public
051 *          License along with this library; if not see
052 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
053 */
054
055public class Lecture extends Variable<Lecture, Placement> implements ConstantVariable {
056    private Long iClassId;
057    private Long iSolverGroupId;
058    private Long iSchedulingSubpartId;
059    private String iName;
060    private Long iDept;
061    private Long iScheduler;
062    private List<TimeLocation> iTimeLocations;
063    private List<RoomLocation> iRoomLocations;
064    private String iNote = null;
065
066    private int iMinClassLimit;
067    private int iMaxClassLimit;
068    private float iRoomToLimitRatio;
069    private int iNrRooms;
070    private int iOrd;
071    private double iWeight = 1.0;
072
073    private Set<Student> iStudents = new HashSet<Student>();
074    private DepartmentSpreadConstraint iDeptSpreadConstraint = null;
075    private Set<SpreadConstraint> iSpreadConstraints = new HashSet<SpreadConstraint>();
076    private Set<Constraint<Lecture, Placement>> iWeakeningConstraints = new HashSet<Constraint<Lecture, Placement>>();
077    private List<InstructorConstraint> iInstructorConstraints = new ArrayList<InstructorConstraint>();
078    private Set<Long> iIgnoreStudentConflictsWith = null;
079    private ClassLimitConstraint iClassLimitConstraint = null;
080
081    private Lecture iParent = null;
082    private HashMap<Long, List<Lecture>> iChildren = null;
083    private java.util.List<Lecture> iSameSubpartLectures = null;
084    private Configuration iParentConfiguration = null;
085
086    private Set<JenrlConstraint> iActiveJenrls = new HashSet<JenrlConstraint>();
087    private List<JenrlConstraint> iJenrlConstraints = new ArrayList<JenrlConstraint>();
088    private HashMap<Lecture, JenrlConstraint> iJenrlConstraintsHash = new HashMap<Lecture, JenrlConstraint>();
089    private HashMap<Placement, Integer> iCommitedConflicts = new HashMap<Placement, Integer>();
090    private Set<GroupConstraint> iGroupConstraints = new HashSet<GroupConstraint>();
091    private Set<GroupConstraint> iHardGroupSoftConstraints = new HashSet<GroupConstraint>();
092    private Set<GroupConstraint> iCanShareRoomGroupConstraints = new HashSet<GroupConstraint>();
093    private Set<FlexibleConstraint> iFlexibleGroupConstraints = new HashSet<FlexibleConstraint>();    
094
095    public boolean iCommitted = false;
096
097    public static boolean sSaveMemory = false;
098    public static boolean sAllowBreakHard = false;
099
100    private Integer iCacheMinRoomSize = null;
101    private Integer iCacheMaxRoomSize = null;
102    private Integer iCacheMaxAchievableClassLimit = null;
103
104    /**
105     * Constructor
106     * 
107     * @param id
108     *            unique identification
109     * @param name
110     *            class name
111     * @param timeLocations
112     *            set of time locations
113     * @param roomLocations
114     *            set of room location
115     * @param initialPlacement
116     *            initial placement
117     */
118    public Lecture(Long id, Long solverGroupId, Long schedulingSubpartId, String name,
119            java.util.List<TimeLocation> timeLocations, java.util.List<RoomLocation> roomLocations, int nrRooms,
120            Placement initialPlacement, int minClassLimit, int maxClassLimit, double room2limitRatio) {
121        super(initialPlacement);
122        iClassId = id;
123        iSchedulingSubpartId = schedulingSubpartId;
124        iTimeLocations = new ArrayList<TimeLocation>(timeLocations);
125        iRoomLocations = new ArrayList<RoomLocation>(roomLocations);
126        iName = name;
127        iMinClassLimit = minClassLimit;
128        iMaxClassLimit = maxClassLimit;
129        iRoomToLimitRatio = (float)room2limitRatio;
130        iNrRooms = nrRooms;
131        iSolverGroupId = solverGroupId;
132    }
133
134    public Lecture(Long id, Long solverGroupId, String name) {
135        super(null);
136        iClassId = id;
137        iSolverGroupId = solverGroupId;
138        iName = name;
139    }
140
141    public Long getSolverGroupId() {
142        return iSolverGroupId;
143    }
144
145    /**
146     * Add active jenrl constraint (active mean that there is at least one
147     * student between its classes)
148     */
149    public void addActiveJenrl(JenrlConstraint constr) {
150        iActiveJenrls.add(constr);
151    }
152
153    /**
154     * Active jenrl constraints (active mean that there is at least one student
155     * between its classes)
156     */
157    public Set<JenrlConstraint> activeJenrls() {
158        return iActiveJenrls;
159    }
160
161    /**
162     * Remove active jenrl constraint (active mean that there is at least one
163     * student between its classes)
164     */
165    public void removeActiveJenrl(JenrlConstraint constr) {
166        iActiveJenrls.remove(constr);
167    }
168
169    /** Class id */
170    public Long getClassId() {
171        return iClassId;
172    }
173
174    public Long getSchedulingSubpartId() {
175        return iSchedulingSubpartId;
176    }
177
178    /** Class name */
179    @Override
180    public String getName() {
181        return iName;
182    }
183
184    /** Class id */
185    @Override
186    public long getId() {
187        return iClassId.longValue();
188    }
189
190    /** Instructor name */
191    public List<String> getInstructorNames() {
192        List<String> ret = new ArrayList<String>();
193        for (InstructorConstraint ic : iInstructorConstraints) {
194            ret.add(ic.getName());
195        }
196        return ret;
197    }
198
199    public String getInstructorName() {
200        StringBuffer sb = new StringBuffer();
201        for (InstructorConstraint ic : iInstructorConstraints) {
202            if (sb.length() > 0)
203                sb.append(", ");
204            sb.append(ic.getName());
205        }
206        return sb.toString();
207    }
208
209    /** List of enrolled students */
210    public Set<Student> students() {
211        return iStudents;
212    }
213
214    public double nrWeightedStudents() {
215        double w = 0.0;
216        for (Student s : iStudents) {
217            w += s.getOfferingWeight(getConfiguration());
218        }
219        return w;
220    }
221
222    /** Add an enrolled student */
223    public void addStudent(Student student) {
224        if (!iStudents.add(student))
225            return;
226        if (getAssignment() != null && getModel() != null)
227            getModel().getCriterion(StudentCommittedConflict.class).inc(student.countConflictPlacements(getAssignment()));
228        iCommitedConflicts.clear();
229    }
230
231    public void removeStudent(Student student) {
232        if (!iStudents.remove(student))
233            return;
234        if (getAssignment() != null && getModel() != null)
235            if (getAssignment() != null && getModel() != null)
236                getModel().getCriterion(StudentCommittedConflict.class).inc(-student.countConflictPlacements(getAssignment()));
237        iCommitedConflicts.clear();
238    }
239
240    /** Returns true if the given student is enrolled */
241    public boolean hasStudent(Student student) {
242        return iStudents.contains(student);
243    }
244
245    /** Set of lectures of the same class (only section is different) */
246    public void setSameSubpartLectures(java.util.List<Lecture> sameSubpartLectures) {
247        iSameSubpartLectures = sameSubpartLectures;
248    }
249
250    /** Set of lectures of the same class (only section is different) */
251    public java.util.List<Lecture> sameSubpartLectures() {
252        return iSameSubpartLectures;
253    }
254
255    /** List of students enrolled in this class as well as in the given class */
256    public Set<Student> sameStudents(Lecture lecture) {
257        JenrlConstraint jenrl = jenrlConstraint(lecture);
258        return (jenrl == null ? new HashSet<Student>() : jenrl.getStudents());
259    }
260
261    /** List of students of this class in conflict with the given assignment */
262    public Set<Student> conflictStudents(Placement value) {
263        if (value == null)
264            return new HashSet<Student>();
265        if (value.equals(getAssignment()))
266            return conflictStudents();
267        Set<Student> ret = new HashSet<Student>();
268        for (JenrlConstraint jenrl : jenrlConstraints()) {
269            if (jenrl.jenrl(this, value) > 0)
270                ret.addAll(sameStudents(jenrl.another(this)));
271        }
272        return ret;
273    }
274
275    /**
276     * List of students of this class which are in conflict with any other
277     * assignment
278     */
279    public Set<Student> conflictStudents() {
280        Set<Student> ret = new HashSet<Student>();
281        if (getAssignment() == null)
282            return ret;
283        for (JenrlConstraint jenrl : activeJenrls()) {
284            ret.addAll(sameStudents(jenrl.another(this)));
285        }
286        Placement placement = getAssignment();
287        for (Student student : students()) {
288            if (student.countConflictPlacements(placement) > 0)
289                ret.add(student);
290        }
291        return ret;
292    }
293
294    /**
295     * Lectures different from this one, where it is student conflict of the
296     * given student between this and the lecture
297     */
298    public List<Lecture> conflictLectures(Student student) {
299        List<Lecture> ret = new ArrayList<Lecture>();
300        if (getAssignment() == null)
301            return ret;
302        for (JenrlConstraint jenrl : activeJenrls()) {
303            Lecture lect = jenrl.another(this);
304            if (lect.students().contains(student))
305                ret.add(lect);
306        }
307        return ret;
308    }
309
310    /** True if this lecture is in a student conflict with the given student */
311    public int isInConflict(Student student) {
312        if (getAssignment() == null)
313            return 0;
314        int ret = 0;
315        for (JenrlConstraint jenrl : activeJenrls()) {
316            Lecture lect = jenrl.another(this);
317            if (lect.students().contains(student))
318                ret++;
319        }
320        return ret;
321    }
322
323    private void computeValues(List<Placement> values, boolean allowBreakHard, TimeLocation timeLocation,
324            List<RoomLocation> roomLocations, int idx) {
325        if (roomLocations.size() == iNrRooms) {
326            Placement p = new Placement(this, timeLocation, roomLocations);
327            p.setVariable(this);
328            if (sSaveMemory && !isValid(p))
329                return;
330            if (getInitialAssignment() != null && p.equals(getInitialAssignment()))
331                setInitialAssignment(p);
332            if (getAssignment() != null && getAssignment().equals(p))
333                iValue = getAssignment();
334            if (getBestAssignment() != null && getBestAssignment().equals(p))
335                setBestAssignment(p);
336            values.add(p);
337            return;
338        }
339        for (int i = idx; i < iRoomLocations.size(); i++) {
340            RoomLocation roomLocation = iRoomLocations.get(i);
341            if (!allowBreakHard
342                    && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(roomLocation
343                            .getPreference())))
344                continue;
345
346            if (roomLocation.getRoomConstraint() != null
347                    && !roomLocation.getRoomConstraint().isAvailable(this, timeLocation, getScheduler()))
348                continue;
349            roomLocations.add(roomLocation);
350            computeValues(values, allowBreakHard, timeLocation, roomLocations, i + 1);
351            roomLocations.remove(roomLocations.size() - 1);
352        }
353    }
354
355    /** Domain -- all combinations of room and time locations */
356    public List<Placement> computeValues(boolean allowBreakHard) {
357        List<Placement> values = new ArrayList<Placement>(iRoomLocations.size() * iTimeLocations.size());
358        for (TimeLocation timeLocation : iTimeLocations) {
359            if (!allowBreakHard
360                    && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(timeLocation
361                            .getPreference())))
362                continue;
363            if (timeLocation.getPreference() > 500)
364                continue;
365            boolean notAvailable = false;
366            for (InstructorConstraint ic : getInstructorConstraints()) {
367                if (!ic.isAvailable(this, timeLocation)) {
368                    notAvailable = true;
369                    break;
370                }
371            }
372            if (notAvailable)
373                continue;
374            if (iNrRooms == 0) {
375                Placement p = new Placement(this, timeLocation, (RoomLocation) null);
376                for (InstructorConstraint ic : getInstructorConstraints()) {
377                    if (!ic.isAvailable(this, p)) {
378                        notAvailable = true;
379                        break;
380                    }
381                }
382                if (notAvailable)
383                    continue;
384                p.setVariable(this);
385                if (sSaveMemory && !isValid(p))
386                    continue;
387                if (getInitialAssignment() != null && p.equals(getInitialAssignment()))
388                    setInitialAssignment(p);
389                if (getAssignment() != null && getAssignment().equals(p))
390                    iValue = getAssignment();
391                if (getBestAssignment() != null && getBestAssignment().equals(p))
392                    setBestAssignment(p);
393                values.add(p);
394            } else if (iNrRooms == 1) {
395                for (RoomLocation roomLocation : iRoomLocations) {
396                    if (!allowBreakHard
397                            && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(roomLocation
398                                    .getPreference())))
399                        continue;
400                    if (roomLocation.getPreference() > 500)
401                        continue;
402                    if (roomLocation.getRoomConstraint() != null
403                            && !roomLocation.getRoomConstraint().isAvailable(this, timeLocation, getScheduler()))
404                        continue;
405                    Placement p = new Placement(this, timeLocation, roomLocation);
406                    p.setVariable(this);
407                    if (sSaveMemory && !isValid(p))
408                        continue;
409                    if (getInitialAssignment() != null && p.equals(getInitialAssignment()))
410                        setInitialAssignment(p);
411                    if (getAssignment() != null && getAssignment().equals(p))
412                        iValue = getAssignment();
413                    if (getBestAssignment() != null && getBestAssignment().equals(p))
414                        setBestAssignment(p);
415                    values.add(p);
416                }
417            } else {
418                computeValues(values, allowBreakHard, timeLocation, new ArrayList<RoomLocation>(iNrRooms), 0);
419            }
420        }
421        return values;
422    }
423    
424    public void clearValueCache() {
425        super.setValues(null);
426    }
427
428    /** All values */
429    @Override
430    public List<Placement> values() {
431        if (super.values() == null) {
432            if (getInitialAssignment() != null && iTimeLocations.size() == 1 && iRoomLocations.size() == getNrRooms()) {
433                List<Placement> values = new ArrayList<Placement>(1);
434                values.add(getInitialAssignment());
435                setValues(values);
436            } else {
437                if (isCommitted() || !sSaveMemory)
438                    setValues(computeValues(sAllowBreakHard));
439            }
440        }
441        if (isCommitted())
442            return super.values();
443        if (sSaveMemory) {
444            return computeValues(sAllowBreakHard);
445        } else
446            return super.values();
447    }
448
449    @Override
450    public boolean equals(Object o) {
451        if (o == null || !(o instanceof Lecture))
452            return false;
453        return getClassId().equals(((Lecture) o).getClassId());
454    }
455
456    /** Best time preference of this lecture */
457    private Double iBestTimePreferenceCache = null;
458
459    public double getBestTimePreference() {
460        if (iBestTimePreferenceCache == null) {
461            double ret = Double.MAX_VALUE;
462            for (TimeLocation time : iTimeLocations) {
463                ret = Math.min(ret, time.getNormalizedPreference());
464            }
465            iBestTimePreferenceCache = new Double(ret);
466        }
467        return iBestTimePreferenceCache.doubleValue();
468    }
469
470    /** Best room preference of this lecture */
471    public int getBestRoomPreference() {
472        int ret = Integer.MAX_VALUE;
473        for (RoomLocation room : iRoomLocations) {
474            ret = Math.min(ret, room.getPreference());
475        }
476        return ret;
477    }
478
479    /**
480     * Number of student conflicts caused by the given assignment of this
481     * lecture
482     */
483    public int countStudentConflicts(Placement value) {
484        int studentConflictsSum = 0;
485        for (JenrlConstraint jenrl : jenrlConstraints()) {
486            studentConflictsSum += jenrl.jenrl(this, value);
487        }
488        return studentConflictsSum;
489    }
490
491    public int countStudentConflictsOfTheSameProblem(Placement value) {
492        int studentConflictsSum = 0;
493        for (JenrlConstraint jenrl : jenrlConstraints()) {
494            if (!jenrl.isOfTheSameProblem())
495                continue;
496            studentConflictsSum += jenrl.jenrl(this, value);
497        }
498        return studentConflictsSum;
499    }
500
501    public int countHardStudentConflicts(Placement value) {
502        int studentConflictsSum = 0;
503        if (!isSingleSection())
504            return 0;
505        for (JenrlConstraint jenrl : jenrlConstraints()) {
506            if (!jenrl.areStudentConflictsHard())
507                continue;
508            studentConflictsSum += jenrl.jenrl(this, value);
509        }
510        return studentConflictsSum;
511    }
512
513    public int countCommittedStudentConflictsOfTheSameProblem(Placement value) {
514        int studentConflictsSum = 0;
515        for (JenrlConstraint jenrl : jenrlConstraints()) {
516            if (!jenrl.isOfTheSameProblem())
517                continue;
518            if (!jenrl.areStudentConflictsCommitted())
519                continue;
520            studentConflictsSum += jenrl.jenrl(this, value);
521        }
522        return studentConflictsSum;
523    }
524    
525    public int countCommittedStudentConflicts(Placement value) {
526        int studentConflictsSum = 0;
527        for (JenrlConstraint jenrl : jenrlConstraints()) {
528            if (!jenrl.areStudentConflictsCommitted())
529                continue;
530            studentConflictsSum += jenrl.jenrl(this, value);
531        }
532        return studentConflictsSum;
533    }
534
535    public int countHardStudentConflictsOfTheSameProblem(Placement value) {
536        int studentConflictsSum = 0;
537        for (JenrlConstraint jenrl : jenrlConstraints()) {
538            if (!jenrl.isOfTheSameProblem())
539                continue;
540            if (!jenrl.areStudentConflictsHard())
541                continue;
542            studentConflictsSum += jenrl.jenrl(this, value);
543        }
544        return studentConflictsSum;
545    }
546
547    public int countDistanceStudentConflicts(Placement value) {
548        int studentConflictsSum = 0;
549        for (JenrlConstraint jenrl : jenrlConstraints()) {
550            if (!jenrl.areStudentConflictsDistance(value))
551                continue;
552            studentConflictsSum += jenrl.jenrl(this, value);
553        }
554        return studentConflictsSum;
555    }
556
557    public int countDistanceStudentConflictsOfTheSameProblem(Placement value) {
558        int studentConflictsSum = 0;
559        for (JenrlConstraint jenrl : jenrlConstraints()) {
560            if (!jenrl.isOfTheSameProblem())
561                continue;
562            if (!jenrl.areStudentConflictsDistance(value))
563                continue;
564            studentConflictsSum += jenrl.jenrl(this, value);
565        }
566        return studentConflictsSum;
567    }
568    
569    private DistanceMetric getDistanceMetric() {
570        return ((TimetableModel)getModel()).getDistanceMetric();
571    }
572
573    /**
574     * Number of student conflicts caused by the initial assignment of this
575     * lecture
576     */
577    public int countInitialStudentConflicts() {
578        Placement value = getInitialAssignment();
579        if (value == null)
580            return 0;
581        int studentConflictsSum = 0;
582        for (JenrlConstraint jenrl : jenrlConstraints()) {
583            Lecture another = jenrl.another(this);
584            if (another.getInitialAssignment() != null)
585                if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric()))
586                    studentConflictsSum += jenrl.getJenrl();
587        }
588        return studentConflictsSum;
589    }
590
591    /**
592     * Table of student conflicts caused by the initial assignment of this
593     * lecture in format (another lecture, number)
594     */
595    public Map<Lecture, Long> getInitialStudentConflicts() {
596        Placement value = getInitialAssignment();
597        if (value == null)
598            return null;
599        Map<Lecture, Long> ret = new HashMap<Lecture, Long>();
600        for (JenrlConstraint jenrl : jenrlConstraints()) {
601            Lecture another = jenrl.another(this);
602            if (another.getInitialAssignment() != null)
603                if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric()))
604                    ret.put(another, jenrl.getJenrl());
605        }
606        return ret;
607    }
608
609    /**
610     * List of student conflicts caused by the initial assignment of this
611     * lecture
612     */
613    public Set<Student> initialStudentConflicts() {
614        Placement value = getInitialAssignment();
615        if (value == null)
616            return null;
617        HashSet<Student> ret = new HashSet<Student>();
618        for (JenrlConstraint jenrl : jenrlConstraints()) {
619            Lecture another = jenrl.another(this);
620            if (another.getInitialAssignment() != null)
621                if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric()))
622                    ret.addAll(sameStudents(another));
623        }
624        return ret;
625    }
626
627    @Override
628    public void addContstraint(Constraint<Lecture, Placement> constraint) {
629        super.addContstraint(constraint);
630
631        if (constraint instanceof WeakeningConstraint)
632            iWeakeningConstraints.add(constraint);
633        
634        if (constraint instanceof FlexibleConstraint)
635            iFlexibleGroupConstraints.add((FlexibleConstraint) constraint);
636
637        if (constraint instanceof JenrlConstraint) {
638            JenrlConstraint jenrl = (JenrlConstraint) constraint;
639            Lecture another = jenrl.another(this);
640            if (another != null) {
641                iJenrlConstraints.add(jenrl);
642                another.iJenrlConstraints.add(jenrl);
643                iJenrlConstraintsHash.put(another, (JenrlConstraint) constraint);
644                another.iJenrlConstraintsHash.put(this, (JenrlConstraint) constraint);
645            }
646        } else if (constraint instanceof DepartmentSpreadConstraint)
647            iDeptSpreadConstraint = (DepartmentSpreadConstraint) constraint;
648        else if (constraint instanceof SpreadConstraint)
649            iSpreadConstraints.add((SpreadConstraint) constraint);
650        else if (constraint instanceof InstructorConstraint) {
651            InstructorConstraint ic = (InstructorConstraint) constraint;
652            if (ic.getResourceId() != null && ic.getResourceId().longValue() > 0)
653                iInstructorConstraints.add(ic);
654        } else if (constraint instanceof ClassLimitConstraint)
655            iClassLimitConstraint = (ClassLimitConstraint) constraint;
656        else if (constraint instanceof GroupConstraint) {
657            GroupConstraint gc = (GroupConstraint) constraint;
658            if (gc.canShareRoom()) {
659                iCanShareRoomGroupConstraints.add((GroupConstraint) constraint);
660            } else {
661                iGroupConstraints.add((GroupConstraint) constraint);
662                if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(gc.getPreference()))
663                        || Constants.sPreferenceRequired.equals(Constants
664                                .preferenceLevel2preference(gc.getPreference())))
665                    iHardGroupSoftConstraints.add((GroupConstraint) constraint);
666            }
667        }
668    }
669
670    @Override
671    public void removeContstraint(Constraint<Lecture, Placement> constraint) {
672        super.removeContstraint(constraint);
673
674        if (constraint instanceof WeakeningConstraint)
675            iWeakeningConstraints.remove(constraint);
676        
677        if (constraint instanceof FlexibleConstraint)
678            iFlexibleGroupConstraints.remove(constraint);
679
680        if (constraint instanceof JenrlConstraint) {
681            JenrlConstraint jenrl = (JenrlConstraint) constraint;
682            Lecture another = jenrl.another(this);
683            if (another != null) {
684                iJenrlConstraints.remove(jenrl);
685                another.iJenrlConstraints.remove(jenrl);
686                iJenrlConstraintsHash.remove(another);
687                another.iJenrlConstraintsHash.remove(this);
688            }
689        } else if (constraint instanceof GroupConstraint) {
690            iCanShareRoomGroupConstraints.remove(constraint);
691            iHardGroupSoftConstraints.remove(constraint);
692            iGroupConstraints.remove(constraint);
693        } else if (constraint instanceof DepartmentSpreadConstraint)
694            iDeptSpreadConstraint = null;
695        else if (constraint instanceof SpreadConstraint)
696            iSpreadConstraints.remove(constraint);
697        else if (constraint instanceof InstructorConstraint)
698            iInstructorConstraints.remove(constraint);
699        else if (constraint instanceof ClassLimitConstraint)
700            iClassLimitConstraint = null;
701    }
702
703    /** All JENRL constraints of this lecture */
704    public JenrlConstraint jenrlConstraint(Lecture another) {
705        /*
706         * for (Enumeration e=iJenrlConstraints.elements();e.hasMoreElements();)
707         * { JenrlConstraint jenrl = (JenrlConstraint)e.nextElement(); if
708         * (jenrl.another(this).equals(another)) return jenrl; } return null;
709         */
710        return iJenrlConstraintsHash.get(another);
711    }
712
713    public List<JenrlConstraint> jenrlConstraints() {
714        return iJenrlConstraints;
715    }
716
717    public int minClassLimit() {
718        return iMinClassLimit;
719    }
720
721    public int maxClassLimit() {
722        return iMaxClassLimit;
723    }
724
725    public int maxAchievableClassLimit() {
726        if (iCacheMaxAchievableClassLimit != null)
727            return iCacheMaxAchievableClassLimit.intValue();
728
729        int maxAchievableClassLimit = Math.min(maxClassLimit(), (int) Math.floor(maxRoomSize() / roomToLimitRatio()));
730
731        if (hasAnyChildren()) {
732
733            for (Long subpartId: getChildrenSubpartIds()) {
734                int maxAchievableChildrenLimit = 0;
735
736                for (Lecture child : getChildren(subpartId)) {
737                    maxAchievableChildrenLimit += child.maxAchievableClassLimit();
738                }
739
740                maxAchievableClassLimit = Math.min(maxAchievableClassLimit, maxAchievableChildrenLimit);
741            }
742        }
743
744        maxAchievableClassLimit = Math.max(minClassLimit(), maxAchievableClassLimit);
745        iCacheMaxAchievableClassLimit = new Integer(maxAchievableClassLimit);
746        return maxAchievableClassLimit;
747    }
748
749    public int classLimit() {
750        if (minClassLimit() == maxClassLimit())
751            return minClassLimit();
752        return classLimit(null, null);
753    }
754
755    public int classLimit(Placement assignment, Set<Placement> conflicts) {
756        Placement a = getAssignment();
757        if (assignment != null && assignment.variable().equals(this))
758            a = assignment;
759        if (conflicts != null && a != null && conflicts.contains(a))
760            a = null;
761        int classLimit = (a == null ? maxAchievableClassLimit() : Math.min(maxClassLimit(), (int) Math.floor(a.getRoomSize() / roomToLimitRatio())));
762
763        if (!hasAnyChildren())
764            return classLimit;
765
766        for (Long subpartId: getChildrenSubpartIds()) {
767            int childrenClassLimit = 0;
768
769            for (Lecture child : getChildren(subpartId)) {
770                childrenClassLimit += child.classLimit(assignment, conflicts);
771            }
772
773            classLimit = Math.min(classLimit, childrenClassLimit);
774        }
775
776        return Math.max(minClassLimit(), classLimit);
777    }
778
779    public double roomToLimitRatio() {
780        return iRoomToLimitRatio;
781    }
782
783    public int minRoomUse() {
784        return (int) Math.ceil(iMinClassLimit * iRoomToLimitRatio);
785    }
786
787    public int maxRoomUse() {
788        return (int) Math.ceil(iMaxClassLimit * iRoomToLimitRatio);
789    }
790
791    @Override
792    public String toString() {
793        return getName();
794    }
795
796    public String getValuesString() {
797        StringBuffer sb = new StringBuffer();
798        for (Placement p : values()) {
799            if (sb.length() > 0)
800                sb.append(", ");
801            sb.append(p.getName());
802        }
803        return sb.toString();
804    }
805
806    /** Controlling Course Offering Department */
807    public Long getDepartment() {
808        return iDept;
809    }
810
811    /** Controlling Course Offering Department */
812    public void setDepartment(Long dept) {
813        iDept = dept;
814    }
815
816    /** Scheduler (Managing Department) */
817    public Long getScheduler() {
818        return iScheduler;
819    }
820
821    /** Scheduler (Managing Department) */
822    public void setScheduler(Long scheduler) {
823        iScheduler = scheduler;
824    }
825
826    /** Departmental spreading constraint */
827    public DepartmentSpreadConstraint getDeptSpreadConstraint() {
828        return iDeptSpreadConstraint;
829    }
830
831    /** Instructor constraint */
832    public List<InstructorConstraint> getInstructorConstraints() {
833        return iInstructorConstraints;
834    }
835
836    public ClassLimitConstraint getClassLimitConstraint() {
837        return iClassLimitConstraint;
838    }
839
840    public Set<SpreadConstraint> getSpreadConstraints() {
841        return iSpreadConstraints;
842    }
843    
844    public Set<FlexibleConstraint> getFlexibleGroupConstraints() {
845        return iFlexibleGroupConstraints;
846    }
847
848    public Set<Constraint<Lecture, Placement>> getWeakeningConstraints() {
849        return iWeakeningConstraints;
850    }
851
852    /** All room locations */
853    public List<RoomLocation> roomLocations() {
854        return iRoomLocations;
855    }
856
857    /** All time locations */
858    public List<TimeLocation> timeLocations() {
859        return iTimeLocations;
860    }
861
862    public int nrTimeLocations() {
863        int ret = 0;
864        for (TimeLocation time : iTimeLocations) {
865            if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference())))
866                ret++;
867        }
868        return ret;
869    }
870
871    public int nrRoomLocations() {
872        int ret = 0;
873        for (RoomLocation room : iRoomLocations) {
874            if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(room.getPreference())))
875                ret++;
876        }
877        return ret;
878    }
879
880    public int nrValues() {
881        int ret = 0;
882        for (Placement placement : values()) {
883            if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(placement
884                    .getRoomPreference()))
885                    && !Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(placement
886                            .getTimeLocation().getPreference())))
887                ret++;
888        }
889        return ret;
890    }
891
892    public int nrValues(TimeLocation time) {
893        int ret = 0;
894        for (RoomLocation room : iRoomLocations) {
895            if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(room.getPreference()))
896                    && (room.getRoomConstraint() == null || room.getRoomConstraint().isAvailable(this, time,
897                            getScheduler())))
898                ret++;
899        }
900        return ret;
901    }
902
903    public int nrValues(RoomLocation room) {
904        int ret = 0;
905        for (TimeLocation time : iTimeLocations) {
906            if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference()))
907                    && (room.getRoomConstraint() == null || room.getRoomConstraint().isAvailable(this, time,
908                            getScheduler())))
909                ret++;
910        }
911        return ret;
912    }
913
914    public int nrValues(List<RoomLocation> rooms) {
915        int ret = 0;
916        for (TimeLocation time : iTimeLocations) {
917            boolean available = true;
918            for (RoomLocation room : rooms) {
919                if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference()))
920                        || (room.getRoomConstraint() != null && !room.getRoomConstraint().isAvailable(this, time,
921                                getScheduler())))
922                    available = false;
923            }
924            if (available)
925                ret++;
926        }
927        return ret;
928    }
929
930    public boolean allowBreakHard() {
931        return sAllowBreakHard;
932    }
933
934    public int getNrRooms() {
935        return iNrRooms;
936    }
937
938    public Lecture getParent() {
939        return iParent;
940    }
941
942    public void setParent(Lecture parent) {
943        iParent = parent;
944        iParent.addChild(this);
945    }
946
947    public boolean hasParent() {
948        return (iParent != null);
949    }
950
951    public boolean hasChildren(Long subpartId) {
952        return (iChildren != null && iChildren.get(subpartId) != null && !iChildren.get(subpartId).isEmpty());
953    }
954
955    public boolean hasAnyChildren() {
956        return (iChildren != null && !iChildren.isEmpty());
957    }
958
959    public List<Lecture> getChildren(Long subpartId) {
960        return iChildren.get(subpartId);
961    }
962
963    public Set<Long> getChildrenSubpartIds() {
964        return (iChildren == null ? null : iChildren.keySet());
965    }
966
967    private void addChild(Lecture child) {
968        if (iChildren == null)
969            iChildren = new HashMap<Long, List<Lecture>>();
970        List<Lecture> childrenThisSubpart = iChildren.get(child.getSchedulingSubpartId());
971        if (childrenThisSubpart == null) {
972            childrenThisSubpart = new ArrayList<Lecture>();
973            iChildren.put(child.getSchedulingSubpartId(), childrenThisSubpart);
974        }
975        childrenThisSubpart.add(child);
976    }
977
978    public boolean isSingleSection() {
979        return (iSameSubpartLectures == null || iSameSubpartLectures.size() <= 1);
980        /*
981        if (iParent == null)
982            return (iSameSubpartLectures == null || iSameSubpartLectures.size() <= 1);
983        return (iParent.getChildren(getSchedulingSubpartId()).size() <= 1);
984        */
985    }
986
987    public java.util.List<Lecture> sameStudentsLectures() {
988        return (hasParent() ? getParent().getChildren(getSchedulingSubpartId()) : sameSubpartLectures());
989    }
990
991    public Lecture getChild(Student student, Long subpartId) {
992        if (!hasAnyChildren())
993            return null;
994        List<Lecture> children = getChildren(subpartId);
995        if (children == null)
996            return null;
997        for (Lecture child : children) {
998            if (child.students().contains(student))
999                return child;
1000        }
1001        return null;
1002    }
1003
1004    public int getCommitedConflicts(Placement placement) {
1005        Integer ret = iCommitedConflicts.get(placement);
1006        if (ret == null) {
1007            ret = new Integer(placement.getCommitedConflicts());
1008            iCommitedConflicts.put(placement, ret);
1009        }
1010        return ret.intValue();
1011    }
1012
1013    public Set<GroupConstraint> hardGroupSoftConstraints() {
1014        return iHardGroupSoftConstraints;
1015    }
1016
1017    public Set<GroupConstraint> groupConstraints() {
1018        return iGroupConstraints;
1019    }
1020
1021    public int minRoomSize() {
1022        if (iCacheMinRoomSize != null)
1023            return iCacheMinRoomSize.intValue();
1024        if (getNrRooms() <= 1) {
1025            int min = Integer.MAX_VALUE;
1026            for (RoomLocation r : roomLocations()) {
1027                if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2)
1028                    min = Math.min(min, r.getRoomSize());
1029            }
1030            iCacheMinRoomSize = new Integer(min);
1031            return min;
1032        } else {
1033            List<RoomLocation> rooms = new ArrayList<RoomLocation>();
1034            for (RoomLocation r: roomLocations())
1035                if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2)
1036                    rooms.add(r);
1037            Collections.sort(rooms, new Comparator<RoomLocation>() {
1038                @Override
1039                public int compare(RoomLocation r1, RoomLocation r2) {
1040                    if (r1.getRoomSize() < r2.getRoomSize()) return -1;
1041                    if (r1.getRoomSize() > r2.getRoomSize()) return 1;
1042                    return r1.compareTo(r2);
1043                }
1044            });
1045            int min = rooms.isEmpty() ? 0 : rooms.get(Math.min(getNrRooms(), rooms.size()) - 1).getRoomSize();
1046            iCacheMinRoomSize = new Integer(min);
1047            return min;
1048        }
1049    }
1050
1051    public int maxRoomSize() {
1052        if (iCacheMaxRoomSize != null)
1053            return iCacheMaxRoomSize.intValue();
1054        if (getNrRooms() <= 1) {
1055            int max = Integer.MIN_VALUE;
1056            for (RoomLocation r : roomLocations()) {
1057                if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) 
1058                    max = Math.max(max, r.getRoomSize());
1059            }
1060            iCacheMaxRoomSize = new Integer(max);
1061            return max;
1062        } else {
1063            List<RoomLocation> rooms = new ArrayList<RoomLocation>();
1064            for (RoomLocation r: roomLocations())
1065                if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) rooms.add(r);
1066            Collections.sort(rooms, new Comparator<RoomLocation>() {
1067                @Override
1068                public int compare(RoomLocation r1, RoomLocation r2) {
1069                    if (r1.getRoomSize() > r2.getRoomSize()) return -1;
1070                    if (r1.getRoomSize() < r2.getRoomSize()) return 1;
1071                    return r1.compareTo(r2);
1072                }
1073            });
1074            int max = rooms.isEmpty() ? 0 : rooms.get(Math.min(getNrRooms(), rooms.size()) - 1).getRoomSize();
1075            iCacheMaxRoomSize = new Integer(max);
1076            return max;
1077        }
1078    }
1079
1080    public boolean canShareRoom() {
1081        return (!iCanShareRoomGroupConstraints.isEmpty());
1082    }
1083
1084    public boolean canShareRoom(Lecture other) {
1085        if (other.equals(this))
1086            return true;
1087        for (GroupConstraint gc : iCanShareRoomGroupConstraints) {
1088            if (gc.variables().contains(other))
1089                return true;
1090        }
1091        return false;
1092    }
1093
1094    public Set<GroupConstraint> canShareRoomConstraints() {
1095        return iCanShareRoomGroupConstraints;
1096    }
1097
1098    public boolean isSingleton() {
1099        return values().size() == 1;
1100    }
1101
1102    public boolean isValid(Placement placement) {
1103        TimetableModel model = (TimetableModel) getModel();
1104        if (model == null)
1105            return true;
1106        if (model.hasConstantVariables()) {
1107            for (Placement confPlacement : model.conflictValuesSkipWeakeningConstraints(placement)) {
1108                Lecture lecture = confPlacement.variable();
1109                if (lecture.isCommitted())
1110                    return false;
1111                if (confPlacement.equals(placement))
1112                    return false;
1113            }
1114        } else {
1115            Set<Placement> conflicts = new HashSet<Placement>();
1116            for (Constraint<Lecture, Placement> constraint : hardConstraints()) {
1117                if (constraint instanceof WeakeningConstraint) continue;
1118                constraint.computeConflicts(placement, conflicts);
1119            }
1120            for (GlobalConstraint<Lecture, Placement> constraint : model.globalConstraints()) {
1121                if (constraint instanceof WeakeningConstraint) continue;
1122                constraint.computeConflicts(placement, conflicts);
1123            }
1124            if (conflicts.contains(placement))
1125                return false;
1126        }
1127        return true;
1128    }
1129
1130    public String getNotValidReason(Placement placement) {
1131        TimetableModel model = (TimetableModel) getModel();
1132        if (model == null)
1133            return "no model for class " + getName();
1134        Map<Constraint<Lecture, Placement>, Set<Placement>> conflictConstraints = model.conflictConstraints(placement);
1135        for (Map.Entry<Constraint<Lecture, Placement>, Set<Placement>> entry : conflictConstraints.entrySet()) {
1136            Constraint<Lecture, Placement> constraint = entry.getKey();
1137            Set<Placement> conflicts = entry.getValue();
1138            String cname = constraint.getName();
1139            if (constraint instanceof RoomConstraint) {
1140                cname = "Room " + constraint.getName();
1141            } else if (constraint instanceof InstructorConstraint) {
1142                cname = "Instructor " + constraint.getName();
1143            } else if (constraint instanceof GroupConstraint) {
1144                cname = "Distribution " + constraint.getName();
1145            } else if (constraint instanceof DepartmentSpreadConstraint) {
1146                cname = "Balancing of department " + constraint.getName();
1147            } else if (constraint instanceof SpreadConstraint) {
1148                cname = "Same subpart spread " + constraint.getName();
1149            } else if (constraint instanceof ClassLimitConstraint) {
1150                cname = "Class limit " + constraint.getName();
1151            }
1152            for (Placement confPlacement : conflicts) {
1153                Lecture lecture = confPlacement.variable();
1154                if (lecture.isCommitted()) {
1155                    return placement.getLongName() + " conflicts with " + lecture.getName() + " "
1156                            + confPlacement.getLongName() + " due to constraint " + cname;
1157                }
1158                if (confPlacement.equals(placement)) {
1159                    return placement.getLongName() + " is not valid due to constraint " + cname;
1160                }
1161            }
1162        }
1163        return null;
1164    }
1165
1166    public void purgeInvalidValues(boolean interactiveMode) {
1167        if (isCommitted() || Lecture.sSaveMemory)
1168            return;
1169        TimetableModel model = (TimetableModel) getModel();
1170        if (model == null)
1171            return;
1172        List<Placement> newValues = new ArrayList<Placement>(values().size());
1173        for (Placement placement : values()) {
1174            if (placement.isValid())
1175                newValues.add(placement);
1176        }
1177        if (!interactiveMode && newValues.size() != values().size()) {
1178            for (Iterator<TimeLocation> i = timeLocations().iterator(); i.hasNext();) {
1179                TimeLocation timeLocation = i.next();
1180                boolean hasPlacement = false;
1181                for (Placement placement : newValues) {
1182                    if (timeLocation.equals(placement.getTimeLocation())) {
1183                        hasPlacement = true;
1184                        break;
1185                    }
1186                }
1187                if (!hasPlacement)
1188                    i.remove();
1189            }
1190            for (Iterator<RoomLocation> i = roomLocations().iterator(); i.hasNext();) {
1191                RoomLocation roomLocation = i.next();
1192                boolean hasPlacement = false;
1193                for (Placement placement : newValues) {
1194                    if (placement.isMultiRoom()) {
1195                        if (placement.getRoomLocations().contains(roomLocation)) {
1196                            hasPlacement = true;
1197                            break;
1198                        }
1199                    } else {
1200                        if (roomLocation.equals(placement.getRoomLocation())) {
1201                            hasPlacement = true;
1202                            break;
1203                        }
1204                    }
1205                }
1206                if (!hasPlacement)
1207                    i.remove();
1208            }
1209        }
1210        setValues(newValues);
1211    }
1212
1213    public void setCommitted(boolean committed) {
1214        iCommitted = committed;
1215    }
1216
1217    public boolean isCommitted() {
1218        return iCommitted;
1219    }
1220
1221    @Override
1222    public boolean isConstant() {
1223        return iCommitted;
1224    }
1225
1226    public int getSpreadPenalty() {
1227        int spread = 0;
1228        for (SpreadConstraint sc : getSpreadConstraints()) {
1229            spread += sc.getPenalty();
1230        }
1231        return spread;
1232    }
1233
1234    @Override
1235    public int hashCode() {
1236        return getClassId().hashCode();
1237    }
1238
1239    public Configuration getConfiguration() {
1240        Lecture lecture = this;
1241        while (lecture.getParent() != null)
1242            lecture = lecture.getParent();
1243        return lecture.iParentConfiguration;
1244    }
1245
1246    public void setConfiguration(Configuration configuration) {
1247        Lecture lecture = this;
1248        while (lecture.getParent() != null)
1249            lecture = lecture.getParent();
1250        lecture.iParentConfiguration = configuration;
1251        configuration.addTopLecture(lecture);
1252    }
1253
1254    private int[] iMinMaxRoomPreference = null;
1255
1256    public int[] getMinMaxRoomPreference() {
1257        if (iMinMaxRoomPreference == null) {
1258            if (getNrRooms() <= 0 || roomLocations().isEmpty()) {
1259                iMinMaxRoomPreference = new int[] { 0, 0 };
1260            } else {
1261                Integer minRoomPref = null, maxRoomPref = null;
1262                for (RoomLocation r : roomLocations()) {
1263                    int pref = r.getPreference();
1264                    if (pref >= Constants.sPreferenceLevelRequired / 2 && pref <= Constants.sPreferenceLevelProhibited / 2) {
1265                        minRoomPref = (minRoomPref == null ? pref : Math.min(minRoomPref, pref));
1266                        maxRoomPref = (maxRoomPref == null ? pref : Math.max(maxRoomPref, pref));
1267                    }
1268                }
1269                iMinMaxRoomPreference = new int[] { minRoomPref == null ? 0 : minRoomPref, maxRoomPref == null ? 0 : maxRoomPref };
1270            }
1271        }
1272        return iMinMaxRoomPreference;
1273    }
1274
1275    private double[] iMinMaxTimePreference = null;
1276
1277    public double[] getMinMaxTimePreference() {
1278        if (iMinMaxTimePreference == null) {
1279            Double minTimePref = null, maxTimePref = null;
1280            for (TimeLocation t : timeLocations()) {
1281                double npref = t.getNormalizedPreference();
1282                int pref = t.getPreference();
1283                if (pref >= Constants.sPreferenceLevelRequired / 2 && pref <= Constants.sPreferenceLevelProhibited / 2) {
1284                    minTimePref = (minTimePref == null ? npref : Math.min(minTimePref, npref));
1285                    maxTimePref = (maxTimePref == null ? npref : Math.max(maxTimePref, npref));
1286                }
1287            }
1288            iMinMaxTimePreference = new double[] { minTimePref == null ? 0.0 : minTimePref, maxTimePref == null ? 0.0 : maxTimePref };
1289        }
1290        return iMinMaxTimePreference;
1291    }
1292
1293    public void setOrd(int ord) {
1294        iOrd = ord;
1295    }
1296
1297    public int getOrd() {
1298        return iOrd;
1299    }
1300
1301    @Override
1302    public int compareTo(Lecture o) {
1303        int cmp = Double.compare(getOrd(), o.getOrd());
1304        if (cmp != 0)
1305            return cmp;
1306        return super.compareTo(o);
1307    }
1308
1309    public String getNote() {
1310        return iNote;
1311    }
1312
1313    public void setNote(String note) {
1314        iNote = note;
1315    }
1316    
1317    public boolean areStudentConflictsHard(Lecture other) {
1318        return StudentConflict.hard(this, other);
1319    }
1320    
1321    public void clearIgnoreStudentConflictsWithCache() {
1322        iIgnoreStudentConflictsWith = null;
1323    }
1324    
1325    /**
1326     * Returns true if there is {@link IgnoreStudentConflictsConstraint} between the two lectures.
1327     */
1328   public boolean isToIgnoreStudentConflictsWith(Lecture other) {
1329        if (iIgnoreStudentConflictsWith == null) {
1330            iIgnoreStudentConflictsWith = new HashSet<Long>();
1331            for (Constraint<Lecture, Placement> constraint: constraints()) {
1332                if (constraint instanceof IgnoreStudentConflictsConstraint)
1333                    for (Lecture x: constraint.variables()) {
1334                        if (!x.equals(this)) iIgnoreStudentConflictsWith.add(x.getClassId());
1335                    }
1336            }
1337        }
1338        return iIgnoreStudentConflictsWith.contains(other.getClassId());
1339    }
1340   
1341   /**
1342    * Get class weight. This weight is used with the criteria. E.g., class that is not meeting all the
1343    * semester can have a lower weight. Defaults to 1.0
1344    */
1345   public double getWeight() { return iWeight; }
1346   /**
1347    * Set class weight. This weight is used with the criteria. E.g., class that is not meeting all the
1348    * semester can have a lower weight.
1349    */
1350   public void setWeight(double weight) { iWeight = weight; }
1351}