1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

Fix Vehicle's break location is ignored #439

This commit is contained in:
reinterpretcat 2018-11-06 15:40:12 +01:00
parent 25a3052a54
commit 2e15005716
3 changed files with 84 additions and 8 deletions

View file

@ -67,6 +67,8 @@ final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
private final AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private final ServiceInsertionCalculator serviceInsertionCalculator;
public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager, JobActivityFactory activityFactory) {
super();
this.transportCosts = routingCosts;
@ -78,6 +80,7 @@ final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
this.activityFactory = activityFactory;
this.serviceInsertionCalculator = new ServiceInsertionCalculator(routingCosts, activityCosts, additionalTransportCostsCalculator, constraintManager, activityFactory);
logger.debug("initialise " + this);
}
@ -105,6 +108,11 @@ final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
BreakActivity breakAct2Insert = (BreakActivity) activityFactory.createActivities(breakToInsert).get(0);
insertionContext.getAssociatedActivities().add(breakAct2Insert);
if (!breakToInsert.hasVariableLocation()) {
breakAct2Insert.setLocation(breakToInsert.getLocation());
return serviceInsertionCalculator.getInsertionData(insertionContext, breakToInsert, breakAct2Insert, currentRoute, newVehicle, newVehicleDepartureTime, newDriver, bestKnownCosts);
}
/*
check hard constraints at route level
*/

View file

@ -31,6 +31,7 @@ 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.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.ServiceActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.Start;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
@ -97,11 +98,14 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
Service service = (Service) jobToInsert;
int insertionIndex = InsertionData.NO_INDEX;
TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0);
TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0);
insertionContext.getAssociatedActivities().add(deliveryAct2Insert);
return getInsertionData(insertionContext, service, deliveryAct2Insert, currentRoute, newVehicle, newVehicleDepartureTime, newDriver, bestKnownCosts);
}
InsertionData getInsertionData(final JobInsertionContext insertionContext, final Service service, final TourActivity deliveryAct2Insert,
final VehicleRoute currentRoute, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
/*
check hard constraints at route level
*/
@ -117,7 +121,7 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
double bestCost = bestKnownCosts;
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
TimeWindow bestTimeWindow = null;
TimeWindow bestTimeWindow = null;
/*
generate new start and end for new vehicle
@ -129,6 +133,7 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
TourActivity prevAct = start;
double prevActStartTime = newVehicleDepartureTime;
int actIndex = 0;
int insertionIndex = InsertionData.NO_INDEX;
Iterator<TourActivity> activityIterator = currentRoute.getActivities().iterator();
boolean tourEnd = false;
while(!tourEnd){
@ -139,7 +144,7 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
tourEnd = true;
}
boolean not_fulfilled_break = true;
for(TimeWindow timeWindow : service.getTimeWindows()) {
for(TimeWindow timeWindow : service.getTimeWindows()) {
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
ActivityContext activityContext = new ActivityContext();
@ -158,7 +163,7 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
} else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
not_fulfilled_break = false;
}
}
}
if(not_fulfilled_break) break;
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle);
prevActStartTime = Math.max(nextActArrTime, nextAct.getTheoreticalEarliestOperationStartTime()) + activityCosts.getActivityDuration(nextAct,nextActArrTime,newDriver,newVehicle);
@ -178,6 +183,4 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
return insertionData;
}
}

View file

@ -0,0 +1,65 @@
package com.graphhopper.jsprit.core.problem;
import static org.junit.Assert.assertEquals;
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem.FleetSize;
import com.graphhopper.jsprit.core.problem.job.Break;
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.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.VehicleImpl;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl.Builder;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
import com.graphhopper.jsprit.core.util.Solutions;
import org.junit.Test;
public class BreakAssignmentTest {
@Test
public void whenBreakHasFixedLocation_breakActivityHasLocationSpecified() {
VehicleImpl vehicle = Builder.newInstance("vehicle")
.setType(VehicleTypeImpl.Builder.newInstance("vehicleType")
.addCapacityDimension(0, 2)
.build())
.setStartLocation(Location.newInstance(0, 0))
.setBreak(Break.Builder.newInstance("break")
.setTimeWindow(TimeWindow.newInstance(5, 8))
.setLocation(Location.newInstance(6, 0))
.setServiceTime(1)
.build())
.build();
Service service1 = Service.Builder.newInstance("1")
.addSizeDimension(0, 1)
.setLocation(Location.newInstance(5, 0))
.setServiceTime(1)
.build();
Service service2 = Service.Builder.newInstance("2")
.addSizeDimension(0, 1)
.setLocation(Location.newInstance(10, 0))
.setServiceTime(10)
.build();
VehicleRoutingProblem problem = VehicleRoutingProblem.Builder.newInstance()
.addVehicle(vehicle)
.addJob(service1)
.addJob(service2)
.setFleetSize(FleetSize.FINITE)
.build();
Location location = findBreak(Solutions.bestOf(Jsprit.Builder
.newInstance(problem)
.buildAlgorithm().searchSolutions()).getRoutes().iterator().next())
.getLocation();
assertEquals(Location.newInstance(6, 0), location);
}
private BreakActivity findBreak(VehicleRoute route) {
for (TourActivity tourActivity : route.getTourActivities().getActivities()) {
if (tourActivity instanceof BreakActivity)
return (BreakActivity) tourActivity;
}
throw new IllegalStateException("Break activity is not found.");
}
}