1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

Merge remote-tracking branch 'origin/master'

This commit is contained in:
Michal Maciejewski 2018-09-26 15:19:19 +02:00
commit b68879303e
No known key found for this signature in database
GPG key ID: 015947E60A2AD77B
28 changed files with 1404 additions and 169 deletions

View file

@ -51,7 +51,7 @@ script:
notifications: notifications:
email: email:
- github@graphhopper.com - $EMAIL
cache: cache:
directories: directories:

View file

@ -1,29 +1,34 @@
## Other Related Open Source Implementations
### VRP ### VRP
#### [Chris Groer's VRPH library](https://sites.google.com/site/vrphlibrary/)
An open source library for solving the capacitated vehicle routing problem written in C++.
#### [OptaPlanner](https://www.optaplanner.org/)
OptaPlanner is a lightweight, embeddable planning engine written in Java™. It can be used to solve the capacitated vehicle routing problem (with time windows).
#### [Open-VRP](https://github.com/mck-/Open-VRP)
Open-VRP is a framework to model and solve various vehicle routing problems.
#### [VROOM](https://github.com/jcoupey/vroom)
VROOM is an optimization engine written in C++14 that aim at providing good solutions to various real-life vehicle routing problems within a small computing time. It is free software, distributed under the term of the GNU General Public License V3.
#### [Hipster4j](http://www.hipster4j.org/) #### [Hipster4j](http://www.hipster4j.org/)
Hipster is an easy to use yet powerful and flexible type-safe library for heuristic search, written in pure Java. It relies on a flexible model with generic operators to define search problems. So you can also model and solve vehicle routing problems. Hipster is an easy to use yet powerful and flexible type-safe library for heuristic search, written in pure Java. It relies on a flexible model with generic operators to define search problems. So you can also model and solve vehicle routing problems.
#### [Open-VRP](https://github.com/mck-/Open-VRP)
Open-VRP is a framework to model and solve various vehicle routing problems.
#### [OptaPlanner](https://www.optaplanner.org/)
OptaPlanner is a lightweight, embeddable planning engine written in Java™. It can be used to solve the capacitated vehicle routing problem (with time windows).
#### [OR-Tools](https://developers.google.com/optimization/)
Google Optimization Tools (OR-Tools) is a fast and portable software suite for solving combinatorial optimization problems, including the VRP. Open-source, written in C++ and available through SWIG for Python, Java, and .NET (using Mono on non-Windows platforms). You can compile OR-Tools on Linux, Mac OS X, and Windows (with Visual Studio).
#### [OscaR](https://bitbucket.org/oscarlib/oscar/wiki/Home) #### [OscaR](https://bitbucket.org/oscarlib/oscar/wiki/Home)
OscaR, an Open Source Toolbox for Optimising Logistics and Supply Chain Systems. OscaR, an Open Source Toolbox for Optimising Logistics and Supply Chain Systems.
#### [VROOM](https://github.com/jcoupey/vroom)
VROOM is an optimization engine written in C++14 that aim at providing good solutions to various real-life vehicle routing problems within a small computing time. It is free software, distributed under the term of the GNU General Public License V3.
#### [VRPH library](https://sites.google.com/site/vrphlibrary/)
An open source library by Chris Groer for solving the capacitated vehicle routing problem written in C++.
Now hosted by [coin-or](https://projects.coin-or.org/VRPH)
### Territory Design ### Territory Design
#### [OpenDoorLogistics](http://www.opendoorlogistics.com) #### [OpenDoorLogistics](http://www.opendoorlogistics.com)
Open Door Logistics Studio is an easy-to-use Open Door Logistics Studio is an easy-to-use
standalone open source application for performing geographic analysis of your customer base and sales territory design, mapping and management. standalone open source application for performing geographic analysis of your customer base and sales territory design, mapping and management.
### Other implementations
If you know another promising open source implementation, report it. If you know another promising open source implementation, report it.

View file

@ -20,6 +20,7 @@ package com.graphhopper.jsprit.core.algorithm.box;
import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy; import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
import com.graphhopper.jsprit.core.algorithm.SearchStrategyModule;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance; import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance;
import com.graphhopper.jsprit.core.algorithm.acceptor.SolutionAcceptor; import com.graphhopper.jsprit.core.algorithm.acceptor.SolutionAcceptor;
@ -124,7 +125,10 @@ public class Jsprit {
STRING_K_MIN("string_kmin"), STRING_K_MIN("string_kmin"),
STRING_K_MAX("string_kmax"), STRING_K_MAX("string_kmax"),
STRING_L_MIN("string_lmin"), STRING_L_MIN("string_lmin"),
STRING_L_MAX("string_lmax"); STRING_L_MAX("string_lmax"),
MIN_UNASSIGNED("min_unassigned"),
PROPORTION_UNASSIGNED("proportion_unassigned");
String paraName; String paraName;
@ -233,6 +237,9 @@ public class Jsprit {
defaults.put(Parameter.FAST_REGRET.toString(), String.valueOf(false)); defaults.put(Parameter.FAST_REGRET.toString(), String.valueOf(false));
defaults.put(Parameter.BREAK_SCHEDULING.toString(), String.valueOf(true)); defaults.put(Parameter.BREAK_SCHEDULING.toString(), String.valueOf(true));
defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString()); defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString());
defaults.put(Parameter.MIN_UNASSIGNED.toString(), String.valueOf(Integer.MAX_VALUE));
defaults.put(Parameter.PROPORTION_UNASSIGNED.toString(), String.valueOf(1.0));
return defaults; return defaults;
} }
@ -526,8 +533,8 @@ public class Jsprit {
boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString())); boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
if (es != null) { if (es != null) {
if(fastRegret){ if(fastRegret){
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads) .setConcurrentMode(es, noThreads)
.setFastRegret(true) .setFastRegret(true)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
@ -540,8 +547,8 @@ public class Jsprit {
regret = regretInsertion; regret = regretInsertion;
} }
else { else {
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads) .setConcurrentMode(es, noThreads)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
@ -553,8 +560,8 @@ public class Jsprit {
} }
} else { } else {
if(fastRegret) { if(fastRegret) {
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.REGRET)
.setFastRegret(true) .setFastRegret(true)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
@ -566,8 +573,8 @@ public class Jsprit {
regret = regretInsertion; regret = regretInsertion;
} }
else{ else{
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) RegretInsertion regretInsertion = (RegretInsertion) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.REGRET)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion) .setActivityInsertionCostCalculator(activityInsertion)
@ -581,16 +588,16 @@ public class Jsprit {
AbstractInsertionStrategy best; AbstractInsertionStrategy best;
if (vrp.getJobs().size() < 250 || es == null) { if (vrp.getJobs().size() < 250 || es == null) {
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) BestInsertion bestInsertion = (BestInsertion) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion) .setActivityInsertionCostCalculator(activityInsertion)
.build(); .build();
best = bestInsertion; best = bestInsertion;
} else { } else {
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST) .setInsertionStrategy(InsertionStrategyBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setConcurrentMode(es, noThreads) .setConcurrentMode(es, noThreads)
@ -621,34 +628,34 @@ public class Jsprit {
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, maxCosts); SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, maxCosts);
SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
radial_regret.addModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial)); radial_regret.addModule(configureModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial)));
SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
radial_best.addModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(), best, radial)); radial_best.addModule(configureModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(), best, radial)));
SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
random_best.addModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best)); random_best.addModule(configureModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best)));
SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
random_regret.addModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(), regret, random_for_regret)); random_regret.addModule(configureModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(), regret, random_for_regret)));
SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
worst_regret.addModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(), regret, worst)); worst_regret.addModule(configureModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(), regret, worst)));
SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
worst_best.addModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(), best, worst)); worst_best.addModule(configureModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(), best, worst)));
final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
clusters_regret.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(), regret, clusters)); clusters_regret.addModule(configureModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(), regret, clusters)));
final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters)); clusters_best.addModule(configureModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters)));
SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
stringRegret.addModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin)); stringRegret.addModule(configureModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin)));
SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin)); stringBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin)));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager); PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager);
prettyBuilder.setRandom(random); prettyBuilder.setRandom(random);
@ -697,6 +704,13 @@ public class Jsprit {
} }
private SearchStrategyModule configureModule(RuinAndRecreateModule ruinAndRecreateModule) {
ruinAndRecreateModule.setRandom(random);
ruinAndRecreateModule.setMinUnassignedJobsToBeReinserted(Integer.valueOf(properties.getProperty(Parameter.MIN_UNASSIGNED.toString())));
ruinAndRecreateModule.setProportionOfUnassignedJobsToBeReinserted(Double.valueOf(properties.getProperty(Parameter.PROPORTION_UNASSIGNED.toString())));
return ruinAndRecreateModule;
}
private DefaultScorer getRegretScorer(VehicleRoutingProblem vrp) { private DefaultScorer getRegretScorer(VehicleRoutingProblem vrp) {
DefaultScorer scorer = new DefaultScorer(vrp); DefaultScorer scorer = new DefaultScorer(vrp);
scorer.setTimeWindowParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString()))); scorer.setTimeWindowParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString())));

