Skip to content

Commit

Permalink
feat: customizable distance calculatorsfor drt constraints (#2971)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebhoerl authored Nov 30, 2023
1 parent b63fa32 commit 38ad994
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
import org.matsim.contrib.drt.extension.insertion.constraints.SkillsConstraint.VehicleSkillsSupplier;
import org.matsim.contrib.drt.extension.insertion.constraints.VehicleRangeConstraint;
import org.matsim.contrib.drt.extension.insertion.constraints.VehicleRangeConstraint.VehicleRangeSupplier;
import org.matsim.contrib.drt.extension.insertion.distances.ApproximateDistanceCalculator;
import org.matsim.contrib.drt.extension.insertion.distances.DistanceApproximator;
import org.matsim.contrib.drt.extension.insertion.distances.DistanceCalculator;
import org.matsim.contrib.drt.extension.insertion.distances.EuclideanDistanceApproximator;
import org.matsim.contrib.drt.extension.insertion.distances.RoutingDistanceCalculator;
import org.matsim.contrib.drt.extension.insertion.objectives.PassengerDelayObjective;
import org.matsim.contrib.drt.extension.insertion.objectives.VehicleActiveTimeObjective;
Expand Down Expand Up @@ -173,10 +174,93 @@ public DrtInsertionModule withConstraint(DrtInsertionConstraint constraint) {
return this;
}

// DISTANCES

private DistanceCalculator distanceCalculator;
private DistanceApproximator distanceApproximator;

private Class<? extends DistanceCalculator> distanceCalculatorClass;
private Class<? extends DistanceApproximator> distanceApproximatorClass;

public DrtInsertionModule withDistanceCalculator(DistanceCalculator distanceCalculator) {
Preconditions.checkState(this.distanceCalculator == null && this.distanceCalculatorClass == null);
this.distanceCalculator = distanceCalculator;
return this;
}

public DrtInsertionModule withDistanceCalculator(Class<? extends DistanceCalculator> distanceCalculatorClass) {
Preconditions.checkState(this.distanceCalculator == null && this.distanceCalculatorClass == null);
this.distanceCalculatorClass = distanceCalculatorClass;
return this;
}

public DrtInsertionModule withDistanceApproximator(DistanceApproximator distanceApproximator) {
Preconditions.checkState(this.distanceApproximator == null && this.distanceApproximatorClass == null);
this.distanceApproximator = distanceApproximator;
return this;
}

public DrtInsertionModule withDistanceApproximator(
Class<? extends DistanceApproximator> distanceApproximatorClass) {
Preconditions.checkState(this.distanceApproximator == null && this.distanceApproximatorClass == null);
this.distanceApproximatorClass = distanceApproximatorClass;
return this;
}

public DrtInsertionModule withEuclideanDistanceApproximator(double euclideanDistanceFactor) {
Preconditions.checkState(this.distanceApproximator == null && this.distanceApproximatorClass == null);
this.distanceApproximator = new EuclideanDistanceApproximator(euclideanDistanceFactor);
return this;
}

public DrtInsertionModule withEuclideanDistanceCalculator(double euclideanDistanceFactor) {
Preconditions.checkState(this.distanceCalculator == null && this.distanceCalculatorClass == null);
this.distanceCalculator = new EuclideanDistanceApproximator(euclideanDistanceFactor);
return this;
}

private void configureDistances() {
bindModal(RoutingDistanceCalculator.class).toProvider(modalProvider(getter -> {
LeastCostPathCalculatorFactory factory = new SpeedyALTFactory();

TravelTime travelTime = getter.getModal(TravelTime.class);
TravelDisutility travelDisutility = new OnlyTimeDependentTravelDisutility(travelTime);
Network network = getter.getModal(Network.class);

printDistanceWarning();

return new RoutingDistanceCalculator(factory.createPathCalculator(network, travelDisutility, travelTime),
travelTime);
}));

if (distanceCalculator == null && distanceCalculatorClass == null) {
distanceCalculatorClass = RoutingDistanceCalculator.class;
}

if (distanceApproximator == null && distanceApproximatorClass == null) {
distanceApproximator = DistanceApproximator.NULL;
}

if (distanceCalculator != null) {
bindModal(DistanceCalculator.class).toInstance(distanceCalculator);
}

if (distanceCalculatorClass != null) {
bindModal(DistanceCalculator.class).to(modalKey(distanceCalculatorClass));
}

if (distanceApproximator != null) {
bindModal(DistanceApproximator.class).toInstance(distanceApproximator);
}

if (distanceApproximatorClass != null) {
bindModal(DistanceApproximator.class).to(modalKey(distanceApproximatorClass));
}
}

// RANGE CONSTRAINT

private boolean useRangeConstraint = false;
private double rangeEstimationFactor = Double.NaN;

private VehicleRangeSupplier vehicleRangeSupplier;
private Class<? extends VehicleRangeSupplier> vehicleRangeSupplierClass;
Expand All @@ -200,11 +284,6 @@ public DrtInsertionModule withVehicleRange(Class<? extends VehicleRangeSupplier>
return this;
}

public DrtInsertionModule withRangeEstimationFactor(double rangeEstimationFactor) {
this.rangeEstimationFactor = rangeEstimationFactor;
return this;
}

private void configureRangeContraint(List<Key<? extends DrtInsertionConstraint>> constraintBindings) {
if (useRangeConstraint) {
if (vehicleRangeSupplier != null) {
Expand All @@ -216,10 +295,12 @@ private void configureRangeContraint(List<Key<? extends DrtInsertionConstraint>>
}

bindModal(VehicleRangeConstraint.class).toProvider(modalProvider(getter -> {
DistanceCalculator distanceCalculator = getter.getModal(RoutingDistanceCalculator.class);
DistanceCalculator distanceApproximator = Double.isFinite(rangeEstimationFactor)
? new ApproximateDistanceCalculator(rangeEstimationFactor)
: null;
DistanceCalculator distanceCalculator = getter.getModal(DistanceCalculator.class);
DistanceApproximator distanceApproximator = getter.getModal(DistanceApproximator.class);

if (distanceApproximator == DistanceApproximator.NULL) {
distanceApproximator = null;
}

return new VehicleRangeConstraint(vehicleRangeSupplier, distanceCalculator, distanceApproximator);
}));
Expand Down Expand Up @@ -362,7 +443,7 @@ private void configureVehicleDistanceObjective() {
final DistanceCalculator distanceCalculator;

if (Double.isFinite(distanceObjectiveEstimationFactor)) {
distanceCalculator = new ApproximateDistanceCalculator(distanceObjectiveEstimationFactor);
distanceCalculator = new EuclideanDistanceApproximator(distanceObjectiveEstimationFactor);
} else {
distanceCalculator = getter.getModal(RoutingDistanceCalculator.class);
}
Expand All @@ -373,6 +454,8 @@ private void configureVehicleDistanceObjective() {

@Override
protected void configureQSim() {
configureDistances();

List<Key<? extends DrtInsertionConstraint>> constraintBindings = new LinkedList<>();
configureExclusivityConstraint(constraintBindings);
configureSingleRequestConstraint(constraintBindings);
Expand Down Expand Up @@ -424,19 +507,6 @@ protected void configureQSim() {

bindModal(CostCalculationStrategy.class).to(modalKey(ConfigurableCostCalculatorStrategy.class));
bindModal(DrtOfferAcceptor.class).to(modalKey(PromisedTimeWindowOfferAcceptor.class));

bindModal(RoutingDistanceCalculator.class).toProvider(modalProvider(getter -> {
LeastCostPathCalculatorFactory factory = new SpeedyALTFactory();

TravelTime travelTime = getter.getModal(TravelTime.class);
TravelDisutility travelDisutility = new OnlyTimeDependentTravelDisutility(travelTime);
Network network = getter.getModal(Network.class);

printDistanceWarning();

return new RoutingDistanceCalculator(factory.createPathCalculator(network, travelDisutility, travelTime),
travelTime);
}));
}

private final static Logger logger = LogManager.getLogger(DrtInsertionModule.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import javax.annotation.Nullable;

import org.matsim.contrib.drt.extension.insertion.DrtInsertionConstraint;
import org.matsim.contrib.drt.extension.insertion.distances.DistanceApproximator;
import org.matsim.contrib.drt.extension.insertion.distances.DistanceCalculator;
import org.matsim.contrib.drt.extension.insertion.distances.InsertionDistanceCalculator;
import org.matsim.contrib.drt.extension.insertion.distances.InsertionDistanceCalculator.VehicleDistance;
Expand All @@ -16,10 +17,10 @@ public class VehicleRangeConstraint implements DrtInsertionConstraint {

private final VehicleRangeSupplier rangeSupplier;
private final DistanceCalculator distanceCalculator;
private final DistanceCalculator distanceApproximator;
private final DistanceApproximator distanceApproximator;

public VehicleRangeConstraint(VehicleRangeSupplier rangeSupplier, DistanceCalculator distanceEstimator,
@Nullable DistanceCalculator distanceApproximator) {
@Nullable DistanceApproximator distanceApproximator) {
this.rangeSupplier = rangeSupplier;
this.distanceCalculator = distanceEstimator;
this.distanceApproximator = distanceApproximator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.matsim.contrib.drt.extension.insertion.distances;

public interface DistanceApproximator extends DistanceCalculator {
static public DistanceApproximator NULL = (departureTime, fromLink, toLink) -> {
throw new IllegalStateException(
"The NULL DistanceApproximator is only used as a tag for not using any approximation.");
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
import org.matsim.api.core.v01.network.Link;

public interface DistanceCalculator {
double estimateDistance(double departureTime, Link fromLink, Link toLink);
double calculateDistance(double departureTime, Link fromLink, Link toLink);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import org.matsim.api.core.v01.network.Link;
import org.matsim.core.utils.geometry.CoordUtils;

public class ApproximateDistanceCalculator implements DistanceCalculator {
public class EuclideanDistanceApproximator implements DistanceApproximator {
private final double distanceEstimationFactor;

public ApproximateDistanceCalculator(double distanceEstimationFactor) {
public EuclideanDistanceApproximator(double distanceEstimationFactor) {
this.distanceEstimationFactor = distanceEstimationFactor;
}

@Override
public double estimateDistance(double departureTime, Link fromLink, Link toLink) {
public double calculateDistance(double departureTime, Link fromLink, Link toLink) {
return distanceEstimationFactor
* CoordUtils.calcEuclideanDistance(fromLink.getFromNode().getCoord(), toLink.getFromNode().getCoord());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ public VehicleDistance calculateInsertionDistance(Insertion insertion, DetourTim
int beforePickupOccupancy = insertion.pickup.previousWaypoint.getOutgoingOccupancy();

double beforePickupDistance = distanceEstimator
.estimateDistance(insertion.pickup.previousWaypoint.getDepartureTime(), pickupFromLink, pickupNewLink);
.calculateDistance(insertion.pickup.previousWaypoint.getDepartureTime(), pickupFromLink, pickupNewLink);

double afterPickupDistance = distanceEstimator.estimateDistance(detourTimeInfo.pickupDetourInfo.departureTime,
double afterPickupDistance = distanceEstimator.calculateDistance(detourTimeInfo.pickupDetourInfo.departureTime,
pickupNewLink, pickupToLink);

addedDistances.add(new DistanceEntry(beforePickupDistance, beforePickupOccupancy));
Expand Down Expand Up @@ -128,15 +128,15 @@ public VehicleDistance calculateInsertionDistance(Insertion insertion, DetourTim
final int beforeDropoffOccupancy;
if (insertion.dropoff.index > insertion.pickup.index) {
beforeDropoffOccupancy = insertion.dropoff.previousWaypoint.getOutgoingOccupancy() + 1;
double beforeDropoffDistance = distanceEstimator.estimateDistance(
double beforeDropoffDistance = distanceEstimator.calculateDistance(
insertion.dropoff.previousWaypoint.getDepartureTime(), dropoffFromLink, dropoffNewLink);

addedDistances.add(new DistanceEntry(beforeDropoffDistance, beforeDropoffOccupancy));
} else {
beforeDropoffOccupancy = beforePickupOccupancy + 1;
}

double afterDropoffDistance = distanceEstimator.estimateDistance(detourTimeInfo.dropoffDetourInfo.arrivalTime,
double afterDropoffDistance = distanceEstimator.calculateDistance(detourTimeInfo.dropoffDetourInfo.arrivalTime,
dropoffNewLink, dropoffToLink);
addedDistances.add(new DistanceEntry(afterDropoffDistance, beforeDropoffOccupancy - 1));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public RoutingDistanceCalculator(LeastCostPathCalculator router, TravelTime trav
// set this up in a more intelligent way, I'm not sure, but I guess that the
// constraints are accesses in parallel by DRT. /sh nov'23
@Override
public synchronized double estimateDistance(double departureTime, Link fromLink, Link toLink) {
public synchronized double calculateDistance(double departureTime, Link fromLink, Link toLink) {
VrpPathWithTravelData path = VrpPaths.calcAndCreatePath(fromLink, toLink, departureTime, router, travelTime);
return VrpPaths.calcDistance(path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import org.matsim.api.core.v01.IdSet;
import org.matsim.api.core.v01.events.LinkEnterEvent;
import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.extension.insertion.distances.DistanceApproximator;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.run.DrtControlerCreator;
import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup;
Expand All @@ -33,6 +35,7 @@
import org.matsim.contrib.dvrp.passenger.PassengerRequestSubmittedEventHandler;
import org.matsim.contrib.dvrp.passenger.PassengerWaitingEvent;
import org.matsim.contrib.dvrp.passenger.PassengerWaitingEventHandler;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule;
import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
import org.matsim.contrib.dvrp.vrpagent.TaskEndedEvent;
import org.matsim.contrib.dvrp.vrpagent.TaskEndedEventHandler;
Expand All @@ -41,6 +44,7 @@
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting;
import org.matsim.core.utils.geometry.CoordUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.examples.ExamplesUtils;
import org.matsim.testcases.MatsimTestUtils;
Expand Down Expand Up @@ -254,6 +258,86 @@ public void testRangeConstraint() {
}
}

@Test
public void testRangeConstraintWithCustomInstances() {
Controler controller = createController();
DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(controller.getConfig());

CustomCalculator distanceCalculator = new CustomCalculator();
CustomCalculator distanceApproximator = new CustomCalculator();

DrtInsertionModule insertionModule = new DrtInsertionModule(drtConfig) //
.withVehicleRange(100.0 * 1e3) //
.withDistanceCalculator(distanceCalculator) //
.withDistanceApproximator(distanceApproximator);

controller.addOverridingQSimModule(insertionModule);

DistanceHandler handler = new DistanceHandler(controller.getScenario().getNetwork());
handler.install(controller);

controller.run();

for (var item : handler.distances.entrySet()) {
assertTrue(item.getValue() < 100.0 * 1e3);
}

assertEquals(1470, distanceCalculator.calculatedDistances);
assertEquals(5288, distanceApproximator.calculatedDistances);
}

@Test
public void testRangeConstraintWithCustomInjection() {
Controler controller = createController();
DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(controller.getConfig());

CustomDistanceCalculator distanceCalculator = new CustomDistanceCalculator();
CustomDistanceApproximator distanceApproximator = new CustomDistanceApproximator();

DrtInsertionModule insertionModule = new DrtInsertionModule(drtConfig) //
.withVehicleRange(100.0 * 1e3) //
.withDistanceCalculator(CustomDistanceCalculator.class) //
.withDistanceApproximator(CustomDistanceApproximator.class);

controller.addOverridingQSimModule(insertionModule);

controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule("drt") {
@Override
protected void configureQSim() {
bindModal(CustomDistanceCalculator.class).toInstance(distanceCalculator);
bindModal(CustomDistanceApproximator.class).toInstance(distanceApproximator);
}
});

DistanceHandler handler = new DistanceHandler(controller.getScenario().getNetwork());
handler.install(controller);

controller.run();

for (var item : handler.distances.entrySet()) {
assertTrue(item.getValue() < 100.0 * 1e3);
}

assertEquals(1470, distanceCalculator.calculatedDistances);
assertEquals(5288, distanceApproximator.calculatedDistances);
}

static class CustomDistanceCalculator extends CustomCalculator {
}

static class CustomDistanceApproximator extends CustomCalculator {
}

static class CustomCalculator implements DistanceApproximator {
int calculatedDistances = 0;

@Override
public synchronized double calculateDistance(double departureTime, Link fromLink, Link toLink) {
calculatedDistances++;
return CoordUtils.calcEuclideanDistance(fromLink.getCoord(), toLink.getCoord());
}
}

static public class DistanceHandler implements LinkEnterEventHandler {
private final Network network;
private final IdMap<Vehicle, Double> distances = new IdMap<>(Vehicle.class);
Expand Down

0 comments on commit 38ad994

Please sign in to comment.