1
0
Fork 0
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:
oblonski 2016-09-20 17:58:02 +02:00
parent 7590be9794
commit 42ae57d00b
14 changed files with 945 additions and 0 deletions

View file

@ -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;
}
}

View file

@ -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;
// }
}

View file

@ -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.
* *

View file

@ -62,4 +62,6 @@ public interface Job extends HasId, HasIndex {
*/ */
public int getPriority(); public int getPriority();
public double getMaxTimeInVehicle();
} }

View file

@ -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>

View file

@ -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;
}
} }

View file

@ -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;
}
} }

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}
}

View file

@ -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));
}
}

View file

@ -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);
}
} }

View file

@ -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);
}
} }

View file

@ -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);
}
} }

View file

@ -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);
}
} }