Skip to content

Commit

Permalink
improve performance of calcTreeObservable
Browse files Browse the repository at this point in the history
- again only observe optimized connections, and not every single individual arrivals at a stop.
- as we already step through each departure time, make sure no later departures are taken in each sub-query
- restructure code a bit, integrate settings into RaptorParameters
  • Loading branch information
mrieser committed May 20, 2024
1 parent fab1ed6 commit f8f5f9f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class RaptorParameters {
* it is compared to the pt generalized cost.
* Set to a very high value to reduce direct walk results.
*/
private double directWalkFactor = 1.0;
private double directWalkFactor = 1.0;

private double beelineWalkSpeed; // meter / second

Expand All @@ -65,11 +65,14 @@ public class RaptorParameters {
private double transferPenaltyPerTravelTimeHour = 0.0;
private double transferPenaltyMinimum = Double.NEGATIVE_INFINITY;
private double transferPenaltyMaximum = Double.POSITIVE_INFINITY;

private boolean useTransportModeUtilities = false;

private final SwissRailRaptorConfigGroup config;

private int maxTransfers = Integer.MAX_VALUE;
private boolean exactDeparturesOnly = false;

public RaptorParameters(SwissRailRaptorConfigGroup config) {
this.config = config;
}
Expand Down Expand Up @@ -161,13 +164,28 @@ public double getTransferPenaltyMaximum() {
public void setTransferPenaltyMaximum(double transferPenaltyMaximum) {
this.transferPenaltyMaximum = transferPenaltyMaximum;
}

public boolean isUseTransportModeUtilities() {
return useTransportModeUtilities;
}

public void setUseTransportModeUtilities(boolean useTransportModeUtilities) {
this.useTransportModeUtilities = useTransportModeUtilities;
}

int getMaxTransfers() {
return this.maxTransfers;
}

public void setMaxTransfers(int maxTransfers) {
this.maxTransfers = maxTransfers;
}

boolean isExactDeparturesOnly() {
return this.exactDeparturesOnly;
}

void setExactDeparturesOnly(boolean exactDeparturesOnly) {
this.exactDeparturesOnly = exactDeparturesOnly;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,25 +231,26 @@ public Map<Id<TransitStopFacility>, SwissRailRaptorCore.TravelInfo> calcTree(Col
for (TransitStopFacility stop : fromStops) {
accessStops.add(new InitialStop(stop, 0, 0, 0, null));
}
return this.calcLeastCostTree(accessStops, departureTime, parameters, Integer.MAX_VALUE, person, null);
return this.calcLeastCostTree(accessStops, departureTime, parameters, person, null);
}

public Map<Id<TransitStopFacility>, SwissRailRaptorCore.TravelInfo> calcTree(Facility fromFacility, double departureTime, Person person, Attributes routingAttributes) {
RaptorParameters parameters = this.parametersForPerson.getRaptorParameters(person);
List<InitialStop> accessStops = findAccessStops(fromFacility, fromFacility, person, departureTime, routingAttributes, parameters);
return this.calcLeastCostTree(accessStops, departureTime, parameters, Integer.MAX_VALUE, person, null);
return this.calcLeastCostTree(accessStops, departureTime, parameters, person, null);
}

/** Calculates a least-cost-tree for every actual departure time between <code>earliestDepartureTime</code>
* and <code>latestDepartureTime</code> at the provided stop-facility.
* This method returns nothing, instead users have to use the <code>observer</code> to collect
* relevant results.
*/
public void calcTreesObservable(TransitStopFacility stopFacility, double earliestDepartureTime, double latestStartTime, RaptorParameters parameters, int maxTransfers, Person person, RaptorObserver observer) {
public void calcTreesObservable(TransitStopFacility stopFacility, double earliestDepartureTime, double latestStartTime, RaptorParameters parameters, Person person, RaptorObserver observer) {
if (this.data.config.getOptimization() != RaptorStaticConfig.RaptorOptimization.OneToAllRouting && !this.treeWarningShown) {
log.warn("SwissRailRaptorData was not initialized with full support for tree calculations and may result in unexpected results. Use `RaptorStaticConfig.setOptimization(RaptorOptimization.OneToAllRouting)` to fix this issue.");
this.treeWarningShown = true;
}
parameters.setExactDeparturesOnly(true);

List<InitialStop> accessStops = List.of(new InitialStop(stopFacility, 0, 0, 0, null));

Expand All @@ -274,14 +275,14 @@ public void calcTreesObservable(TransitStopFacility stopFacility, double earlies
double lastDepTime = -1;
for (double departureTime : departureTimes) {
if (departureTime > lastDepTime) {
calcLeastCostTree(accessStops, departureTime, parameters, maxTransfers, person, observer);
calcLeastCostTree(accessStops, departureTime, parameters, person, observer);
lastDepTime = departureTime;
}
}
}

private Map<Id<TransitStopFacility>, SwissRailRaptorCore.TravelInfo> calcLeastCostTree(Collection<InitialStop> accessStops, double departureTime, RaptorParameters parameters, int maxTransfers, Person person, RaptorObserver observer) {
return this.raptor.calcLeastCostTree(departureTime, accessStops, parameters, maxTransfers, person, observer);
private Map<Id<TransitStopFacility>, SwissRailRaptorCore.TravelInfo> calcLeastCostTree(Collection<InitialStop> accessStops, double departureTime, RaptorParameters parameters, Person person, RaptorObserver observer) {
return this.raptor.calcLeastCostTree(departureTime, accessStops, parameters, person, observer);
}

public SwissRailRaptorData getUnderlyingData() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,40 +487,58 @@ private List<RaptorRoute> filterRoutes(List<RaptorRoute> allRoutes) {
}

public Map<Id<TransitStopFacility>, TravelInfo> calcLeastCostTree(double depTime, Collection<InitialStop> startStops, RaptorParameters parameters, Person person) {
return this.calcLeastCostTree(depTime, startStops, parameters, Integer.MAX_VALUE, person, null);
return this.calcLeastCostTree(depTime, startStops, parameters, person, null);
}

public Map<Id<TransitStopFacility>, TravelInfo> calcLeastCostTree(double depTime, Collection<InitialStop> startStops, RaptorParameters parameters, int maxTransfers, Person person, RaptorObserver observer) {
public Map<Id<TransitStopFacility>, TravelInfo> calcLeastCostTree(double depTime, Collection<InitialStop> startStops, RaptorParameters parameters, Person person, RaptorObserver observer) {
reset();

BitSet initialRouteStopIndices = new BitSet();
BitSet initialStopIndices = new BitSet();
for (InitialStop stop : startStops) {
int[] routeStopIndices = this.data.routeStopsPerStopFacility.get(stop.stop);
for (int routeStopIndex : routeStopIndices) {
int arrivalTime = (int) (depTime + stop.accessTime);
double arrivalCost = stop.accessCost;
RRouteStop toRouteStop = this.data.routeStops[routeStopIndex];
PathElement pe = new PathElement(null, toRouteStop, TIME_UNDEFINED, TIME_UNDEFINED, TIME_UNDEFINED, arrivalTime, arrivalCost, 0, stop.distance, 0, true, null, stop);
this.arrivalPathPerRouteStop[routeStopIndex] = pe;
this.arrivalPathPerStop[toRouteStop.stopFacilityIndex] = pe;
this.leastArrivalCostAtRouteStop[routeStopIndex] = arrivalCost;
this.leastArrivalCostAtStop[toRouteStop.stopFacilityIndex] = arrivalCost;
this.improvedRouteStopIndices.set(routeStopIndex);
// this is special: make sure we can transfer even at the start stop
initialRouteStopIndices.set(routeStopIndex);
initialStopIndices.set(toRouteStop.stopFacilityIndex);
boolean useStop = true;
if (parameters.isExactDeparturesOnly()) {
RRouteStop routeStop = this.data.routeStops[routeStopIndex];
int routeIndex = routeStop.transitRouteIndex;
RRoute route = this.data.routes[routeIndex];
int currentDepartureIndex = findNextDepartureIndex(route, routeStop, (int) depTime);
if (currentDepartureIndex >= 0) {
Vehicle currentVehicle = this.data.departureVehicles[currentDepartureIndex];
int firstDepartureTime = this.data.departures[currentDepartureIndex];
int stopDepartureTime = firstDepartureTime + routeStop.departureOffset;
useStop = Math.abs(depTime - stopDepartureTime) < 1e-5;
} else {
useStop = false;
}
}
if (useStop) {
int arrivalTime = (int) (depTime + stop.accessTime);
double arrivalCost = stop.accessCost;
RRouteStop toRouteStop = this.data.routeStops[routeStopIndex];
PathElement pe = new PathElement(null, toRouteStop, TIME_UNDEFINED, TIME_UNDEFINED, TIME_UNDEFINED, arrivalTime, arrivalCost, 0, stop.distance, 0, true, null, stop);
this.arrivalPathPerRouteStop[routeStopIndex] = pe;
this.arrivalPathPerStop[toRouteStop.stopFacilityIndex] = pe;
this.leastArrivalCostAtRouteStop[routeStopIndex] = arrivalCost;
this.leastArrivalCostAtStop[toRouteStop.stopFacilityIndex] = arrivalCost;
this.improvedRouteStopIndices.set(routeStopIndex);
// this is special: make sure we can transfer even at the start stop
initialRouteStopIndices.set(routeStopIndex);
initialStopIndices.set(toRouteStop.stopFacilityIndex);
}
}
}

// the main loop
int maxTransfers = parameters.getMaxTransfers();
int transfers = 0;
while (true) {
// first stage (according to paper) is to set earliestArrivalTime_k(stop) = earliestArrivalTime_k-1(stop)
// but because we re-use the earliestArrivalTime-array, we don't have to do anything.

// second stage: process routes
exploreRoutes(parameters, person, observer);
exploreRoutes(parameters, person);

if (this.improvedStops.isEmpty()) {
break;
Expand All @@ -537,7 +555,22 @@ public Map<Id<TransitStopFacility>, TravelInfo> calcLeastCostTree(double depTime
break;
}

// third stage (according to paper): handle footpaths / transfers
if (observer != null) {
for (int stopIndex = this.improvedStops.nextSetBit(0); stopIndex >= 0; stopIndex = this.improvedStops.nextSetBit(stopIndex + 1)) {
PathElement fromPE = this.arrivalPathPerStop[stopIndex];
PathElement backpointer = fromPE.comingFrom;
if (backpointer != null) {
while (backpointer.comingFrom != null) {
backpointer = backpointer.comingFrom;
}
TransitStopFacility departureStopFacility = backpointer.toRouteStop.routeStop.getStopFacility();
TransitStopFacility arrivalStopFacility = fromPE.toRouteStop.routeStop.getStopFacility();
observer.arrivedAtStop(fromPE.firstDepartureTime, arrivalStopFacility, fromPE.arrivalTime, fromPE.transferCount, () -> createRaptorRoute(departureStopFacility, arrivalStopFacility, fromPE, fromPE.firstDepartureTime));
}
}
}

// third stage (according to paper): handle footpaths / transfers
handleTransfers(true, parameters);
transfers++;

Expand Down Expand Up @@ -593,10 +626,6 @@ private TravelInfo getTravelInfo(PathElement destination, RaptorParameters param
}

private void exploreRoutes(RaptorParameters parameters, Person person) {
this.exploreRoutes(parameters, person, null);
}

private void exploreRoutes(RaptorParameters parameters, Person person, RaptorObserver observer) {
this.improvedStops.clear();
this.reachedRouteStopIndices.clear();

Expand Down Expand Up @@ -657,17 +686,6 @@ private void exploreRoutes(RaptorParameters parameters, Person person, RaptorObs
double arrivalTransferCost = (boardingPE.firstDepartureTime != TIME_UNDEFINED) ? (currentTransferCostWhenBoarding + this.transferCostCalculator.calcTransferCost(boardingPE,transferProvider, data.config, parameters, arrivalTime - firstDepartureTime, boardingPE.transferCount, boardingPE.arrivalTransferCost, boardingPE.arrivalTime)) : 0;
double previousArrivalCost = this.leastArrivalCostAtRouteStop[toRouteStopIndex];
double totalArrivalCost = arrivalTravelCost + arrivalTransferCost;
if (observer != null) {
double distance = toRouteStop.distanceAlongRoute - boardingPE.toRouteStop.distanceAlongRoute;
PathElement pe = new PathElement(boardingPE, toRouteStop, firstDepartureTime, currentAgentBoardingTime, currentDepartureTime + firstRouteStop.departureOffset, arrivalTime, arrivalTravelCost, arrivalTransferCost, distance, boardingPE.transferCount, false, null, null);
PathElement backpointer = boardingPE;
while (backpointer.comingFrom != null) {
backpointer = backpointer.comingFrom;
}
TransitStopFacility departureStopFacility = backpointer.toRouteStop.routeStop.getStopFacility();
TransitStopFacility arrivalStopFacility = toRouteStop.routeStop.getStopFacility();
observer.arrivedAtStop(pe.firstDepartureTime, arrivalStopFacility, pe.arrivalTime, pe.transferCount, () -> createRaptorRoute(departureStopFacility, arrivalStopFacility, pe, pe.firstDepartureTime));
}
if (totalArrivalCost <= previousArrivalCost) {
double distance = toRouteStop.distanceAlongRoute - boardingPE.toRouteStop.distanceAlongRoute;
PathElement pe = new PathElement(boardingPE, toRouteStop, firstDepartureTime, currentAgentBoardingTime, currentDepartureTime + firstRouteStop.departureOffset, arrivalTime, arrivalTravelCost, arrivalTransferCost, distance, boardingPE.transferCount, false, null, null);
Expand Down

0 comments on commit f8f5f9f

Please sign in to comment.