/** * */ package vroom.trsp; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_A_L; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_A_R; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_A_SIGMA1; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_A_SIGMA2; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_A_SIGMA3; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_MAX_IT; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_MAX_TIME; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_OBJ_GAMMA; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_SA_ALPHA; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_SA_P; import static vroom.trsp.util.TRSPGlobalParameters.ALNS_SA_W; import static vroom.trsp.util.TRSPGlobalParameters.RUN_INIT_HEUR; import gurobi.GRB.DoubleAttr; import gurobi.GRBException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import vroom.common.heuristics.ProcedureStatus; import vroom.common.heuristics.alns.ALNSComponentHandler; import vroom.common.heuristics.alns.ALNSEventType; import vroom.common.heuristics.alns.ALNSGlobalParameters; import vroom.common.heuristics.alns.ALNSLogger; import vroom.common.heuristics.alns.ALNSSALogger; import vroom.common.heuristics.alns.AdaptiveLargeNeighborhoodSearch; import vroom.common.heuristics.alns.IDestroy; import vroom.common.heuristics.alns.IRepair; import vroom.common.heuristics.alns.ParallelALNS; import vroom.common.utilities.BestKnownSolutions; import vroom.common.utilities.StatCollector; import vroom.common.utilities.StatCollector.Label; import vroom.common.utilities.Stopwatch; import vroom.common.utilities.Utilities; import vroom.common.utilities.lp.SolverStatus; import vroom.common.utilities.optimization.IComponentHandler; import vroom.common.utilities.optimization.IParameters.LSStrategy; import vroom.common.utilities.optimization.OptimizationSense; import vroom.common.utilities.optimization.RndComponentHanlder; import vroom.common.utilities.optimization.SAAcceptanceCriterion; import vroom.common.utilities.optimization.SimpleParameters; import vroom.common.utilities.optimization.SolutionComparator; import vroom.trsp.datamodel.HashTourPool; import vroom.trsp.datamodel.ITRSPTourPool; import vroom.trsp.datamodel.NodeSetSolutionHasher; import vroom.trsp.datamodel.TRSPInstance; import vroom.trsp.datamodel.TRSPSolution; import vroom.trsp.datamodel.costDelegates.TRSPCostDelegate; import vroom.trsp.datamodel.costDelegates.TRSPDistance; import vroom.trsp.datamodel.costDelegates.TRSPTourBalance; import vroom.trsp.datamodel.costDelegates.TRSPWorkingTime; import vroom.trsp.optimization.alns.DestroyCritical; import vroom.trsp.optimization.alns.DestroyRandom; import vroom.trsp.optimization.alns.DestroyStaticRelated; import vroom.trsp.optimization.alns.DestroyTimeRelated; import vroom.trsp.optimization.alns.RepairRegret; import vroom.trsp.optimization.constraints.TourConstraintHandler; import vroom.trsp.optimization.constructive.TRSPConstructiveHeuristic; import vroom.trsp.optimization.matheuristic.SCGurobiSolver; import vroom.trsp.optimization.matheuristic.TourPoolCallBack; import vroom.trsp.util.TRSPGlobalParameters; import vroom.trsp.util.TRSPLogging; /** * <code>ALNSSCSolver</code> is a class containing the logic to solve the TRSP * <p> * Creation date: Apr 8, 2011 - 4:38:48 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 ALNSSCSolver extends TRSPSolver { /** * The labels that will be used in {@link #collectStats(StatCollector, BestKnownSolutions)} */ public static final Label<?>[] LABELS = new Label<?>[] { new Label<Integer>("run_id", Integer.class), new Label<String>("name", String.class), // name new Label<String>("group", String.class), // group new Label<Integer>("size", Integer.class), // size new Label<Integer>("crew", Integer.class), // crew new Label<Integer>("run", Integer.class), // run # new Label<String>("comment", String.class), // comment new Label<Double>("init_time", Double.class), // init_time new Label<Integer>("init_it", Integer.class), // init_it // new Label<AssignmentStrategy>("init_strat", // AssignmentStrategy.class),// init_strat new Label<ProcedureStatus>("init_status", ProcedureStatus.class), // init_status new Label<Integer>("init_unserved", Integer.class), // init_unserved new Label<Double>("init_wt", Double.class, COST_FORMAT), // init_wt // new Label<Double>("init_wt_dev", Double.class, COST_FORMAT), // init_wt_dev new Label<Double>("alns_time_s", Double.class, TIME_FORMAT), // alns_time new Label<Integer>("alns_it", Integer.class), // alns_it new Label<Integer>("alns_unserved", Integer.class), // alns_unserved new Label<Double>("alns_wt", Double.class, COST_FORMAT), // alns_wt // new Label<Double>("alns_wt_dev", Double.class, COST_FORMAT), // alns_wt_dev new Label<Integer>("alns_K", Integer.class), // alns_K new Label<Double>("alns_imp_wt", Double.class, PERC_FORMAT), // alns_wt // improvement // new Label<Double>("alns_imp_wt_dev", // Double.class, PERC_FORMAT), // alns_wt_dev // improvement new Label<String>("alns_checksol", String.class), // alns_feasible new Label<Double>("postop_time_s", Double.class, TIME_FORMAT), // postop_time new Label<Integer>("postop_unserved", Integer.class), // postop_unserved new Label<Double>("postop_wt", Double.class, COST_FORMAT), // postop_wt // new Label<Double>("postop_wt_dev", Double.class, COST_FORMAT), // postop_wt_dev new Label<Integer>("postop_K", Integer.class), // postop_K new Label<Double>("postop_imp_wt", Double.class, PERC_FORMAT), // postop_wt // improvement // new Label<Double>("postop_imp_wt_dev", // Double.class, PERC_FORMAT), // // postop_wt_dev // improvement new Label<String>("postop_checksol", String.class), // postop_checksol new Label<Double>("postop_bbgap", Double.class), // postop_gap new Label<SolverStatus>("postop_status", SolverStatus.class), // postop_status new Label<Integer>("postop_pool_size", Integer.class), // postop_pool_size// new Label<Integer>("postop_pool_collisions", Integer.class), // postop_pool_collisions// new Label<Double>("bks", Double.class, COST_FORMAT),// new Label<Double>("alns_gap", Double.class, PERC_FORMAT),// new Label<Double>("postop_gap", Double.class, PERC_FORMAT),// new Label<Integer>("bks_K", Integer.class), // new Label<Integer>("bks_opt", Integer.class), // new Label<String>("seeds", String.class), // seeds new Label<String>("final_sol", String.class), // the detailed // solution }; /** * Returns the default set of destroy procedures * * @return the default set of destroy procedures */ public static List<IDestroy<TRSPSolution>> newDestroySet(TRSPGlobalParameters params) { LinkedList<IDestroy<TRSPSolution>> destroys = new LinkedList<IDestroy<TRSPSolution>>(); destroys.add(new DestroyRandom()); destroys.add(new DestroyStaticRelated(params.get(TRSPGlobalParameters.ALNS_DES_P), 1, 1, 1)); destroys.add(new DestroyTimeRelated(params.get(TRSPGlobalParameters.ALNS_DES_P))); destroys.add(new DestroyCritical(params.get(TRSPGlobalParameters.ALNS_DES_P))); return destroys; } /** * Returns the default set of repair procedures * * @return the default set of repair procedures */ public static List<IRepair<TRSPSolution>> newRepairSet(TourConstraintHandler constraintHandler, TRSPGlobalParameters params) { LinkedList<IRepair<TRSPSolution>> repairs = new LinkedList<IRepair<TRSPSolution>>(); repairs.add(new RepairRegret(params, constraintHandler, 1, false)); repairs.add(new RepairRegret(params, constraintHandler, 2, false)); repairs.add(new RepairRegret(params, constraintHandler, 3, false)); if (params.get(TRSPGlobalParameters.ALNS_REP_NOISE)) { repairs.add(new RepairRegret(params, constraintHandler, 1, true)); repairs.add(new RepairRegret(params, constraintHandler, 2, true)); repairs.add(new RepairRegret(params, constraintHandler, 3, true)); } return repairs; } private TRSPConstructiveHeuristic mInit; private final Stopwatch mInitTimer = new Stopwatch(); private AdaptiveLargeNeighborhoodSearch<TRSPSolution> mALNS; /** * Returns the post-optimizer used in this run * * @return the post-optimizer used in this run */ private SCGurobiSolver mPostOp; private TRSPSolution mALNSSol; private TRSPSolution mInitSol; private List<TRSPSolution> mInitPool; private SimpleParameters mALNSParams; private ALNSLogger<TRSPSolution> mLogger; private TourPoolCallBack mTourPoolCB; private int mTourPoolSize = -1; private final ALNSGlobalParameters mALNSGlobalParams; /** * Returns the global parameters used in the ALNS * * @return the global parameters used in the ALNS */ public ALNSGlobalParameters getALNSGlobalParams() { return mALNSGlobalParams; } /** * Returns the tour pool containing the tours collected during the ALNS * * @return the tour pool containing the tours collected during the ALNS */ public ITRSPTourPool getTourPool() { return mTourPoolCB.getTourPool(); } /** * Returns the size of the tour pool * * @return the size of the tour pool */ public int getTourPoolSize() { if (mTourPoolSize == -1) return getTourPool().size(); else return mTourPoolSize; } /** * Creates a new <code>ALNSSCSolver</code> * * @param instance * the instance to be solved * @param params * the global parameters that will be used in this run * @param rndStream * the random stream used in this solver */ public ALNSSCSolver(TRSPInstance instance, TRSPGlobalParameters params) { super(instance, params); mALNSGlobalParams = new ALNSGlobalParameters(); } @Override public TRSPSolution call() { TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[start ]: Solving instance %s (I=%s, SC=%s)", getInstance().getName(), getParams().get(TRSPGlobalParameters.ALNS_MAX_IT), getParams().get(TRSPGlobalParameters.SC_ENABLED)); if (getInitSol() == null) { initialization(); TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[init ]: Initialization finished in %.1fs", mInitTimer.readTimeS()); TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[init ]: Initial solution: %.3f (%s)", getInitSol().getObjectiveValue(), getInitSol().getUnservedCount()); String err = getChecker().checkSolution(getInitSol()); if (!err.isEmpty()) { TRSPLogging.getProcedureLogger().warn( this.getClass().getSimpleName() + "[init ]: Infeasibility: %s", err); } } setupALNS(); if (ParallelALNS.class.isAssignableFrom(getALNS().getClass())) TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[init ]: Penalty: %.3f - Initial pool: %s", getInitSol().getCostDelegate().getUnservedPenalty(), ((ParallelALNS<?>) getALNS()).getSolPool()); alns(); TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[alns ]: ALNS finished in %.1fs %s", getALNS().getTimer().readTimeS(), getALNS().getStoppingCriterion()); if (ParallelALNS.class.isAssignableFrom(getALNS().getClass())) TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[alns ]: Final pool: %s", ((ParallelALNS<?>) getALNS()).getSolPool()); if (getALNSSol() != null) TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[alns ]: ALNS solution : %.3f (%s)", getALNSSol().getObjectiveValue(), getALNSSol().getUnservedCount()); String err = getChecker().checkSolution(getALNSSol()); if (!err.isEmpty()) { TRSPLogging.getProcedureLogger().warn( this.getClass().getSimpleName() + "[alns ]: Infeasibility: %s", err); } if (getParams().get(TRSPGlobalParameters.SC_ENABLED) && getALNSSol() != null) { TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[postop]: Post-optimization"); setupPostOp(); postOp(); TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[postop]: Post-optimization finished in %.1fs", getPostOp().getTimer().readTimeS()); err = getChecker().checkSolution(getFinalSolution()); if (!err.isEmpty()) { TRSPLogging.getProcedureLogger().warn( this.getClass().getSimpleName() + "[end ]: Infeasibility: %s", err); } } else { setFinalSolution(getALNSSol()); } TRSPLogging.getProcedureLogger().info( this.getClass().getSimpleName() + "[end ]: Final solution : %.3f (%s)", getFinalSolution() != null ? getFinalSolution().getObjectiveValue() : Double.NaN, getFinalSolution() != null ? getFinalSolution().getUnservedCount() : "na"); return getFinalSolution(); } @Override public Label<?>[] getLabels() { return LABELS; } @Override public Object[] getStats(BestKnownSolutions bks, int runId, int runNum) { String group = getInstance().getName().substring(0, (getInstance().getName().contains("RC") ? 3 : 2)); String instanceName = getInstance().getName().replace(".txt", ""); TRSPCostDelegate wtDel; // sCVRPTW if (getParams().isCVRPTW()) wtDel = new TRSPDistance(); else wtDel = new TRSPWorkingTime(); TRSPTourBalance tbDel = new TRSPTourBalance(wtDel, getParams().get( TRSPGlobalParameters.BALANCE_COST_DELEGATE_MEASURE)); double init_wt = wtDel.evaluateSolution(getInitSol(), true, true); // double init_wt_dev = tbDel.evaluateSolution(getInitSol(), true, true); double alns_wt = wtDel.evaluateSolution(getALNSSol(), true, true); // double alns_wt_dev = tbDel.evaluateSolution(getALNSSol(), true, true); double postop_wt = wtDel.evaluateSolution(getFinalSolution(), true, true); // double postop_wt_dev = tbDel.evaluateSolution(getFinalSolution(), true, true); double postop_bbgap = Double.NaN; if (getPostOp() != null) { try { double mipObj = getPostOp().getModel().get(DoubleAttr.ObjVal); double mipLB = getPostOp().getModel().get(DoubleAttr.ObjBound); postop_bbgap = mipLB != 0 ? (mipObj - mipLB) / mipObj : mipObj / 100; } catch (GRBException e) { TRSPLogging.getProcedureLogger().exception( this.getClass().getSimpleName() + ".collectStats", e); } } Object[] stats = new Object[] { runId, getInstance().getName(), // name group, // group getInstance().getRequestCount(), // size getInstance().getFleet().size(), // crew count runNum, getComment(), // comment mInitTimer.readTimeS(), // init_time getInit().getIterationCount(), // init_it // mInit.getAssignmentStrategy(),// init_strat getInit().getStatus(),// init_status getInitSol().getUnservedCount(), // init_unserved init_wt,// init_wt // init_wt_dev,// init_wt_dev getALNS().getTimer().readTimeS(),// alns_time getALNS().getStoppingCriterion().getIterationCount(),// alns_it getALNSSol().getUnservedCount(), // alns_unserved alns_wt,// alns_wt // alns_wt_dev,// alns_wt_dev getALNSSol().getActualTourCount(), // alns_K (init_wt - alns_wt) / init_wt, // wt imp // (init_wt_dev - alns_wt_dev) / init_wt_dev, // wt dev imp getChecker().checkSolution(getALNSSol()),// alns_feasible getPostOp() == null ? 0l : getPostOp().getTimer().readTimeS(), // postop_time getFinalSolution().getUnservedCount(), // postop_unserved postop_wt, // postop_wt // postop_wt_dev, // postop_wt_dev getFinalSolution().getActualTourCount(), // postop_K (alns_wt - postop_wt) / alns_wt, // postop_wt improvement // (alns_wt_dev - postop_wt_dev) / alns_wt_dev, // postop_wt_dev improvement getChecker().checkSolution(getFinalSolution()), // postop_checksol postop_bbgap, // postop_gap getPostOp() != null ? getPostOp().getStatus() : SolverStatus.UNKNOWN_STATUS, // postop_status getPostOp() != null ? getPostOp().getColumnCount() : 0, // postop_pool_size getHashPoolCollisionCount(), // postop_pool_collisions bks.getBKS(instanceName), // BKS bks.getGapToBKS(instanceName, alns_wt, OptimizationSense.MINIMIZATION), // ALNS GAP bks.getGapToBKS(instanceName, postop_wt, OptimizationSense.MINIMIZATION), // POSTOP GAP bks.getIntValue(instanceName, "K"), // BKS - K bks.isOptimal(instanceName) ? 1 : 0, // BKS is optimal? Utilities.toShortString(getParams().get(TRSPGlobalParameters.RUN_SEEDS)),// seeds getFinalSolution().toShortString() }; return stats; } @Override protected void finalize() throws Throwable { if (getPostOp() != null) getPostOp().getModel().dispose(); super.finalize(); } /** * Returns the ALN used in this run * * @return the ALN used in this run */ public AdaptiveLargeNeighborhoodSearch<TRSPSolution> getALNS() { return mALNS; } /** * Returns the solution found by the ALNS * * @return the solution found by the ALNS */ public TRSPSolution getALNSSol() { return mALNSSol; } /** * Returns the constructive heuristic * * @return the constructive heuristic */ public TRSPConstructiveHeuristic getInit() { return mInit; } /** * Returns the initial solution * * @return the initial solution */ public TRSPSolution getInitSol() { return mInitSol; } public SCGurobiSolver getPostOp() { return mPostOp; } /** * Find an initial solution */ public void initialization() { // ---------------------------------------- // Setup the initialization setInit((TRSPConstructiveHeuristic) getParams().newInstance(RUN_INIT_HEUR, getInstance(), getParams(), getTourCtrHandler(), getParams().newInitCostDelegate())); // ---------------------------------------- mInitTimer.reset(); mInitTimer.start(); if (getParams().get(TRSPGlobalParameters.ALNS_PARALLEL)) { // TODO parallelize this int size = Math.min(getParams().get(TRSPGlobalParameters.ALNS_PALNS_POOL_SIZE), getParams().get(TRSPGlobalParameters.THREAD_COUNT)); mInitPool = new ArrayList<TRSPSolution>(size); while (mInitPool.size() < size) { getInit().call(); mInitPool.add(getInit().getSolution()); } Collections.sort(mInitPool, new SolutionComparator<>(OptimizationSense.MINIMIZATION)); mInitSol = mInitPool.get(mInitPool.size() - 1).clone(); } else { getInit().call(); setInitSol(getInit().getSolution()); } mInitTimer.stop(); getInitSol().getCostDelegate().unsetUnservedPenalty(); getInitSol().getCostDelegate().evaluateSolution(getInitSol(), true, true); } public void setupALNS() { // ---------------------------------------- // Setup the ALNS IComponentHandler<IDestroy<TRSPSolution>> destroyComponents = null; IComponentHandler<IRepair<TRSPSolution>> repairComponents = null; getInitSol().setCostDelegate(getALNSCostDelegate(getInitSol())); Class<?> handlerClass = getParams().get(TRSPGlobalParameters.ALNS_COMP_HANDLER); if (handlerClass == ALNSComponentHandler.class) { destroyComponents = new ALNSComponentHandler<IDestroy<TRSPSolution>>(getParams() .getALNSRndStream(), newDestroySet(getParams()), getParams().get(ALNS_A_SIGMA1), getParams().get(ALNS_A_SIGMA2), getParams() .get(ALNS_A_SIGMA3), getParams().get(ALNS_A_R), getParams().get( ALNS_A_L)); repairComponents = new ALNSComponentHandler<IRepair<TRSPSolution>>(getParams() .getALNSRndStream(), newRepairSet(getTourCtrHandler(), getParams()), getParams().get(ALNS_A_SIGMA1), getParams().get(ALNS_A_SIGMA2), getParams() .get(ALNS_A_SIGMA3), getParams().get(ALNS_A_R), getParams().get( ALNS_A_L)); } else if (handlerClass == RndComponentHanlder.class) { destroyComponents = new RndComponentHanlder<IDestroy<TRSPSolution>>(getParams() .getALNSRndStream(), newDestroySet(getParams()), false); repairComponents = new RndComponentHanlder<IRepair<TRSPSolution>>(getParams() .getALNSRndStream(), newRepairSet(getTourCtrHandler(), getParams()), false); } else { TRSPLogging.getSetupLogger().error( this.getClass().getSimpleName() + ".setupALNS: Unsupported ALNS component handler: %s", handlerClass); } getALNSGlobalParams().set( ALNSGlobalParameters.DESTROY_SIZE_RANGE, new double[] { getParams().get(TRSPGlobalParameters.ALNS_XI_MIN), getParams().get(TRSPGlobalParameters.ALNS_XI_MAX) }); // Parallel ALNS if (getParams().get(TRSPGlobalParameters.ALNS_PARALLEL)) { // && getParams().get(TRSPGlobalParameters.THREAD_COUNT) > 1) { getALNSGlobalParams().set(ALNSGlobalParameters.PALNS_IT_P, getParams().get(TRSPGlobalParameters.ALNS_PALNS_IT_P)); getALNSGlobalParams().set(ALNSGlobalParameters.PALNS_POOL_SIZE, getParams().get(TRSPGlobalParameters.ALNS_PALNS_POOL_SIZE)); getALNSGlobalParams().set(ALNSGlobalParameters.PALNS_POOL, getParams().get(TRSPGlobalParameters.ALNS_PALNS_POOL)); getALNSGlobalParams().set(ALNSGlobalParameters.DIVERSITY_METRIC, getParams().get(TRSPGlobalParameters.ALNS_PALNS_DIV_METRIC)); getALNSGlobalParams().set(ALNSGlobalParameters.PALNS_THREAD_COUNT, getParams().getThreadCount()); ParallelALNS<TRSPSolution> alns = new ParallelALNS<TRSPSolution>( OptimizationSense.MINIMIZATION, getParams().getALNSRndStream(), getALNSGlobalParams(), destroyComponents, repairComponents); setALNS(alns); // Setup the solution pool TRSPCostDelegate cd = getALNSCostDelegate(getInitSol()); for (TRSPSolution s : mInitPool) {// FIXME update mInitPool in dynamic setting? s.setCostDelegate(cd); alns.getSolPool().add(s, true); } } else { // Sequential ALNS setALNS(new AdaptiveLargeNeighborhoodSearch<TRSPSolution>( OptimizationSense.MINIMIZATION, getParams().getALNSRndStream(), getALNSGlobalParams(), destroyComponents, repairComponents)); } if (mLogger != null) mLogger.registerToALNS(getALNS()); // ---------------------------------------- mALNSParams = new SimpleParameters(LSStrategy.DET_BEST_IMPROVEMENT, getParams().get( ALNS_MAX_TIME), getParams().get(ALNS_MAX_IT), getParams().getALNSRndStream()); if (getParams().get(TRSPGlobalParameters.SC_ENABLED) || getParams().get(TRSPGlobalParameters.TOUR_POOL_ENABLED)) { mTourPoolCB = new TourPoolCallBack(getInstance(), getParams().get(ALNS_MAX_IT), new NodeSetSolutionHasher(getInstance(), getParams().getHashRndStream())); getALNS().registerCallback(mTourPoolCB, ALNSEventType.REPAIRED); } if (getParams().get(TRSPGlobalParameters.ALNS_ENABLE_LOGGING)) { ALNSLogger<TRSPSolution> logger = new ALNSSALogger<TRSPSolution>("results/alns"); logger.registerToALNS(getALNS()); } // Setup SA acceptance criterion mALNSParams.setAcceptanceCriterion(new SAAcceptanceCriterion( OptimizationSense.MINIMIZATION, getParams().getALNSRndStream(), getInitSol() .getObjectiveValue(), getParams().get(ALNS_SA_W), getParams() .get(ALNS_SA_P), mALNSParams.getMaxIterations(), getParams().get( ALNS_SA_ALPHA), true)); } /** * Returns the number of hash collisions detected, returns -1 if @link {@link HashTourPool#sCountCollisions} is set * to {@code false} * * @return the number of hash collisions detected */ public int getHashPoolCollisionCount() { if (mTourPoolCB != null && HashTourPool.sCountCollisions) return ((HashTourPool) mTourPoolCB.getTourPool()).getCollisionsCount(); else return -1; } /** * Return a cost delegate for the ALNS * * @param sol * @return */ public TRSPCostDelegate getALNSCostDelegate(TRSPSolution sol) { // Load the cost delegate from the global parameters TRSPCostDelegate cd = getParams().newALNSCostDelegate(sol); // Set unserved customer penalty cd.setPenalize(true); // cd.setUnservedPenalty(sol, getParams().get(ALNS_OBJ_GAMMA)); cd.setUnservedPenalty(sol, getParams().get(ALNS_OBJ_GAMMA) * 100 / sol.getInstance().getReleasedRequests().size()); return cd; } /** * Run the ALNS */ public void alns() { setALNSSol(getALNS().localSearch(getInitSol().getInstance(), getInitSol(), mALNSParams)); getALNSSol().getCostDelegate().unsetUnservedPenalty(); getALNSSol().getCostDelegate().evaluateSolution(getALNSSol(), true, true); setFinalSolution(getALNSSol()); getALNS().stop(); } /** * Initialize and setup the post-optimizer */ public void setupPostOp() { setPostOp(new SCGurobiSolver(getInstance(), getParams(), mTourPoolCB.getHasher(), !getALNSSol().getUnservedRequests().isEmpty())); getPostOp().addColumns(mTourPoolCB.getTourPool().getAllTours()); mTourPoolSize = getTourPool().size(); // Free some memory mTourPoolCB.getTourPool().clear(); // Set initial solution getPostOp().setIncumbent(getALNSSol()); if (getModelWriter() != null) try { getModelWriter().write(getPostOp().getModel(), String.format("%s-%s", getInstance().getName(), getComment())); } catch (IOException e) { TRSPLogging.getOptimizationLogger().exception( this.getClass().getSimpleName() + ".setupPostOp", e); } // Add stat writer if (getGRBStatCollector() != null) getGRBStatCollector().setModel(getPostOp().getModel()); } /** * Performs the post optimization by solving a set covering problem with the tours generated during the ALNS. */ public void postOp() { // Solve getPostOp().solve(); // getPostOp().repairSolution(); setFinalSolution(getPostOp().getSolution()); if (getFinalSolution() != null) { // Evaluate the solution with the ALNS cost delegate getFinalSolution().setCostDelegate(getParams().newALNSCostDelegate(null)); } } /** * Set the {@link AdaptiveLargeNeighborhoodSearch ALNS} algorithm * * @param alns */ private void setALNS(AdaptiveLargeNeighborhoodSearch<TRSPSolution> alns) { mALNS = alns; } /** * Set the solution reported as the one returned by the ALNS algorithm * * @param alnsSol * the solution */ protected void setALNSSol(TRSPSolution alnsSol) { mALNSSol = alnsSol; } /** * Set the {@link TRSPConstructiveHeuristic} heuristic used to build an initial solution * * @param init * the constructive heuristic */ private void setInit(TRSPConstructiveHeuristic init) { mInit = init; } /** * Set the initial solution that will be used as a starting point in the ALNS. * * @param initSol * the initial solution */ @Override public void setInitSol(TRSPSolution initSol) { mInitSol = initSol; if (mInitPool != null) { mInitPool.clear(); mInitPool.add(mInitSol); } } /** * Set the logger that will be attached to the ALN * * @param logger * a logger */ public void setALNSLogger(ALNSLogger<TRSPSolution> logger) { mLogger = logger; } /** * Set the post optimization solver * * @param postOp */ private void setPostOp(SCGurobiSolver postOp) { mPostOp = postOp; } @Override public void dispose() { if (getInit() != null) getInit().dispose(); if (getALNS() != null) getALNS().dispose(); if (getPostOp() != null) getPostOp().dispose(); } }