From 9e2afa4f75b9b5d2945a335e080d65f2c373731c Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 15:22:37 +0200 Subject: [PATCH] make string ruin configurable --- .../jsprit/core/algorithm/box/Jsprit.java | 17 +- .../core/algorithm/ruin/RuinString.java | 80 ++---- .../examples/BuildAlgorithmFromScratch2.java | 252 ------------------ 3 files changed, 36 insertions(+), 313 deletions(-) delete mode 100644 jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index b7d6a73e..438344da 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -186,8 +186,8 @@ public class Jsprit { defaults.put(Strategy.RANDOM_BEST.toString(), ".5"); defaults.put(Strategy.RANDOM_REGRET.toString(), ".5"); - defaults.put(Strategy.STRING_BEST.toString(), ".5"); - defaults.put(Strategy.STRING_REGRET.toString(), ".5"); + defaults.put(Strategy.STRING_BEST.toString(), "0.0"); + defaults.put(Strategy.STRING_REGRET.toString(), "0.0"); defaults.put(Parameter.STRING_KMIN.toString(), "1"); defaults.put(Parameter.STRING_KMAX.toString(), "6"); @@ -490,11 +490,14 @@ public class Jsprit { random) ); - int kmin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); - int kmax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); - int lmin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); - int lmax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); - final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods, kmin, kmax, lmin, lmax); + int kMin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); + int kMax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); + int lMin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); + int lMax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); + + final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods); + stringRuin.setNoRoutes(kMin, kMax); + stringRuin.setStringLength(lMin, lMax); stringRuin.setRandom(random); AbstractInsertionStrategy regret; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 79f0310f..cf19a464 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -17,7 +17,6 @@ */ package com.graphhopper.jsprit.core.algorithm.ruin; -import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance; import com.graphhopper.jsprit.core.problem.AbstractActivity; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.job.Job; @@ -31,9 +30,15 @@ import java.util.*; /** - * RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by - * the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary - * measure). + * RuinString is adopted from + * + * Technical report 7.11.2016 + * A Fresh Ruin & Recreate Implementation for the Capacitated Vehicle Routing Problem + * Jan Christiaens, Greet Vanden Berghe + * KU Leuven, Department of Computer Science, CODeS & iMinds-ITEC + * Gebr. De Smetstraat 1, 9000 Gent, Belgium, jan.christiaens@cs.kuleuven.be, greet.vandenberghe@cs.kuleuven.be + * + * https://lirias.kuleuven.be/bitstream/123456789/556398/1/asb_rr_2016.pdf * * @author stefan */ @@ -45,46 +50,14 @@ public final class RuinString extends AbstractRuinStrategy { private JobNeighborhoods jobNeighborhoods; - private int Kmin = 1; + private int kMin = 1; - private int Kmax = 6; + private int kMax = 6; - private int Lmin = 30; - - private int Lmax = 60; - - /** - * Constructs RuinRadial. - * - * @param vrp - * @param jobDistance i.e. a measure to define the distance between two jobs and whether they are located close or distant to eachother - * @param Kmin - * @param Kmax - * @param Lmin - * @param Lmax - */ - public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance, int Kmin, int Kmax, int Lmin, int Lmax) { - super(vrp); - this.vrp = vrp; - JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); - jobNeighborhoodsImpl.initialise(); - jobNeighborhoods = jobNeighborhoodsImpl; - this.Kmin = Kmin; - this.Kmax = Kmax; - this.Lmin = Lmin; - this.Lmax = Lmax; - logger.debug("initialise {}", this); - } - - public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance) { - super(vrp); - this.vrp = vrp; - JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); - jobNeighborhoodsImpl.initialise(); - jobNeighborhoods = jobNeighborhoodsImpl; - logger.debug("initialise {}", this); - } + private int lMin = 30; + private int lMax = 60; + public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) { super(vrp); this.vrp = vrp; @@ -92,15 +65,14 @@ public final class RuinString extends AbstractRuinStrategy { logger.debug("initialise {}", this); } - public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods, int Kmin, int Kmax, int Lmin, int Lmax) { - super(vrp); - this.vrp = vrp; - this.jobNeighborhoods = jobNeighborhoods; - this.Kmin = Kmin; - this.Kmax = Kmax; - this.Lmin = Lmin; - this.Lmax = Lmax; - logger.debug("initialise {}", this); + public void setNoRoutes(int kMin, int kMax) { + this.kMin = kMin; + this.kMax = kMax; + } + + public void setStringLength(int lMin, int lMax) { + this.lMin = lMin; + this.lMax = lMax; } @Override @@ -117,12 +89,12 @@ public final class RuinString extends AbstractRuinStrategy { if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) { return Collections.emptyList(); } - int noStrings = Kmin + random.nextInt((Kmax - Kmin)); + int noStrings = kMin + random.nextInt((kMax - kMin)); noStrings = Math.min(noStrings, vehicleRoutes.size()); Set unassignedJobs = new HashSet<>(); Set ruinedRoutes = new HashSet<>(); Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random); - Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(Kmax * Lmax, prevJob); + Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(kMax * lMax, prevJob); while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) { if (!unassignedJobs.contains(prevJob)) { VehicleRoute route = getRouteOf(prevJob, vehicleRoutes); @@ -149,7 +121,7 @@ public final class RuinString extends AbstractRuinStrategy { private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { int noActivities = seedRoute.getActivities().size(); - int stringLength = Lmin + random.nextInt(Lmax - Lmin); + int stringLength = lMin + random.nextInt(lMax - lMin); stringLength = Math.min(stringLength, seedRoute.getActivities().size()); int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random); @@ -204,7 +176,7 @@ public final class RuinString extends AbstractRuinStrategy { private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { - int stringLength = Lmin + random.nextInt(Lmax - Lmin); + int stringLength = lMin + random.nextInt(lMax - lMin); stringLength = Math.min(stringLength, seedRoute.getActivities().size()); List acts = vrp.getActivities(prevJob); AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random); diff --git a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java deleted file mode 100644 index 88544ec4..00000000 --- a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.graphhopper.jsprit.examples; - - -import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder; -import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer; -import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; -import com.graphhopper.jsprit.core.algorithm.SearchStrategy; -import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; -import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance; -import com.graphhopper.jsprit.core.algorithm.box.Jsprit; -import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener; -import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule; -import com.graphhopper.jsprit.core.algorithm.recreate.*; -import com.graphhopper.jsprit.core.algorithm.ruin.RadialRuinStrategyFactory; -import com.graphhopper.jsprit.core.algorithm.ruin.RandomRuinStrategyFactory; -import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy; -import com.graphhopper.jsprit.core.algorithm.ruin.RuinString; -import com.graphhopper.jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance; -import com.graphhopper.jsprit.core.algorithm.selector.SelectBest; -import com.graphhopper.jsprit.core.algorithm.state.StateManager; -import com.graphhopper.jsprit.core.analysis.SolutionAnalyser; -import com.graphhopper.jsprit.core.problem.Location; -import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; -import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; -import com.graphhopper.jsprit.core.problem.cost.TransportDistance; -import com.graphhopper.jsprit.core.problem.job.Job; -import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator; -import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; -import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; -import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory; -import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; -import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; -import com.graphhopper.jsprit.core.reporting.SolutionPrinter; -import com.graphhopper.jsprit.core.util.Solutions; -import com.graphhopper.jsprit.instance.reader.CordeauReader; -import com.graphhopper.jsprit.util.Examples; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class BuildAlgorithmFromScratch2 { - - - public static class MyBestStrategy extends AbstractInsertionStrategy { - - private JobInsertionCostsCalculatorLight insertionCalculator; - - - public MyBestStrategy(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) { - super(vrp); - insertionCalculator = JobInsertionCostsCalculatorLightFactory.createStandardCalculator(vrp, fleetManager, stateManager, constraintManager); - } - - @Override - public Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs) { - List badJobs = new ArrayList(); - List unassigned = new ArrayList(unassignedJobs); - Collections.shuffle(unassigned, random); - - for (Job j : unassigned) { - - InsertionData bestInsertionData = InsertionData.createEmptyInsertionData(); - VehicleRoute bestRoute = null; - //look for inserting unassigned job into existing route - for (VehicleRoute r : vehicleRoutes) { - InsertionData insertionData = insertionCalculator.getInsertionData(j, r, bestInsertionData.getInsertionCost()); - if (insertionData instanceof InsertionData.NoInsertionFound) continue; - if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { - bestInsertionData = insertionData; - bestRoute = r; - } - } - //try whole new route - VehicleRoute empty = VehicleRoute.emptyRoute(); - InsertionData insertionData = insertionCalculator.getInsertionData(j, empty, bestInsertionData.getInsertionCost()); - if (!(insertionData instanceof InsertionData.NoInsertionFound)) { - if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { - vehicleRoutes.add(empty); - insertJob(j, insertionData, empty); - } - } else { - if (bestRoute != null) insertJob(j, bestInsertionData, bestRoute); - else badJobs.add(j); - } - } - return badJobs; - } - - - } - - - public static void main(String[] args) { - Examples.createOutputFolder(); - - VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); - new CordeauReader(vrpBuilder).read("input/p11"); - final VehicleRoutingProblem vrp = vrpBuilder.build(); - -// VehicleRoutingAlgorithm vra = createAlgorithm(vrp); - VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setProperty(Jsprit.Parameter.FAST_REGRET, "true") - .setProperty(Jsprit.Parameter.THREADS, "4") - .setProperty(Jsprit.Parameter.REGRET_DISTANCE_SCORER, "0.0001") - .setProperty(Jsprit.Strategy.STRING_BEST, "0.2") - .setProperty(Jsprit.Strategy.STRING_REGRET, "0.2") - .buildAlgorithm(); - - vra.setMaxIterations(15000); - AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz"); - eventsRecorder.setRecordingRange(40, 100); -// vra.addListener(eventsRecorder); - - VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); - SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); - - new GraphStreamViewer(vrp, solution).display(); -// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer(); -// viewer.setRuinDelay(6); -// viewer.setRecreationDelay(1); -// viewer.display("output/events.dgs.gz"); - - } - - - public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) { - - VehicleFleetManager fleetManager = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); - StateManager stateManager = new StateManager(vrp); - ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); - - /* - * insertion strategies - */ - //my custom best insertion - MyBestStrategy best = new MyBestStrategy(vrp, fleetManager, stateManager, constraintManager); - - //regret insertion - InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager); - iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); - iBuilder.setFastRegret(true); - - RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build(); - DefaultScorer scoringFunction = new DefaultScorer(vrp); - scoringFunction.setDepotDistanceParam(0.00001); - scoringFunction.setTimeWindowParam(0); - regret.setScoringFunction(scoringFunction); - - /* - * ruin strategies - */ - RuinStrategy randomRuin = new RandomRuinStrategyFactory(0.5).createStrategy(vrp); - RuinStrategy radialRuin = new RadialRuinStrategyFactory(0.3, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())).createStrategy(vrp); - - /* - * objective function - */ - - RuinStrategy stringRuin = new RuinString(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())); - - SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp); - - final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, 0.15); - IterationStartsListener schrimpfThreshold = new IterationStartsListener() { - @Override - public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - if (i == 1) { - double initialThreshold = Solutions.bestOf(solutions).getCost() * 0.03; - schrimpfAcceptance.setInitialThreshold(initialThreshold); - } - } - }; - - SearchStrategy firstStrategy = new SearchStrategy("firstStrategy", new SelectBest(), schrimpfAcceptance, objectiveFunction); - firstStrategy.addModule(new RuinAndRecreateModule("randRuinRegretIns", regret, stringRuin)); - -// SearchStrategy secondStrategy = new SearchStrategy("secondStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); -// secondStrategy.addModule(new RuinAndRecreateModule("radRuinRegretIns", regret, radialRuin)); - -// SearchStrategy thirdStrategy = new SearchStrategy("thirdStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); -// secondStrategy.addModule(new RuinAndRecreateModule("radRuinBestIns", regret, radialRuin)); - - PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fleetManager, stateManager, constraintManager); - final VehicleRoutingAlgorithm vra = prettyAlgorithmBuilder - .withStrategy(firstStrategy, 0.5) -// .withStrategy(secondStrategy, 0.5).withStrategy(thirdStrategy, 0.2) - .addCoreStateAndConstraintStuff() - .constructInitialSolutionWith(regret, objectiveFunction) - .build(); - - //if you want to switch on/off strategies or adapt their weight within the search, you can do the following - //e.g. from iteration 50 on, switch off first strategy - //switch on again at iteration 90 with slightly higher weight -// IterationStartsListener strategyAdaptor = new IterationStartsListener() { -// @Override -// public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { -// if (i == 50) { -// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.0); -// System.out.println("switched off firstStrategy"); -// } -// if (i == 90) { -// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.7); -// System.out.println("switched on firstStrategy again with higher weight"); -// } -// } -// }; -// vra.addListener(strategyAdaptor); - vra.addListener(schrimpfThreshold); - vra.addListener(schrimpfAcceptance); - return vra; - - } - - private static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp) { - return new SolutionCostCalculator() { - - - @Override - public double getCosts(VehicleRoutingProblemSolution solution) { - SolutionAnalyser analyser = new SolutionAnalyser(vrp, solution, new TransportDistance() { - @Override - public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { - return vrp.getTransportCosts().getTransportCost(from, to, 0., null, null); - } - }); - return analyser.getVariableTransportCosts() + solution.getUnassignedJobs().size() * 500.; - } - - }; - } - - -}