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

Merge branch 'master' into max-time-feature

# Conflicts:
#	jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java
#	jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java
This commit is contained in:
oblonski 2017-07-05 10:40:18 +02:00
commit b5998e1d93
No known key found for this signature in database
GPG key ID: 179DE487285680D1
100 changed files with 4103 additions and 2386 deletions

View file

@ -21,7 +21,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jsprit-core</artifactId>

View file

@ -17,6 +17,14 @@
*/
package com.graphhopper.jsprit.core.algorithm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy.DiscoveredSolution;
import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyListener;
import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyModuleListener;
@ -30,11 +38,6 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.util.Solutions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
/**
@ -57,9 +60,8 @@ public class VehicleRoutingAlgorithm {
@Override
public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) {
for (PrematureAlgorithmTermination termination : terminationCriteria) {
if (termination.isPrematureBreak(discoveredSolution)) {
if (termination.isPrematureBreak(discoveredSolution))
return true;
}
}
return false;
}
@ -140,30 +142,36 @@ public class VehicleRoutingAlgorithm {
* @param solution the solution to be added
*/
public void addInitialSolution(VehicleRoutingProblemSolution solution) {
// We will make changes so let's make a copy
solution = VehicleRoutingProblemSolution.copyOf(solution);
verify(solution);
initialSolutions.add(solution);
}
private void verify(VehicleRoutingProblemSolution solution) {
int nuJobs = 0;
Set<Job> allJobs = new HashSet<Job>(problem.getJobs().values());
allJobs.removeAll(solution.getUnassignedJobs());
for (VehicleRoute route : solution.getRoutes()) {
nuJobs += route.getTourActivities().getJobs().size();
allJobs.removeAll(route.getTourActivities().getJobs());
if (route.getVehicle().getIndex() == 0)
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
for (TourActivity act : route.getActivities()) {
if (act.getIndex() == 0) {
if (act.getIndex() == 0)
throw new IllegalStateException("act in initial solution has no index. activities are created and associated to their job in VehicleRoutingProblem\n." +
" thus if you build vehicle-routes use the jobActivityFactory from vehicle routing problem like that \n" +
" VehicleRoute.Builder.newInstance(knownVehicle).setJobActivityFactory(vrp.getJobActivityFactory).addService(..)....build() \n" +
" then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem");
}
" thus if you build vehicle-routes use the jobActivityFactory from vehicle routing problem like that \n" +
" VehicleRoute.Builder.newInstance(knownVehicle).setJobActivityFactory(vrp.getJobActivityFactory).addService(..)....build() \n" +
" then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem");
}
}
if (nuJobs != problem.getJobs().values().size()) {
logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" +
"\n this might yield unintended effects, e.g. initial solution cannot be improved anymore.", nuJobs, problem.getJobs().values().size());
}
solution.getUnassignedJobs().addAll(allJobs);
solution.setCost(getObjectiveFunction().getCosts(solution));
// if (nuJobs != problem.getJobs().values().size()) {
// logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" +
// "\n this might yield unintended effects, e.g. initial solution cannot be improved anymore.", nuJobs, problem.getJobs().values().size());
// }
}
/**
@ -214,7 +222,9 @@ public class VehicleRoutingAlgorithm {
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
algorithmStarts(problem, solutions);
bestEver = Solutions.bestOf(solutions);
if (logger.isTraceEnabled()) log(solutions);
if (logger.isTraceEnabled()) {
log(solutions);
}
logger.info("iterations start");
for (int i = 0; i < maxIterations; i++) {
iterationStarts(i + 1, problem, solutions);
@ -222,7 +232,9 @@ public class VehicleRoutingAlgorithm {
counter.incCounter();
SearchStrategy strategy = searchStrategyManager.getRandomStrategy();
DiscoveredSolution discoveredSolution = strategy.run(problem, solutions);
if (logger.isTraceEnabled()) log(discoveredSolution);
if (logger.isTraceEnabled()) {
log(discoveredSolution);
}
memorizeIfBestEver(discoveredSolution);
selectedStrategy(discoveredSolution, problem, solutions);
if (terminationManager.isPrematureBreak(discoveredSolution)) {
@ -240,11 +252,15 @@ public class VehicleRoutingAlgorithm {
}
private void addBestEver(Collection<VehicleRoutingProblemSolution> solutions) {
if (bestEver != null) solutions.add(bestEver);
if (bestEver != null) {
solutions.add(bestEver);
}
}
private void log(Collection<VehicleRoutingProblemSolution> solutions) {
for (VehicleRoutingProblemSolution sol : solutions) log(sol);
for (VehicleRoutingProblemSolution sol : solutions) {
log(sol);
}
}
private void log(VehicleRoutingProblemSolution solution) {
@ -277,9 +293,11 @@ public class VehicleRoutingAlgorithm {
private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) {
if (discoveredSolution == null) return;
if (bestEver == null) bestEver = discoveredSolution.getSolution();
else if (discoveredSolution.getSolution().getCost() < bestEver.getCost())
if (bestEver == null) {
bestEver = discoveredSolution.getSolution();
} else if (discoveredSolution.getSolution().getCost() < bestEver.getCost()) {
bestEver = discoveredSolution.getSolution();
}
}
@ -297,10 +315,12 @@ public class VehicleRoutingAlgorithm {
public void addListener(VehicleRoutingAlgorithmListener l) {
algoListeners.addListener(l);
if (l instanceof SearchStrategyListener)
if (l instanceof SearchStrategyListener) {
searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l);
if (l instanceof SearchStrategyModuleListener)
}
if (l instanceof SearchStrategyModuleListener) {
searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l);
}
}
private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {

View file

@ -25,7 +25,9 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@ -78,7 +80,6 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
private final int solutionMemory;
public SchrimpfAcceptance(int solutionMemory, double alpha) {
this.alpha = alpha;
this.solutionMemory = solutionMemory;
@ -110,6 +111,32 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
return solutionAccepted;
}
public boolean acceptSolution(VehicleRoutingProblemSolution solution, VehicleRoutingProblemSolution newSolution) {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<>();
solutions.add(solution);
boolean solutionAccepted = false;
if (solutions.size() < solutionMemory) {
solutions.add(newSolution);
solutionAccepted = true;
} else {
VehicleRoutingProblemSolution worst = null;
double threshold = getThreshold(currentIteration);
for (VehicleRoutingProblemSolution solutionInMemory : solutions) {
if (worst == null) worst = solutionInMemory;
else if (solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
}
if (worst == null) {
solutions.add(newSolution);
solutionAccepted = true;
} else if (newSolution.getCost() < worst.getCost() + threshold) {
solutions.remove(worst);
solutions.add(newSolution);
solutionAccepted = true;
}
}
return solutionAccepted;
}
@Override
public String toString() {
return "[name=SchrimpfAcceptance][alpha=" + alpha + "]";
@ -136,6 +163,16 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
this.initialThreshold = initialThreshold;
}
public void setMaxIterations(int maxIteration) {
this.maxIterations = maxIteration;
}
public void incIteration() {
currentIteration++;
}
;
@Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
reset();

View file

@ -46,9 +46,7 @@ import com.graphhopper.jsprit.core.util.NoiseMaker;
import com.graphhopper.jsprit.core.util.RandomNumberGeneration;
import com.graphhopper.jsprit.core.util.Solutions;
import java.util.Collection;
import java.util.Properties;
import java.util.Random;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -82,7 +80,9 @@ public class Jsprit {
WORST_BEST("worst_best"),
WORST_REGRET("worst_regret"),
CLUSTER_BEST("cluster_best"),
CLUSTER_REGRET("cluster_regret");
CLUSTER_REGRET("cluster_regret"),
STRING_BEST("string_best"),
STRING_REGRET("string_regret");
String strategyName;
@ -112,6 +112,7 @@ public class Jsprit {
WORST_MAX_SHARE("worst.max_share"),
THRESHOLD_ALPHA("threshold.alpha"),
THRESHOLD_INI("threshold.ini"),
THRESHOLD_INI_ABS("threshold.ini_abs"),
INSERTION_NOISE_LEVEL("insertion.noise_level"),
INSERTION_NOISE_PROB("insertion.noise_prob"),
RUIN_WORST_NOISE_LEVEL("worst.noise_level"),
@ -119,7 +120,12 @@ public class Jsprit {
FAST_REGRET("regret.fast"),
MAX_TRANSPORT_COSTS("max_transport_costs"),
CONSTRUCTION("construction"),
BREAK_SCHEDULING("break_scheduling");
BREAK_SCHEDULING("break_scheduling"),
STRING_K_MIN("string_kmin"),
STRING_K_MAX("string_kmax"),
STRING_L_MIN("string_lmin"),
STRING_L_MAX("string_lmax");
String paraName;
@ -161,6 +167,12 @@ public class Jsprit {
private SolutionAcceptor solutionAcceptor;
private ScoringFunction regretScorer = null;
private Map<SearchStrategy, Double> customStrategies = new HashMap<>();
private VehicleFleetManager fleetManager = null;
public static Builder newInstance(VehicleRoutingProblem vrp) {
return new Builder(vrp);
}
@ -176,10 +188,21 @@ public class Jsprit {
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");
defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");
defaults.put(Strategy.STRING_BEST.toString(), "0.0");
defaults.put(Strategy.STRING_REGRET.toString(), "0.0");
defaults.put(Parameter.STRING_K_MIN.toString(), "1");
defaults.put(Parameter.STRING_K_MAX.toString(), "6");
defaults.put(Parameter.STRING_L_MIN.toString(), "10");
defaults.put(Parameter.STRING_L_MAX.toString(), "30");
defaults.put(Strategy.WORST_BEST.toString(), "0.");
defaults.put(Strategy.WORST_REGRET.toString(), "1.");
defaults.put(Strategy.CLUSTER_BEST.toString(), "0.");
defaults.put(Strategy.CLUSTER_REGRET.toString(), "1.");
defaults.put(Parameter.FIXED_COST_PARAM.toString(), "0.");
defaults.put(Parameter.VEHICLE_SWITCH.toString(), "true");
defaults.put(Parameter.ITERATIONS.toString(), "2000");
@ -214,6 +237,16 @@ public class Jsprit {
}
public Builder addSearchStrategy(SearchStrategy searchStrategy, double weight) {
customStrategies.put(searchStrategy, weight);
return this;
}
public Builder setVehicleFleetManager(VehicleFleetManager fleetManager) {
this.fleetManager = fleetManager;
return this;
}
public Builder setExecutorService(ExecutorService es, int noThreads) {
this.es = es;
this.noThreads = noThreads;
@ -266,6 +299,11 @@ public class Jsprit {
return this;
}
public Builder setRegretScorer(ScoringFunction scoringFunction) {
this.regretScorer = scoringFunction;
return this;
}
public VehicleRoutingAlgorithm buildAlgorithm() {
return new Jsprit(this).create(vrp);
}
@ -328,6 +366,12 @@ public class Jsprit {
private SolutionAcceptor acceptor;
private ScoringFunction regretScorer;
private final Map<SearchStrategy, Double> customStrategies = new HashMap<>();
private VehicleFleetManager vehicleFleetManager;
private Jsprit(Builder builder) {
this.stateManager = builder.stateManager;
this.constraintManager = builder.constraintManager;
@ -339,16 +383,25 @@ public class Jsprit {
this.random = builder.random;
this.activityInsertion = builder.activityInsertionCalculator;
this.acceptor = builder.solutionAcceptor;
regretScorer = builder.regretScorer;
customStrategies.putAll(builder.customStrategies);
vehicleFleetManager = builder.fleetManager;
}
private void ini(VehicleRoutingProblem vrp) {
if (regretScorer == null) regretScorer = getRegretScorer(vrp);
}
private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
VehicleFleetManager fm;
if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) {
fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} else {
FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles());
finiteFleetManagerFactory.setRandom(random);
fm = finiteFleetManagerFactory.createFleetManager();
ini(vrp);
if (vehicleFleetManager == null) {
if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) {
vehicleFleetManager = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} else {
FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles());
finiteFleetManagerFactory.setRandom(random);
vehicleFleetManager = finiteFleetManagerFactory.createFleetManager();
}
}
if (stateManager == null) {
@ -368,6 +421,14 @@ public class Jsprit {
}
}
double fixedCostParam = toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()));
IncreasingAbsoluteFixedCosts increasingAbsoluteFixedCosts = null;
if (fixedCostParam > 0d) {
increasingAbsoluteFixedCosts = new IncreasingAbsoluteFixedCosts(vrp.getJobs().size());
increasingAbsoluteFixedCosts.setWeightOfFixCost(fixedCostParam);
constraintManager.addConstraint(increasingAbsoluteFixedCosts);
}
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString()));
@ -449,13 +510,23 @@ public class Jsprit {
random)
);
int kMin = toInteger(properties.getProperty(Parameter.STRING_K_MIN.toString()));
int kMax = toInteger(properties.getProperty(Parameter.STRING_K_MAX.toString()));
int lMin = toInteger(properties.getProperty(Parameter.STRING_L_MIN.toString()));
int lMax = toInteger(properties.getProperty(Parameter.STRING_L_MAX.toString()));
final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods);
stringRuin.setNoRoutes(kMin, kMax);
stringRuin.setStringLength(lMin, lMax);
stringRuin.setRandom(random);
AbstractInsertionStrategy regret;
final DefaultScorer scorer;
final ScoringFunction scorer;
boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
if (es != null) {
if(fastRegret){
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads)
.setFastRegret(true)
@ -463,45 +534,45 @@ public class Jsprit {
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion;
}
else {
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
} else {
if(fastRegret) {
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setFastRegret(true)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion;
}
else{
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
@ -510,7 +581,7 @@ public class Jsprit {
AbstractInsertionStrategy best;
if (vrp.getJobs().size() < 250 || es == null) {
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
@ -518,7 +589,7 @@ public class Jsprit {
.build();
best = bestInsertion;
} else {
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
@ -532,15 +603,19 @@ public class Jsprit {
IterationStartsListener schrimpfThreshold = null;
if(acceptor == null) {
final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString())));
schrimpfThreshold = new IterationStartsListener() {
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (i == 1) {
double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString()));
schrimpfAcceptance.setInitialThreshold(initialThreshold);
if (properties.containsKey(Parameter.THRESHOLD_INI_ABS.toString())) {
schrimpfAcceptance.setInitialThreshold(Double.valueOf(properties.getProperty(Parameter.THRESHOLD_INI_ABS.toString())));
} else {
schrimpfThreshold = new IterationStartsListener() {
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (i == 1) {
double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString()));
schrimpfAcceptance.setInitialThreshold(initialThreshold);
}
}
}
};
};
}
acceptor = schrimpfAcceptance;
}
@ -569,8 +644,13 @@ public class Jsprit {
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));
SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
stringRegret.addModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager);
SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager);
prettyBuilder.setRandom(random);
if (addCoreConstraints) {
prettyBuilder.addCoreStateAndConstraintStuff();
@ -582,7 +662,14 @@ public class Jsprit {
.withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString())))
.withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString())))
.withStrategy(clusters_regret, toDouble(getProperty(Strategy.CLUSTER_REGRET.toString())))
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())));
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())))
.withStrategy(stringBest, toDouble(getProperty(Strategy.STRING_BEST.toString())))
.withStrategy(stringRegret, toDouble(getProperty(Strategy.STRING_REGRET.toString())));
for (SearchStrategy customStrategy : customStrategies.keySet()) {
prettyBuilder.withStrategy(customStrategy, customStrategies.get(customStrategy));
}
if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) {
prettyBuilder.constructInitialSolutionWith(best, objectiveFunction);
} else {
@ -598,6 +685,7 @@ public class Jsprit {
vra.addListener(noiseConfigurator);
vra.addListener(noise);
vra.addListener(clusters);
if (increasingAbsoluteFixedCosts != null) vra.addListener(increasingAbsoluteFixedCosts);
if(toBoolean(getProperty(Parameter.BREAK_SCHEDULING.toString()))) {
vra.addListener(new BreakScheduling(vrp, stateManager, constraintManager));
@ -619,25 +707,36 @@ public class Jsprit {
private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) {
if (setupExecutorInternally) {
final Thread hook = new Thread() {
public void run() {
if (!es.isShutdown()) {
System.err.println("shutdownHook shuts down executorService");
es.shutdown();
}
}
};
Runtime.getRuntime().addShutdownHook(hook);
vra.addListener(new AlgorithmEndsListener() {
@Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
es.shutdown();
Runtime.getRuntime().removeShutdownHook(hook);
}
});
}
if (es != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
if (!es.isShutdown()) {
System.err.println("shutdowHook shuts down executorService");
es.shutdown();
}
}
});
}
// if (es != null) {
//
// Runtime.getRuntime().addShutdownHook(hook);
// vra.addListener(new AlgorithmEndsListener() {
// @Override
// public void informAlgorithmEnds(VehicleRoutingProblem aProblem,
// Collection<VehicleRoutingProblemSolution> aSolutions) {
// Runtime.getRuntime().removeShutdownHook(hook);
// }
// });
// }
}
String getProperty(String key) {
@ -685,7 +784,7 @@ public class Jsprit {
}
}
for(Job j : solution.getUnassignedJobs()){
costs += maxCosts * 2 * (4 - j.getPriority());
costs += maxCosts * 2 * (11 - j.getPriority());
}
return costs;
}

View file

@ -0,0 +1,95 @@
/*
* 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.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by schroeder on 06/02/17.
*/
abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
InsertionData checkRouteContraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) {
if (!hardRouteConstraint.fulfilled(insertionContext)) {
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.addFailedConstrainName(hardRouteConstraint.getClass().getSimpleName());
return emptyInsertionData;
}
}
return null;
}
ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection<String> failedActivityConstraints, ConstraintManager constraintManager) {
ConstraintsStatus notFulfilled = null;
List<String> failed = new ArrayList<>();
for (HardActivityConstraint c : constraintManager.getCriticalHardActivityConstraints()) {
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
failedActivityConstraints.add(c.getClass().getSimpleName());
return status;
} else {
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failed.add(c.getClass().getSimpleName());
notFulfilled = status;
}
}
}
if (notFulfilled != null) {
failedActivityConstraints.addAll(failed);
return notFulfilled;
}
for (HardActivityConstraint c : constraintManager.getHighPrioHardActivityConstraints()) {
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
failedActivityConstraints.add(c.getClass().getSimpleName());
return status;
} else {
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failed.add(c.getClass().getSimpleName());
notFulfilled = status;
}
}
}
if (notFulfilled != null) {
failedActivityConstraints.addAll(failed);
return notFulfilled;
}
for (HardActivityConstraint constraint : constraintManager.getLowPrioHardActivityConstraints()) {
ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failedActivityConstraints.add(constraint.getClass().getSimpleName());
return status;
}
}
return ConstraintsStatus.FULFILLED;
}
}

