Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS, vrp.getActivityCosts()));
stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
stateManager.addStateUpdater(new UpdateFutureWaitingTimes(stateManager, vrp.getTransportCosts()));

stateManager.addStateUpdater(new UpdateVehicleDependentTimes(vrp.getTransportCosts(), vrp.getActivityCosts(), stateManager, vrp.getVehicles()));
stateManager.addStateUpdater(new UpdateVehicleDependentFutureWaitingTimes(stateManager, vrp.getVehicles()));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListener;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
Expand Down Expand Up @@ -289,12 +290,18 @@ public List<AbstractActivity> createActivities(Job job) {
};
ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(),actInsertionCalc, constraintManager);
shipmentInsertion.setJobActivityFactory(activityFactory);
shipmentInsertion.setStateManager((StateManager) statesManager);

ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), actInsertionCalc, constraintManager);
serviceInsertion.setJobActivityFactory(activityFactory);
serviceInsertion.setStateManager((StateManager) statesManager);

BreakInsertionCalculator breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), actInsertionCalc, constraintManager);
breakInsertionCalculator.setJobActivityFactory(activityFactory);

shipmentInsertion.setBreakInsertionCalculator(breakInsertionCalculator);
serviceInsertion.setBreakInsertionCalculator(breakInsertionCalculator);

JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
switcher.put(Shipment.class, shipmentInsertion);
switcher.put(Service.class, serviceInsertion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package com.graphhopper.jsprit.core.algorithm.recreate;

import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
Expand All @@ -25,15 +27,11 @@
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.*;
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.Start;
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.solution.route.activity.*;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -71,6 +69,10 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {

private ConstraintManager constraintManager;

private StateManager stateManager;

private BreakInsertionCalculator breakInsertionCalculator;

public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
super();
this.transportCosts = routingCosts;
Expand All @@ -87,6 +89,14 @@ public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
this.activityFactory = jobActivityFactory;
}

public void setStateManager(StateManager stateManager) {
this.stateManager = stateManager;
}

public void setBreakInsertionCalculator(BreakInsertionCalculator breakInsertionCalculator) {
this.breakInsertionCalculator = breakInsertionCalculator;
}

@Override
public String toString() {
return "[name=calculatesServiceInsertion]";
Expand Down Expand Up @@ -149,6 +159,58 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
activityContext.setInsertionIndex(actIndex);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager);

// check if new vehicle has break
Break aBreak = newVehicle.getBreak();
if (aBreak != null) {
// check if break has been inserted
if (!currentRoute.getTourActivities().servesJob(aBreak)) {
// get new route end time before insertion of newAct
Double routeEndTime = stateManager.getRouteState(currentRoute, newVehicle, InternalStates.END_TIME, Double.class);
if (routeEndTime == null) routeEndTime = newVehicle.getEarliestDeparture();
// get future waiting of nextAct in the new route
Double futureWaiting = stateManager.getActivityState(nextAct, newVehicle, InternalStates.FUTURE_WAITING, Double.class);
if (futureWaiting == null) futureWaiting = 0.;
// get nextAct end time delay after insertion of newAct in the new route
double newActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), deliveryAct2Insert.getLocation(), prevActStartTime, newDriver, newVehicle);
double newActEndTime = Math.max(deliveryAct2Insert.getTheoreticalEarliestOperationStartTime(), newActArrTime) + activityCosts.getActivityDuration(deliveryAct2Insert, newActArrTime, newDriver, newVehicle);
double nextActArrTime = newActEndTime + transportCosts.getTransportTime(deliveryAct2Insert.getLocation(), nextAct.getLocation(), newActEndTime, newDriver, newVehicle);
double nextActEndTime = Math.max(nextAct.getTheoreticalEarliestOperationStartTime(), nextActArrTime) + activityCosts.getActivityDuration(nextAct, nextActArrTime, newDriver, newVehicle);
Double nextActEndTimeOld = stateManager.getActivityState(nextAct, newVehicle, InternalStates.END_TIME, Double.class);
if (nextActEndTimeOld == null) nextActEndTimeOld = routeEndTime;
double nextActEndTimeDelay = Math.max(0., nextActEndTime - nextActEndTimeOld);
// get new route end time after insertion of newAct
double routeEndTimeNew = routeEndTime + Math.max(0., nextActEndTimeDelay - futureWaiting);
// check if new route end time later than break time window
if (routeEndTimeNew > aBreak.getTimeWindow().getEnd()) {
VehicleRoute.Builder routeBuilder = VehicleRoute.Builder.newInstance(newVehicle, newDriver);
routeBuilder.setJobActivityFactory(activityFactory);
for (int tourActIndex = 0; tourActIndex < currentRoute.getActivities().size(); tourActIndex++) {
if (tourActIndex == actIndex) {
addJobActToRouteBuilder(routeBuilder, jobToInsert, deliveryAct2Insert);
}
TourActivity tourActivity = currentRoute.getActivities().get(tourActIndex);
if (tourActivity instanceof TourActivity.JobActivity) {
addJobActToRouteBuilder(routeBuilder, ((TourActivity.JobActivity) tourActivity).getJob(), tourActivity);
}
}
if (actIndex == currentRoute.getActivities().size()) {
addJobActToRouteBuilder(routeBuilder, jobToInsert, deliveryAct2Insert);
}
routeBuilder.setDepartureTime(newVehicleDepartureTime);
VehicleRoute route = routeBuilder.build();
stateManager.reCalculateStates(route);
// check if break can be inserted
InsertionData iData = breakInsertionCalculator.getInsertionData(route, aBreak, newVehicle, newVehicleDepartureTime, newDriver, Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
status = ConstraintsStatus.NOT_FULFILLED;
}
if (!currentRoute.isEmpty())
stateManager.reCalculateStates(currentRoute);
}
}
}

if (status.equals(ConstraintsStatus.FULFILLED)) {
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
Expand Down Expand Up @@ -182,5 +244,24 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
return insertionData;
}


private void addJobActToRouteBuilder(VehicleRoute.Builder routeBuilder, Job job, TourActivity tourActivity) {
if (job instanceof Pickup)
routeBuilder.addPickup((Pickup) job);
else if (job instanceof Delivery)
routeBuilder.addDelivery((Delivery) job);
else if (job instanceof Service)
routeBuilder.addService((Service) job);
else if (job instanceof Break)
routeBuilder.addBreak((Break) job);
else if (job instanceof Shipment) {
if (tourActivity instanceof PickupShipment)
routeBuilder.addPickup((Shipment) job);
else if (tourActivity instanceof DeliverShipment)
routeBuilder.addDelivery((Shipment) job);
else
throw new IllegalStateException("tourActivity " + tourActivity.getName());
}
else
throw new IllegalStateException("job " + job.getName());
}
}
Loading