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 Tomas Muller<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 public class DiscouragedRoomConstraintContext extends RoomConstraintContext { 086 int iUsage = 0; 087 int iLimit = 0; 088 private long iUnassignment = 0; 089 090 public DiscouragedRoomConstraintContext(Assignment<Lecture, Placement> assignment) { 091 super(assignment); 092 } 093 094 @Override 095 public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) { 096 super.assigned(assignment, placement); 097 if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted()) 098 iUsage ++; 099 } 100 101 @Override 102 public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) { 103 super.unassigned(assignment, placement); 104 if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted()) 105 iUsage --; 106 else 107 weaken(); 108 } 109 110 public int getLimit() { 111 return iLimit; 112 } 113 114 public int getUsage() { 115 return iUsage; 116 } 117 118 public boolean isOverLimit(Assignment<Lecture, Placement> assignment, Placement value) { 119 if (iUnassignmentsToWeaken == 0) 120 return false; // not working 121 if (!value.hasRoomLocation(getResourceId())) 122 return false; // different room 123 Lecture lecture = value.variable(); 124 if (lecture.roomLocations().size() == lecture.getNrRooms()) 125 return false; // required room 126 if (lecture.isCommitted()) 127 return false; // committed class 128 Placement current = assignment.getValue(lecture); 129 if (current != null && current.hasRoomLocation(getResourceId())) 130 return false; // already assigned in this room 131 if (iUsage + 1 <= iLimit) 132 return false; // under the limit 133 return true; 134 } 135 136 public void weaken() { 137 if (iUnassignmentsToWeaken == 0) return; 138 iUnassignment++; 139 if (iUnassignment % iUnassignmentsToWeaken == 0) 140 iLimit ++; 141 } 142 143 public void weaken(Assignment<Lecture, Placement> assignment, Placement value) { 144 while (isOverLimit(assignment, value)) 145 iLimit ++; 146 } 147 } 148}