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

Drt: streamline constraints and update separation of soft vs hard constraint handling #3652

Open
wants to merge 3 commits 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 @@ -176,8 +176,7 @@ public EmptyVehicleRelocator get() {
getter.getModal(StopTimeCalculator.class), scheduleWaitBeforeDrive)))
.asEagerSingleton();

bindModal(DefaultOfferAcceptor.class).toProvider(modalProvider(getter -> new DefaultOfferAcceptor(
defaultConstraintsSet.maxAllowedPickupDelay)));
bindModal(DefaultOfferAcceptor.class).toProvider(modalProvider(getter -> new DefaultOfferAcceptor()));
bindModal(DrtOfferAcceptor.class).to(modalKey(DefaultOfferAcceptor.class));

bindModal(ScheduleTimingUpdater.class).toProvider(modalProvider(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ public EmptyVehicleRelocator get() {
getter.getModal(StopTimeCalculator.class), scheduleWaitBeforeDrive)))
.asEagerSingleton();

bindModal(DefaultOfferAcceptor.class).toProvider(modalProvider(getter -> new DefaultOfferAcceptor(
defaultOptimizationConstraintsSet.maxAllowedPickupDelay)));
bindModal(DefaultOfferAcceptor.class).toProvider(modalProvider(getter -> new DefaultOfferAcceptor()));
bindModal(DrtOfferAcceptor.class).to(modalKey(DefaultOfferAcceptor.class));

