/** * */ package vroom.common.heuristics.vrp.constraints; import java.util.Iterator; import java.util.List; import vroom.common.heuristics.cw.kernel.RouteMergingMove; import vroom.common.heuristics.vrp.OrOptMove; import vroom.common.heuristics.vrp.PairMove; import vroom.common.heuristics.vrp.RelocateMove; import vroom.common.heuristics.vrp.RelocateMove.RelocateAtomicMove; import vroom.common.heuristics.vrp.StringExchangeMove; import vroom.common.heuristics.vrp.SwapMove; import vroom.common.heuristics.vrp.TwoOptMove; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.IRoute; import vroom.common.modeling.dataModel.IVRPSolution; import vroom.common.utilities.Utilities; import vroom.common.utilities.optimization.IConstraint; import vroom.common.utilities.optimization.IMove; /** * <code>FixedNodesConstraint</code> is a constraint that checks that a move * will not change the position of a fixed node. * <p> * Supported moves: * <ul> * <li>{@link TwoOptMove}</li> * <li>{@link SwapMove}</li> * </ul> * <p> * Creation date: Jun 22, 2010 - 9:44:05 AM * * @param <S> * the generic type * @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 FixedNodesConstraint<S extends IVRPSolution<?>> implements IConstraint<S> { /* * (non-Javadoc) * * @see vroom.common.heuristics.IConstraint#checkMove(java.lang.Object, * vroom.common.heuristics.Move) */ @Override public boolean isFeasible(S solution, IMove move) { if (move instanceof PairMove<?>) { PairMove<?> m = (PairMove<?>) move; IRoute<?> rI = solution.getRoute(m.getRouteI()); IRoute<?> rJ = solution.getRoute(m.getRouteJ()); int i = m.getI(); int j = m.getJ(); if (i < 0 || j < 0 || i > rI.length() - 1 || j > rJ.length() - 1) { return false; } // ----------------------------------- // 2-opt // ----------------------------------- if (move instanceof TwoOptMove) { return checkTwoOpt(solution, (TwoOptMove) move); // ----------------------------------- // Swap // ----------------------------------- } else if (move instanceof SwapMove) { return checkSwap(solution, (SwapMove) move); // ----------------------------------- // Or-opt // ----------------------------------- } else if (move instanceof OrOptMove<?>) { return checkOrOpt(solution, (OrOptMove<?>) move); } else { throw new UnsupportedOperationException("Unsupported move: " + move.getClass().getSimpleName()); // return true; } } else if (move instanceof StringExchangeMove<?>) { return checkStrExchange(solution, (StringExchangeMove<?>) move); } else if (move instanceof RouteMergingMove) { return true; } else if (move instanceof RelocateMove) { for (RelocateAtomicMove reloc : ((RelocateMove) move) .getAtomicMoves()) { if (!checkRelocAtomicMove(reloc)) { return false; } } return true; } else if (move instanceof RelocateAtomicMove) { return checkRelocAtomicMove((RelocateAtomicMove) move); } else { throw new UnsupportedOperationException("Unsupported move: " + move.getClass().getSimpleName()); // return true; } } /** * Check two opt move. * * @param solution * the solution * @param move * the * @return <code>true</code> if move is feasible */ public boolean checkTwoOpt(S solution, TwoOptMove move) { IRoute<?> rI = solution.getRoute(move.getRouteI()); IRoute<?> rJ = solution.getRoute(move.getRouteJ()); int i = move.getI(); int j = move.getJ(); return i < rI.length() - 1 && j < rJ.length() - 1 && !(rI.getNodeAt(i).isFixed() && rI.getNodeAt(i + 1).isFixed()) && !(rJ.getNodeAt(j).isFixed() && rJ.getNodeAt(j + 1).isFixed()); } /** * Check swap move. * * @param solution * the solution * @param move * the * @return <code>true</code> if move is feasible */ public boolean checkSwap(S solution, SwapMove move) { IRoute<?> rI = solution.getRoute(move.getRouteI()); IRoute<?> rJ = solution.getRoute(move.getRouteJ()); int i = move.getI(); int j = move.getJ(); return !rI.getNodeAt(i).isFixed() && !rJ.getNodeAt(j).isFixed(); } /** * Check or opt move. * * @param solution * the solution * @param move * the mve * @return <code>true</code> if move is feasible */ public boolean checkOrOpt(S solution, OrOptMove<?> move) { IRoute<?> rI = solution.getRoute(move.getRouteI()); IRoute<?> insRoute = solution.getRoute(move.getInsertionRoute()); int i = move.getI(); int j = move.getJ(); int ins = move.getInsertionIndex(); if (ins < 0 || ins > insRoute.length() // out of bounds // append but last node is fixed || (ins == insRoute.length() && insRoute.getLastNode() .isFixed()) // insertion node is fixed || (ins < insRoute.length() && insRoute.getNodeAt(ins) .isFixed()) // wrong node order || j < i || (insRoute == rI && i <= ins && ins <= j)) { return false; } List<?> segment = rI.subroute(i, j); Iterator<INodeVisit> it = Utilities.castIterator(segment.iterator()); while (it.hasNext()) { INodeVisit node = it.next(); if (node.isFixed()) { return false; } } return true; } /** * Check str exchange move. * * @param solution * the solution * @param mve * the mve * @return <code>true</code> if move is feasible */ public boolean checkStrExchange(S solution, StringExchangeMove<?> mve) { IRoute<?> r1 = solution.getRoute(mve.getFirstRoute()); IRoute<?> r2 = solution.getRoute(mve.getSecondRoute()); int i = mve.getNodeI(); int j = mve.getNodeJ(); int k = mve.getNodeK(); int l = mve.getNodeL(); if (i < 0 || i > r1.length() - 1 || j < 0 || j > r1.length() - 1 || j < i || k < 0 || k > r2.length() - 1 || l < 0 || l > r2.length() - 1 || l < k) { return false; } List<?> segment = r1.subroute(i, j); Iterator<INodeVisit> it = Utilities.castIterator(segment.iterator()); while (it.hasNext()) { INodeVisit node = it.next(); if (node.isFixed()) { return false; } } segment = r2.subroute(k, l); it = Utilities.castIterator(segment.iterator()); while (it.hasNext()) { INodeVisit node = it.next(); if (node.isFixed()) { return false; } } return true; } /** * Check reloc atomic move. * * @param reloc * the reloc * @return <code>true</code> if move is feasible */ public boolean checkRelocAtomicMove(RelocateAtomicMove reloc) { if (reloc.getInsertion() == null) { return true; } IRoute<?> rte = reloc.getInsertion().getRoute(); int ins = reloc.getInsertion().getPosition(); return !reloc.getNode().isFixed() && (rte.length() <= 3 || ((ins <= 0 || !rte.getNodeAt(ins - 1) .isFixed()) && (ins > rte.length() - 1 || !rte .getNodeAt(ins).isFixed()))); } /* * (non-Javadoc) * * @see vroom.common.heuristics.IConstraint#checkSolution(java.lang.Object) */ @Override public boolean isFeasible(S solution) { return true; } /* * (non-Javadoc) * * @see * vroom.common.heuristics.IConstraint#getInfeasibilityExplanation(java. * lang.Object) */ @Override public String getInfeasibilityExplanation(S solution) { return null; } /* * (non-Javadoc) * * @see * vroom.common.heuristics.IConstraint#getInfeasibilityExplanation(java. * lang.Object, vroom.common.heuristics.Move) */ @Override public String getInfeasibilityExplanation(S solution, IMove move) { if (!isFeasible(solution, move)) { return String.format( "move:%s will change the position of a fixed node", move); } return null; } }