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.ifs.heuristics.NeighbourSelection; 012 import net.sf.cpsolver.ifs.model.Neighbour; 013 import net.sf.cpsolver.ifs.solution.Solution; 014 import net.sf.cpsolver.ifs.solver.Solver; 015 import net.sf.cpsolver.ifs.util.DataProperties; 016 import net.sf.cpsolver.ifs.util.ToolBox; 017 018 /** 019 * A new period is selected for a randomly selected exam. It tries to use the 020 * current set of rooms, if it is possible (exam is assigned, rooms are 021 * available and not used during the new period). Otherwise, rooms are selected 022 * using {@link Exam#findBestAvailableRooms(ExamPeriodPlacement)}. <br> 023 * <br> 024 * 025 * @version ExamTT 1.2 (Examination Timetabling)<br> 026 * Copyright (C) 2008 - 2010 Tomas Muller<br> 027 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 028 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 029 * <br> 030 * This library is free software; you can redistribute it and/or modify 031 * it under the terms of the GNU Lesser General Public License as 032 * published by the Free Software Foundation; either version 3 of the 033 * License, or (at your option) any later version. <br> 034 * <br> 035 * This library is distributed in the hope that it will be useful, but 036 * WITHOUT ANY WARRANTY; without even the implied warranty of 037 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 038 * Lesser General Public License for more details. <br> 039 * <br> 040 * You should have received a copy of the GNU Lesser General Public 041 * License along with this library; if not see 042 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 043 */ 044 public class ExamTimeMove implements NeighbourSelection<Exam,ExamPlacement> { 045 private boolean iCheckStudentConflicts = false; 046 private boolean iCheckDistributionConstraints = true; 047 048 /** 049 * Constructor 050 * @param properties problem properties 051 */ 052 public ExamTimeMove(DataProperties properties) { 053 iCheckStudentConflicts = properties.getPropertyBoolean("ExamTimeMove.CheckStudentConflicts", iCheckStudentConflicts); 054 iCheckDistributionConstraints = properties.getPropertyBoolean("ExamTimeMove.CheckDistributionConstraints", iCheckDistributionConstraints); 055 } 056 057 /** 058 * Initialization 059 */ 060 @Override 061 public void init(Solver<Exam,ExamPlacement> solver) {} 062 063 /** 064 * Select an exam randomly, 065 * select an available period randomly (if it is not assigned), 066 * use rooms if possible, select rooms using {@link Exam#findBestAvailableRooms(ExamPeriodPlacement)} if not (exam is unassigned, a room is not available or used). 067 */ 068 @Override 069 public Neighbour<Exam,ExamPlacement> selectNeighbour(Solution<Exam,ExamPlacement> solution) { 070 ExamModel model = (ExamModel)solution.getModel(); 071 Exam exam = ToolBox.random(model.variables()); 072 ExamPlacement placement = exam.getAssignment(); 073 int px = ToolBox.random(exam.getPeriodPlacements().size()); 074 for (int p=0;p<exam.getPeriodPlacements().size();p++) { 075 ExamPeriodPlacement period = exam.getPeriodPlacements().get((p+px)%exam.getPeriodPlacements().size()); 076 if (placement!=null && placement.getPeriod().equals(period)) continue; 077 if (iCheckStudentConflicts && exam.countStudentConflicts(period)>0) continue; 078 if (iCheckDistributionConstraints && !exam.checkDistributionConstraints(period)) continue; 079 if (placement!=null) { 080 boolean ok = true; 081 for (Iterator<ExamRoomPlacement> i=placement.getRoomPlacements().iterator();i.hasNext();) { 082 ExamRoomPlacement room = i.next(); 083 if (!room.isAvailable(period.getPeriod()) || room.getRoom().getPlacement(period.getPeriod())!=null) { 084 ok = false; break; 085 } 086 } 087 if (ok) 088 return new ExamSimpleNeighbour(new ExamPlacement(exam, period, placement.getRoomPlacements())); 089 } 090 Set<ExamRoomPlacement> rooms = exam.findBestAvailableRooms(period); 091 if (rooms==null) continue; 092 return new ExamSimpleNeighbour(new ExamPlacement(exam, period, rooms)); 093 } 094 return null; 095 } 096 }