mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge pull request #29 from bringg/pass-prev-activity
pass prev activity
This commit is contained in:
commit
92afffcf1e
6 changed files with 381 additions and 15 deletions
|
|
@ -57,6 +57,8 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
|
||||||
|
|
||||||
private final VehicleRoutingActivityCosts activityCosts;
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private TourActivity prevTourActivity = null;
|
||||||
|
|
||||||
private UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate vehiclesToUpdate = new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
private UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate vehiclesToUpdate = new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -98,6 +100,7 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
|
||||||
prevActEndTimes[vehicleIndex] = v.getEarliestDeparture();
|
prevActEndTimes[vehicleIndex] = v.getEarliestDeparture();
|
||||||
prevActLocations[vehicleIndex] = v.getStartLocation();
|
prevActLocations[vehicleIndex] = v.getStartLocation();
|
||||||
}
|
}
|
||||||
|
prevTourActivity = route.getStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -111,7 +114,7 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
|
||||||
double activityArrival = prevActEndTimes[v.getVehicleTypeIdentifier().getIndex()] + transportTime.getTransportTime(prevActLocation,activity.getLocation(),prevActEndTime,route.getDriver(),v);
|
double activityArrival = prevActEndTimes[v.getVehicleTypeIdentifier().getIndex()] + transportTime.getTransportTime(prevActLocation,activity.getLocation(),prevActEndTime,route.getDriver(),v);
|
||||||
double activityStart = Math.max(activityArrival,activity.getTheoreticalEarliestOperationStartTime());
|
double activityStart = Math.max(activityArrival,activity.getTheoreticalEarliestOperationStartTime());
|
||||||
memorizeActStart(activity,v,activityStart);
|
memorizeActStart(activity,v,activityStart);
|
||||||
double activityEnd = activityStart + activityCosts.getActivityDuration(null, activity, activityArrival, route.getDriver(), v);
|
double activityEnd = activityStart + activityCosts.getActivityDuration(prevTourActivity, activity, activityArrival, route.getDriver(), v);
|
||||||
Map<Job, Double> openPickups = openPickupEndTimesPerVehicle.get(vehicleIndex);
|
Map<Job, Double> openPickups = openPickupEndTimesPerVehicle.get(vehicleIndex);
|
||||||
if (activity instanceof ServiceActivity || activity instanceof PickupActivity) {
|
if (activity instanceof ServiceActivity || activity instanceof PickupActivity) {
|
||||||
openPickups.put(((TourActivity.JobActivity) activity).getJob(), activityEnd);
|
openPickups.put(((TourActivity.JobActivity) activity).getJob(), activityEnd);
|
||||||
|
|
@ -129,6 +132,8 @@ public class UpdateMaxTimeInVehicle implements StateUpdater, ActivityVisitor{
|
||||||
prevActEndTimes[vehicleIndex] = activityEnd;
|
prevActEndTimes[vehicleIndex] = activityEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prevTourActivity = activity;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getMaxTimeInVehicle(TourActivity activity) {
|
private double getMaxTimeInVehicle(TourActivity activity) {
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,23 @@ import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.List;
|
||||||
|
|
||||||
public class UpdateVehicleDependentPracticalTimeWindows implements RouteVisitor, StateUpdater {
|
public class UpdateVehicleDependentPracticalTimeWindows implements RouteVisitor, StateUpdater {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(VehicleRoute route) {
|
public void visit(VehicleRoute route) {
|
||||||
begin(route);
|
begin(route);
|
||||||
Iterator<TourActivity> revIterator = route.getTourActivities().reverseActivityIterator();
|
List<TourActivity> activities = new ArrayList<>();
|
||||||
while (revIterator.hasNext()) {
|
activities.add(route.getStart());
|
||||||
visit(revIterator.next());
|
activities.addAll(route.getTourActivities().getActivities());
|
||||||
}
|
|
||||||
|
for (int i = activities.size() - 1; i > 0; --i)
|
||||||
|
visit(activities.get(i), activities.get(i - 1));
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,12 +103,12 @@ public class UpdateVehicleDependentPracticalTimeWindows implements RouteVisitor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void visit(TourActivity activity) {
|
public void visit(TourActivity activity, TourActivity prev) {
|
||||||
for (Vehicle vehicle : vehicles) {
|
for (Vehicle vehicle : vehicles) {
|
||||||
double latestArrTimeAtPrevAct = latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()];
|
double latestArrTimeAtPrevAct = latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()];
|
||||||
Location prevLocation = location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()];
|
Location prevLocation = location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()];
|
||||||
double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocation(), prevLocation,
|
double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocation(), prevLocation,
|
||||||
latestArrTimeAtPrevAct, route.getDriver(), vehicle) - activityCosts.getActivityDuration(null, activity, latestArrTimeAtPrevAct, route.getDriver(), route.getVehicle());
|
latestArrTimeAtPrevAct, route.getDriver(), vehicle) - activityCosts.getActivityDuration(prev, activity, latestArrTimeAtPrevAct, route.getDriver(), route.getVehicle());
|
||||||
double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct);
|
double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct);
|
||||||
if (latestArrivalTime < activity.getTheoreticalEarliestOperationStartTime()) {
|
if (latestArrivalTime < activity.getTheoreticalEarliestOperationStartTime()) {
|
||||||
stateManager.putTypedInternalRouteState(route, vehicle, InternalStates.SWITCH_NOT_FEASIBLE, true);
|
stateManager.putTypedInternalRouteState(route, vehicle, InternalStates.SWITCH_NOT_FEASIBLE, true);
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,17 @@ public class VehicleDependentTimeWindowConstraints implements HardActivityConstr
|
||||||
return ConstraintsStatus.NOT_FULFILLED;
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
}
|
}
|
||||||
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
||||||
|
double routingFromNewToNext = routingCosts.getBackwardTransportTime(newAct.getLocation(), nextActLocation, latestArrTimeAtNextAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double endTimeAtNewAct = Math.max(arrTimeAtNewAct, newAct.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(prevAct, newAct, arrTimeAtNewAct,iFacts.getNewDriver(),iFacts.getNewVehicle());
|
double endTimeAtNewAct = Math.max(arrTimeAtNewAct, newAct.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(prevAct, newAct, arrTimeAtNewAct,iFacts.getNewDriver(),iFacts.getNewVehicle());
|
||||||
|
double savingsInNextActivityDuration =
|
||||||
|
activityCosts.getActivityDuration(prevAct, nextAct, arrTimeAtNextOnDirectRouteWithNewVehicle, iFacts.getNewDriver(), iFacts.getNewVehicle()) -
|
||||||
|
activityCosts.getActivityDuration(newAct, nextAct, endTimeAtNewAct + routingFromNewToNext, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
latestArrTimeAtNextAct = Math.min(nextAct.getTheoreticalLatestOperationStartTime(), latestArrTimeAtNextAct + savingsInNextActivityDuration);
|
||||||
double latestArrTimeAtNewAct =
|
double latestArrTimeAtNewAct =
|
||||||
Math.min(newAct.getTheoreticalLatestOperationStartTime(),
|
Math.min(newAct.getTheoreticalLatestOperationStartTime(),
|
||||||
latestArrTimeAtNextAct -
|
latestArrTimeAtNextAct - routingFromNewToNext
|
||||||
routingCosts.getBackwardTransportTime(newAct.getLocation(), nextActLocation, latestArrTimeAtNextAct, iFacts.getNewDriver(), iFacts.getNewVehicle())
|
|
||||||
- activityCosts.getActivityDuration(prevAct, newAct, arrTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle())
|
- activityCosts.getActivityDuration(prevAct, newAct, arrTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,15 @@ import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
|
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
|
||||||
|
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Pickup;
|
||||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||||
import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory;
|
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.*;
|
||||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
|
|
||||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
|
||||||
import com.graphhopper.jsprit.core.util.Coordinate;
|
import com.graphhopper.jsprit.core.util.Coordinate;
|
||||||
import com.graphhopper.jsprit.core.util.CostFactory;
|
import com.graphhopper.jsprit.core.util.CostFactory;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
@ -42,6 +43,7 @@ import org.junit.Test;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unit tests to test vehicle dependent time window updater
|
* unit tests to test vehicle dependent time window updater
|
||||||
|
|
@ -268,5 +270,86 @@ public class UpdateVehicleDependentTimeWindowTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquash () {
|
||||||
|
Location pickupLocation = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
final double fixedDurationInSameLocation = random.nextDouble(), activityDuration = 10 + random.nextDouble(), travelTime = random.nextDouble();
|
||||||
|
|
||||||
|
Pickup pickup = Pickup.Builder.newInstance("pick1").setLocation(pickupLocation).setTimeWindow(TimeWindow.newInstance(0, 40)).setServiceTime(activityDuration).build();
|
||||||
|
Pickup pickup2 = Pickup.Builder.newInstance("pick2").setLocation(pickupLocation).setTimeWindow(TimeWindow.newInstance(0, 40)).setServiceTime(activityDuration).build();
|
||||||
|
|
||||||
|
Delivery delivery = Delivery.Builder.newInstance("del1").setLocation(Location.newInstance(random.nextDouble(), random.nextDouble())).setTimeWindow(TimeWindow.newInstance(0, 40)).setServiceTime(activityDuration).build();
|
||||||
|
Delivery delivery2 = Delivery.Builder.newInstance("del2").setLocation(Location.newInstance(random.nextDouble(), random.nextDouble())).setTimeWindow(TimeWindow.newInstance(0, 40)).setServiceTime(activityDuration).build();
|
||||||
|
|
||||||
|
Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(random.nextDouble(), random.nextDouble())).setType(VehicleTypeImpl.Builder.newInstance("type").build()).build();
|
||||||
|
|
||||||
|
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||||
|
final VehicleRoutingProblem vrp = vrpBuilder.addJob(pickup).addJob(pickup2).addJob(delivery).addJob(delivery2).addVehicle(vehicle).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).build();
|
||||||
|
|
||||||
|
route = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)).setJobActivityFactory(new JobActivityFactory() {
|
||||||
|
@Override
|
||||||
|
public List<AbstractActivity> createActivities(Job job) {
|
||||||
|
return vrp.copyAndGetActivities(job);
|
||||||
|
}
|
||||||
|
}).addService(pickup).addService(pickup2).addService(delivery).addService(delivery2).build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VehicleRoutingTransportCosts transportCosts = getTransportCosts(travelTime);
|
||||||
|
|
||||||
|
activityCosts = new WaitingTimeCosts() {
|
||||||
|
@Override
|
||||||
|
public double getActivityDuration(TourActivity prevAct, TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return prevAct != null && prevAct.getLocation().getCoordinate().equals(tourAct.getLocation().getCoordinate()) ? fixedDurationInSameLocation : tourAct.getOperationTime();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stateManager = new StateManager(vrp);
|
||||||
|
|
||||||
|
final UpdateVehicleDependentPracticalTimeWindows timeWindowsUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, transportCosts, activityCosts);
|
||||||
|
timeWindowsUpdater.visit(route);
|
||||||
|
|
||||||
|
double latestArrivalAt4Act = 40,
|
||||||
|
latestArrivalAt3Act = latestArrivalAt4Act - activityDuration - travelTime,
|
||||||
|
latestArrivalAt2Act = latestArrivalAt3Act - fixedDurationInSameLocation - travelTime,
|
||||||
|
latestArrivalAt1Act = latestArrivalAt2Act - activityDuration;
|
||||||
|
|
||||||
|
assertEquals(stateManager.getActivityState(route.getActivities().get(3), vehicle, InternalStates.LATEST_OPERATION_START_TIME, Double.class), latestArrivalAt4Act, 0.001);
|
||||||
|
assertEquals(stateManager.getActivityState(route.getActivities().get(2), vehicle, InternalStates.LATEST_OPERATION_START_TIME, Double.class), latestArrivalAt3Act, 0.001);
|
||||||
|
assertEquals(stateManager.getActivityState(route.getActivities().get(1), vehicle, InternalStates.LATEST_OPERATION_START_TIME, Double.class), latestArrivalAt2Act, 0.001);
|
||||||
|
assertEquals(stateManager.getActivityState(route.getActivities().get(0), vehicle, InternalStates.LATEST_OPERATION_START_TIME, Double.class), latestArrivalAt1Act, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingTransportCosts getTransportCosts(final double travelTime) {
|
||||||
|
return new VehicleRoutingTransportCosts() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBackwardTransportTime(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBackwardTransportCost(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,13 @@ import com.graphhopper.jsprit.core.problem.*;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
|
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
|
||||||
|
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupService;
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.*;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||||
import com.graphhopper.jsprit.core.problem.vehicle.*;
|
import com.graphhopper.jsprit.core.problem.vehicle.*;
|
||||||
import com.graphhopper.jsprit.core.util.CostFactory;
|
import com.graphhopper.jsprit.core.util.CostFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
@ -39,6 +41,8 @@ import org.junit.Test;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unit tests to test vehicle dependent time-windows
|
* unit tests to test vehicle dependent time-windows
|
||||||
|
|
@ -338,5 +342,178 @@ public class VehicleDependentTimeWindowWithStartTimeAndMaxOperationTimeTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* driver TW: 5 - 10
|
||||||
|
* prev task 0 - 5
|
||||||
|
* new and next acts at same location, tw 5-10, activity duration 4
|
||||||
|
* |--- newAct ---|
|
||||||
|
* |--- nextAct ---|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
@Test
|
||||||
|
public void testSquashNotEnd () {
|
||||||
|
final double fixedCostAtSameLocation = random.nextDouble(),
|
||||||
|
travelTime = random.nextDouble(),
|
||||||
|
firstActDuration = 5, nextActivitiesDuration = 4.0,
|
||||||
|
vehicleLatestArrival = firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 3;
|
||||||
|
|
||||||
|
Location locationFirst = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
Location locationSecond = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
|
||||||
|
Vehicle vehicle = mock(Vehicle.class);
|
||||||
|
when(vehicle.getLatestArrival()).thenReturn(vehicleLatestArrival);
|
||||||
|
|
||||||
|
JobInsertionContext iFacts = mock(JobInsertionContext.class);
|
||||||
|
when(iFacts.getNewVehicle()).thenReturn(vehicle);
|
||||||
|
|
||||||
|
RouteAndActivityStateGetter routeAndActivityStateGetter = mock(RouteAndActivityStateGetter.class);
|
||||||
|
|
||||||
|
TourActivity prevAct = getTourActivity(.0, firstActDuration, firstActDuration, locationFirst);
|
||||||
|
TourActivity newAct = getTourActivity(firstActDuration, firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 2, nextActivitiesDuration, locationSecond);
|
||||||
|
TourActivity nextAct = getTourActivity(firstActDuration, firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 2, nextActivitiesDuration, locationSecond);
|
||||||
|
|
||||||
|
when(routeAndActivityStateGetter.getActivityState(nextAct, vehicle, InternalStates.LATEST_OPERATION_START_TIME, Double.class)).thenReturn(vehicleLatestArrival - travelTime - nextActivitiesDuration);
|
||||||
|
|
||||||
|
final VehicleDependentTimeWindowConstraints timeWindowConstraints = new VehicleDependentTimeWindowConstraints(routeAndActivityStateGetter, getTransportCosts(travelTime), getActivityCost(fixedCostAtSameLocation));
|
||||||
|
|
||||||
|
assertEquals(timeWindowConstraints.fulfilled(iFacts, prevAct, newAct, nextAct, 5.0), HardActivityConstraint.ConstraintsStatus.FULFILLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoSquashEnd () {
|
||||||
|
final double fixedCostAtSameLocation = random.nextDouble(),
|
||||||
|
travelTime = random.nextDouble(),
|
||||||
|
firstActDuration = 5, nextActivitiesDuration = 4.0,
|
||||||
|
vehicleLatestArrival = firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 3;
|
||||||
|
|
||||||
|
Location locationFirst = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
Location locationSecond = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
|
||||||
|
Vehicle vehicle = mock(Vehicle.class);
|
||||||
|
when(vehicle.getLatestArrival()).thenReturn(vehicleLatestArrival);
|
||||||
|
when(vehicle.isReturnToDepot()).thenReturn(false);
|
||||||
|
|
||||||
|
JobInsertionContext iFacts = mock(JobInsertionContext.class);
|
||||||
|
when(iFacts.getNewVehicle()).thenReturn(vehicle);
|
||||||
|
|
||||||
|
TourActivity prevAct = getTourActivity(.0, firstActDuration, firstActDuration, locationFirst);
|
||||||
|
TourActivity newAct = getTourActivity(firstActDuration, firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 2, nextActivitiesDuration, locationSecond);
|
||||||
|
End end = new End(locationSecond, firstActDuration, firstActDuration + nextActivitiesDuration + fixedCostAtSameLocation + travelTime * 2);
|
||||||
|
|
||||||
|
final VehicleDependentTimeWindowConstraints timeWindowConstraints = new VehicleDependentTimeWindowConstraints(mock(RouteAndActivityStateGetter.class), getTransportCosts(travelTime), getActivityCost(fixedCostAtSameLocation));
|
||||||
|
|
||||||
|
assertEquals(timeWindowConstraints.fulfilled(iFacts, prevAct, newAct, end, 5.0), HardActivityConstraint.ConstraintsStatus.FULFILLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashEndReturnToDepot () {
|
||||||
|
final double fixedCostAtSameLocation = random.nextDouble(),
|
||||||
|
travelTime = random.nextDouble(),
|
||||||
|
firstActDuration = 5.0, newActivityDuration = 4.0,
|
||||||
|
vehicleLatestArrival = firstActDuration + fixedCostAtSameLocation + travelTime;
|
||||||
|
|
||||||
|
Location location = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
Location depot = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
|
||||||
|
Vehicle vehicle = mock(Vehicle.class);
|
||||||
|
when(vehicle.getLatestArrival()).thenReturn(vehicleLatestArrival);
|
||||||
|
when(vehicle.isReturnToDepot()).thenReturn(true);
|
||||||
|
when(vehicle.getEndLocation()).thenReturn(depot);
|
||||||
|
|
||||||
|
JobInsertionContext iFacts = mock(JobInsertionContext.class);
|
||||||
|
when(iFacts.getNewVehicle()).thenReturn(vehicle);
|
||||||
|
|
||||||
|
TourActivity prevAct = getTourActivity(.0, firstActDuration, firstActDuration, location);
|
||||||
|
TourActivity newAct = getTourActivity(firstActDuration, firstActDuration + fixedCostAtSameLocation, newActivityDuration, location);
|
||||||
|
End end = new End(depot, firstActDuration, firstActDuration + fixedCostAtSameLocation + travelTime);
|
||||||
|
|
||||||
|
final VehicleDependentTimeWindowConstraints timeWindowConstraints = new VehicleDependentTimeWindowConstraints(mock(RouteAndActivityStateGetter.class), getTransportCosts(travelTime), getActivityCost(fixedCostAtSameLocation));
|
||||||
|
|
||||||
|
assertEquals(timeWindowConstraints.fulfilled(iFacts, prevAct, newAct, end, 5.0), HardActivityConstraint.ConstraintsStatus.FULFILLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashEndNoReturnToDepot () {
|
||||||
|
final double fixedCostAtSameLocation = random.nextDouble(),
|
||||||
|
travelTime = random.nextDouble(),
|
||||||
|
firstActDuration = 5.0, newActivityDuration = 4.0,
|
||||||
|
vehicleLatestArrival = firstActDuration + fixedCostAtSameLocation;
|
||||||
|
|
||||||
|
Location location = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
Location depot = Location.newInstance(random.nextDouble(), random.nextDouble());
|
||||||
|
|
||||||
|
Vehicle vehicle = mock(Vehicle.class);
|
||||||
|
when(vehicle.getLatestArrival()).thenReturn(vehicleLatestArrival);
|
||||||
|
when(vehicle.isReturnToDepot()).thenReturn(false);
|
||||||
|
when(vehicle.getEndLocation()).thenReturn(depot);
|
||||||
|
|
||||||
|
JobInsertionContext iFacts = mock(JobInsertionContext.class);
|
||||||
|
when(iFacts.getNewVehicle()).thenReturn(vehicle);
|
||||||
|
|
||||||
|
TourActivity prevAct = getTourActivity(.0, firstActDuration, firstActDuration, location);
|
||||||
|
TourActivity newAct = getTourActivity(firstActDuration, firstActDuration + fixedCostAtSameLocation, newActivityDuration, location);
|
||||||
|
End end = new End(depot, firstActDuration, firstActDuration + fixedCostAtSameLocation);
|
||||||
|
|
||||||
|
final VehicleDependentTimeWindowConstraints timeWindowConstraints = new VehicleDependentTimeWindowConstraints(mock(RouteAndActivityStateGetter.class), getTransportCosts(travelTime), getActivityCost(fixedCostAtSameLocation));
|
||||||
|
|
||||||
|
assertEquals(timeWindowConstraints.fulfilled(iFacts, prevAct, newAct, end, 5.0), HardActivityConstraint.ConstraintsStatus.FULFILLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TourActivity getTourActivity(double start, double end, double activityDuration, Location location) {
|
||||||
|
TourActivity act = mock(DeliveryActivity.class);
|
||||||
|
when(act.getTheoreticalEarliestOperationStartTime()).thenReturn(start);
|
||||||
|
when(act.getTheoreticalLatestOperationStartTime()).thenReturn(end);
|
||||||
|
when(act.getOperationTime()).thenReturn(activityDuration);
|
||||||
|
when(act.getLocation()).thenReturn(location);
|
||||||
|
return act;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts getActivityCost(final double fixedCostAtSameLocation) {
|
||||||
|
return new VehicleRoutingActivityCosts() {
|
||||||
|
@Override
|
||||||
|
public double getActivityCost(TourActivity prevAct, TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return getActivityDuration(prevAct, tourAct, arrivalTime, driver, vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getActivityDuration(TourActivity from, TourActivity to, double startTime, Driver driver, Vehicle vehicle) {
|
||||||
|
if (from != null && !(to instanceof BreakActivity || from instanceof BreakActivity) && from.getLocation().getCoordinate().equals(to.getLocation().getCoordinate())) {
|
||||||
|
return fixedCostAtSameLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return to.getOperationTime();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingTransportCosts getTransportCosts(final double travelTime) {
|
||||||
|
return new VehicleRoutingTransportCosts() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBackwardTransportTime(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBackwardTransportCost(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return from.getCoordinate().equals(to.getCoordinate()) ? 0 : travelTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.graphhopper.jsprit.io.algorithm;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||||
|
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.HardActivityConstraint;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||||
|
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||||
|
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||||
|
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.BreakActivity;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||||
|
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.VehicleTypeImpl;
|
||||||
|
import com.graphhopper.jsprit.core.util.Solutions;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TestAlgorithmSquashActivityTimes {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquash () {
|
||||||
|
VehicleRoutingActivityCosts activityCost = new VehicleRoutingActivityCosts() {
|
||||||
|
@Override
|
||||||
|
public double getActivityCost(TourActivity prevAct, TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) {
|
||||||
|
return getActivityDuration(prevAct, tourAct, arrivalTime, driver, vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getActivityDuration(TourActivity from, TourActivity to, double startTime, Driver driver, Vehicle vehicle) {
|
||||||
|
if (from != null && !(to instanceof BreakActivity || from instanceof BreakActivity) && from.getLocation().getCoordinate().equals(to.getLocation().getCoordinate())) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return to.getOperationTime();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||||
|
.addVehicle(VehicleImpl.Builder.newInstance("vehicle")
|
||||||
|
.setStartLocation(Location.newInstance(1.521801, 42.506285))
|
||||||
|
.setEarliestStart(0)
|
||||||
|
.setLatestArrival(10).setType(VehicleTypeImpl.Builder.newInstance(UUID.randomUUID().toString()).addCapacityDimension(0, Integer.MAX_VALUE).build())
|
||||||
|
.setReturnToDepot(false)
|
||||||
|
.build())
|
||||||
|
.addJob(getJobs(0, 10, 1, 7))
|
||||||
|
.addJob(getJobs(0, 10, 1, 7))
|
||||||
|
.addJob(getJobs(0, 10, 1, 7))
|
||||||
|
.addJob(getJobs(0, 10, 1, 6))
|
||||||
|
.setActivityCosts(activityCost)
|
||||||
|
.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
StateManager stateManager = new StateManager(vrp);
|
||||||
|
|
||||||
|
ConstraintManager constraintManager = new ConstraintManager (vrp, stateManager) {
|
||||||
|
@Override
|
||||||
|
public HardActivityConstraint.ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime){
|
||||||
|
if (newAct instanceof BreakActivity && newAct.getLocation().equals(nextAct.getLocation()))
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
|
||||||
|
return super.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, Runtime.getRuntime().availableProcessors() + 1, getClass().getResource("algorithmConfig_withoutIterations.xml").getFile(), stateManager, constraintManager, null);
|
||||||
|
|
||||||
|
final VehicleRoutingProblemSolution problemSolution = Solutions.bestOf(algorithm.searchSolutions());
|
||||||
|
|
||||||
|
assertEquals(problemSolution.getUnassignedJobs().size(), 0);
|
||||||
|
assertEquals(problemSolution.getRoutes().iterator().next().getTourActivities().getActivities().size(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job getJobs(int start, int end, int capacity, int duration) {
|
||||||
|
return Delivery.Builder.newInstance("service_" + new Random().nextInt())
|
||||||
|
.setLocation(Location.newInstance(1.52181, 42.5062))
|
||||||
|
.setServiceTime(duration)
|
||||||
|
.addTimeWindow(new TimeWindow(start, end))
|
||||||
|
.addSizeDimension(0, capacity)
|
||||||
|
.setName(UUID.randomUUID().toString())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue