Skip to content

Commit

Permalink
reimplement range raptor.
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwigway committed Apr 17, 2015
1 parent d70ce40 commit d64d984
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 65 deletions.
Expand Up @@ -76,17 +76,33 @@ public void route () {
Map<TripPattern, TripTimeSubset> timetables =
TripTimeSubset.indexGraph(graph, request.date, request.fromTime, request.toTime + MAX_DURATION);


PathDiscardingRaptorStateStore rss = new PathDiscardingRaptorStateStore(5);

int i = 1;

// We assume the times are aligned to minutes, and we don't do a depart-after search starting
// at the end of the window.
for (int startTime = request.toTime - 60; startTime >= request.fromTime; startTime -= 60) {
if (++i % 30 == 0)
LOG.info("Completed {} RAPTOR searches", i);

// adjust the max time
rss.maxTime = startTime + 120 * 60;

// reset the counter
rss.restart();

// relax the times at the start stops
for (TObjectIntIterator<TransitStop> it = accessTimes.iterator(); it.hasNext();) {
it.advance();
// this is "transfer" from the origin
rss.put(it.key(), startTime + it.value(), true);
}

//LOG.info("Filtering RAPTOR states");

Raptor raptor = new Raptor(graph, 3, request.walkSpeed, accessTimes, startTime, request.date, timetables);
Raptor raptor = new Raptor(graph, 3, request.walkSpeed, rss, startTime, request.date, timetables);

//LOG.info("Performing RAPTOR search for minute {}", i++);

Expand All @@ -99,6 +115,11 @@ public void route () {
it.advance();

int et = it.value() - startTime;

// this can happen if the time is left from a previous search at a later start time
if (et > 120 * 60)
continue;

TransitStop v = it.key();
if (et < mins.get(v))
mins.put(v, et);
Expand Down
@@ -1,5 +1,6 @@
package org.opentripplanner.routing.algorithm;

import java.util.Collection;
import java.util.Iterator;

import gnu.trove.iterator.TObjectIntIterator;
Expand All @@ -17,46 +18,44 @@ public class PathDiscardingRaptorStateStore implements RaptorStateStore {
@SuppressWarnings("rawtypes")
private TObjectIntMap[] matrix;

public final int maxTime;
private TObjectIntMap<TransitStop> bestStops;

public int maxTime;

int current = 0;

@Override
public boolean put(TransitStop t, int time) {
if (time < matrix[current].get(t) && time < maxTime) {
public boolean put(TransitStop t, int time, boolean transfer) {
if (time < matrix[current].get(t) && time < bestStops.get(t) && time < maxTime) {
matrix[current].put(t, time);

// Only update bestStops if this is not the result of a transfer, so that transit stops
// cannot be used to go past the walk distance by transferring and then egressing without boarding.
if (!transfer)
bestStops.put(t, time);

return true;
}
return false;
}

@Override
public void proceed() {
for (TObjectIntIterator<TransitStop> it = currentIterator(); it.hasNext();) {
for (TObjectIntIterator<TransitStop> it = matrix[current].iterator(); it.hasNext();) {
it.advance();

if (it.value() < matrix[current + 1].get(it.key()))
matrix[current + 1].put(it.key(), it.value());
}
current++;
}

@Override
public int getCurrent(TransitStop t) {
return matrix[current].get(t);
}

@Override
public int getPrev(TransitStop t) {
return matrix[current - 1].get(t);
}

public TObjectIntIterator<TransitStop> currentIterator() {
return matrix[current].iterator();
public int getTime (TransitStop t) {
return bestStops.get(t);
}

public TObjectIntIterator<TransitStop> prevIterator() {
return matrix[current - 1].iterator();
public int getPrev (TransitStop t) {
return matrix[current - 1].get(t);
}

/**
Expand All @@ -69,6 +68,10 @@ public void restart () {
current = 0;
}

public TObjectIntIterator<TransitStop> iterator () {
return bestStops.iterator();
}

/** Create a new store with the given number of rounds. Remember to include the initial walk as a "round" */
public PathDiscardingRaptorStateStore(int rounds) {
this(rounds, Integer.MAX_VALUE);
Expand All @@ -82,5 +85,11 @@ public PathDiscardingRaptorStateStore(int rounds, int maxTime) {
for (int i = 0; i < rounds; i++) {
matrix[i] = new TObjectIntHashMap<TransitStop>(1000, 0.75f, Integer.MAX_VALUE);
}

bestStops = new TObjectIntHashMap<TransitStop>(1000, 0.75f, Integer.MAX_VALUE);
}

public Collection<TransitStop> getTouchedStopsIncludingTransfers () {
return matrix[current].keySet();
}
}
51 changes: 16 additions & 35 deletions src/main/java/org/opentripplanner/routing/algorithm/Raptor.java
Expand Up @@ -43,6 +43,8 @@ public class Raptor {
public final int maxTransfers;
public final float walkSpeed;

private RaptorStateStore store;

private static final Logger LOG = LoggerFactory.getLogger(Raptor.class);

private HashSet<TripPattern> markedPatterns = Sets.newHashSet();
Expand All @@ -57,29 +59,17 @@ public class Raptor {
*/
private LocalDate date;

/**
* These are all the stops that could be reached after the previous round by transfers
* (including explicit zero-time loop transfers).
*/
private TObjectIntMap<TransitStop> transferStops = new TObjectIntHashMap<TransitStop>(1000, 0.75f, Integer.MAX_VALUE);

/**
* This keeps track of the overall best time at any stop when that stop is reached by a ride rather than a transfer.
*/
private TObjectIntMap<TransitStop> bestFinalTimes = new TObjectIntHashMap<TransitStop>(1000, 0.75f, Integer.MAX_VALUE);

/** Initialize a RAPTOR router from an existing RaptorStateStore, a routing request, and the timetables of active trips */
public Raptor(Graph graph, int maxTransfers, float walkSpeed, TObjectIntMap<TransitStop> accessTimes, int startTime, LocalDate date, Map<TripPattern, TripTimeSubset> timetables) {
public Raptor(Graph graph, int maxTransfers, float walkSpeed, RaptorStateStore store, int startTime, LocalDate date, Map<TripPattern, TripTimeSubset> timetables) {
this.graph = graph;
this.maxTransfers = maxTransfers;
this.times = timetables;
this.walkSpeed = walkSpeed;
this.date = date;
this.store = store;

for (TObjectIntIterator<TransitStop> it = accessTimes.iterator(); it.hasNext();) {
it.advance();
transferStops.put(it.key(), startTime + it.value());
markedPatterns.addAll(graph.index.patternsForStop.get(it.key().getStop()));
for (TransitStop tstop : store.getTouchedStopsIncludingTransfers()) {
markedPatterns.addAll(graph.index.patternsForStop.get(tstop.getStop()));
}
}

Expand All @@ -102,6 +92,7 @@ public ShortestPathTree getShortestPathTree () {
*/

public void run () {
store.proceed();
for (int round = 0; round <= maxTransfers; round++) {
if (!doRound(round == maxTransfers))
break;
Expand All @@ -125,7 +116,7 @@ private boolean doRound (boolean isLast) {
// Loop over the patterns we marked in the previous iteration
PATTERNS: for (TripPattern tp : oldMarkedPatterns) {
STOPS: for (int i = 0; i < tp.stopVertices.length; i++) {
int time = transferStops.get(tp.stopVertices[i]);
int time = store.getPrev(tp.stopVertices[i]);
if (time == Integer.MAX_VALUE)
continue STOPS;

Expand All @@ -135,7 +126,7 @@ private boolean doRound (boolean isLast) {

// Find all possible transfers. No need to do this on the last round though.
if (!isLast) {
transferStops.clear();
store.proceed();
findTransfers();
}

Expand All @@ -148,22 +139,16 @@ public void findTransfers () {
// only find transfers from stops that were touched in this round.
for (TransitStop tstop : markedStops) {

// we know that bestFinalTimes for this stop was updated on the last round because we mark stops
int timeAtOriginStop = bestFinalTimes.get(tstop);

// 0-time loop transfers
// patterns are already marked; they were marked when the stop was first reached
if (timeAtOriginStop < transferStops.get(tstop))
transferStops.put(tstop, timeAtOriginStop);
// we know that the best time for this stop was updated on the last round because we mark stops
int timeAtOriginStop = store.getTime(tstop);

for (Edge e : tstop.getOutgoing()) {
if (e instanceof SimpleTransfer) {
TransitStop to = (TransitStop) e.getToVertex();

int timeAtDestStop = (int) (bestFinalTimes.get(tstop) + e.getDistance() / walkSpeed);
int timeAtDestStop = (int) (timeAtOriginStop + e.getDistance() / walkSpeed);

if (timeAtDestStop < bestFinalTimes.get(to) && timeAtDestStop < transferStops.get(to)) {
transferStops.put(to, timeAtDestStop);
if (store.put(to, timeAtDestStop, true)) {
markedPatterns.addAll(graph.index.patternsForStop.get(to.getStop()));
}
}
Expand Down Expand Up @@ -231,10 +216,7 @@ public boolean propagateFrequencies (int time, TripPattern tripPattern, int stop
// board time already includes headway, if we are computing the worst-case
int arrTime = bestFreqBoardTime + bestFreq.tripTimes.getScheduledArrivalTime(reachedIdx) - boardOffset;

if (arrTime < bestFinalTimes.get(v)) {
// this is a final stop
bestFinalTimes.put(v, arrTime);

if (store.put(v, arrTime, false)) {
markedStops.add(v);

for (TripPattern tp : graph.index.patternsForStop.get(v.getStop())) {
Expand Down Expand Up @@ -265,8 +247,7 @@ public void propagateSchedules(int time, TripPattern tripPattern, int stopIndex)
TransitStop v = tripPattern.stopVertices[reachedIdx];
int arrTime = tts.getArrivalTime(tripIndex, reachedIdx);

if (arrTime < bestFinalTimes.get(v)) {
bestFinalTimes.put(v, arrTime);
if (store.put(v, arrTime, false)) {
for (TripPattern tp : graph.index.patternsForStop.get(v.getStop())) {
if (tp != tripPattern)
markedPatterns.add(tp);
Expand All @@ -279,7 +260,7 @@ public void propagateSchedules(int time, TripPattern tripPattern, int stopIndex)

/** Get an iterator over all the nondominated target states of this RAPTOR search */
public TObjectIntIterator<TransitStop> iterator () {
return bestFinalTimes.iterator();
return store.iterator();
}

/*
Expand Down
@@ -1,7 +1,9 @@
package org.opentripplanner.routing.algorithm;

import gnu.trove.iterator.TObjectIntIterator;
import gnu.trove.map.TObjectIntMap;

import java.util.Collection;
import java.util.Iterator;

import org.opentripplanner.routing.core.State;
Expand All @@ -10,20 +12,20 @@
/** Stores the states used in RAPTOR; allows easily switching to path-reconstructing store, a highly efficient optimal store, or McRAPTOR */
public interface RaptorStateStore {
/** Add a state to this store, with the given clock time (seconds since midnight) */
public boolean put (TransitStop stop, int clockTime);

/** Get a clock time in seconds since midnight from this store after the current round */
public int getCurrent (TransitStop t);

/** Get a clock time in seconds since midnight from this store after the previous round */
public int getPrev (TransitStop t);
public boolean put (TransitStop stop, int clockTime, boolean transfer);

/** Proceed to the next round */
public void proceed ();

/** Iterator over all current states */
public TObjectIntIterator<TransitStop> currentIterator();
/** get the best time for a given stop that was reached by transit (not by transfers) */
public int getTime(TransitStop t);

/** get the best time for a given stop after the last round, including transfers */
public int getPrev(TransitStop t);

/** get an iterator over the states of this store */
public TObjectIntIterator<TransitStop> iterator ();

/** Iterator over all states from the previous round */
public TObjectIntIterator<TransitStop> prevIterator();
/** get all the stops that were reached in the current round, either via transfers or directly */
public Collection<TransitStop> getTouchedStopsIncludingTransfers();
}

0 comments on commit d64d984

Please sign in to comment.