View file

@ -26,9 +26,7 @@ import com.graphhopper.jsprit.core.algorithm.ruin.listener.RuinListener;
import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.*;
import java.util.HashSet;
import java.util.Set;
public class RuinAndRecreateModule implements SearchStrategyModule { public class RuinAndRecreateModule implements SearchStrategyModule {
@ -39,6 +37,12 @@ public class RuinAndRecreateModule implements SearchStrategyModule {
private String moduleName; private String moduleName;
private Random random = new Random(4711);
private int minUnassignedJobsToBeReinserted = Integer.MAX_VALUE;
private double proportionOfUnassignedJobsToBeReinserted = 1d;
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) { public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
super(); super();
this.insertion = insertion; this.insertion = insertion;
@ -46,16 +50,58 @@ public class RuinAndRecreateModule implements SearchStrategyModule {
this.moduleName = moduleName; this.moduleName = moduleName;
} }
/**
* To make overall results reproducible, make sure this class is provided with the "global" random number generator.
*
* @param random
*/
public void setRandom(Random random) {
this.random = random;
}
/**
* Minimum number of unassigned jobs that is reinserted in each iteration.
*
* @param minUnassignedJobsToBeReinserted
*/
public void setMinUnassignedJobsToBeReinserted(int minUnassignedJobsToBeReinserted) {
this.minUnassignedJobsToBeReinserted = minUnassignedJobsToBeReinserted;
}
/**
* Proportion of unassigned jobs that is reinserted in each iteration.
*
* @param proportionOfUnassignedJobsToBeReinserted
*/
public void setProportionOfUnassignedJobsToBeReinserted(double proportionOfUnassignedJobsToBeReinserted) {
this.proportionOfUnassignedJobsToBeReinserted = proportionOfUnassignedJobsToBeReinserted;
}
@Override @Override
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution previousVrpSolution) {
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); Collection<Job> ruinedJobs = ruin.ruin(previousVrpSolution.getRoutes());
Set<Job> ruinedJobSet = new HashSet<Job>(); Set<Job> ruinedJobSet = new HashSet<>();
ruinedJobSet.addAll(ruinedJobs); ruinedJobSet.addAll(ruinedJobs);
ruinedJobSet.addAll(vrpSolution.getUnassignedJobs()); List<Job> stillUnassignedInThisIteration = new ArrayList<>();
Collection<Job> unassignedJobs = insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobSet); if (previousVrpSolution.getUnassignedJobs().size() < minUnassignedJobsToBeReinserted) {
vrpSolution.getUnassignedJobs().clear(); ruinedJobSet.addAll(previousVrpSolution.getUnassignedJobs());
vrpSolution.getUnassignedJobs().addAll(unassignedJobs); } else {
return vrpSolution; int noUnassignedToBeInserted = Math.max(minUnassignedJobsToBeReinserted, (int) (previousVrpSolution.getUnassignedJobs().size() * proportionOfUnassignedJobsToBeReinserted));
List<Job> jobList = new ArrayList<>(previousVrpSolution.getUnassignedJobs());
Collections.shuffle(jobList, random);
for (int i = 0; i < noUnassignedToBeInserted; i++) {
ruinedJobSet.add(jobList.get(i));
}
for (int i = noUnassignedToBeInserted; i < jobList.size(); i++) {
stillUnassignedInThisIteration.add(jobList.get(i));
}
}
Collection<Job> unassignedJobs = insertion.insertJobs(previousVrpSolution.getRoutes(), ruinedJobSet);
previousVrpSolution.getUnassignedJobs().clear();
previousVrpSolution.getUnassignedJobs().addAll(unassignedJobs);
previousVrpSolution.getUnassignedJobs().addAll(stillUnassignedInThisIteration);
VehicleRoutingProblemSolution newSolution = previousVrpSolution;
return newSolution;
} }

View file

@ -49,25 +49,25 @@ final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LoggerFactory.getLogger(BreakInsertionCalculator.class); private static final Logger logger = LoggerFactory.getLogger(BreakInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint; private final HardRouteConstraint hardRouteLevelConstraint;
private HardActivityConstraint hardActivityLevelConstraint; private final HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint; private final SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint; private final SoftActivityConstraint softActivityConstraint;
private VehicleRoutingTransportCosts transportCosts; private final VehicleRoutingTransportCosts transportCosts;
private final VehicleRoutingActivityCosts activityCosts; private final VehicleRoutingActivityCosts activityCosts;
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator; private final ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
private JobActivityFactory activityFactory; private final JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator; private final AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) { public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager, JobActivityFactory activityFactory) {
super(); super();
this.transportCosts = routingCosts; this.transportCosts = routingCosts;
this.activityCosts = activityCosts; this.activityCosts = activityCosts;
@ -77,12 +77,10 @@ final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
softRouteConstraint = constraintManager; softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator; this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts); additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
this.activityFactory = activityFactory;
logger.debug("initialise " + this); logger.debug("initialise " + this);
} }
public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
this.activityFactory = jobActivityFactory;
}
@Override @Override
public String toString() { public String toString() {

View file

@ -0,0 +1,30 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
public class BreakInsertionCalculatorFactory implements JobInsertionCostsCalculatorFactory {
@Override
public JobInsertionCostsCalculator create(VehicleRoutingProblem vrp, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, JobActivityFactory jobActivityFactory, ConstraintManager constraintManager) {
return new BreakInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityInsertionCostsCalculator, constraintManager, jobActivityFactory);
}
}

View file

@ -49,8 +49,7 @@ public class BreakScheduling implements InsertionStartsListener,JobInsertedListe
public BreakScheduling(VehicleRoutingProblem vrp, StateManager stateManager, ConstraintManager constraintManager) { public BreakScheduling(VehicleRoutingProblem vrp, StateManager stateManager, ConstraintManager constraintManager) {
this.stateManager = stateManager; this.stateManager = stateManager;
this.breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(),vrp.getActivityCosts(),new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(),vrp.getActivityCosts(),stateManager),constraintManager); this.breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), stateManager), constraintManager, vrp.getJobActivityFactory());
this.breakInsertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory());
eventListeners = new EventListeners(); eventListeners = new EventListeners();
} }

View file

