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)

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) {
if (newActIsPickup) return ConstraintsStatus.NOT_FULFILLED;
else return ConstraintsStatus.NOT_FULFILLED;
}
if (newActIsDelivery) {
Map<Job, Double> openJobsAtNext;
if (nextAct instanceof End)
openJobsAtNext = stateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), openJobsId, Map.class);
else openJobsAtNext = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), openJobsId, Map.class);
if (openJobsAtNext == null) openJobsAtNext = Collections.emptyMap();
for (Job openJob : openJobsAtNext.keySet()) {
double slack = openJobsAtNext.get(openJob);
double additionalTimeOfNewJob = additionalTimeOfNewAct;
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());
}
}
if (additionalTimeOfNewJob > slack) {
return ConstraintsStatus.NOT_FULFILLED; return ConstraintsStatus.NOT_FULFILLED;
} }
} else {
boolean isShipment = iFacts.getAssociatedActivities().size() == 2;
if (newActIsDelivery && isShipment) {
StateManager localStateManager = new StateManager(vrp);
StateId stateId = localStateManager.createStateId("local-slack");
UpdateMaxTimeInVehicle updateMaxTimeInVehicle = new UpdateMaxTimeInVehicle(localStateManager, stateId, transportTime, activityCosts);
updateMaxTimeInVehicle.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
@Override
public Collection<Vehicle> get(VehicleRoute route) {
return Arrays.asList(iFacts.getNewVehicle());
}
});
updateMaxTimeInVehicle.begin(iFacts.getRoute());
List<TourActivity> tourActivities = new ArrayList<>(iFacts.getRoute().getActivities());
tourActivities.add(iFacts.getRelatedActivityContext().getInsertionIndex(), iFacts.getAssociatedActivities().get(0));
for (TourActivity act : tourActivities) {
updateMaxTimeInVehicle.visit(act);
}
updateMaxTimeInVehicle.finish(tourActivities, iFacts.getJob());
double latest;
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = localStateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), stateId, Double.class);
} else
latest = localStateManager.getActivityState(nextAct, iFacts.getNewVehicle(), stateId, Double.class);
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED;
}
} }
} }
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

@ -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(Skills skills){ public Builder<T> addAllRequiredSkills(Collection<String> skills) {
for(String s : skills.values()){ skillBuilder.addAllSkills(skills);
skillBuilder.addSkill(s); return this;
} }
public Builder<T> addAllRequiredSkills(Skills skills){
skillBuilder.addAllSkills(skills.values());
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(Skills skills) { public Builder addAllRequiredSkills(Collection<String> skills) {
for (String s : skills.values()) { skillBuilder.addAllSkills(skills);
addRequiredSkill(s); return this;
} }
public Builder addAllRequiredSkills(Skills skills) {
addAllRequiredSkills(skills.values());
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;
} }

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);
@ -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));
@ -166,23 +171,66 @@ public class MaxTimeInVehicleConstraintTest {
} }
@Test @Test
public void insertingDeliveryInBetweenShipmentShouldFail(){ public void insertingD2JustAfterStartShouldWork() {
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 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)); 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
public void insertingDeliveryInBetweenShipmentShouldFail(){
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 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();