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