    001package net.sf.cpsolver.coursett.model;
    002
    003import java.util.ArrayList;
    004import java.util.BitSet;
    005import java.util.Collection;
    006import java.util.Collections;
    007import java.util.Comparator;
    008import java.util.HashSet;
    009import java.util.HashMap;
    010import java.util.List;
    011import java.util.Locale;
    012import java.util.Map;
    013import java.util.Set;
    014
    015import net.sf.cpsolver.coursett.Constants;
    016import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint;
    017import net.sf.cpsolver.coursett.constraint.DepartmentSpreadConstraint;
    018import net.sf.cpsolver.coursett.constraint.GroupConstraint;
    019import net.sf.cpsolver.coursett.constraint.InstructorConstraint;
    020import net.sf.cpsolver.coursett.constraint.JenrlConstraint;
    021import net.sf.cpsolver.coursett.constraint.FlexibleConstraint;
    022import net.sf.cpsolver.coursett.constraint.RoomConstraint;
    023import net.sf.cpsolver.coursett.constraint.SpreadConstraint;
    024import net.sf.cpsolver.coursett.criteria.BackToBackInstructorPreferences;
    025import net.sf.cpsolver.coursett.criteria.BrokenTimePatterns;
    026import net.sf.cpsolver.coursett.criteria.DepartmentBalancingPenalty;
    027import net.sf.cpsolver.coursett.criteria.DistributionPreferences;
    028import net.sf.cpsolver.coursett.criteria.FlexibleConstraintCriterion;
    029import net.sf.cpsolver.coursett.criteria.Perturbations;
    030import net.sf.cpsolver.coursett.criteria.RoomPreferences;
    031import net.sf.cpsolver.coursett.criteria.RoomViolations;
    032import net.sf.cpsolver.coursett.criteria.SameSubpartBalancingPenalty;
    033import net.sf.cpsolver.coursett.criteria.StudentCommittedConflict;
    034import net.sf.cpsolver.coursett.criteria.StudentConflict;
    035import net.sf.cpsolver.coursett.criteria.StudentDistanceConflict;
    036import net.sf.cpsolver.coursett.criteria.StudentHardConflict;
    037import net.sf.cpsolver.coursett.criteria.StudentOverlapConflict;
    038import net.sf.cpsolver.coursett.criteria.TimePreferences;
    039import net.sf.cpsolver.coursett.criteria.TimeViolations;
    040import net.sf.cpsolver.coursett.criteria.TooBigRooms;
    041import net.sf.cpsolver.coursett.criteria.UselessHalfHours;
    042import net.sf.cpsolver.coursett.criteria.placement.AssignmentCount;
    043import net.sf.cpsolver.coursett.criteria.placement.DeltaTimePreference;
    044import net.sf.cpsolver.coursett.criteria.placement.HardConflicts;
    045import net.sf.cpsolver.coursett.criteria.placement.PotentialHardConflicts;
    046import net.sf.cpsolver.coursett.criteria.placement.WeightedHardConflicts;
    047import net.sf.cpsolver.ifs.constant.ConstantModel;
    048import net.sf.cpsolver.ifs.criteria.Criterion;
    049import net.sf.cpsolver.ifs.model.Constraint;
    050import net.sf.cpsolver.ifs.model.GlobalConstraint;
    051import net.sf.cpsolver.ifs.model.WeakeningConstraint;
    052import net.sf.cpsolver.ifs.util.DataProperties;
    053import net.sf.cpsolver.ifs.util.DistanceMetric;
    054
    055/**
    056 * Timetable model.
    057 *
    058 * @version CourseTT 1.2 (University Course Timetabling)<br>
    059 *          Copyright (C) 2006 - 2010 Tomáš Müller<br>
    060 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    061 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    062 * <br>
    063 *          This library is free software; you can redistribute it and/or modify
    064 *          it under the terms of the GNU Lesser General Public License as
    065 *          published by the Free Software Foundation; either version 3 of the
    066 *          License, or (at your option) any later version. <br>
    067 * <br>
    068 *          This library is distributed in the hope that it will be useful, but
    069 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    070 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    071 *          Lesser General Public License for more details. <br>
    072 * <br>
    073 *          You should have received a copy of the GNU Lesser General Public
    074 *          License along with this library; if not see
    075 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    076 */
    077
    078public class TimetableModel extends ConstantModel<Lecture, Placement> {
    079    private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableModel.class);
    080    private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.00",
    081            new java.text.DecimalFormatSymbols(Locale.US));
    082
    083    private List<InstructorConstraint> iInstructorConstraints = new ArrayList<InstructorConstraint>();
    084    private List<JenrlConstraint> iJenrlConstraints = new ArrayList<JenrlConstraint>();
    085    private List<RoomConstraint> iRoomConstraints = new ArrayList<RoomConstraint>();
    086    private List<DepartmentSpreadConstraint> iDepartmentSpreadConstraints = new ArrayList<DepartmentSpreadConstraint>();
    087    private List<SpreadConstraint> iSpreadConstraints = new ArrayList<SpreadConstraint>();
    088    private List<GroupConstraint> iGroupConstraints = new ArrayList<GroupConstraint>();
    089    private List<ClassLimitConstraint> iClassLimitConstraints = new ArrayList<ClassLimitConstraint>();
    090    private List<FlexibleConstraint> iFlexibleConstraints = new ArrayList<FlexibleConstraint>();
    091    private DataProperties iProperties = null;
    092    private int iYear = -1;
    093    private List<BitSet> iWeeks = null;
    094
    095    private HashSet<Student> iAllStudents = new HashSet<Student>();
    096
    097    private DistanceMetric iDistanceMetric = null;
    098
    099    private StudentSectioning iStudentSectioning = null;
    100
    101    public TimetableModel(DataProperties properties) {
    102        super();
    103        iProperties = properties;
    104        iDistanceMetric = new DistanceMetric(properties);
    105        if (properties.getPropertyBoolean("OnFlySectioning.Enabled", false))
    106            addModelListener(new OnFlySectioning(this));
    107        String criteria = properties.getProperty("General.Criteria",
    108                // Objectives
    109                StudentConflict.class.getName() + ";" +
    110                StudentDistanceConflict.class.getName() + ";" +
    111                StudentHardConflict.class.getName() + ";" +
    112                StudentCommittedConflict.class.getName() + ";" +
    113                StudentOverlapConflict.class.getName() + ";" +
    114                UselessHalfHours.class.getName() + ";" +
    115                BrokenTimePatterns.class.getName() + ";" +
    116                TooBigRooms.class.getName() + ";" +
    117                TimePreferences.class.getName() + ";" +
    118                RoomPreferences.class.getName() + ";" +
    119                DistributionPreferences.class.getName() + ";" +
    120                SameSubpartBalancingPenalty.class.getName() + ";" +
    121                DepartmentBalancingPenalty.class.getName() + ";" +
    122                BackToBackInstructorPreferences.class.getName() + ";" +
    123                Perturbations.class.getName() + ";" +
    124                // Additional placement selection criteria
    125                AssignmentCount.class.getName() + ";" +
    126                DeltaTimePreference.class.getName() + ";" +
    127                HardConflicts.class.getName() + ";" +
    128                PotentialHardConflicts.class.getName() + ";" +
    129                FlexibleConstraintCriterion.class.getName() + ";" +
    130                WeightedHardConflicts.class.getName());
    131        // Interactive mode -- count time / room violations
    132        if (properties.getPropertyBoolean("General.InteractiveMode", false))
    133            criteria += ";" + TimeViolations.class.getName() + ";" + RoomViolations.class.getName();
    134        // Additional (custom) criteria
    135        criteria += ";" + properties.getProperty("General.AdditionalCriteria", "");
    136        for (String criterion: criteria.split("\\;")) {
    137            if (criterion == null || criterion.isEmpty()) continue;
    138            try {
    139                @SuppressWarnings("unchecked")
    140                Class<Criterion<Lecture, Placement>> clazz = (Class<Criterion<Lecture, Placement>>)Class.forName(criterion);
    141                addCriterion(clazz.newInstance());
    142            } catch (Exception e) {
    143                sLogger.error("Unable to use " + criterion + ": " + e.getMessage());
    144            }
    145        }
    146        try {
    147            String studentSectioningClassName = properties.getProperty("StudentSectioning.Class", DefaultStudentSectioning.class.getName());
    148            Class<?> studentSectioningClass = Class.forName(studentSectioningClassName);
    149            iStudentSectioning = (StudentSectioning)studentSectioningClass.getConstructor(TimetableModel.class).newInstance(this);
    150        } catch (Exception e) {
    151            sLogger.error("Failed to load custom student sectioning class: " + e.getMessage());
    152            iStudentSectioning = new DefaultStudentSectioning(this);
    153        }
    154    }
    155
    156    public DistanceMetric getDistanceMetric() {
    157        return iDistanceMetric;
    158    }
    159
    160    /**
    161     * Returns interface to the student sectioning functions needed during course timetabling.
    162     * Defaults to an instance of {@link DefaultStudentSectioning}, can be changed using the StudentSectioning.Class parameter.
    163     */
    164    public StudentSectioning getStudentSectioning() {
    165        return iStudentSectioning;
    166    }
    167
    168    public DataProperties getProperties() {
    169        return iProperties;
    170    }
    171
    172    /**
    173     * Student final sectioning (switching students between sections of the same
    174     * class in order to minimize overall number of student conflicts)
    175     */
    176    public void switchStudents() {
    177        getStudentSectioning().switchStudents(this);
    178    }
    179
    180    /**
    181     * String representation -- returns a list of values of objective criteria
    182     */
    183    @Override
    184    public String toString() {
    185        List<Criterion<Lecture, Placement>> criteria = new ArrayList<Criterion<Lecture,Placement>>(getCriteria());
    186        Collections.sort(criteria, new Comparator<Criterion<Lecture, Placement>>() {
    187            @Override
    188            public int compare(Criterion<Lecture, Placement> c1, Criterion<Lecture, Placement> c2) {
    189                int cmp = -Double.compare(c1.getWeight(), c2.getWeight());
    190                if (cmp != 0) return cmp;
    191                return c1.getName().compareTo(c2.getName());
    192            }
    193        });
    194        String ret = "";
    195        for (Criterion<Lecture, Placement> criterion: criteria) {
    196            String val = criterion.toString();
    197            if (!val.isEmpty())
    198                ret += ", " + val;
    199        }
    200        return (nrUnassignedVariables() == 0 ? "" : "V:" + nrAssignedVariables() + "/" + variables().size() + ", ") +
    201                "T:" + sDoubleFormat.format(getTotalValue()) + ret;
    202    }
    203
    204    public Map<String, String> getBounds() {
    205        Map<String, String> ret = new HashMap<String, String>();
    206        ret.put("Room preferences min", "" + getCriterion(RoomPreferences.class).getBounds()[0]);
    207        ret.put("Room preferences max", "" + getCriterion(RoomPreferences.class).getBounds()[1]);
    208        ret.put("Time preferences min", "" + getCriterion(TimePreferences.class).getBounds()[0]);
    209        ret.put("Time preferences max", "" + getCriterion(TimePreferences.class).getBounds()[1]);
    210        ret.put("Distribution preferences min", "" + getCriterion(DistributionPreferences.class).getBounds()[0]);
    211        ret.put("Distribution preferences max", "" + getCriterion(DistributionPreferences.class).getBounds()[1]);
    212        if (getProperties().getPropertyBoolean("General.UseDistanceConstraints", false)) {
    213            ret.put("Back-to-back instructor preferences max", "" + getCriterion(BackToBackInstructorPreferences.class).getBounds()[1]);
    214        }
    215        ret.put("Too big rooms max", "" + getCriterion(TooBigRooms.class).getBounds()[0]);
    216        ret.put("Useless half-hours", "" + getCriterion(UselessHalfHours.class).getBounds()[0]);
    217        return ret;
    218    }
    219
    220    /** Global info */
    221    @Override
    222    public Map<String, String> getInfo() {
    223        Map<String, String> ret = super.getInfo();
    224        ret.put("Memory usage", getMem());
    225
    226        Criterion<Lecture, Placement> rp = getCriterion(RoomPreferences.class);
    227        Criterion<Lecture, Placement> rv = getCriterion(RoomViolations.class);
    228        ret.put("Room preferences", getPerc(rp.getValue(), rp.getBounds()[0], rp.getBounds()[1]) + "% (" + Math.round(rp.getValue()) + ")"
    229                + (rv != null && rv.getValue() >= 0.5 ? " [hard:" + Math.round(rv.getValue()) + "]" : ""));
    230
    231        Criterion<Lecture, Placement> tp = getCriterion(TimePreferences.class);
    232        Criterion<Lecture, Placement> tv = getCriterion(TimeViolations.class);
    233        ret.put("Time preferences", getPerc(tp.getValue(), tp.getBounds()[0], tp.getBounds()[1]) + "% (" + sDoubleFormat.format(tp.getValue()) + ")"
    234                + (tv != null && tv.getValue() >= 0.5 ? " [hard:" + Math.round(tv.getValue()) + "]" : ""));
    235
    236        Criterion<Lecture, Placement> dp = getCriterion(DistributionPreferences.class);
    237        ret.put("Distribution preferences", getPerc(dp.getValue(), dp.getBounds()[0], dp.getBounds()[1]) + "% (" + sDoubleFormat.format(dp.getValue()) + ")");
    238
    239        Criterion<Lecture, Placement> sc = getCriterion(StudentConflict.class);
    240        Criterion<Lecture, Placement> shc = getCriterion(StudentHardConflict.class);
    241        Criterion<Lecture, Placement> sdc = getCriterion(StudentDistanceConflict.class);
    242        Criterion<Lecture, Placement> scc = getCriterion(StudentCommittedConflict.class);
    243        ret.put("Student conflicts", Math.round(scc.getValue() + sc.getValue()) +
    244                " [committed:" + Math.round(scc.getValue()) +
    245                ", distance:" + Math.round(sdc.getValue()) +
    246                ", hard:" + Math.round(shc.getValue()) + "]");
    247
    248        if (!getSpreadConstraints().isEmpty()) {
    249            Criterion<Lecture, Placement> ip = getCriterion(BackToBackInstructorPreferences.class);
    250            ret.put("Back-to-back instructor preferences", getPerc(ip.getValue(), ip.getBounds()[0], ip.getBounds()[1]) + "% (" + Math.round(ip.getValue()) + ")");
    251        }
    252
    253        if (!getDepartmentSpreadConstraints().isEmpty()) {
    254            Criterion<Lecture, Placement> dbp = getCriterion(DepartmentBalancingPenalty.class);
    255            ret.put("Department balancing penalty", sDoubleFormat.format(dbp.getValue()));
    256        }
    257
    258        Criterion<Lecture, Placement> sbp = getCriterion(SameSubpartBalancingPenalty.class);
    259        ret.put("Same subpart balancing penalty", sDoubleFormat.format(sbp.getValue()));
    260
    261        Criterion<Lecture, Placement> tbr = getCriterion(TooBigRooms.class);
    262        ret.put("Too big rooms", getPercRev(tbr.getValue(), tbr.getBounds()[1], tbr.getBounds()[0]) + "% (" + Math.round(tbr.getValue()) + ")");
    263
    264        Criterion<Lecture, Placement> uh = getCriterion(UselessHalfHours.class);
    265        Criterion<Lecture, Placement> bt = getCriterion(BrokenTimePatterns.class);
    266
    267        ret.put("Useless half-hours", getPercRev(uh.getValue() + bt.getValue(), 0, Constants.sPreferenceLevelStronglyDiscouraged * bt.getBounds()[0]) +
    268                "% (" + Math.round(uh.getValue()) + " + " + Math.round(bt.getValue()) + ")");
    269        return ret;
    270    }
    271
    272    @Override
    273    public Map<String, String> getInfo(Collection<Lecture> variables) {
    274        Map<String, String> ret = super.getInfo(variables);
    275
    276        ret.put("Memory usage", getMem());
    277
    278        Criterion<Lecture, Placement> rp = getCriterion(RoomPreferences.class);
    279        ret.put("Room preferences", getPerc(rp.getValue(variables), rp.getBounds(variables)[0], rp.getBounds(variables)[1]) + "% (" + Math.round(rp.getValue(variables)) + ")");
    280
    281        Criterion<Lecture, Placement> tp = getCriterion(TimePreferences.class);
    282        ret.put("Time preferences", getPerc(tp.getValue(variables), tp.getBounds(variables)[0], tp.getBounds(variables)[1]) + "% (" + sDoubleFormat.format(tp.getValue(variables)) + ")");
    283
    284        Criterion<Lecture, Placement> dp = getCriterion(DistributionPreferences.class);
    285        ret.put("Distribution preferences", getPerc(dp.getValue(variables), dp.getBounds(variables)[0], dp.getBounds(variables)[1]) + "% (" + sDoubleFormat.format(dp.getValue(variables)) + ")");
    286
    287        Criterion<Lecture, Placement> sc = getCriterion(StudentConflict.class);
    288        Criterion<Lecture, Placement> shc = getCriterion(StudentHardConflict.class);
    289        Criterion<Lecture, Placement> sdc = getCriterion(StudentDistanceConflict.class);
    290        Criterion<Lecture, Placement> scc = getCriterion(StudentCommittedConflict.class);
    291        ret.put("Student conflicts", Math.round(scc.getValue(variables) + sc.getValue(variables)) +
    292                " [committed:" + Math.round(scc.getValue(variables)) +
    293                ", distance:" + Math.round(sdc.getValue(variables)) +
    294                ", hard:" + Math.round(shc.getValue(variables)) + "]");
    295
    296        if (!getSpreadConstraints().isEmpty()) {
    297            Criterion<Lecture, Placement> ip = getCriterion(BackToBackInstructorPreferences.class);
    298            ret.put("Back-to-back instructor preferences", getPerc(ip.getValue(variables), ip.getBounds(variables)[0], ip.getBounds(variables)[1]) + "% (" + Math.round(ip.getValue(variables)) + ")");
    299        }
    300
    301        if (!getDepartmentSpreadConstraints().isEmpty()) {
    302            Criterion<Lecture, Placement> dbp = getCriterion(DepartmentBalancingPenalty.class);
    303            ret.put("Department balancing penalty", sDoubleFormat.format(dbp.getValue(variables)));
    304        }
    305
    306        Criterion<Lecture, Placement> sbp = getCriterion(SameSubpartBalancingPenalty.class);
    307        ret.put("Same subpart balancing penalty", sDoubleFormat.format(sbp.getValue(variables)));
    308
    309        Criterion<Lecture, Placement> tbr = getCriterion(TooBigRooms.class);
    310        ret.put("Too big rooms", getPercRev(tbr.getValue(variables), tbr.getBounds(variables)[1], tbr.getBounds(variables)[0]) + "% (" + Math.round(tbr.getValue(variables)) + ")");
    311
    312        Criterion<Lecture, Placement> uh = getCriterion(UselessHalfHours.class);
    313        Criterion<Lecture, Placement> bt = getCriterion(BrokenTimePatterns.class);
    314
    315        ret.put("Useless half-hours", getPercRev(uh.getValue(variables) + bt.getValue(variables), 0, Constants.sPreferenceLevelStronglyDiscouraged * bt.getBounds(variables)[0]) +
    316                "% (" + Math.round(uh.getValue(variables)) + " + " + Math.round(bt.getValue(variables)) + ")");
    317        return ret;
    318    }
    319
    320    @Override
    321    public void addConstraint(Constraint<Lecture, Placement> constraint) {
    322        super.addConstraint(constraint);
    323        if (constraint instanceof InstructorConstraint) {
    324            iInstructorConstraints.add((InstructorConstraint) constraint);
    325        } else if (constraint instanceof JenrlConstraint) {
    326            iJenrlConstraints.add((JenrlConstraint) constraint);
    327        } else if (constraint instanceof RoomConstraint) {
    328            iRoomConstraints.add((RoomConstraint) constraint);
    329        } else if (constraint instanceof DepartmentSpreadConstraint) {
    330            iDepartmentSpreadConstraints.add((DepartmentSpreadConstraint) constraint);
    331        } else if (constraint instanceof SpreadConstraint) {
    332            iSpreadConstraints.add((SpreadConstraint) constraint);
    333        } else if (constraint instanceof ClassLimitConstraint) {
    334            iClassLimitConstraints.add((ClassLimitConstraint) constraint);
    335        } else if (constraint instanceof GroupConstraint) {
    336            iGroupConstraints.add((GroupConstraint) constraint);
    337        } else if (constraint instanceof FlexibleConstraint) {
    338            iFlexibleConstraints.add((FlexibleConstraint) constraint);
    339        }
    340    }
    341
    342    @Override
    343    public void removeConstraint(Constraint<Lecture, Placement> constraint) {
    344        super.removeConstraint(constraint);
    345        if (constraint instanceof InstructorConstraint) {
    346            iInstructorConstraints.remove(constraint);
    347        } else if (constraint instanceof JenrlConstraint) {
    348            iJenrlConstraints.remove(constraint);
    349        } else if (constraint instanceof RoomConstraint) {
    350            iRoomConstraints.remove(constraint);
    351        } else if (constraint instanceof DepartmentSpreadConstraint) {
    352            iDepartmentSpreadConstraints.remove(constraint);
    353        } else if (constraint instanceof SpreadConstraint) {
    354            iSpreadConstraints.remove(constraint);
    355        } else if (constraint instanceof ClassLimitConstraint) {
    356            iClassLimitConstraints.remove(constraint);
    357        } else if (constraint instanceof GroupConstraint) {
    358            iGroupConstraints.remove(constraint);
    359        } else if (constraint instanceof FlexibleConstraint) {
    360            iFlexibleConstraints.remove(constraint);
    361        }
    362    }
    363
    364    /** The list of all instructor constraints */
    365    public List<InstructorConstraint> getInstructorConstraints() {
    366        return iInstructorConstraints;
    367    }
    368
    369    /** The list of all group constraints */
    370    public List<GroupConstraint> getGroupConstraints() {
    371        return iGroupConstraints;
    372    }
    373
    374    /** The list of all jenrl constraints */
    375    public List<JenrlConstraint> getJenrlConstraints() {
    376        return iJenrlConstraints;
    377    }
    378
    379    /** The list of all room constraints */
    380    public List<RoomConstraint> getRoomConstraints() {
    381        return iRoomConstraints;
    382    }
    383
    384    /** The list of all departmental spread constraints */
    385    public List<DepartmentSpreadConstraint> getDepartmentSpreadConstraints() {
    386        return iDepartmentSpreadConstraints;
    387    }
    388
    389    public List<SpreadConstraint> getSpreadConstraints() {
    390        return iSpreadConstraints;
    391    }
    392
    393    public List<ClassLimitConstraint> getClassLimitConstraints() {
    394        return iClassLimitConstraints;
    395    }
    396
    397    public List<FlexibleConstraint> getFlexibleConstraints() {
    398        return iFlexibleConstraints;
    399    }
    400
    401    @Override
    402    public double getTotalValue() {
    403        double ret = 0;
    404        for (Criterion<Lecture, Placement> criterion: getCriteria())
    405            ret += criterion.getWeightedValue();
    406        return ret;
    407    }
    408
    409    @Override
    410    public double getTotalValue(Collection<Lecture> variables) {
    411        double ret = 0;
    412        for (Criterion<Lecture, Placement> criterion: getCriteria())
    413            ret += criterion.getWeightedValue(variables);
    414        return ret;
    415    }
    416
    417    public int getYear() {
    418        return iYear;
    419    }
    420
    421    public void setYear(int year) {
    422        iYear = year;
    423    }
    424
    425    public Set<Student> getAllStudents() {
    426        return iAllStudents;
    427    }
    428
    429    public void addStudent(Student student) {
    430        iAllStudents.add(student);
    431    }
    432
    433    public void removeStudent(Student student) {
    434        iAllStudents.remove(student);
    435    }
    436
    437    /**
    438     * Returns amount of allocated memory.
    439     *
    440     * @return amount of allocated memory to be written in the log
    441     */
    442    public static synchronized String getMem() {
    443        Runtime rt = Runtime.getRuntime();
    444        return sDoubleFormat.format(((double) (rt.totalMemory() - rt.freeMemory())) / 1048576) + "M";
    445    }
    446
    447
    448    /**
    449     * Returns the set of conflicting variables with this value, if it is
    450     * assigned to its variable. Conflicts with constraints that implement
    451     * {@link WeakeningConstraint} are ignored.
    452     */
    453    public Set<Placement> conflictValuesSkipWeakeningConstraints(Placement value) {
    454        Set<Placement> conflictValues = new HashSet<Placement>();
    455        for (Constraint<Lecture, Placement> constraint : value.variable().hardConstraints()) {
    456            if (constraint instanceof WeakeningConstraint) continue;
    457            constraint.computeConflicts(value, conflictValues);
    458        }
    459        for (GlobalConstraint<Lecture, Placement> constraint : globalConstraints()) {
    460            if (constraint instanceof WeakeningConstraint) continue;
    461            constraint.computeConflicts(value, conflictValues);
    462        }
    463        return conflictValues;
    464    }
    465
    466    /**
    467     * The method creates date patterns (bitsets) which represent the weeks of a
    468     * semester.
    469     *
    470     * @return a list of BitSets which represents the weeks of a semester.
    471     */
    472    public List<BitSet> getWeeks() {
    473        if (iWeeks == null) {
    474            String defaultDatePattern = getProperties().getProperty("DatePattern.CustomDatePattern", null);
    475            if (defaultDatePattern == null){
    476                defaultDatePattern = getProperties().getProperty("DatePattern.Default");
    477            }
    478            if (defaultDatePattern == null) return null;
    479
    480            // Create default date pattern
    481            BitSet fullTerm = new BitSet(defaultDatePattern.length());
    482            for (int i = 0; i < defaultDatePattern.length(); i++) {
    483                if (defaultDatePattern.charAt(i) == 49) {
    484                    fullTerm.set(i);
    485                }
    486            }
    487
    488            // Cut date pattern into weeks (every week contains 7 positive bits)
    489            iWeeks = new ArrayList<BitSet>();
    490            int cnt = 0;
    491            for (int i = 0; i < fullTerm.length(); i++) {
    492                if (fullTerm.get(i)) {
    493                    int w = (cnt++) / 7;
    494                    if (iWeeks.size() == w) {
    495                        iWeeks.add(new BitSet(fullTerm.length()));
    496                    }
    497                    iWeeks.get(w).set(i);
    498                }
    499            }
    500        }
    501        return iWeeks;
    502    }
    503}