/** * */ package vroom.trsp; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import vroom.common.heuristics.alns.ParallelALNS; import vroom.common.heuristics.alns.SimpleSolutionPool; import vroom.common.utilities.BatchThreadPoolExecutor; import vroom.common.utilities.optimization.IPathRelinking; import vroom.common.utilities.optimization.OptimizationSense; import vroom.trsp.datamodel.TRSPInstance; import vroom.trsp.datamodel.TRSPSolution; import vroom.trsp.datamodel.costDelegates.TRSPLevenshteinDistance; import vroom.trsp.optimization.biobj.ALNSParetoFront; import vroom.trsp.optimization.biobj.HierarchicalParetoSelector; import vroom.trsp.optimization.biobj.IParetoSelector; import vroom.trsp.optimization.biobj.LevenshteinPR; import vroom.trsp.optimization.biobj.ParetoFront; import vroom.trsp.optimization.biobj.ParetoFront.ParetoSolution; import vroom.trsp.optimization.constraints.TourConstraintHandler; import vroom.trsp.util.TRSPGlobalParameters; import vroom.trsp.util.TRSPLogging; /** * The class <code>DynBiObjSolver</code> is an extension of {@link ALNSSCSolver} specialized for dynamic and * bi-objective problems * <p> * Creation date: Dec 13, 2011 - 1:35:04 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 DynBiObjSolver extends ALNSSCSolver { // FIXME Try to use the initial solution as reference solution instead of the solution from previous decision /** the pareto selector that will select a unique solution from the pareto front */ private final IParetoSelector mSelector; /** the path relinking component */ private final IPathRelinking<TRSPSolution> mPathRelinking; /** the path relinking pareto front */ private ParetoFront mPRPareto; /** the reference solution for the biobjective approach */ private TRSPSolution mReferenceSol; /** enable or disable the bi-objective behavior, independently of the global parameter **/ private boolean mBiObjective; /** * Getter for enable or disable the bi-objective behavior, independently of the global parameter * * @return {@code true} if the next call to {@link #call()} will be to solve a bi-objective problem, {@code false} * otherwise */ public boolean isBiObjective() { return this.mBiObjective; } /** * Setter for enable or disable the bi-objective behavior, independently of the global parameter * * @param biobj * {@code true} if the next call to {@link #call()} will be to solve a bi-objective problem, * {@code false} otherwise */ public void setBiObjective(boolean biobj) { this.mBiObjective = biobj; } /** * Returns the solution used as reference to evaluate the route consistency * * @return the solution used as reference to evaluate the route consistency */ public TRSPSolution getReferenceSol() { return mReferenceSol; } /** * Sets the solution used as reference to evaluate the route consistency * * @param referenceSol * the solution used as reference to evaluate the route consistency */ public void setReferenceSol(TRSPSolution referenceSol) { mReferenceSol = referenceSol; } @Override public ParallelALNS<TRSPSolution> getALNS() { return (ParallelALNS<TRSPSolution>) super.getALNS(); } /** * Returns the path relinking component * * @return the path relinking component */ public IPathRelinking<TRSPSolution> getPathRelinking() { return mPathRelinking; } /** * Returns the Pareto front resulting from the last optimization * * @return the Pareto front resulting from the last optimization */ public ParetoFront getALNSPareto() { return (ParetoFront) getALNS().getSolPool(); } /** * Returns the Pareto front found by path relinking * * @return the Pareto front found by path relinking */ public ParetoFront getPRPareto() { return mPRPareto; } /** * Creates a new <code>DynBiObjSolver</code> * * @param instance * @param params */ public DynBiObjSolver(TRSPInstance instance, TRSPGlobalParameters params) { super(instance, params); if (params.get(TRSPGlobalParameters.SC_ENABLED)) throw new IllegalArgumentException("SC_ENABLED set to true"); mSelector = new HierarchicalParetoSelector( params.get(TRSPGlobalParameters.BIOBJ_ALLOWED_DEG)); mPathRelinking = new LevenshteinPR(params); // if (!ParallelALNS.class.isAssignableFrom(params.get(TRSPGlobalParameters.ALNS_VARIANT))) // throw new IllegalArgumentException("Unsupported value for ALNS_VARIANT"); } @Override public TRSPSolution call() { super.call(); if (getParams().get(TRSPGlobalParameters.BIOBJ_ENABLE_PR)) { pr(); setFinalSolution(mSelector.selectSolution(getPRPareto())); } return getFinalSolution(); } @Override public void setupALNS() { super.setupALNS(); // Set the solution pool if (isBiObjective()) getALNS().setSolPool( new ALNSParetoFront(getALNSCostDelegate(getReferenceSol()), getALNS() .getOptimizationSense(), new TRSPLevenshteinDistance(getReferenceSol()), OptimizationSense.MINIMIZATION)); else getALNS().setSolPool( new SimpleSolutionPool<TRSPSolution>(OptimizationSense.MINIMIZATION, getALNSGlobalParams())); } @Override public void alns() { super.alns(); if (isBiObjective()) { ParetoSolution sol = mSelector.selectParetoSolution(getALNSPareto()); TRSPLogging.getRunLogger().debug( "DynBiObjSolver[alns ]: Selected solution %s from Pareto %s", sol, getALNSPareto()); setALNSSol(sol != null ? sol.getSolution() : null); setFinalSolution(getALNSSol()); } } /** * Performs a path relinking between all the non-dominated solutions found by the ALNS */ public void pr() { mPRPareto = getALNSPareto().clone(); int numThreads = getParams().getThreadCount(); BatchThreadPoolExecutor executor = new BatchThreadPoolExecutor(numThreads, "pr"); // Do a PR between all Pareto solutions List<TRSPSolution> solutions = getALNSPareto().getSolutions(); int solPerThread = solutions.size() / numThreads; ListIterator<TRSPSolution> it = solutions.listIterator(); for (int t = 0; t < numThreads; t++) { ArrayList<TRSPSolution> sourceSol = new ArrayList<TRSPSolution>(solPerThread); while (it.hasNext() && sourceSol.size() < solPerThread) sourceSol.add(it.next()); executor.execute(new PRSubprocess(getPRPareto(), sourceSol, solutions, getPathRelinking(), getTourCtrHandler())); } executor.shutdown(); try { executor.awaitTermination(60000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { TRSPLogging.getBaseLogger().exception("DynBiObjSolver.pr", e); } } /** * The class <code>PRSubprocess</code> is an implementation of {@link Runnable} that performs a path relinking * between two sets of collections * <p> * Creation date: Dec 14, 2011 - 11:38:09 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 PRSubprocess implements Runnable { private final ParetoFront mPareto; private final List<TRSPSolution> mSourceSols; private final List<TRSPSolution> mTargetSols; private final IPathRelinking<TRSPSolution> mPR; private final TourConstraintHandler mCtr; /** * Creates a new <code>PRSubprocess</code> * * @param pareto * the {@link ParetoFront} in which feasible non-dominated solutions will be stored * @param sourceSols * the source solutions * @param targetSols * the target solutions * @param pR * the path relinking component * @param ctr * the constraint handler */ public PRSubprocess(ParetoFront pareto, List<TRSPSolution> sourceSols, List<TRSPSolution> targetSols, IPathRelinking<TRSPSolution> pR, TourConstraintHandler ctr) { mPareto = pareto; mSourceSols = sourceSols; mTargetSols = targetSols; mPR = pR; mCtr = ctr; } @Override public void run() { for (TRSPSolution source : mSourceSols) { for (TRSPSolution target : mTargetSols) { LinkedList<TRSPSolution> feasSol = new LinkedList<TRSPSolution>(); if (source != target) { List<TRSPSolution> sols = mPR.pathRelinking(source, target, null); for (TRSPSolution s : sols) if (mCtr.isFeasible(s, false)) feasSol.add(s); mPareto.acquireLock(); for (TRSPSolution s : feasSol) mPareto.add(s, false); mPareto.releaseLock(); } } } } } /** * The class <code>PRJob</code> is an implementation of {@link Callable} that performs a path relinking between two * solutions and return the feasible solutions found. * <p> * Creation date: Dec 14, 2011 - 10:42:36 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 PRJob implements Callable<Collection<TRSPSolution>> { private final TRSPSolution mRef; private final TRSPSolution mTarget; private final IPathRelinking<TRSPSolution> mPR; private final TourConstraintHandler mCtr; /** * Creates a new <code>PRJob</code> * * @param ref * @param target * @param pR * @param ctr */ public PRJob(TRSPSolution ref, TRSPSolution target, IPathRelinking<TRSPSolution> pR, TourConstraintHandler ctr) { mRef = ref; mTarget = target; mPR = pR; mCtr = ctr; } @Override public Collection<TRSPSolution> call() throws Exception { List<TRSPSolution> sols = this.mPR.pathRelinking(mRef, mTarget, null); ArrayList<TRSPSolution> feasSol = new ArrayList<TRSPSolution>(sols.size()); for (TRSPSolution s : sols) { if (mCtr.isFeasible(s, false)) feasSol.add(s); } return feasSol; } } }