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}