diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/PrettyAlgorithmBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/PrettyAlgorithmBuilder.java index 11d85821..2f38413c 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/PrettyAlgorithmBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/PrettyAlgorithmBuilder.java @@ -91,8 +91,8 @@ public class PrettyAlgorithmBuilder { constraintManager.addSkillsConstraint(); stateManager.updateLoadStates(); stateManager.updateTimeWindowStates(); - UpdateVehicleDependentPracticalTimeWindows tw_updater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts()); - tw_updater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { + UpdateVehicleDependentPracticalTimeWindows twUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts()); + twUpdater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { Map uniqueTypes = new HashMap(); @@ -109,12 +109,14 @@ public class PrettyAlgorithmBuilder { vehicles.addAll(uniqueTypes.values()); return vehicles; } + }); - stateManager.addStateUpdater(tw_updater); + stateManager.addStateUpdater(twUpdater); stateManager.updateSkillStates(); stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen()); stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS)); stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager)); + stateManager.addStateUpdater(new UpdateFutureWaitingTimes(stateManager,vrp.getTransportCosts())); } VehicleRoutingAlgorithm vra = new VehicleRoutingAlgorithm(vrp, searchStrategyManager); vra.addListener(stateManager); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index 7eeaa909..8ac7512b 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -20,6 +20,7 @@ import jsprit.core.algorithm.SearchStrategy.DiscoveredSolution; import jsprit.core.algorithm.listener.*; import jsprit.core.algorithm.termination.PrematureAlgorithmTermination; import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.job.Job; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.activity.TourActivity; @@ -35,6 +36,7 @@ import java.util.Collection; * Algorithm that solves a {@link VehicleRoutingProblem}. * * @author stefan schroeder + * */ public class VehicleRoutingAlgorithm { @@ -42,14 +44,14 @@ public class VehicleRoutingAlgorithm { private Collection terminationCriteria = new ArrayList(); - void addTermination(PrematureAlgorithmTermination termination) { + void addTermination(PrematureAlgorithmTermination termination){ terminationCriteria.add(termination); } @Override public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { - for (PrematureAlgorithmTermination termination : terminationCriteria) { - if (termination.isPrematureBreak(discoveredSolution)) { + for(PrematureAlgorithmTermination termination : terminationCriteria){ + if(termination.isPrematureBreak(discoveredSolution)){ return true; } } @@ -194,14 +196,15 @@ public class VehicleRoutingAlgorithm { Collection solutions = new ArrayList(initialSolutions); algorithmStarts(problem, solutions); bestEver = Solutions.bestOf(solutions); + if(logger.isTraceEnabled()) log(solutions); logger.info("iterations start"); - for (int i = 0; i < maxIterations; i++) { - iterationStarts(i + 1, problem, solutions); - logger.debug("start iteration: {}", i); - counter.incCounter(); - SearchStrategy strategy = searchStrategyManager.getRandomStrategy(); - DiscoveredSolution discoveredSolution = strategy.run(problem, solutions); - logger.trace("discovered solution: {}", discoveredSolution); + for(int i=0;i< maxIterations;i++){ + iterationStarts(i+1,problem,solutions); + logger.debug("start iteration: {}",i); + counter.incCounter(); + SearchStrategy strategy = searchStrategyManager.getRandomStrategy(); + DiscoveredSolution discoveredSolution = strategy.run(problem, solutions); + if(logger.isTraceEnabled()) log(discoveredSolution); memorizeIfBestEver(discoveredSolution); selectedStrategy(discoveredSolution, problem, solutions); if (terminationManager.isPrematureBreak(discoveredSolution)) { @@ -222,6 +225,39 @@ public class VehicleRoutingAlgorithm { if (bestEver != null) solutions.add(bestEver); } + private void log(Collection solutions) { + for(VehicleRoutingProblemSolution sol : solutions) log(sol); + } + + private void log(VehicleRoutingProblemSolution solution){ + logger.trace("solution costs: {}",solution.getCost()); + for(VehicleRoute r : solution.getRoutes()){ + StringBuilder b = new StringBuilder(); + b.append(r.getVehicle().getId()).append(" : ").append("[ "); + for(TourActivity act : r.getActivities()){ + if(act instanceof TourActivity.JobActivity){ + b.append(((TourActivity.JobActivity) act).getJob().getId()).append(" "); + } + } + b.append("]"); + logger.trace(b.toString()); + } + StringBuilder b = new StringBuilder(); + b.append("unassigned : [ "); + for(Job j : solution.getUnassignedJobs()){ + b.append(j.getId()).append(" "); + } + b.append("]"); + logger.trace(b.toString()); + } + + private void log(DiscoveredSolution discoveredSolution) { + logger.trace("discovered solution: {}",discoveredSolution); + log(discoveredSolution.getSolution()); + } + + + private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) { if (discoveredSolution == null) return; if (bestEver == null) bestEver = discoveredSolution.getSolution(); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java index 144e24a1..3bbfeb86 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java @@ -40,11 +40,11 @@ public class Jsprit { String name; - Construction(String name) { + Construction(String name){ this.name = name; } - public String toString() { + public String toString(){ return name; } @@ -63,11 +63,11 @@ public class Jsprit { String strategyName; - Strategy(String strategyName) { + Strategy(String strategyName){ this.strategyName = strategyName; } - public String toString() { + public String toString(){ return strategyName; } } @@ -75,7 +75,7 @@ public class Jsprit { public enum Parameter { FIXED_COST_PARAM("fixed_cost_param"), VEHICLE_SWITCH("vehicle_switch"), REGRET_TIME_WINDOW_SCORER("regret.tw_scorer"), - REGRET_DISTANCE_SCORER("regret.distance_scorer"), INITIAL_THRESHOLD("initial_threshold"), ITERATIONS("iterations"), + REGRET_DISTANCE_SCORER("regret.distance_scorer"), INITIAL_THRESHOLD("initial_threshold"), ITERATIONS("iterations"), THREADS("threads"), RANDOM_REGRET_MIN_SHARE("random_regret.min_share"), RANDOM_REGRET_MAX_SHARE("random_regret.max_share"), @@ -97,17 +97,17 @@ public class Jsprit { String paraName; - Parameter(String name) { + Parameter(String name){ this.paraName = name; } - public String toString() { + public String toString(){ return paraName; } } - public static VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vehicleRoutingProblem) { + public static VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vehicleRoutingProblem){ return Jsprit.Builder.newInstance(vehicleRoutingProblem).buildAlgorithm(); } @@ -131,53 +131,53 @@ public class Jsprit { private Random random = RandomNumberGeneration.newInstance(); - public static Builder newInstance(VehicleRoutingProblem vrp) { + public static Builder newInstance(VehicleRoutingProblem vrp){ return new Builder(vrp); } - private Builder(VehicleRoutingProblem vrp) { + private Builder(VehicleRoutingProblem vrp){ this.vrp = vrp; properties = new Properties(createDefaultProperties()); } private Properties createDefaultProperties() { Properties defaults = new Properties(); - defaults.put(Strategy.RADIAL_BEST.toString(), "0."); - defaults.put(Strategy.RADIAL_REGRET.toString(), ".5"); - defaults.put(Strategy.RANDOM_BEST.toString(), ".5"); - defaults.put(Strategy.RANDOM_REGRET.toString(), ".5"); - 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"); - defaults.put(Parameter.REGRET_DISTANCE_SCORER.toString(), ".05"); - defaults.put(Parameter.REGRET_TIME_WINDOW_SCORER.toString(), "-.1"); - defaults.put(Parameter.THREADS.toString(), "1"); - int minShare = (int) Math.min(20, Math.max(3, vrp.getJobs().size() * 0.05)); - int maxShare = (int) Math.min(50, Math.max(5, vrp.getJobs().size() * 0.3)); - defaults.put(Parameter.RADIAL_MIN_SHARE.toString(), String.valueOf(minShare)); - defaults.put(Parameter.RADIAL_MAX_SHARE.toString(), String.valueOf(maxShare)); - defaults.put(Parameter.WORST_MIN_SHARE.toString(), String.valueOf(minShare)); - defaults.put(Parameter.WORST_MAX_SHARE.toString(), String.valueOf(maxShare)); - defaults.put(Parameter.CLUSTER_MIN_SHARE.toString(), String.valueOf(minShare)); - defaults.put(Parameter.CLUSTER_MAX_SHARE.toString(), String.valueOf(maxShare)); - int minShare_ = (int) Math.min(70, Math.max(5, vrp.getJobs().size() * 0.5)); - int maxShare_ = (int) Math.min(70, Math.max(5, vrp.getJobs().size() * 0.5)); - defaults.put(Parameter.RANDOM_REGRET_MIN_SHARE.toString(), String.valueOf(minShare_)); - defaults.put(Parameter.RANDOM_REGRET_MAX_SHARE.toString(), String.valueOf(maxShare_)); - defaults.put(Parameter.RANDOM_BEST_MIN_SHARE.toString(), String.valueOf(minShare_)); - defaults.put(Parameter.RANDOM_BEST_MAX_SHARE.toString(), String.valueOf(maxShare_)); - defaults.put(Parameter.THRESHOLD_ALPHA.toString(), String.valueOf(0.15)); - defaults.put(Parameter.THRESHOLD_INI.toString(), String.valueOf(0.03)); - defaults.put(Parameter.INSERTION_NOISE_LEVEL.toString(), String.valueOf(0.15)); - defaults.put(Parameter.INSERTION_NOISE_PROB.toString(), String.valueOf(0.2)); - defaults.put(Parameter.RUIN_WORST_NOISE_LEVEL.toString(), String.valueOf(0.15)); - defaults.put(Parameter.RUIN_WORST_NOISE_PROB.toString(), String.valueOf(0.2)); - defaults.put(Parameter.VEHICLE_SWITCH.toString(), String.valueOf(true)); - defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString()); + defaults.put(Strategy.RADIAL_BEST.toString(),"0."); + defaults.put(Strategy.RADIAL_REGRET.toString(),".5"); + defaults.put(Strategy.RANDOM_BEST.toString(),".5"); + defaults.put(Strategy.RANDOM_REGRET.toString(),".5"); + 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"); + defaults.put(Parameter.REGRET_DISTANCE_SCORER.toString(),".05"); + defaults.put(Parameter.REGRET_TIME_WINDOW_SCORER.toString(),"-.1"); + defaults.put(Parameter.THREADS.toString(),"1"); + int minShare = (int)Math.min(20, Math.max(3,vrp.getJobs().size() * 0.05)); + int maxShare = (int)Math.min(50, Math.max(5,vrp.getJobs().size() * 0.3)); + defaults.put(Parameter.RADIAL_MIN_SHARE.toString(),String.valueOf(minShare)); + defaults.put(Parameter.RADIAL_MAX_SHARE.toString(),String.valueOf(maxShare)); + defaults.put(Parameter.WORST_MIN_SHARE.toString(),String.valueOf(minShare)); + defaults.put(Parameter.WORST_MAX_SHARE.toString(),String.valueOf(maxShare)); + defaults.put(Parameter.CLUSTER_MIN_SHARE.toString(),String.valueOf(minShare)); + defaults.put(Parameter.CLUSTER_MAX_SHARE.toString(),String.valueOf(maxShare)); + int minShare_ = (int)Math.min(70, Math.max(5,vrp.getJobs().size() * 0.5)); + int maxShare_ = (int)Math.min(70, Math.max(5,vrp.getJobs().size() * 0.5)); + defaults.put(Parameter.RANDOM_REGRET_MIN_SHARE.toString(),String.valueOf(minShare_)); + defaults.put(Parameter.RANDOM_REGRET_MAX_SHARE.toString(),String.valueOf(maxShare_)); + defaults.put(Parameter.RANDOM_BEST_MIN_SHARE.toString(),String.valueOf(minShare_)); + defaults.put(Parameter.RANDOM_BEST_MAX_SHARE.toString(),String.valueOf(maxShare_)); + defaults.put(Parameter.THRESHOLD_ALPHA.toString(),String.valueOf(0.15)); + defaults.put(Parameter.THRESHOLD_INI.toString(),String.valueOf(0.03)); + defaults.put(Parameter.INSERTION_NOISE_LEVEL.toString(),String.valueOf(0.15)); + defaults.put(Parameter.INSERTION_NOISE_PROB.toString(),String.valueOf(0.2)); + defaults.put(Parameter.RUIN_WORST_NOISE_LEVEL.toString(),String.valueOf(0.15)); + defaults.put(Parameter.RUIN_WORST_NOISE_PROB.toString(),String.valueOf(0.2)); + defaults.put(Parameter.VEHICLE_SWITCH.toString(),String.valueOf(true)); + defaults.put(Parameter.CONSTRUCTION.toString(),Construction.REGRET_INSERTION.toString()); return defaults; } @@ -188,23 +188,23 @@ public class Jsprit { return this; } - public Builder setRandom(Random random) { + public Builder setRandom(Random random){ this.random = random; return this; } - public Builder setProperty(String key, String value) { - properties.put(key, value); + public Builder setProperty(String key, String value){ + properties.put(key,value); return this; } - public Builder setProperty(Parameter parameter, String value) { - setProperty(parameter.toString(), value); + public Builder setProperty(Parameter parameter, String value){ + setProperty(parameter.toString(),value); return this; } - public Builder setProperty(Strategy strategy, String value) { - setProperty(strategy.toString(), value); + public Builder setProperty(Strategy strategy, String value){ + setProperty(strategy.toString(),value); return this; } @@ -224,7 +224,7 @@ public class Jsprit { return this; } - public VehicleRoutingAlgorithm buildAlgorithm() { + public VehicleRoutingAlgorithm buildAlgorithm(){ return new Jsprit(this).create(vrp); } @@ -245,15 +245,13 @@ public class Jsprit { } public RuinShareFactoryImpl(int minShare, int maxShare) { - if (maxShare < minShare) - throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); + if(maxShare < minShare) throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); this.minShare = minShare; this.maxShare = maxShare; } public RuinShareFactoryImpl(int minShare, int maxShare, Random random) { - if (maxShare < minShare) - throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); + if(maxShare < minShare) throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); this.minShare = minShare; this.maxShare = maxShare; this.random = random; @@ -295,17 +293,18 @@ public class Jsprit { this.random = builder.random; } - private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) { + private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp){ VehicleFleetManager fm; - if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) { + if(vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)){ fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); - } else fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); + } + else fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); - if (stateManager == null) { + if(stateManager == null){ stateManager = new StateManager(vrp); } - if (constraintManager == null) { - constraintManager = new ConstraintManager(vrp, stateManager); + if(constraintManager == null){ + constraintManager = new ConstraintManager(vrp,stateManager); } double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString())); @@ -317,36 +316,36 @@ public class Jsprit { JobNeighborhoods jobNeighborhoods = new JobNeighborhoodsFactory().createNeighborhoods(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts()), (int) (vrp.getJobs().values().size() * 0.5)); jobNeighborhoods.initialise(); - RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods); + RuinRadial radial = new RuinRadial(vrp,vrp.getJobs().size(),jobNeighborhoods); radial.setRandom(random); radial.setRuinShareFactory(new RuinShareFactoryImpl( toInteger(properties.getProperty(Parameter.RADIAL_MIN_SHARE.toString())), toInteger(properties.getProperty(Parameter.RADIAL_MAX_SHARE.toString())), - random) + random) ); - final RuinRandom random_for_regret = new RuinRandom(vrp, 0.5); + final RuinRandom random_for_regret = new RuinRandom(vrp,0.5); random_for_regret.setRandom(random); random_for_regret.setRuinShareFactory(new RuinShareFactoryImpl( - toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())), - toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())), - random) + toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())), + toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())), + random) ); - final RuinRandom random_for_best = new RuinRandom(vrp, 0.5); + final RuinRandom random_for_best = new RuinRandom(vrp,0.5); random_for_best.setRandom(random); random_for_best.setRuinShareFactory(new RuinShareFactoryImpl( - toInteger(properties.getProperty(Parameter.RANDOM_BEST_MIN_SHARE.toString())), - toInteger(properties.getProperty(Parameter.RANDOM_BEST_MAX_SHARE.toString())), - random) + toInteger(properties.getProperty(Parameter.RANDOM_BEST_MIN_SHARE.toString())), + toInteger(properties.getProperty(Parameter.RANDOM_BEST_MAX_SHARE.toString())), + random) ); - final RuinWorst worst = new RuinWorst(vrp, (int) (vrp.getJobs().values().size() * 0.5)); + final RuinWorst worst = new RuinWorst(vrp, (int) (vrp.getJobs().values().size()*0.5)); worst.setRandom(random); worst.setRuinShareFactory(new RuinShareFactoryImpl( - toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())), - toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())), - random) + toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())), + toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())), + random) ); IterationStartsListener noise = new IterationStartsListener() { @Override @@ -354,50 +353,52 @@ public class Jsprit { worst.setNoiseMaker(new NoiseMaker() { public double makeNoise() { - if (random.nextDouble() < toDouble(getProperty(Parameter.RUIN_WORST_NOISE_PROB.toString()))) { + if(random.nextDouble() < toDouble(getProperty(Parameter.RUIN_WORST_NOISE_PROB.toString()))) { return toDouble(getProperty(Parameter.RUIN_WORST_NOISE_LEVEL.toString())) - * noiseMaker.maxCosts * random.nextDouble(); - } else return 0.; + * noiseMaker.maxCosts * random.nextDouble(); + } + else return 0.; } }); } }; - final RuinClusters clusters = new RuinClusters(vrp, (int) (vrp.getJobs().values().size() * 0.5), jobNeighborhoods); + final RuinClusters clusters = new RuinClusters(vrp,(int) (vrp.getJobs().values().size()*0.5),jobNeighborhoods); clusters.setRandom(random); clusters.setRuinShareFactory(new RuinShareFactoryImpl( - toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())), - toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())), - random) + toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())), + toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())), + random) ); AbstractInsertionStrategy regret; final RegretInsertion.DefaultScorer scorer; - if (noThreads == null) { + if(noThreads == null){ noThreads = toInteger(getProperty(Parameter.THREADS.toString())); } - if (noThreads > 1) { - if (es == null) { + if(noThreads > 1){ + if(es == null){ setupExecutorInternally = true; es = Executors.newFixedThreadPool(noThreads); } } - if (es != null) { + if(es != null) { RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) - .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) - .setConcurrentMode(es, noThreads) - .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) - .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) - .build(); + .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) + .setConcurrentMode(es, noThreads) + .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) + .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) + .build(); scorer = getRegretScorer(vrp); regretInsertion.setScoringFunction(scorer); regret = regretInsertion; - } else { + } + else { RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager) - .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) - .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) - .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) - .build(); + .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) + .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) + .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) + .build(); scorer = getRegretScorer(vrp); regretInsertion.setScoringFunction(scorer); regret = regretInsertion; @@ -405,29 +406,30 @@ public class Jsprit { regret.setRandom(random); AbstractInsertionStrategy best; - if (vrp.getJobs().size() < 250 || es == null) { + if(vrp.getJobs().size() < 250 || es == null) { BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager) - .setInsertionStrategy(InsertionBuilder.Strategy.BEST) - .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) - .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) - .build(); + .setInsertionStrategy(InsertionBuilder.Strategy.BEST) + .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) + .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) + .build(); best = bestInsertion; - } else { + } + else{ BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) - .setInsertionStrategy(InsertionBuilder.Strategy.BEST) - .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) - .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) - .setConcurrentMode(es, noThreads) - .build(); + .setInsertionStrategy(InsertionBuilder.Strategy.BEST) + .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) + .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) + .setConcurrentMode(es, noThreads) + .build(); best = bestInsertion; } best.setRandom(random); - final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString()))); + final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1,toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString()))); IterationStartsListener schrimpfThreshold = new IterationStartsListener() { @Override public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - if (i == 1) { + if(i == 1){ double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString())); schrimpfAcceptance.setInitialThreshold(initialThreshold); } @@ -435,47 +437,48 @@ public class Jsprit { }; SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, noiseMaker.maxCosts); - SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); + SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(),new SelectBest(),schrimpfAcceptance, objectiveFunction); radial_regret.addModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial)); - SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - radial_best.addModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(), best, radial)); + SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + radial_best.addModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(),best,radial)); - SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - random_best.addModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best)); + SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + random_best.addModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(),best,random_for_best)); - SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - random_regret.addModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(), regret, random_for_regret)); + SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + random_regret.addModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(),regret,random_for_regret)); - SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - worst_regret.addModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(), regret, worst)); + SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + worst_regret.addModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(),regret,worst)); - SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - worst_best.addModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(), best, worst)); + SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + worst_best.addModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(),best,worst)); - final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - clusters_regret.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(), regret, clusters)); + final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + clusters_regret.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(),regret,clusters)); - final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); - clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters)); + final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction); + clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(),best,clusters)); - PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager); + PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager); prettyBuilder.setRandom(random); - if (addCoreConstraints) { + if(addCoreConstraints){ prettyBuilder.addCoreStateAndConstraintStuff(); } prettyBuilder.withStrategy(radial_regret, toDouble(getProperty(Strategy.RADIAL_REGRET.toString()))) - .withStrategy(radial_best, toDouble(getProperty(Strategy.RADIAL_BEST.toString()))) - .withStrategy(random_best, toDouble(getProperty(Strategy.RANDOM_BEST.toString()))) - .withStrategy(random_regret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString()))) - .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()))); - if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) { + .withStrategy(radial_best, toDouble(getProperty(Strategy.RADIAL_BEST.toString()))) + .withStrategy(random_best, toDouble(getProperty(Strategy.RANDOM_BEST.toString()))) + .withStrategy(random_regret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString()))) + .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()))); + if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())){ prettyBuilder.constructInitialSolutionWith(best, objectiveFunction); - } else { + } + else{ prettyBuilder.constructInitialSolutionWith(regret, objectiveFunction); } @@ -501,7 +504,7 @@ public class Jsprit { private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) { - if (setupExecutorInternally) { + if(setupExecutorInternally){ vra.addListener(new AlgorithmEndsListener() { @Override @@ -511,7 +514,7 @@ public class Jsprit { }); } - if (es != null) { + if(es != null) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (!es.isShutdown()) { @@ -523,7 +526,7 @@ public class Jsprit { } } - String getProperty(String key) { + String getProperty(String key){ return properties.getProperty(key); } @@ -540,20 +543,21 @@ public class Jsprit { } private SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp, final double maxCosts) { - if (objectiveFunction != null) return objectiveFunction; + if(objectiveFunction != null) return objectiveFunction; SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() { @Override public double getCosts(VehicleRoutingProblemSolution solution) { double costs = 0.; - for (VehicleRoute route : solution.getRoutes()) { + for(VehicleRoute route : solution.getRoutes()){ costs += route.getVehicle().getType().getVehicleCostParams().fix; TourActivity prevAct = route.getStart(); - for (TourActivity act : route.getActivities()) { - costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), act.getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); + for(TourActivity act : route.getActivities()){ + costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(),act.getLocation(),prevAct.getEndTime(),route.getDriver(),route.getVehicle()); + costs += vrp.getActivityCosts().getActivityCost(act,act.getArrTime(),route.getDriver(),route.getVehicle()); prevAct = act; } - costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), route.getEnd().getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); + costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(),route.getEnd().getLocation(),prevAct.getEndTime(),route.getDriver(),route.getVehicle()); } costs += solution.getUnassignedJobs().size() * maxCosts * 2; return costs; diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ConfigureLocalActivityInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ConfigureLocalActivityInsertionCalculator.java new file mode 100644 index 00000000..1c2850df --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ConfigureLocalActivityInsertionCalculator.java @@ -0,0 +1,40 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.algorithm.recreate.listener.InsertionStartsListener; +import jsprit.core.algorithm.recreate.listener.JobInsertedListener; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.solution.route.VehicleRoute; + +import java.util.Collection; + +/** + * Created by schroeder on 22/07/15. + */ +public class ConfigureLocalActivityInsertionCalculator implements InsertionStartsListener, JobInsertedListener { + + private VehicleRoutingProblem vrp; + + private LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator; + + private int nuOfJobsToRecreate; + + public ConfigureLocalActivityInsertionCalculator(VehicleRoutingProblem vrp, LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator) { + this.vrp = vrp; + this.localActivityInsertionCostsCalculator = localActivityInsertionCostsCalculator; + } + + @Override + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { + this.nuOfJobsToRecreate = unassignedJobs.size(); + double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size())); + localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5,completenessRatio)); + } + + @Override + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { + nuOfJobsToRecreate--; + double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size())); + localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5,completenessRatio)); + } +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java index fe7e3755..3ce85b0f 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java @@ -32,249 +32,252 @@ import java.util.ArrayList; import java.util.List; + + public class JobInsertionCostsCalculatorBuilder { - private static class CalculatorPlusListeners { + private static class CalculatorPlusListeners { - private JobInsertionCostsCalculator calculator; + private JobInsertionCostsCalculator calculator; - public JobInsertionCostsCalculator getCalculator() { - return calculator; - } + public JobInsertionCostsCalculator getCalculator() { + return calculator; + } - private List algorithmListener = new ArrayList(); - private List insertionListener = new ArrayList(); + private List algorithmListener = new ArrayList(); + private List insertionListener = new ArrayList(); - public CalculatorPlusListeners(JobInsertionCostsCalculator calculator) { - super(); - this.calculator = calculator; - } + public CalculatorPlusListeners(JobInsertionCostsCalculator calculator) { + super(); + this.calculator = calculator; + } - public List getAlgorithmListener() { - return algorithmListener; - } + public List getAlgorithmListener() { + return algorithmListener; + } - public List getInsertionListener() { - return insertionListener; - } - } + public List getInsertionListener() { + return insertionListener; + } + } - private List insertionListeners; + private List insertionListeners; - private List algorithmListeners; + private List algorithmListeners; - private VehicleRoutingProblem vrp; + private VehicleRoutingProblem vrp; - private RouteAndActivityStateGetter states; + private RouteAndActivityStateGetter states; - private boolean local = true; + private boolean local = true; - private int forwardLooking = 0; + private int forwardLooking = 0; - private int memory = 1; + private int memory = 1; - private boolean considerFixedCost = false; + private boolean considerFixedCost = false; - private double weightOfFixedCost = 0; + private double weightOfFixedCost = 0; - private VehicleFleetManager fleetManager; + private VehicleFleetManager fleetManager; - private boolean timeScheduling = false; + private boolean timeScheduling = false; - private double timeSlice; + private double timeSlice; - private int neighbors; + private int neighbors; - private ConstraintManager constraintManager; + private ConstraintManager constraintManager; - private ActivityInsertionCostsCalculator activityInsertionCostCalculator = null; + private ActivityInsertionCostsCalculator activityInsertionCostCalculator = null; - private boolean allowVehicleSwitch = true; + private boolean allowVehicleSwitch = true; - private boolean addDefaultCostCalc = true; + private boolean addDefaultCostCalc = true; - /** - * Constructs the builder. - *

- *

Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them. - * These listeners are cached in the according list and can thus be added when its time to add them. - * - * @param insertionListeners - * @param algorithmListeners - */ - public JobInsertionCostsCalculatorBuilder(List insertionListeners, List algorithmListeners) { - super(); - this.insertionListeners = insertionListeners; - this.algorithmListeners = algorithmListeners; - } + /** + * Constructs the builder. + * + *

Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them. + * These listeners are cached in the according list and can thus be added when its time to add them. + * + * @param insertionListeners + * @param algorithmListeners + */ + public JobInsertionCostsCalculatorBuilder(List insertionListeners, List algorithmListeners) { + super(); + this.insertionListeners = insertionListeners; + this.algorithmListeners = algorithmListeners; + } - /** - * Sets activityStates. MUST be set. - * - * @param stateManager - * @return - */ - public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager) { - this.states = stateManager; + /** + * Sets activityStates. MUST be set. + * @param stateManager + * + * @return + */ + public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager){ + this.states = stateManager; + return this; + } + + /** + * Sets routingProblem. MUST be set. + * + * @param vehicleRoutingProblem + * @return + */ + public JobInsertionCostsCalculatorBuilder setVehicleRoutingProblem(VehicleRoutingProblem vehicleRoutingProblem){ + this.vrp = vehicleRoutingProblem; + return this; + } + + /** + * Sets fleetManager. MUST be set. + * + * @param fleetManager + * @return + */ + public JobInsertionCostsCalculatorBuilder setVehicleFleetManager(VehicleFleetManager fleetManager){ + this.fleetManager = fleetManager; + return this; + } + + /** + * Sets a flag to build a calculator based on local calculations. + * + *

Insertion of a job and job-activity is evaluated based on the previous and next activity. + * @param addDefaultCostCalc + */ + public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc){ + local = true; + this.addDefaultCostCalc = addDefaultCostCalc; return this; - } + } - /** - * Sets routingProblem. MUST be set. - * - * @param vehicleRoutingProblem - * @return - */ - public JobInsertionCostsCalculatorBuilder setVehicleRoutingProblem(VehicleRoutingProblem vehicleRoutingProblem) { - this.vrp = vehicleRoutingProblem; + public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){ + this.activityInsertionCostCalculator = activityInsertionCostsCalculator; return this; - } + } - /** - * Sets fleetManager. MUST be set. - * - * @param fleetManager - * @return - */ - public JobInsertionCostsCalculatorBuilder setVehicleFleetManager(VehicleFleetManager fleetManager) { - this.fleetManager = fleetManager; + /** + * Sets a flag to build a calculator that evaluates job insertion on route-level. + * + * @param forwardLooking + * @param memory + * @param addDefaultMarginalCostCalc + */ + public JobInsertionCostsCalculatorBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalc){ + local = false; + this.forwardLooking = forwardLooking; + this.memory = memory; return this; - } + } - /** - * Sets a flag to build a calculator based on local calculations. - *

- *

Insertion of a job and job-activity is evaluated based on the previous and next activity. - * - * @param addDefaultCostCalc - */ - public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc) { - local = true; - this.addDefaultCostCalc = addDefaultCostCalc; + /** + * Sets a flag to consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting + * weightofFixedCosts. + * + * @param weightOfFixedCosts + */ + public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts){ + considerFixedCost = true; + this.weightOfFixedCost = weightOfFixedCosts; return this; - } + } - public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) { - this.activityInsertionCostCalculator = activityInsertionCostsCalculator; + public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors){ + timeScheduling = true; + this.timeSlice = timeSlice; + this.neighbors = neighbors; return this; - } + } - /** - * Sets a flag to build a calculator that evaluates job insertion on route-level. - * - * @param forwardLooking - * @param memory - * @param addDefaultMarginalCostCalc - */ - public JobInsertionCostsCalculatorBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalc) { - local = false; - this.forwardLooking = forwardLooking; - this.memory = memory; - return this; - } - - /** - * Sets a flag to consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting - * weightofFixedCosts. - * - * @param weightOfFixedCosts - */ - public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts) { - considerFixedCost = true; - this.weightOfFixedCost = weightOfFixedCosts; - return this; - } - - public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors) { - timeScheduling = true; - this.timeSlice = timeSlice; - this.neighbors = neighbors; - return this; - } - - /** - * Builds the jobInsertionCalculator. - * - * @return jobInsertionCalculator. - * @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null. - */ - public JobInsertionCostsCalculator build() { - if (vrp == null) - throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))"); - if (states == null) - throw new IllegalStateException("states is null, but is must be set (this.setStateManager(states))"); - if (fleetManager == null) - throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))"); - JobInsertionCostsCalculator baseCalculator = null; - CalculatorPlusListeners standardLocal = null; - if (local) { - standardLocal = createStandardLocal(vrp, states); - } else { - checkServicesOnly(); - standardLocal = createStandardRoute(vrp, states, forwardLooking, memory); - } - baseCalculator = standardLocal.getCalculator(); - addAlgorithmListeners(standardLocal.getAlgorithmListener()); - addInsertionListeners(standardLocal.getInsertionListener()); - if (considerFixedCost) { - CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost); - baseCalculator = withFixed.getCalculator(); - addAlgorithmListeners(withFixed.getAlgorithmListener()); - addInsertionListeners(withFixed.getInsertionListener()); - } - if (timeScheduling) { + /** + * Builds the jobInsertionCalculator. + * + * @return jobInsertionCalculator. + * @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null. + */ + public JobInsertionCostsCalculator build(){ + if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))"); + if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStateManager(states))"); + if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))"); + JobInsertionCostsCalculator baseCalculator = null; + CalculatorPlusListeners standardLocal = null; + if(local){ + standardLocal = createStandardLocal(vrp, states); + } + else{ + checkServicesOnly(); + standardLocal = createStandardRoute(vrp, states,forwardLooking,memory); + } + baseCalculator = standardLocal.getCalculator(); + addAlgorithmListeners(standardLocal.getAlgorithmListener()); + addInsertionListeners(standardLocal.getInsertionListener()); + if(considerFixedCost){ + CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost); + baseCalculator = withFixed.getCalculator(); + addAlgorithmListeners(withFixed.getAlgorithmListener()); + addInsertionListeners(withFixed.getInsertionListener()); + } + if(timeScheduling){ // baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors); - CalculatesServiceInsertionWithTimeScheduling wts = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator, timeSlice, neighbors); + CalculatesServiceInsertionWithTimeScheduling wts = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator,timeSlice,neighbors); CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(wts); calcPlusListeners.getInsertionListener().add(new CalculatesServiceInsertionWithTimeScheduling.KnowledgeInjection(wts)); addInsertionListeners(calcPlusListeners.getInsertionListener()); baseCalculator = calcPlusListeners.getCalculator(); - } - return createFinalInsertion(fleetManager, baseCalculator, states); - } + } + return createFinalInsertion(fleetManager, baseCalculator, states); + } - private void checkServicesOnly() { - for (Job j : vrp.getJobs().values()) { - if (j instanceof Shipment) { - throw new UnsupportedOperationException("currently the 'insert-on-route-level' option is only available for services (i.e. service, pickup, delivery), \n" + - "if you want to deal with shipments switch to option 'local-level' by either setting bestInsertionBuilder.setLocalLevel() or \n" - + "by omitting the xml-tag 'route' when defining your insertionStrategy in algo-config.xml file"); - } - } + private void checkServicesOnly() { + for(Job j : vrp.getJobs().values()){ + if(j instanceof Shipment){ + throw new UnsupportedOperationException("currently the 'insert-on-route-level' option is only available for services (i.e. service, pickup, delivery), \n" + + "if you want to deal with shipments switch to option 'local-level' by either setting bestInsertionBuilder.setLocalLevel() or \n" + + "by omitting the xml-tag 'route' when defining your insertionStrategy in algo-config.xml file"); + } + } - } + } - private void addInsertionListeners(List list) { - for (InsertionListener iL : list) { - insertionListeners.add(iL); - } - } + private void addInsertionListeners(List list) { + for(InsertionListener iL : list){ + insertionListeners.add(iL); + } + } - private void addAlgorithmListeners(List list) { - for (PrioritizedVRAListener aL : list) { - algorithmListeners.add(aL); - } - } + private void addAlgorithmListeners(List list) { + for(PrioritizedVRAListener aL : list){ + algorithmListeners.add(aL); + } + } - private CalculatorPlusListeners createStandardLocal(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter statesManager) { - if (constraintManager == null) throw new IllegalStateException("constraint-manager is null"); + private CalculatorPlusListeners createStandardLocal(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter statesManager){ + if(constraintManager == null) throw new IllegalStateException("constraint-manager is null"); - ActivityInsertionCostsCalculator actInsertionCalc; - if (activityInsertionCostCalculator == null && addDefaultCostCalc) { - actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts()); - } else if (activityInsertionCostCalculator == null && !addDefaultCostCalc) { - actInsertionCalc = new ActivityInsertionCostsCalculator() { + ActivityInsertionCostsCalculator actInsertionCalc; + ConfigureLocalActivityInsertionCalculator configLocal = null; + if(activityInsertionCostCalculator == null && addDefaultCostCalc){ + actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), statesManager); + configLocal = new ConfigureLocalActivityInsertionCalculator(vrp, (LocalActivityInsertionCostsCalculator) actInsertionCalc); + } + else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){ + actInsertionCalc = new ActivityInsertionCostsCalculator(){ - @Override - public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, + @Override + public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { - return 0.; - } + return 0.; + } - }; - } else { - actInsertionCalc = activityInsertionCostCalculator; - } + }; + } + else{ + actInsertionCalc = activityInsertionCostCalculator; + } JobActivityFactory activityFactory = new JobActivityFactory() { @@ -284,53 +287,59 @@ public class JobInsertionCostsCalculatorBuilder { } }; - ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager); + ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager); shipmentInsertion.setJobActivityFactory(activityFactory); - ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager); + ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager); serviceInsertion.setJobActivityFactory(activityFactory); JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); - switcher.put(Shipment.class, shipmentInsertion); - switcher.put(Service.class, serviceInsertion); - switcher.put(Pickup.class, serviceInsertion); - switcher.put(Delivery.class, serviceInsertion); + switcher.put(Shipment.class, shipmentInsertion); + switcher.put(Service.class, serviceInsertion); + switcher.put(Pickup.class, serviceInsertion); + switcher.put(Delivery.class, serviceInsertion); - return new CalculatorPlusListeners(switcher); - } + CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(switcher); + if(configLocal != null){ + calculatorPlusListeners.insertionListener.add(configLocal); + } + 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 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) { + private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory){ + ActivityInsertionCostsCalculator routeLevelCostEstimator; + if(activityInsertionCostCalculator == null && addDefaultCostCalc){ RouteLevelActivityInsertionCostsEstimator routeLevelActivityInsertionCostsEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2); routeLevelActivityInsertionCostsEstimator.setForwardLooking(forwardLooking); routeLevelCostEstimator = routeLevelActivityInsertionCostsEstimator; - } else if (activityInsertionCostCalculator == null && !addDefaultCostCalc) { - routeLevelCostEstimator = new ActivityInsertionCostsCalculator() { + } + else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){ + routeLevelCostEstimator = new ActivityInsertionCostsCalculator(){ - final ActivityInsertionCosts noInsertionCosts = new ActivityInsertionCosts(0., 0.); + final ActivityInsertionCosts noInsertionCosts = new ActivityInsertionCosts(0.,0.); - @Override - public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, + @Override + public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { - return 0.; - } + return 0.; + } - }; - } else { - routeLevelCostEstimator = activityInsertionCostCalculator; - } + }; + } + else{ + routeLevelCostEstimator = activityInsertionCostCalculator; + } ServiceInsertionOnRouteLevelCalculator jobInsertionCalculator = new ServiceInsertionOnRouteLevelCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), routeLevelCostEstimator, constraintManager, constraintManager); - jobInsertionCalculator.setNuOfActsForwardLooking(forwardLooking); - jobInsertionCalculator.setMemorySize(solutionMemory); - jobInsertionCalculator.setStates(activityStates2); + jobInsertionCalculator.setNuOfActsForwardLooking(forwardLooking); + jobInsertionCalculator.setMemorySize(solutionMemory); + jobInsertionCalculator.setStates(activityStates2); jobInsertionCalculator.setJobActivityFactory(new JobActivityFactory() { @Override public List createActivities(Job job) { @@ -338,23 +347,23 @@ public class JobInsertionCostsCalculatorBuilder { } }); return new CalculatorPlusListeners(jobInsertionCalculator); - } + } - private JobInsertionCostsCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCostsCalculator baseCalc, RouteAndActivityStateGetter activityStates2) { - VehicleTypeDependentJobInsertionCalculator vehicleTypeDependentJobInsertionCalculator = new VehicleTypeDependentJobInsertionCalculator(vrp, fleetManager, baseCalc); - vehicleTypeDependentJobInsertionCalculator.setVehicleSwitchAllowed(allowVehicleSwitch); - return vehicleTypeDependentJobInsertionCalculator; - } + private JobInsertionCostsCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCostsCalculator baseCalc, RouteAndActivityStateGetter activityStates2){ + VehicleTypeDependentJobInsertionCalculator vehicleTypeDependentJobInsertionCalculator = new VehicleTypeDependentJobInsertionCalculator(vrp, fleetManager, baseCalc); + vehicleTypeDependentJobInsertionCalculator.setVehicleSwitchAllowed(allowVehicleSwitch); + return vehicleTypeDependentJobInsertionCalculator; + } - public JobInsertionCostsCalculatorBuilder setConstraintManager(ConstraintManager constraintManager) { - this.constraintManager = constraintManager; + public JobInsertionCostsCalculatorBuilder setConstraintManager(ConstraintManager constraintManager) { + this.constraintManager = constraintManager; return this; - } + } - public JobInsertionCostsCalculatorBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) { + public JobInsertionCostsCalculatorBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) { this.allowVehicleSwitch = allowVehicleSwitch; return this; - } + } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java index 86e61b76..846531c1 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java @@ -1,3 +1,4 @@ + /******************************************************************************* * Copyright (C) 2014 Stefan Schroeder * @@ -17,70 +18,96 @@ package jsprit.core.algorithm.recreate; +import jsprit.core.algorithm.state.InternalStates; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.misc.JobInsertionContext; import jsprit.core.problem.solution.route.activity.End; import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; +import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.util.CalculationUtils; /** * Calculates activity insertion costs locally, i.e. by comparing the additional costs of insertion the new activity k between * activity i (prevAct) and j (nextAct). * Additional costs are then basically calculated as delta c = c_ik + c_kj - c_ij. - *

