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

Merge remote-tracking branch 'graphhopper/master' into merge_from_gh_master

# Conflicts:
#
jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/Up
dateMaxTimeInVehicle.java
This commit is contained in:
kobyb 2018-01-16 11:53:33 +02:00
commit 92524d53b3
15 changed files with 305 additions and 204 deletions

View file

@ -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: If you want to use the latest release of jsprit-core, add the following lines to your pom:
``` ```
&lt;dependency&gt; <dependency>
&lt;groupId&gt;com.graphhopper&lt;/groupId&gt; <groupId>com.graphhopper</groupId>
&lt;artifactId&gt;jsprit-core&lt;/artifactId&gt; <artifactId>jsprit-core</artifactId>
&lt;version&gt;{version}&lt;/version&gt; <version>{version}</version>
&lt;/dependency&gt; </dependency>
``` ```
Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core) Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core)

View file

@ -15,6 +15,9 @@ VROOM is an optimization engine written in C++14 that aim at providing good solu
#### [Hipster4j](http://www.hipster4j.org/) #### [Hipster4j](http://www.hipster4j.org/)
Hipster is an easy to use yet powerful and flexible type-safe library for heuristic search, written in pure Java. It relies on a flexible model with generic operators to define search problems. So you can also model and solve vehicle routing problems. Hipster is an easy to use yet powerful and flexible type-safe library for heuristic search, written in pure Java. It relies on a flexible model with generic operators to define search problems. So you can also model and solve vehicle routing problems.
#### [OscaR](https://bitbucket.org/oscarlib/oscar/wiki/Home)
OscaR, an Open Source Toolbox for Optimising Logistics and Supply Chain Systems.
### Territory Design ### Territory Design
#### [OpenDoorLogistics](http://www.opendoorlogistics.com) #### [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. If you know another promising open source implementation, report it.

View file

