diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionModule.java index 9408dcfd067..23ad52f4e80 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionModule.java @@ -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; @@ -173,10 +174,93 @@ public DrtInsertionModule withConstraint(DrtInsertionConstraint constraint) { return this; } + // DISTANCES + + private DistanceCalculator distanceCalculator; + private DistanceApproximator distanceApproximator; + + private Class distanceCalculatorClass; + private Class distanceApproximatorClass; + + public DrtInsertionModule withDistanceCalculator(DistanceCalculator distanceCalculator) { + Preconditions.checkState(this.distanceCalculator == null && this.distanceCalculatorClass == null); + this.distanceCalculator = distanceCalculator; + return this; + } + + public DrtInsertionModule withDistanceCalculator(Class 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 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 vehicleRangeSupplierClass; @@ -200,11 +284,6 @@ public DrtInsertionModule withVehicleRange(Class return this; } - public DrtInsertionModule withRangeEstimationFactor(double rangeEstimationFactor) { - this.rangeEstimationFactor = rangeEstimationFactor; - return this; - } - private void configureRangeContraint(List> constraintBindings) { if (useRangeConstraint) { if (vehicleRangeSupplier != null) { @@ -216,10 +295,12 @@ private void configureRangeContraint(List> } 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); })); @@ -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); } @@ -373,6 +454,8 @@ private void configureVehicleDistanceObjective() { @Override protected void configureQSim() { + configureDistances(); + List> constraintBindings = new LinkedList<>(); configureExclusivityConstraint(constraintBindings); configureSingleRequestConstraint(constraintBindings); @@ -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); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/constraints/VehicleRangeConstraint.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/constraints/VehicleRangeConstraint.java index decf605d71a..649a68fd189 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/constraints/VehicleRangeConstraint.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/constraints/VehicleRangeConstraint.java @@ -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; @@ -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; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceApproximator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceApproximator.java new file mode 100644 index 00000000000..bae08f00040 --- /dev/null +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceApproximator.java @@ -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."); + }; +} diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceCalculator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceCalculator.java index ff4943e6a4e..cc74978ac34 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceCalculator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/DistanceCalculator.java @@ -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); } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/ApproximateDistanceCalculator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/EuclideanDistanceApproximator.java similarity index 66% rename from contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/ApproximateDistanceCalculator.java rename to contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/EuclideanDistanceApproximator.java index 3d2893936d8..9f8c5c4556e 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/ApproximateDistanceCalculator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/EuclideanDistanceApproximator.java @@ -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()); } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/InsertionDistanceCalculator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/InsertionDistanceCalculator.java index 60e5642746e..01a6c91bf20 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/InsertionDistanceCalculator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/InsertionDistanceCalculator.java @@ -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)); @@ -128,7 +128,7 @@ 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)); @@ -136,7 +136,7 @@ public VehicleDistance calculateInsertionDistance(Insertion insertion, DetourTim 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)); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/RoutingDistanceCalculator.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/RoutingDistanceCalculator.java index 31ec3a55e06..cf74ff360a1 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/RoutingDistanceCalculator.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/insertion/distances/RoutingDistanceCalculator.java @@ -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); } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionExtensionIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionExtensionIT.java index 3740da65f35..001bae2a1e7 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionExtensionIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/insertion/DrtInsertionExtensionIT.java @@ -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; @@ -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; @@ -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; @@ -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 distances = new IdMap<>(Vehicle.class);