Skip to content

Commit

Permalink
add a configurable reachability threshold, address #2148.
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwigway committed Oct 15, 2015
1 parent f7d2449 commit 1c3b22a
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 6 deletions.
29 changes: 29 additions & 0 deletions src/main/java/org/opentripplanner/profile/ProfileRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* All the modifiable parameters for profile routing.
*/
public class ProfileRequest implements Serializable, Cloneable {
private static final long serialVersionUID = -6501962907644662303L;

/** The latitude of the origin. */
public double fromLat;
Expand Down Expand Up @@ -97,6 +98,34 @@ public class ProfileRequest implements Serializable, Cloneable {
/** If true, disable all goal direction and propagate results to the street network */
public boolean analyst = false;

/**
* What is the minimum proportion of the time for which a destination must be accessible for it to be included in
* the average?
*
* This avoids issues where destinations are reachable for some very small percentage of the time, either because
* there is a single departure near the start of the time window, or because they take approximately 2 hours
* (the default maximum cutoff) to reach.
* Consider a search run with time window 7AM to 9AM, and an origin and destination connected by an express
* bus that runs once at 7:05. For the first five minutes of the time window, accessibility is very good.
* For the rest, there is no accessibility; if we didn't have this rule in place, the average would be the average
* of the time the destination is reachable, and the time it is unreachable would be excluded from the calculation
* (see issue 2148)
* There is another issue that this rule does not completely address. Consider a trip that takes 1:45
* exclusive of wait time and runs every half-hour. Half the time it takes less than two hours and is considered
* and half the time it takes more than two hours and is excluded, so the average is biased low on very long trips.
* This rule catches the most egregious cases (say where we average only the best four minutes out of a two-hour
* span) but does not completely address the issue. However if you're looking at a time cutoff significantly
* less than two hours, it's not a big problem. Significantly less is half the headway of your least-frequent service, because
* if there is a trip on your least-frequent service that takes on average the time cutoff plus one minute
* it will be unbiased and considered unreachable iff the longest trip is less than two hours, which it has
* to be if the time cutoff plus half the headway is less than two hours, assuming a symmetric travel time
*
* The default is 0.5.
*/
public float reachabilityThreshold = 0.5f;

/** What assumption should be used when boarding frequency vehicles? */
public RaptorWorkerTimetable.BoardingAssumption boardingAssumption = RaptorWorkerTimetable.BoardingAssumption.RANDOM;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,20 @@ public class PropagatedTimesStore {
Graph graph;
int size;
int[] mins, maxs, avgs;
ProfileRequest req;

// number of times to bootstrap the mean.
public final int N_BOOTSTRAPS = 400;

private static final Random random = new Random();

public PropagatedTimesStore(Graph graph) {
this(graph, Vertex.getMaxIndex());
public PropagatedTimesStore(Graph graph, ProfileRequest req) {
this(graph, req, Vertex.getMaxIndex());
}

public PropagatedTimesStore(Graph graph, int size) {
public PropagatedTimesStore(Graph graph, ProfileRequest req, int size) {
this.graph = graph;
this.req = req;

this.size = size;
mins = new int[size];
Expand Down Expand Up @@ -149,7 +151,7 @@ public void setFromArray(int[][] times, ConfidenceCalculationMethod confidenceCa
// TODO: due to multiple paths to a target the distribution is not symmetrical though - evaluate the
// effect of this. Also, transfers muddy the concept of "worst frequency" since there is variation in mid-trip
// wait times as well.
if (count >= times.length / 2)
if (count >= times.length * req.reachabilityThreshold)
avgs[target] = sum / count;

// TODO: correctly handle partial accessibility for bootstrap and percentile options.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public PropagatedTimesStore runRaptor (Graph graph, TIntIntMap accessTimes, int[
initialStops.put(stopIndex, accessTime);
}

PropagatedTimesStore propagatedTimesStore = new PropagatedTimesStore(graph, data.nTargets);
PropagatedTimesStore propagatedTimesStore = new PropagatedTimesStore(graph, this.req, data.nTargets);

// optimization: if no schedules, only run Monte Carlo
int fromTime = req.fromTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public ResultEnvelope route () {
ts.initialStopCount = transitStopAccessTimes.size();
} else {
// Nontransit case: skip transit routing and make a propagated times store based on only one row.
propagatedTimesStore = new PropagatedTimesStore(graph, nonTransitTimes.length);
propagatedTimesStore = new PropagatedTimesStore(graph, request, nonTransitTimes.length);
int[][] singleRoundResults = new int[1][];
singleRoundResults[0] = nonTransitTimes;
propagatedTimesStore.setFromArray(singleRoundResults,
Expand Down

0 comments on commit 1c3b22a

Please sign in to comment.