001package org.cpsolver.exam.criteria; 002 003import java.util.Collection; 004import java.util.Set; 005 006import org.cpsolver.exam.criteria.additional.RoomViolation; 007import org.cpsolver.exam.model.Exam; 008import org.cpsolver.exam.model.ExamModel; 009import org.cpsolver.exam.model.ExamPeriod; 010import org.cpsolver.exam.model.ExamPlacement; 011import org.cpsolver.exam.model.ExamRoom; 012import org.cpsolver.exam.model.ExamRoomPlacement; 013import org.cpsolver.ifs.assignment.Assignment; 014import org.cpsolver.ifs.solver.Solver; 015import org.cpsolver.ifs.util.DataProperties; 016 017 018/** 019 * Room penalty (penalty for using given rooms). I.e., sum of 020 * {@link ExamRoomPlacement#getPenalty(ExamPeriod)} of assigned rooms. 021 * <br><br> 022 * A weight for room penalty can be set by problem property 023 * Exams.RoomPreferenceWeight, or in the input xml file, property 024 * roomWeight). 025 * 026 * <br> 027 * 028 * @version ExamTT 1.3 (Examination Timetabling)<br> 029 * Copyright (C) 2008 - 2014 Tomáš Müller<br> 030 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 031 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 032 * <br> 033 * This library is free software; you can redistribute it and/or modify 034 * it under the terms of the GNU Lesser General Public License as 035 * published by the Free Software Foundation; either version 3 of the 036 * License, or (at your option) any later version. <br> 037 * <br> 038 * This library is distributed in the hope that it will be useful, but 039 * WITHOUT ANY WARRANTY; without even the implied warranty of 040 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 041 * Lesser General Public License for more details. <br> 042 * <br> 043 * You should have received a copy of the GNU Lesser General Public 044 * License along with this library; if not see 045 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 046 */ 047public class RoomPenalty extends ExamCriterion { 048 protected Integer iSoftRooms = null; 049 050 @Override 051 public boolean init(Solver<Exam, ExamPlacement> solver) { 052 if (super.init(solver)) { 053 iSoftRooms = solver.getProperties().getPropertyInteger("Exam.SoftRooms", null); 054 if (iSoftRooms != null) { 055 RoomViolation rv = new RoomViolation(); 056 getModel().addCriterion(rv); 057 return rv.init(solver); 058 } 059 } 060 return true; 061 } 062 063 @Override 064 public String getWeightName() { 065 return "Exams.RoomWeight"; 066 } 067 068 @Override 069 public String getXmlWeightName() { 070 return "roomWeight"; 071 } 072 073 @Override 074 public double getWeightDefault(DataProperties config) { 075 return 0.1; 076 } 077 078 @Override 079 public double getValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value, Set<ExamPlacement> conflicts) { 080 double penalty = 0.0; 081 if (value.getRoomPlacements() != null) 082 for (ExamRoomPlacement r : value.getRoomPlacements()) { 083 penalty += (iSoftRooms != null && (iSoftRooms == r.getPenalty() || iSoftRooms == r.getPenalty(value.getPeriod())) ? 0.0 : r.getPenalty(value.getPeriod())); 084 } 085 return penalty; 086 } 087 088 private int getMinPenalty(ExamRoom r) { 089 int min = Integer.MAX_VALUE; 090 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) { 091 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms)) { 092 min = Math.min(min, r.getPenalty(p)); 093 } 094 } 095 return min; 096 } 097 098 private int getMaxPenalty(ExamRoom r) { 099 int max = Integer.MIN_VALUE; 100 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) { 101 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms)) { 102 max = Math.max(max, r.getPenalty(p)); 103 } 104 } 105 return max; 106 } 107 108 private boolean isAvailable(ExamRoom r) { 109 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) { 110 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms)) 111 return true; 112 } 113 return false; 114 } 115 116 @Override 117 public double[] getBounds(Assignment<Exam, ExamPlacement> assignment, Collection<Exam> variables) { 118 double[] bounds = new double[] { 0.0, 0.0 }; 119 for (Exam exam : variables) { 120 if (!exam.getRoomPlacements().isEmpty()) { 121 int minPenalty = Integer.MAX_VALUE, maxPenalty = Integer.MIN_VALUE; 122 for (ExamRoomPlacement roomPlacement : exam.getRoomPlacements()) { 123 if (iSoftRooms != null && iSoftRooms == roomPlacement.getPenalty()) continue; 124 if (!isAvailable(roomPlacement.getRoom())) continue; 125 minPenalty = Math.min(minPenalty, 2 * roomPlacement.getPenalty() + getMinPenalty(roomPlacement.getRoom())); 126 maxPenalty = Math.max(maxPenalty, 2 * roomPlacement.getPenalty() + getMaxPenalty(roomPlacement.getRoom())); 127 } 128 bounds[0] += minPenalty; 129 bounds[1] += maxPenalty; 130 } 131 } 132 return bounds; 133 } 134 135 @Override 136 public String toString(Assignment<Exam, ExamPlacement> assignment) { 137 return "RP:" + sDoubleFormat.format(getValue(assignment)); 138 } 139 140 @Override 141 public boolean isPeriodCriterion() { return false; } 142}