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