001package org.cpsolver.exam.model; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.List; 006import java.util.Set; 007 008import org.cpsolver.coursett.IdConvertor; 009import org.cpsolver.ifs.model.Model; 010import org.cpsolver.ifs.util.DataProperties; 011import org.cpsolver.ifs.util.ToolBox; 012import org.dom4j.Element; 013 014 015/** 016 * Abstract room sharing model. Defines when and under what conditions two or more exams can share a room.<br> 017 * <br> 018 * 019 * @author Tomáš Müller 020 * @version ExamTT 1.3 (Examination Timetabling)<br> 021 * Copyright (C) 2008 - 2014 Tomáš Müller<br> 022 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 023 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 024 * <br> 025 * This library is free software; you can redistribute it and/or modify 026 * it under the terms of the GNU Lesser General Public License as 027 * published by the Free Software Foundation; either version 3 of the 028 * License, or (at your option) any later version. <br> 029 * <br> 030 * This library is distributed in the hope that it will be useful, but 031 * WITHOUT ANY WARRANTY; without even the implied warranty of 032 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 033 * Lesser General Public License for more details. <br> 034 * <br> 035 * You should have received a copy of the GNU Lesser General Public 036 * License along with this library; if not see 037 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 038 */ 039public abstract class ExamRoomSharing { 040 041 public ExamRoomSharing(Model<Exam, ExamPlacement> model, DataProperties config) {} 042 043 /** 044 * True if given examination can not be placed in the same room at the same period as the other examinations 045 * @param exam examination placement in question 046 * @param other exams currently assigned in the room at the requested period 047 * @param room examination room in questions 048 * @return true if there is a conflict 049 */ 050 public boolean inConflict(ExamPlacement exam, Collection<ExamPlacement> other, ExamRoom room) { 051 if (exam.getRoomPlacements().size() != 1) 052 return !other.isEmpty(); 053 054 return inConflict(exam.variable(), other, room); 055 } 056 057 /** 058 * True if given examination can not be placed in the same room at the same period as the other examinations 059 * @param exam examination in question 060 * @param other exams currently assigned in the room at the requested period 061 * @param room examination room in questions 062 * @return true if there is a conflict 063 */ 064 public boolean inConflict(Exam exam, Collection<ExamPlacement> other, ExamRoom room) { 065 int total = exam.getSize(); 066 boolean altSeating = exam.hasAltSeating(); 067 for (ExamPlacement x: other) { 068 if (x.variable().equals(exam)) continue; 069 if (x.getRoomPlacements().size() != 1) return true; // already split into multiple rooms 070 if (!canShareRoom(exam, x.variable())) return true; // sharing not allowed between the pair 071 total += x.variable().getSize(); 072 if (x.variable().hasAltSeating()) altSeating = true; 073 } 074 075 return total > (altSeating ? room.getAltSize() : room.getSize()); // check size limit 076 } 077 078 /** 079 * Compute conflicting placement for the case when a given examination needs to be placed in the same room at the same period as the other examinations 080 * @param exam examination placement in question 081 * @param other exams currently assigned in the room at the requested period 082 * @param room examination room in questions 083 * @param conflicts set of conflicting assignments 084 */ 085 public void computeConflicts(ExamPlacement exam, Collection<ExamPlacement> other, ExamRoom room, Set<ExamPlacement> conflicts) { 086 // more than one room is required -> no sharing 087 if (exam.getRoomPlacements().size() != 1) { 088 conflicts.addAll(other); 089 return; 090 } 091 092 computeConflicts(exam.variable(), other, room, conflicts); 093 } 094 095 /** 096 * Compute conflicting placement for the case when a given examination needs to be placed in the same room at the same period as the other examinations 097 * @param exam examination in question 098 * @param other exams currently assigned in the room at the requested period 099 * @param room examination room in questions 100 * @param conflicts set of conflicting assignments 101 */ 102 public void computeConflicts(Exam exam, Collection<ExamPlacement> other, ExamRoom room, Set<ExamPlacement> conflicts) { 103 int total = exam.getSize(); 104 boolean altSeating = exam.hasAltSeating(); 105 List<ExamPlacement> adepts = new ArrayList<ExamPlacement>(); 106 for (ExamPlacement x: other) { 107 if (x.variable().equals(exam)) continue; 108 // already a conflict -> do not count 109 if (conflicts.contains(x)) continue; 110 // already split into multiple rooms 111 if (x.getRoomPlacements().size() != 1) { 112 conflicts.add(x); continue; 113 } 114 // sharing not allowed between the pair 115 if (!canShareRoom(exam, x.variable())) { 116 conflicts.add(x); continue; 117 } 118 if (x.variable().hasAltSeating()) altSeating = true; 119 total += x.variable().getSize(); 120 adepts.add(x); 121 } 122 123 // fix the total size if needed 124 while (total > (altSeating ? room.getAltSize() : room.getSize()) && !adepts.isEmpty()) { 125 ExamPlacement x = ToolBox.random(adepts); 126 adepts.remove(x); 127 conflicts.add(x); 128 total -= x.variable().getSize(); 129 } 130 } 131 132 133 /** 134 * True if given two exams can share a room 135 * @param x1 first exam 136 * @param x2 second exam 137 * @return true if the two exams can share a room 138 */ 139 public abstract boolean canShareRoom(Exam x1, Exam x2); 140 141 /** 142 * Save sharing information (if needed) for a given exam 143 * @param exam exam in question 144 * @param element XML exam element to include sharing information 145 * @param idConvertor id converter 146 */ 147 public void save(Exam exam, Element element, IdConvertor idConvertor) {} 148 149 /** 150 * Load sharing information (if needed) for a given exam 151 * @param exam exam in question 152 * @param element XML exam element including sharing information 153 */ 154 public void load(Exam exam, Element element) {} 155}