@ -28,7 +28,10 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
/**
* use InsertionStrategyBuilder instead
*/
@Deprecated
public class InsertionBuilder { public class InsertionBuilder {
private boolean fastRegret; private boolean fastRegret;

View file

@ -0,0 +1,239 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListener;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class InsertionStrategyBuilder {
private boolean fastRegret;
public enum Strategy {
REGRET, BEST
}
private VehicleRoutingProblem vrp;
private StateManager stateManager;
private boolean local = true;
private ConstraintManager constraintManager;
private VehicleFleetManager fleetManager;
private double weightOfFixedCosts;
private boolean considerFixedCosts = false;
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
private int forwaredLooking;
private int memory;
private ExecutorService executor;
private int nuOfThreads;
private double timeSlice;
private int nNeighbors;
private boolean timeScheduling = false;
private boolean allowVehicleSwitch = true;
private boolean addDefaultCostCalc = true;
private Strategy strategy = Strategy.BEST;
private boolean isFastRegret = false;
private JobInsertionCostsCalculatorFactory shipmentInsertionCalculatorFactory;
private JobInsertionCostsCalculatorFactory serviceInsertionCalculatorFactory;
private JobInsertionCostsCalculatorFactory breakInsertionCalculatorFactory;
public InsertionStrategyBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
super();
this.vrp = vrp;
this.stateManager = stateManager;
this.constraintManager = constraintManager;
this.fleetManager = vehicleFleetManager;
}
public InsertionStrategyBuilder setShipmentInsertionCalculatorFactory(JobInsertionCostsCalculatorFactory shipmentInsertionCalculatorFactory) {
this.shipmentInsertionCalculatorFactory = shipmentInsertionCalculatorFactory;
return this;
}
public InsertionStrategyBuilder setServiceInsertionCalculator(JobInsertionCostsCalculatorFactory serviceInsertionCalculator) {
this.serviceInsertionCalculatorFactory = serviceInsertionCalculator;
return this;
}
public InsertionStrategyBuilder setBreakInsertionCalculator(JobInsertionCostsCalculatorFactory breakInsertionCalculator) {
this.breakInsertionCalculatorFactory = breakInsertionCalculator;
return this;
}
public InsertionStrategyBuilder setInsertionStrategy(Strategy strategy) {
this.strategy = strategy;
return this;
}
public InsertionStrategyBuilder setRouteLevel(int forwardLooking, int memory) {
local = false;
this.forwaredLooking = forwardLooking;
this.memory = memory;
return this;
}
public InsertionStrategyBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation) {
local = false;
this.forwaredLooking = forwardLooking;
this.memory = memory;
this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
return this;
}
public InsertionStrategyBuilder setFastRegret(boolean fastRegret) {
this.isFastRegret = fastRegret;
return this;
}
public InsertionStrategyBuilder setLocalLevel() {
local = true;
return this;
}
/**
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
* is controlled by your custom soft constraints.
*
* @param addDefaultMarginalCostCalculation
* @return
*/
public InsertionStrategyBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation) {
local = true;
addDefaultCostCalc = addDefaultMarginalCostCalculation;
return this;
}
public InsertionStrategyBuilder considerFixedCosts(double weightOfFixedCosts) {
this.weightOfFixedCosts = weightOfFixedCosts;
this.considerFixedCosts = true;
return this;
}
public InsertionStrategyBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
return this;
}
public InsertionStrategyBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
this.executor = executor;
this.nuOfThreads = nuOfThreads;
return this;
}
public InsertionStrategy build() {
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
List<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener> algorithmListeners = new ArrayList<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener>();
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
if (local) {
calcBuilder.setLocalLevel(addDefaultCostCalc);
} else {
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
}
if (shipmentInsertionCalculatorFactory != null)
calcBuilder.setShipmentCalculatorFactory(shipmentInsertionCalculatorFactory);
if (serviceInsertionCalculatorFactory != null)
calcBuilder.setServiceCalculatorFactory(serviceInsertionCalculatorFactory);
if (breakInsertionCalculatorFactory != null)
calcBuilder.setBreakCalculatorFactory(breakInsertionCalculatorFactory);
calcBuilder.setConstraintManager(constraintManager);
calcBuilder.setStateManager(stateManager);
calcBuilder.setVehicleRoutingProblem(vrp);
calcBuilder.setVehicleFleetManager(fleetManager);
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
if (considerFixedCosts) {
calcBuilder.considerFixedCosts(weightOfFixedCosts);
}
if (timeScheduling) {
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
}
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
JobInsertionCostsCalculator costCalculator = calcBuilder.build();
InsertionStrategy insertion;
if (strategy.equals(Strategy.BEST)) {
if (executor == null) {
insertion = new BestInsertion(costCalculator, vrp);
} else {
insertion = new BestInsertionConcurrent(costCalculator, executor, nuOfThreads, vrp);
}
} else if (strategy.equals(Strategy.REGRET)) {
if (executor == null) {
if (isFastRegret) {
RegretInsertionFast regret = new RegretInsertionFast(costCalculator, vrp, fleetManager);
regret.setSwitchAllowed(allowVehicleSwitch);
insertion = regret;
} else {
RegretInsertion regret = new RegretInsertion(costCalculator, vrp);
insertion = regret;
}
} else {
if (isFastRegret) {
RegretInsertionConcurrentFast regret = new RegretInsertionConcurrentFast(costCalculator, vrp, executor, fleetManager);
regret.setSwitchAllowed(allowVehicleSwitch);
insertion = regret;
} else {
RegretInsertionConcurrent regret = new RegretInsertionConcurrent(costCalculator, vrp, executor);
insertion = regret;
}
}
} else throw new IllegalStateException("you should never get here");
for (InsertionListener l : iListeners) insertion.addListener(l);
return insertion;
}
public InsertionStrategyBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
this.allowVehicleSwitch = allowVehicleSwitch;
return this;
}
}

View file

@ -25,6 +25,6 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
public interface JobInsertionCostsCalculator { public interface JobInsertionCostsCalculator {
public InsertionData getInsertionData(VehicleRoute currentRoute, Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts); InsertionData getInsertionData(VehicleRoute currentRoute, Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts);
} }

View file

@ -94,6 +94,12 @@ public class JobInsertionCostsCalculatorBuilder {
private boolean addDefaultCostCalc = true; private boolean addDefaultCostCalc = true;
private JobInsertionCostsCalculatorFactory shipmentCalculatorFactory = new ShipmentInsertionCalculatorFactory();
private JobInsertionCostsCalculatorFactory serviceCalculatorFactory = new ServiceInsertionCalculatorFactory();
private JobInsertionCostsCalculatorFactory breakCalculatorFactory = new BreakInsertionCalculatorFactory();
/** /**
* Constructs the builder. * Constructs the builder.
* <p> * <p>
@ -109,6 +115,24 @@ public class JobInsertionCostsCalculatorBuilder {
this.algorithmListeners = algorithmListeners; this.algorithmListeners = algorithmListeners;
} }
public JobInsertionCostsCalculatorBuilder setShipmentCalculatorFactory(JobInsertionCostsCalculatorFactory shipmentCalculatorFactory) {
if (shipmentCalculatorFactory == null) return this;
this.shipmentCalculatorFactory = shipmentCalculatorFactory;
return this;
}
public JobInsertionCostsCalculatorBuilder setServiceCalculatorFactory(JobInsertionCostsCalculatorFactory serviceCalculatorFactory) {
if (serviceCalculatorFactory == null) return this;
this.serviceCalculatorFactory = serviceCalculatorFactory;
return this;
}
public JobInsertionCostsCalculatorBuilder setBreakCalculatorFactory(JobInsertionCostsCalculatorFactory breakCalculatorFactory) {
if (breakCalculatorFactory == null) return this;
this.breakCalculatorFactory = breakCalculatorFactory;
return this;
}
/** /**
* Sets activityStates. MUST be set. * Sets activityStates. MUST be set.
* *
@ -287,20 +311,17 @@ public class JobInsertionCostsCalculatorBuilder {
} }
}; };
ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(),actInsertionCalc, constraintManager);
shipmentInsertion.setJobActivityFactory(activityFactory);
ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), actInsertionCalc, constraintManager);
serviceInsertion.setJobActivityFactory(activityFactory);
BreakInsertionCalculator breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), actInsertionCalc, constraintManager); JobInsertionCostsCalculator shipmentInsertion = shipmentCalculatorFactory.create(vrp, actInsertionCalc, activityFactory, constraintManager);
breakInsertionCalculator.setJobActivityFactory(activityFactory); JobInsertionCostsCalculator serviceInsertion = serviceCalculatorFactory.create(vrp, actInsertionCalc, activityFactory, constraintManager);
JobInsertionCostsCalculator breakInsertion = breakCalculatorFactory.create(vrp, actInsertionCalc, activityFactory, constraintManager);
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
switcher.put(Shipment.class, shipmentInsertion); switcher.put(Shipment.class, shipmentInsertion);
switcher.put(Service.class, serviceInsertion); switcher.put(Service.class, serviceInsertion);
switcher.put(Pickup.class, serviceInsertion); switcher.put(Pickup.class, serviceInsertion);
switcher.put(Delivery.class, serviceInsertion); switcher.put(Delivery.class, serviceInsertion);
switcher.put(Break.class, breakInsertionCalculator); switcher.put(Break.class, breakInsertion);
CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(switcher); CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(switcher);
if (configLocal != null) { if (configLocal != null) {

View file

@ -0,0 +1,29 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
public interface JobInsertionCostsCalculatorFactory {
JobInsertionCostsCalculator create(VehicleRoutingProblem vrp, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, JobActivityFactory jobActivityFactory, ConstraintManager constraintManager);
}

View file

@ -37,7 +37,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
* *
* @author stefan * @author stefan
*/ */
class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator { public class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator {
private VehicleRoutingTransportCosts routingCosts; private VehicleRoutingTransportCosts routingCosts;

View file

@ -55,38 +55,35 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
// private HardActivityConstraint hardActivityLevelConstraint; // private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint; private final SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint; private final SoftActivityConstraint softActivityConstraint;
private VehicleRoutingTransportCosts transportCosts; private final VehicleRoutingTransportCosts transportCosts;
private final VehicleRoutingActivityCosts activityCosts; private final VehicleRoutingActivityCosts activityCosts;
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator; private final ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
private JobActivityFactory activityFactory; private final JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator; private final AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private ConstraintManager constraintManager; private final ConstraintManager constraintManager;
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) { public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager, JobActivityFactory activityFactory) {
super(); super();
this.transportCosts = routingCosts; this.transportCosts = routingCosts;
this.activityCosts = activityCosts; this.activityCosts = activityCosts;
this.constraintManager = constraintManager; this.constraintManager = constraintManager;
softActivityConstraint = constraintManager; softActivityConstraint = constraintManager;
softRouteConstraint = constraintManager; softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator; this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts); additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
this.activityFactory = activityFactory;
logger.debug("initialise {}", this); logger.debug("initialise {}", this);
} }
public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
this.activityFactory = jobActivityFactory;
}
@Override @Override
public String toString() { public String toString() {
return "[name=calculatesServiceInsertion]"; return "[name=calculatesServiceInsertion]";
@ -151,7 +148,7 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager); ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager);
if (status.equals(ConstraintsStatus.FULFILLED)) { if (status.equals(ConstraintsStatus.FULFILLED)) {
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); double additionalTransportationCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) { if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) {
bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts; bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts;
insertionIndex = actIndex; insertionIndex = actIndex;

View file

@ -0,0 +1,30 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
public class ServiceInsertionCalculatorFactory implements JobInsertionCostsCalculatorFactory {
@Override
public JobInsertionCostsCalculator create(VehicleRoutingProblem vrp, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, JobActivityFactory jobActivityFactory, ConstraintManager constraintManager) {
return new ServiceInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityInsertionCostsCalculator, constraintManager, jobActivityFactory);
}
}