bindModal(ScheduleTimingUpdater.class).toProvider(modalProvider(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/* *********************************************************************** *
* project: org.matsim.*
* *
* *********************************************************************** *
* *
* copyright : (C) 2024 by the members listed in the COPYING, *
* LICENSE and WARRANTY file. *
* email : info at matsim dot org *
* *
* *********************************************************************** *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* See also COPYING, LICENSE and WARRANTY file *
* *
* *********************************************************************** */

package org.matsim.contrib.drt.optimizer.constraints;

/**
Expand All @@ -6,7 +25,17 @@
public record DrtRouteConstraints( //
double maxTravelTime, //
double maxRideTime, //
double maxWaitTime//
double maxWaitTime, //
double maxPickupDelay, //
double lateDiversionThreshold
) {

public final static DrtRouteConstraints UNDEFINED =
new DrtRouteConstraints(
Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY,
0
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package org.matsim.contrib.drt.optimizer.insertion;

import org.matsim.contrib.drt.optimizer.VehicleEntry;
import org.matsim.contrib.drt.optimizer.Waypoint;
import org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.DetourTimeInfo;
import org.matsim.contrib.drt.passenger.DrtRequest;

Expand All @@ -46,6 +48,31 @@ public double calcCost(DrtRequest request, InsertionGenerator.Insertion insertio
return InsertionCostCalculator.INFEASIBLE_SOLUTION_COST;
}

// check if the max riding time constraints is violated (with default config, the max ride duration
// is infinity)
double rideDuration = detourTimeInfo.dropoffDetourInfo.arrivalTime - detourTimeInfo.pickupDetourInfo.departureTime;
if (rideDuration > request.getMaxRideDuration()) {
return InsertionCostCalculator.INFEASIBLE_SOLUTION_COST;
}

if(insertion != null) {

// in case of prebooking, we may have intermediate stay times after pickup
// insertion that may reduce the effective pickup delay that remains that the
// dropoff insertion point
double effectiveDropoffTimeLoss = InsertionDetourTimeCalculator.calculateRemainingPickupTimeLossAtDropoff(
insertion, detourTimeInfo.pickupDetourInfo) + detourTimeInfo.dropoffDetourInfo.dropoffTimeLoss;

double lateDiversionThreshold = request.getLateDiversionThreshold();
if (lateDiversionThreshold > 0) {
if (insertion.vehicleEntry.stops != null && !insertion.vehicleEntry.stops.isEmpty()) {
if (lateDiversionViolation(insertion, detourTimeInfo, insertion.vehicleEntry, effectiveDropoffTimeLoss, lateDiversionThreshold) > 0) {
return InsertionCostCalculator.INFEASIBLE_SOLUTION_COST;
}
}
}
}

return totalTimeLoss;
}
}
Expand All @@ -55,6 +82,8 @@ class DiscourageSoftConstraintViolations implements CostCalculationStrategy {
//XXX however, at the same time prefer max-wait-time to max-travel-time violations
static final double MAX_WAIT_TIME_VIOLATION_PENALTY = 1;// 1 second of penalty per 1 second of late departure
static final double MAX_TRAVEL_TIME_VIOLATION_PENALTY = 10;// 10 seconds of penalty per 1 second of late arrival
static final double MAX_RIDE_TIME_VIOLATION_PENALTY = 10;// 10 seconds of penalty per 1 second of exceeded detour
static final double LATE_DIVERSION_VIOLATION_PENALTY = 10;// 1 second of penalty per 1 second of late diversion of onboard requests

@Override
public double calcCost(DrtRequest request, InsertionGenerator.Insertion insertion,
Expand All @@ -69,9 +98,50 @@ public double calcCost(DrtRequest request, InsertionGenerator.Insertion insertio
double travelTimeViolation = Math.max(0, detourTimeInfo.dropoffDetourInfo.arrivalTime - request.getLatestArrivalTime());
// (if drt vehicle drops off too late) (submission time + alpha * directTravelTime + beta)

return MAX_WAIT_TIME_VIOLATION_PENALTY * waitTimeViolation
double detourViolation = Math.max(0, (detourTimeInfo.dropoffDetourInfo.arrivalTime - detourTimeInfo.pickupDetourInfo.departureTime) - request.getMaxRideDuration());

double lateDiversionViolation = 0;
if(insertion != null) {
// in case of prebooking, we may have intermediate stay times after pickup
// insertion that may reduce the effective pickup delay that remains that the
// dropoff insertion point
double effectiveDropoffTimeLoss = InsertionDetourTimeCalculator.calculateRemainingPickupTimeLossAtDropoff(
insertion, detourTimeInfo.pickupDetourInfo) + detourTimeInfo.dropoffDetourInfo.dropoffTimeLoss;

lateDiversionViolation = lateDiversionViolation(insertion, detourTimeInfo, insertion.vehicleEntry, effectiveDropoffTimeLoss, request.getLateDiversionThreshold());
}

return MAX_WAIT_TIME_VIOLATION_PENALTY * waitTimeViolation
+ MAX_TRAVEL_TIME_VIOLATION_PENALTY * travelTimeViolation
+ MAX_RIDE_TIME_VIOLATION_PENALTY * detourViolation
+ MAX_RIDE_TIME_VIOLATION_PENALTY * lateDiversionViolation
+ totalTimeLoss;
}
}

private static double lateDiversionViolation(InsertionGenerator.Insertion insertion, DetourTimeInfo detourTimeInfo,
VehicleEntry vEntry, double effectiveDropoffTimeLoss, double lateDiversionThreshold) {
double violation = 0;
if (detourTimeInfo.pickupDetourInfo.pickupTimeLoss > 0) {
violation += lateDiversionViolationBetweenStopIndices(vEntry, insertion.pickup.index, insertion.dropoff.index, lateDiversionThreshold);
}
if (effectiveDropoffTimeLoss > 0) {
violation += lateDiversionViolationBetweenStopIndices(vEntry, insertion.dropoff.index, vEntry.stops.size(), lateDiversionThreshold);
}
return violation;
}

private static double lateDiversionViolationBetweenStopIndices(VehicleEntry vehicleEntry, int start, int end, double lateDiversionThreshold) {
double violation = 0;
for (int s = start; s < end; s++) {
Waypoint.Stop stop = vehicleEntry.stops.get(s);
if (!stop.task.getDropoffRequests().isEmpty()) {
double remainingRideDuration = stop.getArrivalTime() - vehicleEntry.start.getDepartureTime();
if (remainingRideDuration < lateDiversionThreshold) {
violation += lateDiversionThreshold - remainingRideDuration;
}
}
}
return violation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ public DefaultInsertionCostCalculator(CostCalculationStrategy costCalculationStr
*/
@Override
public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeInfo detourTimeInfo) {
// check if the max riding time constraints is violated (with default config, the max ride duration
// is infinity)
if (violatesMaxRideDuration(drtRequest, detourTimeInfo)) {
return INFEASIBLE_SOLUTION_COST;
}

var vEntry = insertion.vehicleEntry;

Expand All @@ -73,49 +68,6 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn
return INFEASIBLE_SOLUTION_COST;
}

if (vEntry.stops != null && !vEntry.stops.isEmpty() && constraintsSet.lateDiversionthreshold > 0) {
if(violatesLateDiversion(insertion, detourTimeInfo, vEntry, effectiveDropoffTimeLoss)) {
return INFEASIBLE_SOLUTION_COST;
}
}

return costCalculationStrategy.calcCost(drtRequest, insertion, detourTimeInfo);
}

private boolean violatesMaxRideDuration(DrtRequest drtRequest, InsertionDetourTimeCalculator.DetourTimeInfo detourTimeInfo) {
// Check if the max travel time constraint for the newly inserted request is violated
double rideDuration = detourTimeInfo.dropoffDetourInfo.arrivalTime - detourTimeInfo.pickupDetourInfo.departureTime;
return drtRequest.getMaxRideDuration() < rideDuration;
}

private boolean violatesLateDiversion(Insertion insertion, DetourTimeInfo detourTimeInfo,
VehicleEntry vEntry, double effectiveDropoffTimeLoss) {
if (detourTimeInfo.pickupDetourInfo.pickupTimeLoss > 0) {
if (violatesLateDiversionBetweenStopIndices(vEntry, insertion.pickup.index, insertion.dropoff.index,
constraintsSet.lateDiversionthreshold)) {
return true;
}
}
if (effectiveDropoffTimeLoss > 0) {
if (violatesLateDiversionBetweenStopIndices(vEntry, insertion.dropoff.index, vEntry.stops.size(),
constraintsSet.lateDiversionthreshold)) {
return true;
}
}
return false;
}

private boolean violatesLateDiversionBetweenStopIndices(VehicleEntry vehicleEntry, int start, int end, double lateDiversionThreshold) {
for (int s = start; s < end; s++) {
Waypoint.Stop stop = vehicleEntry.stops.get(s);
if (!stop.task.getDropoffRequests().isEmpty()) {
double remainingRideDuration = stop.getArrivalTime() - vehicleEntry.start.getDepartureTime();
if (remainingRideDuration < lateDiversionThreshold) {
return true;
}
break;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
/*
* *********************************************************************** *
* project: org.matsim.*
* *********************************************************************** *
* *
* copyright : (C) 2021 by the members listed in the COPYING, *
* LICENSE and WARRANTY file. *
* email : info at matsim dot org *
* *
* *********************************************************************** *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* See also COPYING, LICENSE and WARRANTY file *
* *
* *********************************************************************** *
*/
package org.matsim.contrib.drt.passenger;

import java.util.Optional;

public class DefaultOfferAcceptor implements DrtOfferAcceptor{
private final double maxAllowedPickupDelay;

/**
* Generate Default offer acceptor with max allowed pickup delay.
* @param maxAllowedPickupDelay: maximum allowed delay since the initially assigned pickup time.
*/
public DefaultOfferAcceptor(double maxAllowedPickupDelay) {
this.maxAllowedPickupDelay = maxAllowedPickupDelay;
}

/**
* Generate Default offer acceptor.
*/
public DefaultOfferAcceptor() {
this.maxAllowedPickupDelay = Double.POSITIVE_INFINITY;
}

@Override
public Optional<AcceptedDrtRequest> acceptDrtOffer(DrtRequest request, double departureTime, double arrivalTime) {
double updatedLatestStartTime = Math.min(departureTime
+ maxAllowedPickupDelay, request.getLatestStartTime());
+ request.getMaxPickupDelay(), request.getLatestStartTime());
return Optional.of(AcceptedDrtRequest
.newBuilder()
.request(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class DrtRequest implements PassengerRequest {
private final double latestStartTime;
private final double latestArrivalTime;
private final double maxRideDuration;
private final double maxPickupDelay;
private final double lateDiversionThreshold;

private final List<Id<Person>> passengerIds = new ArrayList<>();
private final String mode;
Expand All @@ -58,6 +60,8 @@ private DrtRequest(Builder builder) {
mode = builder.mode;
fromLink = builder.fromLink;
toLink = builder.toLink;
maxPickupDelay = builder.maxPickupDelay;
lateDiversionThreshold = builder.lateDiversionThreshold;
}

public static Builder newBuilder() {
Expand All @@ -76,6 +80,8 @@ public static Builder newBuilder(DrtRequest copy) {
builder.mode = copy.getMode();
builder.fromLink = copy.getFromLink();
builder.toLink = copy.getToLink();
builder.maxPickupDelay = copy.getMaxPickupDelay();
builder.lateDiversionThreshold = copy.getLateDiversionThreshold();
return builder;
}

Expand Down Expand Up @@ -107,6 +113,10 @@ public double getMaxRideDuration() {
return maxRideDuration;
}

public double getMaxPickupDelay() {return maxPickupDelay;}

public double getLateDiversionThreshold() {return lateDiversionThreshold;}

@Override
public Link getFromLink() {
return fromLink;
Expand Down Expand Up @@ -155,6 +165,8 @@ public static final class Builder {
private double latestStartTime;
private double latestArrivalTime;
private double maxRideDuration;
private double maxPickupDelay;
private double lateDiversionThreshold;
private List<Id<Person>> passengerIds = new ArrayList<>();
private String mode;
private Link fromLink;
Expand Down Expand Up @@ -193,6 +205,16 @@ public Builder maxRideDuration(double maxRideDuration) {
return this;
}

public Builder maxPickupDelay(double maxPickupDelay) {
this.maxPickupDelay = maxPickupDelay;
return this;
}

public Builder lateDiversionThreshold(double lateDiversionThreshold) {
this.lateDiversionThreshold = lateDiversionThreshold;
return this;
}

public Builder passengerIds(List<Id<Person>> val) {
passengerIds = new ArrayList<>(val);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Route;
import org.matsim.contrib.drt.optimizer.constraints.DrtOptimizationConstraintsSet;
import org.matsim.contrib.drt.optimizer.constraints.DrtRouteConstraints;
import org.matsim.contrib.drt.passenger.events.DrtRequestSubmittedEvent;
import org.matsim.contrib.drt.routing.DrtRoute;
import org.matsim.contrib.dvrp.optimizer.Request;
Expand All @@ -41,18 +43,21 @@ public class DrtRequestCreator implements PassengerRequestCreator {
private final String mode;
private final EventsManager eventsManager;

public DrtRequestCreator(String mode, EventsManager eventsManager) {
public DrtRequestCreator(String mode, EventsManager eventsManager) {
this.mode = mode;
this.eventsManager = eventsManager;
}
}

@Override
public DrtRequest createRequest(Id<Request> id, List<Id<Person>> passengerIds, Route route, Link fromLink, Link toLink,
double departureTime, double submissionTime) {
DrtRoute drtRoute = (DrtRoute)route;
double latestDepartureTime = departureTime + drtRoute.getMaxWaitTime();
double latestArrivalTime = departureTime + drtRoute.getTravelTime().seconds();
double maxRideDuration = drtRoute.getMaxRideTime();
DrtRouteConstraints constraints = drtRoute.getConstraints();
double latestDepartureTime = departureTime + constraints.maxWaitTime();
double latestArrivalTime = departureTime + constraints.maxTravelTime();
double maxRideDuration = constraints.maxRideTime();
double maxPickupDelay = constraints.maxPickupDelay();
double lateDiversionThreshold = constraints.lateDiversionThreshold();

eventsManager.processEvent(
new DrtRequestSubmittedEvent(submissionTime, mode, id, passengerIds, fromLink.getId(), toLink.getId(),
Expand All @@ -68,6 +73,8 @@ public DrtRequest createRequest(Id<Request> id, List<Id<Person>> passengerIds, R
.latestStartTime(latestDepartureTime)
.latestArrivalTime(latestArrivalTime)
.maxRideDuration(maxRideDuration)
.maxPickupDelay(maxPickupDelay)
.lateDiversionThreshold(lateDiversionThreshold)
.submissionTime(submissionTime)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ public DrtRouteConstraints calculateRouteConstraints(double departureTime, Link
double maxDetour = Math.max(defaultSet.minimumAllowedDetour, unsharedRideTime * (defaultSet.maxDetourAlpha -1) + defaultSet.maxDetourBeta);
double maxRideTime = unsharedRideTime + Math.min(defaultSet.maxAbsoluteDetour, maxDetour);
double maxWaitTime = constraintsSet.maxWaitTime;

return new DrtRouteConstraints(maxTravelTime, maxRideTime, maxWaitTime);
return new DrtRouteConstraints(maxTravelTime, maxRideTime, maxWaitTime, constraintsSet.maxAllowedPickupDelay, constraintsSet.lateDiversionthreshold);
} else {
throw new IllegalArgumentException("Constraint set is not a default set");
}
Expand Down
Loading