001package org.cpsolver.ifs.extension; 002 003import java.util.Collection; 004import java.util.Map; 005 006import org.cpsolver.ifs.assignment.Assignment; 007import org.cpsolver.ifs.assignment.context.AssignmentContext; 008import org.cpsolver.ifs.assignment.context.ExtensionWithContext; 009import org.cpsolver.ifs.model.Model; 010import org.cpsolver.ifs.model.Value; 011import org.cpsolver.ifs.model.Variable; 012import org.cpsolver.ifs.solution.Solution; 013import org.cpsolver.ifs.solution.SolutionListener; 014import org.cpsolver.ifs.solver.Solver; 015import org.cpsolver.ifs.util.DataProperties; 016 017 018/** 019 * Go back to the best known solution when no better solution is found within 020 * the given amount of iterations. 021 * 022 * @author Tomáš Müller 023 * @version IFS 1.3 (Iterative Forward Search)<br> 024 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 025 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 026 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 027 * <br> 028 * This library is free software; you can redistribute it and/or modify 029 * it under the terms of the GNU Lesser General Public License as 030 * published by the Free Software Foundation; either version 3 of the 031 * License, or (at your option) any later version. <br> 032 * <br> 033 * This library is distributed in the hope that it will be useful, but 034 * WITHOUT ANY WARRANTY; without even the implied warranty of 035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036 * Lesser General Public License for more details. <br> 037 * <br> 038 * You should have received a copy of the GNU Lesser General Public 039 * License along with this library; if not see 040 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 041 * @param <V> Variable 042 * @param <T> Value 043 */ 044public class SearchIntensification<V extends Variable<V, T>, T extends Value<V, T>> extends ExtensionWithContext<V, T, SearchIntensification<V, T>.Context> implements SolutionListener<V, T> { 045 private static org.apache.logging.log4j.Logger sLogger = org.apache.logging.log4j.LogManager.getLogger(SearchIntensification.class); 046 private long iInitialIterationLimit = 100; 047 private ConflictStatistics<V, T> iCBS = null; 048 private int iResetInterval = 5; 049 private int iMux = 2; 050 private int iMuxInterval = 2; 051 052 public SearchIntensification(Solver<V, T> solver, DataProperties properties) { 053 super(solver, properties); 054 iInitialIterationLimit = properties.getPropertyLong("SearchIntensification.IterationLimit", iInitialIterationLimit); 055 iResetInterval = properties.getPropertyInt("SearchIntensification.ResetInterval", iResetInterval); 056 iMuxInterval = properties.getPropertyInt("SearchIntensification.MultiplyInterval", iMuxInterval); 057 iMux = properties.getPropertyInt("SearchIntensification.Multiply", iMux); 058 } 059 060 @Override 061 public boolean init(Solver<V, T> solver) { 062 if (iResetInterval > 0) { 063 for (Extension<V, T> ex : solver.getExtensions()) { 064 if (ConflictStatistics.class.isInstance(ex)) { 065 iCBS = (ConflictStatistics<V, T>) ex; 066 break; 067 } 068 } 069 } 070 return super.init(solver); 071 } 072 073 @Override 074 public void register(Model<V, T> model) { 075 super.register(model); 076 getSolver().currentSolution().addSolutionListener(this); 077 } 078 079 @Override 080 public void unregister(Model<V, T> model) { 081 super.unregister(model); 082 getSolver().currentSolution().removeSolutionListener(this); 083 } 084 085 @Override 086 public void afterAssigned(Assignment<V, T> assignment, long iteration, T value) { 087 getContext(assignment).afterAssigned(assignment, iteration, value); 088 } 089 090 @Override 091 public void bestSaved(Solution<V, T> solution) { 092 Context context = getContext(solution.getAssignment()); 093 context.bestSaved(solution); 094 } 095 096 @Override 097 public void solutionUpdated(Solution<V, T> solution) { 098 } 099 100 @Override 101 public void bestCleared(Solution<V, T> solution) { 102 } 103 104 @Override 105 public void bestRestored(Solution<V, T> solution) { 106 } 107 108 @Override 109 public void getInfo(Solution<V, T> solution, Map<String, String> info) { 110 } 111 112 @Override 113 public void getInfo(Solution<V, T> solution, Map<String, String> info, Collection<V> variables) { 114 } 115 116 /** 117 * Assignment context 118 */ 119 public class Context implements AssignmentContext { 120 private int iResetCounter = 0; 121 private int iMuxCounter = 0; 122 private long iLastReturn = 0; 123 private long iIterationLimit = 100; 124 125 public Context(Assignment<V, T> assignment) { 126 iIterationLimit = iInitialIterationLimit; 127 } 128 129 public void afterAssigned(Assignment<V, T> assignment, long iteration, T value) { 130 if (iIterationLimit > 0 && iteration > 0) { 131 Solution<V, T> solution = getSolver().currentSolution(); 132 if (solution.getBestIteration() < 0 || !solution.isBestComplete()) 133 return; 134 long bestIt = Math.max(solution.getBestIteration(), iLastReturn); 135 long currIt = solution.getIteration(); 136 if (currIt - bestIt > iIterationLimit) { 137 iLastReturn = currIt; 138 iResetCounter++; 139 iMuxCounter++; 140 sLogger.debug("Going back to the best known solution..."); 141 solution.restoreBest(); 142 sLogger.debug("Reset counter set to " + iResetCounter); 143 if (iMuxInterval > 0 && (iMuxCounter % iMuxInterval) == 0) { 144 iIterationLimit *= iMux; 145 sLogger.debug("Iteration limit increased to " + iIterationLimit); 146 } 147 if (iCBS != null && iResetInterval > 0 && (iResetCounter % iResetInterval) == 0) { 148 sLogger.debug("Reseting CBS..."); 149 iCBS.reset(); 150 } 151 } 152 } 153 } 154 155 public void bestSaved(Solution<V, T> solution) { 156 if (iResetCounter > 0) 157 sLogger.debug("Reset counter set to zero."); 158 iResetCounter = 0; 159 iMuxCounter = 0; 160 iIterationLimit = iInitialIterationLimit; 161 } 162 } 163 164 @Override 165 public Context createAssignmentContext(Assignment<V, T> assignment) { 166 return new Context(assignment); 167 } 168}