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

feat: customizable distance calculators for drt constraints #2971

Merged
merged 1 commit into from
Nov 30, 2023
Merged
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 @@ -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
Loading