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 = Map<TripPattern, TripTimeSubset> timetables =
TripTimeSubset.indexGraph(graph, request.date, request.fromTime, request.toTime + MAX_DURATION); TripTimeSubset.indexGraph(graph, request.date, request.fromTime, request.toTime + MAX_DURATION);



PathDiscardingRaptorStateStore rss = new PathDiscardingRaptorStateStore(5);

int i = 1; int i = 1;


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


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


int et = it.value() - startTime; 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(); TransitStop v = it.key();
if (et < mins.get(v)) if (et < mins.get(v))
mins.put(v, et); mins.put(v, et);
Expand Down
@@ -1,5 +1,6 @@
package org.opentripplanner.routing.algorithm; package org.opentripplanner.routing.algorithm;


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


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


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

public int maxTime;


int current = 0; int current = 0;


@Override @Override
public boolean put(TransitStop t, int time) { public boolean put(TransitStop t, int time, boolean transfer) {
if (time < matrix[current].get(t) && time < maxTime) { if (time < matrix[current].get(t) && time < bestStops.get(t) && time < maxTime) {
matrix[current].put(t, time); 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 true;
} }
return false; return false;
} }


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


if (it.value() < matrix[current + 1].get(it.key())) if (it.value() < matrix[current + 1].get(it.key()))
matrix[current + 1].put(it.key(), it.value()); matrix[current + 1].put(it.key(), it.value());
} }
current++; 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() { public int getTime (TransitStop t) {
return matrix[current].iterator(); return bestStops.get(t);
} }


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


/** /**
Expand All @@ -69,6 +68,10 @@ public void restart () {
current = 0; 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" */ /** Create a new store with the given number of rounds. Remember to include the initial walk as a "round" */
public PathDiscardingRaptorStateStore(int rounds) { public PathDiscardingRaptorStateStore(int rounds) {
this(rounds, Integer.MAX_VALUE); this(rounds, Integer.MAX_VALUE);
Expand All @@ -82,5 +85,11 @@ public PathDiscardingRaptorStateStore(int rounds, int maxTime) {
for (int i = 0; i < rounds; i++) { for (int i = 0; i < rounds; i++) {
matrix[i] = new TObjectIntHashMap<TransitStop>(1000, 0.75f, Integer.MAX_VALUE); 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 int maxTransfers;
public final float walkSpeed; public final float walkSpeed;


private RaptorStateStore store;

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


private HashSet<TripPattern> markedPatterns = Sets.newHashSet(); private HashSet<TripPattern> markedPatterns = Sets.newHashSet();
Expand All @@ -57,29 +59,17 @@ public class Raptor {
*/ */
private LocalDate date; 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 */ /** 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.graph = graph;
this.maxTransfers = maxTransfers; this.maxTransfers = maxTransfers;
this.times = timetables; this.times = timetables;
this.walkSpeed = walkSpeed; this.walkSpeed = walkSpeed;
this.date = date; this.date = date;
this.store = store;


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


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


public void run () { public void run () {
store.proceed();
for (int round = 0; round <= maxTransfers; round++) { for (int round = 0; round <= maxTransfers; round++) {
if (!doRound(round == maxTransfers)) if (!doRound(round == maxTransfers))
break; break;
Expand All @@ -125,7 +116,7 @@ private boolean doRound (boolean isLast) {
// Loop over the patterns we marked in the previous iteration // Loop over the patterns we marked in the previous iteration
PATTERNS: for (TripPattern tp : oldMarkedPatterns) { PATTERNS: for (TripPattern tp : oldMarkedPatterns) {
STOPS: for (int i = 0; i < tp.stopVertices.length; i++) { 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) if (time == Integer.MAX_VALUE)
continue STOPS; 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. // Find all possible transfers. No need to do this on the last round though.
if (!isLast) { if (!isLast) {
transferStops.clear(); store.proceed();
findTransfers(); findTransfers();
} }


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


// we know that bestFinalTimes for this stop was updated on the last round because we mark stops // we know that the best time for this stop was updated on the last round because we mark stops
int timeAtOriginStop = bestFinalTimes.get(tstop); int timeAtOriginStop = store.getTime(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);


for (Edge e : tstop.getOutgoing()) { for (Edge e : tstop.getOutgoing()) {
if (e instanceof SimpleTransfer) { if (e instanceof SimpleTransfer) {
TransitStop to = (TransitStop) e.getToVertex(); 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)) { if (store.put(to, timeAtDestStop, true)) {
transferStops.put(to, timeAtDestStop);
markedPatterns.addAll(graph.index.patternsForStop.get(to.getStop())); 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 // board time already includes headway, if we are computing the worst-case
int arrTime = bestFreqBoardTime + bestFreq.tripTimes.getScheduledArrivalTime(reachedIdx) - boardOffset; int arrTime = bestFreqBoardTime + bestFreq.tripTimes.getScheduledArrivalTime(reachedIdx) - boardOffset;


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

markedStops.add(v); markedStops.add(v);


for (TripPattern tp : graph.index.patternsForStop.get(v.getStop())) { 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]; TransitStop v = tripPattern.stopVertices[reachedIdx];
int arrTime = tts.getArrivalTime(tripIndex, reachedIdx); int arrTime = tts.getArrivalTime(tripIndex, reachedIdx);


if (arrTime < bestFinalTimes.get(v)) { if (store.put(v, arrTime, false)) {
bestFinalTimes.put(v, arrTime);
for (TripPattern tp : graph.index.patternsForStop.get(v.getStop())) { for (TripPattern tp : graph.index.patternsForStop.get(v.getStop())) {
if (tp != tripPattern) if (tp != tripPattern)
markedPatterns.add(tp); 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 */ /** Get an iterator over all the nondominated target states of this RAPTOR search */
public TObjectIntIterator<TransitStop> iterator () { public TObjectIntIterator<TransitStop> iterator () {
return bestFinalTimes.iterator(); return store.iterator();
} }


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


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


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


import org.opentripplanner.routing.core.State; 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 */ /** Stores the states used in RAPTOR; allows easily switching to path-reconstructing store, a highly efficient optimal store, or McRAPTOR */
public interface RaptorStateStore { public interface RaptorStateStore {
/** Add a state to this store, with the given clock time (seconds since midnight) */ /** Add a state to this store, with the given clock time (seconds since midnight) */
public boolean put (TransitStop stop, int clockTime); public boolean put (TransitStop stop, int clockTime, boolean transfer);

/** 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);


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


/** Iterator over all current states */ /** get the best time for a given stop that was reached by transit (not by transfers) */
public TObjectIntIterator<TransitStop> currentIterator(); 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 */ /** get all the stops that were reached in the current round, either via transfers or directly */
public TObjectIntIterator<TransitStop> prevIterator(); public Collection<TransitStop> getTouchedStopsIncludingTransfers();
} }

0 comments on commit d64d984

Please sign in to comment.