+ * *

Note once time has an effect on costs this class requires activity endTimes. * * @author stefan + * */ -class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator { +class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator{ - private VehicleRoutingTransportCosts routingCosts; + private VehicleRoutingTransportCosts routingCosts; - private VehicleRoutingActivityCosts activityCosts; + private VehicleRoutingActivityCosts activityCosts; + private double activityCostsWeight = 1.; - public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts) { - super(); - this.routingCosts = routingCosts; - this.activityCosts = actCosts; - } + private double solutionCompletenessRatio = 1.; - @Override - public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { + private RouteAndActivityStateGetter stateManager; - double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct; - double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct); - double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) { + super(); + this.routingCosts = routingCosts; + this.activityCosts = actCosts; + this.stateManager = stateManager; + } - //open routes - if (nextAct instanceof End) { - if (!iFacts.getNewVehicle().isReturnToDepot()) { - return tp_costs_prevAct_newAct; - } - } + @Override + public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { - double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; - double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct; + double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct; + double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct); - double oldCosts; - if (iFacts.getRoute().isEmpty()) { - double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct; - } else { - double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); - double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); - double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); - oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct; - } - return totalCosts - oldCosts; - } + double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + if(isEnd(nextAct) && !toDepot(iFacts.getNewVehicle())) return tp_costs_prevAct_newAct; + + double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; + double endTime_nextAct_new = CalculationUtils.getActivityEndTime(nextAct_arrTime, nextAct); + double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + solutionCompletenessRatio * activityCostsWeight * (act_costs_newAct + act_costs_nextAct); + + double oldCosts = 0.; + if(iFacts.getRoute().isEmpty()){ + double 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()); + double arrTime_nextAct = depTimeAtPrevAct + routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); + double endTime_nextAct_old = CalculationUtils.getActivityEndTime(arrTime_nextAct,nextAct); + double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); + + double endTimeDelay_nextAct = Math.max(0, endTime_nextAct_new - endTime_nextAct_old); + Double futureWaiting = stateManager.getActivityState(nextAct, iFacts.getRoute().getVehicle(), InternalStates.FUTURE_WAITING, Double.class); + if (futureWaiting == null) futureWaiting = 0.; + double waitingTime_savings_timeUnit = Math.min(futureWaiting, endTimeDelay_nextAct); + double waitingTime_savings = waitingTime_savings_timeUnit * iFacts.getRoute().getVehicle().getType().getVehicleCostParams().perWaitingTimeUnit; + oldCosts += solutionCompletenessRatio * activityCostsWeight * waitingTime_savings; + oldCosts += tp_costs_prevAct_nextAct + solutionCompletenessRatio * activityCostsWeight * actCost_nextAct; + } + return totalCosts - oldCosts; + } + + private boolean toDepot(Vehicle newVehicle) { + return newVehicle.isReturnToDepot(); + } + + private boolean isEnd(TourActivity nextAct) { + return nextAct instanceof End; + } + + public void setSolutionCompletenessRatio(double solutionCompletenessRatio) { + this.solutionCompletenessRatio = solutionCompletenessRatio; + } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java index 05253655..f3e723ad 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java @@ -33,97 +33,99 @@ import java.util.HashSet; import java.util.Set; -final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCostsCalculator { +final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCostsCalculator{ - private Logger logger = LogManager.getLogger(VehicleTypeDependentJobInsertionCalculator.class); + private Logger logger = LogManager.getLogger(VehicleTypeDependentJobInsertionCalculator.class); - private final VehicleFleetManager fleetManager; + private final VehicleFleetManager fleetManager; - private final JobInsertionCostsCalculator insertionCalculator; + private final JobInsertionCostsCalculator insertionCalculator; - private final VehicleRoutingProblem vrp; + private final VehicleRoutingProblem vrp; - private Set initialVehicleIds = new HashSet(); + private Set initialVehicleIds = new HashSet(); - /** - * true if a vehicle(-type) is allowed to take over the whole route that was previously served by another vehicle - *

- *

