    001package org.cpsolver.coursett.constraint;
    002
    003import java.util.BitSet;
    004import java.util.Enumeration;
    005import java.util.Set;
    006
    007import org.cpsolver.coursett.Constants;
    008import org.cpsolver.coursett.criteria.additional.InstructorConflict;
    009import org.cpsolver.coursett.model.Lecture;
    010import org.cpsolver.coursett.model.Placement;
    011import org.cpsolver.coursett.model.TimeLocation;
    012import org.cpsolver.ifs.assignment.Assignment;
    013
    014/**
    015 * Soft version of the instructor constraint.
    016 *
    017 * @version CourseTT 1.3 (University Course Timetabling)<br>
    018 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
    019 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    020 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    021 * <br>
    022 *          This library is free software; you can redistribute it and/or modify
    023 *          it under the terms of the GNU Lesser General Public License as
    024 *          published by the Free Software Foundation; either version 3 of the
    025 *          License, or (at your option) any later version. <br>
    026 * <br>
    027 *          This library is distributed in the hope that it will be useful, but
    028 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    029 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    030 *          Lesser General Public License for more details. <br>
    031 * <br>
    032 *          You should have received a copy of the GNU Lesser General Public
    033 *          License along with this library; if not see
    034 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    035 */
    036public class SoftInstructorConstraint extends InstructorConstraint {
    037
    038    public SoftInstructorConstraint(Long id, String puid, String name, boolean ignDist) {
    039        super(id, puid, name, ignDist);
    040    }
    041
    042
    043    @Override
    044    public void computeConflicts(Assignment<Lecture, Placement> assignment, Placement placement, Set<Placement> conflicts) {
    045        return;
    046    }
    047
    048    @Override
    049    public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement placement) {
    050        return false;
    051    }
    052
    053    @Override
    054    public boolean isConsistent(Placement p1, Placement p2) {
    055        return true;
    056    }
    057
    058    @Override
    059    public boolean isHard() {
    060        return false;
    061    }
    062
    063    @Override
    064    public InstructorConstraintContext createAssignmentContext(Assignment<Lecture, Placement> assignment) {
    065        return new SoftInstructorConstraintContext(assignment);
    066    }
    067
    068    public int getConflicts(Assignment<Lecture, Placement> assignment) {
    069        return ((SoftInstructorConstraintContext)getContext(assignment)).getConflicts();
    070    }
    071
    072    public int getConflicts(Assignment<Lecture, Placement> assignment, Placement placement) {
    073        if (((SoftInstructorConstraintContext)getContext(assignment)).inConflict(assignment, placement)) return 1;
    074        return 0;
    075    }
    076
    077    public int getWorstConflicts() {
    078        if (variables().size() < 2) return 0;
    079        return variables().size() - 1;
    080    }
    081
    082    public class SoftInstructorConstraintContext extends InstructorConstraintContext {
    083        private int iConficts = 0;
    084
    085        public SoftInstructorConstraintContext(Assignment<Lecture, Placement> assignment) {
    086            super(assignment);
    087            iConficts = countConflicts(assignment);
    088            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
    089        }
    090
    091        @Override
    092        public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) {
    093            super.assigned(assignment, placement);
    094            getModel().getCriterion(InstructorConflict.class).inc(assignment, -iConficts);
    095            iConficts = countConflicts(assignment);
    096            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
    097        }
    098
    099        @Override
    100        public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) {
    101            super.unassigned(assignment, placement);
    102            getModel().getCriterion(InstructorConflict.class).inc(assignment, -iConficts);
    103            iConficts = countConflicts(assignment);
    104            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
    105        }
    106
    107        public int getConflicts() { return iConficts; }
    108
    109        protected int countConflicts(Assignment<Lecture, Placement> assignment) {
    110            int conflicts = 0;
    111            for (Lecture lecture: variables()) {
    112                Placement placement = assignment.getValue(lecture);
    113                if (placement != null && inConflict(assignment, placement))
    114                    conflicts ++;
    115            }
    116            return conflicts;
    117        }
    118
    119        public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement placement) {
    120            Lecture lecture = placement.variable();
    121            Placement current = assignment.getValue(lecture);
    122            BitSet weekCode = placement.getTimeLocation().getWeekCode();
    123
    124            if (!isAvailable(lecture, placement)) return true;
    125
    126            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    127                int slot = e.nextElement();
    128                for (Placement p : getPlacements(slot)) {
    129                    if (!p.equals(current) && p.getTimeLocation().shareWeeks(weekCode)) {
    130                        if (p.canShareRooms(placement) && p.sameRooms(placement))
    131                            continue;
    132                        return true;
    133                    }
    134                }
    135            }
    136            if (!isIgnoreDistances()) {
    137                for (Enumeration<Integer> e = placement.getTimeLocation().getStartSlots(); e.hasMoreElements();) {
    138                    int startSlot = e.nextElement();
    139
    140                    int prevSlot = startSlot - 1;
    141                    if (prevSlot >= 0 && (prevSlot / Constants.SLOTS_PER_DAY) == (startSlot / Constants.SLOTS_PER_DAY)) {
    142                        for (Placement c : getPlacements(prevSlot, placement)) {
    143                            if (lecture.equals(c.variable())) continue;
    144                            if (c.canShareRooms(placement) && c.sameRooms(placement)) continue;
    145                            if (Placement.getDistanceInMeters(getDistanceMetric(), placement, c) > getDistanceMetric().getInstructorProhibitedLimit())
    146                                return true;
    147                        }
    148                    }
    149                    int nextSlot = startSlot + placement.getTimeLocation().getLength();
    150                    if ((nextSlot / Constants.SLOTS_PER_DAY) == (startSlot / Constants.SLOTS_PER_DAY)) {
    151                        for (Placement c : getPlacements(nextSlot, placement)) {
    152                            if (lecture.equals(c.variable())) continue;
    153                            if (c.canShareRooms(placement) && c.sameRooms(placement)) continue;
    154                            if (Placement.getDistanceInMeters(getDistanceMetric(), placement, c) > getDistanceMetric().getInstructorProhibitedLimit())
    155                                return true;
    156                        }
    157                    }
    158
    159                    if (getDistanceMetric().doComputeDistanceConflictsBetweenNonBTBClasses()) {
    160                        TimeLocation t1 = placement.getTimeLocation();
    161                        for (Lecture other: variables()) {
    162                            Placement otherPlacement = assignment.getValue(other);
    163                            if (otherPlacement == null || other.equals(placement.variable())) continue;
    164                            TimeLocation t2 = otherPlacement.getTimeLocation();
    165                            if (t1 == null || t2 == null || !t1.shareDays(t2) || !t1.shareWeeks(t2)) continue;
    166                            if (t1.getStartSlot() + t1.getLength() < t2.getStartSlot()) {
    167                                if (Placement.getDistanceInMinutes(getDistanceMetric(), placement, otherPlacement) > t1.getBreakTime() + Constants.SLOT_LENGTH_MIN * (t2.getStartSlot() - t1.getStartSlot() - t1.getLength()))
    168                                    return true;
    169                            } else if (t2.getStartSlot() + t2.getLength() < t1.getStartSlot()) {
    170                                if (Placement.getDistanceInMinutes(getDistanceMetric(), placement, otherPlacement) >  t2.getBreakTime() + Constants.SLOT_LENGTH_MIN * (t1.getStartSlot() - t2.getStartSlot() - t2.getLength()))
    171                                    return true;
    172                            }
    173                        }
    174                    }
    175                }
    176            }
    177            return false;
    178        }
    179    }
    180}