From 0ea1a87dfecf6147fa487cac0b3a1fc5d55c2cfd Mon Sep 17 00:00:00 2001 From: Michal Maciejewski Date: Tue, 14 Nov 2017 11:08:07 +0100 Subject: [PATCH 01/11] service/shipmentActivityFactories - reduced scope to JobActivityFactory --- .../core/problem/solution/route/VehicleRoute.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 7dd0c17d..40fe5907 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 @@ -115,15 +115,15 @@ public class VehicleRoute { private End end; - private TourActivities tourActivities = new TourActivities(); + private final TourActivities tourActivities = new TourActivities(); - private TourActivityFactory serviceActivityFactory = new DefaultTourActivityFactory(); - - private TourShipmentActivityFactory shipmentActivityFactory = new DefaultShipmentActivityFactory(); - - private Set openShipments = new HashSet(); + private final Set openShipments = new HashSet(); private JobActivityFactory jobActivityFactory = new JobActivityFactory() { + + private final TourShipmentActivityFactory shipmentActivityFactory = new DefaultShipmentActivityFactory(); + + private final TourActivityFactory serviceActivityFactory = new DefaultTourActivityFactory(); @Override public List createActivities(Job job) { From 36d0b644a065ea3ad85659dec15fee1dfa44788f Mon Sep 17 00:00:00 2001 From: Michal Maciejewski Date: Tue, 14 Nov 2017 11:10:48 +0100 Subject: [PATCH 02/11] updated job indexing: lower indices for unplanned jobs, higher for jobs in initial routes --- .../core/problem/VehicleRoutingProblem.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) 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 99a1788e..913c5eea 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 @@ -116,8 +116,6 @@ public class VehicleRoutingProblem { }; - private int jobIndexCounter = 1; - private int vehicleIndexCounter = 1; private int activityIndexCounter = 1; @@ -132,10 +130,6 @@ public class VehicleRoutingProblem { private final DefaultTourActivityFactory serviceActivityFactory = new DefaultTourActivityFactory(); - private void incJobIndexCounter() { - jobIndexCounter++; - } - private void incActivityIndexCounter() { activityIndexCounter++; } @@ -235,8 +229,6 @@ public class VehicleRoutingProblem { throw new IllegalArgumentException("vehicle routing problem already contains a service or shipment with id " + job.getId() + ". make sure you use unique ids for all services and shipments"); if (!(job instanceof Service || job instanceof Shipment)) throw new IllegalArgumentException("job must be either a service or a shipment"); - job.setIndex(jobIndexCounter); - incJobIndexCounter(); tentativeJobs.put(job.getId(), job); addLocationToTentativeLocations(job); return this; @@ -441,6 +433,15 @@ public class VehicleRoutingProblem { addJobToFinalJobMapAndCreateActivities(job); } } + + int jobIndexCounter = 1; + for (Job job : jobs.values()) { + ((AbstractJob)job).setIndex(jobIndexCounter++); + } + for (String jobId : jobsInInitialRoutes) { + ((AbstractJob)tentativeJobs.get(jobId)).setIndex(jobIndexCounter++); + } + boolean hasBreaks = addBreaksToActivityMap(); if (hasBreaks && fleetSize.equals(FleetSize.INFINITE)) throw new UnsupportedOperationException("breaks are not yet supported when dealing with infinite fleet. either set it to finite or omit breaks."); From 1967430c40d3d0025efb4f2d6dc33df2171158bc Mon Sep 17 00:00:00 2001 From: Michal Maciejewski Date: Tue, 14 Nov 2017 11:37:02 +0100 Subject: [PATCH 03/11] bugfix: all jobs in initial routes are included into VRP.allJobs --- .../jsprit/core/problem/VehicleRoutingProblem.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 913c5eea..ce3f9cad 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 @@ -81,7 +81,7 @@ public class VehicleRoutingProblem { private Map tentativeJobs = new LinkedHashMap(); - private Set jobsInInitialRoutes = new HashSet(); + private Set jobsInInitialRoutes = new HashSet<>(); private Map tentative_coordinates = new HashMap(); @@ -308,7 +308,7 @@ public class VehicleRoutingProblem { incActivityIndexCounter(); if (act instanceof TourActivity.JobActivity) { Job job = ((TourActivity.JobActivity) act).getJob(); - jobsInInitialRoutes.add(job.getId()); + jobsInInitialRoutes.add(job); addLocationToTentativeLocations(job); registerJobAndActivity(abstractAct, job); } @@ -429,7 +429,7 @@ public class VehicleRoutingProblem { transportCosts = new CrowFlyCosts(getLocations()); } for (Job job : tentativeJobs.values()) { - if (!jobsInInitialRoutes.contains(job.getId())) { + if (!jobsInInitialRoutes.contains(job)) { addJobToFinalJobMapAndCreateActivities(job); } } @@ -438,8 +438,8 @@ public class VehicleRoutingProblem { for (Job job : jobs.values()) { ((AbstractJob)job).setIndex(jobIndexCounter++); } - for (String jobId : jobsInInitialRoutes) { - ((AbstractJob)tentativeJobs.get(jobId)).setIndex(jobIndexCounter++); + for (Job job : jobsInInitialRoutes) { + ((AbstractJob)job).setIndex(jobIndexCounter++); } boolean hasBreaks = addBreaksToActivityMap(); From 1777e666e7f98674c7dca3c6aa835b48df02c9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Thu, 16 Nov 2017 12:45:19 +0100 Subject: [PATCH 04/11] Update Other-Projects.md --- docs/Other-Projects.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/Other-Projects.md b/docs/Other-Projects.md index f61ccecb..20e9a196 100644 --- a/docs/Other-Projects.md +++ b/docs/Other-Projects.md @@ -15,6 +15,9 @@ VROOM is an optimization engine written in C++14 that aim at providing good solu #### [Hipster4j](http://www.hipster4j.org/) Hipster is an easy to use yet powerful and flexible type-safe library for heuristic search, written in pure Java. It relies on a flexible model with generic operators to define search problems. So you can also model and solve vehicle routing problems. +#### [OscaR](https://bitbucket.org/oscarlib/oscar/wiki/Home) +OscaR, an Open Source Toolbox for Optimising Logistics and Supply Chain Systems. + ### Territory Design #### [OpenDoorLogistics](http://www.opendoorlogistics.com) @@ -23,4 +26,4 @@ standalone open source application for performing geographic analysis of your cu -If you know another promising open source implementation, report it. \ No newline at end of file +If you know another promising open source implementation, report it. From 86b914d174fec0bc47bed1a34ba1aa3cf16977ef Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 21 Nov 2017 19:59:26 +0100 Subject: [PATCH 05/11] add human readable reason --- .../jsprit/core/util/UnassignedJobReasonTracker.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index a4577a05..0ab34dec 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -29,8 +29,11 @@ import java.util.*; */ public class UnassignedJobReasonTracker implements JobUnassignedListener { + private final static String NO_REASON = "cannot determine a particular reason"; + public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) { - if (failedConstraintNamesFrequency == null) return "no reason found"; + if (failedConstraintNamesFrequency == null || failedConstraintNamesFrequency.getUniqueCount() == 0) + return NO_REASON; Iterator, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator(); long maxCount = 0; String mostLikely = null; @@ -54,6 +57,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { Set failedConstraintNamesToBeIgnored = new HashSet<>(); public UnassignedJobReasonTracker() { + codesToHumanReadableReason.put(-1, NO_REASON); codesToHumanReadableReason.put(1, "cannot serve required skill"); codesToHumanReadableReason.put(2, "cannot be visited within time window"); codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity"); @@ -165,8 +169,9 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public String getMostLikelyReason(String jobId) { - if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return "no reason found"; + if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return codesToHumanReadableReason.get(-1); Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId); + String mostLikelyReason = getMostLikelyFailedConstraintName(reasons); int code = toCode(mostLikelyReason); if (code == -1) return mostLikelyReason; From 369139211d1f5c58c6ea9d4f7f5e3ed5f61c16ea Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 28 Nov 2017 15:47:33 +0100 Subject: [PATCH 06/11] refine error messages --- .../jsprit/core/problem/vehicle/VehicleImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java index f77f7b9c..809f2adf 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java @@ -145,7 +145,7 @@ public class VehicleImpl extends AbstractVehicle { * @throws IllegalArgumentException if type is null */ public Builder setType(VehicleType type) { - if (type == null) throw new IllegalArgumentException("type cannot be null."); + if (type == null) throw new IllegalArgumentException("Vehicle type must not be null."); this.type = type; return this; } @@ -213,7 +213,7 @@ public class VehicleImpl extends AbstractVehicle { */ public Builder setEarliestStart(double earliest_startTime) { if (earliest_startTime < 0) - throw new IllegalArgumentException("earliest start of vehicle " + id + " must not be negative"); + throw new IllegalArgumentException("The earliest start time of vehicle " + id + " must not be negative."); this.earliestStart = earliest_startTime; return this; } @@ -226,7 +226,7 @@ public class VehicleImpl extends AbstractVehicle { */ public Builder setLatestArrival(double latest_arrTime) { if (latest_arrTime < 0) - throw new IllegalArgumentException("latest arrival time of vehicle " + id + " must not be negative"); + throw new IllegalArgumentException("The latest arrival time of vehicle " + id + " must not be negative."); this.latestArrival = latest_arrTime; return this; } @@ -254,17 +254,17 @@ public class VehicleImpl extends AbstractVehicle { */ public VehicleImpl build() { if (latestArrival < earliestStart) - throw new IllegalArgumentException("latest arrival of vehicle " + id + " must not be smaller than its start time"); + throw new IllegalArgumentException("The latest arrival time of vehicle " + id + " must not be smaller than its start time."); if (startLocation != null && endLocation != null) { if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot) - throw new IllegalArgumentException("this must not be. you specified both endLocationId and open-routes. this is contradictory.
" + - "if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified."); + throw new IllegalArgumentException("You specified both the end location and that the vehicle " + id + " does not need to return to its end location. This must not be. " + + "Either specify end location and return to depot or leave end location unspecified."); } if (startLocation != null && endLocation == null) { endLocation = startLocation; } if (startLocation == null && endLocation == null) - throw new IllegalArgumentException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set"); + throw new IllegalArgumentException("Every vehicle requires a start location, but vehicle " + id + " does not have one."); skills = skillBuilder.build(); return new VehicleImpl(this); } From 3b5a64c989a17c00f90862a0f46dd5868857b644 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 30 Nov 2017 09:49:00 +0100 Subject: [PATCH 07/11] refine error messages --- .../core/problem/VehicleRoutingProblem.java | 23 +++++++++------ .../jsprit/core/problem/job/Job.java | 1 + .../jsprit/core/problem/job/Service.java | 16 +++++------ .../jsprit/core/problem/job/Shipment.java | 28 +++++++++++-------- .../core/problem/vehicle/VehicleTypeImpl.java | 14 ++++++---- 5 files changed, 48 insertions(+), 34 deletions(-) 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 ce3f9cad..ea5101dd 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 @@ -226,9 +226,15 @@ public class VehicleRoutingProblem { */ public Builder addJob(AbstractJob job) { if (tentativeJobs.containsKey(job.getId())) - throw new IllegalArgumentException("vehicle routing problem already contains a service or shipment with id " + job.getId() + ". make sure you use unique ids for all services and shipments"); + throw new IllegalArgumentException("The vehicle routing problem already contains a service or shipment with id " + job.getId() + ". Please make sure you use unique ids for all services and shipments."); if (!(job instanceof Service || job instanceof Shipment)) +<<<<<<< Upstream, based on branch 'master' of https://github.com/michalmac/jsprit.git throw new IllegalArgumentException("job must be either a service or a shipment"); +======= + throw new IllegalArgumentException("Job must be either a service or a shipment."); + job.setIndex(jobIndexCounter); + incJobIndexCounter(); +>>>>>>> b610626 refine error messages tentativeJobs.put(job.getId(), job); addLocationToTentativeLocations(job); return this; @@ -277,10 +283,11 @@ public class VehicleRoutingProblem { for (Vehicle v : uniqueVehicles) { if (v.getBreak() != null) { if (!uniqueBreakIds.add(v.getBreak().getId())) - throw new IllegalArgumentException("problem already contains a vehicle break with id " + v.getBreak().getId() + ". choose unique ids for each vehicle break."); + throw new IllegalArgumentException("The vehicle routing roblem already contains a vehicle break with id " + v.getBreak().getId() + ". Please choose unique ids for each vehicle break."); hasBreaks = true; List breakActivities = jobActivityFactory.createActivities(v.getBreak()); - if(breakActivities.isEmpty()) throw new IllegalArgumentException("at least one activity for break needs to be created by activityFactory"); + if (breakActivities.isEmpty()) + throw new IllegalArgumentException("At least one activity for break needs to be created by activityFactory."); for(AbstractActivity act : breakActivities){ act.setIndex(activityIndexCounter); incActivityIndexCounter(); @@ -343,7 +350,7 @@ public class VehicleRoutingProblem { private void addShipment(Shipment job) { if (jobs.containsKey(job.getId())) { - logger.warn("job " + job + " already in job list. overrides existing job."); + logger.warn("The job " + job + " has already been added to the job list. This overrides the existing job."); } addLocationToTentativeLocations(job); // tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate()); @@ -359,7 +366,7 @@ public class VehicleRoutingProblem { * */ public Builder addVehicle(Vehicle vehicle) { if (!(vehicle instanceof AbstractVehicle)) - throw new IllegalArgumentException("vehicle must be an AbstractVehicle"); + throw new IllegalArgumentException("A vehicle must be an AbstractVehicle."); return addVehicle((AbstractVehicle) vehicle); } @@ -371,7 +378,7 @@ public class VehicleRoutingProblem { */ public Builder addVehicle(AbstractVehicle vehicle) { if(addedVehicleIds.contains(vehicle.getId())){ - throw new IllegalArgumentException("problem already contains a vehicle with id " + vehicle.getId() + ". choose unique ids for each vehicle."); + throw new IllegalArgumentException("The vehicle routing problem already contains a vehicle with id " + vehicle.getId() + ". Please choose unique ids for each vehicle."); } else addedVehicleIds.add(vehicle.getId()); if (!uniqueVehicles.contains(vehicle)) { @@ -444,7 +451,7 @@ public class VehicleRoutingProblem { boolean hasBreaks = addBreaksToActivityMap(); if (hasBreaks && fleetSize.equals(FleetSize.INFINITE)) - throw new UnsupportedOperationException("breaks are not yet supported when dealing with infinite fleet. either set it to finite or omit breaks."); + throw new UnsupportedOperationException("Breaks are not yet supported when dealing with infinite fleet. Either set it to finite or omit breaks."); return new VehicleRoutingProblem(this); } @@ -511,7 +518,7 @@ public class VehicleRoutingProblem { // tentative_coordinates.put(service.getLocation().getId(), service.getLocation().getCoordinate()); addLocationToTentativeLocations(service); if (jobs.containsKey(service.getId())) { - logger.warn("service " + service + " already in job list. overrides existing job."); + logger.warn("The service " + service + " has already been added to job list. This overrides existing job."); } jobs.put(service.getId(), service); return this; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java index 55728235..76b65084 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java @@ -30,6 +30,7 @@ import com.graphhopper.jsprit.core.problem.Skills; */ public interface Job extends HasId, HasIndex { + /** * Returns the unique identifier (id) of a job. * 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 af4e6b85..1f4f436e 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 @@ -92,7 +92,7 @@ public class Service extends AbstractJob { protected Object userData; protected double maxTimeInVehicle = Double.MAX_VALUE; - + Builder(String id){ this.id = id; timeWindows = new TimeWindowsImpl(); @@ -135,7 +135,7 @@ public class Service extends AbstractJob { */ public Builder setServiceTime(double serviceTime) { if (serviceTime < 0) - throw new IllegalArgumentException("serviceTime must be greater than or equal to zero"); + throw new IllegalArgumentException("The service time of a service must be greater than or equal to zero."); this.serviceTime = serviceTime; return this; } @@ -167,20 +167,20 @@ public class Service extends AbstractJob { * @throws IllegalArgumentException if dimensionValue < 0 */ public Builder addSizeDimension(int dimensionIndex, int dimensionValue) { - if (dimensionValue < 0) throw new IllegalArgumentException("capacity value cannot be negative"); + if (dimensionValue < 0) throw new IllegalArgumentException("The capacity value must not be negative."); capacityBuilder.addDimension(dimensionIndex, dimensionValue); return this; } public Builder setTimeWindow(TimeWindow tw){ - if(tw == null) throw new IllegalArgumentException("time-window arg must not be null"); + if (tw == null) throw new IllegalArgumentException("The time window must not be null."); this.timeWindows = new TimeWindowsImpl(); timeWindows.add(tw); return this; } public Builder addTimeWindow(TimeWindow timeWindow) { - if(timeWindow == null) throw new IllegalArgumentException("time-window arg must not be null"); + if (timeWindow == null) throw new IllegalArgumentException("The time window must not be null."); if(!twAdded){ timeWindows = new TimeWindowsImpl(); twAdded = true; @@ -205,7 +205,7 @@ public class Service extends AbstractJob { * @throws IllegalArgumentException if neither locationId nor coordinate is set. */ public T build() { - if (location == null) throw new IllegalArgumentException("location is missing"); + if (location == null) throw new IllegalArgumentException("The location of service " + id + " is missing."); this.setType("service"); capacity = capacityBuilder.build(); skills = skillBuilder.build(); @@ -246,13 +246,13 @@ public class Service extends AbstractJob { */ public Builder setPriority(int priority) { if (priority < 1 || priority > 10) - throw new IllegalArgumentException("incorrect priority. only priority values from 1 to 10 are allowed where 1 = high and 10 is low"); + throw new IllegalArgumentException("The priority value is not valid. Only 1 (very high) to 10 (very low) are allowed."); this.priority = priority; return this; } public Builder setMaxTimeInVehicle(double maxTimeInVehicle){ - throw new UnsupportedOperationException("maxTimeInVehicle is not yet supported for Pickups and Services (only for Deliveries and Shipments)"); + throw new UnsupportedOperationException("The maximum time in vehicle is not yet supported for Pickups and Services (only for Deliveries and Shipments)."); // if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive"); // this.maxTimeInVehicle = maxTimeInVehicle; // return this; 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 a3eeaaf6..60085b3a 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 @@ -148,7 +148,8 @@ public class Shipment extends AbstractJob { * @throws IllegalArgumentException if servicTime < 0.0 */ public Builder setPickupServiceTime(double serviceTime) { - if (serviceTime < 0.0) throw new IllegalArgumentException("serviceTime must not be < 0.0"); + if (serviceTime < 0.0) + throw new IllegalArgumentException("The service time of a shipment must not be < 0.0."); this.pickupServiceTime = serviceTime; return this; } @@ -164,7 +165,7 @@ public class Shipment extends AbstractJob { * @throws IllegalArgumentException if timeWindow is null */ public Builder setPickupTimeWindow(TimeWindow timeWindow) { - if (timeWindow == null) throw new IllegalArgumentException("delivery time-window must not be null"); + if (timeWindow == null) throw new IllegalArgumentException("The delivery time window must not be null."); this.pickupTimeWindows = new TimeWindowsImpl(); this.pickupTimeWindows.add(timeWindow); return this; @@ -193,7 +194,8 @@ public class Shipment extends AbstractJob { * @throws IllegalArgumentException if serviceTime < 0.0 */ public Builder setDeliveryServiceTime(double deliveryServiceTime) { - if (deliveryServiceTime < 0.0) throw new IllegalArgumentException("deliveryServiceTime must not be < 0.0"); + if (deliveryServiceTime < 0.0) + throw new IllegalArgumentException("The service time of a delivery must not be < 0.0."); this.deliveryServiceTime = deliveryServiceTime; return this; } @@ -209,7 +211,7 @@ public class Shipment extends AbstractJob { * @throws IllegalArgumentException if timeWindow is null */ public Builder setDeliveryTimeWindow(TimeWindow timeWindow) { - if (timeWindow == null) throw new IllegalArgumentException("delivery time-window must not be null"); + if (timeWindow == null) throw new IllegalArgumentException("The delivery time window must not be null."); this.deliveryTimeWindows = new TimeWindowsImpl(); this.deliveryTimeWindows.add(timeWindow); return this; @@ -224,7 +226,8 @@ public class Shipment extends AbstractJob { * @throws IllegalArgumentException if dimVal < 0 */ public Builder addSizeDimension(int dimensionIndex, int dimensionValue) { - if (dimensionValue < 0) throw new IllegalArgumentException("capacity value cannot be negative"); + if (dimensionValue < 0) + throw new IllegalArgumentException("The capacity value must not be negative, but is " + dimensionValue + "."); capacityBuilder.addDimension(dimensionIndex, dimensionValue); return this; } @@ -245,8 +248,8 @@ public class Shipment extends AbstractJob { * is set */ public Shipment build() { - if (pickupLocation_ == null) throw new IllegalArgumentException("pickup location is missing"); - if (deliveryLocation_ == null) throw new IllegalArgumentException("delivery location is missing"); + if (pickupLocation_ == null) throw new IllegalArgumentException("The pickup location is missing."); + if (deliveryLocation_ == null) throw new IllegalArgumentException("The delivery location is missing."); capacity = capacityBuilder.build(); skills = skillBuilder.build(); return new Shipment(this); @@ -271,7 +274,7 @@ public class Shipment extends AbstractJob { } public Builder addDeliveryTimeWindow(TimeWindow timeWindow) { - if(timeWindow == null) throw new IllegalArgumentException("time-window arg must not be null"); + if (timeWindow == null) throw new IllegalArgumentException("The time window must not be null."); if(!deliveryTimeWindowAdded){ deliveryTimeWindows = new TimeWindowsImpl(); deliveryTimeWindowAdded = true; @@ -291,7 +294,7 @@ public class Shipment extends AbstractJob { } public Builder addPickupTimeWindow(TimeWindow timeWindow) { - if(timeWindow == null) throw new IllegalArgumentException("time-window arg must not be null"); + if (timeWindow == null) throw new IllegalArgumentException("The time window must not be null."); if(!pickupTimeWindowAdded){ pickupTimeWindows = new TimeWindowsImpl(); pickupTimeWindowAdded = true; @@ -319,7 +322,7 @@ public class Shipment extends AbstractJob { */ public Builder setPriority(int priority) { if (priority < 1 || priority > 10) - throw new IllegalArgumentException("incorrect priority. only 1 (very high) to 10 (very low) are allowed"); + throw new IllegalArgumentException("The priority value is not valid. Only 1 (very high) to 10 (very low) are allowed."); this.priority = priority; return this; } @@ -331,7 +334,8 @@ public class Shipment extends AbstractJob { * @return */ public Builder setMaxTimeInVehicle(double maxTimeInVehicle){ - if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive"); + if (maxTimeInVehicle < 0) + throw new IllegalArgumentException("The maximum time in vehicle must be positive."); this.maxTimeInVehicle = maxTimeInVehicle; return this; } @@ -436,7 +440,7 @@ public class Shipment extends AbstractJob { return pickupTimeWindows.getTimeWindows(); } - + /** * Returns a string with the shipment's attributes. *

diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java index 3e8da61d..112c137c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java @@ -151,7 +151,8 @@ public class VehicleTypeImpl implements VehicleType { * if velocity is smaller than zero */ public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) { - if (inMeterPerSeconds < 0.0) throw new IllegalArgumentException("velocity cannot be smaller than zero"); + if (inMeterPerSeconds < 0.0) + throw new IllegalArgumentException("The velocity of a vehicle (type) cannot be smaller than zero."); this.maxVelo = inMeterPerSeconds; return this; } @@ -166,7 +167,7 @@ public class VehicleTypeImpl implements VehicleType { * @throws IllegalArgumentException if fixedCost is smaller than zero */ public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { - if (fixedCost < 0.0) throw new IllegalArgumentException("fixed costs cannot be smaller than zero"); + if (fixedCost < 0.0) throw new IllegalArgumentException("Fixed costs must not be smaller than zero."); this.fixedCost = fixedCost; return this; } @@ -181,7 +182,8 @@ public class VehicleTypeImpl implements VehicleType { * @throws IllegalArgumentException if perDistance is smaller than zero */ public VehicleTypeImpl.Builder setCostPerDistance(double perDistance) { - if (perDistance < 0.0) throw new IllegalArgumentException("cost per distance must not be smaller than zero"); + if (perDistance < 0.0) + throw new IllegalArgumentException("Cost per distance must not be smaller than zero."); this.perDistance = perDistance; return this; } @@ -260,9 +262,9 @@ public class VehicleTypeImpl implements VehicleType { * @throws IllegalArgumentException 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 (dimVal < 0) throw new IllegalArgumentException("The capacity value must not be negative."); if (capacityDimensions != null) - throw new IllegalArgumentException("either build your dimension with build your dimensions with " + + throw new IllegalArgumentException("Either build your dimension with build your dimensions with " + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + "You used both methods."); dimensionAdded = true; @@ -283,7 +285,7 @@ public class VehicleTypeImpl implements VehicleType { */ public Builder setCapacityDimensions(Capacity capacity) { if (dimensionAdded) - throw new IllegalArgumentException("either build your dimension with build your dimensions with " + + throw new IllegalArgumentException("Either build your dimension with build your dimensions with " + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + "You used both methods."); this.capacityDimensions = capacity; From 0dd16277d5ab291e396a00c767112aed43042dc1 Mon Sep 17 00:00:00 2001 From: Tom Ingold Date: Fri, 8 Dec 2017 14:47:05 -0600 Subject: [PATCH 08/11] updated getting started to fix formatting removed html escaping for markdown --- docs/Getting-Started.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index aea9645f..e666ef52 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -13,11 +13,11 @@ jsprit is a multi-module project and consists of: If you want to use the latest release of jsprit-core, add the following lines to your pom: ``` -<dependency> - <groupId>com.graphhopper</groupId> - <artifactId>jsprit-core</artifactId> - <version>{version}</version> -</dependency> + + com.graphhopper + jsprit-core + {version} + ``` Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core) From ae1d4004a511b30a6e4e20e4db5916fcb2069f48 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 11 Dec 2017 13:29:44 +0100 Subject: [PATCH 09/11] throw exception if vehicle id is null --- .../graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java index 809f2adf..3686d703 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java @@ -135,6 +135,7 @@ public class VehicleImpl extends AbstractVehicle { private Builder(String id) { super(); this.id = id; + if (id == null) throw new IllegalArgumentException("Vehicle id must not be null."); } /** @@ -196,6 +197,8 @@ public class VehicleImpl extends AbstractVehicle { * @return start location */ public Builder setStartLocation(Location startLocation) { + if (startLocation == null) + throw new IllegalArgumentException("Start location of vehicle " + id + " must not be null."); this.startLocation = startLocation; return this; } @@ -232,6 +235,7 @@ public class VehicleImpl extends AbstractVehicle { } public Builder addSkill(String skill) { + if (skill == null) throw new IllegalArgumentException("Skill of vehicle " + id + " must not be null"); skillBuilder.addSkill(skill); return this; } From d0ebc2d60b80bb5b1416c6be206035f0592bc1c1 Mon Sep 17 00:00:00 2001 From: Michal Maciejewski Date: Thu, 14 Dec 2017 16:19:10 +0100 Subject: [PATCH 10/11] fixing compile errors due to incorrect merging --- .../jsprit/core/problem/VehicleRoutingProblem.java | 6 ------ 1 file changed, 6 deletions(-) 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 ea5101dd..b1d13747 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 @@ -228,13 +228,7 @@ public class VehicleRoutingProblem { if (tentativeJobs.containsKey(job.getId())) throw new IllegalArgumentException("The vehicle routing problem already contains a service or shipment with id " + job.getId() + ". Please make sure you use unique ids for all services and shipments."); if (!(job instanceof Service || job instanceof Shipment)) -<<<<<<< Upstream, based on branch 'master' of https://github.com/michalmac/jsprit.git - throw new IllegalArgumentException("job must be either a service or a shipment"); -======= throw new IllegalArgumentException("Job must be either a service or a shipment."); - job.setIndex(jobIndexCounter); - incJobIndexCounter(); ->>>>>>> b610626 refine error messages tentativeJobs.put(job.getId(), job); addLocationToTentativeLocations(job); return this; From dde8b01e1c3acbfed464318163c70d338ec70cc1 Mon Sep 17 00:00:00 2001 From: Michal Maciejewski Date: Tue, 6 Feb 2018 14:38:09 +0100 Subject: [PATCH 11/11] fix bug: not all initial jobs returned by getJobsInclusiveInitialJobsInRoutes() --- .../jsprit/core/problem/VehicleRoutingProblem.java | 11 ++++++----- .../graphhopper/jsprit/core/problem/job/Delivery.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) 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 b1d13747..ad2a7ea0 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 @@ -81,7 +81,7 @@ public class VehicleRoutingProblem { private Map tentativeJobs = new LinkedHashMap(); - private Set jobsInInitialRoutes = new HashSet<>(); + private Map jobsInInitialRoutes = new HashMap<>(); private Map tentative_coordinates = new HashMap(); @@ -309,7 +309,7 @@ public class VehicleRoutingProblem { incActivityIndexCounter(); if (act instanceof TourActivity.JobActivity) { Job job = ((TourActivity.JobActivity) act).getJob(); - jobsInInitialRoutes.add(job); + jobsInInitialRoutes.put(job.getId(), job); addLocationToTentativeLocations(job); registerJobAndActivity(abstractAct, job); } @@ -430,7 +430,7 @@ public class VehicleRoutingProblem { transportCosts = new CrowFlyCosts(getLocations()); } for (Job job : tentativeJobs.values()) { - if (!jobsInInitialRoutes.contains(job)) { + if (!jobsInInitialRoutes.containsKey(job.getId())) { addJobToFinalJobMapAndCreateActivities(job); } } @@ -439,7 +439,7 @@ public class VehicleRoutingProblem { for (Job job : jobs.values()) { ((AbstractJob)job).setIndex(jobIndexCounter++); } - for (Job job : jobsInInitialRoutes) { + for (Job job : jobsInInitialRoutes.values()) { ((AbstractJob)job).setIndex(jobIndexCounter++); } @@ -595,7 +595,8 @@ public class VehicleRoutingProblem { this.activityMap = builder.activityMap; this.nuActivities = builder.activityIndexCounter; this.allLocations = builder.allLocations; - this.allJobs = builder.tentativeJobs; + this.allJobs = new HashMap<>(jobs); + this.allJobs.putAll(builder.jobsInInitialRoutes); logger.info("setup problem: {}", this); } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Delivery.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Delivery.java index f31b25ef..40b70a75 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Delivery.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Delivery.java @@ -43,7 +43,7 @@ public class Delivery extends Service { public Builder setMaxTimeInVehicle(double maxTimeInVehicle){ - if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive"); + if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should not be negative"); this.maxTimeInVehicle = maxTimeInVehicle; return this; }