View file

@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
return badJobs;
}
public void markUnassigned(Job unassigned, List<String> reasons) {
insertionsListeners.informJobUnassignedListeners(unassigned, reasons);
}
public abstract Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
@Override

View file

@ -0,0 +1,35 @@
/*
* 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.job.Job;
import java.util.Comparator;
/**
* Created by schroeder on 30/06/17.
*/
class AccordingToPriorities implements Comparator<Job> {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
}

View file

@ -24,7 +24,10 @@ import com.graphhopper.jsprit.core.util.NoiseMaker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@ -63,13 +66,15 @@ public final class BestInsertion extends AbstractInsertionStrategy {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
Collections.sort(unassignedJobList, new AccordingToPriorities());
for (Job unassignedJob : unassignedJobList) {
Insertion bestInsertion = null;
InsertionData empty = new InsertionData.NoInsertionFound();
double bestInsertionCost = Double.MAX_VALUE;
for (VehicleRoute vehicleRoute : vehicleRoutes) {
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if (iData instanceof InsertionData.NoInsertionFound) {
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
@ -84,23 +89,16 @@ public final class BestInsertion extends AbstractInsertionStrategy {
bestInsertion = new Insertion(newRoute, newIData);
vehicleRoutes.add(newRoute);
}
} else {
empty.getFailedConstraintNames().addAll(newIData.getFailedConstraintNames());
}
if (bestInsertion == null) {
badJobs.add(unassignedJob);
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
}
if (bestInsertion == null) badJobs.add(unassignedJob);
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
// nextInsertion();
}
return badJobs;
}
private void sometimesSortPriorities(List<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
}
}
}

View file

@ -27,7 +27,10 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
@ -99,8 +102,9 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
Collections.sort(unassignedJobList, new AccordingToPriorities());
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
List<String> failedConstraintNames = new ArrayList<>();
for (final Job unassignedJob : unassignedJobList) {
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
@ -118,7 +122,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
for (int i = 0; i < batches.size(); i++) {
Future<Insertion> futureIData = completionService.take();
Insertion insertion = futureIData.get();
if (insertion == null) continue;
if (insertion.insertionData instanceof NoInsertionFound) {
failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames());
continue;
}
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
bestInsertion = insertion;
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
@ -136,29 +143,24 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
vehicleRoutes.add(newRoute);
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
}
if (bestInsertion == null) badJobs.add(unassignedJob);
if (bestInsertion == null) {
badJobs.add(unassignedJob);
markUnassigned(unassignedJob, failedConstraintNames);
}
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
return badJobs;
}
private void sometimesSortPriorities(List<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
}
}
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
Insertion bestInsertion = null;
InsertionData empty = new InsertionData.NoInsertionFound();
double bestInsertionCost = Double.MAX_VALUE;
for (VehicleRoute vehicleRoute : batch.routes) {
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if (iData instanceof NoInsertionFound) {
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestInsertionCost) {
@ -166,6 +168,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
bestInsertionCost = iData.getInsertionCost();
}
}
if (bestInsertion == null) return new Insertion(null, empty);
return bestInsertion;
}

View file

@ -32,7 +32,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Random;
@Deprecated
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator {

View file

@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
@Deprecated
class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInsertionCostsCalculator {

View file

@ -0,0 +1,77 @@
/*
* 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.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
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.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class DecreasingRelativeFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(DecreasingRelativeFixedCosts.class);
private double weightDeltaFixCost = 0.5;
private RouteAndActivityStateGetter stateGetter;
public DecreasingRelativeFixedCosts(RouteAndActivityStateGetter stateGetter, int noJobs) {
super(noJobs);
this.stateGetter = stateGetter;
logger.debug("initialise {}", this);
}
public void setWeightOfFixCost(double weight) {
weightDeltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=DecreasingRelativeFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
}
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
return maxLoad;
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
VehicleRoute route = insertionContext.getRoute();
Capacity currentLoad = getCurrentMaxLoadInRoute(route);
Capacity load = Capacity.addup(currentLoad, insertionContext.getJob().getSize());
double currentRelFix = 0d;
if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
}
double newRelFix = insertionContext.getNewVehicle().getType().getVehicleCostParams().fix * (Capacity.divide(load, insertionContext.getNewVehicle().getType().getCapacityDimensions()));
double decreasingRelativeFixedCosts = (1 - solutionCompletenessRatio) * (newRelFix - currentRelFix);
return weightDeltaFixCost * solutionCompletenessRatio * decreasingRelativeFixedCosts;
}
}

View file

@ -31,14 +31,14 @@ public class DellAmicoFixCostCalculator implements SoftRouteConstraint, Insertio
private int nuOfJobsToRecreate;
private final JobInsertionConsideringFixCostsCalculator calculator;
private final IncreasingAbsoluteFixedCosts calculator;
private final int nuOfJobs;
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
super();
this.nuOfJobs = nuOfJobs;
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
calculator = new IncreasingAbsoluteFixedCosts(nuOfJobs);
}
@Override

View file

@ -0,0 +1,61 @@
/*
* 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.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class IncreasingAbsoluteFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(IncreasingAbsoluteFixedCosts.class);
private double weightDeltaFixCost = 0.5;
public IncreasingAbsoluteFixedCosts(int noJobs) {
super(noJobs);
logger.debug("initialise {}", this);
}
public void setWeightOfFixCost(double weight) {
weightDeltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=IncreasingAbsoluteFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
final VehicleRoute currentRoute = insertionContext.getRoute();
double currentFix = 0d;
if (currentRoute.getVehicle() != null && !(currentRoute.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentFix = currentRoute.getVehicle().getType().getVehicleCostParams().fix;
}
double increasingAbsoluteFixedCosts = solutionCompletenessRatio * (insertionContext.getNewVehicle().getType().getVehicleCostParams().fix - currentFix);
return weightDeltaFixCost * solutionCompletenessRatio * increasingAbsoluteFixedCosts;
}
}

View file

@ -31,6 +31,7 @@ import java.util.List;
*/
public class InsertionData {
public static class NoInsertionFound extends InsertionData {
public NoInsertionFound() {
@ -75,6 +76,8 @@ public class InsertionData {
return events;
}
private List<String> reasons = new ArrayList<>();
/**
* @return the additionalTime
*/
@ -82,6 +85,14 @@ public class InsertionData {
return additionalTime;
}
public void addFailedConstrainName(String name) {
reasons.add(name);
}
public List<String> getFailedConstraintNames() {
return reasons;
}
/**
* @param additionalTime the additionalTime to set
*/

View file

@ -33,7 +33,7 @@ class InsertionDataUpdater {
static boolean update(boolean addAllAvailable, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet<VersionedInsertionData> insertionDataSet, int updateRound, Job unassignedJob, Collection<VehicleRoute> routes) {
for(VehicleRoute route : routes) {
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
Collection<Vehicle> relevantVehicles = new ArrayList<>();
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
relevantVehicles.add(route.getVehicle());
if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){
@ -71,7 +71,7 @@ class InsertionDataUpdater {
};
}
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<Job> badJobs) {
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for(Job j : unassignedJobList){
VehicleRoute bestRoute = null;
@ -79,6 +79,7 @@ class InsertionDataUpdater {
InsertionData secondBest = null;
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
List<String> failedConstraintNames = new ArrayList<>();
while(iterator.hasNext()){
VersionedInsertionData versionedIData = iterator.next();
if(bestRoute != null){
@ -86,7 +87,10 @@ class InsertionDataUpdater {
continue;
}
}
if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue;
if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) {
failedConstraintNames.addAll(versionedIData.getiData().getFailedConstraintNames());
continue;
}
if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
if (!switchAllowed) continue;
@ -136,9 +140,9 @@ class InsertionDataUpdater {
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
if (best == null) {
badJobs.add(j);
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
continue;
}
double score = score(j, best, secondBest, scoringFunction);

View file

@ -1,135 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.job.Job;
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.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(JobInsertionConsideringFixCostsCalculator.class);
private final JobInsertionCostsCalculator standardServiceInsertion;
private double weight_deltaFixCost = 0.5;
private double solution_completeness_ratio = 0.5;
private RouteAndActivityStateGetter stateGetter;
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
super();
this.standardServiceInsertion = standardInsertionCalculator;
this.stateGetter = stateGetter;
logger.debug("inialise {}", this);
}
@Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
double fixcost_contribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle);
if (fixcost_contribution > bestKnownPrice) {
return InsertionData.createEmptyInsertionData();
}
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
if (iData instanceof InsertionData.NoInsertionFound) {
return iData;
}
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.getEvents().addAll(iData.getEvents());
return insertionData;
}
private double getFixCostContribution(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle) {
Capacity currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute);
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost;
double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost;
return fixcost_contribution;
}
public void setWeightOfFixCost(double weight) {
weight_deltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]";
}
public void setSolutionCompletenessRatio(double ratio) {
solution_completeness_ratio = ratio;
}
public double getSolutionCompletenessRatio() { return solution_completeness_ratio; }
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentMaxLoadInRoute) {
Capacity load = Capacity.addup(currentMaxLoadInRoute, job.getSize());
double currentFix = 0.0;
if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentFix += route.getVehicle().getType().getVehicleCostParams().fix;
}
}
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
return Double.MAX_VALUE;
}
return newVehicle.getType().getVehicleCostParams().fix - currentFix;
}
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentLoad) {
Capacity load = Capacity.addup(currentLoad, job.getSize());
double currentRelFix = 0.0;
if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
}
}
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
return Double.MAX_VALUE;
}
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
return relativeFixCost;
}
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
return maxLoad;
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle());
}
}

View file

