001package org.cpsolver.coursett.neighbourhoods; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import java.util.Map; 007import java.util.Set; 008import java.util.concurrent.locks.Lock; 009 010import org.cpsolver.coursett.model.Lecture; 011import org.cpsolver.coursett.model.Placement; 012import org.cpsolver.coursett.model.RoomLocation; 013import org.cpsolver.coursett.model.TimetableModel; 014import org.cpsolver.ifs.algorithms.neighbourhoods.RandomSwapMove; 015import org.cpsolver.ifs.assignment.Assignment; 016import org.cpsolver.ifs.model.Neighbour; 017import org.cpsolver.ifs.model.SimpleNeighbour; 018import org.cpsolver.ifs.solution.Solution; 019import org.cpsolver.ifs.solver.Solver; 020import org.cpsolver.ifs.util.DataProperties; 021import org.cpsolver.ifs.util.JProf; 022import org.cpsolver.ifs.util.ToolBox; 023 024 025/** 026 * Try to assign a class with a new room. A class is selected randomly, a 027 * different room is randomly selected for the class -- the class is 028 * assigned into the new room. If the room is used or there is some other conflict, 029 * it tries to resolve these conflicts by assigning conflicting classes to other 030 * rooms as well. 031 * <br> 032 * 033 * @author Tomáš Müller 034 * @version IFS 1.3 (Iterative Forward Search)<br> 035 * Copyright (C) 2014 Tomáš Müller<br> 036 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 037 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 038 * <br> 039 * This library is free software; you can redistribute it and/or modify 040 * it under the terms of the GNU Lesser General Public License as 041 * published by the Free Software Foundation; either version 3 of the 042 * License, or (at your option) any later version. <br> 043 * <br> 044 * This library is distributed in the hope that it will be useful, but 045 * WITHOUT ANY WARRANTY; without even the implied warranty of 046 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 047 * Lesser General Public License for more details. <br> 048 * <br> 049 * You should have received a copy of the GNU Lesser General Public 050 * License along with this library; if not see 051 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 052 */ 053public class RoomSwap extends RandomSwapMove<Lecture, Placement> { 054 055 public RoomSwap(DataProperties config) { 056 super(config); 057 } 058 059 @Override 060 public void init(Solver<Lecture, Placement> solver) { 061 } 062 063 @Override 064 public Neighbour<Lecture, Placement> selectNeighbour(Solution<Lecture, Placement> solution) { 065 TimetableModel model = (TimetableModel)solution.getModel(); 066 Assignment<Lecture, Placement> assignment = solution.getAssignment(); 067 double total = model.getTotalValue(assignment); 068 int varIdx = ToolBox.random(model.variables().size()); 069 for (int i = 0; i < model.variables().size(); i++) { 070 Lecture lecture = model.variables().get((i + varIdx) % model.variables().size()); 071 Placement old = assignment.getValue(lecture); 072 if (old == null || old.getNrRooms() != 1) continue; 073 074 List<RoomLocation> values = lecture.roomLocations(); 075 if (values.isEmpty()) continue; 076 077 Lock lock = solution.getLock().writeLock(); 078 lock.lock(); 079 try { 080 int attempts = 0; 081 int valIdx = ToolBox.random(values.size()); 082 long startTime = JProf.currentTimeMillis(); 083 for (int j = 0; j < values.size(); j++) { 084 RoomLocation room = values.get((j + valIdx) % values.size()); 085 if (room.getPreference() > 50) continue; 086 if (room.equals(old.getRoomLocation())) continue; 087 088 Placement placement = new Placement(lecture, old.getTimeLocation(), room); 089 if (!placement.isValid()) continue; 090 091 Set<Placement> conflicts = model.conflictValues(assignment, placement); 092 if (conflicts.contains(placement)) continue; 093 if (conflicts.isEmpty()) { 094 SimpleNeighbour<Lecture, Placement> n = new SimpleNeighbour<Lecture, Placement>(lecture, placement); 095 if (!iHC || n.value(assignment) <= 0) return n; 096 else continue; 097 } 098 099 Map<Lecture, Placement> assignments = new HashMap<Lecture, Placement>(); 100 assignments.put(lecture, placement); 101 102 for (Placement conflict: conflicts) 103 assignment.unassign(solution.getIteration(), conflict.variable()); 104 assignment.assign(solution.getIteration(), placement); 105 106 Double v = resolve(solution, total, startTime, assignments, new ArrayList<Placement>(conflicts), 0); 107 if (!conflicts.isEmpty()) 108 attempts ++; 109 110 assignment.unassign(solution.getIteration(), lecture); 111 for (Placement conflict: conflicts) 112 assignment.assign(solution.getIteration(), conflict); 113 assignment.assign(solution.getIteration(), old); 114 115 if (v != null) 116 return new SwapNeighbour(assignments.values(), v); 117 118 if (attempts >= iMaxAttempts) break; 119 } 120 } finally { 121 lock.unlock(); 122 } 123 } 124 return null; 125 } 126 127 128 @Override 129 public Double resolve(Solution<Lecture, Placement> solution, double total, long startTime, Map<Lecture, Placement> assignments, List<Placement> conflicts, int index) { 130 Assignment<Lecture, Placement> assignment = solution.getAssignment(); 131 132 if (index == conflicts.size()) return solution.getModel().getTotalValue(assignment) - total; 133 Placement conflict = conflicts.get(index); 134 Lecture variable = conflict.variable(); 135 136 if (conflict.getNrRooms() != 1) return null; 137 138 List<RoomLocation> values = variable.roomLocations(); 139 if (values.isEmpty()) return null; 140 141 int valIdx = ToolBox.random(values.size()); 142 int attempts = 0; 143 for (int i = 0; i < values.size(); i++) { 144 RoomLocation room = values.get((i + valIdx) % values.size()); 145 if (room.getPreference() > 50) continue; 146 if (room.equals(conflict.getRoomLocation())) continue; 147 148 Placement value = new Placement(variable, conflict.getTimeLocation(), room); 149 if (!value.isValid() || solution.getModel().inConflict(assignment, value)) continue; 150 151 assignment.assign(solution.getIteration(), value); 152 Double v = resolve(solution, total, startTime, assignments, conflicts, 1 + index); 153 assignment.unassign(solution.getIteration(), variable); 154 attempts ++; 155 156 if (v != null && (!iHC || v <= 0)) { 157 assignments.put(variable, value); 158 return v; 159 } 160 if (attempts >= iMaxAttempts || isTimeLimitReached(startTime)) break; 161 } 162 163 return null; 164 } 165}