mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
make string ruin configurable
This commit is contained in:
parent
5d56d2e091
commit
9e2afa4f75
3 changed files with 36 additions and 313 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Job> unassignedJobs = new HashSet<>();
|
||||
Set<VehicleRoute> ruinedRoutes = new HashSet<>();
|
||||
Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random);
|
||||
Iterator<Job> neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(Kmax * Lmax, prevJob);
|
||||
Iterator<Job> 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<Job> 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<Job> unassignedJobs) {
|
||||
int stringLength = Lmin + random.nextInt(Lmax - Lmin);
|
||||
int stringLength = lMin + random.nextInt(lMax - lMin);
|
||||
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
|
||||
List<AbstractActivity> acts = vrp.getActivities(prevJob);
|
||||
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
|
||||
|
|
|
|||
|
|
@ -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<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||
List<Job> badJobs = new ArrayList<Job>();
|
||||
List<Job> unassigned = new ArrayList<Job>(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<VehicleRoutingProblemSolution> 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<VehicleRoutingProblemSolution> 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.;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue