Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Vehicle's break location is ignored #439 #440

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -78,6 +80,7 @@ public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, Vehic
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
this.activityFactory = activityFactory;
this.serviceInsertionCalculator = new ServiceInsertionCalculator(routingCosts, activityCosts, additionalTransportCostsCalculator, constraintManager, activityFactory);
logger.debug("initialise " + this);
}

Expand Down Expand Up @@ -105,6 +108,11 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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;
Expand Down Expand Up @@ -97,11 +98,14 @@ public String toString() {
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
*/
Expand All @@ -117,7 +121,7 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job

double bestCost = bestKnownCosts;
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
TimeWindow bestTimeWindow = null;
TimeWindow bestTimeWindow = null;

/*
generate new start and end for new vehicle
Expand All @@ -129,6 +133,7 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
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){
Expand All @@ -139,7 +144,7 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
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();
Expand All @@ -158,7 +163,7 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
} 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);
Expand All @@ -178,6 +183,4 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
return insertionData;
}


}
Original file line number Diff line number Diff line change
@@ -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.");
}
}