/** * */ package vrp2013.algorithms; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.IVRPInstance; import vroom.common.modeling.util.IRoutePool; import vroom.common.modeling.util.ISolutionFactory; import vroom.common.utilities.optimization.OptimizationSense; import vrp2013.util.BatchExecutor; import vrp2013.util.BatchExecutor.Result; import vrp2013.util.VRPSolution; /** * The class <code>ParallelGRASP</code> is a parallel implementation of {@link GRASP} * <p> * Creation date: May 4, 2013 - 2:56:28 PM * * @author Victor Pillac, <a href="http://www.nicta.com.au">National ICT Australia</a>, <a * href="http://www.victorpillac.com">www.victorpillac.com</a> * @version 1.0 */ public class ParallelGRASP implements IVRPOptimizationAlgorithm { private final IVRPInstance mInstance; private final ISolutionFactory mSolutionFactory; private final long mInitSeed; private final int mIterations; private final List<GRASP> mSubprocesses; private final IRoutePool<INodeVisit> mRoutePool; private VRPSolution mBestSolution; private final BatchExecutor mExecutor; /** * Returns the pool of routes generated during the iterations of the GRASP * * @return the pool containing the generated routes */ @Override public IRoutePool<INodeVisit> getRoutePool() { return mRoutePool; } /** * Returns the best solution found by this GRASP instance on the last run * * @return the best solution found by this GRASP instance on the last run */ @Override public VRPSolution getBestSolution() { return mBestSolution; } @Override public IVRPInstance getInstance() { return mInstance; } @Override public int getIterations() { return mIterations; } @Override public ISolutionFactory getSolutionFactory() { return mSolutionFactory; } /** * Creates a new <code>ParallelGRASP</code> * * @param instance * the instance that will be solved * @param solutionFactory * a factory to generate new solutions and routes * @param initSeed * the seed for the first iteration of the GRASP * @param iterations * the total number of iterations * @param routePool * the pool in which routes will be stored * @author vpillac */ public ParallelGRASP(IVRPInstance instance, ISolutionFactory solutionFactory, long initSeed, int iterations, IRoutePool<INodeVisit> routePool) { mInstance = instance; mInitSeed = initSeed; mSolutionFactory = solutionFactory; mIterations = iterations; mSubprocesses = new LinkedList<>(); // Initialize the GRASP subprocesses // - Get the number of available processors int threadCount = Runtime.getRuntime().availableProcessors(); // - Create one GRASP instance for each iteration for (int t = 0; t < mIterations; t++) { // Create a new subprocess mSubprocesses .add(new GRASP(mInstance, mSolutionFactory, initSeed, 1, routePool.clone())); // Make sure the seeds are the same as they would be in the sequential execution initSeed++; } mRoutePool = routePool; // Create an executor that will be used to run the GRASP subprocess mExecutor = new BatchExecutor(threadCount, "pGRASP"); } @Override public VRPSolution call() { // Submit the subprocesses to the executor // This will create the thread and run the GRASP subprocesses // Once all subprocesses have finished, the method returns a mapping between subprocesses and the best solution // found (Result is a wrapper that allows for exceptions to be captured) Map<GRASP, Result<VRPSolution>> results = mExecutor.submitBatchAndWait(mSubprocesses); // Loop through the <GRASP subprocess, Best solution> pairs for (Entry<GRASP, Result<VRPSolution>> r : results.entrySet()) { if (mBestSolution == null || OptimizationSense.MINIMIZATION.isBetter(getBestSolution(), r.getValue() .get())) // Found a better solution mBestSolution = r.getValue().get(); if (getRoutePool() != null) // Add the routes collected in the subprocess to the main route pool getRoutePool().add(r.getKey().getRoutePool()); } // Shutdown the executor and terminate its threads mExecutor.shutdown(); return getBestSolution(); } @Override public void dispose() { if (mRoutePool != null) mRoutePool.dispose(); for (GRASP g : mSubprocesses) g.dispose(); } }