vehicleSwitch allowed makes sense if fleet consists of vehicles with different capacities such that one - * can start with a small vehicle, but as the number of customers grows bigger vehicles can be operated, i.e. - * bigger vehicles can take over the route that was previously served by a small vehicle. - */ - private boolean vehicleSwitchAllowed = false; + /** + * true if a vehicle(-type) is allowed to take over the whole route that was previously served by another vehicle + * + *

vehicleSwitch allowed makes sense if fleet consists of vehicles with different capacities such that one + * can start with a small vehicle, but as the number of customers grows bigger vehicles can be operated, i.e. + * bigger vehicles can take over the route that was previously served by a small vehicle. + * + */ + private boolean vehicleSwitchAllowed = false; - public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) { - this.fleetManager = fleetManager; - this.insertionCalculator = jobInsertionCalc; - this.vrp = vrp; - getInitialVehicleIds(); - logger.debug("initialise {}", this); - } + public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) { + this.fleetManager = fleetManager; + this.insertionCalculator = jobInsertionCalc; + this.vrp = vrp; + getInitialVehicleIds(); + logger.debug("initialise " + this); + } - private void getInitialVehicleIds() { + private void getInitialVehicleIds() { Collection initialVehicleRoutes = vrp.getInitialVehicleRoutes(); - for (VehicleRoute initialRoute : initialVehicleRoutes) { - initialVehicleIds.add(initialRoute.getVehicle().getId()); - } - } + for(VehicleRoute initialRoute : initialVehicleRoutes){ + initialVehicleIds.add(initialRoute.getVehicle().getId()); + } + } - @Override - public String toString() { - return "[name=vehicleTypeDependentServiceInsertion]"; - } + @Override + public String toString() { + return "[name=vehicleTypeDependentServiceInsertion]"; + } - /** - * @return the vehicleSwitchAllowed - */ - @SuppressWarnings("UnusedDeclaration") + /** + * @return the vehicleSwitchAllowed + */ + @SuppressWarnings("UnusedDeclaration") public boolean isVehicleSwitchAllowed() { - return vehicleSwitchAllowed; - } + return vehicleSwitchAllowed; + } - /** - * default is true - * - * @param vehicleSwitchAllowed the vehicleSwitchAllowed to set - */ - public void setVehicleSwitchAllowed(boolean vehicleSwitchAllowed) { - logger.debug("set vehicleSwitchAllowed to {}", vehicleSwitchAllowed); - this.vehicleSwitchAllowed = vehicleSwitchAllowed; - } + /** + * default is true + * + * @param vehicleSwitchAllowed the vehicleSwitchAllowed to set + */ + public void setVehicleSwitchAllowed(boolean vehicleSwitchAllowed) { + logger.debug("set vehicleSwitchAllowed to " + vehicleSwitchAllowed); + this.vehicleSwitchAllowed = vehicleSwitchAllowed; + } - public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) { - Vehicle selectedVehicle = currentRoute.getVehicle(); - Driver selectedDriver = currentRoute.getDriver(); - InsertionData bestIData = InsertionData.createEmptyInsertionData(); - double bestKnownCost_ = bestKnownCost; - Collection relevantVehicles = new ArrayList(); - if (!(selectedVehicle instanceof NoVehicle)) { - relevantVehicles.add(selectedVehicle); - if (vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)) { - relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle)); - } - } else { //if no vehicle has been assigned, i.e. it is an empty route - relevantVehicles.addAll(fleetManager.getAvailableVehicles()); - } - for (Vehicle v : relevantVehicles) { - double depTime; - if (v == selectedVehicle) depTime = currentRoute.getDepartureTime(); - else depTime = v.getEarliestDeparture(); - InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_); - if (iData instanceof NoInsertionFound) { + public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) { + Vehicle selectedVehicle = currentRoute.getVehicle(); + Driver selectedDriver = currentRoute.getDriver(); + InsertionData bestIData = InsertionData.createEmptyInsertionData(); + double bestKnownCost_ = bestKnownCost; + Collection relevantVehicles = new ArrayList(); + if(!(selectedVehicle instanceof NoVehicle)) { + relevantVehicles.add(selectedVehicle); + if(vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)){ + relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle)); + } + } + else{ //if no vehicle has been assigned, i.e. it is an empty route + relevantVehicles.addAll(fleetManager.getAvailableVehicles()); + } + for(Vehicle v : relevantVehicles){ + double depTime; + if(v == selectedVehicle) depTime = currentRoute.getDepartureTime(); + else depTime = v.getEarliestDeparture(); + InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_); + if(iData instanceof NoInsertionFound) { continue; - } - if (iData.getInsertionCost() < bestKnownCost_) { - bestIData = iData; - bestKnownCost_ = iData.getInsertionCost(); - } - } - return bestIData; - } + } + if(iData.getInsertionCost() < bestKnownCost_){ + bestIData = iData; + bestKnownCost_ = iData.getInsertionCost(); + } + } + return bestIData; + } - private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) { - return initialVehicleIds.contains(selectedVehicle.getId()); - } + private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) { + return initialVehicleIds.contains(selectedVehicle.getId()); + } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/InternalStates.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/InternalStates.java index 75a2cb09..270b3b17 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/InternalStates.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/InternalStates.java @@ -41,4 +41,12 @@ public class InternalStates { public final static StateId PAST_MAXLOAD = new StateFactory.StateIdImpl("past_max_load", 9); public static final StateId SKILLS = new StateFactory.StateIdImpl("skills", 10); + + public static final StateId WAITING = new StateFactory.StateIdImpl("waiting",11); + + public static final StateId TIME_SLACK = new StateFactory.StateIdImpl("time_slack",12); + + public static final StateId FUTURE_WAITING = new StateFactory.StateIdImpl("future_waiting",13); + + public static final StateId EARLIEST_WITHOUT_WAITING = new StateFactory.StateIdImpl("earliest_without_waiting",14); } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateFutureWaitingTimes.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateFutureWaitingTimes.java new file mode 100644 index 00000000..61b99284 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateFutureWaitingTimes.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (C) 2014 Stefan Schroeder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + ******************************************************************************/ +package jsprit.core.algorithm.state; + +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor; +import jsprit.core.problem.solution.route.activity.TourActivity; + +/** + * Updates and memorizes latest operation start times at activities. + * + * @author schroeder + * + */ +public class UpdateFutureWaitingTimes implements ReverseActivityVisitor, StateUpdater{ + + private StateManager states; + + private VehicleRoute route; + + private VehicleRoutingTransportCosts transportCosts; + + private double futureWaiting; + + public UpdateFutureWaitingTimes(StateManager states, VehicleRoutingTransportCosts tpCosts) { + super(); + this.states = states; + this.transportCosts = tpCosts; + } + + @Override + public void begin(VehicleRoute route) { + this.route = route; + this.futureWaiting = 0.; + } + + @Override + public void visit(TourActivity activity) { + states.putInternalTypedActivityState(activity,route.getVehicle(),InternalStates.FUTURE_WAITING,futureWaiting); + futureWaiting += Math.max(activity.getTheoreticalEarliestOperationStartTime() - activity.getArrTime(),0); + } + + @Override + public void finish() {} +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java index 8898f33d..43b7186a 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java @@ -19,15 +19,26 @@ package jsprit.core.algorithm.state; import jsprit.core.problem.Location; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.solution.route.RouteVisitor; import jsprit.core.problem.solution.route.VehicleRoute; -import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; -public class UpdateVehicleDependentPracticalTimeWindows implements ReverseActivityVisitor, StateUpdater { +public class UpdateVehicleDependentPracticalTimeWindows implements RouteVisitor, StateUpdater{ + + @Override + public void visit(VehicleRoute route) { + begin(route); + Iterator revIterator = route.getTourActivities().reverseActivityIterator(); + while(revIterator.hasNext()){ + visit(revIterator.next()); + } + finish(); + } public static interface VehiclesToUpdate { @@ -64,27 +75,27 @@ public class UpdateVehicleDependentPracticalTimeWindows implements ReverseActivi location_of_prevAct = new Location[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1]; } - public void setVehiclesToUpdate(VehiclesToUpdate vehiclesToUpdate) { + public void setVehiclesToUpdate(VehiclesToUpdate vehiclesToUpdate){ this.vehiclesToUpdate = vehiclesToUpdate; } - @Override + public void begin(VehicleRoute route) { this.route = route; vehicles = vehiclesToUpdate.get(route); - for (Vehicle vehicle : vehicles) { + for(Vehicle vehicle : vehicles){ latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = vehicle.getLatestArrival(); location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = vehicle.getEndLocation(); } } - @Override + public void visit(TourActivity activity) { - for (Vehicle vehicle : vehicles) { + for(Vehicle vehicle : vehicles){ double latestArrTimeAtPrevAct = latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()]; Location prevLocation = location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()]; double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocation(), prevLocation, - latestArrTimeAtPrevAct, route.getDriver(), vehicle) - activity.getOperationTime(); + latestArrTimeAtPrevAct, route.getDriver(), vehicle) - activity.getOperationTime(); double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct); stateManager.putInternalTypedActivityState(activity, vehicle, InternalStates.LATEST_OPERATION_START_TIME, latestArrivalTime); latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = latestArrivalTime; @@ -92,9 +103,8 @@ public class UpdateVehicleDependentPracticalTimeWindows implements ReverseActivi } } - @Override - public void finish() { - } + + public void finish() {} } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java index 63d394ec..2ffb56c3 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java @@ -18,7 +18,7 @@ package jsprit.core.problem; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; -import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.cost.WaitingTimeCosts; import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Service; import jsprit.core.problem.job.Shipment; @@ -41,75 +41,67 @@ import java.util.*; /** * Contains and defines the vehicle routing problem. - *

+ * *

A routing problem is defined as jobs, vehicles, costs and constraints. - *

+ * *

To construct the problem, use VehicleRoutingProblem.Builder. Get an instance of this by using the static method VehicleRoutingProblem.Builder.newInstance(). - *

+ * *

By default, fleetSize is INFINITE, transport-costs are calculated as euclidean-distance (CrowFlyCosts), * and activity-costs are set to zero. * + * + * * @author stefan schroeder + * */ public class VehicleRoutingProblem { - /** - * Builder to build the routing-problem. - * - * @author stefan schroeder - */ - public static class Builder { + /** + * Builder to build the routing-problem. + * + * @author stefan schroeder + * + */ + public static class Builder { + /** - * Returns a new instance of this builder. - * - * @return builder - */ - public static Builder newInstance() { - return new Builder(); - } + * Returns a new instance of this builder. + * + * @return builder + */ + public static Builder newInstance(){ return new Builder(); } - private VehicleRoutingTransportCosts transportCosts; + private VehicleRoutingTransportCosts transportCosts; - private VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts() { + private VehicleRoutingActivityCosts activityCosts = new WaitingTimeCosts(); - @Override - public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { - return 0; - } + private Map jobs = new LinkedHashMap(); - @Override - public String toString() { - return "[name=defaultActivityCosts]"; - } + private Map tentativeJobs = new LinkedHashMap(); - }; + private Set jobsInInitialRoutes = new HashSet(); - private Map jobs = new LinkedHashMap(); + private Map tentative_coordinates = new HashMap(); - private Map tentativeJobs = new LinkedHashMap(); + private FleetSize fleetSize = FleetSize.INFINITE; - private Set jobsInInitialRoutes = new HashSet(); + private Collection vehicleTypes = new ArrayList(); - private Map tentative_coordinates = new HashMap(); + private Collection initialRoutes = new ArrayList(); - private FleetSize fleetSize = FleetSize.INFINITE; + private Set uniqueVehicles = new HashSet(); - private Collection vehicleTypes = new ArrayList(); - - private Collection initialRoutes = new ArrayList(); - - private Set uniqueVehicles = new HashSet(); - - private JobActivityFactory jobActivityFactory = new JobActivityFactory() { + private JobActivityFactory jobActivityFactory = new JobActivityFactory() { @Override public List createActivities(Job job) { List acts = new ArrayList(); - if (job instanceof Service) { + if(job instanceof Service){ acts.add(serviceActivityFactory.createActivity((Service) job)); - } else if (job instanceof Shipment) { + } + else if(job instanceof Shipment){ acts.add(shipmentActivityFactory.createPickup((Shipment) job)); acts.add(shipmentActivityFactory.createDelivery((Shipment) job)); } @@ -126,98 +118,97 @@ public class VehicleRoutingProblem { private int vehicleTypeIdIndexCounter = 1; - private Map typeKeyIndices = new HashMap(); + private Map typeKeyIndices = new HashMap(); - private Map> activityMap = new HashMap>(); + private Map> activityMap = new HashMap>(); private final DefaultShipmentActivityFactory shipmentActivityFactory = new DefaultShipmentActivityFactory(); private final DefaultTourActivityFactory serviceActivityFactory = new DefaultTourActivityFactory(); - private void incJobIndexCounter() { + private void incJobIndexCounter(){ jobIndexCounter++; } - private void incActivityIndexCounter() { + private void incActivityIndexCounter(){ activityIndexCounter++; } - private void incVehicleTypeIdIndexCounter() { - vehicleTypeIdIndexCounter++; - } + private void incVehicleTypeIdIndexCounter() { vehicleTypeIdIndexCounter++; } - /** - * Returns the unmodifiable map of collected locations (mapped by their location-id). - * - * @return map with locations - */ - public Map getLocationMap() { - return Collections.unmodifiableMap(tentative_coordinates); - } + /** + * Returns the unmodifiable map of collected locations (mapped by their location-id). + * + * @return map with locations + */ + public Map getLocationMap(){ + return Collections.unmodifiableMap(tentative_coordinates); + } - /** - * Returns the locations collected SO FAR by this builder. - *

- *

Locations are cached when adding a shipment, service, depot, vehicle. - * - * @return locations - */ - public Locations getLocations() { - return new Locations() { + /** + * Returns the locations collected SO FAR by this builder. + * + *

Locations are cached when adding a shipment, service, depot, vehicle. + * + * @return locations + * + **/ + public Locations getLocations(){ + return new Locations() { - @Override - public Coordinate getCoord(String id) { - return tentative_coordinates.get(id); - } + @Override + public Coordinate getCoord(String id) { + return tentative_coordinates.get(id); + } - }; - } + }; + } - /** - * Sets routing costs. - * - * @param costs the routingCosts - * @return builder - * @see VehicleRoutingTransportCosts - */ - public Builder setRoutingCost(VehicleRoutingTransportCosts costs) { - this.transportCosts = costs; - return this; - } + /** + * Sets routing costs. + * + * @param costs the routingCosts + * @return builder + * @see VehicleRoutingTransportCosts + */ + public Builder setRoutingCost(VehicleRoutingTransportCosts costs){ + this.transportCosts = costs; + return this; + } - /** - * Sets the type of fleetSize. - *

- *

FleetSize is either FleetSize.INFINITE or FleetSize.FINITE. By default it is FleetSize.INFINITE. - * - * @param fleetSize the fleet size used in this problem. it can either be FleetSize.INFINITE or FleetSize.FINITE - * @return this builder - */ - public Builder setFleetSize(FleetSize fleetSize) { - this.fleetSize = fleetSize; - return this; - } + /** + * Sets the type of fleetSize. + * + *

FleetSize is either FleetSize.INFINITE or FleetSize.FINITE. By default it is FleetSize.INFINITE. + * + * @param fleetSize the fleet size used in this problem. it can either be FleetSize.INFINITE or FleetSize.FINITE + * @return this builder + */ + public Builder setFleetSize(FleetSize fleetSize){ + this.fleetSize = fleetSize; + return this; + } - /** - * Adds a job which is either a service or a shipment. - *

- *

Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id. - * - * @param job job to be added - * @return this builder - * @throws IllegalStateException if job is neither a shipment nor a service, or jobId has already been added. + /** + * Adds a job which is either a service or a shipment. + * + *

Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id. + * + * @param job job to be added + * @return this builder + * @throws IllegalStateException if job is neither a shipment nor a service, or jobId has already been added. * @deprecated use addJob(AbstractJob job) instead - */ + */ @Deprecated - public Builder addJob(Job job) { - if (!(job instanceof AbstractJob)) throw new IllegalArgumentException("job must be of type AbstractJob"); - return addJob((AbstractJob) job); - } + public Builder addJob(Job job) { + if(!(job instanceof AbstractJob)) throw new IllegalArgumentException("job must be of type AbstractJob"); + return addJob((AbstractJob)job); + } /** * Adds a job which is either a service or a shipment. - *

+ * *

Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id. * * @param job job to be added @@ -225,10 +216,8 @@ public class VehicleRoutingProblem { * @throws IllegalStateException if job is neither a shipment nor a service, or jobId has already been added. */ public Builder addJob(AbstractJob job) { - if (tentativeJobs.containsKey(job.getId())) - throw new IllegalStateException("jobList already contains a job with id " + job.getId() + ". make sure you use unique ids for your jobs (i.e. service and shipments)"); - if (!(job instanceof Service || job instanceof Shipment)) - throw new IllegalStateException("job must be either a service or a shipment"); + if(tentativeJobs.containsKey(job.getId())) throw new IllegalStateException("jobList already contains a job with id " + job.getId() + ". make sure you use unique ids for your jobs (i.e. service and shipments)"); + if(!(job instanceof Service || job instanceof Shipment)) throw new IllegalStateException("job must be either a service or a shipment"); job.setIndex(jobIndexCounter); incJobIndexCounter(); tentativeJobs.put(job.getId(), job); @@ -236,31 +225,33 @@ public class VehicleRoutingProblem { return this; } - private void addLocationToTentativeLocations(Job job) { - if (job instanceof Service) { - tentative_coordinates.put(((Service) job).getLocation().getId(), ((Service) job).getLocation().getCoordinate()); - } else if (job instanceof Shipment) { - Shipment shipment = (Shipment) job; - tentative_coordinates.put(shipment.getPickupLocation().getId(), shipment.getPickupLocation().getCoordinate()); - tentative_coordinates.put(shipment.getDeliveryLocation().getId(), shipment.getDeliveryLocation().getCoordinate()); - } - } + private void addLocationToTentativeLocations(Job job) { + if(job instanceof Service) { + tentative_coordinates.put(((Service)job).getLocation().getId(), ((Service)job).getLocation().getCoordinate()); + } + else if(job instanceof Shipment){ + Shipment shipment = (Shipment)job; + tentative_coordinates.put(shipment.getPickupLocation().getId(), shipment.getPickupLocation().getCoordinate()); + tentative_coordinates.put(shipment.getDeliveryLocation().getId(), shipment.getDeliveryLocation().getCoordinate()); + } + } - private void addJobToFinalJobMapAndCreateActivities(Job job) { - if (job instanceof Service) { + private void addJobToFinalJobMapAndCreateActivities(Job job){ + if(job instanceof Service) { Service service = (Service) job; - addService(service); - } else if (job instanceof Shipment) { - Shipment shipment = (Shipment) job; + addService(service); + } + else if(job instanceof Shipment){ + Shipment shipment = (Shipment)job; addShipment(shipment); - } + } List jobActs = jobActivityFactory.createActivities(job); - for (AbstractActivity act : jobActs) { + for(AbstractActivity act : jobActs){ act.setIndex(activityIndexCounter); incActivityIndexCounter(); } activityMap.put(job, jobActs); - } + } /** @@ -269,26 +260,25 @@ public class VehicleRoutingProblem { * @param route initial route * @return the builder */ - public Builder addInitialVehicleRoute(VehicleRoute route) { - addVehicle((AbstractVehicle) route.getVehicle()); - for (TourActivity act : route.getActivities()) { + public Builder addInitialVehicleRoute(VehicleRoute route){ + addVehicle((AbstractVehicle)route.getVehicle()); + for(TourActivity act : route.getActivities()){ AbstractActivity abstractAct = (AbstractActivity) act; abstractAct.setIndex(activityIndexCounter); incActivityIndexCounter(); - if (act instanceof TourActivity.JobActivity) { + if(act instanceof TourActivity.JobActivity) { Job job = ((TourActivity.JobActivity) act).getJob(); jobsInInitialRoutes.add(job.getId()); registerLocation(job); registerJobAndActivity(abstractAct, job); } } - initialRoutes.add(route); - return this; - } + initialRoutes.add(route); + return this; + } private void registerLocation(Job job) { - if (job instanceof Service) - tentative_coordinates.put(((Service) job).getLocation().getId(), ((Service) job).getLocation().getCoordinate()); + if (job instanceof Service) tentative_coordinates.put(((Service) job).getLocation().getId(), ((Service) job).getLocation().getCoordinate()); if (job instanceof Shipment) { Shipment shipment = (Shipment) job; tentative_coordinates.put(shipment.getPickupLocation().getId(), shipment.getPickupLocation().getCoordinate()); @@ -297,11 +287,11 @@ public class VehicleRoutingProblem { } private void registerJobAndActivity(AbstractActivity abstractAct, Job job) { - if (activityMap.containsKey(job)) activityMap.get(job).add(abstractAct); - else { + if(activityMap.containsKey(job)) activityMap.get(job).add(abstractAct); + else{ List actList = new ArrayList(); actList.add(abstractAct); - activityMap.put(job, actList); + activityMap.put(job,actList); } } @@ -311,61 +301,61 @@ public class VehicleRoutingProblem { * @param routes initial routes * @return the builder */ - public Builder addInitialVehicleRoutes(Collection routes) { - for (VehicleRoute r : routes) { - addInitialVehicleRoute(r); - } - return this; - } + public Builder addInitialVehicleRoutes(Collection routes){ + for(VehicleRoute r : routes){ + addInitialVehicleRoute(r); + } + return this; + } - private void addShipment(Shipment job) { - if (jobs.containsKey(job.getId())) { - logger.warn("job {} already in job list. overrides existing job.", job); - } - tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate()); - tentative_coordinates.put(job.getDeliveryLocation().getId(), job.getDeliveryLocation().getCoordinate()); - jobs.put(job.getId(), job); - } + private void addShipment(Shipment job) { + if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); } + tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate()); + tentative_coordinates.put(job.getDeliveryLocation().getId(), job.getDeliveryLocation().getCoordinate()); + jobs.put(job.getId(),job); + } + + /** + * Adds a vehicle. + * + * + * @param vehicle vehicle to be added + * @return this builder + * @deprecated use addVehicle(AbstractVehicle vehicle) instead + */ + @Deprecated + public Builder addVehicle(Vehicle vehicle) { + if(!(vehicle instanceof AbstractVehicle)) throw new IllegalStateException("vehicle must be an AbstractVehicle"); + return addVehicle((AbstractVehicle)vehicle); + } /** * Adds a vehicle. * - * @param vehicle vehicle to be added - * @return this builder - * @deprecated use addVehicle(AbstractVehicle vehicle) instead - */ - @Deprecated - public Builder addVehicle(Vehicle vehicle) { - if (!(vehicle instanceof AbstractVehicle)) - throw new IllegalStateException("vehicle must be an AbstractVehicle"); - return addVehicle((AbstractVehicle) vehicle); - } - - /** - * Adds a vehicle. * * @param vehicle vehicle to be added * @return this builder */ public Builder addVehicle(AbstractVehicle vehicle) { - if (!uniqueVehicles.contains(vehicle)) { + if(!uniqueVehicles.contains(vehicle)){ vehicle.setIndex(vehicleIndexCounter); incVehicleIndexCounter(); } - if (typeKeyIndices.containsKey(vehicle.getVehicleTypeIdentifier())) { + if(typeKeyIndices.containsKey(vehicle.getVehicleTypeIdentifier())){ vehicle.getVehicleTypeIdentifier().setIndex(typeKeyIndices.get(vehicle.getVehicleTypeIdentifier())); - } else { + } + else { vehicle.getVehicleTypeIdentifier().setIndex(vehicleTypeIdIndexCounter); - typeKeyIndices.put(vehicle.getVehicleTypeIdentifier(), vehicleTypeIdIndexCounter); + typeKeyIndices.put(vehicle.getVehicleTypeIdentifier(),vehicleTypeIdIndexCounter); incVehicleTypeIdIndexCounter(); } uniqueVehicles.add(vehicle); - if (!vehicleTypes.contains(vehicle.getType())) { + if(!vehicleTypes.contains(vehicle.getType())){ vehicleTypes.add(vehicle.getType()); } String startLocationId = vehicle.getStartLocation().getId(); tentative_coordinates.put(startLocationId, vehicle.getStartLocation().getCoordinate()); - if (!vehicle.getEndLocation().getId().equals(startLocationId)) { + if(!vehicle.getEndLocation().getId().equals(startLocationId)){ tentative_coordinates.put(vehicle.getEndLocation().getId(), vehicle.getEndLocation().getCoordinate()); } return this; @@ -376,97 +366,97 @@ public class VehicleRoutingProblem { } /** - * Sets the activity-costs. - *

- *

By default it is set to zero. - * - * @param activityCosts activity costs of the problem - * @return this builder - * @see VehicleRoutingActivityCosts - */ - public Builder setActivityCosts(VehicleRoutingActivityCosts activityCosts) { - this.activityCosts = activityCosts; - return this; - } + * Sets the activity-costs. + * + *

By default it is set to zero. + * + * @param activityCosts activity costs of the problem + * @return this builder + * @see VehicleRoutingActivityCosts + */ + public Builder setActivityCosts(VehicleRoutingActivityCosts activityCosts){ + this.activityCosts = activityCosts; + return this; + } - /** - * Builds the {@link VehicleRoutingProblem}. - *

- *

If {@link VehicleRoutingTransportCosts} are not set, {@link CrowFlyCosts} is used. - * - * @return {@link VehicleRoutingProblem} - */ - public VehicleRoutingProblem build() { - if (transportCosts == null) { - transportCosts = new CrowFlyCosts(getLocations()); - } - for (Job job : tentativeJobs.values()) + /** + * Builds the {@link VehicleRoutingProblem}. + * + *

If {@link VehicleRoutingTransportCosts} are not set, {@link CrowFlyCosts} is used. + * + * @return {@link VehicleRoutingProblem} + */ + public VehicleRoutingProblem build() { + if(transportCosts == null){ + transportCosts = new CrowFlyCosts(getLocations()); + } + for(Job job : tentativeJobs.values()) if (!jobsInInitialRoutes.contains(job.getId())) { addJobToFinalJobMapAndCreateActivities(job); } - return new VehicleRoutingProblem(this); - } + return new VehicleRoutingProblem(this); + } @SuppressWarnings("UnusedDeclaration") public Builder addLocation(String locationId, Coordinate coordinate) { - tentative_coordinates.put(locationId, coordinate); - return this; - } + tentative_coordinates.put(locationId, coordinate); + return this; + } - /** - * Adds a collection of jobs. - * - * @param jobs which is a collection of jobs that subclasses Job - * @return this builder - */ - @SuppressWarnings("deprecation") + /** + * Adds a collection of jobs. + * + * @param jobs which is a collection of jobs that subclasses Job + * @return this builder + */ + @SuppressWarnings("deprecation") public Builder addAllJobs(Collection jobs) { - for (Job j : jobs) { - addJob(j); - } - return this; - } + for(Job j : jobs){ + addJob(j); + } + return this; + } - /** - * Adds a collection of vehicles. - * - * @param vehicles vehicles to be added - * @return this builder - */ - @SuppressWarnings("deprecation") + /** + * Adds a collection of vehicles. + * + * @param vehicles vehicles to be added + * @return this builder + */ + @SuppressWarnings("deprecation") public Builder addAllVehicles(Collection vehicles) { - for (Vehicle v : vehicles) { - addVehicle(v); - } - return this; - } + for(Vehicle v : vehicles){ + addVehicle(v); + } + return this; + } - /** - * Gets an unmodifiable collection of already added vehicles. - * - * @return collection of vehicles - */ - public Collection getAddedVehicles() { - return Collections.unmodifiableCollection(uniqueVehicles); - } + /** + * Gets an unmodifiable collection of already added vehicles. + * + * @return collection of vehicles + */ + public Collection getAddedVehicles(){ + return Collections.unmodifiableCollection(uniqueVehicles); + } - /** - * Gets an unmodifiable collection of already added vehicle-types. - * - * @return collection of vehicle-types - */ - public Collection getAddedVehicleTypes() { - return Collections.unmodifiableCollection(vehicleTypes); - } + /** + * Gets an unmodifiable collection of already added vehicle-types. + * + * @return collection of vehicle-types + */ + public Collection getAddedVehicleTypes(){ + return Collections.unmodifiableCollection(vehicleTypes); + } /** * Returns an unmodifiable collection of already added jobs. * * @return collection of jobs */ - public Collection getAddedJobs() { - return Collections.unmodifiableCollection(tentativeJobs.values()); - } + public Collection getAddedJobs(){ + return Collections.unmodifiableCollection(tentativeJobs.values()); + } private Builder addService(Service service) { tentative_coordinates.put(service.getLocation().getId(), service.getLocation().getCoordinate()); @@ -478,58 +468,59 @@ public class VehicleRoutingProblem { } - } +} - /** - * Enum that characterizes the fleet-size. - * - * @author sschroeder - */ - public static enum FleetSize { - FINITE, INFINITE - } + /** + * Enum that characterizes the fleet-size. + * + * @author sschroeder + * + */ + public static enum FleetSize { + FINITE, INFINITE + } - /** - * logger logging for this class - */ - private final static Logger logger = LogManager.getLogger(VehicleRoutingProblem.class); + /** + * logger logging for this class + */ + private final static Logger logger = LogManager.getLogger(VehicleRoutingProblem.class); - /** - * contains transportation costs, i.e. the costs traveling from location A to B - */ - private final VehicleRoutingTransportCosts transportCosts; + /** + * contains transportation costs, i.e. the costs traveling from location A to B + */ + private final VehicleRoutingTransportCosts transportCosts; - /** - * contains activity costs, i.e. the costs imposed by an activity - */ - private final VehicleRoutingActivityCosts activityCosts; + /** + * contains activity costs, i.e. the costs imposed by an activity + */ + private final VehicleRoutingActivityCosts activityCosts; - /** - * map of jobs, stored by jobId - */ - private final Map jobs; + /** + * map of jobs, stored by jobId + */ + private final Map jobs; - /** - * Collection that contains available vehicles. - */ - private final Collection vehicles; + /** + * Collection that contains available vehicles. + */ + private final Collection vehicles; - /** - * Collection that contains all available types. - */ - private final Collection vehicleTypes; + /** + * Collection that contains all available types. + */ + private final Collection vehicleTypes; - private final Collection initialVehicleRoutes; + private final Collection initialVehicleRoutes; - /** - * An enum that indicates type of fleetSize. By default, it is INFINTE - */ - private final FleetSize fleetSize; + /** + * An enum that indicates type of fleetSize. By default, it is INFINTE + */ + private final FleetSize fleetSize; - private final Locations locations; + private final Locations locations; - private Map> activityMap; + private Map> activityMap; private int nuActivities; @@ -542,15 +533,15 @@ public class VehicleRoutingProblem { }; - private VehicleRoutingProblem(Builder builder) { - this.jobs = builder.jobs; - this.fleetSize = builder.fleetSize; - this.vehicles = builder.uniqueVehicles; - this.vehicleTypes = builder.vehicleTypes; - this.initialVehicleRoutes = builder.initialRoutes; - this.transportCosts = builder.transportCosts; - this.activityCosts = builder.activityCosts; - this.locations = builder.getLocations(); + private VehicleRoutingProblem(Builder builder) { + this.jobs = builder.jobs; + this.fleetSize = builder.fleetSize; + this.vehicles=builder.uniqueVehicles; + this.vehicleTypes = builder.vehicleTypes; + this.initialVehicleRoutes = builder.initialRoutes; + this.transportCosts = builder.transportCosts; + this.activityCosts = builder.activityCosts; + this.locations = builder.getLocations(); this.activityMap = builder.activityMap; this.nuActivities = builder.activityIndexCounter; logger.info("setup problem: {}", this); @@ -562,103 +553,101 @@ public class VehicleRoutingProblem { "transportCost=" + transportCosts + "][activityCosts=" + activityCosts + "]"; } - /** - * Returns type of fleetSize, either INFINITE or FINITE. - *

- *

By default, it is INFINITE. - * - * @return either FleetSize.INFINITE or FleetSize.FINITE - */ - public FleetSize getFleetSize() { - return fleetSize; - } + /** + * Returns type of fleetSize, either INFINITE or FINITE. + * + *

By default, it is INFINITE. + * + * @return either FleetSize.INFINITE or FleetSize.FINITE + */ + public FleetSize getFleetSize() { + return fleetSize; + } - /** - * Returns the unmodifiable job map. - * - * @return unmodifiable jobMap - */ - public Map getJobs() { - return Collections.unmodifiableMap(jobs); - } + /** + * Returns the unmodifiable job map. + * + * @return unmodifiable jobMap + */ + public Map getJobs() { + return Collections.unmodifiableMap(jobs); + } /** * Returns a copy of initial vehicle routes. * * @return copied collection of initial vehicle routes */ - public Collection getInitialVehicleRoutes() { - Collection copiedInitialRoutes = new ArrayList(); - for (VehicleRoute route : initialVehicleRoutes) { + public Collection getInitialVehicleRoutes(){ + Collection copiedInitialRoutes = new ArrayList(); + for(VehicleRoute route : initialVehicleRoutes){ copiedInitialRoutes.add(VehicleRoute.copyOf(route)); } return copiedInitialRoutes; - } + } - /** - * Returns the entire, unmodifiable collection of types. - * - * @return unmodifiable collection of types - * @see VehicleTypeImpl - */ - public Collection getTypes() { - return Collections.unmodifiableCollection(vehicleTypes); - } + /** + * Returns the entire, unmodifiable collection of types. + * + * @return unmodifiable collection of types + * @see VehicleTypeImpl + */ + public Collection getTypes(){ + return Collections.unmodifiableCollection(vehicleTypes); + } - /** - * Returns the entire, unmodifiable collection of vehicles. - * - * @return unmodifiable collection of vehicles - * @see Vehicle - */ - public Collection getVehicles() { - return Collections.unmodifiableCollection(vehicles); - } + /** + * Returns the entire, unmodifiable collection of vehicles. + * + * @return unmodifiable collection of vehicles + * @see Vehicle + */ + public Collection getVehicles() { + return Collections.unmodifiableCollection(vehicles); + } - /** - * Returns routing costs. - * - * @return routingCosts - * @see VehicleRoutingTransportCosts - */ - public VehicleRoutingTransportCosts getTransportCosts() { - return transportCosts; - } + /** + * Returns routing costs. + * + * @return routingCosts + * @see VehicleRoutingTransportCosts + */ + public VehicleRoutingTransportCosts getTransportCosts() { + return transportCosts; + } - /** - * Returns activityCosts. - */ - public VehicleRoutingActivityCosts getActivityCosts() { - return activityCosts; - } + /** + * Returns activityCosts. + */ + public VehicleRoutingActivityCosts getActivityCosts(){ + return activityCosts; + } /** * @return returns all location, i.e. from vehicles and jobs. */ - public Locations getLocations() { - return locations; - } + public Locations getLocations(){ + return locations; + } /** * @param job for which the corresponding activities needs to be returned * @return associated activities */ - public List getActivities(Job job) { + public List getActivities(Job job){ return Collections.unmodifiableList(activityMap.get(job)); } /** * @return total number of activities */ - public int getNuActivities() { - return nuActivities; - } + public int getNuActivities(){ return nuActivities; } /** * @return factory that creates the activities associated to a job */ - public JobActivityFactory getJobActivityFactory() { + public JobActivityFactory getJobActivityFactory(){ return jobActivityFactory; } @@ -666,9 +655,9 @@ public class VehicleRoutingProblem { * @param job for which the corresponding activities needs to be returned * @return a copy of the activities that are associated to the specified job */ - public List copyAndGetActivities(Job job) { + public List copyAndGetActivities(Job job){ List acts = new ArrayList(); - if (activityMap.containsKey(job)) { + if(activityMap.containsKey(job)) { for (AbstractActivity act : activityMap.get(job)) acts.add((AbstractActivity) act.duplicate()); } return acts; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/cost/WaitingTimeCosts.java b/jsprit-core/src/main/java/jsprit/core/problem/cost/WaitingTimeCosts.java new file mode 100644 index 00000000..91103616 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/problem/cost/WaitingTimeCosts.java @@ -0,0 +1,20 @@ +package jsprit.core.problem.cost; + +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; + +/** + * Created by schroeder on 23/07/15. + */ +public class WaitingTimeCosts implements VehicleRoutingActivityCosts { + + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { + if(vehicle != null){ + return vehicle.getType().getVehicleCostParams().perWaitingTimeUnit * Math.max(0.,tourAct.getTheoreticalEarliestOperationStartTime()-arrivalTime); + } + return 0; + } + +} diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java index 9f427163..bb46d7a5 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java @@ -25,69 +25,71 @@ import java.util.HashMap; import java.util.Map; -class InfiniteVehicles implements VehicleFleetManager { - private static Logger logger = LogManager.getLogger(InfiniteVehicles.class); - private Map types = new HashMap(); +class InfiniteVehicles implements VehicleFleetManager{ + + private static Logger logger = LogManager.getLogger(InfiniteVehicles.class); + + private Map types = new HashMap(); // private List sortedTypes = new ArrayList(); - public InfiniteVehicles(Collection vehicles) { - extractTypes(vehicles); - logger.debug("initialise {}", this); - } + public InfiniteVehicles(Collection vehicles){ + extractTypes(vehicles); + logger.debug("initialise " + this); + } - @Override - public String toString() { - return "[name=infiniteVehicle]"; - } + @Override + public String toString() { + return "[name=infiniteVehicle]"; + } - private void extractTypes(Collection vehicles) { - for (Vehicle v : vehicles) { - VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); - types.put(typeKey, v); + private void extractTypes(Collection vehicles) { + for(Vehicle v : vehicles){ + VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(),v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills(), v.isReturnToDepot()); + types.put(typeKey,v); // sortedTypes.add(typeKey); - } - } + } + } - @Override - public void lock(Vehicle vehicle) { + @Override + public void lock(Vehicle vehicle) { - } + } - @Override - public void unlock(Vehicle vehicle) { + @Override + public void unlock(Vehicle vehicle) { - } + } - @Override - public boolean isLocked(Vehicle vehicle) { - return false; - } + @Override + public boolean isLocked(Vehicle vehicle) { + return false; + } - @Override - public void unlockAll() { + @Override + public void unlockAll() { - } + } - @Override - public Collection getAvailableVehicles() { - return types.values(); - } + @Override + public Collection getAvailableVehicles() { + return types.values(); + } - @Override - public Collection getAvailableVehicles(Vehicle withoutThisType) { - Collection vehicles = new ArrayList(); - VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocation().getId(), withoutThisType.getEndLocation().getId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills()); - for (VehicleTypeKey key : types.keySet()) { - if (!key.equals(thisKey)) { - vehicles.add(types.get(key)); - } - } - return vehicles; - } + @Override + public Collection getAvailableVehicles(Vehicle withoutThisType) { + Collection vehicles = new ArrayList(); + VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocation().getId(), withoutThisType.getEndLocation().getId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills(), withoutThisType.isReturnToDepot()); + for(VehicleTypeKey key : types.keySet()){ + if(!key.equals(thisKey)){ + vehicles.add(types.get(key)); + } + } + return vehicles; + } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java index 64b06a22..119a179f 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java @@ -70,4 +70,5 @@ public interface Vehicle extends HasId, HasIndex { public abstract VehicleTypeKey getVehicleTypeIdentifier(); public abstract Skills getSkills(); + } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java index 556825cb..83438ba9 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java @@ -25,184 +25,186 @@ import java.util.*; class VehicleFleetManagerImpl implements VehicleFleetManager { - public VehicleFleetManagerImpl newInstance(Collection vehicles) { - return new VehicleFleetManagerImpl(vehicles); - } + public VehicleFleetManagerImpl newInstance(Collection vehicles){ + return new VehicleFleetManagerImpl(vehicles); + } - static class TypeContainer { + static class TypeContainer { - private ArrayList vehicleList; + private ArrayList vehicleList; - public TypeContainer() { - super(); - vehicleList = new ArrayList(); - } + public TypeContainer() { + super(); + vehicleList = new ArrayList(); + } - void add(Vehicle vehicle) { - if (vehicleList.contains(vehicle)) { - throw new IllegalStateException("cannot add vehicle twice " + vehicle.getId()); - } - vehicleList.add(vehicle); - } + void add(Vehicle vehicle){ + if(vehicleList.contains(vehicle)){ + throw new IllegalStateException("cannot add vehicle twice " + vehicle.getId()); + } + vehicleList.add(vehicle); + } - void remove(Vehicle vehicle) { - vehicleList.remove(vehicle); - } + void remove(Vehicle vehicle){ + vehicleList.remove(vehicle); + } - public Vehicle getVehicle() { - return vehicleList.get(0); + public Vehicle getVehicle() { + return vehicleList.get(0); // return vehicleList.getFirst(); - } + } - public boolean isEmpty() { - return vehicleList.isEmpty(); - } + public boolean isEmpty() { + return vehicleList.isEmpty(); + } - } + } - private static Logger logger = LogManager.getLogger(VehicleFleetManagerImpl.class); + private static Logger logger = LogManager.getLogger(VehicleFleetManagerImpl.class); - private Collection vehicles; + private Collection vehicles; - private Set lockedVehicles; + private Set lockedVehicles; - private Map typeMapOfAvailableVehicles; + private Map typeMapOfAvailableVehicles; - private Map penaltyVehicles = new HashMap(); + private Map penaltyVehicles = new HashMap(); - public VehicleFleetManagerImpl(Collection vehicles) { - super(); - this.vehicles = vehicles; - this.lockedVehicles = new HashSet(); - makeMap(); - logger.debug("initialise {}", this); - } + public VehicleFleetManagerImpl(Collection vehicles) { + super(); + this.vehicles = vehicles; + this.lockedVehicles = new HashSet(); + makeMap(); + logger.debug("initialise " + this); + } - @Override - public String toString() { - return "[name=finiteVehicles]"; - } + @Override + public String toString() { + return "[name=finiteVehicles]"; + } - private void makeMap() { - typeMapOfAvailableVehicles = new HashMap(); - penaltyVehicles = new HashMap(); - for (Vehicle v : vehicles) { - addVehicle(v); - } - } + private void makeMap() { + typeMapOfAvailableVehicles = new HashMap(); + penaltyVehicles = new HashMap(); + for(Vehicle v : vehicles){ + addVehicle(v); + } + } - private void addVehicle(Vehicle v) { - if (v.getType() == null) { - throw new IllegalStateException("vehicle needs type"); - } - VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); - if (!typeMapOfAvailableVehicles.containsKey(typeKey)) { - typeMapOfAvailableVehicles.put(typeKey, new TypeContainer()); - } - typeMapOfAvailableVehicles.get(typeKey).add(v); + private void addVehicle(Vehicle v) { + if(v.getType() == null){ + throw new IllegalStateException("vehicle needs type"); + } + VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills(),v.isReturnToDepot() ); + if(!typeMapOfAvailableVehicles.containsKey(typeKey)){ + typeMapOfAvailableVehicles.put(typeKey, new TypeContainer()); + } + typeMapOfAvailableVehicles.get(typeKey).add(v); - } + } - private void removeVehicle(Vehicle v) { - VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); - if (typeMapOfAvailableVehicles.containsKey(key)) { - typeMapOfAvailableVehicles.get(key).remove(v); - } - } + private void removeVehicle(Vehicle v){ + VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills(),v.isReturnToDepot() ); + if(typeMapOfAvailableVehicles.containsKey(key)){ + typeMapOfAvailableVehicles.get(key).remove(v); + } + } - /** - * Returns a collection of available vehicles. - *

- *

If there is no vehicle with a certain type and location anymore, it looks up whether a penalty vehicle has been specified with - * this type and location. If so, it returns this penalty vehicle. If not, no vehicle with this type and location is returned. - */ - @Override - public Collection getAvailableVehicles() { - List vehicles = new ArrayList(); - for (VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()) { - if (!typeMapOfAvailableVehicles.get(key).isEmpty()) { - vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle()); - } else { - if (penaltyVehicles.containsKey(key)) { - vehicles.add(penaltyVehicles.get(key)); - } - } - } - return vehicles; - } + /** + * Returns a collection of available vehicles. + * + *

If there is no vehicle with a certain type and location anymore, it looks up whether a penalty vehicle has been specified with + * this type and location. If so, it returns this penalty vehicle. If not, no vehicle with this type and location is returned. + */ + @Override + public Collection getAvailableVehicles() { + List vehicles = new ArrayList(); + for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){ + if(!typeMapOfAvailableVehicles.get(key).isEmpty()){ + vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle()); + } + else{ + if(penaltyVehicles.containsKey(key)){ + vehicles.add(penaltyVehicles.get(key)); + } + } + } + return vehicles; + } - @Override - public Collection getAvailableVehicles(Vehicle withoutThisType) { - List vehicles = new ArrayList(); - VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocation().getId(), withoutThisType.getEndLocation().getId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills()); - for (VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()) { - if (key.equals(thisKey)) continue; - if (!typeMapOfAvailableVehicles.get(key).isEmpty()) { - vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle()); - } else { - if (penaltyVehicles.containsKey(key)) { - vehicles.add(penaltyVehicles.get(key)); - } - } - } - return vehicles; - } + @Override + public Collection getAvailableVehicles(Vehicle withoutThisType) { + List vehicles = new ArrayList(); + VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocation().getId(), withoutThisType.getEndLocation().getId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills(),withoutThisType.isReturnToDepot() ); + for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){ + if(key.equals(thisKey)) continue; + if(!typeMapOfAvailableVehicles.get(key).isEmpty()){ + vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle()); + } + else{ + if(penaltyVehicles.containsKey(key)){ + vehicles.add(penaltyVehicles.get(key)); + } + } + } + return vehicles; + } - /* (non-Javadoc) - * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#lock(org.matsim.contrib.freight.vrp.basics.Vehicle) - */ - @Override - public void lock(Vehicle vehicle) { - if (vehicles.isEmpty() || vehicle instanceof NoVehicle) { - return; - } - boolean locked = lockedVehicles.add(vehicle); - removeVehicle(vehicle); - if (!locked) { - throw new IllegalStateException("cannot lock vehicle twice " + vehicle.getId()); - } - } + /* (non-Javadoc) + * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#lock(org.matsim.contrib.freight.vrp.basics.Vehicle) + */ + @Override + public void lock(Vehicle vehicle){ + if(vehicles.isEmpty() || vehicle instanceof NoVehicle){ + return; + } + boolean locked = lockedVehicles.add(vehicle); + removeVehicle(vehicle); + if(!locked){ + throw new IllegalStateException("cannot lock vehicle twice " + vehicle.getId()); + } + } - /* (non-Javadoc) - * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlock(org.matsim.contrib.freight.vrp.basics.Vehicle) - */ - @Override - public void unlock(Vehicle vehicle) { - if (vehicles.isEmpty() || vehicle instanceof NoVehicle) { - return; - } - if (vehicle == null) return; - lockedVehicles.remove(vehicle); - addVehicle(vehicle); - } + /* (non-Javadoc) + * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlock(org.matsim.contrib.freight.vrp.basics.Vehicle) + */ + @Override + public void unlock(Vehicle vehicle){ + if(vehicles.isEmpty() || vehicle instanceof NoVehicle){ + return; + } + if(vehicle == null) return; + lockedVehicles.remove(vehicle); + addVehicle(vehicle); + } - /* (non-Javadoc) - * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#isLocked(org.matsim.contrib.freight.vrp.basics.Vehicle) - */ - @Override - public boolean isLocked(Vehicle vehicle) { - return lockedVehicles.contains(vehicle); - } + /* (non-Javadoc) + * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#isLocked(org.matsim.contrib.freight.vrp.basics.Vehicle) + */ + @Override + public boolean isLocked(Vehicle vehicle) { + return lockedVehicles.contains(vehicle); + } - /* (non-Javadoc) - * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlockAll() - */ - @Override - public void unlockAll() { - Collection locked = new ArrayList(lockedVehicles); - for (Vehicle v : locked) { - unlock(v); - } - if (!lockedVehicles.isEmpty()) { - throw new IllegalStateException("no vehicle must be locked"); - } - } + /* (non-Javadoc) + * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlockAll() + */ + @Override + public void unlockAll() { + Collection locked = new ArrayList(lockedVehicles); + for(Vehicle v : locked){ + unlock(v); + } + if(!lockedVehicles.isEmpty()){ + throw new IllegalStateException("no vehicle must be locked"); + } + } - @Deprecated - public int sizeOfLockedVehicles() { - return lockedVehicles.size(); - } + @Deprecated + public int sizeOfLockedVehicles(){ + return lockedVehicles.size(); + } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java index 70db61f3..45e6f26a 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java @@ -23,29 +23,34 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; + /** * Implementation of {@link Vehicle}. * * @author stefan schroeder + * */ -public class VehicleImpl extends AbstractVehicle { +public class VehicleImpl extends AbstractVehicle{ + + /** - * Extension of {@link VehicleImpl} representing an unspecified vehicle with the id 'noVehicle' - * (to avoid null). - * - * @author schroeder - */ - public static class NoVehicle extends AbstractVehicle { + * Extension of {@link VehicleImpl} representing an unspecified vehicle with the id 'noVehicle' + * (to avoid null). + * + * @author schroeder + * + */ + public static class NoVehicle extends AbstractVehicle { private String id = "noVehicle"; private VehicleType type = VehicleTypeImpl.Builder.newInstance("noType").build(); - public NoVehicle() { - } + public NoVehicle() { + } @Override public double getEarliestDeparture() { @@ -88,28 +93,29 @@ public class VehicleImpl extends AbstractVehicle { } } - /** - * Builder that builds the vehicle. - *

- *

By default, earliestDepartureTime is 0.0, latestDepartureTime is Double.MAX_VALUE, - * it returns to the depot and its {@link VehicleType} is the DefaultType with typeId equal to 'default' - * and a capacity of 0. - * - * @author stefan - */ - public static class Builder { + /** + * Builder that builds the vehicle. + * + *

By default, earliestDepartureTime is 0.0, latestDepartureTime is Double.MAX_VALUE, + * it returns to the depot and its {@link VehicleType} is the DefaultType with typeId equal to 'default' + * and a capacity of 0. + * + * @author stefan + * + */ + public static class Builder { static final Logger log = LogManager.getLogger(Builder.class.getName()); private String id; - private double earliestStart = 0.0; + private double earliestStart = 0.0; - private double latestArrival = Double.MAX_VALUE; + private double latestArrival = Double.MAX_VALUE; - private boolean returnToDepot = true; + private boolean returnToDepot = true; - private VehicleType type = VehicleTypeImpl.Builder.newInstance("default").build(); + private VehicleType type = VehicleTypeImpl.Builder.newInstance("default").build(); private Skills.Builder skillBuilder = Skills.Builder.newInstance(); @@ -120,124 +126,120 @@ public class VehicleImpl extends AbstractVehicle { private Location endLocation; private Builder(String id) { - super(); - this.id = id; - } + super(); + this.id = id; + } - /** - * Sets the {@link VehicleType}.
- * - * @param type the type to be set - * @return this builder - * @throws IllegalStateException if type is null - */ - public Builder setType(VehicleType type) { - if (type == null) throw new IllegalStateException("type cannot be null."); - this.type = type; - return this; - } + /** + * Sets the {@link VehicleType}.
+ * + * @param type the type to be set + * @throws IllegalStateException if type is null + * @return this builder + */ + public Builder setType(VehicleType type){ + if(type==null) throw new IllegalStateException("type cannot be null."); + this.type = type; + return this; + } - /** - * Sets the flag whether the vehicle must return to depot or not. - *

- *

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. - *

- *

If returnToDepot is false, the end-location of the vehicle is endogenous. - * - * @param returnToDepot true if vehicle need to return to depot, otherwise false - * @return this builder - */ - public Builder setReturnToDepot(boolean returnToDepot) { - this.returnToDepot = returnToDepot; - return this; - } + /** + * Sets the flag whether the vehicle must return to depot or not. + * + *

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. + * + *

If returnToDepot is false, the end-location of the vehicle is endogenous. + * + * @param returnToDepot true if vehicle need to return to depot, otherwise false + * @return this builder + */ + public Builder setReturnToDepot(boolean returnToDepot){ + this.returnToDepot = returnToDepot; + return this; + } /** * Sets start location. - * * @param startLocation start location * @return start location */ - public Builder setStartLocation(Location startLocation) { + public Builder setStartLocation(Location startLocation){ this.startLocation = startLocation; return this; } - public Builder setEndLocation(Location endLocation) { + public Builder setEndLocation(Location endLocation){ this.endLocation = endLocation; return this; } - /** - * Sets earliest-start of vehicle which should be the lower bound of the vehicle's departure times. - * - * @param earliest_startTime the earliest start time / departure time of the vehicle at its start location - * @return this builder - */ - public Builder setEarliestStart(double earliest_startTime) { - this.earliestStart = earliest_startTime; - return this; - } + /** + * Sets earliest-start of vehicle which should be the lower bound of the vehicle's departure times. + * + * @param earliest_startTime the earliest start time / departure time of the vehicle at its start location + * @return this builder + */ + public Builder setEarliestStart(double earliest_startTime){ + this.earliestStart = earliest_startTime; + return this; + } - /** - * Sets the latest arrival at vehicle's end-location which is the upper bound of the vehicle's arrival times. - * - * @param latest_arrTime the latest arrival time of the vehicle at its end location - * @return this builder - */ - public Builder setLatestArrival(double latest_arrTime) { - this.latestArrival = latest_arrTime; - return this; - } + /** + * Sets the latest arrival at vehicle's end-location which is the upper bound of the vehicle's arrival times. + * + * @param latest_arrTime the latest arrival time of the vehicle at its end location + * @return this builder + */ + public Builder setLatestArrival(double latest_arrTime){ + this.latestArrival = latest_arrTime; + return this; + } - public Builder addSkill(String skill) { + public Builder addSkill(String skill){ skillBuilder.addSkill(skill); return this; } - /** - * Builds and returns the vehicle. - *

- *

if {@link VehicleType} is not set, default vehicle-type is set with id="default" and - * capacity=0 - *

- *

if startLocationId || locationId is null (=> startLocationCoordinate || locationCoordinate must be set) then startLocationId=startLocationCoordinate.toString() - * and locationId=locationCoordinate.toString() [coord.toString() --> [x=x_val][y=y_val]) - *

if endLocationId is null and endLocationCoordinate is set then endLocationId=endLocationCoordinate.toString() - *

if endLocationId==null AND endLocationCoordinate==null then endLocationId=startLocationId AND endLocationCoord=startLocationCoord - * Thus endLocationId can never be null even returnToDepot is false. - * - * @return vehicle - * @throws IllegalStateException if both locationId and locationCoord is not set or (endLocationCoord!=null AND returnToDepot=false) - * or (endLocationId!=null AND returnToDepot=false) - */ - public VehicleImpl build() { - if (startLocation != null && endLocation != null) { - if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot) - throw new IllegalStateException("this must not be. you specified both endLocationId and open-routes. this is contradictory.
" + + /** + * Builds and returns the vehicle. + * + *

if {@link VehicleType} is not set, default vehicle-type is set with id="default" and + * capacity=0 + * + *

if startLocationId || locationId is null (=> startLocationCoordinate || locationCoordinate must be set) then startLocationId=startLocationCoordinate.toString() + * and locationId=locationCoordinate.toString() [coord.toString() --> [x=x_val][y=y_val]) + *

if endLocationId is null and endLocationCoordinate is set then endLocationId=endLocationCoordinate.toString() + *

if endLocationId==null AND endLocationCoordinate==null then endLocationId=startLocationId AND endLocationCoord=startLocationCoord + * Thus endLocationId can never be null even returnToDepot is false. + * + * @return vehicle + * @throws IllegalStateException if both locationId and locationCoord is not set or (endLocationCoord!=null AND returnToDepot=false) + * or (endLocationId!=null AND returnToDepot=false) + */ + public VehicleImpl build(){ + if(startLocation != null && endLocation != null){ + if( !startLocation.getId().equals(endLocation.getId()) && !returnToDepot) throw new IllegalStateException("this must not be. you specified both endLocationId and open-routes. this is contradictory.
" + "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) { - throw new IllegalStateException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set"); - } + if(startLocation == null && endLocation == null) { + throw new IllegalStateException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set"); + } skills = skillBuilder.build(); return new VehicleImpl(this); - } + } - /** - * Returns new instance of vehicle builder. - * - * @param vehicleId the id of the vehicle which must be a unique identifier among all vehicles - * @return vehicle builder - */ - public static Builder newInstance(String vehicleId) { - return new Builder(vehicleId); - } + /** + * Returns new instance of vehicle builder. + * + * @param vehicleId the id of the vehicle which must be a unique identifier among all vehicles + * @return vehicle builder + */ + public static Builder newInstance(String vehicleId){ return new Builder(vehicleId); } public Builder addSkills(Skills skills) { this.skillBuilder.addAllSkills(skills.values()); @@ -245,26 +247,26 @@ public class VehicleImpl extends AbstractVehicle { } } - /** - * Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id. - *

- *

NoVehicle has id="noVehicle" and extends {@link VehicleImpl} - * - * @return emptyVehicle - */ - public static NoVehicle createNoVehicle() { - return new NoVehicle(); - } + /** + * Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id. + * + *

NoVehicle has id="noVehicle" and extends {@link VehicleImpl} + * + * @return emptyVehicle + */ + public static NoVehicle createNoVehicle(){ + return new NoVehicle(); + } - private final String id; + private final String id; - private final VehicleType type; + private final VehicleType type; - private final double earliestDeparture; + private final double earliestDeparture; - private final double latestArrival; + private final double latestArrival; - private final boolean returnToDepot; + private final boolean returnToDepot; private final Skills skills; @@ -272,57 +274,57 @@ public class VehicleImpl extends AbstractVehicle { private final Location startLocation; - private VehicleImpl(Builder builder) { - id = builder.id; - type = builder.type; - earliestDeparture = builder.earliestStart; - latestArrival = builder.latestArrival; - returnToDepot = builder.returnToDepot; - skills = builder.skills; + private VehicleImpl(Builder builder){ + id = builder.id; + type = builder.type; + earliestDeparture = builder.earliestStart; + latestArrival = builder.latestArrival; + returnToDepot = builder.returnToDepot; + skills = builder.skills; endLocation = builder.endLocation; startLocation = builder.startLocation; - setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(), startLocation.getId(), endLocation.getId(), earliestDeparture, latestArrival, skills)); - } + setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills)); + } - /** - * Returns String with attributes of this vehicle - *

- *

String has the following format [attr1=val1][attr2=val2]...[attrn=valn] - */ - @Override - public String toString() { - return "[id=" + id + "]" + - "[type=" + type + "]" + - "[startLocation=" + startLocation + "]" + - "[endLocation=" + endLocation + "]" + - "[isReturnToDepot=" + isReturnToDepot() + "]" + - "[skills=" + skills + "]"; + /** + * Returns String with attributes of this vehicle + * + *

String has the following format [attr1=val1][attr2=val2]...[attrn=valn] + */ + @Override + public String toString() { + return "[id="+id+"]" + + "[type="+type+"]" + + "[startLocation="+startLocation+"]" + + "[endLocation=" + endLocation+"]" + + "[isReturnToDepot=" + isReturnToDepot() + "]" + + "[skills="+ skills + "]"; - } + } - @Override - public double getEarliestDeparture() { - return earliestDeparture; - } + @Override + public double getEarliestDeparture() { + return earliestDeparture; + } - @Override - public double getLatestArrival() { - return latestArrival; - } + @Override + public double getLatestArrival() { + return latestArrival; + } - @Override - public VehicleType getType() { - return type; - } + @Override + public VehicleType getType() { + return type; + } - @Override - public String getId() { - return id; - } + @Override + public String getId() { + return id; + } - public boolean isReturnToDepot() { - return returnToDepot; - } + public boolean isReturnToDepot() { + return returnToDepot; + } @Override public Location getStartLocation() { @@ -342,39 +344,41 @@ public class VehicleImpl extends AbstractVehicle { /* (non-Javadoc) * @see java.lang.Object#hashCode() */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((id == null) ? 0 : id.hashCode()); - result = prime * result + ((type == null) ? 0 : type.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + /** + * Two vehicles are equal if they have the same id and if their types are equal. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + VehicleImpl other = (VehicleImpl) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } + - /** - * Two vehicles are equal if they have the same id and if their types are equal. - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - VehicleImpl other = (VehicleImpl) obj; - if (id == null) { - if (other.id != null) - return false; - } else if (!id.equals(other.id)) - return false; - if (type == null) { - if (other.type != null) - return false; - } else if (!type.equals(other.type)) - return false; - return true; - } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java index d043dc8e..6edb9b68 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeImpl.java @@ -21,282 +21,330 @@ import jsprit.core.problem.Capacity; /** * Implementation of {@link VehicleType}. - *

+ * *

Two vehicle-types are equal if they have the same typeId. * * @author schroeder + * */ public class VehicleTypeImpl implements VehicleType { - /** - * CostParameter consisting of fixed cost parameter, time-based cost parameter and distance-based cost parameter. - * - * @author schroeder - */ - public static class VehicleCostParams { + /** + * CostParameter consisting of fixed cost parameter, time-based cost parameter and distance-based cost parameter. + * + * @author schroeder + * + */ + public static class VehicleCostParams { - public static VehicleTypeImpl.VehicleCostParams newInstance(double fix, double perTimeUnit, double perDistanceUnit) { - return new VehicleCostParams(fix, perTimeUnit, perDistanceUnit); - } + public static VehicleTypeImpl.VehicleCostParams newInstance(double fix, double perTimeUnit,double perDistanceUnit){ + return new VehicleCostParams(fix, perTimeUnit, perDistanceUnit); + } - public final double fix; - public final double perTimeUnit; - public final double perDistanceUnit; + public final double fix; + @Deprecated + public final double perTimeUnit; + public final double perTransportTimeUnit; + public final double perDistanceUnit; + public final double perWaitingTimeUnit; - private VehicleCostParams(double fix, double perTimeUnit, double perDistanceUnit) { - super(); - this.fix = fix; - this.perTimeUnit = perTimeUnit; - this.perDistanceUnit = perDistanceUnit; - } + private VehicleCostParams(double fix, double perTimeUnit,double perDistanceUnit) { + super(); + this.fix = fix; + this.perTimeUnit = perTimeUnit; + this.perTransportTimeUnit = perTimeUnit; + this.perDistanceUnit = perDistanceUnit; + this.perWaitingTimeUnit = 0.; + } - @Override - public String toString() { - return "[fixed=" + fix + "][perTime=" + perTimeUnit + "][perDistance=" + perDistanceUnit + "]"; - } - } + public VehicleCostParams(double fix, double perTimeUnit, double perDistanceUnit, double perWaitingTimeUnit) { + this.fix = fix; + this.perTimeUnit = perTimeUnit; + this.perTransportTimeUnit = perTimeUnit; + this.perDistanceUnit = perDistanceUnit; + this.perWaitingTimeUnit = perWaitingTimeUnit; + } - /** - * Builder that builds the vehicle-type. - * - * @author schroeder - */ - public static class Builder { + @Override + public String toString() { + return "[fixed="+fix+"][perTime="+perTransportTimeUnit+"][perDistance="+perDistanceUnit+"][perWaitingTimeUnit="+perWaitingTimeUnit+"]"; + } + } - public static VehicleTypeImpl.Builder newInstance(String id) { - if (id == null) throw new IllegalStateException(); - return new Builder(id); - } + /** + * Builder that builds the vehicle-type. + * + * @author schroeder + * + */ + public static class Builder{ - private String id; - private int capacity = 0; - private double maxVelo = Double.MAX_VALUE; - /** - * default cost values for default vehicle type - */ - private double fixedCost = 0.0; - private double perDistance = 1.0; - private double perTime = 0.0; - private String profile = "car"; - private Capacity.Builder capacityBuilder = Capacity.Builder.newInstance(); + public static VehicleTypeImpl.Builder newInstance(String id) { + if(id==null) throw new IllegalStateException(); + return new Builder(id); + } - private Capacity capacityDimensions = null; + private String id; + private int capacity = 0; + private double maxVelo = Double.MAX_VALUE; + /** + * default cost values for default vehicle type + */ + private double fixedCost = 0.0; + private double perDistance = 1.0; + private double perTime = 0.0; + private double perWaitingTime = 0.0; - private boolean dimensionAdded = false; + private String profile = "car"; - private Builder(String id) { - this.id = id; - } + private Capacity.Builder capacityBuilder = Capacity.Builder.newInstance(); - /** - * Sets the maximum velocity this vehicle-type can go [in meter per seconds]. - * - * @param inMeterPerSeconds - * @return this builder - * @throws IllegalStateException if velocity is smaller than zero - */ - public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) { - if (inMeterPerSeconds < 0.0) throw new IllegalStateException("velocity cannot be smaller than zero"); - this.maxVelo = inMeterPerSeconds; - return this; - } + private Capacity capacityDimensions = null; - /** - * Sets the fixed costs of the vehicle-type. - *

- *

by default it is 0. - * - * @param fixedCost - * @return this builder - * @throws IllegalStateException if fixedCost is smaller than zero - */ - public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { - if (fixedCost < 0.0) throw new IllegalStateException("fixed costs cannot be smaller than zero"); - this.fixedCost = fixedCost; - return this; - } + private boolean dimensionAdded = false; - /** - * Sets the cost per distance unit, for instance € per meter. - *

- *

by default it is 1.0 - * - * @param perDistance - * @return this builder - * @throws IllegalStateException if perDistance is smaller than zero - */ - public VehicleTypeImpl.Builder setCostPerDistance(double perDistance) { - if (perDistance < 0.0) throw new IllegalStateException("cost per distance must not be smaller than zero"); - this.perDistance = perDistance; - return this; - } + private Builder(String id) { + this.id = id; + } - /** - * Sets cost per time unit, for instance € per second. - *

- *

by default it is 0.0 - * - * @param perTime - * @return this builder - * @throws IllegalStateException if costPerTime is smaller than zero - */ - public VehicleTypeImpl.Builder setCostPerTime(double perTime) { - if (perTime < 0.0) throw new IllegalStateException(); - this.perTime = perTime; - return this; - } + /** + * Sets the maximum velocity this vehicle-type can go [in meter per seconds]. + * + * @param inMeterPerSeconds + * @return this builder + * @throws IllegalStateException if velocity is smaller than zero + */ + public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds){ + if(inMeterPerSeconds < 0.0) throw new IllegalStateException("velocity cannot be smaller than zero"); + this.maxVelo = inMeterPerSeconds; return this; + } - /** - * Builds the vehicle-type. - * - * @return VehicleTypeImpl - */ - public VehicleTypeImpl build() { - if (capacityDimensions == null) { - capacityDimensions = capacityBuilder.build(); - } - return new VehicleTypeImpl(this); - } + /** + * Sets the fixed costs of the vehicle-type. + * + *

by default it is 0. + * + * @param fixedCost + * @return this builder + * @throws IllegalStateException if fixedCost is smaller than zero + */ + public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { + if(fixedCost < 0.0) throw new IllegalStateException("fixed costs cannot be smaller than zero"); + this.fixedCost = fixedCost; + return this; + } - /** - * Adds a capacity dimension. - * - * @param dimIndex - * @param dimVal - * @return the builder - * @throws IllegalArgumentException if dimVal < 0 - * @throws IllegalStateException if capacity dimension is already set - */ - public Builder addCapacityDimension(int dimIndex, int dimVal) { - if (dimVal < 0) throw new IllegalArgumentException("capacity value cannot be negative"); - if (capacityDimensions != null) - throw new IllegalStateException("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."); - dimensionAdded = true; - capacityBuilder.addDimension(dimIndex, dimVal); - return this; - } + /** + * Sets the cost per distance unit, for instance € per meter. + * + *

by default it is 1.0 + * + * @param perDistance + * @return this builder + * @throws IllegalStateException if perDistance is smaller than zero + */ + public VehicleTypeImpl.Builder setCostPerDistance(double perDistance){ + if(perDistance < 0.0) throw new IllegalStateException("cost per distance must not be smaller than zero"); + this.perDistance = perDistance; + return this; + } - /** - * Sets capacity dimensions. - *

- *

Note if you use this you cannot use addCapacityDimension(int dimIndex, int dimVal) anymore. Thus either build - * your dimensions with addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with - * this method. - * - * @param capacity - * @return this builder - * @throws IllegalStateException if capacityDimension has already been added - */ - public Builder setCapacityDimensions(Capacity capacity) { - if (dimensionAdded) - throw new IllegalStateException("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."); - this.capacityDimensions = capacity; - return this; - } + /** + * Sets cost per time unit, for instance € per second. + * + *

by default it is 0.0 + * + * @param perTime + * @return this builder + * @throws IllegalStateException if costPerTime is smaller than zero + * @deprecated use .setCostPerTransportTime(..) instead + */ + @Deprecated + public VehicleTypeImpl.Builder setCostPerTime(double perTime){ + if(perTime < 0.0) throw new IllegalStateException(); + this.perTime = perTime; + return this; + } - public Builder setProfile(String profile) { - this.profile = profile; - return this; - } - } + /** + * Sets cost per time unit, for instance € per second. + * + *

by default it is 0.0 + * + * @param perTime + * @return this builder + * @throws IllegalStateException if costPerTime is smaller than zero + * + */ + public VehicleTypeImpl.Builder setCostPerTransportTime(double perTime){ + if(perTime < 0.0) throw new IllegalStateException(); + this.perTime = perTime; + return this; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((typeId == null) ? 0 : typeId.hashCode()); - return result; - } + /** + * Sets cost per waiting time unit, for instance € per second. + * + *

by default it is 0.0 + * + * @param perWaitingTime + * @return this builder + * @throws IllegalStateException if costPerTime is smaller than zero + * + */ + public VehicleTypeImpl.Builder setCostPerWaitingTime(double perWaitingTime){ + if(perWaitingTime < 0.0) throw new IllegalStateException(); + this.perWaitingTime = perWaitingTime; + return this; + } - /** - * Two vehicle-types are equal if they have the same vehicleId. - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - VehicleTypeImpl other = (VehicleTypeImpl) obj; - if (typeId == null) { - if (other.typeId != null) - return false; - } else if (!typeId.equals(other.typeId)) - return false; - return true; - } + /** + * Builds the vehicle-type. + * + * @return VehicleTypeImpl + */ + public VehicleTypeImpl build(){ + if(capacityDimensions == null){ + capacityDimensions = capacityBuilder.build(); + } + return new VehicleTypeImpl(this); + } - private final String typeId; + /** + * Adds a capacity dimension. + * + * @param dimIndex + * @param dimVal + * @return the builder + * @throws IllegalArgumentException if dimVal < 0 + * @throws IllegalStateException if capacity dimension is already set + */ + public Builder addCapacityDimension(int dimIndex, int dimVal) { + if(dimVal<0) throw new IllegalArgumentException("capacity value cannot be negative"); + if(capacityDimensions != null) throw new IllegalStateException("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."); + dimensionAdded = true; + capacityBuilder.addDimension(dimIndex,dimVal); + return this; + } - private final int capacity; + /** + * Sets capacity dimensions. + * + *

Note if you use this you cannot use addCapacityDimension(int dimIndex, int dimVal) anymore. Thus either build + * your dimensions with addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with + * this method. + * + * @param capacity + * @return this builder + * @throws IllegalStateException if capacityDimension has already been added + */ + public Builder setCapacityDimensions(Capacity capacity){ + if(dimensionAdded) throw new IllegalStateException("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."); + this.capacityDimensions = capacity; + return this; + } - private final String profile; + public Builder setProfile(String profile){ + this.profile = profile; + return this; + } + } - private final VehicleTypeImpl.VehicleCostParams vehicleCostParams; + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((typeId == null) ? 0 : typeId.hashCode()); + return result; + } - private final Capacity capacityDimensions; + /** + * Two vehicle-types are equal if they have the same vehicleId. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + VehicleTypeImpl other = (VehicleTypeImpl) obj; + if (typeId == null) { + if (other.typeId != null) + return false; + } else if (!typeId.equals(other.typeId)) + return false; + return true; + } - private final double maxVelocity; + private final String typeId; - /** - * priv constructor constructing vehicle-type - * - * @param builder - */ - private VehicleTypeImpl(VehicleTypeImpl.Builder builder) { - typeId = builder.id; - capacity = builder.capacity; - maxVelocity = builder.maxVelo; - vehicleCostParams = new VehicleCostParams(builder.fixedCost, builder.perTime, builder.perDistance); - capacityDimensions = builder.capacityDimensions; - profile = builder.profile; - } + private final int capacity; - /* (non-Javadoc) - * @see basics.route.VehicleType#getTypeId() - */ - @Override - public String getTypeId() { - return typeId; - } + private final String profile; - /* (non-Javadoc) - * @see basics.route.VehicleType#getVehicleCostParams() - */ - @Override - public VehicleTypeImpl.VehicleCostParams getVehicleCostParams() { - return vehicleCostParams; - } + private final VehicleTypeImpl.VehicleCostParams vehicleCostParams; - @Override - public String toString() { - return "[typeId=" + typeId + "]" + - "[capacity=" + capacityDimensions + "]" + - "[costs=" + vehicleCostParams + "]"; - } + private final Capacity capacityDimensions; - @Override - public double getMaxVelocity() { - return maxVelocity; - } + private final double maxVelocity; - @Override - public Capacity getCapacityDimensions() { - return capacityDimensions; - } + /** + * priv constructor constructing vehicle-type + * + * @param builder + */ + private VehicleTypeImpl(VehicleTypeImpl.Builder builder){ + typeId = builder.id; + capacity = builder.capacity; + maxVelocity = builder.maxVelo; + vehicleCostParams = new VehicleCostParams(builder.fixedCost, builder.perTime, builder.perDistance, builder.perWaitingTime); + capacityDimensions = builder.capacityDimensions; + profile = builder.profile; + } - @Override - public String getProfile() { - return profile; - } + /* (non-Javadoc) + * @see basics.route.VehicleType#getTypeId() + */ + @Override + public String getTypeId() { + return typeId; + } + + /* (non-Javadoc) + * @see basics.route.VehicleType#getVehicleCostParams() + */ + @Override + public VehicleTypeImpl.VehicleCostParams getVehicleCostParams() { + return vehicleCostParams; + } + + @Override + public String toString() { + return "[typeId="+typeId+"]" + + "[capacity="+capacityDimensions+"]" + + "[costs=" + vehicleCostParams + "]"; + } + + @Override + public double getMaxVelocity() { + return maxVelocity; + } + + @Override + public Capacity getCapacityDimensions() { + return capacityDimensions; + } + + @Override + public String getProfile(){ return profile; } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java index 59b85bc8..fd1366f8 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java @@ -23,39 +23,43 @@ import jsprit.core.problem.Skills; /** * Key to identify similar vehicles - *

+ * *

Two vehicles are equal if they share the same type, the same start and end-location and the same earliestStart and latestStart. * * @author stefan + * */ -public class VehicleTypeKey extends AbstractVehicle.AbstractTypeKey { +public class VehicleTypeKey extends AbstractVehicle.AbstractTypeKey{ - public final String type; - public final String startLocationId; - public final String endLocationId; - public final double earliestStart; - public final double latestEnd; + public final String type; + public final String startLocationId; + public final String endLocationId; + public final double earliestStart; + public final double latestEnd; public final Skills skills; + public final boolean returnToDepot; - public VehicleTypeKey(String typeId, String startLocationId, String endLocationId, double earliestStart, double latestEnd, Skills skills) { - super(); - this.type = typeId; - this.startLocationId = startLocationId; - this.endLocationId = endLocationId; - this.earliestStart = earliestStart; - this.latestEnd = latestEnd; + public VehicleTypeKey(String typeId, String startLocationId, String endLocationId, double earliestStart, double latestEnd, Skills skills, boolean returnToDepot) { + super(); + this.type = typeId; + this.startLocationId = startLocationId; + this.endLocationId = endLocationId; + this.earliestStart = earliestStart; + this.latestEnd = latestEnd; this.skills = skills; - } + this.returnToDepot=returnToDepot; + } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof VehicleTypeKey)) return false; + if (o == null || getClass() != o.getClass()) return false; VehicleTypeKey that = (VehicleTypeKey) o; if (Double.compare(that.earliestStart, earliestStart) != 0) return false; if (Double.compare(that.latestEnd, latestEnd) != 0) return false; + if (returnToDepot != that.returnToDepot) return false; if (!endLocationId.equals(that.endLocationId)) return false; if (!skills.equals(that.skills)) return false; if (!startLocationId.equals(that.startLocationId)) return false; @@ -76,16 +80,18 @@ public class VehicleTypeKey extends AbstractVehicle.AbstractTypeKey { temp = Double.doubleToLongBits(latestEnd); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + skills.hashCode(); + result = 31 * result + (returnToDepot ? 1 : 0); return result; } @Override - public String toString() { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(type).append("_").append(startLocationId).append("_").append(endLocationId) - .append("_").append(Double.toString(earliestStart)).append("_").append(Double.toString(latestEnd)); - return stringBuilder.toString(); - } + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(type).append("_").append(startLocationId).append("_").append(endLocationId) + .append("_").append(Double.toString(earliestStart)).append("_").append(Double.toString(latestEnd)); + return stringBuilder.toString(); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/VariableDepartureAndWaitingTime_IT.java b/jsprit-core/src/test/java/jsprit/core/algorithm/VariableDepartureAndWaitingTime_IT.java new file mode 100644 index 00000000..baf2d17d --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/VariableDepartureAndWaitingTime_IT.java @@ -0,0 +1,108 @@ +package jsprit.core.algorithm; + +import jsprit.core.algorithm.box.Jsprit; +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.analysis.SolutionAnalyser; +import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.constraint.ConstraintManager; +import jsprit.core.problem.cost.TransportDistance; +import jsprit.core.problem.cost.VehicleRoutingActivityCosts; +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.SolutionCostCalculator; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.solution.route.activity.TimeWindow; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.util.CostFactory; +import jsprit.core.util.Solutions; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by schroeder on 22/07/15. + */ +public class VariableDepartureAndWaitingTime_IT { + + static interface AlgorithmFactory { + VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp); + } + + VehicleRoutingActivityCosts activityCosts; + + AlgorithmFactory algorithmFactory; + + @Before + public void doBefore(){ + activityCosts = new VehicleRoutingActivityCosts() { + + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { + return vehicle.getType().getVehicleCostParams().perWaitingTimeUnit * Math.max(0,tourAct.getTheoreticalEarliestOperationStartTime() - arrivalTime); + } + + }; + algorithmFactory = new AlgorithmFactory() { + @Override + public VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) { + StateManager stateManager = new StateManager(vrp); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + + return Jsprit.Builder.newInstance(vrp) + .addCoreStateAndConstraintStuff(true) + .setStateAndConstraintManager(stateManager,constraintManager) + .setObjectiveFunction(new SolutionCostCalculator() { + @Override + public double getCosts(VehicleRoutingProblemSolution solution) { + SolutionAnalyser sa = new SolutionAnalyser(vrp, solution, new TransportDistance() { + @Override + public double getDistance(Location from, Location to) { + return vrp.getTransportCosts().getTransportCost(from, to, 0., null, null); + } + }); + return sa.getWaitingTime() + sa.getDistance(); + } + }) + .buildAlgorithm(); + } + }; + } + + @Test + public void plainSetupShouldWork(){ + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build(); + Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(10,0)).build(); + Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(20,0)).build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addJob(s1).addJob(s2).addVehicle(v) + .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) + .setRoutingCost(CostFactory.createManhattanCosts()) + .setActivityCosts(activityCosts) + .build(); + VehicleRoutingAlgorithm vra = algorithmFactory.createAlgorithm(vrp); + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(40.,solution.getCost()); + } + + @Test + public void withTimeWindowsShouldWork(){ + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build(); + Service s1 = Service.Builder.newInstance("s1").setTimeWindow(TimeWindow.newInstance(1010,1100)).setLocation(Location.newInstance(10,0)).build(); + Service s2 = Service.Builder.newInstance("s2").setTimeWindow(TimeWindow.newInstance(1020,1100)).setLocation(Location.newInstance(20,0)).build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addJob(s1).addJob(s2).addVehicle(v) + .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) + .setRoutingCost(CostFactory.createManhattanCosts()) + .setActivityCosts(activityCosts) + .build(); + VehicleRoutingAlgorithm vra = algorithmFactory.createAlgorithm(vrp); + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(40.+1000.,solution.getCost()); + } + + + +} diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ServiceInsertionAndLoadConstraintsTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ServiceInsertionAndLoadConstraintsTest.java index 152dfffc..a41281ab 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ServiceInsertionAndLoadConstraintsTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ServiceInsertionAndLoadConstraintsTest.java @@ -54,49 +54,49 @@ import static org.mockito.Mockito.mock; public class ServiceInsertionAndLoadConstraintsTest { - VehicleRoutingTransportCosts routingCosts; + VehicleRoutingTransportCosts routingCosts; - VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts() { + VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts(){ - @Override - public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { - return 0; - } + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime,Driver driver, Vehicle vehicle) { + return 0; + } - }; + }; - HardActivityConstraint hardActivityLevelConstraint = new HardActivityConstraint() { + HardActivityConstraint hardActivityLevelConstraint = new HardActivityConstraint() { - @Override - public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { - return ConstraintsStatus.FULFILLED; - } - }; + @Override + public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + return ConstraintsStatus.FULFILLED; + } + }; - HardRouteConstraint hardRouteLevelConstraint = new HardRouteConstraint() { + HardRouteConstraint hardRouteLevelConstraint = new HardRouteConstraint(){ - @Override - public boolean fulfilled(JobInsertionContext insertionContext) { - return true; - } + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + return true; + } - }; + }; - ActivityInsertionCostsCalculator activityInsertionCostsCalculator; + ActivityInsertionCostsCalculator activityInsertionCostsCalculator; - ShipmentInsertionCalculator insertionCalculator; + ShipmentInsertionCalculator insertionCalculator; VehicleRoutingProblem vehicleRoutingProblem; - Vehicle vehicle; + Vehicle vehicle; - @Before - public void doBefore() { - routingCosts = CostFactory.createManhattanCosts(); - VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build(); - vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build(); - activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts); - createInsertionCalculator(hardRouteLevelConstraint); + @Before + public void doBefore(){ + routingCosts = CostFactory.createManhattanCosts(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build(); + vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build(); + activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, mock(StateManager.class)); + createInsertionCalculator(hardRouteLevelConstraint); vehicleRoutingProblem = mock(VehicleRoutingProblem.class); } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java index a77f25d0..93aefedf 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java @@ -61,71 +61,71 @@ import static org.mockito.Mockito.when; public class ShipmentInsertionCalculatorTest { - VehicleRoutingTransportCosts routingCosts; + VehicleRoutingTransportCosts routingCosts; VehicleRoutingProblem vehicleRoutingProblem; - VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts() { + VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts(){ - @Override - public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { - return 0; - } + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime,Driver driver, Vehicle vehicle) { + return 0; + } - }; + }; - HardRouteConstraint hardRouteLevelConstraint = new HardRouteConstraint() { + HardRouteConstraint hardRouteLevelConstraint = new HardRouteConstraint(){ - @Override - public boolean fulfilled(JobInsertionContext insertionContext) { - return true; - } + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + return true; + } - }; + }; - ActivityInsertionCostsCalculator activityInsertionCostsCalculator; + ActivityInsertionCostsCalculator activityInsertionCostsCalculator; - ShipmentInsertionCalculator insertionCalculator; + ShipmentInsertionCalculator insertionCalculator; - Vehicle vehicle; + Vehicle vehicle; - @Before - public void doBefore() { - routingCosts = CostFactory.createManhattanCosts(); - VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build(); - vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build(); - activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts); - createInsertionCalculator(hardRouteLevelConstraint); + @Before + public void doBefore(){ + routingCosts = CostFactory.createManhattanCosts(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0, 2).setCostPerDistance(1).build(); + vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setType(type).build(); + activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, mock(StateManager.class)); + createInsertionCalculator(hardRouteLevelConstraint); vehicleRoutingProblem = mock(VehicleRoutingProblem.class); - } + } - private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) { - ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class)); - constraintManager.addConstraint(hardRouteLevelConstraint); - insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); - } + private void createInsertionCalculator(HardRouteConstraint hardRouteLevelConstraint) { + ConstraintManager constraintManager = new ConstraintManager(mock(VehicleRoutingProblem.class), mock(RouteAndActivityStateGetter.class)); + constraintManager.addConstraint(hardRouteLevelConstraint); + insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); + } - @Test - public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - VehicleRoute route = VehicleRoute.emptyRoute(); + @Test + public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + VehicleRoute route = VehicleRoute.emptyRoute(); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); activities.add(new PickupShipment(shipment)); activities.add(new DeliverShipment(shipment)); when(activityFactory.createActivities(shipment)).thenReturn(activities); insertionCalculator.setJobActivityFactory(activityFactory); - InsertionData iData = insertionCalculator.getInsertionData(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(40.0, iData.getInsertionCost(), 0.05); - } + InsertionData iData = insertionCalculator.getInsertionData(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE); + assertEquals(40.0,iData.getInsertionCost(),0.05); + } - @Test - public void whenCalculatingInsertionIntoExistingRoute_itShouldReturnCorrectCosts() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - VehicleRoute route = VehicleRoute.emptyRoute(); - when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); - new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); + @Test + public void whenCalculatingInsertionIntoExistingRoute_itShouldReturnCorrectCosts(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); + new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); @@ -134,11 +134,11 @@ public class ShipmentInsertionCalculatorTest { when(activityFactory.createActivities(shipment2)).thenReturn(activities); insertionCalculator.setJobActivityFactory(activityFactory); - InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(0.0, iData.getInsertionCost(), 0.05); - assertEquals(1, iData.getPickupInsertionIndex()); - assertEquals(2, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); + assertEquals(0.0,iData.getInsertionCost(),0.05); + assertEquals(1,iData.getPickupInsertionIndex()); + assertEquals(2,iData.getDeliveryInsertionIndex()); + } private List getTourActivities(Shipment shipment) { List acts = new ArrayList(); @@ -150,20 +150,20 @@ public class ShipmentInsertionCalculatorTest { } @Test - public void whenInsertingShipmentInRouteWithNotEnoughCapacity_itShouldReturnNoInsertion() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - VehicleRoute route = VehicleRoute.emptyRoute(); + public void whenInsertingShipmentInRouteWithNotEnoughCapacity_itShouldReturnNoInsertion(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + VehicleRoute route = VehicleRoute.emptyRoute(); when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); - new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); - createInsertionCalculator(new HardRouteConstraint() { + new Inserter(new InsertionListeners(), vehicleRoutingProblem).insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); + createInsertionCalculator(new HardRouteConstraint() { - @Override - public boolean fulfilled(JobInsertionContext insertionContext) { - return false; - } + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + return false; + } - }); + }); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); @@ -173,23 +173,23 @@ public class ShipmentInsertionCalculatorTest { insertionCalculator.setJobActivityFactory(activityFactory); InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(InsertionData.createEmptyInsertionData(), iData); + assertEquals(InsertionData.createEmptyInsertionData(),iData); - } + } - @Test - public void whenInsertingThirdShipment_itShouldCalcCorrectVal() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,10")).build(); + @Test + public void whenInsertingThirdShipment_itShouldCalcCorrectVal(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,10")).build(); - VehicleRoute route = VehicleRoute.emptyRoute(); + VehicleRoute route = VehicleRoute.emptyRoute(); when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); when(vehicleRoutingProblem.copyAndGetActivities(shipment2)).thenReturn(getTourActivities(shipment2)); - Inserter inserter = new Inserter(new InsertionListeners(), vehicleRoutingProblem); - inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); - inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route); + Inserter inserter = new Inserter(new InsertionListeners(),vehicleRoutingProblem ); + inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); + inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null),route); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); @@ -198,23 +198,23 @@ public class ShipmentInsertionCalculatorTest { when(activityFactory.createActivities(shipment3)).thenReturn(activities); insertionCalculator.setJobActivityFactory(activityFactory); - InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(0.0, iData.getInsertionCost(), 0.05); - assertEquals(0, iData.getPickupInsertionIndex()); - assertEquals(1, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE); + assertEquals(0.0,iData.getInsertionCost(),0.05); + assertEquals(0,iData.getPickupInsertionIndex()); + assertEquals(1,iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingThirdShipment_itShouldCalcCorrectVal2() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build(); + @Test + public void whenInsertingThirdShipment_itShouldCalcCorrectVal2(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build(); when(vehicleRoutingProblem.copyAndGetActivities(shipment)).thenReturn(getTourActivities(shipment)); when(vehicleRoutingProblem.copyAndGetActivities(shipment2)).thenReturn(getTourActivities(shipment2)); - VehicleRoute route = VehicleRoute.emptyRoute(); - Inserter inserter = new Inserter(new InsertionListeners(), vehicleRoutingProblem); - inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); - inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route); + VehicleRoute route = VehicleRoute.emptyRoute(); + Inserter inserter = new Inserter(new InsertionListeners(), vehicleRoutingProblem); + inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); + inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null),route); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); @@ -225,78 +225,78 @@ public class ShipmentInsertionCalculatorTest { InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(2.0, iData.getInsertionCost(), 0.05); - assertEquals(0, iData.getPickupInsertionIndex()); - assertEquals(1, iData.getDeliveryInsertionIndex()); - } + assertEquals(2.0,iData.getInsertionCost(),0.05); + assertEquals(0,iData.getPickupInsertionIndex()); + assertEquals(1,iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInstertingShipmentWithLoadConstraintWhereCapIsNotSufficient_capConstraintsAreFulfilled() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build(); + @Test + public void whenInstertingShipmentWithLoadConstraintWhereCapIsNotSufficient_capConstraintsAreFulfilled(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("10,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + Shipment shipment3 = Shipment.Builder.newInstance("s3").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,0").build()).setDeliveryLocation(Location.newInstance("9,9")).build(); VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); VehicleRoutingProblem vrp = vrpBuilder.addJob(shipment).addJob(shipment2).addJob(shipment3).build(); VehicleRoute route = VehicleRoute.emptyRoute(); - route.setVehicleAndDepartureTime(vehicle, 0.0); + route.setVehicleAndDepartureTime(vehicle, 0.0); - Inserter inserter = new Inserter(new InsertionListeners(), vrp); - inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); - inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route); + Inserter inserter = new Inserter(new InsertionListeners(), vrp); + inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); + inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null), route); StateManager stateManager = new StateManager(vrp); - stateManager.updateLoadStates(); - stateManager.informInsertionStarts(Arrays.asList(route), null); + stateManager.updateLoadStates(); + stateManager.informInsertionStarts(Arrays.asList(route), null); - ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); - constraintManager.addConstraint(new PickupAndDeliverShipmentLoadActivityLevelConstraint(stateManager), Priority.CRITICAL); - constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(), Priority.CRITICAL); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + constraintManager.addConstraint(new PickupAndDeliverShipmentLoadActivityLevelConstraint(stateManager),Priority.CRITICAL); + constraintManager.addConstraint(new ShipmentPickupsFirstConstraint(),Priority.CRITICAL); - ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, - constraintManager); + ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, + constraintManager); insertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory()); - InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE); - assertTrue(iData instanceof InsertionData.NoInsertionFound); + InsertionData iData = insertionCalculator.getInsertionData(route, shipment3, vehicle, 0.0, DriverImpl.noDriver(), Double.MAX_VALUE); + assertTrue(iData instanceof InsertionData.NoInsertionFound); - } + } - @Test - public void whenInsertingServiceWhileNoCapIsAvailable_itMustReturnNoInsertionData() { - Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); - Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + @Test + public void whenInsertingServiceWhileNoCapIsAvailable_itMustReturnNoInsertionData(){ + Shipment shipment = Shipment.Builder.newInstance("s").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("0,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); + Shipment shipment2 = Shipment.Builder.newInstance("s2").addSizeDimension(0, 1).setPickupLocation(Location.Builder.newInstance().setId("10,10").build()).setDeliveryLocation(Location.newInstance("0,0")).build(); VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); VehicleRoutingProblem vrp = vrpBuilder.addJob(shipment).addJob(shipment2).build(); VehicleRoute route = VehicleRoute.emptyRoute(); - route.setVehicleAndDepartureTime(vehicle, 0.0); + route.setVehicleAndDepartureTime(vehicle, 0.0); - Inserter inserter = new Inserter(new InsertionListeners(), vrp); + Inserter inserter = new Inserter(new InsertionListeners(), vrp); - inserter.insertJob(shipment, new InsertionData(0, 0, 0, vehicle, null), route); - inserter.insertJob(shipment2, new InsertionData(0, 1, 2, vehicle, null), route); + inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route); + inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null), route); - StateManager stateManager = new StateManager(vrp); - stateManager.updateLoadStates(); - stateManager.informInsertionStarts(Arrays.asList(route), null); + StateManager stateManager = new StateManager(vrp); + stateManager.updateLoadStates(); + stateManager.informInsertionStarts(Arrays.asList(route), null); - ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); - constraintManager.addLoadConstraint(); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + constraintManager.addLoadConstraint(); - stateManager.informInsertionStarts(Arrays.asList(route), null); + stateManager.informInsertionStarts(Arrays.asList(route), null); - JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); - ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); - ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); - switcher.put(Pickup.class, serviceInsertionCalc); - switcher.put(Service.class, serviceInsertionCalc); - switcher.put(Shipment.class, insertionCalculator); + JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); + ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); + ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, constraintManager); + switcher.put(Pickup.class, serviceInsertionCalc); + switcher.put(Service.class, serviceInsertionCalc); + switcher.put(Shipment.class, insertionCalculator); // Service service = Service.Builder.newInstance("pick", 1).setLocationId("5,5").build(); - Pickup service = (Pickup) Pickup.Builder.newInstance("pick").addSizeDimension(0, 1).setLocation(Location.newInstance("5,5")).build(); + Pickup service = (Pickup)Pickup.Builder.newInstance("pick").addSizeDimension(0, 1).setLocation(Location.newInstance("5,5")).build(); JobActivityFactory activityFactory = mock(JobActivityFactory.class); List activities = new ArrayList(); @@ -308,8 +308,8 @@ public class ShipmentInsertionCalculatorTest { InsertionData iData = switcher.getInsertionData(route, service, vehicle, 0, DriverImpl.noDriver(), Double.MAX_VALUE); // routeActVisitor.visit(route); - assertEquals(3, iData.getDeliveryInsertionIndex()); - } + assertEquals(3, iData.getDeliveryInsertionIndex()); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java index 61d53110..fa52fc58 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java @@ -50,207 +50,209 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; + + public class TestCalculatesServiceInsertion { - ServiceInsertionCalculator serviceInsertion; + ServiceInsertionCalculator serviceInsertion; - VehicleRoutingTransportCosts costs; + VehicleRoutingTransportCosts costs; - VehicleImpl vehicle; + VehicleImpl vehicle; - VehicleImpl newVehicle; + VehicleImpl newVehicle; - private Service first; + private Service first; - private Service third; + private Service third; - private Service second; + private Service second; - private StateManager states; + private StateManager states; - private NoDriver driver; + private NoDriver driver; private VehicleRoutingProblem vrp; - @Before - public void setup() { + @Before + public void setup(){ - VehicleType t1 = VehicleTypeImpl.Builder.newInstance("t1").addCapacityDimension(0, 1000).setCostPerDistance(1.0).build(); - vehicle = VehicleImpl.Builder.newInstance("vehicle").setLatestArrival(100.0).setStartLocation(Location.newInstance("0,0")).setType(t1).build(); + VehicleType t1 = VehicleTypeImpl.Builder.newInstance("t1").addCapacityDimension(0, 1000).setCostPerDistance(1.0).build(); + vehicle = VehicleImpl.Builder.newInstance("vehicle").setLatestArrival(100.0).setStartLocation(Location.newInstance("0,0")).setType(t1).build(); - VehicleType t2 = VehicleTypeImpl.Builder.newInstance("t2").addCapacityDimension(0, 1000).setCostPerDistance(2.0).build(); - newVehicle = VehicleImpl.Builder.newInstance("newVehicle").setLatestArrival(100.0).setStartLocation(Location.newInstance("0,0")).setType(t2).build(); + VehicleType t2 = VehicleTypeImpl.Builder.newInstance("t2").addCapacityDimension(0, 1000).setCostPerDistance(2.0).build(); + newVehicle = VehicleImpl.Builder.newInstance("newVehicle").setLatestArrival(100.0).setStartLocation(Location.newInstance("0,0")).setType(t2).build(); - driver = DriverImpl.noDriver(); + driver = DriverImpl.noDriver(); - final Locations locations = new Locations() { + final Locations locations = new Locations(){ - @Override - public Coordinate getCoord(String id) { - //assume: locationId="x,y" - String[] splitted = id.split(","); - return Coordinate.newInstance(Double.parseDouble(splitted[0]), - Double.parseDouble(splitted[1])); - } + @Override + public Coordinate getCoord(String id) { + //assume: locationId="x,y" + String[] splitted = id.split(","); + return Coordinate.newInstance(Double.parseDouble(splitted[0]), + Double.parseDouble(splitted[1])); + } - }; - costs = new AbstractForwardVehicleRoutingTransportCosts() { + }; + costs = new AbstractForwardVehicleRoutingTransportCosts() { - @Override - public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { - return ManhattanDistanceCalculator.calculateDistance(locations.getCoord(from.getId()), locations.getCoord(to.getId())); - } + @Override + public double getTransportTime(Location from, Location to,double departureTime, Driver driver, Vehicle vehicle) { + return ManhattanDistanceCalculator.calculateDistance(locations.getCoord(from.getId()), locations.getCoord(to.getId())); + } - @Override - public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { - return vehicle.getType().getVehicleCostParams().perDistanceUnit * ManhattanDistanceCalculator.calculateDistance(locations.getCoord(from.getId()), locations.getCoord(to.getId())); - } - }; + @Override + public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { + return vehicle.getType().getVehicleCostParams().perDistanceUnit*ManhattanDistanceCalculator.calculateDistance(locations.getCoord(from.getId()), locations.getCoord(to.getId())); + } + }; - first = Service.Builder.newInstance("1").addSizeDimension(0, 0).setLocation(Location.newInstance("0,10")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); - second = Service.Builder.newInstance("2").addSizeDimension(0, 0).setLocation(Location.newInstance("10,10")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); - third = Service.Builder.newInstance("3").addSizeDimension(0, 0).setLocation(Location.newInstance("10,0")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); + first = Service.Builder.newInstance("1").addSizeDimension(0, 0).setLocation(Location.newInstance("0,10")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); + second = Service.Builder.newInstance("2").addSizeDimension(0, 0).setLocation(Location.newInstance("10,10")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); + third = Service.Builder.newInstance("3").addSizeDimension(0, 0).setLocation(Location.newInstance("10,0")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); - Collection jobs = new ArrayList(); - jobs.add(first); - jobs.add(third); - jobs.add(second); + Collection jobs = new ArrayList(); + jobs.add(first); + jobs.add(third); + jobs.add(second); - vrp = VehicleRoutingProblem.Builder.newInstance().addAllJobs(jobs) - .addVehicle(vehicle).setRoutingCost(costs).build(); + vrp = VehicleRoutingProblem.Builder.newInstance().addAllJobs(jobs) + .addVehicle(vehicle).setRoutingCost(costs).build(); - states = new StateManager(vrp); - states.updateLoadStates(); - states.updateTimeWindowStates(); + states = new StateManager(vrp); + states.updateLoadStates(); + states.updateTimeWindowStates(); - ConstraintManager cManager = new ConstraintManager(vrp, states); - cManager.addLoadConstraint(); - cManager.addTimeWindowConstraint(); + ConstraintManager cManager = new ConstraintManager(vrp,states); + cManager.addLoadConstraint(); + cManager.addTimeWindowConstraint(); - VehicleRoutingActivityCosts actCosts = mock(VehicleRoutingActivityCosts.class); + VehicleRoutingActivityCosts actCosts = mock(VehicleRoutingActivityCosts.class); - serviceInsertion = new ServiceInsertionCalculator(costs, new LocalActivityInsertionCostsCalculator(costs, actCosts), cManager); - serviceInsertion.setJobActivityFactory(new JobActivityFactory() { + serviceInsertion = new ServiceInsertionCalculator(costs, new LocalActivityInsertionCostsCalculator(costs, actCosts), cManager); + serviceInsertion.setJobActivityFactory(new JobActivityFactory() { @Override public List createActivities(Job job) { return vrp.copyAndGetActivities(job); } }); - } + } - @Test - public void whenInsertingTheFirstJobInAnEmptyTourWithVehicle_itCalculatesMarginalCostChanges() { - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).build(); - states.informInsertionStarts(Arrays.asList(route), null); + @Test + public void whenInsertingTheFirstJobInAnEmptyTourWithVehicle_itCalculatesMarginalCostChanges(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).build(); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(20.0, iData.getInsertionCost(), 0.2); - assertEquals(0, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(20.0, iData.getInsertionCost(), 0.2); + assertEquals(0, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingTheSecondJobInAnNonEmptyTourWithVehicle_itCalculatesMarginalCostChanges() { - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).build(); - states.informInsertionStarts(Arrays.asList(route), null); + @Test + public void whenInsertingTheSecondJobInAnNonEmptyTourWithVehicle_itCalculatesMarginalCostChanges(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).build(); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(20.0, iData.getInsertionCost(), 0.2); - assertEquals(0, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(20.0, iData.getInsertionCost(), 0.2); + assertEquals(0, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingThirdJobWithVehicle_itCalculatesMarginalCostChanges() { - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(third).build(); - states.informInsertionStarts(Arrays.asList(route), null); + @Test + public void whenInsertingThirdJobWithVehicle_itCalculatesMarginalCostChanges(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(third).build(); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(0.0, iData.getInsertionCost(), 0.2); - assertEquals(1, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(0.0, iData.getInsertionCost(), 0.2); + assertEquals(1, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingThirdJobWithNewVehicle_itCalculatesMarginalCostChanges() { - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(third).build(); - states.informInsertionStarts(Arrays.asList(route), null); + @Test + public void whenInsertingThirdJobWithNewVehicle_itCalculatesMarginalCostChanges(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(third).build(); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, second, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(40.0, iData.getInsertionCost(), 0.2); - assertEquals(1, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, second, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(40.0, iData.getInsertionCost(), 0.2); + assertEquals(1, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingASecondJobWithAVehicle_itCalculatesLocalMarginalCostChanges() { - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(second).build(); - states.informInsertionStarts(Arrays.asList(route), null); + @Test + public void whenInsertingASecondJobWithAVehicle_itCalculatesLocalMarginalCostChanges(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(second).build(); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(0.0, iData.getInsertionCost(), 0.2); - assertEquals(2, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(0.0, iData.getInsertionCost(), 0.2); + assertEquals(2, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingASecondJobWithANewVehicle_itCalculatesLocalMarginalCostChanges() { + @Test + public void whenInsertingASecondJobWithANewVehicle_itCalculatesLocalMarginalCostChanges(){ - VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(second).build(); + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, driver).setJobActivityFactory(vrp.getJobActivityFactory()).addService(first).addService(second).build(); - states.informInsertionStarts(Arrays.asList(route), null); + states.informInsertionStarts(Arrays.asList(route), null); - InsertionData iData = serviceInsertion.getInsertionData(route, third, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); - assertEquals(50.0, iData.getInsertionCost(), 0.2); - assertEquals(2, iData.getDeliveryInsertionIndex()); - } + InsertionData iData = serviceInsertion.getInsertionData(route, third, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); + assertEquals(50.0, iData.getInsertionCost(), 0.2); + assertEquals(2, iData.getDeliveryInsertionIndex()); + } - @Test - public void whenInsertingJobAndCurrRouteIsEmpty_accessEggressCalcShouldReturnZero() { - VehicleRoute route = VehicleRoute.Builder.newInstance(VehicleImpl.createNoVehicle(), DriverImpl.noDriver()).build(); - AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs); - Job job = Service.Builder.newInstance("1").addSizeDimension(0, 0).setLocation(Location.newInstance("1")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); - JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0); - assertEquals(0.0, accessEgressCalc.getCosts(iContex), 0.01); - } + @Test + public void whenInsertingJobAndCurrRouteIsEmpty_accessEggressCalcShouldReturnZero(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(VehicleImpl.createNoVehicle(), DriverImpl.noDriver()).build(); + AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs); + Job job = Service.Builder.newInstance("1").addSizeDimension(0, 0).setLocation(Location.newInstance("1")).setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build(); + JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0); + assertEquals(0.0, accessEgressCalc.getCosts(iContex),0.01); + } - @Test - public void whenInsertingJobAndCurrRouteAndVehicleHaveTheSameLocation_accessEggressCalcShouldReturnZero() { - VehicleRoute route = VehicleRoute.Builder.newInstance(newVehicle, DriverImpl.noDriver()) - .addService(first) - .build(); + @Test + public void whenInsertingJobAndCurrRouteAndVehicleHaveTheSameLocation_accessEggressCalcShouldReturnZero(){ + VehicleRoute route = VehicleRoute.Builder.newInstance(newVehicle, DriverImpl.noDriver()) + .addService(first) + .build(); - AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs); - JobInsertionContext iContex = new JobInsertionContext(route, first, newVehicle, mock(Driver.class), 0.0); - assertEquals(0.0, accessEgressCalc.getCosts(iContex), 0.01); - } + AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs); + JobInsertionContext iContex = new JobInsertionContext(route, first, newVehicle, mock(Driver.class), 0.0); + assertEquals(0.0, accessEgressCalc.getCosts(iContex),0.01); + } - @Test - public void whenInsertingJobAndCurrRouteAndNewVehicleHaveDifferentLocations_accessEggressCostsMustBeCorrect() { - final Map coords = new HashMap(); - coords.put("oldV", Coordinate.newInstance(1, 0)); - coords.put("newV", Coordinate.newInstance(5, 0)); - coords.put("service", Coordinate.newInstance(0, 0)); + @Test + public void whenInsertingJobAndCurrRouteAndNewVehicleHaveDifferentLocations_accessEggressCostsMustBeCorrect(){ + final Map coords = new HashMap(); + coords.put("oldV", Coordinate.newInstance(1, 0)); + coords.put("newV", Coordinate.newInstance(5, 0)); + coords.put("service", Coordinate.newInstance(0, 0)); - AbstractForwardVehicleRoutingTransportCosts routingCosts = new AbstractForwardVehicleRoutingTransportCosts() { + AbstractForwardVehicleRoutingTransportCosts routingCosts = new AbstractForwardVehicleRoutingTransportCosts() { - @Override - public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { - return getTransportCost(from, to, departureTime, driver, vehicle); - } + @Override + public double getTransportTime(Location from, Location to,double departureTime, Driver driver, Vehicle vehicle) { + return getTransportCost(from, to, departureTime, driver, vehicle); + } - @Override - public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { - return EuclideanDistanceCalculator.calculateDistance(coords.get(from.getId()), coords.get(to.getId())); - } - }; - Vehicle oldVehicle = VehicleImpl.Builder.newInstance("oldV").setStartLocation(Location.newInstance("oldV")).build(); + @Override + public double getTransportCost(Location from, Location to,double departureTime, Driver driver, Vehicle vehicle) { + return EuclideanDistanceCalculator.calculateDistance(coords.get(from.getId()), coords.get(to.getId())); + } + }; + Vehicle oldVehicle = VehicleImpl.Builder.newInstance("oldV").setStartLocation(Location.newInstance("oldV")).build(); - VehicleRoute route = VehicleRoute.Builder.newInstance(oldVehicle, DriverImpl.noDriver()) - .addService(Service.Builder.newInstance("service").addSizeDimension(0, 0).setLocation(Location.newInstance("service")).build()) - .build(); + VehicleRoute route = VehicleRoute.Builder.newInstance(oldVehicle, DriverImpl.noDriver()) + .addService(Service.Builder.newInstance("service").addSizeDimension(0, 0).setLocation(Location.newInstance("service")).build()) + .build(); - Vehicle newVehicle = VehicleImpl.Builder.newInstance("newV").setStartLocation(Location.newInstance("newV")).build(); + Vehicle newVehicle = VehicleImpl.Builder.newInstance("newV").setStartLocation(Location.newInstance("newV")).build(); - AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(routingCosts); - Job job = Service.Builder.newInstance("service2").addSizeDimension(0, 0).setLocation(Location.newInstance("service")).build(); - JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0); - assertEquals(8.0, accessEgressCalc.getCosts(iContex), 0.01); - } + AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(routingCosts); + Job job = Service.Builder.newInstance("service2").addSizeDimension(0, 0).setLocation(Location.newInstance("service")).build(); + JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0); + assertEquals(8.0, accessEgressCalc.getCosts(iContex),0.01); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java index 012e1c5d..72e576ae 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java @@ -16,118 +16,498 @@ ******************************************************************************/ package jsprit.core.algorithm.recreate; +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.algorithm.state.UpdateActivityTimes; +import jsprit.core.algorithm.state.UpdateFutureWaitingTimes; +import jsprit.core.algorithm.state.UpdateVehicleDependentPracticalTimeWindows; import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.cost.WaitingTimeCosts; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; import jsprit.core.problem.misc.JobInsertionContext; import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.activity.End; +import jsprit.core.problem.solution.route.activity.Start; +import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.CostFactory; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; +import java.util.Arrays; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class TestLocalActivityInsertionCostsCalculator { - VehicleRoutingTransportCosts tpCosts; + VehicleRoutingTransportCosts tpCosts; - VehicleRoutingActivityCosts actCosts; + VehicleRoutingActivityCosts actCosts; - LocalActivityInsertionCostsCalculator calc; + LocalActivityInsertionCostsCalculator calc; - Vehicle vehicle; + Vehicle vehicle; - VehicleRoute route; + VehicleRoute route; - JobInsertionContext jic; + JobInsertionContext jic; - @Before - public void doBefore() { + @Before + public void doBefore(){ - vehicle = mock(Vehicle.class); - route = mock(VehicleRoute.class); - when(route.isEmpty()).thenReturn(false); - when(route.getVehicle()).thenReturn(vehicle); + vehicle = mock(Vehicle.class); + route = mock(VehicleRoute.class); + when(route.isEmpty()).thenReturn(false); + when(route.getVehicle()).thenReturn(vehicle); - jic = mock(JobInsertionContext.class); - when(jic.getRoute()).thenReturn(route); - when(jic.getNewVehicle()).thenReturn(vehicle); + jic = mock(JobInsertionContext.class); + when(jic.getRoute()).thenReturn(route); + when(jic.getNewVehicle()).thenReturn(vehicle); + when(vehicle.getType()).thenReturn(VehicleTypeImpl.Builder.newInstance("type").build()); - tpCosts = mock(VehicleRoutingTransportCosts.class); - when(tpCosts.getTransportCost(loc("i"), loc("j"), 0.0, null, vehicle)).thenReturn(2.0); - when(tpCosts.getTransportTime(loc("i"), loc("j"), 0.0, null, vehicle)).thenReturn(0.0); - when(tpCosts.getTransportCost(loc("i"), loc("k"), 0.0, null, vehicle)).thenReturn(3.0); - when(tpCosts.getTransportTime(loc("i"), loc("k"), 0.0, null, vehicle)).thenReturn(0.0); - when(tpCosts.getTransportCost(loc("k"), loc("j"), 0.0, null, vehicle)).thenReturn(3.0); - when(tpCosts.getTransportTime(loc("k"), loc("j"), 0.0, null, vehicle)).thenReturn(0.0); + tpCosts = mock(VehicleRoutingTransportCosts.class); + when(tpCosts.getTransportCost(loc("i"), loc("j"), 0.0, null, vehicle)).thenReturn(2.0); + when(tpCosts.getTransportTime(loc("i"), loc("j"), 0.0, null, vehicle)).thenReturn(0.0); + when(tpCosts.getTransportCost(loc("i"), loc("k"), 0.0, null, vehicle)).thenReturn(3.0); + when(tpCosts.getTransportTime(loc("i"), loc("k"), 0.0, null, vehicle)).thenReturn(0.0); + when(tpCosts.getTransportCost(loc("k"), loc("j"), 0.0, null, vehicle)).thenReturn(3.0); + when(tpCosts.getTransportTime(loc("k"), loc("j"), 0.0, null, vehicle)).thenReturn(0.0); - actCosts = mock(VehicleRoutingActivityCosts.class); - calc = new LocalActivityInsertionCostsCalculator(tpCosts, actCosts); - } + actCosts = mock(VehicleRoutingActivityCosts.class); + calc = new LocalActivityInsertionCostsCalculator(tpCosts, actCosts, mock(StateManager.class)); + } private Location loc(String i) { return Location.Builder.newInstance().setId(i).build(); } @Test - public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts() { - TourActivity prevAct = mock(TourActivity.class); - when(prevAct.getLocation()).thenReturn(loc("i")); - TourActivity nextAct = mock(TourActivity.class); - when(nextAct.getLocation()).thenReturn(loc("j")); - TourActivity newAct = mock(TourActivity.class); - when(newAct.getLocation()).thenReturn(loc("k")); + public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocation()).thenReturn(loc("i")); + when(prevAct.getIndex()).thenReturn(1); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocation()).thenReturn(loc("j")); + when(nextAct.getIndex()).thenReturn(1); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocation()).thenReturn(loc("k")); + when(newAct.getIndex()).thenReturn(1); - when(vehicle.isReturnToDepot()).thenReturn(true); + when(vehicle.isReturnToDepot()).thenReturn(true); - double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); - assertEquals(4.0, costs, 0.01); - } + double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs,0.01); + } - @Test - public void whenInsertingActBetweenLastActAndEnd_itCalcsMarginalTpCosts() { - TourActivity prevAct = mock(TourActivity.class); - when(prevAct.getLocation()).thenReturn(loc("i")); - End nextAct = End.newInstance("j", 0.0, 0.0); - TourActivity newAct = mock(TourActivity.class); - when(newAct.getLocation()).thenReturn(loc("k")); + @Test + public void whenInsertingActBetweenLastActAndEnd_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocation()).thenReturn(loc("i")); + when(prevAct.getIndex()).thenReturn(1); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocation()).thenReturn(loc("k")); + when(newAct.getIndex()).thenReturn(1); - when(vehicle.isReturnToDepot()).thenReturn(true); + when(vehicle.isReturnToDepot()).thenReturn(true); - double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); - assertEquals(4.0, costs, 0.01); - } + double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs,0.01); + } - @Test - public void whenInsertingActBetweenTwoRouteActsAndRouteIsOpen_itCalcsMarginalTpCosts() { - TourActivity prevAct = mock(TourActivity.class); - when(prevAct.getLocation()).thenReturn(loc("i")); - TourActivity nextAct = mock(TourActivity.class); - when(nextAct.getLocation()).thenReturn(loc("j")); - TourActivity newAct = mock(TourActivity.class); - when(newAct.getLocation()).thenReturn(loc("k")); + @Test + public void whenInsertingActBetweenTwoRouteActsAndRouteIsOpen_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocation()).thenReturn(loc("i")); + when(prevAct.getIndex()).thenReturn(1); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocation()).thenReturn(loc("j")); + when(nextAct.getIndex()).thenReturn(1); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocation()).thenReturn(loc("k")); + when(newAct.getIndex()).thenReturn(1); - when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.isReturnToDepot()).thenReturn(false); - double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); - assertEquals(4.0, costs, 0.01); - } + double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs,0.01); + } - @Test - public void whenInsertingActBetweenLastActAndEndAndRouteIsOpen_itCalculatesTpCostsFromPrevToNewAct() { - TourActivity prevAct = mock(TourActivity.class); - when(prevAct.getLocation()).thenReturn(loc("i")); - End nextAct = End.newInstance("j", 0.0, 0.0); - TourActivity newAct = mock(TourActivity.class); - when(newAct.getLocation()).thenReturn(loc("k")); + @Test + public void whenInsertingActBetweenLastActAndEndAndRouteIsOpen_itCalculatesTpCostsFromPrevToNewAct(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocation()).thenReturn(loc("i")); + when(prevAct.getIndex()).thenReturn(1); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocation()).thenReturn(loc("k")); + when(newAct.getIndex()).thenReturn(1); - when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.isReturnToDepot()).thenReturn(false); - double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); - assertEquals(3.0, costs, 0.01); - } + double costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(3.0,costs,0.01); + } + + @Test + public void test(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build(); + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setLocation(Location.newInstance(60, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,80)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(prevS).addJob(newS).addJob(nextS).addVehicle(v).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(), new StateManager(mock(VehicleRoutingProblem.class))); + calc.setSolutionCompletenessRatio(1.); + + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(50.,c,0.01); + + /* + new: dist = 90 & wait = 0 + old: dist = 30 & wait = 10 + c = new - old = 90 - 40 = 50 + */ + } + + @Test + public void whenAddingNewBetweenStartAndAct_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setLocation(Location.newInstance(10, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30, 0)) + .setTimeWindow(TimeWindow.newInstance(40, 50)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(newS).addJob(nextS).addVehicle(v).build(); + + Start prevAct = new Start(Location.newInstance(0,0),0,100); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(nextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),new StateManager(vrp)); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,0); + assertEquals(-10.,c,0.01); + } + + @Test + public void whenAddingNewBetweenStartAndAct2_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setLocation(Location.newInstance(10, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)) + .setTimeWindow(TimeWindow.newInstance(140,150)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(newS).addJob(nextS).addVehicle(v2).build(); + + Start prevAct = new Start(Location.newInstance(0,0),0,100); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v2).setJobActivityFactory(vrp.getJobActivityFactory()).addService(nextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v2,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(), new StateManager(vrp)); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,0); + assertEquals(-10.,c,0.01); + } + + @Test + public void whenAddingNewInEmptyRoute_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setLocation(Location.newInstance(10, 0)).setTimeWindow(TimeWindow.newInstance(100, 150)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(newS).addVehicle(v).build(); + + Start prevAct = new Start(Location.newInstance(0,0),0,100); + TourActivity newAct = vrp.getActivities(newS).get(0); + End nextAct = new End(Location.newInstance(0,0),0,100); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),new StateManager(vrp) ); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,0); + assertEquals(110.,c,0.01); + } + + @Test + public void whenAddingNewBetweenTwoActs_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10, 0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,50)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(prevS).addJob(newS).addJob(nextS).addVehicle(v).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),new StateManager(vrp) ); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(-10.,c,0.01); + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(100, 120)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(prevS).addJob(newS).addJob(nextS).addVehicle(v).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),new StateManager(vrp) ); + calc.setSolutionCompletenessRatio(0.5); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(35.,c,0.01); + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs2_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); +// VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setHasVariableDepartureTime(true).setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(100,120)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,500)).build(); + + Service afterNextS = Service.Builder.newInstance("afterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(400,500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(afterNextS).addJob(prevS).addJob(newS).addJob(nextS).addVehicle(v).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).addService(afterNextS).build(); + + StateManager stateManager = getStateManager(vrp,route); + + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),stateManager); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(-10.,c,0.01); + // + //old: dist: 0, waiting: 10 + 350 = 360 + //new: dist: 0, waiting: 80 + 270 = 350 + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs3_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); +// VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setHasVariableDepartureTime(true).setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(100, 120)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30, 0)).setTimeWindow(TimeWindow.newInstance(40, 500)).build(); + + Service afterNextS = Service.Builder.newInstance("afterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(80, 500)).build(); + Service afterAfterNextS = Service.Builder.newInstance("afterAfterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(100, 500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addJob(prevS).addJob(newS).addJob(nextS) + .addJob(afterNextS).addJob(afterAfterNextS).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).addService(afterNextS).addService(afterAfterNextS).build(); + + StateManager stateManager = getStateManager(vrp, route); + + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),stateManager); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(20.,c,0.01); + //start-delay = new - old = 120 - 40 = 80 > future waiting time savings = 30 + 20 + 10 + //ref: 10 + 50 + 20 = 80 + //new: 80 - 10 - 30 - 20 = 20 + /* + w(new) + w(next) - w_old(next) - min{start_delay(next),future_waiting} + */ + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs4_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); +// VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setHasVariableDepartureTime(true).setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(100,120)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,500)).build(); + + Service afterNextS = Service.Builder.newInstance("afterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(80,500)).build(); + Service afterAfterNextS = Service.Builder.newInstance("afterAfterNext").setLocation(Location.newInstance(50,0)).setTimeWindow(TimeWindow.newInstance(100,500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addJob(prevS).addJob(newS).addJob(nextS) + .addJob(afterNextS).addJob(afterAfterNextS).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).addService(afterNextS).addService(afterAfterNextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + + StateManager stateManager = getStateManager(vrp, route); + + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),stateManager); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(30.,c,0.01); + //ref: 10 + 30 + 10 = 50 + //new: 50 - 50 = 0 + + /* + activity start time delay at next act = start-time-old - start-time-new is always bigger than subsequent waiting time savings + */ + /* + old = 10 + 30 + 10 = 50 + new = 80 + 0 - 10 - min{80,40} = 30 + */ + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs4WithVarStart_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); +// VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setHasVariableDepartureTime(true).setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(100,120)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,500)).build(); + + Service afterNextS = Service.Builder.newInstance("afterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(80,500)).build(); + Service afterAfterNextS = Service.Builder.newInstance("afterAfterNext").setLocation(Location.newInstance(50,0)).setTimeWindow(TimeWindow.newInstance(100,500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addJob(prevS).addJob(newS).addJob(nextS) + .addJob(afterNextS).addJob(afterAfterNextS).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).addService(afterNextS).addService(afterAfterNextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + + StateManager stateManager = getStateManager(vrp, route); + + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),stateManager); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(30.,c,0.01); + /* + activity start time delay at next act = start-time-old - start-time-new is always bigger than subsequent waiting time savings + */ + /* + old = 10 + 30 + 10 = 50 + new = 80 + new - old = 80 - 40 = 40 + + */ + } + + @Test + public void whenAddingNewWithTWBetweenTwoActs3WithVarStart_itShouldCalcInsertionCostsCorrectly(){ + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t").setCostPerWaitingTime(1.).build(); + + VehicleImpl v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0,0)).build(); +// VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setHasVariableDepartureTime(true).setType(type).setStartLocation(Location.newInstance(0,0)).build(); + + Service prevS = Service.Builder.newInstance("prev").setLocation(Location.newInstance(10,0)).build(); + Service newS = Service.Builder.newInstance("new").setServiceTime(10).setTimeWindow(TimeWindow.newInstance(50,70)).setLocation(Location.newInstance(20, 0)).build(); + Service nextS = Service.Builder.newInstance("next").setLocation(Location.newInstance(30,0)).setTimeWindow(TimeWindow.newInstance(40,70)).build(); + + Service afterNextS = Service.Builder.newInstance("afterNext").setLocation(Location.newInstance(40,0)).setTimeWindow(TimeWindow.newInstance(50,100)).build(); + Service afterAfterNextS = Service.Builder.newInstance("afterAfterNext").setLocation(Location.newInstance(50,0)).setTimeWindow(TimeWindow.newInstance(100,500)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addJob(prevS).addJob(newS).addJob(nextS) + .addJob(afterNextS).addJob(afterAfterNextS).build(); + + TourActivity prevAct = vrp.getActivities(prevS).get(0); + TourActivity newAct = vrp.getActivities(newS).get(0); + TourActivity nextAct = vrp.getActivities(nextS).get(0); + + VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(prevS).addService(nextS).addService(afterNextS).addService(afterAfterNextS).build(); + JobInsertionContext context = new JobInsertionContext(route,newS,v,null,0.); + + StateManager stateManager = getStateManager(vrp, route); + + LocalActivityInsertionCostsCalculator calc = new LocalActivityInsertionCostsCalculator(CostFactory.createEuclideanCosts(),new WaitingTimeCosts(),stateManager); + calc.setSolutionCompletenessRatio(1.); + double c = calc.getCosts(context,prevAct,nextAct,newAct,10); + assertEquals(-10.,c,0.01); + /* + activity start time delay at next act = start-time-old - start-time-new is always bigger than subsequent waiting time savings + */ + /* + old = 10 + 40 = 50 + new = 30 + 10 = 40 + */ + } + + + + + + + private StateManager getStateManager(VehicleRoutingProblem vrp, VehicleRoute route) { + StateManager stateManager = new StateManager(vrp); + stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts())); + stateManager.addStateUpdater(new UpdateVehicleDependentPracticalTimeWindows(stateManager,vrp.getTransportCosts())); + stateManager.addStateUpdater(new UpdateFutureWaitingTimes(stateManager,vrp.getTransportCosts())); + stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList()); + return stateManager; + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java index 5487f897..ee0f8a4d 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java @@ -34,6 +34,35 @@ public class VehicleImplTest { Vehicle v = VehicleImpl.Builder.newInstance("v").build(); } + @Test + 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(); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("screwdriver")); + } + + @Test + 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(); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("dRill")); + assertTrue(v.getSkills().containsSkill("ScrewDriver")); + } + + @Test + 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(); + assertFalse(v.getSkills().containsSkill("ScrewDriver")); + } + + @Test public void whenVehicleIsBuiltToReturnToDepot_itShouldReturnToDepot() { Vehicle v = VehicleImpl.Builder.newInstance("v").setReturnToDepot(true).setStartLocation(Location.newInstance("loc")).build(); diff --git a/jsprit-examples/src/main/java/jsprit/examples/CostMatrixExample.java b/jsprit-examples/src/main/java/jsprit/examples/CostMatrixExample.java index a43cfdeb..28e670ae 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/CostMatrixExample.java +++ b/jsprit-examples/src/main/java/jsprit/examples/CostMatrixExample.java @@ -18,7 +18,7 @@ package jsprit.examples; import jsprit.analysis.toolbox.Plotter; import jsprit.core.algorithm.VehicleRoutingAlgorithm; -import jsprit.core.algorithm.io.VehicleRoutingAlgorithms; +import jsprit.core.algorithm.box.Jsprit; import jsprit.core.problem.Location; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.FleetSize; @@ -40,26 +40,27 @@ import java.util.Collection; * Illustrates how you can use jsprit with an already compiled distance and time matrix. * * @author schroeder + * */ public class CostMatrixExample { - public static void main(String[] args) { - /* - * some preparation - create output folder + public static void main(String[] args) { + /* + * some preparation - create output folder */ - Examples.createOutputFolder(); + Examples.createOutputFolder(); - VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 2).setCostPerDistance(1).setCostPerTime(2).build(); - VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle") - .setStartLocation(Location.newInstance("0")).setType(type).build(); + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 2).setCostPerDistance(1).setCostPerTime(2).build(); + VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle") + .setStartLocation(Location.newInstance("0")).setType(type).build(); - Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(Location.newInstance("1")).build(); - Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance("2")).build(); - Service s3 = Service.Builder.newInstance("3").addSizeDimension(0, 1).setLocation(Location.newInstance("3")).build(); + Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(Location.newInstance("1")).build(); + Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance("2")).build(); + Service s3 = Service.Builder.newInstance("3").addSizeDimension(0, 1).setLocation(Location.newInstance("3")).build(); /* - * Assume the following symmetric distance-matrix + * Assume the following symmetric distance-matrix * from,to,distance * 0,1,10.0 * 0,2,20.0 @@ -76,35 +77,35 @@ public class CostMatrixExample { * 1,3,0.5 * 2,3,1.0 */ - //define a matrix-builder building a symmetric matrix - VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true); - costMatrixBuilder.addTransportDistance("0", "1", 10.0); - costMatrixBuilder.addTransportDistance("0", "2", 20.0); - costMatrixBuilder.addTransportDistance("0", "3", 5.0); - costMatrixBuilder.addTransportDistance("1", "2", 4.0); - costMatrixBuilder.addTransportDistance("1", "3", 1.0); - costMatrixBuilder.addTransportDistance("2", "3", 2.0); + //define a matrix-builder building a symmetric matrix + VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true); + costMatrixBuilder.addTransportDistance("0", "1", 10.0); + costMatrixBuilder.addTransportDistance("0", "2", 20.0); + costMatrixBuilder.addTransportDistance("0", "3", 5.0); + costMatrixBuilder.addTransportDistance("1", "2", 4.0); + costMatrixBuilder.addTransportDistance("1", "3", 1.0); + costMatrixBuilder.addTransportDistance("2", "3", 2.0); - costMatrixBuilder.addTransportTime("0", "1", 10.0); - costMatrixBuilder.addTransportTime("0", "2", 20.0); - costMatrixBuilder.addTransportTime("0", "3", 5.0); - costMatrixBuilder.addTransportTime("1", "2", 4.0); - costMatrixBuilder.addTransportTime("1", "3", 1.0); - costMatrixBuilder.addTransportTime("2", "3", 2.0); + costMatrixBuilder.addTransportTime("0", "1", 10.0); + costMatrixBuilder.addTransportTime("0", "2", 20.0); + costMatrixBuilder.addTransportTime("0", "3", 5.0); + costMatrixBuilder.addTransportTime("1", "2", 4.0); + costMatrixBuilder.addTransportTime("1", "3", 1.0); + costMatrixBuilder.addTransportTime("2", "3", 2.0); - VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build(); + VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build(); - VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(FleetSize.INFINITE).setRoutingCost(costMatrix) - .addVehicle(vehicle).addJob(s1).addJob(s2).addJob(s3).build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(FleetSize.INFINITE).setRoutingCost(costMatrix) + .addVehicle(vehicle).addJob(s1).addJob(s2).addJob(s3).build(); - VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/fastAlgo.xml"); + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); - Collection solutions = vra.searchSolutions(); + Collection solutions = vra.searchSolutions(); - SolutionPrinter.print(Solutions.bestOf(solutions)); + SolutionPrinter.print(Solutions.bestOf(solutions)); - new Plotter(vrp, Solutions.bestOf(solutions)).plot("output/yo.png", "po"); + new Plotter(vrp, Solutions.bestOf(solutions)).plot("output/yo.png", "po"); - } + } } diff --git a/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample.java b/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample.java new file mode 100644 index 00000000..6894b2f8 --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample.java @@ -0,0 +1,74 @@ +package jsprit.examples; + +import jsprit.analysis.toolbox.AlgorithmSearchProgressChartListener; +import jsprit.analysis.toolbox.Plotter; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.box.Jsprit; +import jsprit.core.analysis.SolutionAnalyser; +import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.cost.TransportDistance; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.solution.route.activity.TimeWindow; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.reporting.SolutionPrinter; +import jsprit.core.util.RandomNumberGeneration; +import jsprit.core.util.Solutions; + +import java.util.Random; + +/** + * Created by schroeder on 23/07/15. + */ +public class WaitingTimeExample { + + public static void main(String[] args) { + + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(4.).setCostPerWaitingTime(1.0).build(); + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type1").setCostPerDistance(4.).setCostPerWaitingTime(1.0).build(); + + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setReturnToDepot(true) + .setStartLocation(Location.newInstance(0, 0)) + .setEarliestStart(0).setLatestArrival(220) + .build(); + VehicleImpl v3 = VehicleImpl.Builder.newInstance("v3").setType(type1).setReturnToDepot(true) + .setStartLocation(Location.newInstance(0, 10)) + .setEarliestStart(200).setLatestArrival(450) + .build(); + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + Random r = RandomNumberGeneration.newInstance(); + for(int i=0;i<40;i++){ + Service s = Service.Builder.newInstance("s_"+i).setServiceTime(5) + .setLocation(Location.newInstance(1 - r.nextInt(5), 10 + r.nextInt(10))).build(); + vrpBuilder.addJob(s); + } + Service s1 = Service.Builder.newInstance("s12").setLocation(Location.newInstance(-3, 15)).setTimeWindow(TimeWindow.newInstance(290, 600)).build(); + Service s4 = Service.Builder.newInstance("s13").setLocation(Location.newInstance(0,20)).setTimeWindow(TimeWindow.newInstance(290, 340)).build(); + Service s2 = Service.Builder.newInstance("s10").setLocation(Location.newInstance(-1, 15)).setTimeWindow(TimeWindow.newInstance(300, 350)).build(); + Service s3 = Service.Builder.newInstance("s11").setLocation(Location.newInstance(10, 10)).setTimeWindow(TimeWindow.newInstance(400, 600)).build(); + vrpBuilder.addJob(s1).addJob(s2).addJob(s3).addJob(s4).addVehicle(v2).addVehicle(v3); + vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); + final VehicleRoutingProblem vrp = vrpBuilder.build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + vra.setMaxIterations(2000); + vra.addListener(new AlgorithmSearchProgressChartListener("output/search")); + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + System.out.println("c: " + solution.getCost()); + SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); + + SolutionAnalyser sa = new SolutionAnalyser(vrp, solution, new TransportDistance() { + @Override + public double getDistance(Location from, Location to) { + return vrp.getTransportCosts().getTransportTime(from,to,0.,null,null); + } + }); + + System.out.println("totalWaiting: " + sa.getWaitingTime()); + System.out.println("brokenTWs: " + sa.getTimeWindowViolation()); + + new Plotter(vrp,solution).setLabel(Plotter.Label.ID).plot("output/plot","plot"); + } +} diff --git a/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample2.java b/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample2.java new file mode 100644 index 00000000..905da16c --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/WaitingTimeExample2.java @@ -0,0 +1,90 @@ +package jsprit.examples; + +import jsprit.analysis.toolbox.AlgorithmSearchProgressChartListener; +import jsprit.analysis.toolbox.Plotter; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.box.Jsprit; +import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.solution.route.activity.TimeWindow; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.reporting.SolutionPrinter; +import jsprit.core.util.Solutions; + +/** + * Created by schroeder on 23/07/15. + */ +public class WaitingTimeExample2 { + + static interface AlgorithmFactory { + VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp); + } + + public static void main(String[] args) { + + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").setCostPerDistance(1.5).setCostPerWaitingTime(1.).build(); +// VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type1").setCostPerDistance(1.5).setCostPerWaitingTime(.0).build(); + + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setReturnToDepot(true) + .setStartLocation(Location.newInstance(0, 0)).build(); + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + + + Service s1 = Service.Builder.newInstance("s12").setLocation(Location.newInstance(-1, 5)).setTimeWindow(TimeWindow.newInstance(100, 110)).build(); + Service s4 = Service.Builder.newInstance("s13").setLocation(Location.newInstance(0, 10)).build(); + Service s2 = Service.Builder.newInstance("s10").setLocation(Location.newInstance(1, 12)).build(); + Service s3 = Service.Builder.newInstance("s11").setLocation(Location.newInstance(4, 10)).build(); + Service s5 = Service.Builder.newInstance("s14").setLocation(Location.newInstance(6, 5)).setTimeWindow(TimeWindow.newInstance(110,220)).build(); + vrpBuilder.addJob(s1).addJob(s2).addJob(s3).addJob(s4).addJob(s5).addVehicle(v2); + vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); + final VehicleRoutingProblem vrp = vrpBuilder.build(); + +// AlgorithmFactory algorithmFactory = new AlgorithmFactory() { +// @Override +// public VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) { +// StateManager stateManager = new StateManager(vrp); +// stateManager.addStateUpdater(new UpdateFutureWaitingTimes(stateManager,vrp.getTransportCosts())); +// ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); +// +// return Jsprit.Builder.newInstance(vrp) +// .addCoreStateAndConstraintStuff(true) +// .setStateAndConstraintManager(stateManager, constraintManager) +//// .setProperty(Jsprit.Parameter.THRESHOLD_INI, "0.1") +//// .setProperty(Jsprit.Parameter.THRESHOLD_ALPHA, "0.3") +//// .setProperty(Parameter.) +//// .setProperty(Jsprit.Parameter.CONSTRUCTION, Jsprit.Construction.BEST_INSERTION.toString()) +// .setObjectiveFunction(new SolutionCostCalculator() { +// @Override +// public double getCosts(VehicleRoutingProblemSolution solution) { +// double costs = 0.; +// for (VehicleRoute route : solution.getRoutes()) { +// costs += route.getVehicle().getType().getVehicleCostParams().fix; +// TourActivity prevAct = route.getStart(); +// for (TourActivity act : route.getActivities()) { +// costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), act.getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); +// costs += vrp.getActivityCosts().getActivityCost(act, act.getArrTime(), route.getDriver(), route.getVehicle()); +// prevAct = act; +// } +// costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), route.getEnd().getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); +// } +// costs += solution.getUnassignedJobs().size() * 200; +// return costs; +// } +// }) +// .buildAlgorithm(); +// } +// }; + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + vra.setMaxIterations(1000); + vra.addListener(new AlgorithmSearchProgressChartListener("output/search")); + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + System.out.println("c: " + solution.getCost()); + SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); + + new Plotter(vrp,solution).setLabel(Plotter.Label.ID).plot("output/plot","plot"); + } +}