Skip to content

Commit

Permalink
Add sanity limit for the cost of a transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardehrenfried committed Nov 15, 2023
1 parent a89009c commit 04ae499
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.opentripplanner.routing.algorithm.raptoradapter.transit;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand All @@ -16,6 +17,19 @@

public class Transfer {

/**
* Since transfers costs are not computed through a full A* they can incur an absurdly high
* cost that overflows the integer cost inside raptor.
* <p>
* An example would be a transfer using lots of stairs being used on a wheelchair when no
* wheelchair-specific one has been generated.
* (see https://docs.opentripplanner.org/en/dev-2.x/Accessibility/).
* <p>
* For this reason there is this sanit limit that make sure that the transfer cost stays inside a
* bound that is still very high but far away from the integer overflow.
*/
private final double MAX_TRANSFER_COST = Duration.ofDays(3).toSeconds();

private final int toStop;

private final int distanceMeters;
Expand Down Expand Up @@ -63,29 +77,37 @@ public Optional<RaptorTransfer> asRaptorTransfer(StreetSearchRequest request) {
WalkPreferences walkPreferences = request.preferences().walk();
if (edges == null || edges.isEmpty()) {
double durationSeconds = distanceMeters / walkPreferences.speed();
return Optional.of(
new DefaultRaptorTransfer(
this.toStop,
(int) Math.ceil(durationSeconds),
RaptorCostConverter.toRaptorCost(durationSeconds * walkPreferences.reluctance()),
this
)
);
final double domainCost = durationSeconds * walkPreferences.reluctance();
if (domainCost > MAX_TRANSFER_COST) {
return Optional.empty();
} else {
return Optional.of(
new DefaultRaptorTransfer(
this.toStop,
(int) Math.ceil(durationSeconds),
RaptorCostConverter.toRaptorCost(domainCost),
this
)
);
}
}

StateEditor se = new StateEditor(edges.get(0).getFromVertex(), request);
se.setTimeSeconds(0);

var state = EdgeTraverser.traverseEdges(se.makeState(), edges);

return state.map(s ->
new DefaultRaptorTransfer(
this.toStop,
(int) s.getElapsedTimeSeconds(),
RaptorCostConverter.toRaptorCost(s.getWeight()),
this
)
);
return state
.filter(s -> s.weight < MAX_TRANSFER_COST)
.map(s -> {
final int raptorCost = RaptorCostConverter.toRaptorCost(s.getWeight());
return new DefaultRaptorTransfer(
this.toStop,
(int) s.getElapsedTimeSeconds(),
raptorCost,
this
);
});
}

@Override
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/opentripplanner/street/search/state/State.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
Expand Down Expand Up @@ -481,6 +482,21 @@ public String toString() {
.toString();
}

/**
* Iterates over all back states of this instance and returns them as a list.
* <p>
* Note: Use this only for debugging not for performance-critical paths!
*/
public List<State> chain() {
List<State> states = new ArrayList<>();
State current = this;
while (current != null) {
states.add(current);
current = current.backState;
}
return states;
}

void checkNegativeWeight() {
double dw = this.weight - backState.weight;
if (dw < 0) {
Expand Down

0 comments on commit 04ae499

Please sign in to comment.