/** * */ package vroom.trsp.optimization.localSearch; import vroom.common.heuristics.Move; import vroom.common.heuristics.NeighborhoodBase; import vroom.common.utilities.optimization.IInstance; import vroom.common.utilities.optimization.IMove; import vroom.common.utilities.optimization.IParameters; import vroom.trsp.datamodel.ITRSPTour; import vroom.trsp.datamodel.TRSPTour; import vroom.trsp.datamodel.TRSPTour.TRSPTourIterator; import vroom.trsp.optimization.TRSPMove; import vroom.trsp.optimization.constraints.TourConstraintHandler; import vroom.trsp.optimization.localSearch.TRSPTwoOpt.TRSPTwoOptMove; /** * <code>TRSPTwoOpt</code> is an implementation of the 2-opt neighborhood for the TRSP. * <p> * Creation date: May 3, 2011 - 2:18:11 PM * * @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 class TRSPTwoOpt extends NeighborhoodBase<ITRSPTour, TRSPTwoOptMove> implements TRSPTourNeighborhood<TRSPTwoOptMove> { /** * <code>TRSPTwoOptMove</code> is a specialization of {@link Move} to the {@link TRSPTwoOpt} neighborhood * <p> * Creation date: May 9, 2011 - 11:27:25 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 static class TRSPTwoOptMove extends TRSPMove { /** the id of the tail of the first removed edge (i,j) **/ private final int mFirst; /** * Getter for the id of the tail of the first removed edge (i,j) * * @return the id of the tail of the first removed edge (i,j) */ public int getFirst() { return this.mFirst; } /** the id of the tail of the second removed edge (m,n) **/ private final int mSecond; /** * Getter for the id of the tail of the second removed edge (m,n) * * @return the id of the tail of the second removed edge (m,n) */ public int getSecond() { return this.mSecond; } /** * Creates a new <code>TRSPTwoOptMove</code> * * @param first * the if of the tail of the first removed edge (i,j) * @param second * the if of the tail of the second removed edge (m,n), assumed to be a successor of * <code>first</code> */ public TRSPTwoOptMove(TRSPTour tour, int first, int second) { super(Double.NaN, tour); mFirst = first; mSecond = second; } @Override public String getMoveName() { return "2opt"; } @Override public String toString() { return String.format("2opt[%s,%s](%.3f)", getFirst(), getSecond(), getImprovement()); } } /** * Creates a new <code>TwoOptNeighborhood</code> * * @param constraintHandler */ public TRSPTwoOpt(TourConstraintHandler constraintHandler) { super(constraintHandler); } @Override public boolean executeMove(ITRSPTour itour, IMove imove) { TRSPTwoOptMove move = (TRSPTwoOptMove) imove; TRSPTour tour = (TRSPTour) itour; int i = move.getFirst(); int j = tour.getSucc(i); int m = move.getSecond(); int n = tour.getSucc(m); // Reverse j-m subtour TRSPTourIterator it = tour.iterator(j); int pred = it.next(); while (it.hasNext() && pred != m) { int suc = it.next(); tour.setPred(pred, suc); tour.setSucc(suc, pred); pred = suc; } // Relink // (i,m) tour.setSucc(i, m); tour.setPred(m, i); // (n,j) tour.setSucc(j, n); tour.setPred(n, j); // Propagate the update tour.propagateUpdate(i, n); // Reevaluate tour tour.getCostDelegate().evaluateTour(tour, true); checkSolution(itour, move, false, true, ""); return false; } @Override public void pertub(IInstance instance, ITRSPTour tour, IParameters params) { throw new UnsupportedOperationException("pertub is not implemented yet " + params); } @Override protected TRSPTwoOptMove randomNonImproving(ITRSPTour tour, IParameters params) { throw new UnsupportedOperationException("randomNonImproving is not implemented yet " + params); } @Override protected TRSPTwoOptMove randomFirstImprovement(ITRSPTour tour, IParameters params) { throw new UnsupportedOperationException("randomFirstImprovement is not implemented yet " + params); } @Override protected TRSPTwoOptMove deterministicBestImprovement(ITRSPTour tour, IParameters params) { return deterministicExploration(tour, params, false); } @Override protected TRSPTwoOptMove deterministicFirstImprovement(ITRSPTour tour, IParameters params) { return deterministicExploration(tour, params, true); } protected TRSPTwoOptMove deterministicExploration(ITRSPTour itour, IParameters params, boolean first) { if (itour.length() < 4) // No 2-opt move can be defined with a tour with less than 4 nodes return null; TRSPTwoOptMove move = null; TRSPTour tour = (TRSPTour) itour; TRSPTourIterator firstIt = tour.iterator(); // Skip first node (depot) // firstIt.next(); while (firstIt.hasNext()) { int i = firstIt.next(); TRSPTourIterator secondIt = tour.iterator(i); // Skip first node (i) if (secondIt.hasNext()) secondIt.next(); else break; // Skip second node (j) // if (secondIt.hasNext()) // secondIt.next(); // else // break; while (secondIt.hasNext()) { int m = secondIt.next(); if (!secondIt.hasNext()) // m is the last node break; TRSPTwoOptMove tmp = new TRSPTwoOptMove(tour, i, m); tour.getCostDelegate().evaluateMove(tmp); if (tmp.isImproving()) { // Found an improving move // Evaluate feasibility boolean feas = getConstraintHandler().isFeasible(tour, tmp); if (feas) { if (params.acceptFirstImprovement()) { // First improvement return tmp; } else if (move == null || tmp.getImprovement() > move.getImprovement()) { // Update best move move = tmp; } } else { // The move is infeasible, prune the rest of the (i,*) neighborhood break; } } } } return move; } @Override public String getShortName() { return "twoOpt"; } }