001 package net.sf.cpsolver.exam.neighbours;
002
003 import java.util.Iterator;
004 import java.util.Set;
005
006 import net.sf.cpsolver.exam.model.Exam;
007 import net.sf.cpsolver.exam.model.ExamModel;
008 import net.sf.cpsolver.exam.model.ExamPeriodPlacement;
009 import net.sf.cpsolver.exam.model.ExamPlacement;
010 import net.sf.cpsolver.exam.model.ExamRoomPlacement;
011 import net.sf.cpsolver.exam.model.ExamRoomSharing;
012 import net.sf.cpsolver.ifs.heuristics.NeighbourSelection;
013 import net.sf.cpsolver.ifs.model.Neighbour;
014 import net.sf.cpsolver.ifs.solution.Solution;
015 import net.sf.cpsolver.ifs.solver.Solver;
016 import net.sf.cpsolver.ifs.util.DataProperties;
017 import net.sf.cpsolver.ifs.util.ToolBox;
018
019 /**
020 * A new period is selected for a randomly selected exam. It tries to use the
021 * current set of rooms, if it is possible (exam is assigned, rooms are
022 * available and not used during the new period). Otherwise, rooms are selected
023 * using {@link Exam#findBestAvailableRooms(ExamPeriodPlacement)}. <br>
024 * <br>
025 *
026 * @version ExamTT 1.2 (Examination Timetabling)<br>
027 * Copyright (C) 2008 - 2010 Tomas Muller<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 */
045 public class ExamTimeMove implements NeighbourSelection<Exam,ExamPlacement> {
046 private boolean iCheckStudentConflicts = false;
047 private boolean iCheckDistributionConstraints = true;
048
049 /**
050 * Constructor
051 * @param properties problem properties
052 */
053 public ExamTimeMove(DataProperties properties) {
054 iCheckStudentConflicts = properties.getPropertyBoolean("ExamTimeMove.CheckStudentConflicts", iCheckStudentConflicts);
055 iCheckDistributionConstraints = properties.getPropertyBoolean("ExamTimeMove.CheckDistributionConstraints", iCheckDistributionConstraints);
056 }
057
058 /**
059 * Initialization
060 */
061 @Override
062 public void init(Solver<Exam,ExamPlacement> solver) {}
063
064 /**
065 * Select an exam randomly,
066 * select an available period randomly (if it is not assigned),
067 * use rooms if possible, select rooms using {@link Exam#findBestAvailableRooms(ExamPeriodPlacement)} if not (exam is unassigned, a room is not available or used).
068 */
069 @Override
070 public Neighbour<Exam,ExamPlacement> selectNeighbour(Solution<Exam,ExamPlacement> solution) {
071 ExamModel model = (ExamModel)solution.getModel();
072 ExamRoomSharing sharing = model.getRoomSharing();
073 Exam exam = ToolBox.random(model.variables());
074 ExamPlacement placement = exam.getAssignment();
075 int px = ToolBox.random(exam.getPeriodPlacements().size());
076 for (int p=0;p<exam.getPeriodPlacements().size();p++) {
077 ExamPeriodPlacement period = exam.getPeriodPlacements().get((p+px)%exam.getPeriodPlacements().size());
078 if (placement!=null && placement.getPeriod().equals(period)) continue;
079 if (iCheckStudentConflicts && exam.countStudentConflicts(period)>0) continue;
080 if (iCheckDistributionConstraints && !exam.checkDistributionConstraints(period)) continue;
081 if (placement!=null) {
082 boolean ok = true;
083 if (sharing != null && placement.getRoomPlacements().size() == 1) {
084 ExamRoomPlacement room = placement.getRoomPlacements().iterator().next();
085 ok = room.isAvailable(period.getPeriod()) && !sharing.inConflict(exam, room.getRoom().getPlacements(period.getPeriod()), room.getRoom());
086 } else {
087 for (Iterator<ExamRoomPlacement> i=placement.getRoomPlacements().iterator();i.hasNext();) {
088 ExamRoomPlacement room = i.next();
089 if (!room.isAvailable(period.getPeriod()) || !room.getRoom().getPlacements(period.getPeriod()).isEmpty()) {
090 ok = false; break;
091 }
092 }
093 }
094 if (ok)
095 return new ExamSimpleNeighbour(new ExamPlacement(exam, period, placement.getRoomPlacements()));
096 }
097 Set<ExamRoomPlacement> rooms = exam.findBestAvailableRooms(period);
098 if (rooms==null) continue;
099 return new ExamSimpleNeighbour(new ExamPlacement(exam, period, rooms));
100 }
101 return null;
102 }
103 }