001 package net.sf.cpsolver.exam.heuristics; 002 003 import org.apache.log4j.Logger; 004 005 import net.sf.cpsolver.ifs.heuristics.NeighbourSelection; 006 import net.sf.cpsolver.ifs.heuristics.StandardNeighbourSelection; 007 import net.sf.cpsolver.ifs.model.Neighbour; 008 import net.sf.cpsolver.ifs.solution.Solution; 009 import net.sf.cpsolver.ifs.solver.Solver; 010 import net.sf.cpsolver.ifs.termination.TerminationCondition; 011 import net.sf.cpsolver.ifs.util.Callback; 012 import net.sf.cpsolver.ifs.util.DataProperties; 013 import net.sf.cpsolver.ifs.util.Progress; 014 015 /** 016 * Examination timetabling neighbour selection. 017 * <br><br> 018 * It consists of the following three phases: 019 * <ul> 020 * <li>Construction phase ({@link ExamConstruction} until all exams are assigned) 021 * <li>Hill-climbing phase ({@link ExamHillClimbing} until the given number if idle iterations) 022 * <li>Simulated annealing phase ({@link ExamSimulatedAnnealing} until timeout is reached) 023 * <ul> 024 * <li>Or greate deluge phase (when Exam.GreatDeluge is true,{@link ExamGreatDeluge} until timeout is reached) 025 * </ul> 026 * <li>At the end (when {@link TerminationCondition#canContinue(Solution)} is false), the search is finished with one sweep 027 * of final phase ({@link ExamHillClimbing} until the given number if idle iterations). 028 * </ul> 029 * <br><br> 030 * 031 * @version 032 * ExamTT 1.1 (Examination Timetabling)<br> 033 * Copyright (C) 2008 Tomáš Müller<br> 034 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 035 * Lazenska 391, 76314 Zlin, Czech Republic<br> 036 * <br> 037 * This library is free software; you can redistribute it and/or 038 * modify it under the terms of the GNU Lesser General Public 039 * License as published by the Free Software Foundation; either 040 * version 2.1 of the License, or (at your option) any later version. 041 * <br><br> 042 * This library is distributed in the hope that it will be useful, 043 * but WITHOUT ANY WARRANTY; without even the implied warranty of 044 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 045 * Lesser General Public License for more details. 046 * <br><br> 047 * You should have received a copy of the GNU Lesser General Public 048 * License along with this library; if not, write to the Free Software 049 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 050 */ 051 public class ExamNeighbourSelection implements NeighbourSelection, TerminationCondition { 052 private static Logger sLog = Logger.getLogger(ExamNeighbourSelection.class); 053 private ExamConstruction iCon = null; 054 private StandardNeighbourSelection iStd = null; 055 private ExamSimulatedAnnealing iSA = null; 056 private ExamHillClimbing iHC = null; 057 private ExamHillClimbing iFin = null; 058 private ExamGreatDeluge iGD = null; 059 private int iPhase = -1; 060 private boolean iUseGD = false; 061 private Progress iProgress = null; 062 private Callback iFinalPhaseFinished = null; 063 private boolean iCanContinue = true; 064 private TerminationCondition iTerm = null; 065 066 /** 067 * Constructor 068 * @param properties problem properties 069 */ 070 public ExamNeighbourSelection(DataProperties properties) { 071 iCon = new ExamConstruction(properties); 072 try { 073 iStd = new StandardNeighbourSelection(properties); 074 iStd.setVariableSelection(new ExamUnassignedVariableSelection(properties)); 075 iStd.setValueSelection(new ExamTabuSearch(properties)); 076 } catch (Exception e) { 077 sLog.error("Unable to initialize standard selection, reason: "+e.getMessage(),e); 078 iStd = null; 079 } 080 iSA = new ExamSimulatedAnnealing(properties); 081 iHC = new ExamHillClimbing(properties,"Hill Climbing"); 082 iFin = new ExamHillClimbing(properties,"Finalization"); 083 iGD = new ExamGreatDeluge(properties); 084 iUseGD = properties.getPropertyBoolean("Exam.GreatDeluge", iUseGD); 085 } 086 087 /** 088 * Initialization 089 */ 090 public void init(Solver solver){ 091 iCon.init(solver); 092 iStd.init(solver); 093 iSA.init(solver); 094 iHC.init(solver); 095 iFin.init(solver); 096 iGD.init(solver); 097 if (iTerm==null) { 098 iTerm = solver.getTerminationCondition(); 099 solver.setTerminalCondition(this); 100 } 101 iCanContinue = true; 102 iProgress = Progress.getInstance(solver.currentSolution().getModel()); 103 } 104 105 /** 106 * Neighbour selection. It consists of the following three phases: 107 * <ul> 108 * <li>Construction phase ({@link ExamConstruction} until all exams are assigned) 109 * <li>Hill-climbing phase ({@link ExamHillClimbing} until the given number if idle iterations) 110 * <li>Simulated annealing phase ({@link ExamSimulatedAnnealing} until timeout is reached) 111 * </ul> 112 */ 113 public synchronized Neighbour selectNeighbour(Solution solution) { 114 Neighbour n = null; 115 if (!isFinalPhase() && !iTerm.canContinue(solution)) setFinalPhase(null); 116 switch (iPhase) { 117 case -1 : 118 iPhase++; 119 sLog.info("***** construction phase *****"); 120 case 0 : 121 n = iCon.selectNeighbour(solution); 122 if (n!=null) return n; 123 if (solution.getModel().nrUnassignedVariables()>0) 124 iProgress.setPhase("Searching for initial solution...", solution.getModel().variables().size()); 125 iPhase++; 126 sLog.info("***** cbs/tabu-search phase *****"); 127 case 1 : 128 if (iStd!=null && solution.getModel().nrUnassignedVariables()>0) { 129 iProgress.setProgress(solution.getModel().variables().size()-solution.getModel().getBestUnassignedVariables()); 130 n = iStd.selectNeighbour(solution); 131 if (n!=null) return n; 132 } 133 iPhase++; 134 sLog.info("***** hill climbing phase *****"); 135 case 2 : 136 n = iHC.selectNeighbour(solution); 137 if (n!=null) return n; 138 iPhase++; 139 sLog.info("***** "+(iUseGD?"great deluge":"simulated annealing")+" phase *****"); 140 case 3 : 141 if (iUseGD) 142 return iGD.selectNeighbour(solution); 143 else 144 return iSA.selectNeighbour(solution); 145 case 9999 : 146 n = iFin.selectNeighbour(solution); 147 if (n!=null) return n; 148 iPhase = -1; 149 if (iFinalPhaseFinished!=null) iFinalPhaseFinished.execute(); 150 iCanContinue = false; 151 default : 152 return null; 153 } 154 } 155 156 /** Set final phase 157 * @param finalPhaseFinished to be called when the final phase is finished 158 **/ 159 public synchronized void setFinalPhase(Callback finalPhaseFinished) { 160 sLog.info("***** final phase *****"); 161 iFinalPhaseFinished = finalPhaseFinished; 162 iPhase = 9999; 163 } 164 165 /** Is final phase */ 166 public boolean isFinalPhase() { 167 return iPhase == 9999; 168 } 169 170 /** Termination condition (i.e., has final phase finished)*/ 171 public boolean canContinue(Solution currentSolution) { 172 return iCanContinue; 173 } 174 175 }