@ -218,10 +218,10 @@ public class JobInsertionCostsCalculatorBuilder {
addAlgorithmListeners(standardLocal.getAlgorithmListener());
addInsertionListeners(standardLocal.getInsertionListener());
if (considerFixedCost) {
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
baseCalculator = withFixed.getCalculator();
addAlgorithmListeners(withFixed.getAlgorithmListener());
addInsertionListeners(withFixed.getInsertionListener());
// CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
// baseCalculator = withFixed.getCalculator();
// addAlgorithmListeners(withFixed.getAlgorithmListener());
// addInsertionListeners(withFixed.getInsertionListener());
}
if (timeScheduling) {
// baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors);
@ -309,14 +309,6 @@ public class JobInsertionCostsCalculatorBuilder {
return calculatorPlusListeners;
}
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) {
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
return calcPlusListeners;
}
private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory) {
ActivityInsertionCostsCalculator routeLevelCostEstimator;
if (activityInsertionCostCalculator == null && addDefaultCostCalc) {

View file

@ -22,6 +22,7 @@ import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
@ -77,7 +78,9 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double oldCosts = 0.;
if (iFacts.getRoute().isEmpty()) {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
double tp_costs_prevAct_nextAct = 0.;
if (newAct instanceof DeliverShipment)
tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
oldCosts += tp_costs_prevAct_nextAct;
} else {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());

View file

@ -105,10 +105,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
List<Job> jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
@ -117,9 +117,11 @@ public class RegretInsertion extends AbstractInsertionStrategy {
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
}
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -132,12 +134,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
return null;
}
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for (Job unassignedJob : unassignedJobList) {
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
if (scoredJob instanceof ScoredJob.BadJob) {
badJobs.add(unassignedJob);
badJobs.add(scoredJob);
continue;
}
if (bestScoredJob == null) bestScoredJob = scoredJob;
@ -158,14 +160,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
InsertionData best = null;
InsertionData secondBest = null;
VehicleRoute bestRoute = null;
List<String> failedConstraintNames = new ArrayList<>();
double benchmark = Double.MAX_VALUE;
for (VehicleRoute route : routes) {
if (secondBest != null) {
benchmark = secondBest.getInsertionCost();
}
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
if (iData instanceof InsertionData.NoInsertionFound) continue;
if (iData instanceof InsertionData.NoInsertionFound) {
failedConstraintNames.addAll(iData.getFailedConstraintNames());
continue;
}
if (best == null) {
best = iData;
bestRoute = route;
@ -191,9 +196,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
if (best == null) {
return new ScoredJob.BadJob(unassignedJob);
ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames);
return badJob;
}
double score = score(unassignedJob, best, secondBest, scoringFunction);
ScoredJob scoredJob;

View file

@ -109,10 +109,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
List<Job> jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
@ -121,15 +121,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
}
for (Job j : badJobList) {
jobs.remove(j);
badJobs.add(j);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
}
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<ScoredJob> badJobList) {
ScoredJob bestScoredJob = null;
for (final Job unassignedJob : unassignedJobList) {
@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
Future<ScoredJob> fsj = completionService.take();
ScoredJob sJob = fsj.get();
if (sJob instanceof ScoredJob.BadJob) {
badJobList.add(sJob.getJob());
badJobList.add(sJob);
continue;
}
if (bestScoredJob == null) {

View file

@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
if(firstRun) firstRun = false;
@ -159,9 +159,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -172,7 +174,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
boolean updatedAllRoutes = false;
for (final Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
updatedAllRoutes = true;

View file

@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
VehicleRoute lastModified = null;
boolean firstRun = true;
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
Map<VehicleRoute, Integer> updates = new HashMap<>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
if(firstRun){
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
@ -156,9 +156,11 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -167,7 +169,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
for (Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);

View file

@ -31,7 +31,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity
import java.util.ArrayList;
import java.util.List;
@Deprecated
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator {
private VehicleRoutingActivityCosts activityCosts;

View file

@ -21,6 +21,8 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import java.util.List;
/**
* Created by schroeder on 15/10/15.
*/
@ -28,8 +30,14 @@ class ScoredJob {
static class BadJob extends ScoredJob {
BadJob(Job job) {
super(job, 0., null, null, false);
BadJob(Job job, List<String> failedConstraintNames) {
super(job, 0., getEmptyInsertion(failedConstraintNames), null, false);
}
private static InsertionData getEmptyInsertion(List<String> failedConstraintNames) {
InsertionData empty = new InsertionData.NoInsertionFound();
empty.getFailedConstraintNames().addAll(failedConstraintNames);
return empty;
}
}

View file

@ -33,9 +33,9 @@ class Scorer {
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
//if only one vehicle, I want the job to be inserted with min iCosts
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
score = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
score = (11 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
} else {
score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
score = (11 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
}
return score;
}

View file

@ -25,6 +25,6 @@ import com.graphhopper.jsprit.core.problem.job.Job;
*/
public interface ScoringFunction {
public double score(InsertionData best, Job job);
double score(InsertionData best, Job job);
}

View file

@ -18,8 +18,10 @@
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.*;
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;
@ -36,6 +38,8 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
@ -43,13 +47,13 @@ import java.util.Iterator;
*
* @author schroeder
*/
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint;
// private HardRouteConstraint hardRouteLevelConstraint;
private HardActivityConstraint hardActivityLevelConstraint;
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
@ -65,12 +69,13 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private ConstraintManager constraintManager;
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
super();
this.transportCosts = routingCosts;
this.activityCosts = activityCosts;
hardRouteLevelConstraint = constraintManager;
hardActivityLevelConstraint = constraintManager;
this.constraintManager = constraintManager;
softActivityConstraint = constraintManager;
softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
@ -103,9 +108,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
/*
check hard constraints at route level
*/
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
return InsertionData.createEmptyInsertionData();
}
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
if (noInsertion != null) return noInsertion;
Collection<String> failedActivityConstraints = new ArrayList<>();
/*
check soft constraints at route level
@ -142,7 +148,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext = new ActivityContext();
activityContext.setInsertionIndex(actIndex);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager);
if (status.equals(ConstraintsStatus.FULFILLED)) {
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
@ -163,7 +169,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
actIndex++;
}
if(insertionIndex == InsertionData.NO_INDEX) {
return InsertionData.createEmptyInsertionData();
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
return emptyInsertionData;
}
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
@ -173,4 +181,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
return insertionData;
}
}

View file

@ -45,7 +45,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
@Deprecated
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionOnRouteLevelCalculator.class);

View file

@ -18,8 +18,10 @@
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.*;
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;
@ -36,16 +38,19 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint;
private final ConstraintManager constraintManager;
private HardActivityConstraint hardActivityLevelConstraint;
// private HardRouteConstraint hardRouteLevelConstraint;
//
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
@ -64,8 +69,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
super();
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
this.hardRouteLevelConstraint = constraintManager;
this.hardActivityLevelConstraint = constraintManager;
this.constraintManager = constraintManager;
this.softActivityConstraint = constraintManager;
this.softRouteConstraint = constraintManager;
this.transportCosts = routingCosts;
@ -99,9 +103,8 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
/*
check hard route constraints
*/
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
return InsertionData.createEmptyInsertionData();
}
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
if (noInsertion != null) return noInsertion;
/*
check soft route constraints
*/
@ -132,6 +135,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
//pickupShipmentLoop
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
List<String> failedActivityConstraints = new ArrayList<>();
while (!tourEnd) {
TourActivity nextAct;
if (i < activities.size()) {
@ -148,7 +152,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext = new ActivityContext();
activityContext.setInsertionIndex(i);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
ConstraintsStatus pickupShipmentConstraintStatus = fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime, failedActivityConstraints, constraintManager);
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
pickupInsertionNotFulfilledBreak = false;
continue;
@ -194,7 +198,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext_ = new ActivityContext();
activityContext_.setInsertionIndex(j);
insertionContext.setActivityContext(activityContext_);
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
ConstraintsStatus deliverShipmentConstraintStatus = fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop, failedActivityConstraints, constraintManager);
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
double deliveryAIC = calculate(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
@ -230,7 +234,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
i++;
}
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
return InsertionData.createEmptyInsertionData();
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
return emptyInsertionData;
}
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());

View file

@ -15,50 +15,48 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection;
/**
* Created by schroeder on 11/01/17.
*/
class SolutionCompletenessRatio implements InsertionStartsListener, JobInsertedListener {
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener {
protected double solutionCompletenessRatio = 0.5;
private final VehicleRoutingProblem vrp;
private final JobInsertionConsideringFixCostsCalculator calcConsideringFix;
private final double minRatio = 0.5;
private final int nuOfJobs;
private int nuOfJobsToRecreate;
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
super();
this.vrp = vrp;
this.calcConsideringFix = calcConsideringFix;
public SolutionCompletenessRatio(int nuOfJobs) {
this.nuOfJobs = nuOfJobs;
}
@Override
public String toString() {
return "[name=configureFixCostCalculator]";
public void setSolutionCompletenessRatio(double ratio) {
solutionCompletenessRatio = ratio;
}
public double getSolutionCompletenessRatio() {
return solutionCompletenessRatio;
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio));
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
}
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--;
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio));
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
}
}

View file

@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
}
Vehicle selectedVehicle = currentRoute.getVehicle();
Driver selectedDriver = currentRoute.getDriver();
InsertionData bestIData = InsertionData.createEmptyInsertionData();
InsertionData bestIData = new InsertionData.NoInsertionFound();
double bestKnownCost_ = bestKnownCost;
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
else depTime = v.getEarliestDeparture();
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
if (iData instanceof InsertionData.NoInsertionFound) {
bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestKnownCost_) {

View file

@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class InsertionListeners {
@ -74,6 +75,14 @@ public class InsertionListeners {
}
}
public void informJobUnassignedListeners(Job unassigned, List<String> reasons) {
for (InsertionListener l : listeners) {
if (l instanceof JobUnassignedListener) {
((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons);
}
}
}
public void addListener(InsertionListener insertionListener) {
listeners.add(insertionListener);
}

View file

@ -0,0 +1,32 @@
/*
* 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.listener;
import com.graphhopper.jsprit.core.problem.job.Job;
import java.util.Collection;
/**
* Created by schroeder on 06/02/17.
*/
public interface JobUnassignedListener extends InsertionListener {
void informJobUnassigned(Job unassigned, Collection<String> failedConstraintNames);
}

View file

@ -0,0 +1,218 @@
/*
* 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.ruin;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.util.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* RuinString is adopted from
* <p>
* Technical report 7.11.2016
* A Fresh Ruin & Recreate Implementation for the Capacitated Vehicle Routing Problem
* Jan Christiaens, Greet Vanden Berghe
* KU Leuven, Department of Computer Science, CODeS & iMinds-ITEC
* Gebr. De Smetstraat 1, 9000 Gent, Belgium, jan.christiaens@cs.kuleuven.be, greet.vandenberghe@cs.kuleuven.be
* <p>
* https://lirias.kuleuven.be/bitstream/123456789/556398/1/asb_rr_2016.pdf
*
* @author stefan
*/
public final class RuinString extends AbstractRuinStrategy {
private static Logger logger = LoggerFactory.getLogger(RuinString.class);
private final VehicleRoutingProblem vrp;
private final JobNeighborhoods jobNeighborhoods;
private int kMin = 1;
private int kMax = 6;
private int lMin = 30;
private int lMax = 60;
public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) {
super(vrp);
this.vrp = vrp;
this.jobNeighborhoods = jobNeighborhoods;
logger.debug("initialise {}", this);
}
public void setNoRoutes(int kMin, int kMax) {
this.kMin = kMin;
this.kMax = kMax;
}
public void setStringLength(int lMin, int lMax) {
this.lMin = lMin;
this.lMax = lMax;
}
@Override
public String toString() {
return "[name=splitRuin]";
}
/**
* Ruins the collection of vehicleRoutes, i.e. removes a share of jobs. First, it selects a job randomly. Second, it identifies its neighborhood. And finally, it removes
* the neighborhood plus the randomly selected job from the number of vehicleRoutes. All removed jobs are then returned as a collection.
*/
@Override
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes) {
if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) {
return Collections.emptyList();
}
int noStrings;
if (kMin == kMax) noStrings = kMax;
else noStrings = kMin + random.nextInt((kMax - kMin));
noStrings = Math.min(noStrings, vehicleRoutes.size());
Set<Job> unassignedJobs = new HashSet<>();
Set<VehicleRoute> ruinedRoutes = new HashSet<>();
Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random);
Iterator<Job> neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(kMax * lMax, prevJob);
while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) {
if (!unassignedJobs.contains(prevJob)) {
VehicleRoute route = getRouteOf(prevJob, vehicleRoutes);
if (route != null && !ruinedRoutes.contains(route)) {
if (random.nextDouble() < .5) {
ruinRouteWithStringRuin(route, prevJob, unassignedJobs);
} else {
ruinRouteWithSplitStringRuin(route, prevJob, unassignedJobs);
}
ruinedRoutes.add(route);
}
}
prevJob = neighborhoodIterator.next();
}
return unassignedJobs;
}
private VehicleRoute getRouteOf(Job job, Collection<VehicleRoute> vehicleRoutes) {
for (VehicleRoute route : vehicleRoutes) {
if (route.getTourActivities().servesJob(job)) return route;
}
return null;
}
private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int noActivities = seedRoute.getActivities().size();
int stringLength;
if (lMin == lMax) stringLength = lMin;
else stringLength = lMin + random.nextInt(lMax - lMin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random);
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
int totalStringLength = stringLength + preservedSubstringLength;
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(totalStringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
int startIndexOfPreservedSubstring = random.nextInt(stringLength);
int position = 0;
int noStringsInPreservedSubstring = 0;
boolean isPreservedSubstring = false;
for (int i = lowerBound; i < (lowerBound + totalStringLength); i++) {
if (position == startIndexOfPreservedSubstring) {
isPreservedSubstring = true;
}
if (noStringsInPreservedSubstring >= preservedSubstringLength) {
isPreservedSubstring = false;
}
if (!isPreservedSubstring) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
} else noStringsInPreservedSubstring++;
position++;
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int stringLength = lMin + random.nextInt(lMax - lMin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int noActivities = seedRoute.getActivities().size();
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
for (int i = lowerBound; i < (lowerBound + stringLength); i++) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.ruin;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by schroeder on 13/01/17.
*/
class StringUtil {
static List<Integer> getLowerBoundsOfAllStrings(int length, int seedIndex, int routeLength) {
List<Integer> lowerBounds = new ArrayList<>();
for (int i = 1; i <= length; i++) {
int lower = seedIndex - (length - i);
int upper = seedIndex + (i - 1);
if (lower >= 0 && upper < routeLength) {
lowerBounds.add(lower);
}
}
return lowerBounds;
}
static int determineSubstringLength(int baseLength, int routeLength, Random random) {
if (baseLength == routeLength) return 0;
int substringLength = 1;
while (baseLength + substringLength < routeLength) {
if (random.nextDouble() < 0.01) {
return substringLength;
} else substringLength++;
}
return substringLength;
}
}

View file

@ -0,0 +1,120 @@
/*
* 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.state;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeKey;
import java.util.*;
/**
* Created by schroeder on 17/05/16.
*/
public class VehicleDependentTraveledDistance implements StateUpdater, ActivityVisitor {
static class State {
Location prevLocation;
double distance;
public State(Location prevLocation, double distance) {
this.prevLocation = prevLocation;
this.distance = distance;
}
public Location getPrevLocation() {
return prevLocation;
}
public double getDistance() {
return distance;
}
}
private final TransportDistance transportDistance;
private final StateManager stateManager;
private final StateId traveledDistanceId;
private VehicleRoute route;
private List<Vehicle> uniqueVehicles;
private Map<VehicleTypeKey,State> states;
public VehicleDependentTraveledDistance(TransportDistance transportCostMatrices, StateManager stateManager, StateId distanceInRouteId, Collection<Vehicle> vehicles) {
this.transportDistance = transportCostMatrices;
this.stateManager = stateManager;
this.traveledDistanceId = distanceInRouteId;
uniqueVehicles = getUniqueVehicles(vehicles);
}
private List<Vehicle> getUniqueVehicles(Collection<Vehicle> vehicles) {
Set<VehicleTypeKey> types = new HashSet<>();
List<Vehicle> uniqueVehicles = new ArrayList<>();
for(Vehicle v : vehicles){
if(!types.contains(v.getVehicleTypeIdentifier())){
types.add(v.getVehicleTypeIdentifier());
uniqueVehicles.add(v);
}
}
return uniqueVehicles;
}
@Override
public void begin(VehicleRoute route) {
this.route = route;
states = new HashMap<>();
for(Vehicle v : uniqueVehicles){
State state = new State(v.getStartLocation(),0);
states.put(v.getVehicleTypeIdentifier(),state);
}
}
@Override
public void visit(TourActivity activity) {
for(Vehicle v : uniqueVehicles){
State old = states.get(v.getVehicleTypeIdentifier());
double distance = old.getDistance();
distance += transportDistance.getDistance(old.getPrevLocation(),activity.getLocation(),0,v);
stateManager.putActivityState(activity,v,traveledDistanceId,distance);
states.put(v.getVehicleTypeIdentifier(),new State(activity.getLocation(),distance));
}
}
@Override
public void finish() {
for(Vehicle v : uniqueVehicles){
State old = states.get(v.getVehicleTypeIdentifier());
double distance = old.getDistance();
if(v.isReturnToDepot()) {
distance += transportDistance.getDistance(old.getPrevLocation(), v.getEndLocation(), 0, v);
}
stateManager.putRouteState(route,v,traveledDistanceId, distance);
}
}
}

View file

@ -30,7 +30,9 @@ import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@ -119,9 +121,22 @@ public class VariationCoefficientTermination implements PrematureAlgorithmTermin
}
}
public void informIterationEnds(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) {
informIterationEnds(i, problem, toList(solution));
}
private List<VehicleRoutingProblemSolution> toList(VehicleRoutingProblemSolution solution) {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<>();
solutions.add(solution);
return solutions;
}
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (lastAccepted == null) lastAccepted = Solutions.bestOf(solutions);
}
public void informIterationStarts(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) {
informIterationStarts(i, problem, toList(solution));
}
}

View file

@ -26,7 +26,9 @@ import com.graphhopper.jsprit.core.problem.job.Job;
public abstract class AbstractJob implements Job {
private int index;
private Object userData;
@Override
public int getIndex() {
return index;
}
@ -35,4 +37,15 @@ public abstract class AbstractJob implements Job {
this.index = index;
}
/**
* @return User-specific domain data associated by the job
*/
public Object getUserData() {
return userData;
}
protected void setUserData(Object userData) {
this.userData = userData;
}
}

View file

