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 current
020     * set of rooms, if it is possible (exam is assigned, rooms are available and
021     * not used during the new period). Otherwise, rooms are selected using 
022     * {@link Exam#findBestAvailableRooms(ExamPeriodPlacement)}. 
023     * <br><br>
024     * 
025     * @version
026     * ExamTT 1.1 (Examination Timetabling)<br>
027     * Copyright (C) 2008 Tomáš Müller<br>
028     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
029     * Lazenska 391, 76314 Zlin, Czech Republic<br>
030     * <br>
031     * This library is free software; you can redistribute it and/or
032     * modify it under the terms of the GNU Lesser General Public
033     * License as published by the Free Software Foundation; either
034     * version 2.1 of the License, or (at your option) any later version.
035     * <br><br>
036     * This library is distributed in the hope that it will be useful,
037     * but 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.
040     * <br><br>
041     * You should have received a copy of the GNU Lesser General Public
042     * License along with this library; if not, write to the Free Software
043     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
044     */
045    public class ExamTimeMove implements NeighbourSelection {
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        public void init(Solver 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        public Neighbour selectNeighbour(Solution solution) {
069            ExamModel model = (ExamModel)solution.getModel();
070            Exam exam = (Exam)ToolBox.random(model.variables());
071            ExamPlacement placement = (ExamPlacement)exam.getAssignment();
072            int px = ToolBox.random(exam.getPeriodPlacements().size());
073            for (int p=0;p<exam.getPeriodPlacements().size();p++) {
074                ExamPeriodPlacement period = (ExamPeriodPlacement)exam.getPeriodPlacements().elementAt((p+px)%exam.getPeriodPlacements().size());
075                if (placement!=null && placement.getPeriod().equals(period)) continue;
076                if (iCheckStudentConflicts && exam.countStudentConflicts(period)>0) continue;
077                if (iCheckDistributionConstraints && !exam.checkDistributionConstraints(period)) continue;
078                if (placement!=null) {
079                    boolean ok = true;
080                    for (Iterator i=placement.getRoomPlacements().iterator();i.hasNext();) {
081                        ExamRoomPlacement room = (ExamRoomPlacement)i.next();
082                        if (!room.isAvailable(period.getPeriod()) || room.getRoom().getPlacement(period.getPeriod())!=null) {
083                            ok = false; break;
084                        }
085                    }
086                    if (ok)
087                        return new ExamSimpleNeighbour(new ExamPlacement(exam, period, placement.getRoomPlacements()));
088                }
089                Set rooms = exam.findBestAvailableRooms(period);
090                if (rooms==null) continue;
091                return new ExamSimpleNeighbour(new ExamPlacement(exam, period, rooms));
092            }
093            return null;
094        }
095    }