001package org.cpsolver.exam.criteria; 002 003import java.util.Arrays; 004import java.util.Map; 005import java.util.Set; 006 007import org.cpsolver.exam.model.Exam; 008import org.cpsolver.exam.model.ExamPlacement; 009import org.cpsolver.ifs.assignment.Assignment; 010import org.cpsolver.ifs.util.DataProperties; 011 012 013/** 014 * Cost for using more than one room (nrSplits^2). 015 * <br><br> 016 * A weight for room split penalty can be set by problem 017 * property Exams.RoomSplitWeight, or in the input xml file, property 018 * roomSplitWeight. 019 * 020 * <br> 021 * 022 * @version ExamTT 1.3 (Examination Timetabling)<br> 023 * Copyright (C) 2008 - 2014 Tomáš Müller<br> 024 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 025 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 026 * <br> 027 * This library is free software; you can redistribute it and/or modify 028 * it under the terms of the GNU Lesser General Public License as 029 * published by the Free Software Foundation; either version 3 of the 030 * License, or (at your option) any later version. <br> 031 * <br> 032 * This library is distributed in the hope that it will be useful, but 033 * WITHOUT ANY WARRANTY; without even the implied warranty of 034 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 035 * Lesser General Public License for more details. <br> 036 * <br> 037 * You should have received a copy of the GNU Lesser General Public 038 * License along with this library; if not see 039 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 040 */ 041public class RoomSplitPenalty extends ExamCriterion { 042 043 @Override 044 public ValueContext createAssignmentContext(Assignment<Exam, ExamPlacement> assignment) { 045 return new RoomSplitContext(assignment); 046 } 047 048 @Override 049 public String getWeightName() { 050 return "Exams.RoomSplitWeight"; 051 } 052 053 @Override 054 public String getXmlWeightName() { 055 return "roomSplitWeight"; 056 } 057 058 @Override 059 public double getWeightDefault(DataProperties config) { 060 return 10.0; 061 } 062 063 @Override 064 public double getValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value, Set<ExamPlacement> conflicts) { 065 return (value.getRoomPlacements() == null || value.getRoomPlacements().size() <= 1 ? 0 : (value.getRoomPlacements().size() - 1) * (value.getRoomPlacements().size() - 1)); 066 } 067 068 @Override 069 public void getInfo(Assignment<Exam, ExamPlacement> assignment, Map<String, String> info) { 070 if (getValue(assignment) != 0.0) { 071 int[] roomSplits = ((RoomSplitContext)getContext(assignment)).getRoomSplits(); 072 String split = ""; 073 for (int i = 0; i < roomSplits.length; i++) { 074 if (roomSplits[i] > 0) { 075 if (split.length() > 0) 076 split += ", "; 077 split += roomSplits[i] + "×" + (i + 2); 078 } 079 } 080 info.put(getName(), sDoubleFormat.format(getValue(assignment)) + " (" + split + ")"); 081 } 082 } 083 084 @Override 085 public String toString(Assignment<Exam, ExamPlacement> assignment) { 086 return "RSp:" + sDoubleFormat.format(getValue(assignment)); 087 } 088 089 @Override 090 public boolean isPeriodCriterion() { return false; } 091 092 protected class RoomSplitContext extends ValueContext { 093 private int iRoomSplits[] = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 094 095 protected void ensureCapacity(int minCapacity) { 096 if (minCapacity > iRoomSplits.length){ 097 int oldCapacity = iRoomSplits.length; 098 int newCapacity = oldCapacity + (oldCapacity / 2); 099 if (newCapacity < minCapacity) 100 newCapacity = minCapacity + (minCapacity / 2); 101 iRoomSplits = Arrays.copyOf(iRoomSplits, newCapacity); 102 } 103 } 104 105 public RoomSplitContext(Assignment<Exam, ExamPlacement> assignment) { 106 super(assignment); 107 for (Exam exam: getModel().variables()) { 108 ExamPlacement placement = assignment.getValue(exam); 109 if (placement != null && placement.getRoomPlacements() != null && placement.getRoomPlacements().size() > 1) { 110 ensureCapacity(placement.getRoomPlacements().size()); 111 iRoomSplits[placement.getRoomPlacements().size() - 2] ++; 112 } 113 } 114 } 115 116 @Override 117 public void assigned(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 118 super.assigned(assignment, value); 119 if (value.getRoomPlacements() != null && value.getRoomPlacements().size() > 1) { 120 ensureCapacity(value.getRoomPlacements().size()); 121 iRoomSplits[value.getRoomPlacements().size() - 2] ++; 122 } 123 } 124 125 @Override 126 public void unassigned(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 127 super.unassigned(assignment, value); 128 if (value.getRoomPlacements() != null && value.getRoomPlacements().size() > 1) { 129 ensureCapacity(value.getRoomPlacements().size()); 130 iRoomSplits[value.getRoomPlacements().size() - 2] --; 131 } 132 } 133 134 public int[] getRoomSplits() { 135 return iRoomSplits; 136 } 137 } 138}