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