/** * */ package vroom.common.heuristics; import vroom.common.heuristics.utils.HeuristicsLogging; import vroom.common.utilities.optimization.IAcceptanceCriterion; import vroom.common.utilities.optimization.IInstance; import vroom.common.utilities.optimization.IMove; import vroom.common.utilities.optimization.INeighborhood; import vroom.common.utilities.optimization.IParameters; import vroom.common.utilities.optimization.ISolution; import vroom.common.utilities.optimization.ImprovingAcceptanceCriterion; /** * <code>GenericNeighborhood</code> is a base class for implementations of {@link INeighborhood} that contains a set of * constraints and a generic implementation of {@link INeighborhood#localSearch(IInstance, ISolution, IParameters)} and * {@link INeighborhood#localSearch(ISolution, IParameters)} * <p> * Creation date: Jun 22, 2010 - 9:21:21 AM * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 1.0 */ public abstract class NeighborhoodBase<S extends ISolution, M extends Move> implements INeighborhood<S, M> { /** A flag to toggle mSolution checking after each move */ private static boolean sCheckSolutionAfterMove = false; /** * Setter for <code>checkSolutionAfterMove</code> * * @param checkSolutionAfterMove * the checkSolutionAfterMove to set */ public static void setCheckSolutionAfterMove(boolean checkSolutionAfterMove) { sCheckSolutionAfterMove = checkSolutionAfterMove; if (isCheckSolutionAfterMove()) { HeuristicsLogging .getNeighborhoodsLogger() .warn("NeighborhoodBase.CheckSolutionAfterMove is set to true, set to false to increase performance (set in %s)", Thread.currentThread().getStackTrace()[2]); } } /** * Getter for <code>checkSolutionAfterMove</code> * * @return the checkSolutionAfterMove */ public static boolean isCheckSolutionAfterMove() { return sCheckSolutionAfterMove; } /** A constraint handler for this neighborhood **/ private final ConstraintHandler<S> mConstraintHandler; /** * Getter for the constraint handler * * @return A constraint handler for this neighborhood */ public ConstraintHandler<S> getConstraintHandler() { return this.mConstraintHandler; } /** * Creates a new <code>GenericNeighborhood</code> * * @param constraintHandler * the constraint handler to be used in this neighborhood */ public NeighborhoodBase(ConstraintHandler<S> constraintHandler) { mConstraintHandler = constraintHandler; } /** * Creates a new <code>GenericNeighborhood</code> with a default constraint handler */ public NeighborhoodBase() { this(new ConstraintHandler<S>()); } @Override public M exploreNeighborhood(S solution, IParameters params) { switch (params.getStrategy()) { case DET_FIRST_IMPROVEMENT: return deterministicFirstImprovement(solution, params); case DET_BEST_IMPROVEMENT: return deterministicBestImprovement(solution, params); case RND_FIRST_IMPROVEMENT: return randomFirstImprovement(solution, params); case RND_NON_IMPROVING: return randomNonImproving(solution, params); default: throw new IllegalArgumentException("Unsupported strategy: " + params.getStrategy()); } }; /** * Random exploration of the neighborhood accepting non improving moves * * @param solution * the solution which neighborhood will be explored * @param params * the local search parameters * @return a random move */ protected abstract M randomNonImproving(S solution, IParameters params); /** * Random exploration of the neighborhood accepting the first improving moves * * @param solution * the solution which neighborhood will be explored * @param params * the local search parameters * @return a random improving move */ protected abstract M randomFirstImprovement(S solution, IParameters params); /** * Deterministic exploration of the neighborhood accepting the best moves * * @param solution * the solution which neighborhood will be explored * @param params * the local search parameters * @return the most improving move */ protected abstract M deterministicBestImprovement(S solution, IParameters params); /** * Deterministic exploration of the neighborhood accepting the first improving moves * * @param solution * the solution which neighborhood will be explored * @param params * the local search parameters * @return an improving move */ protected abstract M deterministicFirstImprovement(S solution, IParameters params); @Override public boolean localSearch(S solution, IParameters params) { IAcceptanceCriterion acceptance = getAcceptanceCriterion(params); // if (params.acceptFirstImprovement()) { // // First improvement // M move = exploreNeighborhood(solution, params); // if (move != null && acceptance.accept(solution, this, move)) { // // Execute first improving move // executeMove(solution, move); // return true; // } else { // return false; // } // } else { // Thorough exploration boolean changed = false; M move = exploreNeighborhood(solution, params); while (move != null && acceptance.accept(solution, this, move)) { // Execute the best move executeMove(solution, move); changed = true; move = exploreNeighborhood(solution, params); } return changed; // } } @Override public S localSearch(IInstance instance, S solution, IParameters param) { @SuppressWarnings("unchecked") S clone = (S) solution.clone(); localSearch(clone, param); return clone; }; /** * Return the currently defined acceptance criterion * * @param params * optional parameters * @return the {@link IAcceptanceCriterion} defined in <code>params</code> if any, or an instance of * {@link ImprovingAcceptanceCriterion} */ protected IAcceptanceCriterion getAcceptanceCriterion(IParameters params) { return params != null && params.getAcceptanceCriterion() != null ? params .getAcceptanceCriterion() : new ImprovingAcceptanceCriterion(null); } /** * Check a solution for feasibility * * @param solution * @param move * @param before * <code>true</code> if this is a pre-check * @param prevState * the previous solution state, i.e., {@code true} if the value returned by the pre-check * @param prevSol * the solution as it was before the move was executed * @return {@code true} if the solution is feasible, false otherwise */ protected boolean checkSolution(S solution, IMove move, boolean before, boolean prevState, String prevSol) { if (isCheckSolutionAfterMove() && prevState) { String errCtr = getConstraintHandler().getInfeasibilityExplanation(solution); if (errCtr != null && prevState) { if (!before) { HeuristicsLogging .getNeighborhoodsLogger() .warn("%s: solution is infeasible/inconsistent %s executing move %s (err: %s, sol:%s)", this.getClass().getSimpleName(), before ? "before" : "after", move, errCtr, before ? solution : prevSol); } return false; } else { return true; } } return prevState; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName(); } @Override public void dispose() { // Do nothing } }