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}