View file

@ -48,25 +48,21 @@ final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
private final ConstraintManager constraintManager; private final ConstraintManager constraintManager;
// private HardRouteConstraint hardRouteLevelConstraint; private final SoftRouteConstraint softRouteConstraint;
//
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint; private final SoftActivityConstraint softActivityConstraint;
private SoftActivityConstraint softActivityConstraint; private final ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator; private final VehicleRoutingTransportCosts transportCosts;
private VehicleRoutingTransportCosts transportCosts; private final VehicleRoutingActivityCosts activityCosts;
private VehicleRoutingActivityCosts activityCosts; private final JobActivityFactory activityFactory;
private JobActivityFactory activityFactory; private final AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator; public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager, JobActivityFactory jobActivityFactory) {
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
super(); super();
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator; this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
this.constraintManager = constraintManager; this.constraintManager = constraintManager;
@ -75,16 +71,13 @@ final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
this.transportCosts = routingCosts; this.transportCosts = routingCosts;
this.activityCosts = activityCosts; this.activityCosts = activityCosts;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts); additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
this.activityFactory = jobActivityFactory;
logger.debug("initialise {}", this); logger.debug("initialise {}", this);
} }
public void setJobActivityFactory(JobActivityFactory activityFactory) {
this.activityFactory = activityFactory;
}
@Override @Override
public String toString() { public String toString() {
return "[name=calculatesServiceInsertion]"; return "[name=calculatesShipmentInsertion]";
} }
/** /**

View file

@ -0,0 +1,30 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
public class ShipmentInsertionCalculatorFactory implements JobInsertionCostsCalculatorFactory {
@Override
public JobInsertionCostsCalculator create(VehicleRoutingProblem vrp, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, JobActivityFactory jobActivityFactory, ConstraintManager constraintManager) {
return new ShipmentInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityInsertionCostsCalculator, constraintManager, jobActivityFactory);
}
}

View file

@ -0,0 +1,274 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.ActivityContext;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.Start;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public final class ShipmentInsertionCalculatorFlex extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculatorFlex.class);
private final ConstraintManager constraintManager;
// private HardRouteConstraint hardRouteLevelConstraint;
//
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint;
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
private VehicleRoutingTransportCosts transportCosts;
private VehicleRoutingActivityCosts activityCosts;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private int evalIndexPickup = Integer.MAX_VALUE;
private int evalIndexDelivery = Integer.MAX_VALUE;
public void setEvalIndexPickup(int evalIndexPickup) {
this.evalIndexPickup = evalIndexPickup;
}
public void setEvalIndexDelivery(int evalIndexDelivery) {
this.evalIndexDelivery = evalIndexDelivery;
}
public ShipmentInsertionCalculatorFlex(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
super();
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
this.constraintManager = constraintManager;
this.softActivityConstraint = constraintManager;
this.softRouteConstraint = constraintManager;
this.transportCosts = routingCosts;
this.activityCosts = activityCosts;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
logger.debug("initialise {}", this);
}
public void setJobActivityFactory(JobActivityFactory activityFactory) {
this.activityFactory = activityFactory;
}
@Override
public String toString() {
return "[name=calculatesServiceInsertion]";
}
/**
* Calculates the marginal cost of inserting job i locally. This is based on the
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
*/
@Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
Shipment shipment = (Shipment) jobToInsert;
TourActivity pickupShipment = activityFactory.createActivities(shipment).get(0);
TourActivity deliverShipment = activityFactory.createActivities(shipment).get(1);
insertionContext.getAssociatedActivities().add(pickupShipment);
insertionContext.getAssociatedActivities().add(deliverShipment);
/*
check hard route constraints
*/
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
if (noInsertion != null) return noInsertion;
/*
check soft route constraints
*/
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
double bestCost = bestKnownCosts;
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
int pickupInsertionIndex = InsertionData.NO_INDEX;
int deliveryInsertionIndex = InsertionData.NO_INDEX;
TimeWindow bestPickupTimeWindow = null;
TimeWindow bestDeliveryTimeWindow = null;
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime);
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
ActivityContext pickupContext = new ActivityContext();
TourActivity prevAct = start;
double prevActEndTime = newVehicleDepartureTime;
//loops
int i = 0;
boolean tourEnd = false;
//pickupShipmentLoop
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
List<String> failedActivityConstraints = new ArrayList<>();
while (!tourEnd) {
TourActivity nextAct;
if (i < activities.size()) {
nextAct = activities.get(i);
} else {
nextAct = end;
tourEnd = true;
}
if (i > evalIndexPickup) break;
if (i == evalIndexPickup || evalIndexPickup == Integer.MAX_VALUE) {
boolean pickupInsertionNotFulfilledBreak = true;
for (TimeWindow pickupTimeWindow : shipment.getPickupTimeWindows()) {
pickupShipment.setTheoreticalEarliestOperationStartTime(pickupTimeWindow.getStart());
pickupShipment.setTheoreticalLatestOperationStartTime(pickupTimeWindow.getEnd());
ActivityContext activityContext = new ActivityContext();
activityContext.setInsertionIndex(i);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus pickupShipmentConstraintStatus = fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime, failedActivityConstraints, constraintManager);
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
pickupInsertionNotFulfilledBreak = false;
continue;
} else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
continue;
} else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
pickupInsertionNotFulfilledBreak = false;
}
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
double pickupAIC = calculate(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), pickupShipment.getLocation(), prevActEndTime, newDriver, newVehicle);
double shipmentPickupEndTime = Math.max(shipmentPickupArrTime, pickupShipment.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(pickupShipment, shipmentPickupArrTime, newDriver, newVehicle);
pickupContext.setArrivalTime(shipmentPickupArrTime);
pickupContext.setEndTime(shipmentPickupEndTime);
pickupContext.setInsertionIndex(i);
insertionContext.setRelatedActivityContext(pickupContext);
TourActivity prevActForDeliveryLoop = pickupShipment;
double prevActEndTimeForDeliveryLoop = shipmentPickupEndTime;
/*
--------------------------------
*/
//deliverShipmentLoop
int j = i;
boolean tourEndInDeliveryLoop = false;
while (!tourEndInDeliveryLoop) {
TourActivity nextActForDeliveryLoop;
if (j < activities.size()) {
nextActForDeliveryLoop = activities.get(j);
} else {
nextActForDeliveryLoop = end;
tourEndInDeliveryLoop = true;
}
if (j > evalIndexDelivery) break;
if (j == evalIndexDelivery || evalIndexDelivery == Integer.MAX_VALUE) {
boolean deliveryInsertionNotFulfilledBreak = true;
for (TimeWindow deliveryTimeWindow : shipment.getDeliveryTimeWindows()) {
deliverShipment.setTheoreticalEarliestOperationStartTime(deliveryTimeWindow.getStart());
deliverShipment.setTheoreticalLatestOperationStartTime(deliveryTimeWindow.getEnd());
ActivityContext activityContext_ = new ActivityContext();
activityContext_.setInsertionIndex(j);
insertionContext.setActivityContext(activityContext_);
ConstraintsStatus deliverShipmentConstraintStatus = fulfilled(insertionContext, prevActForDeliveryLoop, deliverShipment, nextActForDeliveryLoop, prevActEndTimeForDeliveryLoop, failedActivityConstraints, constraintManager);
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevActForDeliveryLoop, deliverShipment, nextActForDeliveryLoop, prevActEndTimeForDeliveryLoop);
double deliveryAIC = calculate(insertionContext, prevActForDeliveryLoop, deliverShipment, nextActForDeliveryLoop, prevActEndTimeForDeliveryLoop);
double totalActivityInsertionCosts = pickupAIC + deliveryAIC
+ additionalICostsAtRouteLevel + additionalPickupICosts + additionalDeliveryICosts;
if (totalActivityInsertionCosts < bestCost) {
bestCost = totalActivityInsertionCosts;
pickupInsertionIndex = i;
deliveryInsertionIndex = j;
bestPickupTimeWindow = pickupTimeWindow;
bestDeliveryTimeWindow = deliveryTimeWindow;
}
deliveryInsertionNotFulfilledBreak = false;
} else if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
deliveryInsertionNotFulfilledBreak = false;
}
}
if (deliveryInsertionNotFulfilledBreak) break;
}
//update prevAct and endTime
double nextActArrTime = prevActEndTimeForDeliveryLoop + transportCosts.getTransportTime(prevActForDeliveryLoop.getLocation(), nextActForDeliveryLoop.getLocation(), prevActEndTimeForDeliveryLoop, newDriver, newVehicle);
prevActEndTimeForDeliveryLoop = Math.max(nextActArrTime, nextActForDeliveryLoop.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(nextActForDeliveryLoop, nextActArrTime, newDriver, newVehicle);
prevActForDeliveryLoop = nextActForDeliveryLoop;
j++;
}
}
if (pickupInsertionNotFulfilledBreak) {
break;
}
}
//update prevAct and endTime
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActEndTime, newDriver, newVehicle);
prevActEndTime = Math.max(nextActArrTime, nextAct.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(nextAct, nextActArrTime, newDriver, newVehicle);
prevAct = nextAct;
i++;
}
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
return emptyInsertionData;
}
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());
pickupShipment.setTheoreticalLatestOperationStartTime(bestPickupTimeWindow.getEnd());
deliverShipment.setTheoreticalEarliestOperationStartTime(bestDeliveryTimeWindow.getStart());
deliverShipment.setTheoreticalLatestOperationStartTime(bestDeliveryTimeWindow.getEnd());
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, deliverShipment, deliveryInsertionIndex));
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, pickupShipment, pickupInsertionIndex));
insertionData.getEvents().add(new SwitchVehicle(currentRoute, newVehicle, newVehicleDepartureTime));
return insertionData;
}
private double calculate(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
return activityInsertionCostsCalculator.getCosts(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
}
}

View file

@ -87,7 +87,7 @@ public class VehicleRoutingProblem {
private FleetSize fleetSize = FleetSize.INFINITE; private FleetSize fleetSize = FleetSize.INFINITE;
private Collection<VehicleType> vehicleTypes = new ArrayList<VehicleType>(); private Map<String, VehicleType> vehicleTypes = new HashMap<>();
private Collection<VehicleRoute> initialRoutes = new ArrayList<VehicleRoute>(); private Collection<VehicleRoute> initialRoutes = new ArrayList<VehicleRoute>();
@ -387,8 +387,13 @@ public class VehicleRoutingProblem {
incVehicleTypeIdIndexCounter(); incVehicleTypeIdIndexCounter();
} }
uniqueVehicles.add(vehicle); uniqueVehicles.add(vehicle);
if (!vehicleTypes.contains(vehicle.getType())) { if (!vehicleTypes.containsKey(vehicle.getType().getTypeId())) {
vehicleTypes.add(vehicle.getType()); vehicleTypes.put(vehicle.getType().getTypeId(), vehicle.getType());
} else {
VehicleType existingType = vehicleTypes.get(vehicle.getType().getTypeId());
if (!vehicle.getType().equals(existingType)) {
throw new IllegalArgumentException("A type with type id " + vehicle.getType().getTypeId() + " already exists. However, types are different. Please use unique vehicle types only.");
}
} }
String startLocationId = vehicle.getStartLocation().getId(); String startLocationId = vehicle.getStartLocation().getId();
addLocationToTentativeLocations(vehicle.getStartLocation()); addLocationToTentativeLocations(vehicle.getStartLocation());
@ -496,7 +501,7 @@ public class VehicleRoutingProblem {
* @return collection of vehicle-types * @return collection of vehicle-types
*/ */
public Collection<VehicleType> getAddedVehicleTypes() { public Collection<VehicleType> getAddedVehicleTypes() {
return Collections.unmodifiableCollection(vehicleTypes); return Collections.unmodifiableCollection(vehicleTypes.values());
} }
/** /**
@ -588,7 +593,7 @@ public class VehicleRoutingProblem {
this.jobs = builder.jobs; this.jobs = builder.jobs;
this.fleetSize = builder.fleetSize; this.fleetSize = builder.fleetSize;
this.vehicles = builder.uniqueVehicles; this.vehicles = builder.uniqueVehicles;
this.vehicleTypes = builder.vehicleTypes; this.vehicleTypes = builder.vehicleTypes.values();
this.initialVehicleRoutes = builder.initialRoutes; this.initialVehicleRoutes = builder.initialRoutes;
this.transportCosts = builder.transportCosts; this.transportCosts = builder.transportCosts;
this.activityCosts = builder.activityCosts; this.activityCosts = builder.activityCosts;

View file

@ -22,7 +22,7 @@ import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.Skills; import com.graphhopper.jsprit.core.problem.Skills;
/** /**
* Pickup extends Service and is intended to model a Service where smth is LOADED (i.e. picked up) to a transport unit. * Break extends Service and is intended to model a time-window based driver break.
* *
* @author schroeder * @author schroeder
*/ */
@ -31,7 +31,7 @@ public class Break extends Service {
public static class Builder extends Service.Builder<Break> { public static class Builder extends Service.Builder<Break> {
/** /**
* Returns a new instance of builder that builds a pickup. * Returns a new instance of builder that builds a break.
* *
* @param id the id of the pickup * @param id the id of the pickup
* @return the builder * @return the builder
@ -47,9 +47,9 @@ public class Break extends Service {
} }
/** /**
* Builds Pickup. * Builds Break.
* <p> * <p>
* <p>Pickup type is "pickup" * <p>Pickup type is "break"
* *
* @return pickup * @return pickup
* @throws IllegalStateException if neither locationId nor coordinate has been set * @throws IllegalStateException if neither locationId nor coordinate has been set

View file

@ -81,6 +81,37 @@ public class VehicleTypeImpl implements VehicleType {
public String toString() { public String toString() {
return "[fixed=" + fix + "][perTime=" + perTransportTimeUnit + "][perDistance=" + perDistanceUnit + "][perWaitingTimeUnit=" + perWaitingTimeUnit + "]"; return "[fixed=" + fix + "][perTime=" + perTransportTimeUnit + "][perDistance=" + perDistanceUnit + "][perWaitingTimeUnit=" + perWaitingTimeUnit + "]";
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof VehicleCostParams)) return false;
VehicleCostParams that = (VehicleCostParams) o;
if (Double.compare(that.fix, fix) != 0) return false;
if (Double.compare(that.perTransportTimeUnit, perTransportTimeUnit) != 0) return false;
if (Double.compare(that.perDistanceUnit, perDistanceUnit) != 0) return false;
if (Double.compare(that.perWaitingTimeUnit, perWaitingTimeUnit) != 0) return false;
return Double.compare(that.perServiceTimeUnit, perServiceTimeUnit) == 0;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(fix);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(perTransportTimeUnit);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(perDistanceUnit);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(perWaitingTimeUnit);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(perServiceTimeUnit);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
} }
/** /**
@ -299,32 +330,30 @@ public class VehicleTypeImpl implements VehicleType {
} }
@Override @Override
public int hashCode() { public boolean equals(Object o) {
final int prime = 31; if (this == o) return true;
int result = 1; if (!(o instanceof VehicleTypeImpl)) return false;
result = prime * result
+ ((typeId == null) ? 0 : typeId.hashCode()); VehicleTypeImpl that = (VehicleTypeImpl) o;
return result;
if (Double.compare(that.maxVelocity, maxVelocity) != 0) return false;
if (!typeId.equals(that.typeId)) return false;
if (profile != null ? !profile.equals(that.profile) : that.profile != null) return false;
if (!vehicleCostParams.equals(that.vehicleCostParams)) return false;
return capacityDimensions.equals(that.capacityDimensions);
} }
/**
* Two vehicle-types are equal if they have the same vehicleId.
*/
@Override @Override
public boolean equals(Object obj) { public int hashCode() {
if (this == obj) int result;
return true; long temp;
if (obj == null) result = typeId.hashCode();
return false; result = 31 * result + (profile != null ? profile.hashCode() : 0);
if (getClass() != obj.getClass()) result = 31 * result + vehicleCostParams.hashCode();
return false; result = 31 * result + capacityDimensions.hashCode();
VehicleTypeImpl other = (VehicleTypeImpl) obj; temp = Double.doubleToLongBits(maxVelocity);
if (typeId == null) { result = 31 * result + (int) (temp ^ (temp >>> 32));
if (other.typeId != null) return result;
return false;
} else if (!typeId.equals(other.typeId))
return false;
return true;
} }
private final String typeId; private final String typeId;

View file

@ -0,0 +1,85 @@
/*
* 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.core.algorithm.module;
import com.graphhopper.jsprit.core.algorithm.recreate.InsertionStrategy;
import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.mockito.Mockito.mock;
public class RuinAndRecreateModuleTest {
@Test
public void initialNumOfUnassignedShouldWorkCorrectly() {
InsertionStrategy insertionStrategy = mock(InsertionStrategy.class);
RuinStrategy ruinStrategy = mock(RuinStrategy.class);
RuinAndRecreateModule module = new RuinAndRecreateModule("name", insertionStrategy, ruinStrategy);
Collection<VehicleRoute> routes = new ArrayList<>();
List<Job> unassigned = new ArrayList<>();
for (int i = 0; i < 20; i++) {
unassigned.add(mock(Job.class));
}
VehicleRoutingProblemSolution previousSolution = new VehicleRoutingProblemSolution(routes, unassigned, 0);
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(previousSolution);
Assert.assertEquals(0, newSolution.getUnassignedJobs().size());
}
@Test
public void proportionOfUnassignedShouldWorkCorrectly() {
InsertionStrategy insertionStrategy = mock(InsertionStrategy.class);
RuinStrategy ruinStrategy = mock(RuinStrategy.class);
RuinAndRecreateModule module = new RuinAndRecreateModule("name", insertionStrategy, ruinStrategy);
module.setMinUnassignedJobsToBeReinserted(5);
module.setProportionOfUnassignedJobsToBeReinserted(0.01);
Collection<VehicleRoute> routes = new ArrayList<>();
List<Job> unassigned = new ArrayList<>();
for (int i = 0; i < 20; i++) {
unassigned.add(mock(Job.class));
}
VehicleRoutingProblemSolution previousSolution = new VehicleRoutingProblemSolution(routes, unassigned, 0);
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(previousSolution);
Assert.assertEquals(15, newSolution.getUnassignedJobs().size());
}
@Test
public void proportionOfUnassignedShouldWorkCorrectly2() {
InsertionStrategy insertionStrategy = mock(InsertionStrategy.class);
RuinStrategy ruinStrategy = mock(RuinStrategy.class);
RuinAndRecreateModule module = new RuinAndRecreateModule("name", insertionStrategy, ruinStrategy);
module.setMinUnassignedJobsToBeReinserted(5);
module.setProportionOfUnassignedJobsToBeReinserted(0.5);
Collection<VehicleRoute> routes = new ArrayList<>();
List<Job> unassigned = new ArrayList<>();
for (int i = 0; i < 20; i++) {
unassigned.add(mock(Job.class));
}
VehicleRoutingProblemSolution previousSolution = new VehicleRoutingProblemSolution(routes, unassigned, 0);
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(previousSolution);
Assert.assertEquals(10, newSolution.getUnassignedJobs().size());
}
}

View file

@ -90,7 +90,7 @@ public class ServiceInsertionAndLoadConstraintsTest {
ActivityInsertionCostsCalculator activityInsertionCostsCalculator; ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
ShipmentInsertionCalculator insertionCalculator; // ShipmentInsertionCalculator insertionCalculator;
VehicleRoutingProblem vehicleRoutingProblem; VehicleRoutingProblem vehicleRoutingProblem;
@ -109,7 +109,7 @@ public class ServiceInsertionAndLoadConstraintsTest {
private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) { private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) {
ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class)); ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(hardRouteLevelConstraint); constraintManager.addConstraint(hardRouteLevelConstraint);
insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager); // insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, );
} }
@Test @Test
@ -143,10 +143,9 @@ public class ServiceInsertionAndLoadConstraintsTest {
stateManager.informInsertionStarts(Arrays.asList(route), null); stateManager.informInsertionStarts(Arrays.asList(route), null);
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager); ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
serviceInsertionCalc.setJobActivityFactory(activityFactory); ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
switcher.put(Pickup.class, serviceInsertionCalc); switcher.put(Pickup.class, serviceInsertionCalc);
switcher.put(Delivery.class, serviceInsertionCalc); switcher.put(Delivery.class, serviceInsertionCalc);

View file

@ -0,0 +1,367 @@
/*
* 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.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListeners;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
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.constraint.HardRouteConstraint;
import com.graphhopper.jsprit.core.problem.constraint.PickupAndDeliverShipmentLoadActivityLevelConstraint;
import com.graphhopper.jsprit.core.problem.constraint.ShipmentPickupsFirstConstraint;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.driver.DriverImpl;
import com.graphhopper.jsprit.core.problem.job.Pickup;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupService;
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupShipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
import com.graphhopper.jsprit.core.util.CostFactory;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ShipmentInsertionCalculatorFlexTest {
VehicleRoutingTransportCosts routingCosts;
VehicleRoutingProblem vehicleRoutingProblem;
VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts() {
@Override
public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) {
return 0;
}
@Override
public double getActivityDuration(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) {
return tourAct.getOperationTime();
}
};
HardRouteConstraint hardRouteLevelConstraint = new HardRouteConstraint() {
@Override
public boolean fulfilled(JobInsertionContext insertionContext) {
return true;
}
};
ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
ShipmentInsertionCalculatorFlex insertionCalculator;
Vehicle vehicle;
ConstraintManager constraintManager;
@Before
public void doBefore() {
routingCosts = CostFactory.createManhattanCosts();
VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build();
vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build();
activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, mock(StateManager.class));
constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(hardRouteLevelConstraint);
vehicleRoutingProblem = mock(VehicleRoutingProblem.class);
}
// private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) {
// ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
// constraintManager.addConstraint(hardRouteLevelConstraint);
// insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, );
// }
@Test
public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupShipment(shipment));
activities.add(new DeliverShipment(shipment));
when(activityFactory.createActivities(shipment)).thenReturn(activities);
insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(40.0, iData.getInsertionCost(), 0.05);
}
@Test
public void whenCalculatingInsertionIntoExistingRoute_itShouldReturnCorrectCosts() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
VehicleRoute route = VehicleRoute.emptyRoute();
when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment));
new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupShipment(shipment2));
activities.add(new DeliverShipment(shipment2));
when(activityFactory.createActivities(shipment2)).thenReturn(activities);
insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0, iData.getInsertionCost(), 0.05);
assertEquals(1, iData.getPickupInsertionIndex());
assertEquals(2, iData.getDeliveryInsertionIndex());
}
private List<AbstractActivity> getTourActivities(Shipment shipment) {
List<AbstractActivity> acts = new ArrayList<AbstractActivity>();
PickupShipment pick = new PickupShipment(shipment);
DeliverShipment del = new DeliverShipment(shipment);
acts.add(pick);
acts.add(del);
return acts;
}
@Test
public void whenInsertingShipmentInRouteWithNotEnoughCapacity_itShouldReturnNoInsertion() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
VehicleRoute route = VehicleRoute.emptyRoute();
when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment));
new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(new HardRouteConstraint() {
@Override
public boolean fulfilled(JobInsertionContext insertionContext) {
return false;
}
});
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupShipment(shipment2));
activities.add(new DeliverShipment(shipment2));
when(activityFactory.createActivities(shipment2)).thenReturn(activities);
insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertTrue(iData instanceof InsertionData.NoInsertionFound);
}
@Test
public void whenInsertingThirdShipment_itShouldCalcCorrectVal() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,10")).build();
VehicleRoute route = VehicleRoute.emptyRoute();
when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment));
when(vehicleRoutingProblem.copyAndGetActivities(shipment2)).thenReturn(getTourActivities(shipment2));
Inserter inserter = new Inserter(new InsertionListeners(), vehicleRoutingProblem);
inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route);
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupShipment(shipment3));
activities.add(new DeliverShipment(shipment3));
when(activityFactory.createActivities(shipment3)).thenReturn(activities);
insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0, iData.getInsertionCost(), 0.05);
assertEquals(0, iData.getPickupInsertionIndex());
assertEquals(1, iData.getDeliveryInsertionIndex());
}
@Test
public void whenInsertingThirdShipment_itShouldCalcCorrectVal2() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build();
when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment));
when(vehicleRoutingProblem.copyAndGetActivities(shipment2)).thenReturn(getTourActivities(shipment2));
VehicleRoute route = VehicleRoute.emptyRoute();
Inserter inserter = new Inserter(new InsertionListeners(), vehicleRoutingProblem);
inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route);
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupShipment(shipment3));
activities.add(new DeliverShipment(shipment3));
when(activityFactory.createActivities(shipment3)).thenReturn(activities);
insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(2.0, iData.getInsertionCost(), 0.05);
assertEquals(0, iData.getPickupInsertionIndex());
assertEquals(1, iData.getDeliveryInsertionIndex());
}
@Test
public void whenInstertingShipmentWithLoadConstraintWhereCapIsNotSufficient_capConstraintsAreFulfilled() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build();
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
VehicleRoutingProblem vrp = vrpBuilder.addJob(shipment).addJob(shipment2).addJob(shipment3).build();
VehicleRoute route = VehicleRoute.emptyRoute();
route.setVehicleAndDepartureTime(vehicle, 0.0);
Inserter inserter = new Inserter(new InsertionListeners(), vrp);
inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route);
StateManager stateManager = new StateManager(vrp);
stateManager.updateLoadStates();
stateManager.informInsertionStarts(Arrays.asList(route), null);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
constraintManager.addConstraint(new PickupAndDeliverShipmentLoadActivityLevelConstraint(stateManager), ConstraintManager.Priority.CRITICAL);
constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(), ConstraintManager.Priority.CRITICAL);
ShipmentInsertionCalculatorFlex insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts,
activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory());
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE);
assertTrue(iData instanceof InsertionData.NoInsertionFound);
}
@Ignore
@Test
public void whenInsertingShipmentWithLoadConstraintWhereCapIsNotSufficient_capConstraintsAreFulfilledV2() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build();
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
VehicleRoutingProblem vrp = vrpBuilder.addJob(shipment).addJob(shipment2).addJob(shipment3).build();
VehicleRoute route = VehicleRoute.emptyRoute();
route.setVehicleAndDepartureTime(vehicle, 0.0);
Inserter inserter = new Inserter(new InsertionListeners(), vrp);
inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route);
StateManager stateManager = new StateManager(vrp);
stateManager.updateLoadStates();
stateManager.informInsertionStarts(Arrays.asList(route), null);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
constraintManager.addConstraint(new PickupAndDeliverShipmentLoadActivityLevelConstraint(stateManager), ConstraintManager.Priority.CRITICAL);
// constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(), ConstraintManager.Priority.CRITICAL);
ShipmentInsertionCalculatorFlex insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts,
activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setEvalIndexPickup(0);
insertionCalculator.setEvalIndexDelivery(3);
insertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory());
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE);
assertTrue(iData instanceof InsertionData.NoInsertionFound);
}
@Test
public void whenInsertingServiceWhileNoCapIsAvailable_itMustReturnNoInsertionData() {
Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build();
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
VehicleRoutingProblem vrp = vrpBuilder.addJob(shipment).addJob(shipment2).build();
VehicleRoute route = VehicleRoute.emptyRoute();
route.setVehicleAndDepartureTime(vehicle, 0.0);
Inserter inserter = new Inserter(new InsertionListeners(), vrp);
inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route);
StateManager stateManager = new StateManager(vrp);
stateManager.updateLoadStates();
stateManager.informInsertionStarts(Arrays.asList(route), null);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
constraintManager.addLoadConstraint();
stateManager.informInsertionStarts(Arrays.asList(route), null);
Pickup service = (Pickup) Pickup.Builder.newInstance("pick").addSizeDimension(0, 1).setLocation(Location.newInstance("5,5")).build();
JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupService(service));
when(activityFactory.createActivities(service)).thenReturn(activities);
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
ShipmentInsertionCalculatorFlex insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
insertionCalculator.setJobActivityFactory(activityFactory);
switcher.put(Pickup.class, serviceInsertionCalc);
switcher.put(Service.class, serviceInsertionCalc);
switcher.put(Shipment.class, insertionCalculator);
InsertionData iData = switcher.getInsertionData(route, service, vehicle, 0, DriverImpl.noDriver(), Double.MAX_VALUE);
// routeActVisitor.visit(route);
assertEquals(3, iData.getDeliveryInsertionIndex());
}
}

View file

@ -94,21 +94,24 @@ public class ShipmentInsertionCalculatorTest {
Vehicle vehicle; Vehicle vehicle;
ConstraintManager constraintManager;
@Before @Before
public void doBefore() { public void doBefore() {
routingCosts = CostFactory.createManhattanCosts(); routingCosts = CostFactory.createManhattanCosts();
VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build(); VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build();
vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build(); vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build();
activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, mock(StateManager.class)); activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, mock(StateManager.class));
createInsertionCalculator(hardRouteLevelConstraint); constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(hardRouteLevelConstraint);
vehicleRoutingProblem = mock(VehicleRoutingProblem.class); vehicleRoutingProblem = mock(VehicleRoutingProblem.class);
} }
private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) { // private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) {
ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class)); // ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(hardRouteLevelConstraint); // constraintManager.addConstraint(hardRouteLevelConstraint);
insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager); // insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, );
} // }
@Test @Test
public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue() { public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue() {
@ -119,7 +122,7 @@ public class ShipmentInsertionCalculatorTest {
activities.add(new PickupShipment(shipment)); activities.add(new PickupShipment(shipment));
activities.add(new DeliverShipment(shipment)); activities.add(new DeliverShipment(shipment));
when(activityFactory.createActivities(shipment)).thenReturn(activities); when(activityFactory.createActivities(shipment)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory); insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(40.0, iData.getInsertionCost(), 0.05); assertEquals(40.0, iData.getInsertionCost(), 0.05);
} }
@ -137,7 +140,7 @@ public class ShipmentInsertionCalculatorTest {
activities.add(new PickupShipment(shipment2)); activities.add(new PickupShipment(shipment2));
activities.add(new DeliverShipment(shipment2)); activities.add(new DeliverShipment(shipment2));
when(activityFactory.createActivities(shipment2)).thenReturn(activities); when(activityFactory.createActivities(shipment2)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory); insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0, iData.getInsertionCost(), 0.05); assertEquals(0.0, iData.getInsertionCost(), 0.05);
@ -161,7 +164,9 @@ public class ShipmentInsertionCalculatorTest {
VehicleRoute route = VehicleRoute.emptyRoute(); VehicleRoute route = VehicleRoute.emptyRoute();
when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment));
new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route);
createInsertionCalculator(new HardRouteConstraint() {
constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class));
constraintManager.addConstraint(new HardRouteConstraint() {
@Override @Override
public boolean fulfilled(JobInsertionContext insertionContext) { public boolean fulfilled(JobInsertionContext insertionContext) {
@ -175,7 +180,7 @@ public class ShipmentInsertionCalculatorTest {
activities.add(new PickupShipment(shipment2)); activities.add(new PickupShipment(shipment2));
activities.add(new DeliverShipment(shipment2)); activities.add(new DeliverShipment(shipment2));
when(activityFactory.createActivities(shipment2)).thenReturn(activities); when(activityFactory.createActivities(shipment2)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory); insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertTrue(iData instanceof InsertionData.NoInsertionFound); assertTrue(iData instanceof InsertionData.NoInsertionFound);
@ -201,7 +206,7 @@ public class ShipmentInsertionCalculatorTest {
activities.add(new PickupShipment(shipment3)); activities.add(new PickupShipment(shipment3));
activities.add(new DeliverShipment(shipment3)); activities.add(new DeliverShipment(shipment3));
when(activityFactory.createActivities(shipment3)).thenReturn(activities); when(activityFactory.createActivities(shipment3)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory); insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0, iData.getInsertionCost(), 0.05); assertEquals(0.0, iData.getInsertionCost(), 0.05);
@ -226,7 +231,7 @@ public class ShipmentInsertionCalculatorTest {
activities.add(new PickupShipment(shipment3)); activities.add(new PickupShipment(shipment3));
activities.add(new DeliverShipment(shipment3)); activities.add(new DeliverShipment(shipment3));
when(activityFactory.createActivities(shipment3)).thenReturn(activities); when(activityFactory.createActivities(shipment3)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory); insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
@ -260,8 +265,7 @@ public class ShipmentInsertionCalculatorTest {
constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(), ConstraintManager.Priority.CRITICAL); constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(), ConstraintManager.Priority.CRITICAL);
ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts,
activityInsertionCostsCalculator, constraintManager); activityInsertionCostsCalculator, constraintManager, vrp.getJobActivityFactory());
insertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory());
InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE); InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE);
assertTrue(iData instanceof InsertionData.NoInsertionFound); assertTrue(iData instanceof InsertionData.NoInsertionFound);
@ -293,22 +297,20 @@ public class ShipmentInsertionCalculatorTest {
stateManager.informInsertionStarts(Arrays.asList(route), null); stateManager.informInsertionStarts(Arrays.asList(route), null);
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
switcher.put(Pickup.class, serviceInsertionCalc);
switcher.put(Service.class, serviceInsertionCalc);
switcher.put(Shipment.class, insertionCalculator);
// Service service = Service.Builder.newInstance("pick", 1).setLocationId("5,5").build();
Pickup service = (Pickup) Pickup.Builder.newInstance("pick").addSizeDimension(0, 1).setLocation(Location.newInstance("5,5")).build(); Pickup service = (Pickup) Pickup.Builder.newInstance("pick").addSizeDimension(0, 1).setLocation(Location.newInstance("5,5")).build();
JobActivityFactory activityFactory = mock(JobActivityFactory.class); JobActivityFactory activityFactory = mock(JobActivityFactory.class);
List<AbstractActivity> activities = new ArrayList<AbstractActivity>(); List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
activities.add(new PickupService(service)); activities.add(new PickupService(service));
when(activityFactory.createActivities(service)).thenReturn(activities); when(activityFactory.createActivities(service)).thenReturn(activities);
insertionCalculator.setJobActivityFactory(activityFactory);
serviceInsertionCalc.setJobActivityFactory(activityFactory); JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
switcher.put(Pickup.class, serviceInsertionCalc);
switcher.put(Service.class, serviceInsertionCalc);
switcher.put(Shipment.class, insertionCalculator);
InsertionData iData = switcher.getInsertionData(route, service, vehicle, 0, DriverImpl.noDriver(), Double.MAX_VALUE); InsertionData iData = switcher.getInsertionData(route, service, vehicle, 0, DriverImpl.noDriver(), Double.MAX_VALUE);
// routeActVisitor.visit(route); // routeActVisitor.visit(route);

View file

@ -136,13 +136,13 @@ public class TestCalculatesServiceInsertion {
VehicleRoutingActivityCosts actCosts = mock(VehicleRoutingActivityCosts.class); VehicleRoutingActivityCosts actCosts = mock(VehicleRoutingActivityCosts.class);
serviceInsertion = new ServiceInsertionCalculator(costs, vrp.getActivityCosts(), new LocalActivityInsertionCostsCalculator(costs, actCosts, states), cManager); serviceInsertion = new ServiceInsertionCalculator(costs, vrp.getActivityCosts(), new LocalActivityInsertionCostsCalculator(costs, actCosts, states), cManager, new JobActivityFactory() {
serviceInsertion.setJobActivityFactory(new JobActivityFactory() {
@Override @Override
public List<AbstractActivity> createActivities(Job job) { public List<AbstractActivity> createActivities(Job job) {
return vrp.copyAndGetActivities(job); return vrp.copyAndGetActivities(job);
} }
}); });
} }
@Test @Test

View file

@ -316,6 +316,17 @@ public class VehicleRoutingProblemTest {
builder.addVehicle(vehicle2); builder.addVehicle(vehicle2);
} }
@Test(expected = IllegalArgumentException.class)
public void whenAddingVehicleTypesWithSameIdButDifferentCosts_itShouldThrowException() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleType type1 = VehicleTypeImpl.Builder.newInstance("type").build();
VehicleType type2 = VehicleTypeImpl.Builder.newInstance("type").setCostPerServiceTime(2d).build();
VehicleImpl vehicle1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance("loc")).setType(type1).build();
VehicleImpl vehicle2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance("loc")).setType(type2).build();
builder.addVehicle(vehicle1);
builder.addVehicle(vehicle2);
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void whenBuildingProblemWithSameBreakId_itShouldThrowException(){ public void whenBuildingProblemWithSameBreakId_itShouldThrowException(){
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();

View file

@ -124,6 +124,7 @@ public class VehicleTypeImplTest {
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(-10).build(); VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(-10).build();
} }
@Test
public void whenSettingPerDistanceCosts_itShouldBeSetCorrectly() { public void whenSettingPerDistanceCosts_itShouldBeSetCorrectly() {
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(10).build(); VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(10).build();
assertEquals(10.0, type.getVehicleCostParams().perDistanceUnit, 0.0); assertEquals(10.0, type.getVehicleCostParams().perDistanceUnit, 0.0);
@ -166,4 +167,32 @@ public class VehicleTypeImplTest {
assertEquals(42, two.getUserData()); assertEquals(42, two.getUserData());
assertNull(three.getUserData()); assertNull(three.getUserData());
} }
@Test
public void typesShouldBeEqual() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").setFixedCost(100).build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").setFixedCost(100).build();
assertTrue(one.equals(two));
}
@Test
public void typesShouldBeNotEqual() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").setFixedCost(100).build();
assertFalse(one.equals(two));
}
@Test
public void typesShouldBeNotEqual2() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 10).build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 20).build();
assertFalse(one.equals(two));
}
@Test
public void typesShouldBeEqual2() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 10).build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 10).build();
assertTrue(one.equals(two));
}
} }