@ -30,6 +30,7 @@ public abstract class AbstractVehicle implements Vehicle {
private int index;
@Override
public int getIndex() {
return index;
}
@ -44,19 +45,35 @@ public abstract class AbstractVehicle implements Vehicle {
private VehicleTypeKey vehicleIdentifier;
public int getIndex() {
return index;
}
private Object userData;
protected void setIndex(int index) {
this.index = index;
}
/**
* @return User-specific domain data associated with the vehicle
*/
@Override
public Object getUserData() {
return userData;
}
public VehicleTypeKey getVehicleTypeIdentifier() {
return vehicleIdentifier;
}
protected void setUserData(Object userData) {
this.userData = userData;
}
protected void setVehicleIdentifier(VehicleTypeKey vehicleTypeIdentifier) {
this.vehicleIdentifier = vehicleTypeIdentifier;
}
@Override
public int getIndex() {
return index;
}
protected void setIndex(int index) {
this.index = index;
}
@Override
public VehicleTypeKey getVehicleTypeIdentifier() {
return vehicleIdentifier;
}
protected void setVehicleIdentifier(VehicleTypeKey vehicleTypeIdentifier) {
this.vehicleIdentifier = vehicleTypeIdentifier;
}
}

View file

@ -64,26 +64,77 @@ public final class Location implements HasIndex, HasId {
private Coordinate coordinate;
private String name = "";
private Object userData;
public static Builder newInstance() {
return new Builder();
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets location index
*
* @param index
* @return the builder
*/
public Builder setIndex(int index) {
if (index < 0) throw new IllegalArgumentException("index must be >= 0");
this.index = index;
return this;
}
/**
* Sets coordinate of location
*
* @param coordinate
* @return
*/
public Builder setCoordinate(Coordinate coordinate) {
this.coordinate = coordinate;
return this;
}
/**
* Sets location id
*
* @param id
* @return
*/
public Builder setId(String id) {
this.id = id;
return this;
}
/**
* Adds name, e.g. street name, to location
*
* @param name
* @return
*/
public Builder setName(String name){
this.name = name;
return this;
}
public Location build() {
if (id == null && coordinate == null) {
if (index == -1) throw new IllegalArgumentException("either id or coordinate or index must be set");
@ -107,10 +158,23 @@ public final class Location implements HasIndex, HasId {
private final String id;
private final String name;
private Object userData;
private Location(Builder builder) {
this.userData = builder.userData;
this.index = builder.index;
this.coordinate = builder.coordinate;
this.id = builder.id;
this.name = builder.name;
}
/**
* @return User-specific domain data associated by the job
*/
public Object getUserData() {
return userData;
}
@Override
@ -127,6 +191,8 @@ public final class Location implements HasIndex, HasId {
return coordinate;
}
public String getName() { return name; }
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -568,8 +568,6 @@ public class VehicleRoutingProblem {
*/
private final FleetSize fleetSize;
private final Locations locations;
private Map<Job, List<AbstractActivity>> activityMap;
private int nuActivities;
@ -591,7 +589,6 @@ public class VehicleRoutingProblem {
this.initialVehicleRoutes = builder.initialRoutes;
this.transportCosts = builder.transportCosts;
this.activityCosts = builder.activityCosts;
this.locations = builder.getLocations();
this.activityMap = builder.activityMap;
this.nuActivities = builder.activityIndexCounter;
this.allLocations = builder.allLocations;

View file

@ -37,6 +37,7 @@ import java.util.List;
*/
public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint {
public static enum Priority {
CRITICAL, HIGH, LOW
}
@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager();
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
resolveConstraints(constraints);
}
public Collection<HardRouteConstraint> getHardRouteConstraints() {
return hardRouteConstraintManager.getConstraints();
}
public Collection<HardActivityConstraint> getCriticalHardActivityConstraints() {
return actLevelConstraintManager.getCriticalConstraints();
}
public Collection<HardActivityConstraint> getHighPrioHardActivityConstraints() {
return actLevelConstraintManager.getHighPrioConstraints();
}
public Collection<HardActivityConstraint> getLowPrioHardActivityConstraints() {
return actLevelConstraintManager.getLowPrioConstraints();
}
// public Collection<HardActivityConstraint> getHardActivityConstraints() {
// return actLevelConstraintManager.g;
// }
public DependencyType[] getDependencyTypes() {
return dependencyTypes;
}
@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
constraintTypeKnown = true;
}
if (c instanceof HardRouteConstraint) {
routeLevelConstraintManager.addConstraint((HardRouteConstraint) c);
hardRouteConstraintManager.addConstraint((HardRouteConstraint) c);
constraintTypeKnown = true;
}
if (c instanceof SoftRouteConstraint) {
@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
}
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
hardRouteConstraintManager.addConstraint(routeLevelConstraint);
}
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
@Override
public boolean fulfilled(JobInsertionContext insertionContext) {
return routeLevelConstraintManager.fulfilled(insertionContext);
return hardRouteConstraintManager.fulfilled(insertionContext);
}
@Override
@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
public Collection<Constraint> getConstraints() {
List<Constraint> constraints = new ArrayList<Constraint>();
constraints.addAll(actLevelConstraintManager.getAllConstraints());
constraints.addAll(routeLevelConstraintManager.getConstraints());
constraints.addAll(hardRouteConstraintManager.getConstraints());
constraints.addAll(softActivityConstraintManager.getConstraints());
constraints.addAll(softRouteConstraintManager.getConstraints());
return Collections.unmodifiableCollection(constraints);

View file

@ -0,0 +1,134 @@
/*
* 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.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
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.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.Collection;
import java.util.Map;
/**
* Created by schroeder on 11/10/16.
*/
public class MaxDistanceConstraint implements HardActivityConstraint{
private StateManager stateManager;
private StateId distanceId;
private TransportDistance distanceCalculator;
private Double[] maxDistances;
public MaxDistanceConstraint(StateManager stateManager, StateId distanceId, TransportDistance distanceCalculator, Map<Vehicle,Double> maxDistancePerVehicleMap) {
this.stateManager = stateManager;
this.distanceId = distanceId;
this.distanceCalculator = distanceCalculator;
makeArray(maxDistancePerVehicleMap);
}
private void makeArray(Map<Vehicle, Double> maxDistances) {
int maxIndex = getMaxIndex(maxDistances.keySet());
this.maxDistances = new Double[maxIndex+1];
for(Vehicle v : maxDistances.keySet()){
this.maxDistances[v.getIndex()]=maxDistances.get(v);
}
}
private int getMaxIndex(Collection<Vehicle> vehicles) {
int index = 0;
for(Vehicle v : vehicles){
if(v.getIndex() > index) index = v.getIndex();
}
return index;
}
@Override
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
if(!hasMaxDistance(iFacts.getNewVehicle())) return ConstraintsStatus.FULFILLED;
Double currentDistance = 0d;
boolean routeIsEmpty = iFacts.getRoute().isEmpty();
if(!routeIsEmpty){
currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class);
}
double maxDistance = getMaxDistance(iFacts.getNewVehicle());
if(currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK;
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
if(prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0;
if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){
distanceNewAct2nextAct = 0;
distancePrevAct2NextAct = 0;
}
double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct;
if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED;
double additionalDistanceOfPickup = 0;
if(newAct instanceof DeliverShipment){
int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex();
TourActivity pickup = iFacts.getAssociatedActivities().get(0);
TourActivity actBeforePickup;
if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1);
else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE);
TourActivity actAfterPickup;
if (iIndexOfPickup < iFacts.getRoute().getActivities().size())
actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup);
else
actAfterPickup = nextAct;
double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle());
double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
if (routeIsEmpty) distanceBeforePickup2AfterPickup = 0;
if (actAfterPickup instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) {
distancePickup2ActAfterPickup = 0;
distanceBeforePickup2AfterPickup = 0;
}
additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup;
}
if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){
return ConstraintsStatus.NOT_FULFILLED;
}
return ConstraintsStatus.FULFILLED;
}
private boolean hasMaxDistance(Vehicle newVehicle){
if(newVehicle.getIndex() >= this.maxDistances.length) return false;
return this.maxDistances[newVehicle.getIndex()] != null;
}
private double getMaxDistance(Vehicle newVehicle) {
Double maxDistance = this.maxDistances[newVehicle.getIndex()];
if(maxDistance == null) return Double.MAX_VALUE;
return maxDistance;
}
}

View file

@ -20,21 +20,32 @@ package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
import com.graphhopper.jsprit.core.algorithm.state.UpdateVehicleDependentPracticalTimeWindows;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.cost.TransportTime;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
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.DeliveryActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Created by schroeder on 15/09/16.
*/
public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
private final VehicleRoutingProblem vrp;
private final TransportTime transportTime;
private final VehicleRoutingActivityCosts activityCosts;
@ -43,15 +54,19 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
private final StateManager stateManager;
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager) {
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager, VehicleRoutingProblem vrp) {
this.transportTime = transportTime;
this.latestStartId = latestStartId;
this.stateManager = stateManager;
this.activityCosts = activityCosts;
this.vrp = vrp;
}
@Override
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
public ConstraintsStatus fulfilled(final JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
boolean newActIsPickup = newAct instanceof PickupActivity;
boolean newActIsDelivery = newAct instanceof DeliveryActivity;
boolean isShipment = iFacts.getJob() instanceof Shipment;
/*
1. check whether insertion of new shipment satisfies own max-in-vehicle-constraint
2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
@ -75,7 +90,7 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
if(timeInVehicle > maxTimeInVehicle) return ConstraintsStatus.NOT_FULFILLED;
}
else if(newAct instanceof PickupActivity){
else if(newActIsPickup){
if(iFacts.getAssociatedActivities().size() == 1){
double maxTimeInVehicle = ((TourActivity.JobActivity)newAct).getJob().getMaxTimeInVehicle();
//ToDo - estimate in vehicle time of pickups here - This seems to trickier than I thought
@ -88,15 +103,46 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
//************ 2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
double latest;
if(iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if(nextAct instanceof End){
latest = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), latestStartId,Double.class);
}
else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class);
if(newActIsPickup || iFacts.getAssociatedActivities().size() == 1) {
double latest;
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = stateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), latestStartId, Double.class);
} else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class);
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED;
}
}
else if(newActIsDelivery && iFacts.getAssociatedActivities().size() == 2){
StateManager localStateManager = new StateManager(vrp);
StateId stateId = localStateManager.createStateId("local-slack");
UpdateMaxTimeInVehicle updateMaxTimeInVehicle = new UpdateMaxTimeInVehicle(localStateManager,stateId,transportTime,activityCosts);
updateMaxTimeInVehicle.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
@Override
public Collection<Vehicle> get(VehicleRoute route) {
return Arrays.asList(iFacts.getNewVehicle());
}
});
updateMaxTimeInVehicle.begin(iFacts.getRoute());
List<TourActivity> tourActivities = new ArrayList<>(iFacts.getRoute().getActivities());
tourActivities.add(iFacts.getRelatedActivityContext().getInsertionIndex(),iFacts.getAssociatedActivities().get(0));
for(TourActivity act : tourActivities){
updateMaxTimeInVehicle.visit(act);
}
updateMaxTimeInVehicle.finish(tourActivities,iFacts.getJob());
double latest;
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = localStateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), stateId, Double.class);
} else latest = localStateManager.getActivityState(nextAct, iFacts.getNewVehicle(), stateId, Double.class);
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED;
}
if(nextActStart > latest){
return ConstraintsStatus.NOT_FULFILLED;
}
return ConstraintsStatus.FULFILLED;
}

View file

@ -17,6 +17,8 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import java.util.Collection;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.Location;
@ -26,8 +28,6 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import com.graphhopper.jsprit.core.util.Coordinate;
import java.util.Collection;
/**
* Service implementation of a job.
* <p>
@ -88,13 +88,12 @@ public class Service extends AbstractJob {
protected TimeWindowsImpl timeWindows;
private boolean twAdded = false;
private boolean twAdded = false;
private int priority = 2;
protected Object userData;
protected double maxTimeInVehicle = Double.MAX_VALUE;
Builder(String id){
protected double maxTimeInVehicle = Double.MAX_VALUE;Builder(String id){
this.id = id;
timeWindows = new TimeWindowsImpl();
timeWindows.add(timeWindow);
@ -141,6 +140,24 @@ public class Service extends AbstractJob {
return this;
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder<T> setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Adds capacity dimension.
*
@ -216,15 +233,16 @@ public class Service extends AbstractJob {
}
/**
* Set priority to service. Only 1 = high priority, 2 = medium and 3 = low are allowed.
* Set priority to service. Only 1 (very high) to 10 (very low) are allowed.
* <p>
* Default is 2 = medium.
* Default is 2.
*
* @param priority
* @return builder
*/
public Builder<T> setPriority(int priority) {
if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
if (priority < 1 || priority > 10)
throw new IllegalArgumentException("incorrect priority. only priority values from 1 to 10 are allowed where 1 = high and 10 is low");
this.priority = priority;
return this;
}
@ -259,7 +277,8 @@ public class Service extends AbstractJob {
private final double maxTimeInVehicle;
Service(Builder builder) {
Service(Builder<?> builder) {
setUserData(builder.userData);
id = builder.id;
serviceTime = builder.serviceTime;
timeWindow = builder.timeWindow;
@ -268,14 +287,13 @@ public class Service extends AbstractJob {
skills = builder.skills;
name = builder.name;
location = builder.location;
timeWindowManager = builder.timeWindows;
timeWindowManager = builder.timeWindows;
priority = builder.priority;
maxTimeInVehicle = builder.maxTimeInVehicle;
}
maxTimeInVehicle = builder.maxTimeInVehicle;}
public Collection<TimeWindow> getTimeWindows(){
return timeWindowManager.getTimeWindows();
}
public Collection<TimeWindow> getTimeWindows(){
return timeWindowManager.getTimeWindows();
}
@Override
public String getId() {
@ -380,6 +398,7 @@ public class Service extends AbstractJob {
*
* @return priority
*/
@Override
public int getPriority() {
return priority;
}

View file

@ -17,6 +17,8 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import java.util.Collection;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.Location;
@ -24,8 +26,6 @@ import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import java.util.Collection;
/**
* Shipment is an implementation of Job and consists of a pickup and a delivery of something.
@ -89,6 +89,8 @@ public class Shipment extends AbstractJob {
private int priority = 2;
public Object userData;
public double maxTimeInVehicle = Double.MAX_VALUE;
/**
@ -110,10 +112,29 @@ public class Shipment extends AbstractJob {
deliveryTimeWindows.add(deliveryTimeWindow);
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets pickup location.
*
* @param pickupLocation pickup location
* @param pickupLocation
* pickup location
* @return builder
*/
public Builder setPickupLocation(Location pickupLocation) {
@ -271,7 +292,7 @@ public class Shipment extends AbstractJob {
}
/**
* Set priority to shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed.
* Set priority to shipment. Only 1 (high) to 10 (low) are allowed.
* <p>
* Default is 2 = medium.
*
@ -279,7 +300,8 @@ public class Shipment extends AbstractJob {
* @return builder
*/
public Builder setPriority(int priority) {
if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
if (priority < 1 || priority > 10)
throw new IllegalArgumentException("incorrect priority. only 1 (very high) to 10 (very low) are allowed");
this.priority = priority;
return this;
}
@ -326,6 +348,7 @@ public class Shipment extends AbstractJob {
private final double maxTimeInVehicle;
Shipment(Builder builder) {
setUserData(builder.userData);
this.id = builder.id;
this.pickupServiceTime = builder.pickupServiceTime;
this.pickupTimeWindow = builder.pickupTimeWindow;
@ -454,6 +477,7 @@ public class Shipment extends AbstractJob {
*
* @return priority
*/
@Override
public int getPriority() {
return priority;
}

View file

@ -19,6 +19,7 @@ package com.graphhopper.jsprit.core.problem.solution.route;
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.driver.Driver;
import com.graphhopper.jsprit.core.problem.driver.DriverImpl;
import com.graphhopper.jsprit.core.problem.job.*;
@ -196,16 +197,33 @@ public class VehicleRoute {
return this;
}
@Deprecated
public Builder addBreak(Break currentbreak) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addBreak(currentbreak, currentbreak.getTimeWindow());
}
@Deprecated
public Builder addBreak(Break currentbreak, TimeWindow timeWindow) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addService(currentbreak,timeWindow);
}
public Builder addBreak(Break currentbreak, TimeWindow timeWindow, Location location) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addBreakInternally(currentbreak, timeWindow, location);
}
private Builder addBreakInternally(Break currentBreak, TimeWindow timeWindow, Location breakLocation) {
List<AbstractActivity> acts = jobActivityFactory.createActivities(currentBreak);
BreakActivity act = (BreakActivity) acts.get(0);
act.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
act.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
act.setLocation(breakLocation);
tourActivities.addActivity(act);
return this;
}
/**
* Adds a pickup to this route.
*

View file

@ -72,6 +72,14 @@ public interface Vehicle extends HasId, HasIndex {
public abstract VehicleTypeKey getVehicleTypeIdentifier();
public abstract Skills getSkills();
/**
* @return User-specific domain data associated with the vehicle
*/
public Object getUserData();
public abstract Break getBreak();
// Switch to this as soon as we switct to Java 8:
// default Object getUserData() {
// return null;
// };
}

View file

@ -17,12 +17,13 @@
*/
package com.graphhopper.jsprit.core.problem.vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.graphhopper.jsprit.core.problem.AbstractVehicle;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.job.Break;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@ -130,6 +131,8 @@ public class VehicleImpl extends AbstractVehicle {
private Break aBreak;
private Object userData;
private Builder(String id) {
super();
this.id = id;
@ -148,16 +151,39 @@ public class VehicleImpl extends AbstractVehicle {
return this;
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets the flag whether the vehicle must return to depot or not.
* <p>
* <p>If returnToDepot is true, the vehicle must return to specified end-location. If you
* omit specifying the end-location, vehicle returns to start-location (that must to be set). If
* you specify it, it returns to specified end-location.
* <p>
* <p>If returnToDepot is false, the end-location of the vehicle is endogenous.
* If returnToDepot is true, the vehicle must return to specified
* end-location. If you omit specifying the end-location, vehicle
* returns to start-location (that must to be set). If you specify it,
* it returns to specified end-location.
* <p>
* <p>
* If returnToDepot is false, the end-location of the vehicle is
* endogenous.
*
* @param returnToDepot true if vehicle need to return to depot, otherwise false
* @param returnToDepot
* true if vehicle need to return to depot, otherwise false
* @return this builder
*/
public Builder setReturnToDepot(boolean returnToDepot) {
@ -234,14 +260,13 @@ public class VehicleImpl extends AbstractVehicle {
if (startLocation != null && endLocation != null) {
if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot)
throw new IllegalArgumentException("this must not be. you specified both endLocationId and open-routes. this is contradictory. <br>" +
"if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified.");
"if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified.");
}
if (startLocation != null && endLocation == null) {
endLocation = startLocation;
}
if (startLocation == null && endLocation == null) {
if (startLocation == null && endLocation == null)
throw new IllegalArgumentException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set");
}
skills = skillBuilder.build();
return new VehicleImpl(this);
}
@ -297,6 +322,7 @@ public class VehicleImpl extends AbstractVehicle {
private final Break aBreak;
private VehicleImpl(Builder builder) {
setUserData(builder.userData);
id = builder.id;
type = builder.type;
earliestDeparture = builder.earliestStart;
@ -306,7 +332,7 @@ public class VehicleImpl extends AbstractVehicle {
endLocation = builder.endLocation;
startLocation = builder.startLocation;
aBreak = builder.aBreak;
// setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills));
// setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills));
setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(), startLocation.getId(), endLocation.getId(), earliestDeparture, latestArrival, skills, returnToDepot));
}
@ -318,11 +344,11 @@ public class VehicleImpl extends AbstractVehicle {
@Override
public String toString() {
return "[id=" + id + "]" +
"[type=" + type + "]" +
"[startLocation=" + startLocation + "]" +
"[endLocation=" + endLocation + "]" +
"[isReturnToDepot=" + isReturnToDepot() + "]" +
"[skills=" + skills + "]";
"[type=" + type + "]" +
"[startLocation=" + startLocation + "]" +
"[endLocation=" + endLocation + "]" +
"[isReturnToDepot=" + isReturnToDepot() + "]" +
"[skills=" + skills + "]";
}
@ -346,6 +372,7 @@ public class VehicleImpl extends AbstractVehicle {
return id;
}
@Override
public boolean isReturnToDepot() {
return returnToDepot;
}

View file

@ -56,4 +56,13 @@ public interface VehicleType {
public String getProfile();
/**
* @return User-specific domain data associated with the vehicle type
*/
public Object getUserData();
// Switch to this as soon as we switct to Java 8:
// default Object getUserData() {
// return null;
// };
}

View file

@ -116,16 +116,39 @@ public class VehicleTypeImpl implements VehicleType {
private boolean dimensionAdded = false;
private Object userData;
private Builder(String id) {
this.id = id;
}
/**
* Sets the maximum velocity this vehicle-type can go [in meter per seconds].
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets the maximum velocity this vehicle-type can go [in meter per
* seconds].
*
* @param inMeterPerSeconds
* @return this builder
* @throws IllegalArgumentException if velocity is smaller than zero
* @throws IllegalArgumentException
* if velocity is smaller than zero
*/
public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) {
if (inMeterPerSeconds < 0.0) throw new IllegalArgumentException("velocity cannot be smaller than zero");
@ -240,8 +263,8 @@ public class VehicleTypeImpl implements VehicleType {
if (dimVal < 0) throw new IllegalArgumentException("capacity value cannot be negative");
if (capacityDimensions != null)
throw new IllegalArgumentException("either build your dimension with build your dimensions with " +
"addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods.");
"addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods.");
dimensionAdded = true;
capacityBuilder.addDimension(dimIndex, dimVal);
return this;
@ -261,8 +284,8 @@ public class VehicleTypeImpl implements VehicleType {
public Builder setCapacityDimensions(Capacity capacity) {
if (dimensionAdded)
throw new IllegalArgumentException("either build your dimension with build your dimensions with " +
"addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods.");
"addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods.");
this.capacityDimensions = capacity;
return this;
}
@ -278,7 +301,7 @@ public class VehicleTypeImpl implements VehicleType {
final int prime = 31;
int result = 1;
result = prime * result
+ ((typeId == null) ? 0 : typeId.hashCode());
+ ((typeId == null) ? 0 : typeId.hashCode());
return result;
}
@ -314,12 +337,15 @@ public class VehicleTypeImpl implements VehicleType {
private final double maxVelocity;
private Object userData;
/**
* priv constructor constructing vehicle-type
*
* @param builder
*/
private VehicleTypeImpl(VehicleTypeImpl.Builder builder) {
this.userData = builder.userData;
typeId = builder.id;
capacity = builder.capacity;
maxVelocity = builder.maxVelo;
@ -328,6 +354,14 @@ public class VehicleTypeImpl implements VehicleType {
profile = builder.profile;
}
/**
* @return User-specific domain data associated with the vehicle
*/
@Override
public Object getUserData() {
return userData;
}
/* (non-Javadoc)
* @see basics.route.VehicleType#getTypeId()
*/
@ -347,8 +381,8 @@ public class VehicleTypeImpl implements VehicleType {
@Override
public String toString() {
return "[typeId=" + typeId + "]" +
"[capacity=" + capacityDimensions + "]" +
"[costs=" + vehicleCostParams + "]";
"[capacity=" + capacityDimensions + "]" +
"[costs=" + vehicleCostParams + "]";
}
@Override

View file

@ -45,6 +45,8 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private double[][][] matrix;
private final int noLocations;
/**
* Creates a new builder returning the matrix-builder.
* <p>If you want to consider symmetric matrices, set isSymmetric to true.
@ -59,6 +61,7 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private Builder(int noLocations, boolean isSymmetric) {
this.isSymmetric = isSymmetric;
matrix = new double[noLocations][noLocations][2];
this.noLocations = noLocations;
}
/**
@ -74,11 +77,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return this;
}
private void add(int fromIndex, int toIndex, int indicatorIndex, double distance) {
private void add(int fromIndex, int toIndex, int indicatorIndex, double value) {
if (isSymmetric) {
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = distance;
else matrix[toIndex][fromIndex][indicatorIndex] = distance;
} else matrix[fromIndex][toIndex][indicatorIndex] = distance;
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = value;
else matrix[toIndex][fromIndex][indicatorIndex] = value;
} else matrix[fromIndex][toIndex][indicatorIndex] = value;
}
/**
@ -94,6 +97,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return this;
}
public Builder addTransportTimeAndDistance(int fromIndex, int toIndex, double time, double distance){
addTransportTime(fromIndex, toIndex, time);
addTransportDistance(fromIndex,toIndex,distance);
return this;
}
/**
* Builds the matrix.
*
@ -110,9 +118,12 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private final double[][][] matrix;
private int noLocations;
private FastVehicleRoutingTransportCostsMatrix(Builder builder) {
this.isSymmetric = builder.isSymmetric;
matrix = builder.matrix;
noLocations = builder.noLocations;
}
/**
@ -169,4 +180,9 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return costParams.perDistanceUnit * getDistance(from.getIndex(), to.getIndex()) + costParams.perTransportTimeUnit * getTransportTime(from, to, departureTime, driver, vehicle);
}
public int getNoLocations() {
return noLocations;
}
}

View file

@ -0,0 +1,181 @@
/*
* 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.util;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedListener;
import com.graphhopper.jsprit.core.problem.job.Job;
import org.apache.commons.math3.stat.Frequency;
import java.util.*;
/**
* Created by schroeder on 06/02/17.
*/
public class UnassignedJobReasonTracker implements JobUnassignedListener {
public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) {
if (failedConstraintNamesFrequency == null) return "no reason found";
Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator();
int maxCount = 0;
String mostLikely = null;
while (entryIterator.hasNext()) {
Map.Entry<Comparable<?>, Long> entry = entryIterator.next();
if (entry.getValue() > maxCount) {
Comparable<?> key = entry.getKey();
mostLikely = key.toString();
}
}
return mostLikely;
}
Map<String, Frequency> failedConstraintNamesFrequencyMapping = new HashMap<>();
Map<Integer, String> codesToHumanReadableReason = new HashMap<>();
Map<String, Integer> failedConstraintNamesToCode = new HashMap<>();
Set<String> failedConstraintNamesToBeIgnored = new HashSet<>();
public UnassignedJobReasonTracker() {
codesToHumanReadableReason.put(1, "cannot serve required skill");
codesToHumanReadableReason.put(2, "cannot be visited within time window");
codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity");
codesToHumanReadableReason.put(4, "cannot be assigned due to max distance constraint of vehicle");
failedConstraintNamesToCode.put("HardSkillConstraint", 1);
failedConstraintNamesToCode.put("VehicleDependentTimeWindowConstraints", 2);
failedConstraintNamesToCode.put("ServiceLoadRouteLevelConstraint", 3);
failedConstraintNamesToCode.put("PickupAndDeliverShipmentLoadActivityLevelConstraint", 3);
failedConstraintNamesToCode.put("ServiceLoadActivityLevelConstraint", 3);
failedConstraintNamesToCode.put("MaxDistanceConstraint", 4);
}
public void ignore(String simpleNameOfConstraint) {
failedConstraintNamesToBeIgnored.add(simpleNameOfConstraint);
}
@Override
public void informJobUnassigned(Job unassigned, Collection<String> failedConstraintNames) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(unassigned.getId())) {
this.failedConstraintNamesFrequencyMapping.put(unassigned.getId(), new Frequency());
}
for (String r : failedConstraintNames) {
if (failedConstraintNamesToBeIgnored.contains(r)) continue;
this.failedConstraintNamesFrequencyMapping.get(unassigned.getId()).addValue(r);
}
}
public void put(String simpleNameOfFailedConstraint, int code, String reason) {
if (code <= 20)
throw new IllegalArgumentException("first 20 codes are reserved internally. choose a code > 20");
codesToHumanReadableReason.put(code, reason);
if (failedConstraintNamesToCode.containsKey(simpleNameOfFailedConstraint)) {
throw new IllegalArgumentException(simpleNameOfFailedConstraint + " already assigned to code and reason");
} else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code);
}
/**
* For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
*
* @return
*/
@Deprecated
public Map<String, Frequency> getReasons() {
return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping);
}
/**
* For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
*
* @return
*/
public Map<String, Frequency> getFailedConstraintNamesFrequencyMapping() {
return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping);
}
/**
* Returns an unmodifiable map of codes and reason pairs.
*
* @return
*/
public Map<Integer, String> getCodesToReason() {
return Collections.unmodifiableMap(codesToHumanReadableReason);
}
/**
* Returns an unmodifiable map of constraint names (simple name of constraint) and reason code pairs.
*
* @return
*/
public Map<String, Integer> getFailedConstraintNamesToCode() {
return Collections.unmodifiableMap(failedConstraintNamesToCode);
}
public int getCode(String failedConstraintName) {
return toCode(failedConstraintName);
}
public String getHumanReadableReason(int code) {
return getCodesToReason().get(code);
}
public String getHumanReadableReason(String failedConstraintName) {
return getCodesToReason().get(getCode(failedConstraintName));
}
/**
* Returns the most likely reason code i.e. the reason (failed constraint) being observed most often.
*
* 1 --> "cannot serve required skill
* 2 --> "cannot be visited within time window"
* 3 --> "does not fit into any vehicle due to capacity"
* 4 --> "cannot be assigned due to max distance constraint of vehicle"
*
* @param jobId
* @return
*/
public int getMostLikelyReasonCode(String jobId) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return -1;
Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId);
String mostLikelyReason = getMostLikelyFailedConstraintName(reasons);
return toCode(mostLikelyReason);
}
/**
* Returns the most likely reason i.e. the reason (failed constraint) being observed most often.
*
* @param jobId
* @return
*/
public String getMostLikelyReason(String jobId) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return "no reason found";
Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId);
String mostLikelyReason = getMostLikelyFailedConstraintName(reasons);
int code = toCode(mostLikelyReason);
if (code == -1) return mostLikelyReason;
else return codesToHumanReadableReason.get(code);
}
private int toCode(String mostLikelyReason) {
if (failedConstraintNamesToCode.containsKey(mostLikelyReason))
return failedConstraintNamesToCode.get(mostLikelyReason);
else return -1;
}
}

View file

@ -31,7 +31,6 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
import com.graphhopper.jsprit.core.util.Solutions;
import org.junit.Assert;
import org.junit.Test;
/**
@ -43,10 +42,10 @@ public class MaxTimeInVehicle_IT {
public void test(){
Shipment s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
.setMaxTimeInVehicle(90d)
.setMaxTimeInVehicle(100d)
.build();
Shipment s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
.setMaxTimeInVehicle(90d)
.setMaxTimeInVehicle(100d)
.build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
@ -58,12 +57,12 @@ public class MaxTimeInVehicle_IT {
stateManager.addStateUpdater(new UpdateMaxTimeInVehicle(stateManager,id,vrp.getTransportCosts(),vrp.getActivityCosts()));
ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager);
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager), ConstraintManager.Priority.CRITICAL);
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager, vrp), ConstraintManager.Priority.CRITICAL);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager,constraintManager).buildAlgorithm();
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(400, solution.getCost(), 0.001);
// SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE);
// Assert.assertEquals(400, solution.getCost(), 0.001);
SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE);
}
}

View file

@ -26,14 +26,17 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.Solutions;
import com.graphhopper.jsprit.core.util.UnassignedJobReasonTracker;
import org.junit.Test;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class UnassignedJobListTest {
@Test
public void job2ShouldBeInBadJobList_dueToTimeWindow() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
@ -46,11 +49,17 @@ public class UnassignedJobListTest {
VehicleRoutingProblem vrp = builder.build();
VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp);
algorithm.setMaxIterations(10);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
algorithm.addListener(reasonTracker);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
assertTrue(!solution.getUnassignedJobs().contains(job1));
assertTrue(solution.getUnassignedJobs().contains(job2));
assertEquals(2, reasonTracker.getMostLikelyReasonCode("job2"));
}
@Test
@ -63,13 +72,19 @@ public class UnassignedJobListTest {
builder.addJob(job2);
VehicleRoutingProblem vrp = builder.build();
VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp);
algorithm.setMaxIterations(10);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
algorithm.addListener(reasonTracker);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
assertTrue(!solution.getUnassignedJobs().contains(job1));
assertTrue(solution.getUnassignedJobs().contains(job2));
assertEquals(3, reasonTracker.getMostLikelyReasonCode("job2"));
}
}

View file

@ -1,95 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.mock;
/**
* Created by schroeder on 15/08/16.
*/
public class ConfigureFixCostCalculatorTest {
VehicleRoutingProblem vrp;
@Before
public void before(){
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
for(int i=0;i<100;i++){
Service service = Service.Builder.newInstance("" + i).setLocation(Location.newInstance(0)).build();
vrpBuilder.addJob(service);
}
vrp = vrpBuilder.build();
}
@Test
public void shouldCalculateCorrectly(){
List<Job> unassigned = new ArrayList<>();
int count = 1;
for(String key : vrp.getJobs().keySet()) {
if(count <= 25) {
unassigned.add(vrp.getJobs().get(key));
}
count++;
}
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(0.75, jicc.getSolutionCompletenessRatio(), 0.001);
}
@Test
public void shouldBeMinRatio(){
List<Job> unassigned = new ArrayList<>();
int count = 1;
for(String key : vrp.getJobs().keySet()) {
if(count <= 75) {
unassigned.add(vrp.getJobs().get(key));
}
count++;
}
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(0.5, jicc.getSolutionCompletenessRatio(), 0.001);
}
@Test
public void shouldBeOne(){
List<Job> unassigned = new ArrayList<>();
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(1.0, jicc.getSolutionCompletenessRatio(), 0.001);
}
}

View file

@ -20,6 +20,7 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.job.Job;
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.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
@ -34,11 +35,15 @@ import static org.mockito.Mockito.when;
public class JobInsertionConsideringFixCostsCalculatorTest {
private JobInsertionConsideringFixCostsCalculator calc;
private IncreasingAbsoluteFixedCosts absFixedCosts;
private Vehicle oVehicle;
private DecreasingRelativeFixedCosts relFixedCosts;
private Vehicle nVehicle;
private Vehicle small;
private Vehicle medium;
private Vehicle large;
private Job job;
@ -52,194 +57,333 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
job = mock(Job.class);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).build());
oVehicle = mock(Vehicle.class);
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
small = mock(Vehicle.class);
VehicleType smallType = VehicleTypeImpl.Builder.newInstance("smallType").addCapacityDimension(0, 50).setFixedCost(50.0).build();
when(small.getType()).thenReturn(smallType);
nVehicle = mock(Vehicle.class);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
medium = mock(Vehicle.class);
VehicleType mediumType = VehicleTypeImpl.Builder.newInstance("mediumType").addCapacityDimension(0, 100).setFixedCost(100.0).build();
when(medium.getType()).thenReturn(mediumType);
InsertionData iData = new InsertionData(0.0, 1, 1, nVehicle, null);
large = mock(Vehicle.class);
VehicleType largeType = VehicleTypeImpl.Builder.newInstance("largeType").addCapacityDimension(0, 400).setFixedCost(200.0).build();
when(large.getType()).thenReturn(largeType);
InsertionData iData = new InsertionData(0.0, 1, 1, medium, null);
route = mock(VehicleRoute.class);
when(jobInsertionCosts.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
when(jobInsertionCosts.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
when(jobInsertionCosts.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE)).thenReturn(new InsertionData(0.0, 1, 1, large, null));
stateGetter = mock(RouteAndActivityStateGetter.class);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().build());
calc = new JobInsertionConsideringFixCostsCalculator(jobInsertionCosts, stateGetter);
absFixedCosts = new IncreasingAbsoluteFixedCosts(10);
relFixedCosts = new DecreasingRelativeFixedCosts(stateGetter, 10);
}
@Test
public void whenOldVehicleIsNullAndSolutionComplete_itShouldReturnFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(1.0);
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*100. + 0.*50.) * 1. * 1. = 100.
assertEquals(100., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
assertEquals(100., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(1.0);
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.1);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs50PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(1.0);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*100+0.5*50)*0.5*1. = 37.5
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs75PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(1.0);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*100.+0.25*50.)*0.75*1. = 65.625
assertEquals(65.625, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(65.625, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionCompleteAndWeightIs05_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*100. + 0.*50.) * 1. * 0.5 = 5.
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnHalfOfNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*100+0.5*50)*0.5*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*100.+0.25*50.)*0.75*0.5 = 32.8125
assertEquals(32.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(32.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionComplete_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 1. = 50.
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs50PercentComplete_itShouldCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*(100-50)+0.5*(50-0))*0.5*1. = 25.
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs75PercentComplete_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*(100.-50.)+0.25*(50.-0.))*0.75*1. = 37.5
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 0.5 = 25.
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(50-0))*0.5*0.5 = 12.5
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(50.-0.))*0.75*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(75.-25.))*0.75*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(.5);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(.5);
relFixedCosts.setWeightOfFixCost(.5);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
when(small.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
when(medium.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(oVehicle);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
/*
* (0.5*(100-50)+0.5*(
* relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) =
* )*0.5*0.5
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
*/
assertEquals(7.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsMoreExpensive() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(medium.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(small.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
/*
@ -249,26 +393,125 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
*/
assertEquals(7.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(-50d, insertionCost, 0.01);
}
@Test
public void smallVSMediumAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(50d, insertionCost, 0.01);
}
@Test
public void smallVSLargeAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(150d, insertionCost, 0.01);
}
@Test
public void largeVSMediumAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(large);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(-100d, insertionCost, 0.01);
}
@Test
public void mediumVSLargeAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(medium);
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(100d, insertionCost, 0.01);
}
@Test
public void whenOldVehicleIsMoreExpensive2() {
absFixedCosts.setSolutionCompletenessRatio(0.1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(0.1);
relFixedCosts.setWeightOfFixCost(1);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(medium.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(small.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
/*
job = 50
abs = (50 - 100) * 0.1 * 0.1 * 1.0 = -0.5
rel = ( (75/50+100/100)/2 * 50 - (25/100 + 100/400)/2 * 100) * 0.9 * 0.1 = 3.375
c = -0.5 + 3.375 = 2.875
*/
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(2.875, insertionCost, 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
when(small.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
when(medium.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(oVehicle);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*12.5)*0.75*0.5 = 15.234375
assertEquals(15.234375, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(15.234375, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}

View file

@ -178,7 +178,7 @@ public class ShipmentInsertionCalculatorTest {
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(InsertionData.createEmptyInsertionData(), iData);
assertTrue(iData instanceof InsertionData.NoInsertionFound);
}

View file

@ -28,6 +28,7 @@ import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
import com.graphhopper.jsprit.core.problem.job.Job;
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.End;
@ -91,6 +92,74 @@ public class TestLocalActivityInsertionCostsCalculator {
return Location.Builder.newInstance().setId(i).build();
}
@Test
public void whenAddingServiceBetweenDiffStartAndEnd_costMustBeCorrect() {
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(20, 0))
.build();
Service s = Service.Builder.newInstance("s")
.setLocation(Location.newInstance(10, 0))
.build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addVehicle(v)
.addJob(s)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext jobInsertionContext =
new JobInsertionContext(route, s, v, null, 0);
LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator =
new LocalActivityInsertionCostsCalculator(
vrp.getTransportCosts(),
vrp.getActivityCosts(),
new StateManager(vrp));
double cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
new Start(v.getStartLocation(),0,Double.MAX_VALUE),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(0),
0);
assertEquals(20., cost, Math.ulp(20.));
}
@Test
public void whenAddingShipmentBetweenDiffStartAndEnd_costMustBeCorrect() {
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(20, 0))
.build();
Shipment s = Shipment.Builder.newInstance("p")
.setPickupLocation(Location.newInstance(10, 0))
.setDeliveryLocation(Location.newInstance(10, 7.5))
.build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addVehicle(v)
.addJob(s)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext jobInsertionContext =
new JobInsertionContext(route, s, v, null, 0);
LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator =
new LocalActivityInsertionCostsCalculator(
vrp.getTransportCosts(),
vrp.getActivityCosts(),
new StateManager(vrp));
double cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
new Start(v.getStartLocation(),0,Double.MAX_VALUE),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(0),
0);
assertEquals(20., cost, Math.ulp(20.));
cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
vrp.getActivities(s).get(0),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(1),
0);
assertEquals(10, cost, Math.ulp(10.));
}
@Test
public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts() {
TourActivity prevAct = mock(TourActivity.class);

View file

@ -0,0 +1,87 @@
/*
* 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.ruin;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* Created by schroeder on 13/01/17.
*/
public class StringUtilTest {
@Test
public void test() {
int stringLength = 4;
int seedIndex = 4;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(4, bounds.size());
Assert.assertEquals(1, (int) bounds.get(0));
Assert.assertEquals(2, (int) bounds.get(1));
Assert.assertEquals(3, (int) bounds.get(2));
Assert.assertEquals(4, (int) bounds.get(3));
}
@Test
public void test2() {
int stringLength = 4;
int seedIndex = 2;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(3, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
Assert.assertEquals(1, (int) bounds.get(1));
Assert.assertEquals(2, (int) bounds.get(2));
}
@Test
public void test3() {
int stringLength = 4;
int seedIndex = 0;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
}
@Test
public void test4() {
int stringLength = 4;
int seedIndex = 9;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(6, (int) bounds.get(0));
}
@Test
public void test5() {
int stringLength = 4;
int seedIndex = 8;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(2, bounds.size());
Assert.assertEquals(5, (int) bounds.get(0));
Assert.assertEquals(6, (int) bounds.get(1));
}
}

View file

@ -18,10 +18,18 @@
package com.graphhopper.jsprit.core.problem;
import com.graphhopper.jsprit.core.util.Coordinate;
import junit.framework.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.graphhopper.jsprit.core.util.Coordinate;
/**
* Created by schroeder on 16.12.14.
*/
@ -34,6 +42,12 @@ public class LocationTest {
Assert.assertTrue(true);
}
@Test
public void whenNameSet_buildLocation() {
Location l = Location.Builder.newInstance().setName("mystreet 6a").setIndex(1).build();
Assert.assertEquals("mystreet 6a",l.getName());
}
@Test
public void whenIndexSetWitFactory_returnCorrectLocation() {
Location l = Location.newInstance(1);
@ -68,19 +82,31 @@ public class LocationTest {
@Test
public void whenCoordinateSet_build() {
Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20)).build();
Assert.assertEquals(10., l.getCoordinate().getX());
Assert.assertEquals(20., l.getCoordinate().getY());
Assert.assertEquals(10., l.getCoordinate().getX(),0.001);
Assert.assertEquals(20., l.getCoordinate().getY(),0.001);
Assert.assertTrue(true);
}
@Test
public void whenCoordinateSetWithFactory_returnCorrectLocation() {
// Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build();
// Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build();
Location l = Location.newInstance(10, 20);
Assert.assertEquals(10., l.getCoordinate().getX());
Assert.assertEquals(20., l.getCoordinate().getY());
Assert.assertEquals(10., l.getCoordinate().getX(),0.001);
Assert.assertEquals(20., l.getCoordinate().getY(),0.001);
Assert.assertTrue(true);
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheLocation() {
Location one = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20))
.setUserData(new HashMap<String, Object>()).build();
Location two = Location.Builder.newInstance().setIndex(1).setUserData(42).build();
Location three = Location.Builder.newInstance().setIndex(2).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -31,6 +31,7 @@ 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.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
@ -47,7 +48,9 @@ public class MaxTimeInVehicleConstraintTest {
Delivery d1;
Shipment shipment;
Shipment s1;
Shipment s2;
Delivery d2;
@ -68,8 +71,13 @@ public class MaxTimeInVehicleConstraintTest {
private void ini(double maxTime){
d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,0)).build();
shipment = Shipment.Builder.newInstance("shipment").setPickupLocation(Location.newInstance(20,0))
s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(maxTime).build();
s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(maxTime).build();
d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(30,0)).setServiceTime(10).build();
p1 = Pickup.Builder.newInstance("p1").setLocation(Location.newInstance(10, 0)).build();
@ -77,11 +85,59 @@ public class MaxTimeInVehicleConstraintTest {
v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
vrp = VehicleRoutingProblem.Builder.newInstance().addJob(d1).addJob(shipment).addJob(d2).addJob(p1).addJob(p2)
vrp = VehicleRoutingProblem.Builder.newInstance().addJob(d1).addJob(s1).addJob(d2).addJob(p1).addJob(p2)
.addVehicle(v).build();
route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
.addDelivery(d1).addPickup(shipment).addDelivery(shipment).build();
.addDelivery(d1).addPickup(s1).addDelivery(s1).build();
}
@Test
public void shiftOfExistingShipmentsShouldWork(){
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
Shipment s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(20).build();
Shipment s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(20,0))
.setPickupServiceTime(10)
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(20).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build();
VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
.addPickup(s1).addDelivery(s1).build();
StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,s2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s2);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, act(route,0), acts.get(0), act(route,1), 20));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,1), acts.get(0), route.getEnd(), 40));
//insert pickup at 0
c.setRelatedActivityContext(new ActivityContext());
c.getRelatedActivityContext().setArrivalTime(20);
c.getRelatedActivityContext().setEndTime(30);
c.getRelatedActivityContext().setInsertionIndex(0);
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, acts.get(0), acts.get(1), act(route,0), 30));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,0), acts.get(1), act(route,1), 30));
}
private TourActivity act(VehicleRoute route, int index){
return route.getActivities().get(index);
}
@Test
@ -94,7 +150,7 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
@ -116,7 +172,7 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
@ -142,9 +198,9 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
@ -169,8 +225,8 @@ public class MaxTimeInVehicleConstraintTest {
// stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
//
// MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager);
// JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
// List<AbstractActivity> acts = vrp.getActivities(shipment);
// JobInsertionContext c = new JobInsertionContext(r,s1,v,r.getDriver(),0.);
// List<AbstractActivity> acts = vrp.getActivities(s1);
// c.getAssociatedActivities().add(acts.get(0));
// c.getAssociatedActivities().add(acts.get(1));
//
@ -192,14 +248,14 @@ public class MaxTimeInVehicleConstraintTest {
StateId latestStartId = stateManager.createStateId("latest-start-id");
Map<String,Double> maxTimes = new HashMap<>();
maxTimes.put("shipment",25d);
maxTimes.put("s1",25d);
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
@ -223,14 +279,14 @@ public class MaxTimeInVehicleConstraintTest {
StateId latestStartId = stateManager.createStateId("latest-start-id");
Map<String,Double> maxTimes = new HashMap<>();
maxTimes.put("shipment",25d);
maxTimes.put("s1",25d);
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));

View file

@ -0,0 +1,357 @@
/*
* 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.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.job.Delivery;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Pickup;
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.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.ManhattanCosts;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import static org.mockito.Mockito.mock;
/**
* Created by schroeder on 18/05/16.
*/
public class VehicleDependentTraveledDistanceTest {
StateManager stateManager;
VehicleRoute route;
StateId traveledDistanceId;
Vehicle vehicle;
Vehicle vehicle2;
VehicleRoutingProblem vrp;
Delivery d1,d2,newDelivery;
Pickup pickup;
Shipment s1;
Map<Vehicle,Double> maxDistanceMap;
@Before
public void doBefore(){
vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
vehicle2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(10,10)).build();
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,200d);
maxDistanceMap.put(vehicle2,200d);
d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,10)).build();
d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(20,15)).build();
pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(50,50)).build();
s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(35,30))
.setDeliveryLocation(Location.newInstance(20,25)).build();
newDelivery = Delivery.Builder.newInstance("new").setLocation(Location.newInstance(-10,10)).build();
vrp = VehicleRoutingProblem.Builder.newInstance()
.setRoutingCost(new ManhattanCosts()).addVehicle(vehicle).addVehicle(vehicle2)
.addJob(d1).addJob(d2).addJob(s1).addJob(pickup).addJob(newDelivery).build();
route = VehicleRoute.Builder.newInstance(vehicle).setJobActivityFactory(vrp.getJobActivityFactory())
.addDelivery(d1).addDelivery(d2).addPickup(s1).addPickup(pickup).addDelivery(s1).build();
stateManager = new StateManager(vrp);
traveledDistanceId = stateManager.createStateId("traveledDistance");
com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance traveledDistance =
new com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance(new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return new ManhattanCosts().getDistance(from,to,departureTime,vehicle);
}
},stateManager,traveledDistanceId,Arrays.asList(vehicle,vehicle2));
stateManager.addStateUpdater(traveledDistance);
stateManager.informInsertionStarts(Arrays.asList(route), Collections.<Job>emptyList());
}
@Test
public void whenEndLocationIsSet_constraintShouldWork(){
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0))
.setEndLocation(Location.newInstance(10,0)).build();
Pickup pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(10,0)).build();
vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(vehicle).addJob(pickup).build();
route = VehicleRoute.emptyRoute();
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,5d);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(new StateManager(vrp), traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,pickup,vehicle,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(),0,Double.MAX_VALUE),vrp.getActivities(pickup).get(0),
new End(vehicle.getEndLocation(),0,Double.MAX_VALUE),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
}
/*
vehicle: 200.0
vehicle (max distance): 200.0
vehicle2: 160.0
vehicle2 (max distance): 180.0
*/
@Test
public void insertNewInVehicleShouldFail(){
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
}
@Test
public void insertNewInVehicle2ShouldBeCorrect(){
//current distance vehicle2: 160 allowed: 200
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle2,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
//additional distance: 20+35-15=40
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
//additional distance: 35+65-30=70
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 65+100-35
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 100+45-55
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 45+20-25
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
private TourActivity act(int i) {
return route.getActivities().get(i);
}
private TourActivity newAct(){
return vrp.getActivities(newDelivery).get(0);
}
@Test
public void traveledDistanceShouldBeCorrect(){
Assert.assertEquals(20d,stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(35d,stateManager.getActivityState(route.getActivities().get(1),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(65d,stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(100d,stateManager.getActivityState(route.getActivities().get(3),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(155d,stateManager.getActivityState(route.getActivities().get(4),vehicle,traveledDistanceId,Double.class),0.01);
}
@Test
public void traveledDistanceWithVehicle2ShouldBeCorrect(){
Assert.assertEquals(0d,stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(15d,stateManager.getActivityState(route.getActivities().get(1),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(45d,stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(80d,stateManager.getActivityState(route.getActivities().get(3),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(135d,stateManager.getActivityState(route.getActivities().get(4),vehicle2,traveledDistanceId,Double.class),0.01);
}
@Test
public void distanceOfShipmentInRoute(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle,traveledDistanceId, Double.class);
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class);
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfShipmentInRouteVehicle2(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2,traveledDistanceId, Double.class);
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class);
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfPickupInRoute(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class);
double total = stateManager.getRouteState(route, vehicle,traveledDistanceId, Double.class);
Assert.assertEquals(100d,total-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfPickupInRouteVehicle2(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class);
double total = stateManager.getRouteState(route, vehicle2,traveledDistanceId, Double.class);
Assert.assertEquals(80d,total-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceToTravelShouldBeCorrect(){
double total = stateManager.getRouteState(route, vehicle, traveledDistanceId, Double.class);
Assert.assertEquals(180d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(165d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(135d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(100d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(45d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class), 0.01);
}
@Test
public void distanceToTravelShouldBeCorrectVehicle2(){
double total = stateManager.getRouteState(route, vehicle2, traveledDistanceId, Double.class);
Assert.assertEquals(160d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(145d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle2, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(115d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(80d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(25d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class), 0.01);
}
@Test
public void whenAddingDeliverShipment_constraintShouldWork() {
Shipment shipment = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.newInstance(0, 3))
.setDeliveryLocation(Location.newInstance(4, 0))
.build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addJob(shipment)
.addVehicle(vehicle)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,12d);
StateManager stateManager = new StateManager(vrp);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
vrp.getActivities(shipment).get(0),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
ActivityContext pickupContext = new ActivityContext();
pickupContext.setArrivalTime(3);
pickupContext.setEndTime(3);
pickupContext.setInsertionIndex(0);
context.setRelatedActivityContext(pickupContext);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
vrp.getActivities(shipment).get(0),
vrp.getActivities(shipment).get(1),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
3).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
@Test
public void whenAddingDeliverShipmentWithVehDiffStartEndLocs_constraintShouldWork() {
Shipment shipment = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.newInstance(0, 1))
.setDeliveryLocation(Location.newInstance(4, 1))
.build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(0, 4))
.build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addJob(shipment)
.addVehicle(vehicle)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,10d);
StateManager stateManager = new StateManager(vrp);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
vrp.getActivities(shipment).get(0),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
ActivityContext pickupContext = new ActivityContext();
pickupContext.setArrivalTime(1);
pickupContext.setEndTime(1);
pickupContext.setInsertionIndex(0);
context.setRelatedActivityContext(pickupContext);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
vrp.getActivities(shipment).get(0),
vrp.getActivities(shipment).get(1),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
1).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
}

View file

@ -17,11 +17,18 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
public class DeliveryTest {
@ -33,9 +40,9 @@ public class DeliveryTest {
@Test
public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() {
Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
assertEquals(2, one.getSize().getNuOfDimensions());
assertEquals(2, one.getSize().get(0));
assertEquals(4, one.getSize().get(1));
@ -45,7 +52,7 @@ public class DeliveryTest {
@Test
public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() {
Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(0, one.getSize().get(0));
}
@ -53,7 +60,7 @@ public class DeliveryTest {
@Test
public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() {
Delivery one = Delivery.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(1, one.getSize().get(0));
}
@ -61,7 +68,7 @@ public class DeliveryTest {
@Test
public void whenAddingSkills_theyShouldBeAddedCorrectly() {
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver"));
}
@ -69,7 +76,7 @@ public class DeliveryTest {
@Test
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() {
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drilL"));
}
@ -77,7 +84,7 @@ public class DeliveryTest {
@Test
public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() {
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("screwDriver").build();
.addRequiredSkill("screwDriver").build();
assertFalse(s.getRequiredSkills().containsSkill("drill"));
assertFalse(s.getRequiredSkills().containsSkill("drilL"));
}
@ -85,21 +92,21 @@ public class DeliveryTest {
@Test
public void nameShouldBeAssigned() {
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setName("name").build();
.setName("name").build();
assertEquals("name", s.getName());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly(){
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(3).build();
.setPriority(3).build();
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe(){
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.build();
.build();
Assert.assertEquals(2, s.getPriority());
}
@ -119,4 +126,16 @@ public class DeliveryTest {
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Delivery two = Delivery.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42)
.build();
Delivery three = Delivery.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,11 +17,18 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
public class PickupTest {
@ -33,9 +40,9 @@ public class PickupTest {
@Test
public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() {
Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
assertEquals(2, one.getSize().getNuOfDimensions());
assertEquals(2, one.getSize().get(0));
assertEquals(4, one.getSize().get(1));
@ -45,7 +52,7 @@ public class PickupTest {
@Test
public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() {
Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(0, one.getSize().get(0));
}
@ -53,7 +60,7 @@ public class PickupTest {
@Test
public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() {
Pickup one = Pickup.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(1, one.getSize().get(0));
}
@ -61,7 +68,7 @@ public class PickupTest {
@Test
public void whenAddingSkills_theyShouldBeAddedCorrectly() {
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver"));
@ -70,7 +77,7 @@ public class PickupTest {
@Test
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() {
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drilL"));
}
@ -78,7 +85,7 @@ public class PickupTest {
@Test
public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() {
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("screwDriver").build();
.addRequiredSkill("screwDriver").build();
assertFalse(s.getRequiredSkills().containsSkill("drill"));
assertFalse(s.getRequiredSkills().containsSkill("drilL"));
}
@ -86,7 +93,7 @@ public class PickupTest {
@Test
public void nameShouldBeAssigned() {
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setName("name").build();
.setName("name").build();
assertEquals("name", s.getName());
}
@ -94,17 +101,29 @@ public class PickupTest {
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly(){
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(3).build();
.setPriority(3).build();
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe(){
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.build();
.build();
Assert.assertEquals(2, s.getPriority());
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Pickup two = Pickup.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42).build();
Pickup three = Pickup.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
@Test(expected = UnsupportedOperationException.class)
public void whenAddingMaxTimeInVehicle_itShouldThrowEx(){
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))

View file

@ -17,17 +17,25 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
public class ServiceTest {
@ -53,7 +61,7 @@ public class ServiceTest {
Service one = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("foo")).build();
Service two = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("fo")).build();
serviceSet.add(one);
// assertTrue(serviceSet.contains(two));
// assertTrue(serviceSet.contains(two));
serviceSet.remove(two);
assertTrue(serviceSet.isEmpty());
}
@ -67,16 +75,16 @@ public class ServiceTest {
@Test
public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() {
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
assertEquals(2, one.getSize().getNuOfDimensions());
}
@Test
public void whenShipmentIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() {
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(0, one.getSize().get(0));
}
@ -84,7 +92,7 @@ public class ServiceTest {
@Test
public void whenShipmentIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() {
Service one = Service.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo"))
.build();
.build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(1, one.getSize().get(0));
}
@ -116,71 +124,71 @@ public class ServiceTest {
}
@Test
public void whenSettingLocationCoord_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance(1, 2)).build();
assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01);
assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01);
@Test
public void whenSettingLocationCoord_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance(1, 2)).build();
assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01);
assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01);
}
assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01);
assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01);
}
@Test(expected=IllegalArgumentException.class)
public void whenSettingNeitherLocationIdNorCoord_throwsException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").build();
}
@Test(expected=IllegalArgumentException.class)
public void whenSettingNeitherLocationIdNorCoord_throwsException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").build();
}
@Test(expected=IllegalArgumentException.class)
public void whenServiceTimeSmallerZero_throwIllegalStateException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(-1).build();
}
@Test(expected=IllegalArgumentException.class)
public void whenServiceTimeSmallerZero_throwIllegalStateException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(-1).build();
}
@Test
public void whenSettingServiceTime_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(1).build();
assertEquals(1.0,s.getServiceDuration(),0.01);
}
@Test
public void whenSettingServiceTime_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(1).build();
assertEquals(1.0,s.getServiceDuration(),0.01);
}
@Test(expected=IllegalArgumentException.class)
public void whenTimeWindowIsNull_throwException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(null).build();
}
@Test(expected=IllegalArgumentException.class)
public void whenTimeWindowIsNull_throwException(){
@SuppressWarnings("unused")
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(null).build();
}
@Test
public void whenSettingTimeWindow_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build();
assertEquals(1.0,s.getTimeWindow().getStart(),0.01);
assertEquals(2.0,s.getTimeWindow().getEnd(),0.01);
}
@Test
public void whenSettingTimeWindow_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build();
assertEquals(1.0,s.getTimeWindow().getStart(),0.01);
assertEquals(2.0,s.getTimeWindow().getEnd(),0.01);
}
@Test
public void whenAddingSkills_theyShouldBeAddedCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver"));
}
@Test
public void whenAddingSkills_theyShouldBeAddedCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver"));
}
@Test
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drilL"));
}
@Test
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drilL"));
}
@Test
public void whenAddingSeveralTimeWindows_itShouldBeSetCorrectly(){
TimeWindow tw1 = TimeWindow.newInstance(1.0, 2.0);
TimeWindow tw2 = TimeWindow.newInstance(3.0, 5.0);
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(tw1)
.addTimeWindow(tw2)
.build();
.addTimeWindow(tw1)
.addTimeWindow(tw2)
.build();
assertEquals(2, s.getTimeWindows().size());
assertThat(s.getTimeWindows(),hasItem(is(tw1)));
assertThat(s.getTimeWindows(),hasItem(is(tw2)));
@ -189,7 +197,7 @@ public class ServiceTest {
@Test
public void whenAddingTimeWindow_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build();
.addTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build();
assertEquals(1.0, s.getTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getTimeWindow().getEnd(), 0.01);
}
@ -200,7 +208,7 @@ public class ServiceTest {
@Test
public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() {
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addRequiredSkill("screwDriver").build();
.addRequiredSkill("screwDriver").build();
assertFalse(s.getRequiredSkills().containsSkill("drill"));
assertFalse(s.getRequiredSkills().containsSkill("drilL"));
}
@ -208,66 +216,73 @@ public class ServiceTest {
@Test
public void nameShouldBeAssigned() {
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setName("name").build();
.setName("name").build();
assertEquals("name", s.getName());
}
@Test
public void shouldKnowMultipleTimeWindows(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(0., 10.)).addTimeWindow(TimeWindow.newInstance(20., 30.))
.setName("name").build();
assertEquals(2,s.getTimeWindows().size());
}
@Test
public void shouldKnowMultipleTimeWindows(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(0., 10.)).addTimeWindow(TimeWindow.newInstance(20., 30.))
.setName("name").build();
assertEquals(2,s.getTimeWindows().size());
}
@Test(expected = IllegalArgumentException.class)
public void whenMultipleTWOverlap_throwEx(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(0.,10.))
.addTimeWindow(TimeWindow.newInstance(5., 30.))
.setName("name").build();
}
@Test(expected = IllegalArgumentException.class)
public void whenMultipleTWOverlap_throwEx(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(0.,10.))
.addTimeWindow(TimeWindow.newInstance(5., 30.))
.setName("name").build();
}
@Test(expected = IllegalArgumentException.class)
public void whenMultipleTWOverlap2_throwEx(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(20., 30.))
.addTimeWindow(TimeWindow.newInstance(0., 25.))
.setName("name").build();
}
@Test(expected = IllegalArgumentException.class)
public void whenMultipleTWOverlap2_throwEx(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.addTimeWindow(TimeWindow.newInstance(20., 30.))
.addTimeWindow(TimeWindow.newInstance(0., 25.))
.setName("name").build();
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(1).build();
.setPriority(1).build();
Assert.assertEquals(1, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly2(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(3).build();
.setPriority(3).build();
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(10).build();
Assert.assertEquals(10, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.build();
.build();
Assert.assertEquals(2, s.getPriority());
}
@Test(expected = IllegalArgumentException.class)
public void whenSettingIncorrectPriorities_itShouldThrowException(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(30).build();
.setPriority(30).build();
}
@Test(expected = IllegalArgumentException.class)
public void whenSettingIncorrectPriorities_itShouldThrowException2(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(0).build();
.setPriority(0).build();
}
@ -285,4 +300,17 @@ public class ServiceTest {
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Service two = Service.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42)
.build();
Service three = Service.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,25 +17,34 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.util.Coordinate;
import com.graphhopper.jsprit.core.util.TestUtils;
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.*;
public class ShipmentTest {
@Test
public void whenTwoShipmentsHaveTheSameId_theyReferencesShouldBeUnEqual() {
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()).
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
Shipment two = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()).
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
assertTrue(one != two);
}
@ -43,9 +52,9 @@ public class ShipmentTest {
@Test
public void whenTwoShipmentsHaveTheSameId_theyShouldBeEqual() {
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()).
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
Shipment two = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()).
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
assertTrue(one.equals(two));
}
@ -53,7 +62,7 @@ public class ShipmentTest {
@Test
public void whenShipmentIsInstantiatedWithASizeOf10_theSizeShouldBe10() {
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()).
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build();
assertEquals(10, one.getSize().get(0));
}
@ -61,24 +70,24 @@ public class ShipmentTest {
public void whenShipmentIsBuiltWithNegativeDemand_itShouldThrowException() {
@SuppressWarnings("unused")
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, -10)
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
}
@Test(expected = IllegalArgumentException.class)
public void whenShipmentIsBuiltWithNegativeDemand_itShouldThrowException_v2() {
@SuppressWarnings("unused")
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, -10)
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
}
@Test(expected = IllegalArgumentException.class)
public void whenIdIsNull_itShouldThrowException() {
@SuppressWarnings("unused")
Shipment one = Shipment.Builder.newInstance(null).addSizeDimension(0, 10)
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
.setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
}
@Test
@ -115,7 +124,7 @@ public class ShipmentTest {
@Test
public void whenPickupCoordIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s")
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").setCoordinate(Coordinate.newInstance(1, 2)).build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").setCoordinate(Coordinate.newInstance(1, 2)).build()).build();
assertEquals(1.0, s.getPickupLocation().getCoordinate().getX(), 0.01);
assertEquals(2.0, s.getPickupLocation().getCoordinate().getY(), 0.01);
assertEquals(1.0, s.getPickupLocation().getCoordinate().getX(), 0.01);
@ -126,7 +135,7 @@ public class ShipmentTest {
@Test
public void whenDeliveryLocationIdIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s")
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals("delLoc", s.getDeliveryLocation().getId());
assertEquals("delLoc", s.getDeliveryLocation().getId());
}
@ -135,8 +144,8 @@ public class ShipmentTest {
@Test
public void whenDeliveryCoordIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(1, 2)))
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
.build();
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
.build();
assertEquals(1.0, s.getDeliveryLocation().getCoordinate().getX(), 0.01);
assertEquals(2.0, s.getDeliveryLocation().getCoordinate().getY(), 0.01);
assertEquals(1.0, s.getDeliveryLocation().getCoordinate().getX(), 0.01);
@ -146,22 +155,22 @@ public class ShipmentTest {
@Test
public void whenPickupServiceTimeIsNotSet_itShouldBeZero() {
Shipment s = Shipment.Builder.newInstance("s")
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(0.0, s.getPickupServiceTime(), 0.01);
}
@Test
public void whenDeliveryServiceTimeIsNotSet_itShouldBeZero() {
Shipment s = Shipment.Builder.newInstance("s")
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(0.0, s.getDeliveryServiceTime(), 0.01);
}
@Test
public void whenPickupServiceTimeIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s")
.setPickupServiceTime(2.0)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setPickupServiceTime(2.0)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(2.0, s.getPickupServiceTime(), 0.01);
}
@ -169,13 +178,13 @@ public class ShipmentTest {
public void whenPickupServiceIsSmallerThanZero_itShouldThrowException() {
@SuppressWarnings("unused")
Shipment s = Shipment.Builder.newInstance("s").setPickupServiceTime(-2.0)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
}
@Test
public void whenDeliveryServiceTimeIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setDeliveryServiceTime(2.0)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(2.0, s.getDeliveryServiceTime(), 0.01);
}
@ -201,7 +210,7 @@ public class ShipmentTest {
@Test
public void whenPickupTimeWindowIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setPickupTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01);
}
@ -222,7 +231,7 @@ public class ShipmentTest {
@Test
public void whenDeliveryTimeWindowIsSet_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setDeliveryTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01);
}
@ -230,7 +239,7 @@ public class ShipmentTest {
@Test
public void whenUsingAddDeliveryTimeWindow_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01);
}
@ -238,7 +247,7 @@ public class ShipmentTest {
@Test
public void whenUsingAddDeliveryTimeWindow2_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(1, 2)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01);
}
@ -248,7 +257,7 @@ public class ShipmentTest {
TimeWindow tw1 = TimeWindow.newInstance(1,2);
TimeWindow tw2 = TimeWindow.newInstance(4,5);
Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(tw1).addDeliveryTimeWindow(tw2)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(s.getDeliveryTimeWindows().size(),2);
assertThat(s.getDeliveryTimeWindows(),hasItem(is(tw1)));
assertThat(s.getDeliveryTimeWindows(),hasItem(is(tw2)));
@ -257,7 +266,7 @@ public class ShipmentTest {
@Test(expected = IllegalArgumentException.class)
public void whenAddingMultipleOverlappingDeliveryTimeWindows_itShouldThrowException() {
Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(1, 3).addDeliveryTimeWindow(2,5)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01);
}
@ -267,7 +276,7 @@ public class ShipmentTest {
@Test
public void whenUsingAddPickupTimeWindow_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01);
}
@ -275,7 +284,7 @@ public class ShipmentTest {
@Test
public void whenUsingAddPickupTimeWindow2_itShouldBeDoneCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(1, 2)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01);
}
@ -285,7 +294,7 @@ public class ShipmentTest {
TimeWindow tw1 = TimeWindow.newInstance(1,2);
TimeWindow tw2 = TimeWindow.newInstance(4,5);
Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(tw1).addPickupTimeWindow(tw2)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(s.getPickupTimeWindows().size(),2);
assertThat(s.getPickupTimeWindows(), hasItem(is(tw1)));
assertThat(s.getPickupTimeWindows(), hasItem(is(tw2)));
@ -294,7 +303,7 @@ public class ShipmentTest {
@Test(expected = IllegalArgumentException.class)
public void whenAddingMultipleOverlappingPickupTimeWindows_itShouldThrowException() {
Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(1, 3).addPickupTimeWindow(2,5)
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
.setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build();
assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01);
assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01);
}
@ -305,26 +314,26 @@ public class ShipmentTest {
public void whenShipmentHasNegativeCapacityVal_throwIllegalStateExpception() {
@SuppressWarnings("unused")
Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo"))
.addSizeDimension(0, -2)
.build();
.setDeliveryLocation(TestUtils.loc("foofoo"))
.addSizeDimension(0, -2)
.build();
}
@Test
public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() {
Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("foo").build())
.setDeliveryLocation(TestUtils.loc("foofoo"))
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
.setDeliveryLocation(TestUtils.loc("foofoo"))
.addSizeDimension(0, 2)
.addSizeDimension(1, 4)
.build();
assertEquals(2, one.getSize().getNuOfDimensions());
}
@Test
public void whenShipmentIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() {
Shipment one = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
.setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(0, one.getSize().get(0));
}
@ -332,8 +341,8 @@ public class ShipmentTest {
@Test
public void whenShipmentIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() {
Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 1)
.setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
.setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build())
.setDeliveryLocation(TestUtils.loc("foofoo")).build();
assertEquals(1, one.getSize().getNuOfDimensions());
assertEquals(1, one.getSize().get(0));
}
@ -341,8 +350,8 @@ public class ShipmentTest {
@Test
public void whenAddingSkills_theyShouldBeAddedCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build())
.setDeliveryLocation(TestUtils.loc("delLoc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
.setDeliveryLocation(TestUtils.loc("delLoc"))
.addRequiredSkill("drill").addRequiredSkill("screwdriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver"));
@ -351,9 +360,9 @@ public class ShipmentTest {
@Test
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() {
Shipment s = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.Builder.newInstance().setId("pick").build())
.setDeliveryLocation(TestUtils.loc("del"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
.setPickupLocation(Location.Builder.newInstance().setId("pick").build())
.setDeliveryLocation(TestUtils.loc("del"))
.addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build();
assertTrue(s.getRequiredSkills().containsSkill("drill"));
assertTrue(s.getRequiredSkills().containsSkill("drilL"));
}
@ -361,8 +370,8 @@ public class ShipmentTest {
@Test
public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build())
.setDeliveryLocation(TestUtils.loc("del"))
.addRequiredSkill("screwDriver").build();
.setDeliveryLocation(TestUtils.loc("del"))
.addRequiredSkill("screwDriver").build();
assertFalse(s.getRequiredSkills().containsSkill("drill"));
assertFalse(s.getRequiredSkills().containsSkill("drilL"));
}
@ -370,15 +379,15 @@ public class ShipmentTest {
@Test
public void nameShouldBeAssigned() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build())
.setDeliveryLocation(TestUtils.loc("del"))
.setName("name").build();
.setDeliveryLocation(TestUtils.loc("del"))
.setName("name").build();
assertEquals("name", s.getName());
}
@Test
public void whenSettingLocation_itShouldWork() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build())
.setDeliveryLocation(Location.Builder.newInstance().setId("del").build()).build();
.setDeliveryLocation(Location.Builder.newInstance().setId("del").build()).build();
assertEquals("loc", s.getPickupLocation().getId());
assertEquals("loc", s.getPickupLocation().getId());
assertEquals("del", s.getDeliveryLocation().getId());
@ -388,43 +397,64 @@ public class ShipmentTest {
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(1).build();
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(1).build();
Assert.assertEquals(1, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly2(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(3).build();
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(3).build();
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(10).build();
Assert.assertEquals(10, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.build();
.setDeliveryLocation(Location.newInstance("loc"))
.build();
Assert.assertEquals(2, s.getPriority());
}
@Test(expected = IllegalArgumentException.class)
public void whenSettingIncorrectPriorities_itShouldThrowException(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(30).build();
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(30).build();
}
@Test(expected = IllegalArgumentException.class)
public void whenSettingIncorrectPriorities_itShouldThrowException2(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(0).build();
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(0).build();
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).setUserData(new HashMap<String, Object>()).build();
Shipment two = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).setUserData(42).build();
Shipment three = Shipment.Builder.newInstance("s3").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
@Test
public void whenAddingMaxTimeInVehicle_itShouldBeSet(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")).setDeliveryLocation(Location.newInstance("loc"))

View file

@ -18,12 +18,20 @@
package com.graphhopper.jsprit.core.problem.vehicle;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.job.Break;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import org.junit.Test;
import static org.junit.Assert.*;
public class VehicleImplTest {
@ -39,10 +47,10 @@ public class VehicleImplTest {
@Test
public void whenAddingDriverBreak_itShouldBeAddedCorrectly() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Break aBreak = (Break) Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build();
Break aBreak = Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start"))
.setType(type1).setEndLocation(Location.newInstance("start"))
.setBreak(aBreak).build();
.setType(type1).setEndLocation(Location.newInstance("start"))
.setBreak(aBreak).build();
assertNotNull(v.getBreak());
assertEquals(100., v.getBreak().getTimeWindow().getStart(), 0.1);
assertEquals(200., v.getBreak().getTimeWindow().getEnd(), 0.1);
@ -54,7 +62,7 @@ public class VehicleImplTest {
public void whenAddingSkills_theyShouldBeAddedCorrectly() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start"))
.addSkill("drill").addSkill("screwdriver").build();
.addSkill("drill").addSkill("screwdriver").build();
assertTrue(v.getSkills().containsSkill("drill"));
assertTrue(v.getSkills().containsSkill("drill"));
assertTrue(v.getSkills().containsSkill("screwdriver"));
@ -64,7 +72,7 @@ public class VehicleImplTest {
public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start"))
.addSkill("drill").addSkill("screwdriver").build();
.addSkill("drill").addSkill("screwdriver").build();
assertTrue(v.getSkills().containsSkill("drill"));
assertTrue(v.getSkills().containsSkill("dRill"));
assertTrue(v.getSkills().containsSkill("ScrewDriver"));
@ -233,9 +241,23 @@ public class VehicleImplTest {
public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start"))
.addSkill("drill").build();
.addSkill("drill").build();
assertFalse(v.getSkills().containsSkill("ScrewDriver"));
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheVehicle() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Vehicle one = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).setUserData(new HashMap<String, Object>()).build();
Vehicle two = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).setUserData(42).build();
Vehicle three = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,9 +17,15 @@
*/
package com.graphhopper.jsprit.core.problem.vehicle;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class VehicleTypeImplTest {
@ -32,18 +38,18 @@ public class VehicleTypeImplTest {
@Test
public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() {
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t")
.addCapacityDimension(0, 2)
.addCapacityDimension(1, 4)
.build();
.addCapacityDimension(0, 2)
.addCapacityDimension(1, 4)
.build();
assertEquals(2, type.getCapacityDimensions().getNuOfDimensions());
}
@Test
public void whenAddingTwoCapDimension_dimValuesMustBeCorrect() {
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t")
.addCapacityDimension(0, 2)
.addCapacityDimension(1, 4)
.build();
.addCapacityDimension(0, 2)
.addCapacityDimension(1, 4)
.build();
assertEquals(2, type.getCapacityDimensions().get(0));
assertEquals(4, type.getCapacityDimensions().get(1));
}
@ -152,4 +158,15 @@ public class VehicleTypeImplTest {
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheVehicleType() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").setUserData(new HashMap<String, Object>())
.build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").setUserData(42).build();
VehicleType three = VehicleTypeImpl.Builder.newInstance("type").build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -40,6 +40,7 @@ public class FastVehicleRoutingTransportCostsMatrixTest {
assertEquals(2., matrix.getDistance(2, 1), 0.1);
}
@Test
public void whenAddingDistanceToAsymmetricMatrix_itShouldReturnCorrectValues() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false);
@ -62,6 +63,18 @@ public class FastVehicleRoutingTransportCostsMatrixTest {
assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1);
}
@Test
public void whenAddingTimeAndDistanceToSymmetricMatrix_itShouldReturnCorrectValues2() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, true);
matrixBuilder.addTransportTimeAndDistance(1, 2, 2.,100.);
FastVehicleRoutingTransportCostsMatrix matrix = matrixBuilder.build();
assertEquals(2., matrix.getTransportTime(loc(1), loc(2), 0.0, null, null), 0.1);
assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1);
assertEquals(100., matrix.getDistance(loc(1), loc(2), 0.0, null), 0.1);
assertEquals(100., matrix.getDistance(loc(2), loc(1), 0.0, null), 0.1);
}
@Test
public void whenAddingTimeToAsymmetricMatrix_itShouldReturnCorrectValues() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false);

View file

@ -0,0 +1,156 @@
/*
* 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.util;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
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.MaxDistanceConstraint;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
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 org.apache.commons.math3.stat.Frequency;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by schroeder on 06/02/17.
*/
public class UnassignedJobReasonTrackerTest {
Vehicle vehicle;
@Before
public void doBefore() {
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(0, 1);
VehicleType vehicleType = vehicleTypeBuilder.build();
VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle");
vehicleBuilder.setStartLocation(Location.newInstance(10, 10));
vehicleBuilder.setType(vehicleType);
vehicleBuilder.setEarliestStart(0).setLatestArrival(100);
vehicle = vehicleBuilder.build();
}
@Test
public void shouldReturnCorrectCapacityReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 5).setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(3, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectSkillReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).addRequiredSkill("ice").setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(1, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectTWReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).setTimeWindow(TimeWindow.newInstance(110, 200)).setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(2, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectMaxDistanceReasonCode() {
Service service = Service.Builder.newInstance("1").setLocation(Location.newInstance(51, 0)).build();
Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service).build();
StateManager stateManager = new StateManager(vrp);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
StateId maxDistance = stateManager.createStateId("max-distance");
Map<Vehicle, Double> distMap = new HashMap<>();
distMap.put(vehicle, 100d);
MaxDistanceConstraint distanceConstraint = new MaxDistanceConstraint(stateManager, maxDistance, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportCost(from, to, departureTime, null, vehicle);
}
}, distMap);
constraintManager.addConstraint(distanceConstraint, ConstraintManager.Priority.CRITICAL);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager, constraintManager)
.buildAlgorithm();
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void testFreq() {
Frequency frequency = new Frequency();
frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
frequency.addValue("b");
frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = frequency.entrySetIterator();
while (entryIterator.hasNext()) {
Map.Entry<Comparable<?>, Long> e = entryIterator.next();
System.out.println(e.getKey().toString() + " " + e.getValue());
}
}
}