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:
commit
b68879303e
28 changed files with 1404 additions and 169 deletions
|
|
@ -51,8 +51,8 @@ script:
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
- github@graphhopper.com
|
- $EMAIL
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.m2
|
- $HOME/.m2
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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())));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue