1
0
Fork 0
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:
kobyb 2018-02-04 14:00:38 +02:00 committed by GitHub
commit 92afffcf1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 381 additions and 15 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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