001package org.cpsolver.coursett.constraint; 002 003import java.util.Set; 004 005import org.cpsolver.coursett.model.Lecture; 006import org.cpsolver.coursett.model.Placement; 007import org.cpsolver.coursett.model.RoomSharingModel; 008import org.cpsolver.ifs.assignment.Assignment; 009import org.cpsolver.ifs.model.WeakeningConstraint; 010import org.cpsolver.ifs.util.DataProperties; 011 012 013/** 014 * Discouraged room constraint. This constraint is based on 015 * {@link RoomConstraint}, however, it tries to minimize the usage of the room 016 * as much as possible. 017 * 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 DiscouragedRoomConstraint extends RoomConstraint implements WeakeningConstraint<Lecture, Placement> { 038 private int iUnassignmentsToWeaken = 1000; 039 040 public DiscouragedRoomConstraint(DataProperties config, Long id, String name, Long buildingId, int capacity, 041 RoomSharingModel roomSharingModel, Double x, Double y, boolean ignoreTooFar, boolean constraint) { 042 super(id, name, buildingId, capacity, roomSharingModel, x, y, ignoreTooFar, constraint); 043 iUnassignmentsToWeaken = config.getPropertyInt("DiscouragedRoom.Unassignments2Weaken", iUnassignmentsToWeaken); 044 } 045 046 @Override 047 public void computeConflicts(Assignment<Lecture, Placement> assignment, Placement value, Set<Placement> conflicts) { 048 if (!getConstraint() || !value.hasRoomLocation(getResourceId())) return; 049 super.computeConflicts(assignment, value, conflicts); 050 if (((DiscouragedRoomConstraintContext)getContext(assignment)).isOverLimit(assignment, value)) 051 conflicts.add(value); 052 } 053 054 @Override 055 public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement value) { 056 if (!getConstraint() || !value.hasRoomLocation(getResourceId())) return false; 057 return ((DiscouragedRoomConstraintContext)getContext(assignment)).isOverLimit(assignment, value) || super.inConflict(assignment, value); 058 } 059 060 @Override 061 public String getName() { 062 return "discouraged " + super.getName(); 063 } 064 065 @Override 066 public String toString() { 067 return "Discouraged " + super.toString(); 068 } 069 070 @Override 071 public void weaken(Assignment<Lecture, Placement> assignment) { 072 ((DiscouragedRoomConstraintContext)getContext(assignment)).weaken(); 073 } 074 075 @Override 076 public void weaken(Assignment<Lecture, Placement> assignment, Placement value) { 077 ((DiscouragedRoomConstraintContext)getContext(assignment)).weaken(assignment, value); 078 } 079 080 @Override 081 public RoomConstraintContext createAssignmentContext(Assignment<Lecture, Placement> assignment) { 082 return new DiscouragedRoomConstraintContext(assignment); 083 } 084 085 @Override 086 public void unassigned(Assignment<Lecture, Placement> assignment, long iteration, Placement placement) { 087 super.unassigned(assignment, iteration, placement); 088 if (!placement.hasRoomLocation(getResourceId())) 089 ((DiscouragedRoomConstraintContext)getContext(assignment)).weaken(); 090 } 091 092 public class DiscouragedRoomConstraintContext extends RoomConstraintContext { 093 int iUsage = 0; 094 int iLimit = 0; 095 private long iUnassignment = 0; 096 097 public DiscouragedRoomConstraintContext(Assignment<Lecture, Placement> assignment) { 098 super(assignment); 099 } 100 101 @Override 102 public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) { 103 super.assigned(assignment, placement); 104 if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted()) 105 iUsage ++; 106 } 107 108 @Override 109 public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) { 110 super.unassigned(assignment, placement); 111 if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted()) 112 iUsage --; 113 } 114 115 public int getLimit() { 116 return iLimit; 117 } 118 119 public int getUsage() { 120 return iUsage; 121 } 122 123 public boolean isOverLimit(Assignment<Lecture, Placement> assignment, Placement value) { 124 if (iUnassignmentsToWeaken == 0) 125 return false; // not working 126 if (!value.hasRoomLocation(getResourceId())) 127 return false; // different room 128 Lecture lecture = value.variable(); 129 if (lecture.roomLocations().size() == lecture.getNrRooms()) 130 return false; // required room 131 if (lecture.isCommitted()) 132 return false; // committed class 133 Placement current = assignment.getValue(lecture); 134 if (current != null && current.hasRoomLocation(getResourceId())) 135 return false; // already assigned in this room 136 if (iUsage + 1 <= iLimit) 137 return false; // under the limit 138 return true; 139 } 140 141 public void weaken() { 142 if (iUnassignmentsToWeaken == 0) return; 143 iUnassignment++; 144 if (iUnassignment % iUnassignmentsToWeaken == 0) 145 iLimit ++; 146 } 147 148 public void weaken(Assignment<Lecture, Placement> assignment, Placement value) { 149 while (isOverLimit(assignment, value)) 150 iLimit ++; 151 } 152 } 153}