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