package vroom.common.heuristics.vrp; import java.util.ArrayList; import java.util.LinkedList; import umontreal.iro.lecuyer.rng.RandomPermutation; import umontreal.iro.lecuyer.rng.RandomStream; import vroom.common.heuristics.ConstraintHandler; import vroom.common.heuristics.GenericNeighborhood; import vroom.common.heuristics.vrp.RelocateMove.RelocateAtomicMove; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.IRoute; import vroom.common.modeling.dataModel.IVRPSolution; import vroom.common.modeling.dataModel.NodeInsertion; import vroom.common.modeling.util.ISolutionFactory; import vroom.common.utilities.optimization.IMove; import vroom.common.utilities.optimization.IParameters; import vroom.common.utilities.optimization.ISolution; public class RelocateNeighborhood<S extends ISolution> extends GenericNeighborhood<S, RelocateMove> { private final ISolutionFactory mSolutionFactory; /** Number of nodes to relocate **/ private int mCardinality; /** * Getter for Number of nodes to relocate * * @return the value of cardinality */ public int getCardinality() { return mCardinality; } /** * Setter for Number of nodes to relocate * * @param cardinality * the value to be set for Number of nodes to relocate */ public void setCardinality(int cardinality) { mCardinality = cardinality; } public RelocateNeighborhood(ConstraintHandler<S> constraintHandler, ISolutionFactory solFactory) { super(constraintHandler); setCardinality(1); mSolutionFactory = solFactory; } @SuppressWarnings("unchecked") @Override protected boolean executeMoveImplem(S solution, IMove move) { RelocateMove mve = (RelocateMove) move; IVRPSolution<?> sol = (IVRPSolution<?>) solution; boolean b = true; for (RelocateAtomicMove reloc : mve.getAtomicMoves()) { sol.getRoute(reloc.getRoute()).remove(reloc.getNode()); // b &= ((IVRPSolution<IRoute<INodeVisit>>) // solution).getRoute(reloc.getRoute()) // .insertNode(reloc.getInsertion(), reloc.getNode()); } for (RelocateAtomicMove reloc : mve.getAtomicMoves()) { evaluateCandidateMove(sol, reloc); if (reloc.getInsertion() == null) { // Add a new route to the solution IRoute<INodeVisit> newRte = (IRoute<INodeVisit>) mSolutionFactory.newRoute(sol, sol .getParentInstance().getFleet().getVehicle()); newRte.appendNode(sol.getParentInstance().getDepotsVisits().iterator().next()); newRte.appendNode(reloc.getNode()); newRte.appendNode(sol.getParentInstance().getDepotsVisits().iterator().next()); evaluateCandidateMove(sol, reloc); } else { b &= ((IRoute<INodeVisit>) reloc.getInsertion().getRoute()).insertNode( reloc.getInsertion(), reloc.getNode()); } } return b; } @Override protected LinkedList<RelocateMove> generateCandidateList(S solution, IParameters params) { if (getCardinality() != 1) { throw new UnsupportedOperationException( "generateCandidateList not implemented yet for cardinality other than 1"); } LinkedList<RelocateMove> cand = new LinkedList<RelocateMove>(); IVRPSolution<?> sol = (IVRPSolution<?>) solution; int ir = 0; for (IRoute<?> r : sol) { int in = 0; for (INodeVisit n : r) { if (!n.isFixed()) { RelocateMove m = new RelocateMove(sol); m.addAtomicMove(m.newAtomicMove(n, ir, in)); cand.add(m); } in++; } ir++; } return cand; } @Override protected double evaluateCandidateMove(RelocateMove cand) { IVRPSolution<?> sol = cand.getSolution(); for (RelocateAtomicMove reloc : cand.getAtomicMoves()) { evaluateCandidateMove(sol, reloc); } return cand.getImprovement(); } protected void evaluateCandidateMove(IVRPSolution<?> sol, RelocateAtomicMove reloc) { NodeInsertion bestIns = null; for (int rte = 0; rte < sol.getRouteCount(); rte++) { IRoute<?> route = sol.getRoute(rte); if (rte != reloc.getRoute() && route.canAccommodateRequest(reloc.getNode().getParentRequest())) { NodeInsertion ins = route.getBestNodeInsertion(reloc.getNode()); if (bestIns == null || ins.getCost() < bestIns.getCost()) { bestIns = ins; } } } reloc.setInsertion(bestIns); } @Override public RelocateMove randomNonImproving(S solution, IParameters params) { RelocateMove move = new RelocateMove((IVRPSolution<?>) solution); int count = 0; RandomStream rnd = params.getRandomStream(); IVRPSolution<?> sol = (IVRPSolution<?>) solution; if (sol.getRouteCount() >= 2) { ArrayList<Integer> candRoutes = new ArrayList<Integer>(sol.getRouteCount()); LinkedList<?>[] candidates = new LinkedList<?>[sol.getRouteCount()]; for (int r = 0; r < candidates.length; r++) { candRoutes.add(r); LinkedList<Integer> nodes = new LinkedList<Integer>(); for (int i = 0; i < sol.getRoute(r).length(); i++) { nodes.add(i); } RandomPermutation.shuffle(candidates, params.getRandomStream()); candidates[r] = nodes; } while (count < getCardinality() && !candRoutes.isEmpty()) { int r = rnd.nextInt(0, candRoutes.size() - 1); int rndRouteIdx = candRoutes.get(r); IRoute<?> rndroute = sol.getRoute(rndRouteIdx); if (rndroute.length() > 2 && !candidates[rndRouteIdx].isEmpty()) { int n = (Integer) candidates[rndRouteIdx].pop(); if (!rndroute.getNodeAt(n).isDepot()) { move.addAtomicMove(move.newAtomicMove(rndroute.getNodeAt(n), rndRouteIdx, n)); // evaluateCandidateMove(sol, reloc); // if (reloc.getInsertion() != null // && getConstraintHandler().checkMove(solution, reloc)) // { // move.addAtomicMove(reloc); // count++; // } } } else { candRoutes.remove(r); } } } return move; }; @Override public String toString() { return String.format("%s(%s)", super.toString(), getCardinality()); } @Override public String getShortName() { return "reloc"; } }