diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/GraphStreamViewer.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/GraphStreamViewer.java index e04097f3..22d38ce9 100644 --- a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/GraphStreamViewer.java +++ b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/GraphStreamViewer.java @@ -572,28 +572,30 @@ public class GraphStreamViewer { n.addAttribute("ui.label", "start"); } for (TourActivity act : route.getActivities()) { - Job job = ((JobActivity) act).getJob(); - String currIdentifier = makeId(job.getId(), act.getLocation().getId()); - if (label.equals(Label.ACTIVITY)) { - Node actNode = g.getNode(currIdentifier); - actNode.addAttribute("ui.label", act.getName()); - } else if (label.equals(Label.JOB_NAME)) { - Node actNode = g.getNode(currIdentifier); - actNode.addAttribute("ui.label", job.getName()); - } else if (label.equals(Label.ARRIVAL_TIME)) { - Node actNode = g.getNode(currIdentifier); - actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime())); - } else if (label.equals(Label.DEPARTURE_TIME)) { - Node actNode = g.getNode(currIdentifier); - actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime())); + if (act instanceof JobActivity) { + Job job = ((JobActivity) act).getJob(); + String currIdentifier = makeId(job.getId(), act.getLocation().getId()); + if (label.equals(Label.ACTIVITY)) { + Node actNode = g.getNode(currIdentifier); + actNode.addAttribute("ui.label", act.getName()); + } else if (label.equals(Label.JOB_NAME)) { + Node actNode = g.getNode(currIdentifier); + actNode.addAttribute("ui.label", job.getName()); + } else if (label.equals(Label.ARRIVAL_TIME)) { + Node actNode = g.getNode(currIdentifier); + actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime())); + } else if (label.equals(Label.DEPARTURE_TIME)) { + Node actNode = g.getNode(currIdentifier); + actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime())); + } + g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true); + if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute"); + else if (act instanceof DeliveryActivity) + g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute"); + prevIdentifier = currIdentifier; + vehicle_edgeId++; + sleep(renderDelay_in_ms); } - g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true); - if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute"); - else if (act instanceof DeliveryActivity) - g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute"); - prevIdentifier = currIdentifier; - vehicle_edgeId++; - sleep(renderDelay_in_ms); } if (route.getVehicle().isReturnToDepot()) { String lastIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getEndLocation().getId()); diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/Plotter.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/Plotter.java index 2124fb02..c519e759 100644 --- a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/Plotter.java +++ b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/Plotter.java @@ -302,6 +302,10 @@ public class Plotter { final XYPlot plot = createPlot(problem, shipments, solution); JFreeChart chart = new JFreeChart(title, plot); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinesVisible(false); + plot.setRangeGridlinesVisible(false); + LegendTitle legend = createLegend(routes, shipments, plot); chart.removeLegend(); chart.addLegend(legend); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index 1155955b..f0c7a383 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -135,23 +135,28 @@ public class VehicleRoutingAlgorithm { this.objectiveFunction = objectiveFunction; } - /** - * Adds solution to the collection of initial solutions. - * - * @param solution the solution to be added - */ - public void addInitialSolution(VehicleRoutingProblemSolution solution) { + /** + * Adds solution to the collection of initial solutions. + * + * This method may lead to errors if tour activities in the solution are different to the + * ones in the VRP (including differences in indexing) + * + * @param solution the solution to be added + */ + public void addInitialSolution(VehicleRoutingProblemSolution solution) { // We will make changes so let's make a copy solution = VehicleRoutingProblemSolution.copyOf(solution); - verify(solution); + verifyAndAdaptSolution(solution); initialSolutions.add(solution); } - private void verify(VehicleRoutingProblemSolution solution) { - Set allJobs = new HashSet(problem.getJobs().values()); - allJobs.removeAll(solution.getUnassignedJobs()); + //this method may lead to errors if tour activities in the solution are different to the ones in the VRP + //(including differences in indexing) + private void verifyAndAdaptSolution(VehicleRoutingProblemSolution solution) { + Set jobsNotInSolution = new HashSet(problem.getJobs().values()); + jobsNotInSolution.removeAll(solution.getUnassignedJobs()); for (VehicleRoute route : solution.getRoutes()) { - allJobs.removeAll(route.getTourActivities().getJobs()); + jobsNotInSolution.removeAll(route.getTourActivities().getJobs()); if (route.getVehicle().getIndex() == 0) throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " + " the VehicleRoutingProblem. only use vehicles that have already been added to the problem."); @@ -164,7 +169,9 @@ public class VehicleRoutingAlgorithm { } } - solution.getUnassignedJobs().addAll(allJobs); + //if solution is partial (not all jobs are considered), add these jobs to solution.unassignedJobs + solution.getUnassignedJobs().addAll(jobsNotInSolution); + //update the cost of solution (regardless if partial or not) solution.setCost(getObjectiveFunction().getCosts(solution)); // if (nuJobs != problem.getJobs().values().size()) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinWorst.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinWorst.java index 620d1fed..10c5cc42 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinWorst.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinWorst.java @@ -104,6 +104,10 @@ public final class RuinWorst extends AbstractRuinStrategy { TourActivity actBefore = route.getStart(); TourActivity actToEval = null; for (TourActivity act : route.getActivities()) { + if (!(act instanceof TourActivity.JobActivity)) { + continue; + } + if (actToEval == null) { actToEval = act; continue; @@ -119,6 +123,9 @@ public final class RuinWorst extends AbstractRuinStrategy { actBefore = actToEval; actToEval = act; } + if (actToEval == null) { + continue; + } double savings = savings(route, actBefore, actToEval, route.getEnd()); Job job = ((TourActivity.JobActivity) actToEval).getJob(); if (!savingsMap.containsKey(job)) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java index 328d9a46..c688ce9c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java @@ -414,6 +414,17 @@ public class VehicleRoutingProblem { return this; } + private final List nonJobActivities = new ArrayList<>(); + + public Builder addNonJobActivities(Collection nonJobActivities) { + for (AbstractActivity act : nonJobActivities) { + act.setIndex(activityIndexCounter); + incActivityIndexCounter(); + this.nonJobActivities.add(act); + } + return this; + } + /** * Builds the {@link VehicleRoutingProblem}. *

diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index bb88358b..bf2d8800 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -78,8 +78,8 @@ public class MaxDistanceConstraint implements HardActivityConstraint { double maxDistance = getMaxDistance(iFacts.getNewVehicle()); if (currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK; - double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); - double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); + double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); + double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); if (prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0; if (nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java index 99608c23..f9be6a4c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java @@ -398,9 +398,9 @@ public class Service extends AbstractJob { } /** - * Get priority of service. Only 1 = high priority, 2 = medium and 3 = low are allowed. + * Get priority of service. Only 1 (high) to 10 (low) are allowed. *

- * Default is 2 = medium. + * Default is 2. * * @return priority */ diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java index 8d356a02..0af407c2 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java @@ -318,7 +318,7 @@ public class Shipment extends AbstractJob { /** * Set priority to shipment. Only 1 (high) to 10 (low) are allowed. *

- * Default is 2 = medium. + * Default is 2. * * @param priority * @return builder @@ -505,9 +505,9 @@ public class Shipment extends AbstractJob { } /** - * Get priority of shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed. + * Get priority of shipment. Only 1 (high) to 10 (low) are allowed. *

- * Default is 2 = medium. + * Default is 2. * * @return priority */ diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java index 40fe5907..ee14a75f 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java @@ -367,7 +367,7 @@ public class VehicleRoute { * @return list of tourActivities */ public List getActivities() { - return Collections.unmodifiableList(tourActivities.getActivities()); + return tourActivities.getActivities(); } /**