@ -33,17 +33,19 @@ import java.util.*;
*/ */
public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
private Map<Integer,Map<Job,Double>> openPickupEndTimes = new HashMap<>(); private Map<Integer, Map<Job, Double>> openPickupEndTimesPerVehicle = new HashMap<>();
private Map<Integer,Map<TourActivity,Double>> slackTimes = new HashMap<>(); private Map<Integer, Map<TourActivity, Double>> slackTimesPerVehicle = new HashMap<>();
private Map<Integer,Map<TourActivity,Double>> actStartTimes = new HashMap<>(); private Map<Integer, Map<TourActivity, Double>> actStartTimesPerVehicle = new HashMap<>();
private VehicleRoute route; private VehicleRoute route;
private final StateManager stateManager; private final StateManager stateManager;
private final StateId latestStartId; private final StateId minSlackId;
private final StateId openJobsId;
private double[] prevActEndTimes; private double[] prevActEndTimes;
@ -65,9 +67,10 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
}; };
public UpdateMaxTimeInVehicle(StateManager stateManager, StateId slackTimeId, TransportTime transportTime, VehicleRoutingActivityCosts activityCosts) { public UpdateMaxTimeInVehicle(StateManager stateManager, StateId slackTimeId, TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId openJobsId) {
this.stateManager = stateManager; this.stateManager = stateManager;
this.latestStartId = slackTimeId; this.minSlackId = slackTimeId;
this.openJobsId = openJobsId;
this.transportTime = transportTime; this.transportTime = transportTime;
prevActEndTimes = new double[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1]; prevActEndTimes = new double[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1];
prevActLocations = new Location[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1]; prevActLocations = new Location[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1];
@ -82,16 +85,16 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
@Override @Override
public void begin(VehicleRoute route) { public void begin(VehicleRoute route) {
openPickupEndTimes.clear(); openPickupEndTimesPerVehicle.clear();
slackTimes.clear(); slackTimesPerVehicle.clear();
actStartTimes.clear(); actStartTimesPerVehicle.clear();
vehicles = vehiclesToUpdate.get(route); vehicles = vehiclesToUpdate.get(route);
this.route = route; this.route = route;
for(Vehicle v : vehicles){ for(Vehicle v : vehicles){
int vehicleIndex = v.getVehicleTypeIdentifier().getIndex(); int vehicleIndex = v.getVehicleTypeIdentifier().getIndex();
openPickupEndTimes.put(vehicleIndex,new HashMap<Job, Double>()); openPickupEndTimesPerVehicle.put(vehicleIndex, new HashMap<Job, Double>());
slackTimes.put(vehicleIndex,new HashMap<TourActivity, Double>()); slackTimesPerVehicle.put(vehicleIndex, new HashMap<TourActivity, Double>());
actStartTimes.put(vehicleIndex,new HashMap<TourActivity, Double>()); actStartTimesPerVehicle.put(vehicleIndex, new HashMap<TourActivity, Double>());
prevActEndTimes[vehicleIndex] = v.getEarliestDeparture(); prevActEndTimes[vehicleIndex] = v.getEarliestDeparture();
prevActLocations[vehicleIndex] = v.getStartLocation(); prevActLocations[vehicleIndex] = v.getStartLocation();
} }
@ -109,7 +112,7 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
double activityStart = Math.max(activityArrival,activity.getTheoreticalEarliestOperationStartTime()); double activityStart = Math.max(activityArrival,activity.getTheoreticalEarliestOperationStartTime());
memorizeActStart(activity,v,activityStart); memorizeActStart(activity,v,activityStart);
double activityEnd = activityStart + activityCosts.getActivityDuration(null, activity, activityArrival, route.getDriver(), v); double activityEnd = activityStart + activityCosts.getActivityDuration(null, activity, activityArrival, route.getDriver(), v);
Map<Job, Double> openPickups = openPickupEndTimes.get(vehicleIndex); Map<Job, Double> openPickups = openPickupEndTimesPerVehicle.get(vehicleIndex);
if (activity instanceof ServiceActivity || activity instanceof PickupActivity) { if (activity instanceof ServiceActivity || activity instanceof PickupActivity) {
openPickups.put(((TourActivity.JobActivity) activity).getJob(), activityEnd); openPickups.put(((TourActivity.JobActivity) activity).getJob(), activityEnd);
} else if (activity instanceof DeliveryActivity) { } else if (activity instanceof DeliveryActivity) {
@ -120,7 +123,7 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
openPickups.remove(job); openPickups.remove(job);
} else pickupEnd = v.getEarliestDeparture(); } else pickupEnd = v.getEarliestDeparture();
double slackTime = maxTime - (activityStart - pickupEnd); double slackTime = maxTime - (activityStart - pickupEnd);
slackTimes.get(vehicleIndex).put(activity, slackTime); slackTimesPerVehicle.get(vehicleIndex).put(activity, slackTime);
} }
prevActLocations[vehicleIndex] = activity.getLocation(); prevActLocations[vehicleIndex] = activity.getLocation();
prevActEndTimes[vehicleIndex] = activityEnd; prevActEndTimes[vehicleIndex] = activityEnd;
@ -136,16 +139,8 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
return maxTime; return maxTime;
} }
// private double getMaxTimeInVehicle(String jobId) {
// double maxTime = Double.MAX_VALUE;
// if(maxTimes.containsKey(jobId)){
// maxTime = maxTimes.get(jobId);
// }
// return maxTime;
// }
private void memorizeActStart(TourActivity activity, Vehicle v, double activityStart) { private void memorizeActStart(TourActivity activity, Vehicle v, double activityStart) {
actStartTimes.get(v.getVehicleTypeIdentifier().getIndex()).put(activity,activityStart); actStartTimesPerVehicle.get(v.getVehicleTypeIdentifier().getIndex()).put(activity, activityStart);
} }
@Override @Override
@ -158,33 +153,35 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
if(!v.isReturnToDepot()) routeEnd = prevActEndTimes[vehicleIndex]; if(!v.isReturnToDepot()) routeEnd = prevActEndTimes[vehicleIndex];
else routeEnd = prevActEndTimes[vehicleIndex] + transportTime.getTransportTime(prevActLocations[vehicleIndex],v.getEndLocation(),prevActEndTimes[vehicleIndex],route.getDriver(),v); else routeEnd = prevActEndTimes[vehicleIndex] + transportTime.getTransportTime(prevActLocations[vehicleIndex],v.getEndLocation(),prevActEndTimes[vehicleIndex],route.getDriver(),v);
Map<String, Double> openDeliveries = new HashMap<>(); Map<Job, Double> openDeliveries = new HashMap<>();
for (Job job : openPickupEndTimes.get(vehicleIndex).keySet()) { for (Job job : openPickupEndTimesPerVehicle.get(vehicleIndex).keySet()) {
double actEndTime = openPickupEndTimes.get(vehicleIndex).get(job); double actEndTime = openPickupEndTimesPerVehicle.get(vehicleIndex).get(job);
double slackTime = job.getMaxTimeInVehicle() - (routeEnd - actEndTime); double slackTime = job.getMaxTimeInVehicle() - (routeEnd - actEndTime);
openDeliveries.put(job.getId(), slackTime); openDeliveries.put(job, slackTime);
} }
double minSlackTimeAtEnd = minSlackTime(openDeliveries); double minSlackTimeAtEnd = minSlackTime(openDeliveries);
stateManager.putRouteState(route, v, latestStartId, routeEnd + minSlackTimeAtEnd); stateManager.putRouteState(route, v, minSlackId, minSlackTimeAtEnd);
stateManager.putRouteState(route, v, openJobsId, new HashMap<>(openDeliveries));
List<TourActivity> acts = new ArrayList<>(this.route.getActivities()); List<TourActivity> acts = new ArrayList<>(this.route.getActivities());
Collections.reverse(acts); Collections.reverse(acts);
for (TourActivity act : acts) { for (TourActivity act : acts) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (act instanceof ServiceActivity || act instanceof PickupActivity) { if (act instanceof ServiceActivity || act instanceof PickupActivity) {
String jobId = ((TourActivity.JobActivity) act).getJob().getId(); openDeliveries.remove(job);
openDeliveries.remove(jobId);
double minSlackTime = minSlackTime(openDeliveries); double minSlackTime = minSlackTime(openDeliveries);
double latestStart = actStart(act, v) + minSlackTime; // double latestStart = actStart(act, v) + minSlackTime;
stateManager.putActivityState(act, v, latestStartId, latestStart); stateManager.putActivityState(act, v, openJobsId, new HashMap<>(openDeliveries));
stateManager.putActivityState(act, v, minSlackId, minSlackTime);
} else { } else {
String jobId = ((TourActivity.JobActivity) act).getJob().getId(); if (slackTimesPerVehicle.get(vehicleIndex).containsKey(act)) {
if(slackTimes.get(vehicleIndex).containsKey(act)){ double slackTime = slackTimesPerVehicle.get(vehicleIndex).get(act);
double slackTime = slackTimes.get(vehicleIndex).get(act); openDeliveries.put(job, slackTime);
openDeliveries.put(jobId,slackTime);
} }
double minSlackTime = minSlackTime(openDeliveries); double minSlackTime = minSlackTime(openDeliveries);
double latestStart = actStart(act, v) + minSlackTime; // double latestStart = actStart(act, v) + minSlackTime;
stateManager.putActivityState(act, v, latestStartId, latestStart); stateManager.putActivityState(act, v, openJobsId, new HashMap<>(openDeliveries));
stateManager.putActivityState(act, v, minSlackId, minSlackTime);
} }
} }
} }
@ -200,44 +197,44 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
else else
routeEnd = prevActEndTimes[vehicleIndex] + transportTime.getTransportTime(prevActLocations[vehicleIndex], v.getEndLocation(), prevActEndTimes[vehicleIndex], route.getDriver(), v); routeEnd = prevActEndTimes[vehicleIndex] + transportTime.getTransportTime(prevActLocations[vehicleIndex], v.getEndLocation(), prevActEndTimes[vehicleIndex], route.getDriver(), v);
Map<String, Double> openDeliveries = new HashMap<>(); Map<Job, Double> openDeliveries = new HashMap<>();
for (Job job : openPickupEndTimes.get(vehicleIndex).keySet()) { for (Job job : openPickupEndTimesPerVehicle.get(vehicleIndex).keySet()) {
if (job == ignore) continue; if (job == ignore) continue;
double actEndTime = openPickupEndTimes.get(vehicleIndex).get(job); double actEndTime = openPickupEndTimesPerVehicle.get(vehicleIndex).get(job);
double slackTime = job.getMaxTimeInVehicle() - (routeEnd - actEndTime); double slackTime = job.getMaxTimeInVehicle() - (routeEnd - actEndTime);
openDeliveries.put(job.getId(), slackTime); openDeliveries.put(job, slackTime);
} }
double minSlackTimeAtEnd = minSlackTime(openDeliveries); double minSlackTimeAtEnd = minSlackTime(openDeliveries);
stateManager.putRouteState(route, v, latestStartId, routeEnd + minSlackTimeAtEnd); stateManager.putRouteState(route, v, minSlackId, routeEnd + minSlackTimeAtEnd);
List<TourActivity> acts = new ArrayList<>(activities); List<TourActivity> acts = new ArrayList<>(activities);
Collections.reverse(acts); Collections.reverse(acts);
for (TourActivity act : acts) { for (TourActivity act : acts) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (act instanceof ServiceActivity || act instanceof PickupActivity) { if (act instanceof ServiceActivity || act instanceof PickupActivity) {
String jobId = ((TourActivity.JobActivity) act).getJob().getId(); String jobId = job.getId();
openDeliveries.remove(jobId); openDeliveries.remove(jobId);
double minSlackTime = minSlackTime(openDeliveries); double minSlackTime = minSlackTime(openDeliveries);
double latestStart = actStart(act, v) + minSlackTime; double latestStart = actStart(act, v) + minSlackTime;
stateManager.putActivityState(act, v, latestStartId, latestStart); stateManager.putActivityState(act, v, minSlackId, latestStart);
} else { } else {
String jobId = ((TourActivity.JobActivity) act).getJob().getId(); if (slackTimesPerVehicle.get(vehicleIndex).containsKey(act)) {
if (slackTimes.get(vehicleIndex).containsKey(act)) { double slackTime = slackTimesPerVehicle.get(vehicleIndex).get(act);
double slackTime = slackTimes.get(vehicleIndex).get(act); openDeliveries.put(job, slackTime);
openDeliveries.put(jobId, slackTime);
} }
double minSlackTime = minSlackTime(openDeliveries); double minSlackTime = minSlackTime(openDeliveries);
double latestStart = actStart(act, v) + minSlackTime; double latestStart = actStart(act, v) + minSlackTime;
stateManager.putActivityState(act, v, latestStartId, latestStart); stateManager.putActivityState(act, v, minSlackId, latestStart);
} }
} }
} }
} }
private double actStart(TourActivity act, Vehicle v) { private double actStart(TourActivity act, Vehicle v) {
return actStartTimes.get(v.getVehicleTypeIdentifier().getIndex()).get(act); return actStartTimesPerVehicle.get(v.getVehicleTypeIdentifier().getIndex()).get(act);
} }
private double minSlackTime(Map<String, Double> openDeliveries) { private double minSlackTime(Map<Job, Double> openDeliveries) {
double min = Double.MAX_VALUE; double min = Double.MAX_VALUE;
for(Double value : openDeliveries.values()){ for(Double value : openDeliveries.values()){
if(value < min) min = value; if(value < min) min = value;

View file

@ -232,9 +232,9 @@ public class VehicleRoutingProblem {
*/ */
public Builder addJob(AbstractJob job) { public Builder addJob(AbstractJob job) {
if (tentativeJobs.containsKey(job.getId())) 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)) if (!(job instanceof Service || job instanceof Shipment))
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); job.setIndex(jobIndexCounter);
incJobIndexCounter(); incJobIndexCounter();
tentativeJobs.put(job.getId(), job); tentativeJobs.put(job.getId(), job);
@ -285,10 +285,11 @@ public class VehicleRoutingProblem {
for (Vehicle v : uniqueVehicles) { for (Vehicle v : uniqueVehicles) {
if (v.getBreak() != null) { if (v.getBreak() != null) {
if (!uniqueBreakIds.add(v.getBreak().getId())) 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; hasBreaks = true;
List<AbstractActivity> breakActivities = jobActivityFactory.createActivities(v.getBreak()); List<AbstractActivity> 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){ for(AbstractActivity act : breakActivities){
act.setIndex(activityIndexCounter); act.setIndex(activityIndexCounter);
incActivityIndexCounter(); incActivityIndexCounter();
@ -351,7 +352,7 @@ public class VehicleRoutingProblem {
private void addShipment(Shipment job) { private void addShipment(Shipment job) {
if (jobs.containsKey(job.getId())) { 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); addLocationToTentativeLocations(job);
// tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate()); // tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate());
@ -367,7 +368,7 @@ public class VehicleRoutingProblem {
* */ * */
public Builder addVehicle(Vehicle vehicle) { public Builder addVehicle(Vehicle vehicle) {
if (!(vehicle instanceof AbstractVehicle)) 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); return addVehicle((AbstractVehicle) vehicle);
} }
@ -379,7 +380,7 @@ public class VehicleRoutingProblem {
*/ */
public Builder addVehicle(AbstractVehicle vehicle) { public Builder addVehicle(AbstractVehicle vehicle) {
if(addedVehicleIds.contains(vehicle.getId())){ 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()); else addedVehicleIds.add(vehicle.getId());
if (!uniqueVehicles.contains(vehicle)) { if (!uniqueVehicles.contains(vehicle)) {
@ -443,7 +444,7 @@ public class VehicleRoutingProblem {
} }
boolean hasBreaks = addBreaksToActivityMap(); boolean hasBreaks = addBreaksToActivityMap();
if (hasBreaks && fleetSize.equals(FleetSize.INFINITE)) 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); return new VehicleRoutingProblem(this);
} }
@ -510,7 +511,7 @@ public class VehicleRoutingProblem {
// tentative_coordinates.put(service.getLocation().getId(), service.getLocation().getCoordinate()); // tentative_coordinates.put(service.getLocation().getId(), service.getLocation().getCoordinate());
addLocationToTentativeLocations(service); addLocationToTentativeLocations(service);
if (jobs.containsKey(service.getId())) { 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); jobs.put(service.getId(), service);
return this; return this;

View file

@ -20,23 +20,19 @@ package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId; import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager; import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
import com.graphhopper.jsprit.core.algorithm.state.UpdateVehicleDependentPracticalTimeWindows;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.cost.TransportTime; import com.graphhopper.jsprit.core.problem.cost.TransportTime;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliveryActivity; import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliveryActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End; import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupActivity; import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.ArrayList; import java.util.Collections;
import java.util.Arrays; import java.util.Map;
import java.util.Collection;
import java.util.List;
/** /**
* Created by schroeder on 15/09/16. * Created by schroeder on 15/09/16.
@ -49,16 +45,19 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
private final VehicleRoutingActivityCosts activityCosts; private final VehicleRoutingActivityCosts activityCosts;
private final StateId latestStartId; private final StateId minSlackId;
private final StateId openJobsId;
private final StateManager stateManager; private final StateManager stateManager;
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager, VehicleRoutingProblem vrp) { public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId minSlackId, StateManager stateManager, VehicleRoutingProblem vrp, StateId openJobsId) {
this.transportTime = transportTime; this.transportTime = transportTime;
this.latestStartId = latestStartId; this.minSlackId = minSlackId;
this.stateManager = stateManager; this.stateManager = stateManager;
this.activityCosts = activityCosts; this.activityCosts = activityCosts;
this.vrp = vrp; this.vrp = vrp;
this.openJobsId = openJobsId;
} }
@Override @Override
@ -102,55 +101,53 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
//************ 2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints //************ 2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
if(newActIsPickup || iFacts.getAssociatedActivities().size() == 1) { double minSlack = Double.MAX_VALUE;
double latest; if (!(nextAct instanceof End)) {
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE; minSlack = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), minSlackId, Double.class);
else if (nextAct instanceof End) { }
latest = stateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), latestStartId, Double.class); double directArrTimeNextAct = prevActDepTime + transportTime.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
} else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class); double directNextActStart = Math.max(directArrTimeNextAct, nextAct.getTheoreticalEarliestOperationStartTime());
double additionalTimeOfNewAct = (nextActStart - prevActDepTime) - (directNextActStart - prevActDepTime);
if (nextActStart > latest) { if (additionalTimeOfNewAct > minSlack) {
return ConstraintsStatus.NOT_FULFILLED; if (newActIsPickup) return ConstraintsStatus.NOT_FULFILLED;
} else return ConstraintsStatus.NOT_FULFILLED;
}
} else { if (newActIsDelivery) {
boolean isShipment = iFacts.getAssociatedActivities().size() == 2; Map<Job, Double> openJobsAtNext;
if (newActIsDelivery && isShipment) { if (nextAct instanceof End)
StateManager localStateManager = new StateManager(vrp); openJobsAtNext = stateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), openJobsId, Map.class);
StateId stateId = localStateManager.createStateId("local-slack"); else openJobsAtNext = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), openJobsId, Map.class);
UpdateMaxTimeInVehicle updateMaxTimeInVehicle = new UpdateMaxTimeInVehicle(localStateManager, stateId, transportTime, activityCosts); if (openJobsAtNext == null) openJobsAtNext = Collections.emptyMap();
updateMaxTimeInVehicle.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { for (Job openJob : openJobsAtNext.keySet()) {
@Override double slack = openJobsAtNext.get(openJob);
public Collection<Vehicle> get(VehicleRoute route) { double additionalTimeOfNewJob = additionalTimeOfNewAct;
return Arrays.asList(iFacts.getNewVehicle()); if (openJob instanceof Shipment) {
Map<Job, Double> openJobsAtNextOfPickup = Collections.emptyMap();
TourActivity nextAfterPickup;
if (iFacts.getAssociatedActivities().size() == 1 && !iFacts.getRoute().isEmpty())
nextAfterPickup = iFacts.getRoute().getActivities().get(0);
else
nextAfterPickup = iFacts.getRoute().getActivities().get(iFacts.getRelatedActivityContext().getInsertionIndex());
if (nextAfterPickup != null)
openJobsAtNextOfPickup = stateManager.getActivityState(nextAfterPickup, iFacts.getNewVehicle(), openJobsId, Map.class);
if (openJobsAtNextOfPickup.containsKey(openJob)) {
TourActivity pickupAct = iFacts.getAssociatedActivities().get(0);
double pickupActArrTime = iFacts.getRelatedActivityContext().getArrivalTime();
double pickupActEndTime = startOf(pickupAct, pickupActArrTime) + activityCosts.getActivityDuration(pickupAct, pickupActArrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double nextAfterPickupArr = pickupActEndTime + transportTime.getTransportTime(pickupAct.getLocation(), nextAfterPickup.getLocation(), pickupActArrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
additionalTimeOfNewJob += startOf(nextAfterPickup, nextAfterPickupArr) - startOf(nextAfterPickup, nextAfterPickup.getArrTime());
} }
});
updateMaxTimeInVehicle.begin(iFacts.getRoute());
List<TourActivity> tourActivities = new ArrayList<>(iFacts.getRoute().getActivities());
tourActivities.add(iFacts.getRelatedActivityContext().getInsertionIndex(), iFacts.getAssociatedActivities().get(0));
for (TourActivity act : tourActivities) {
updateMaxTimeInVehicle.visit(act);
} }
updateMaxTimeInVehicle.finish(tourActivities, iFacts.getJob()); if (additionalTimeOfNewJob > slack) {
double latest;
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = localStateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), stateId, Double.class);
} else
latest = localStateManager.getActivityState(nextAct, iFacts.getNewVehicle(), stateId, Double.class);
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED; return ConstraintsStatus.NOT_FULFILLED;
} }
} }
} }
return ConstraintsStatus.FULFILLED; return ConstraintsStatus.FULFILLED;
} }
// private double getMaxTime(String jobId) { private double startOf(TourActivity act, double arrTime) {
// if(maxTimes.containsKey(jobId)) return maxTimes.get(jobId); return Math.max(arrTime, act.getTheoreticalEarliestOperationStartTime());
// else return Double.MAX_VALUE; }
// }
} }

View file

@ -30,6 +30,7 @@ import com.graphhopper.jsprit.core.problem.Skills;
*/ */
public interface Job extends HasId, HasIndex { public interface Job extends HasId, HasIndex {
/** /**
* Returns the unique identifier (id) of a job. * Returns the unique identifier (id) of a job.
* *

View file

@ -92,7 +92,7 @@ public class Service extends AbstractJob {
protected Object userData; protected Object userData;
protected double maxTimeInVehicle = Double.MAX_VALUE; protected double maxTimeInVehicle = Double.MAX_VALUE;
Builder(String id){ Builder(String id){
this.id = id; this.id = id;
timeWindows = new TimeWindowsImpl(); timeWindows = new TimeWindowsImpl();
@ -135,7 +135,7 @@ public class Service extends AbstractJob {
*/ */
public Builder<T> setServiceTime(double serviceTime) { public Builder<T> setServiceTime(double serviceTime) {
if (serviceTime < 0) 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; this.serviceTime = serviceTime;
return this; return this;
} }
@ -167,20 +167,20 @@ public class Service extends AbstractJob {
* @throws IllegalArgumentException if dimensionValue < 0 * @throws IllegalArgumentException if dimensionValue < 0
*/ */
public Builder<T> addSizeDimension(int dimensionIndex, int dimensionValue) { public Builder<T> 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); capacityBuilder.addDimension(dimensionIndex, dimensionValue);
return this; return this;
} }
public Builder<T> setTimeWindow(TimeWindow tw){ public Builder<T> 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(); this.timeWindows = new TimeWindowsImpl();
timeWindows.add(tw); timeWindows.add(tw);
return this; return this;
} }
public Builder<T> addTimeWindow(TimeWindow timeWindow) { public Builder<T> 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){ if(!twAdded){
timeWindows = new TimeWindowsImpl(); timeWindows = new TimeWindowsImpl();
twAdded = true; twAdded = true;
@ -205,7 +205,7 @@ public class Service extends AbstractJob {
* @throws IllegalArgumentException if neither locationId nor coordinate is set. * @throws IllegalArgumentException if neither locationId nor coordinate is set.
*/ */
public T build() { 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"); this.setType("service");
capacity = capacityBuilder.build(); capacity = capacityBuilder.build();
skills = skillBuilder.build(); skills = skillBuilder.build();
@ -222,10 +222,13 @@ public class Service extends AbstractJob {
return this; return this;
} }
public Builder<T> addAllRequiredSkills(Collection<String> skills) {
skillBuilder.addAllSkills(skills);
return this;
}
public Builder<T> addAllRequiredSkills(Skills skills){ public Builder<T> addAllRequiredSkills(Skills skills){
for(String s : skills.values()){ skillBuilder.addAllSkills(skills.values());
skillBuilder.addSkill(s);
}
return this; return this;
} }
@ -246,13 +249,13 @@ public class Service extends AbstractJob {
*/ */
public Builder<T> setPriority(int priority) { public Builder<T> setPriority(int priority) {
if (priority < 1 || priority > 10) 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; this.priority = priority;
return this; return this;
} }
public Builder<T> setMaxTimeInVehicle(double maxTimeInVehicle){ public Builder<T> 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"); // if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive");
// this.maxTimeInVehicle = maxTimeInVehicle; // this.maxTimeInVehicle = maxTimeInVehicle;
// return this; // return this;

View file

@ -148,7 +148,8 @@ public class Shipment extends AbstractJob {
* @throws IllegalArgumentException if servicTime < 0.0 * @throws IllegalArgumentException if servicTime < 0.0
*/ */
public Builder setPickupServiceTime(double serviceTime) { 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; this.pickupServiceTime = serviceTime;
return this; return this;
} }
@ -164,7 +165,7 @@ public class Shipment extends AbstractJob {
* @throws IllegalArgumentException if timeWindow is null * @throws IllegalArgumentException if timeWindow is null
*/ */
public Builder setPickupTimeWindow(TimeWindow timeWindow) { 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 = new TimeWindowsImpl();
this.pickupTimeWindows.add(timeWindow); this.pickupTimeWindows.add(timeWindow);
return this; return this;
@ -193,7 +194,8 @@ public class Shipment extends AbstractJob {
* @throws IllegalArgumentException if serviceTime < 0.0 * @throws IllegalArgumentException if serviceTime < 0.0
*/ */
public Builder setDeliveryServiceTime(double deliveryServiceTime) { 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; this.deliveryServiceTime = deliveryServiceTime;
return this; return this;
} }
@ -209,7 +211,7 @@ public class Shipment extends AbstractJob {
* @throws IllegalArgumentException if timeWindow is null * @throws IllegalArgumentException if timeWindow is null
*/ */
public Builder setDeliveryTimeWindow(TimeWindow timeWindow) { 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 = new TimeWindowsImpl();
this.deliveryTimeWindows.add(timeWindow); this.deliveryTimeWindows.add(timeWindow);
return this; return this;
@ -224,7 +226,8 @@ public class Shipment extends AbstractJob {
* @throws IllegalArgumentException if dimVal < 0 * @throws IllegalArgumentException if dimVal < 0
*/ */
public Builder addSizeDimension(int dimensionIndex, int dimensionValue) { 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); capacityBuilder.addDimension(dimensionIndex, dimensionValue);
return this; return this;
} }
@ -245,8 +248,8 @@ public class Shipment extends AbstractJob {
* is set * is set
*/ */
public Shipment build() { public Shipment build() {
if (pickupLocation_ == null) throw new IllegalArgumentException("pickup location is missing"); if (pickupLocation_ == null) throw new IllegalArgumentException("The pickup location is missing.");
if (deliveryLocation_ == null) throw new IllegalArgumentException("delivery location is missing"); if (deliveryLocation_ == null) throw new IllegalArgumentException("The delivery location is missing.");
capacity = capacityBuilder.build(); capacity = capacityBuilder.build();
skills = skillBuilder.build(); skills = skillBuilder.build();
return new Shipment(this); return new Shipment(this);
@ -258,10 +261,13 @@ public class Shipment extends AbstractJob {
return this; return this;
} }
public Builder addAllRequiredSkills(Collection<String> skills) {
skillBuilder.addAllSkills(skills);
return this;
}
public Builder addAllRequiredSkills(Skills skills) { public Builder addAllRequiredSkills(Skills skills) {
for (String s : skills.values()) { addAllRequiredSkills(skills.values());
addRequiredSkill(s);
}
return this; return this;
} }
@ -271,7 +277,7 @@ public class Shipment extends AbstractJob {
} }
public Builder addDeliveryTimeWindow(TimeWindow timeWindow) { 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){ if(!deliveryTimeWindowAdded){
deliveryTimeWindows = new TimeWindowsImpl(); deliveryTimeWindows = new TimeWindowsImpl();
deliveryTimeWindowAdded = true; deliveryTimeWindowAdded = true;
@ -291,7 +297,7 @@ public class Shipment extends AbstractJob {
} }
public Builder addPickupTimeWindow(TimeWindow timeWindow) { 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){ if(!pickupTimeWindowAdded){
pickupTimeWindows = new TimeWindowsImpl(); pickupTimeWindows = new TimeWindowsImpl();
pickupTimeWindowAdded = true; pickupTimeWindowAdded = true;
@ -319,7 +325,7 @@ public class Shipment extends AbstractJob {
*/ */
public Builder setPriority(int priority) { public Builder setPriority(int priority) {
if (priority < 1 || priority > 10) 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; this.priority = priority;
return this; return this;
} }
@ -331,7 +337,8 @@ public class Shipment extends AbstractJob {
* @return * @return
*/ */
public Builder setMaxTimeInVehicle(double maxTimeInVehicle){ 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; this.maxTimeInVehicle = maxTimeInVehicle;
return this; return this;
} }
@ -436,7 +443,7 @@ public class Shipment extends AbstractJob {
return pickupTimeWindows.getTimeWindows(); return pickupTimeWindows.getTimeWindows();
} }
/** /**
* Returns a string with the shipment's attributes. * Returns a string with the shipment's attributes.
* <p> * <p>

View file

@ -24,6 +24,8 @@ import com.graphhopper.jsprit.core.problem.job.Break;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Collection;
/** /**
* Implementation of {@link Vehicle}. * Implementation of {@link Vehicle}.
@ -135,6 +137,7 @@ public class VehicleImpl extends AbstractVehicle {
private Builder(String id) { private Builder(String id) {
super(); super();
this.id = id; this.id = id;
if (id == null) throw new IllegalArgumentException("Vehicle id must not be null.");
} }
/** /**
@ -145,7 +148,7 @@ public class VehicleImpl extends AbstractVehicle {
* @throws IllegalArgumentException if type is null * @throws IllegalArgumentException if type is null
*/ */
public Builder setType(VehicleType type) { 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; this.type = type;
return this; return this;
} }
@ -196,6 +199,8 @@ public class VehicleImpl extends AbstractVehicle {
* @return start location * @return start location
*/ */
public Builder setStartLocation(Location startLocation) { public Builder setStartLocation(Location startLocation) {
if (startLocation == null)
throw new IllegalArgumentException("Start location of vehicle " + id + " must not be null.");
this.startLocation = startLocation; this.startLocation = startLocation;
return this; return this;
} }
@ -213,7 +218,7 @@ public class VehicleImpl extends AbstractVehicle {
*/ */
public Builder setEarliestStart(double earliest_startTime) { public Builder setEarliestStart(double earliest_startTime) {
if (earliest_startTime < 0) 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; this.earliestStart = earliest_startTime;
return this; return this;
} }
@ -226,12 +231,19 @@ public class VehicleImpl extends AbstractVehicle {
*/ */
public Builder setLatestArrival(double latest_arrTime) { public Builder setLatestArrival(double latest_arrTime) {
if (latest_arrTime < 0) 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; this.latestArrival = latest_arrTime;
return this; return this;
} }
public Builder addAllSkills(Collection<String> skills) {
if (skills == null) throw new IllegalArgumentException("Skills of vehicle " + id + " must not be null");
skillBuilder.addAllSkills(skills);
return this;
}
public Builder addSkill(String skill) { public Builder addSkill(String skill) {
if (skill == null) throw new IllegalArgumentException("Skill of vehicle " + id + " must not be null");
skillBuilder.addSkill(skill); skillBuilder.addSkill(skill);
return this; return this;
} }
@ -254,17 +266,17 @@ public class VehicleImpl extends AbstractVehicle {
*/ */
public VehicleImpl build() { public VehicleImpl build() {
if (latestArrival < earliestStart) 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 != null && endLocation != null) {
if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot) if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot)
throw new IllegalArgumentException("this must not be. you specified both endLocationId and open-routes. this is contradictory. <br>" + 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. " +
"if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified."); "Either specify end location and return to depot or leave end location unspecified.");
} }
if (startLocation != null && endLocation == null) { if (startLocation != null && endLocation == null) {
endLocation = startLocation; endLocation = startLocation;
} }
if (startLocation == null && endLocation == null) if (startLocation == null && endLocation == null)
throw new IllegalArgumentException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set"); throw new IllegalArgumentException("Every vehicle requires a start location, but vehicle " + id + " does not have one.");
skills = skillBuilder.build(); skills = skillBuilder.build();
return new VehicleImpl(this); return new VehicleImpl(this);
} }

View file

@ -151,7 +151,8 @@ public class VehicleTypeImpl implements VehicleType {
* if velocity is smaller than zero * if velocity is smaller than zero
*/ */
public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) { 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; this.maxVelo = inMeterPerSeconds;
return this; return this;
} }
@ -166,7 +167,7 @@ public class VehicleTypeImpl implements VehicleType {
* @throws IllegalArgumentException if fixedCost is smaller than zero * @throws IllegalArgumentException if fixedCost is smaller than zero
*/ */
public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { 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; this.fixedCost = fixedCost;
return this; return this;
} }
@ -181,7 +182,8 @@ public class VehicleTypeImpl implements VehicleType {
* @throws IllegalArgumentException if perDistance is smaller than zero * @throws IllegalArgumentException if perDistance is smaller than zero
*/ */
public VehicleTypeImpl.Builder setCostPerDistance(double perDistance) { 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; this.perDistance = perDistance;
return this; return this;
} }
@ -260,9 +262,9 @@ public class VehicleTypeImpl implements VehicleType {
* @throws IllegalArgumentException if capacity dimension is already set * @throws IllegalArgumentException if capacity dimension is already set
*/ */
public Builder addCapacityDimension(int dimIndex, int dimVal) { 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) 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)." + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods."); "You used both methods.");
dimensionAdded = true; dimensionAdded = true;
@ -283,7 +285,7 @@ public class VehicleTypeImpl implements VehicleType {
*/ */
public Builder setCapacityDimensions(Capacity capacity) { public Builder setCapacityDimensions(Capacity capacity) {
if (dimensionAdded) 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)." + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." +
"You used both methods."); "You used both methods.");
this.capacityDimensions = capacity; this.capacityDimensions = capacity;

View file

@ -29,15 +29,19 @@ import java.util.*;
*/ */
public class UnassignedJobReasonTracker implements JobUnassignedListener { public class UnassignedJobReasonTracker implements JobUnassignedListener {
private final static String NO_REASON = "cannot determine a particular reason";
public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) { public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) {
if (failedConstraintNamesFrequency == null) return "no reason found"; if (failedConstraintNamesFrequency == null || failedConstraintNamesFrequency.getUniqueCount() == 0)
return NO_REASON;
Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator(); Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator();
int maxCount = 0; long maxCount = 0;
String mostLikely = null; String mostLikely = null;
while (entryIterator.hasNext()) { while (entryIterator.hasNext()) {
Map.Entry<Comparable<?>, Long> entry = entryIterator.next(); Map.Entry<Comparable<?>, Long> entry = entryIterator.next();
if (entry.getValue() > maxCount) { if (entry.getValue() > maxCount) {
Comparable<?> key = entry.getKey(); Comparable<?> key = entry.getKey();
maxCount = entry.getValue();
mostLikely = key.toString(); mostLikely = key.toString();
} }
} }
@ -53,6 +57,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
Set<String> failedConstraintNamesToBeIgnored = new HashSet<>(); Set<String> failedConstraintNamesToBeIgnored = new HashSet<>();
public UnassignedJobReasonTracker() { public UnassignedJobReasonTracker() {
codesToHumanReadableReason.put(-1, NO_REASON);
codesToHumanReadableReason.put(1, "cannot serve required skill"); codesToHumanReadableReason.put(1, "cannot serve required skill");
codesToHumanReadableReason.put(2, "cannot be visited within time window"); codesToHumanReadableReason.put(2, "cannot be visited within time window");
codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity"); codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity");
@ -164,8 +169,9 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
* @return * @return
*/ */
public String getMostLikelyReason(String jobId) { 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); Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId);
String mostLikelyReason = getMostLikelyFailedConstraintName(reasons); String mostLikelyReason = getMostLikelyFailedConstraintName(reasons);
int code = toCode(mostLikelyReason); int code = toCode(mostLikelyReason);
if (code == -1) return mostLikelyReason; if (code == -1) return mostLikelyReason;

View file

@ -54,10 +54,11 @@ public class MaxTimeInVehicle_IT {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId id = stateManager.createStateId("max-time"); StateId id = stateManager.createStateId("max-time");
stateManager.addStateUpdater(new UpdateMaxTimeInVehicle(stateManager,id,vrp.getTransportCosts(),vrp.getActivityCosts())); StateId openJobsId = stateManager.createStateId("open-jobs-id");
stateManager.addStateUpdater(new UpdateMaxTimeInVehicle(stateManager, id, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId));
ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager);
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager, vrp), ConstraintManager.Priority.CRITICAL); constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), id, stateManager, vrp, openJobsId), ConstraintManager.Priority.CRITICAL);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager,constraintManager).buildAlgorithm(); VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager,constraintManager).buildAlgorithm();
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());

View file

@ -30,15 +30,12 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType; import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl; import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/** /**
* Created by schroeder on 15/09/16. * Created by schroeder on 15/09/16.
@ -61,7 +58,9 @@ public class UpdateMaxTimeInVehicleTest {
private StateManager stateManager; private StateManager stateManager;
private StateId latestStartId; private StateId minSlackId;
private StateId openJobsId;
@Before @Before
public void doBefore() { public void doBefore() {
@ -107,12 +106,13 @@ public class UpdateMaxTimeInVehicleTest {
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(),vrp.getActivityCosts())); stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(),vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route), null); stateManager.informInsertionStarts(Arrays.asList(route), null);
latestStartId = stateManager.createStateId("slack-time-id"); minSlackId = stateManager.createStateId("min-slack-id");
openJobsId = stateManager.createStateId("open-jobs-id");
// Map<String,Double> maxTimes = new HashMap<>(); // Map<String,Double> maxTimes = new HashMap<>();
// maxTimes.put("s",40d); // maxTimes.put("s",40d);
// maxTimes.put("shipment",20d); // maxTimes.put("shipment",20d);
maxTimeInVehicleConstraint = new UpdateMaxTimeInVehicle(stateManager, latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); maxTimeInVehicleConstraint = new UpdateMaxTimeInVehicle(stateManager, minSlackId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
maxTimeInVehicleConstraint.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { maxTimeInVehicleConstraint.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
@Override @Override
public Collection<Vehicle> get(VehicleRoute route) { public Collection<Vehicle> get(VehicleRoute route) {
@ -128,23 +128,23 @@ public class UpdateMaxTimeInVehicleTest {
// for(TourActivity act : route.getActivities()){ // for(TourActivity act : route.getActivities()){
// String jobId = ((TourActivity.JobActivity)act).getJob().getId(); // String jobId = ((TourActivity.JobActivity)act).getJob().getId();
// if(jobId.equals("s4")){ // if(jobId.equals("s4")){
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,route.getVehicle(), minSlackId,Double.class);
// Assert.assertEquals(40, slackTime, 0.001); // Assert.assertEquals(40, slackTime, 0.001);
// } // }
// if(jobId.equals("s3")){ // if(jobId.equals("s3")){
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,route.getVehicle(), minSlackId,Double.class);
// Assert.assertEquals(30, slackTime, 0.001); // Assert.assertEquals(30, slackTime, 0.001);
// } // }
// if(jobId.equals("s2")){ // if(jobId.equals("s2")){
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,route.getVehicle(), minSlackId,Double.class);
// Assert.assertEquals(20, slackTime, 0.001); // Assert.assertEquals(20, slackTime, 0.001);
// } // }
// if(jobId.equals("s")){ // if(jobId.equals("s")){
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,route.getVehicle(), minSlackId,Double.class);
// Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001); // Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
// } // }
// } // }
// Double slackTime = stateManager.getRouteState(route,route.getVehicle(), latestStartId,Double.class); // Double slackTime = stateManager.getRouteState(route,route.getVehicle(), minSlackId,Double.class);
// Assert.assertNotNull(slackTime); // Assert.assertNotNull(slackTime);
// Assert.assertEquals(50,slackTime,0.001); // Assert.assertEquals(50,slackTime,0.001);
// } // }
@ -155,23 +155,23 @@ public class UpdateMaxTimeInVehicleTest {
// for(TourActivity act : route.getActivities()){ // for(TourActivity act : route.getActivities()){
// String jobId = ((TourActivity.JobActivity)act).getJob().getId(); // String jobId = ((TourActivity.JobActivity)act).getJob().getId();
// if(jobId.equals("s4")){ // if(jobId.equals("s4")){
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,vehicle2, minSlackId,Double.class);
// Assert.assertEquals(40, slackTime, 0.001); // Assert.assertEquals(40, slackTime, 0.001);
// } // }
// if(jobId.equals("s3")){ // if(jobId.equals("s3")){
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,vehicle2, minSlackId,Double.class);
// Assert.assertEquals(30, slackTime, 0.001); // Assert.assertEquals(30, slackTime, 0.001);
// } // }
// if(jobId.equals("s2")){ // if(jobId.equals("s2")){
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,vehicle2, minSlackId,Double.class);
// Assert.assertEquals(20, slackTime, 0.001); // Assert.assertEquals(20, slackTime, 0.001);
// } // }
// if(jobId.equals("s")){ // if(jobId.equals("s")){
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class); // Double slackTime = stateManager.getActivityState(act,vehicle2, minSlackId,Double.class);
// Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001); // Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
// } // }
// } // }
// Double slackTime = stateManager.getRouteState(route,vehicle2, latestStartId,Double.class); // Double slackTime = stateManager.getRouteState(route,vehicle2, minSlackId,Double.class);
// Assert.assertNotNull(slackTime); // Assert.assertNotNull(slackTime);
// Assert.assertEquals(40,slackTime,0.001); // Assert.assertEquals(40,slackTime,0.001);
// } // }
@ -182,17 +182,17 @@ public class UpdateMaxTimeInVehicleTest {
for(TourActivity act : route2.getActivities()){ for(TourActivity act : route2.getActivities()){
String jobId = ((TourActivity.JobActivity)act).getJob().getId(); String jobId = ((TourActivity.JobActivity)act).getJob().getId();
if(jobId.equals("d1")){ if(jobId.equals("d1")){
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class); Double slackTime = stateManager.getActivityState(act, v, minSlackId, Double.class);
Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001); Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
} }
if(jobId.equals("shipment")){ if(jobId.equals("shipment")){
if(act instanceof PickupActivity){ if(act instanceof PickupActivity){
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class); Double slackTime = stateManager.getActivityState(act, v, minSlackId, Double.class);
Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001); Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
} }
else{ else{
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class); Double slackTime = stateManager.getActivityState(act, v, minSlackId, Double.class);
Assert.assertEquals(40, slackTime, 0.001); Assert.assertEquals(0, slackTime, 0.001);
} }
} }

View file

@ -20,6 +20,7 @@ package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId; import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager; import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.algorithm.state.UpdateActivityTimes;
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle; import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
import com.graphhopper.jsprit.core.problem.AbstractActivity; import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.Location;
@ -112,13 +113,15 @@ public class MaxTimeInVehicleConstraintTest {
.addPickup(s1).addDelivery(s1).build(); .addPickup(s1).addDelivery(s1).build();
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId minSlackId = stateManager.createStateId("min-slack-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, minSlackId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), minSlackId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(route,s2,v,route.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(route,s2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s2); List<AbstractActivity> acts = vrp.getActivities(s2);
@ -126,7 +129,7 @@ public class MaxTimeInVehicleConstraintTest {
c.getAssociatedActivities().add(acts.get(1)); c.getAssociatedActivities().add(acts.get(1));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0)); Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, act(route,0), acts.get(0), act(route,1), 20)); Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, act(route, 0), acts.get(0), act(route, 1), 20));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,1), acts.get(0), route.getEnd(), 40)); Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,1), acts.get(0), route.getEnd(), 40));
//insert pickup at 0 //insert pickup at 0
@ -148,12 +151,14 @@ public class MaxTimeInVehicleConstraintTest {
ini(30d, Double.MAX_VALUE, Double.MAX_VALUE); ini(30d, Double.MAX_VALUE, Double.MAX_VALUE);
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2); List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
@ -165,24 +170,67 @@ public class MaxTimeInVehicleConstraintTest {
} }
@Test
public void insertingD2JustAfterStartShouldWork() {
ini(20d, 30, Double.MAX_VALUE);
StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route), new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(route, d2, v, route.getDriver(), 0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
Assert.assertEquals("inserting d2 just after start should work", HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0));
}
@Test
public void insertingD2AfterFirstDeliveryShouldWork() {
ini(20d, 30, Double.MAX_VALUE);
StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route), new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(route, d2, v, route.getDriver(), 0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
Assert.assertEquals("inserting d2 after first delivery should work", HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getActivities().get(0), acts.get(0), route.getActivities().get(1), 10));
}
@Test @Test
public void insertingDeliveryInBetweenShipmentShouldFail(){ public void insertingDeliveryInBetweenShipmentShouldFail(){
ini(20d, 30, Double.MAX_VALUE); ini(20d, 30, Double.MAX_VALUE);
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(),vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2); List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
Assert.assertEquals("inserting d2 just after start should work", HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0));
Assert.assertEquals("inserting d2 after first delivery should work", HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getActivities().get(0), acts.get(0), route.getActivities().get(1), 10));
Assert.assertEquals("inserting d2 between pickup and delivery shipment should fail due to max-in-vehicle constraint of shipment", HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, route.getActivities().get(1), acts.get(0), route.getActivities().get(2), 20)); Assert.assertEquals("inserting d2 between pickup and delivery shipment should fail due to max-in-vehicle constraint of shipment", HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, route.getActivities().get(1), acts.get(0), route.getActivities().get(2), 20));
Assert.assertEquals("inserting d2 at end should fail", HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, route.getActivities().get(2), acts.get(0), route.getEnd(), 40)); Assert.assertEquals("inserting d2 at end should fail", HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, route.getActivities().get(2), acts.get(0), route.getEnd(), 40));
} }
@ -197,12 +245,14 @@ public class MaxTimeInVehicleConstraintTest {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1); List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
@ -223,12 +273,14 @@ public class MaxTimeInVehicleConstraintTest {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(r), new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(r), new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(r, s1, v, r.getDriver(), 0.); JobInsertionContext c = new JobInsertionContext(r, s1, v, r.getDriver(), 0.);
List<AbstractActivity> acts = vrp.getActivities(s1); List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
@ -250,12 +302,14 @@ public class MaxTimeInVehicleConstraintTest {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(r), new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(r), new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(r, s1, v, r.getDriver(), 0.); JobInsertionContext c = new JobInsertionContext(r, s1, v, r.getDriver(), 0.);
List<AbstractActivity> acts = vrp.getActivities(s1); List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
@ -308,12 +362,14 @@ public class MaxTimeInVehicleConstraintTest {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1); List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));
@ -337,14 +393,16 @@ public class MaxTimeInVehicleConstraintTest {
StateManager stateManager = new StateManager(vrp); StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id"); StateId latestStartId = stateManager.createStateId("latest-start-id");
StateId openJobsId = stateManager.createStateId("open-jobs-id");
Map<String,Double> maxTimes = new HashMap<>(); Map<String,Double> maxTimes = new HashMap<>();
maxTimes.put("s1",25d); maxTimes.put("s1",25d);
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts()); UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager, latestStartId, vrp.getTransportCosts(), vrp.getActivityCosts(), openJobsId);
stateManager.addStateUpdater(updater); stateManager.addStateUpdater(updater);
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), vrp.getActivityCosts()));
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>()); stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp); MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager, vrp, openJobsId);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.); JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1); List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0)); c.getAssociatedActivities().add(acts.get(0));

View file

@ -134,6 +134,19 @@ public class UnassignedJobReasonTrackerTest {
Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId())); Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
} }
@Test
public void getMostLikelyTest() {
Frequency frequency = new Frequency();
frequency.addValue("a");
frequency.addValue("b");
frequency.addValue("a");
frequency.addValue("a");
frequency.addValue("a");
frequency.addValue("a");
frequency.addValue("a");
Assert.assertEquals("a", UnassignedJobReasonTracker.getMostLikelyFailedConstraintName(frequency));
}
@Test @Test
public void testFreq() { public void testFreq() {
Frequency frequency = new Frequency(); Frequency frequency = new Frequency();