mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
add maxTimeInVehicle feature - related to 261
This commit is contained in:
parent
7590be9794
commit
42ae57d00b
14 changed files with 945 additions and 0 deletions
|
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.algorithm.state;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.problem.Location;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.TransportTime;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.*;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 15/09/16.
|
||||||
|
*/
|
||||||
|
public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
|
||||||
|
|
||||||
|
private Map<Integer,Map<Job,Double>> openPickupEndTimes = new HashMap<>();
|
||||||
|
|
||||||
|
private Map<Integer,Map<TourActivity,Double>> slackTimes = new HashMap<>();
|
||||||
|
|
||||||
|
private Map<Integer,Map<TourActivity,Double>> actStartTimes = new HashMap<>();
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private final StateManager stateManager;
|
||||||
|
|
||||||
|
private final StateId latestStartId;
|
||||||
|
|
||||||
|
private double[] prevActEndTimes;
|
||||||
|
|
||||||
|
private Location[] prevActLocations;
|
||||||
|
|
||||||
|
private Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
private final TransportTime transportTime;
|
||||||
|
|
||||||
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate vehiclesToUpdate = new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Vehicle> get(VehicleRoute route) {
|
||||||
|
return Arrays.asList(route.getVehicle());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public UpdateMaxTimeInVehicle(StateManager stateManager, StateId slackTimeId, TransportTime transportTime, VehicleRoutingActivityCosts activityCosts) {
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.latestStartId = slackTimeId;
|
||||||
|
this.transportTime = transportTime;
|
||||||
|
prevActEndTimes = new double[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1];
|
||||||
|
prevActLocations = new Location[stateManager.getMaxIndexOfVehicleTypeIdentifiers() + 1];
|
||||||
|
this.activityCosts = activityCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setVehiclesToUpdate(UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate vehiclesToUpdate) {
|
||||||
|
this.vehiclesToUpdate = vehiclesToUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
openPickupEndTimes.clear();
|
||||||
|
slackTimes.clear();
|
||||||
|
actStartTimes.clear();
|
||||||
|
vehicles = vehiclesToUpdate.get(route);
|
||||||
|
this.route = route;
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
int vehicleIndex = v.getVehicleTypeIdentifier().getIndex();
|
||||||
|
openPickupEndTimes.put(vehicleIndex,new HashMap<Job, Double>());
|
||||||
|
slackTimes.put(vehicleIndex,new HashMap<TourActivity, Double>());
|
||||||
|
actStartTimes.put(vehicleIndex,new HashMap<TourActivity, Double>());
|
||||||
|
prevActEndTimes[vehicleIndex] = v.getEarliestDeparture();
|
||||||
|
prevActLocations[vehicleIndex] = v.getStartLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
double maxTime = getMaxTimeInVehicle(activity);
|
||||||
|
|
||||||
|
for(Vehicle v : vehicles) {
|
||||||
|
int vehicleIndex = v.getVehicleTypeIdentifier().getIndex();
|
||||||
|
Location prevActLocation = prevActLocations[vehicleIndex];
|
||||||
|
double prevActEndTime = prevActEndTimes[v.getVehicleTypeIdentifier().getIndex()];
|
||||||
|
double activityArrival = prevActEndTimes[v.getVehicleTypeIdentifier().getIndex()] + transportTime.getTransportTime(prevActLocation,activity.getLocation(),prevActEndTime,route.getDriver(),v);
|
||||||
|
double activityStart = Math.max(activityArrival,activity.getTheoreticalEarliestOperationStartTime());
|
||||||
|
memorizeActStart(activity,v,activityStart);
|
||||||
|
double activityEnd = activityStart + activityCosts.getActivityDuration(activity, activityArrival, route.getDriver(), v);
|
||||||
|
Map<Job, Double> openPickups = openPickupEndTimes.get(vehicleIndex);
|
||||||
|
if (activity instanceof ServiceActivity || activity instanceof PickupActivity) {
|
||||||
|
openPickups.put(((TourActivity.JobActivity) activity).getJob(), activityEnd);
|
||||||
|
} else if (activity instanceof DeliveryActivity) {
|
||||||
|
Job job = ((TourActivity.JobActivity) activity).getJob();
|
||||||
|
double pickupEnd;
|
||||||
|
if (openPickups.containsKey(job)) {
|
||||||
|
pickupEnd = openPickups.get(job);
|
||||||
|
openPickups.remove(job);
|
||||||
|
} else pickupEnd = v.getEarliestDeparture();
|
||||||
|
double slackTime = maxTime - (activityStart - pickupEnd);
|
||||||
|
slackTimes.get(vehicleIndex).put(activity, slackTime);
|
||||||
|
}
|
||||||
|
prevActLocations[vehicleIndex] = activity.getLocation();
|
||||||
|
prevActEndTimes[vehicleIndex] = activityEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getMaxTimeInVehicle(TourActivity activity) {
|
||||||
|
double maxTime = Double.MAX_VALUE;
|
||||||
|
if(activity instanceof TourActivity.JobActivity){
|
||||||
|
maxTime = ((TourActivity.JobActivity) activity).getJob().getMaxTimeInVehicle();
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
actStartTimes.get(v.getVehicleTypeIdentifier().getIndex()).put(activity,activityStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
for(Vehicle v : vehicles) {
|
||||||
|
int vehicleIndex = v.getVehicleTypeIdentifier().getIndex();
|
||||||
|
|
||||||
|
//!!! open routes !!!
|
||||||
|
double routeEnd;
|
||||||
|
if(!v.isReturnToDepot()) routeEnd = prevActEndTimes[vehicleIndex];
|
||||||
|
else routeEnd = prevActEndTimes[vehicleIndex] + transportTime.getTransportTime(prevActLocations[vehicleIndex],v.getEndLocation(),prevActEndTimes[vehicleIndex],route.getDriver(),v);
|
||||||
|
|
||||||
|
Map<String, Double> openDeliveries = new HashMap<>();
|
||||||
|
for (Job job : openPickupEndTimes.get(vehicleIndex).keySet()) {
|
||||||
|
double actEndTime = openPickupEndTimes.get(vehicleIndex).get(job);
|
||||||
|
double slackTime = job.getMaxTimeInVehicle() - (routeEnd - actEndTime);
|
||||||
|
openDeliveries.put(job.getId(), slackTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
double minSlackTimeAtEnd = minSlackTime(openDeliveries);
|
||||||
|
stateManager.putRouteState(route, v, latestStartId, routeEnd + minSlackTimeAtEnd);
|
||||||
|
List<TourActivity> acts = new ArrayList<>(this.route.getActivities());
|
||||||
|
Collections.reverse(acts);
|
||||||
|
for (TourActivity act : acts) {
|
||||||
|
if (act instanceof ServiceActivity || act instanceof PickupActivity) {
|
||||||
|
String jobId = ((TourActivity.JobActivity) act).getJob().getId();
|
||||||
|
openDeliveries.remove(jobId);
|
||||||
|
double minSlackTime = minSlackTime(openDeliveries);
|
||||||
|
double latestStart = actStart(act, v) + minSlackTime;
|
||||||
|
stateManager.putActivityState(act, v, latestStartId, latestStart);
|
||||||
|
} else {
|
||||||
|
String jobId = ((TourActivity.JobActivity) act).getJob().getId();
|
||||||
|
if(slackTimes.get(vehicleIndex).containsKey(act)){
|
||||||
|
double slackTime = slackTimes.get(vehicleIndex).get(act);
|
||||||
|
openDeliveries.put(jobId,slackTime);
|
||||||
|
}
|
||||||
|
double minSlackTime = minSlackTime(openDeliveries);
|
||||||
|
double latestStart = actStart(act, v) + minSlackTime;
|
||||||
|
stateManager.putActivityState(act, v, latestStartId, latestStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double actStart(TourActivity act, Vehicle v) {
|
||||||
|
return actStartTimes.get(v.getVehicleTypeIdentifier().getIndex()).get(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double minSlackTime(Map<String, Double> openDeliveries) {
|
||||||
|
double min = Double.MAX_VALUE;
|
||||||
|
for(Double value : openDeliveries.values()){
|
||||||
|
if(value < min) min = value;
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.problem.constraint;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateId;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.TransportTime;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||||
|
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||||
|
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.PickupActivity;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 15/09/16.
|
||||||
|
*/
|
||||||
|
public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
|
||||||
|
|
||||||
|
private final TransportTime transportTime;
|
||||||
|
|
||||||
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private final StateId latestStartId;
|
||||||
|
|
||||||
|
private final StateManager stateManager;
|
||||||
|
|
||||||
|
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager) {
|
||||||
|
this.transportTime = transportTime;
|
||||||
|
this.latestStartId = latestStartId;
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.activityCosts = activityCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
/*
|
||||||
|
1. check whether insertion of new shipment satisfies own max-in-vehicle-constraint
|
||||||
|
2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
|
||||||
|
*/
|
||||||
|
//************ 1. check whether insertion of new shipment satisfies own max-in-vehicle-constraint
|
||||||
|
double newActArrival = prevActDepTime + transportTime.getTransportTime(prevAct.getLocation(),newAct.getLocation(),prevActDepTime,iFacts.getNewDriver(),iFacts.getNewVehicle());
|
||||||
|
double newActStart = Math.max(newActArrival, newAct.getTheoreticalEarliestOperationStartTime());
|
||||||
|
double newActDeparture = newActStart + activityCosts.getActivityDuration(newAct, newActArrival, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
double nextActArrival = newActDeparture + transportTime.getTransportTime(newAct.getLocation(),nextAct.getLocation(),newActDeparture,iFacts.getNewDriver(),iFacts.getNewVehicle());
|
||||||
|
double nextActStart = Math.max(nextActArrival,nextAct.getTheoreticalEarliestOperationStartTime());
|
||||||
|
if(newAct instanceof DeliveryActivity){
|
||||||
|
double pickupEnd;
|
||||||
|
if(iFacts.getAssociatedActivities().size() == 1){
|
||||||
|
pickupEnd = iFacts.getNewDepTime();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pickupEnd = iFacts.getRelatedActivityContext().getEndTime();
|
||||||
|
}
|
||||||
|
double timeInVehicle = newActStart - pickupEnd;
|
||||||
|
double maxTimeInVehicle = ((TourActivity.JobActivity)newAct).getJob().getMaxTimeInVehicle();
|
||||||
|
if(timeInVehicle > maxTimeInVehicle) return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(newAct instanceof PickupActivity){
|
||||||
|
if(iFacts.getAssociatedActivities().size() == 1){
|
||||||
|
double maxTimeInVehicle = ((TourActivity.JobActivity)newAct).getJob().getMaxTimeInVehicle();
|
||||||
|
//ToDo - estimate in vehicle time of pickups here - This seems to trickier than I thought
|
||||||
|
double nextActDeparture = nextActStart + activityCosts.getActivityDuration(nextAct, nextActArrival, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
// if(!nextAct instanceof End)
|
||||||
|
double timeToEnd = 0; //newAct.end + tt(newAct,nextAct) + t@nextAct + t_to_end
|
||||||
|
if(timeToEnd > maxTimeInVehicle) return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//************ 2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
|
||||||
|
|
||||||
|
double latest;
|
||||||
|
if(iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
|
||||||
|
else if(nextAct instanceof End){
|
||||||
|
latest = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), latestStartId,Double.class);
|
||||||
|
}
|
||||||
|
else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class);
|
||||||
|
|
||||||
|
if(nextActStart > latest){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private double getMaxTime(String jobId) {
|
||||||
|
// if(maxTimes.containsKey(jobId)) return maxTimes.get(jobId);
|
||||||
|
// else return Double.MAX_VALUE;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -41,6 +41,13 @@ public class Delivery extends Service {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Builder setMaxTimeInVehicle(double maxTimeInVehicle){
|
||||||
|
if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive");
|
||||||
|
this.maxTimeInVehicle = maxTimeInVehicle;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds Delivery.
|
* Builds Delivery.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -62,4 +62,6 @@ public interface Job extends HasId, HasIndex {
|
||||||
*/
|
*/
|
||||||
public int getPriority();
|
public int getPriority();
|
||||||
|
|
||||||
|
public double getMaxTimeInVehicle();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,13 @@ public class Pickup extends Service {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setMaxTimeInVehicle(double maxTimeInVehicle){
|
||||||
|
throw new UnsupportedOperationException("maxTimeInVehicle is not yet supported for Pickups and Services (only for Deliveries and Shipments)");
|
||||||
|
// if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive");
|
||||||
|
// this.maxTimeInVehicle = maxTimeInVehicle;
|
||||||
|
// return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds Pickup.
|
* Builds Pickup.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ import java.util.Collection;
|
||||||
*/
|
*/
|
||||||
public class Service extends AbstractJob {
|
public class Service extends AbstractJob {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder that builds a service.
|
* Builder that builds a service.
|
||||||
*
|
*
|
||||||
|
|
@ -90,6 +92,8 @@ public class Service extends AbstractJob {
|
||||||
|
|
||||||
private int priority = 2;
|
private int priority = 2;
|
||||||
|
|
||||||
|
protected double maxTimeInVehicle = Double.MAX_VALUE;
|
||||||
|
|
||||||
Builder(String id){
|
Builder(String id){
|
||||||
this.id = id;
|
this.id = id;
|
||||||
timeWindows = new TimeWindowsImpl();
|
timeWindows = new TimeWindowsImpl();
|
||||||
|
|
@ -224,6 +228,13 @@ public class Service extends AbstractJob {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder<T> setMaxTimeInVehicle(double maxTimeInVehicle){
|
||||||
|
throw new UnsupportedOperationException("maxTimeInVehicle is not yet supported for Pickups and Services (only for Deliveries and Shipments)");
|
||||||
|
// if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive");
|
||||||
|
// this.maxTimeInVehicle = maxTimeInVehicle;
|
||||||
|
// return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
@ -246,6 +257,8 @@ public class Service extends AbstractJob {
|
||||||
|
|
||||||
private final int priority;
|
private final int priority;
|
||||||
|
|
||||||
|
private final double maxTimeInVehicle;
|
||||||
|
|
||||||
Service(Builder builder) {
|
Service(Builder builder) {
|
||||||
id = builder.id;
|
id = builder.id;
|
||||||
serviceTime = builder.serviceTime;
|
serviceTime = builder.serviceTime;
|
||||||
|
|
@ -257,6 +270,7 @@ public class Service extends AbstractJob {
|
||||||
location = builder.location;
|
location = builder.location;
|
||||||
timeWindowManager = builder.timeWindows;
|
timeWindowManager = builder.timeWindows;
|
||||||
priority = builder.priority;
|
priority = builder.priority;
|
||||||
|
maxTimeInVehicle = builder.maxTimeInVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<TimeWindow> getTimeWindows(){
|
public Collection<TimeWindow> getTimeWindows(){
|
||||||
|
|
@ -370,4 +384,9 @@ public class Service extends AbstractJob {
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMaxTimeInVehicle() {
|
||||||
|
return this.maxTimeInVehicle;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,8 @@ public class Shipment extends AbstractJob {
|
||||||
|
|
||||||
private int priority = 2;
|
private int priority = 2;
|
||||||
|
|
||||||
|
public double maxTimeInVehicle = Double.MAX_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns new instance of this builder.
|
* Returns new instance of this builder.
|
||||||
*
|
*
|
||||||
|
|
@ -281,6 +283,18 @@ public class Shipment extends AbstractJob {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets maximal time the job can be in vehicle.
|
||||||
|
*
|
||||||
|
* @param maxTimeInVehicle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder setMaxTimeInVehicle(double maxTimeInVehicle){
|
||||||
|
if(maxTimeInVehicle < 0) throw new IllegalArgumentException("maxTimeInVehicle should be positive");
|
||||||
|
this.maxTimeInVehicle = maxTimeInVehicle;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
@ -309,6 +323,8 @@ public class Shipment extends AbstractJob {
|
||||||
|
|
||||||
private final int priority;
|
private final int priority;
|
||||||
|
|
||||||
|
private final double maxTimeInVehicle;
|
||||||
|
|
||||||
Shipment(Builder builder) {
|
Shipment(Builder builder) {
|
||||||
this.id = builder.id;
|
this.id = builder.id;
|
||||||
this.pickupServiceTime = builder.pickupServiceTime;
|
this.pickupServiceTime = builder.pickupServiceTime;
|
||||||
|
|
@ -323,6 +339,7 @@ public class Shipment extends AbstractJob {
|
||||||
this.deliveryTimeWindows = builder.deliveryTimeWindows;
|
this.deliveryTimeWindows = builder.deliveryTimeWindows;
|
||||||
this.pickupTimeWindows = builder.pickupTimeWindows;
|
this.pickupTimeWindows = builder.pickupTimeWindows;
|
||||||
this.priority = builder.priority;
|
this.priority = builder.priority;
|
||||||
|
this.maxTimeInVehicle = builder.maxTimeInVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -440,4 +457,9 @@ public class Shipment extends AbstractJob {
|
||||||
public int getPriority() {
|
public int getPriority() {
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMaxTimeInVehicle() {
|
||||||
|
return maxTimeInVehicle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.algorithm;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateId;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
|
||||||
|
import com.graphhopper.jsprit.core.problem.Location;
|
||||||
|
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
|
||||||
|
import com.graphhopper.jsprit.core.problem.constraint.MaxTimeInVehicleConstraint;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
|
import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
|
||||||
|
import com.graphhopper.jsprit.core.util.Solutions;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 20/09/16.
|
||||||
|
*/
|
||||||
|
public class MaxTimeInVehicle_IT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
|
||||||
|
Shipment s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
|
||||||
|
.setMaxTimeInVehicle(90d)
|
||||||
|
.build();
|
||||||
|
Shipment s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
|
||||||
|
.setMaxTimeInVehicle(90d)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
|
||||||
|
|
||||||
|
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addJob(s1).addJob(s2).build();
|
||||||
|
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId id = stateManager.createStateId("max-time");
|
||||||
|
stateManager.addStateUpdater(new UpdateMaxTimeInVehicle(stateManager,id,vrp.getTransportCosts(),vrp.getActivityCosts()));
|
||||||
|
|
||||||
|
ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager);
|
||||||
|
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager), ConstraintManager.Priority.CRITICAL);
|
||||||
|
|
||||||
|
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager,constraintManager).buildAlgorithm();
|
||||||
|
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||||
|
|
||||||
|
Assert.assertEquals(400, solution.getCost(), 0.001);
|
||||||
|
// SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.algorithm.state;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.problem.Location;
|
||||||
|
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Pickup;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
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.vehicle.Vehicle;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 15/09/16.
|
||||||
|
*/
|
||||||
|
public class UpdateMaxTimeInVehicleTest {
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private VehicleRoute route2;
|
||||||
|
|
||||||
|
private VehicleImpl vehicle;
|
||||||
|
|
||||||
|
private VehicleImpl v;
|
||||||
|
|
||||||
|
private VehicleImpl vehicle2;
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle maxTimeInVehicleConstraint;
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
private StateId latestStartId;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void doBefore() {
|
||||||
|
VehicleType type = VehicleTypeImpl.Builder.newInstance("t").build();
|
||||||
|
|
||||||
|
v = VehicleImpl.Builder.newInstance("v0").setStartLocation(Location.newInstance(0, 0))
|
||||||
|
.setType(type).build();
|
||||||
|
|
||||||
|
vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0))
|
||||||
|
.setEndLocation(Location.newInstance(0,50)).setType(type).build();
|
||||||
|
|
||||||
|
vehicle2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(0,10))
|
||||||
|
.setEndLocation(Location.newInstance(0,40)).setType(type).build();
|
||||||
|
|
||||||
|
Pickup service = Pickup.Builder.newInstance("s").setLocation(Location.newInstance(0, 10)).build();
|
||||||
|
Pickup service2 = Pickup.Builder.newInstance("s2").setLocation(Location.newInstance(0, 20)).build();
|
||||||
|
|
||||||
|
Pickup service3 = Pickup.Builder.newInstance("s3").setLocation(Location.newInstance(0, 30)).build();
|
||||||
|
Pickup service4 = Pickup.Builder.newInstance("s4").setLocation(Location.newInstance(0, 40)).build();
|
||||||
|
|
||||||
|
Delivery d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,0)).build();
|
||||||
|
|
||||||
|
Shipment shipment = Shipment.Builder.newInstance("shipment").setPickupLocation(Location.newInstance(20,0))
|
||||||
|
.setDeliveryLocation(Location.newInstance(40,0))
|
||||||
|
.setMaxTimeInVehicle(20d)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Delivery d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(30,0)).setServiceTime(10).build();
|
||||||
|
|
||||||
|
|
||||||
|
vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).addVehicle(vehicle).addVehicle(vehicle2).addJob(service)
|
||||||
|
.addJob(service2).addJob(service3).addJob(service4)
|
||||||
|
.addJob(d1).addJob(shipment).addJob(d2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
route = VehicleRoute.Builder.newInstance(vehicle).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addService(service).addService(service2).addService(service3).addService(service4).build();
|
||||||
|
|
||||||
|
route2 = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addDelivery(d1).addPickup(shipment).addDelivery(shipment).build();
|
||||||
|
|
||||||
|
stateManager = new StateManager(vrp);
|
||||||
|
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(),vrp.getActivityCosts()));
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(route), null);
|
||||||
|
|
||||||
|
latestStartId = stateManager.createStateId("slack-time-id");
|
||||||
|
|
||||||
|
// Map<String,Double> maxTimes = new HashMap<>();
|
||||||
|
// maxTimes.put("s",40d);
|
||||||
|
// maxTimes.put("shipment",20d);
|
||||||
|
maxTimeInVehicleConstraint = new UpdateMaxTimeInVehicle(stateManager, latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
maxTimeInVehicleConstraint.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
||||||
|
@Override
|
||||||
|
public Collection<Vehicle> get(VehicleRoute route) {
|
||||||
|
return Arrays.asList((Vehicle)vehicle,(Vehicle)vehicle2,v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stateManager.addStateUpdater(maxTimeInVehicleConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testVehicle(){
|
||||||
|
// stateManager.informInsertionStarts(Arrays.asList(route), null);
|
||||||
|
// for(TourActivity act : route.getActivities()){
|
||||||
|
// String jobId = ((TourActivity.JobActivity)act).getJob().getId();
|
||||||
|
// if(jobId.equals("s4")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(40, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s3")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(30, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s2")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(20, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,route.getVehicle(), latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Double slackTime = stateManager.getRouteState(route,route.getVehicle(), latestStartId,Double.class);
|
||||||
|
// Assert.assertNotNull(slackTime);
|
||||||
|
// Assert.assertEquals(50,slackTime,0.001);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testVehicle2(){
|
||||||
|
// stateManager.informInsertionStarts(Arrays.asList(route), null);
|
||||||
|
// for(TourActivity act : route.getActivities()){
|
||||||
|
// String jobId = ((TourActivity.JobActivity)act).getJob().getId();
|
||||||
|
// if(jobId.equals("s4")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(40, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s3")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(30, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s2")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(20, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// if(jobId.equals("s")){
|
||||||
|
// Double slackTime = stateManager.getActivityState(act,vehicle2, latestStartId,Double.class);
|
||||||
|
// Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Double slackTime = stateManager.getRouteState(route,vehicle2, latestStartId,Double.class);
|
||||||
|
// Assert.assertNotNull(slackTime);
|
||||||
|
// Assert.assertEquals(40,slackTime,0.001);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithShipment(){
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(route2), null);
|
||||||
|
for(TourActivity act : route2.getActivities()){
|
||||||
|
String jobId = ((TourActivity.JobActivity)act).getJob().getId();
|
||||||
|
if(jobId.equals("d1")){
|
||||||
|
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class);
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
|
||||||
|
}
|
||||||
|
if(jobId.equals("shipment")){
|
||||||
|
if(act instanceof PickupActivity){
|
||||||
|
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class);
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, slackTime, 0.001);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Double slackTime = stateManager.getActivityState(act,v, latestStartId,Double.class);
|
||||||
|
Assert.assertEquals(40, slackTime, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.problem.constraint;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateId;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
|
||||||
|
import com.graphhopper.jsprit.core.problem.AbstractActivity;
|
||||||
|
import com.graphhopper.jsprit.core.problem.Location;
|
||||||
|
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Pickup;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||||
|
import com.graphhopper.jsprit.core.problem.misc.ActivityContext;
|
||||||
|
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/09/16.
|
||||||
|
*/
|
||||||
|
public class MaxTimeInVehicleConstraintTest {
|
||||||
|
|
||||||
|
Delivery d1;
|
||||||
|
|
||||||
|
Shipment shipment;
|
||||||
|
|
||||||
|
Delivery d2;
|
||||||
|
|
||||||
|
Pickup p1;
|
||||||
|
|
||||||
|
Pickup p2;
|
||||||
|
|
||||||
|
Vehicle v;
|
||||||
|
|
||||||
|
VehicleRoute route;
|
||||||
|
|
||||||
|
VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void doBefore(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ini(double maxTime){
|
||||||
|
d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,0)).build();
|
||||||
|
shipment = Shipment.Builder.newInstance("shipment").setPickupLocation(Location.newInstance(20,0))
|
||||||
|
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(maxTime).build();
|
||||||
|
d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(30,0)).setServiceTime(10).build();
|
||||||
|
|
||||||
|
p1 = Pickup.Builder.newInstance("p1").setLocation(Location.newInstance(10, 0)).build();
|
||||||
|
p2 = Pickup.Builder.newInstance("p2").setLocation(Location.newInstance(20,0)).build();
|
||||||
|
|
||||||
|
v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
|
||||||
|
|
||||||
|
vrp = VehicleRoutingProblem.Builder.newInstance().addJob(d1).addJob(shipment).addJob(d2).addJob(p1).addJob(p2)
|
||||||
|
.addVehicle(v).build();
|
||||||
|
|
||||||
|
route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addDelivery(d1).addPickup(shipment).addDelivery(shipment).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void insertingDeliveryAtAnyPositionShouldWork(){
|
||||||
|
ini(30d);
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
|
||||||
|
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
stateManager.addStateUpdater(updater);
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
|
||||||
|
|
||||||
|
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
|
||||||
|
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
|
||||||
|
List<AbstractActivity> acts = vrp.getActivities(d2);
|
||||||
|
c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
|
||||||
|
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.getActivities().get(0), acts.get(0), route.getActivities().get(1), 10));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getActivities().get(1), acts.get(0), route.getActivities().get(2), 20));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getActivities().get(2), acts.get(0), route.getEnd(), 40));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void insertingDeliveryInBetweenShipmentShouldFail(){
|
||||||
|
ini(25d);
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
|
||||||
|
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(),vrp.getActivityCosts());
|
||||||
|
stateManager.addStateUpdater(updater);
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
|
||||||
|
|
||||||
|
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
|
||||||
|
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
|
||||||
|
List<AbstractActivity> acts = vrp.getActivities(d2);
|
||||||
|
c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
|
||||||
|
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.getActivities().get(0), acts.get(0), route.getActivities().get(1), 10));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, route.getActivities().get(1), acts.get(0), route.getActivities().get(2), 20));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getActivities().get(2), acts.get(0), route.getEnd(), 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void insertingPickupShipmentAtAnyPositionShouldWork(){
|
||||||
|
ini(25d);
|
||||||
|
VehicleRoute r = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addDelivery(d1).addDelivery(d2).build();
|
||||||
|
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
|
||||||
|
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
stateManager.addStateUpdater(updater);
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
|
||||||
|
|
||||||
|
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
|
||||||
|
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
|
||||||
|
List<AbstractActivity> acts = vrp.getActivities(shipment);
|
||||||
|
c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
c.getAssociatedActivities().add(acts.get(1));
|
||||||
|
|
||||||
|
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getStart(), acts.get(0), r.getActivities().get(0), 0));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getActivities().get(0), acts.get(0), r.getActivities().get(1), 10));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(0), r.getEnd(), 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void insertingPickupBeforeDeliveryShouldFail(){
|
||||||
|
// VehicleRoute r = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
// .addPickup(p1).addDelivery(d2).build();
|
||||||
|
//
|
||||||
|
// StateManager stateManager = new StateManager(vrp);
|
||||||
|
// StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
//
|
||||||
|
// Map<String,Double> maxTimes = new HashMap<>();
|
||||||
|
// maxTimes.put("p2",30d);
|
||||||
|
// UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(),vrp.getActivityCosts());
|
||||||
|
// stateManager.addStateUpdater(updater);
|
||||||
|
// stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
|
||||||
|
//
|
||||||
|
// MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager);
|
||||||
|
// JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
|
||||||
|
// List<AbstractActivity> acts = vrp.getActivities(shipment);
|
||||||
|
// c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
// c.getAssociatedActivities().add(acts.get(1));
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getStart(), acts.get(0), r.getActivities().get(0), 0));
|
||||||
|
// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getActivities().get(0), acts.get(0), r.getActivities().get(1), 10));
|
||||||
|
// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(0), r.getEnd(), 30));
|
||||||
|
//// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getActivities().get(0), acts.get(0), r.getActivities().get(1), 10));
|
||||||
|
//// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(0), r.getEnd(), 40));
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPickupIsInsertedAt0_insertingDeliveryShipmentShouldFailWhereConstraintIsBroken(){
|
||||||
|
ini(25d);
|
||||||
|
VehicleRoute r = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addDelivery(d1).addDelivery(d2).build();
|
||||||
|
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
|
||||||
|
Map<String,Double> maxTimes = new HashMap<>();
|
||||||
|
maxTimes.put("shipment",25d);
|
||||||
|
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
stateManager.addStateUpdater(updater);
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
|
||||||
|
|
||||||
|
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
|
||||||
|
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
|
||||||
|
List<AbstractActivity> acts = vrp.getActivities(shipment);
|
||||||
|
c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
c.getAssociatedActivities().add(acts.get(1));
|
||||||
|
|
||||||
|
ActivityContext ac = new ActivityContext();
|
||||||
|
ac.setArrivalTime(20);
|
||||||
|
ac.setEndTime(20);
|
||||||
|
c.setRelatedActivityContext(ac);
|
||||||
|
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, acts.get(0), acts.get(1), r.getActivities().get(0), 20));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getActivities().get(0), acts.get(1), r.getActivities().get(1), 30));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(1), r.getEnd(), 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPickupIsInsertedAt1_insertingDeliveryShipmentShouldFailWhereConstraintIsBroken(){
|
||||||
|
ini(25d);
|
||||||
|
VehicleRoute r = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
|
||||||
|
.addDelivery(d1).addDelivery(d2).build();
|
||||||
|
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
StateId latestStartId = stateManager.createStateId("latest-start-id");
|
||||||
|
|
||||||
|
Map<String,Double> maxTimes = new HashMap<>();
|
||||||
|
maxTimes.put("shipment",25d);
|
||||||
|
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
stateManager.addStateUpdater(updater);
|
||||||
|
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
|
||||||
|
|
||||||
|
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
|
||||||
|
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
|
||||||
|
List<AbstractActivity> acts = vrp.getActivities(shipment);
|
||||||
|
c.getAssociatedActivities().add(acts.get(0));
|
||||||
|
c.getAssociatedActivities().add(acts.get(1));
|
||||||
|
|
||||||
|
ActivityContext ac = new ActivityContext();
|
||||||
|
ac.setArrivalTime(20);
|
||||||
|
ac.setEndTime(20);
|
||||||
|
c.setRelatedActivityContext(ac);
|
||||||
|
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, acts.get(0), acts.get(1), r.getActivities().get(1), 20));
|
||||||
|
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(1), r.getEnd(), 40));
|
||||||
|
// Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, r.getActivities().get(1), acts.get(1), r.getEnd(), 40));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -103,5 +103,20 @@ public class DeliveryTest {
|
||||||
Assert.assertEquals(2, s.getPriority());
|
Assert.assertEquals(2, s.getPriority());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenAddingMaxTimeInVehicle_itShouldBeSet(){
|
||||||
|
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.setMaxTimeInVehicle(10)
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(10, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenNotAddingMaxTimeInVehicle_itShouldBeDefault(){
|
||||||
|
Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,4 +105,18 @@ public class PickupTest {
|
||||||
Assert.assertEquals(2, s.getPriority());
|
Assert.assertEquals(2, s.getPriority());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnsupportedOperationException.class)
|
||||||
|
public void whenAddingMaxTimeInVehicle_itShouldThrowEx(){
|
||||||
|
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.setMaxTimeInVehicle(10)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenNotAddingMaxTimeInVehicle_itShouldBeDefault(){
|
||||||
|
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -271,4 +271,18 @@ public class ServiceTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnsupportedOperationException.class)
|
||||||
|
public void whenAddingMaxTimeInVehicle_itShouldThrowEx(){
|
||||||
|
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.setMaxTimeInVehicle(10)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenNotAddingMaxTimeInVehicle_itShouldBeDefault(){
|
||||||
|
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -425,4 +425,19 @@ public class ShipmentTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenAddingMaxTimeInVehicle_itShouldBeSet(){
|
||||||
|
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")).setDeliveryLocation(Location.newInstance("loc"))
|
||||||
|
.setMaxTimeInVehicle(10)
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(10, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenNotAddingMaxTimeInVehicle_itShouldBeDefault(){
|
||||||
|
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")).setDeliveryLocation(Location.newInstance("loc"))
|
||||||
|
.build();
|
||||||
|
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue