private boolean checkForInterliningArriveBy( RoutingRequest options, int nBoardings, RaptorRoute route, List<RaptorState> boardStates) { int firstStop = route.getNStops() - 1; boolean started = false; final List<RaptorState> states = statesByStop[route.stops[firstStop].index]; if (states == null) return false; INTERLINE: for (RaptorState oldState : states) { if (oldState.nBoardings != nBoardings - 1) { continue; } if (oldState.route == null) { continue; } if (oldState.route.stops[0] != oldState.stop) { continue; } RaptorInterlineData interline = oldState.route.interlinesIn.get(oldState.tripId); if (interline == null || interline.fromRoute != route) { continue; } RaptorState stayOn = oldState.clone(); stayOn.arrivalTime += options.getBoardSlack(); // go backwards in time stayOn.interlining = true; // generate a board state for this interline RaptorState boardState = new RaptorState(stayOn); // we need to subtract out the boardSlack that we are about to mistakenly pay boardState.weight = -options.getBoardSlack() - options.getAlightSlack(); boardState.nBoardings = boardState.nBoardings = nBoardings - 1; boardState.boardStop = route.stops[firstStop]; boardState.boardStopSequence = firstStop; TransitBoardAlight alight = route.alights[firstStop - 1][interline.fromPatternIndex]; TableTripPattern pattern = alight.getPattern(); boardState.tripTimes = pattern.getTripTimes(interline.fromTripIndex); final ServiceDay serviceDay = oldState.serviceDay; boardState.arrivalTime = (int) serviceDay.time(boardState.tripTimes.getArrivalTime(firstStop - 1)); boardState.patternIndex = interline.fromPatternIndex; boardState.tripId = interline.fromTripId; boardState.serviceDay = serviceDay; boardState.route = route; boardState.walkDistance = oldState.walkDistance; for (RaptorState state : boardStates) { if (state.eDominates(boardState)) { continue INTERLINE; } } boardStates.add(boardState); started = true; } return started; }
public State traverse(State state0) { RoutingContext rctx = state0.getContext(); RoutingRequest options = state0.getOptions(); Trip trip = pattern.getTrip(); if (options.isArriveBy()) { /* reverse traversal, not so much to do */ // do not alight immediately when arrive-depart dwell has been eliminated // this affects multi-itinerary searches if (state0.getBackEdge() instanceof TransitBoardAlight && !((TransitBoardAlight) state0.getBackEdge()).isBoarding()) { return null; } StateEditor s1 = state0.edit(this); int type = pattern.getBoardType(stopIndex); if (TransitUtils.handleBoardAlightType(s1, type)) { return null; } s1.setTripId(null); s1.setLastAlightedTime(state0.getTime()); s1.setBackMode(TraverseMode.BOARDING); s1.setPreviousStop(fromv); return s1.makeState(); } else { /* forward traversal: look for a transit trip on this pattern */ if (!options.getModes().get(modeMask)) { return null; } /* find next boarding time */ /* * check lists of transit serviceIds running yesterday, today, and tomorrow (relative to * initial state) if this pattern's serviceId is running look for the next boarding time * choose the soonest boarding time among trips starting yesterday, today, or tomorrow */ long currentTime = state0.getTime(); int bestWait = -1; TraverseMode mode = state0.getNonTransitMode(); if (options.bannedTrips.containsKey(trip.getId())) { // see comment in FrequencyAlight for details return null; } for (ServiceDay sd : rctx.serviceDays) { int secondsSinceMidnight = sd.secondsSinceMidnight(currentTime); // only check for service on days that are not in the future // this avoids unnecessarily examining tomorrow's services if (secondsSinceMidnight < 0) continue; if (sd.serviceIdRunning(serviceId)) { int startTime = pattern.getNextDepartureTime( stopIndex, secondsSinceMidnight, options.wheelchairAccessible, mode == TraverseMode.BICYCLE, true); if (startTime >= 0) { // a trip was found, wait will be non-negative int wait = (int) (sd.time(startTime) - currentTime); if (wait < 0) _log.error("negative wait time on board"); if (bestWait < 0 || wait < bestWait) { // track the soonest departure over all relevant schedules bestWait = wait; } } } } if (bestWait < 0) { return null; } /* check if trip is banned for this plan */ if (options.tripIsBanned(trip)) return null; /* check if route is preferred for this plan */ long preferences_penalty = options.preferencesPenaltyForTrip(trip); StateEditor s1 = state0.edit(this); int type = pattern.getBoardType(stopIndex); if (TransitUtils.handleBoardAlightType(s1, type)) { return null; } s1.incrementTimeInSeconds(bestWait); s1.incrementNumBoardings(); s1.setTripId(trip.getId()); s1.setZone(pattern.getZone(stopIndex)); s1.setRoute(trip.getRoute().getId()); s1.setBackMode(TraverseMode.BOARDING); long wait_cost = bestWait; if (state0.getNumBoardings() == 0) { wait_cost *= options.waitAtBeginningFactor; } else { wait_cost *= options.waitReluctance; } s1.incrementWeight(preferences_penalty); s1.incrementWeight(wait_cost + options.getBoardCost(mode)); return s1.makeState(); } }
public List<RaptorState> transitPhase(RoutingRequest options, int nBoardings) { Collection<RaptorRoute> routesToVisit = new HashSet<RaptorRoute>(); if (data.routesForStop == null) { Collection<RaptorRoute> routes = data.routes; for (RaptorStop stop : visitedLastRound) { for (RaptorRoute route : data.routesForStop[stop.index]) { if (routes.contains(route)) { routesToVisit.add(route); } } } } else { for (RaptorStop stop : visitedLastRound) { for (RaptorRoute route : data.routesForStop[stop.index]) { routesToVisit.add(route); } } } HashSet<RaptorStop> visitedThisRound = new HashSet<RaptorStop>(); List<RaptorState> createdStates = new ArrayList<RaptorState>(); int boardSlack; if (options.isArriveBy()) { boardSlack = nBoardings == 1 ? options.getAlightSlack() : (options.getTransferSlack() - options.getBoardSlack()); } else { boardSlack = nBoardings == 1 ? options.getBoardSlack() : (options.getTransferSlack() - options.getAlightSlack()); } for (RaptorRoute route : routesToVisit) { List<RaptorState> boardStates = new ArrayList<RaptorState>(); // not really states boolean started; int firstStop, lastStop, direction, lastBoardStop; if (options.isArriveBy()) { firstStop = route.getNStops() - 1; lastStop = -1; direction = -1; lastBoardStop = 0; // check for interlining on the first stop started = checkForInterliningArriveBy(options, nBoardings, route, boardStates); } else { firstStop = 0; lastStop = route.getNStops(); direction = 1; lastBoardStop = lastStop - 1; started = checkForInterliningDepartAt(options, nBoardings, route, boardStates); } for (int stopNo = firstStop; stopNo != lastStop; stopNo += direction) { // find the current time at this stop RaptorStop stop = route.stops[stopNo]; if (!started && !visitedLastRound.contains(stop)) continue; started = true; // skip stops which aren't in this set of data; // this is used for the rush ahead search if (!data.raptorStopsForStopId.containsKey(stop.stopVertex.getStopId())) { continue; } // Skip banned stops if (options.getBannedStops().matches(stop.stopVertex.getStop())) { continue; } if (options.getBannedStopsHard().matches(stop.stopVertex.getStop())) { continue; } List<RaptorState> states = statesByStop[stop.index]; List<RaptorState> newStates = new ArrayList<RaptorState>(); if (states == null) { states = new ArrayList<RaptorState>(); statesByStop[stop.index] = states; } // this checks the case of continuing on the current trips. CONTINUE: for (RaptorState boardState : boardStates) { if (boardState.boardStop == stop) { // this only happens due to interlines where // the last stop of the first route is equal to the first stop of the // subsequent route. continue; } RaptorState newState = new RaptorState(boardState.getParent()); ServiceDay sd = boardState.serviceDay; int travelTime; if (options.isArriveBy()) { if (!route.alights[0][boardState.patternIndex].getPattern().canBoard(stopNo)) continue; int boardTime = route.getBoardTime(boardState.tripTimes, stopNo); newState.arrivalTime = (int) sd.time(boardTime); // add in slack newState.arrivalTime -= options.getBoardSlack(); travelTime = newState.getParent().arrivalTime - newState.arrivalTime; } else { if (!route.boards[0][boardState.patternIndex].getPattern().canAlight(stopNo)) continue; int alightTime = route.getAlightTime(boardState.tripTimes, stopNo); newState.arrivalTime = (int) sd.time(alightTime); // add in slack newState.arrivalTime += options.getAlightSlack(); travelTime = newState.arrivalTime - newState.getParent().arrivalTime; } newState.weight += travelTime; // TODO: consider transfer penalties newState.weight += boardState.weight; newState.boardStop = boardState.boardStop; newState.boardStopSequence = boardState.boardStopSequence; newState.route = route; newState.patternIndex = boardState.patternIndex; newState.tripTimes = boardState.tripTimes; newState.nBoardings = boardState.nBoardings; newState.walkDistance = boardState.walkDistance; newState.tripId = boardState.tripId; newState.stop = stop; newState.serviceDay = boardState.serviceDay; for (RaptorState oldState : states) { if (oldState.eDominates(newState)) { continue CONTINUE; } } for (RaptorState oldState : newStates) { if (oldState.eDominates(newState)) { continue CONTINUE; } } Iterator<RaptorState> it = states.iterator(); while (it.hasNext()) { RaptorState oldState = it.next(); if (newState.eDominates(oldState)) { it.remove(); } } it = newStates.iterator(); while (it.hasNext()) { RaptorState oldState = it.next(); if (newState.eDominates(oldState)) { it.remove(); } } visitedThisRound.add(stop); visitedEver.add(stop); newStates.add(newState); } if (stopNo != lastBoardStop) { if (stop.stopVertex.isLocal() && nBoardings > 1) { // cannot transfer at a local stop createdStates.addAll(newStates); states.addAll(newStates); continue; } // try boarding here TRYBOARD: for (RaptorState oldState : states) { if (oldState.nBoardings != nBoardings - 1) continue; if (oldState.getRoute() == route) continue; // we got here via this route, so no reason to transfer RaptorBoardSpec boardSpec; int waitTime; if (options.isArriveBy()) { int arrivalTime = oldState.arrivalTime - boardSlack; boardSpec = route.getTripIndexReverse(options, arrivalTime, stopNo); if (boardSpec == null) continue; waitTime = oldState.arrivalTime - boardSpec.departureTime; } else { int arrivalTime = oldState.arrivalTime + boardSlack; boardSpec = route.getTripIndex(options, arrivalTime, stopNo); if (boardSpec == null) continue; waitTime = boardSpec.departureTime - oldState.arrivalTime; } RaptorState boardState = new RaptorState(oldState); if (nBoardings == 1) { // do not count initial wait time, since it will be optimized away later boardState.initialWaitTime = waitTime; waitTime = 0; } boardState.weight = options.getBoardCost(route.mode) + waitTime; boardState.nBoardings = nBoardings; boardState.boardStop = stop; boardState.boardStopSequence = stopNo; boardState.arrivalTime = boardSpec.departureTime; boardState.patternIndex = boardSpec.patternIndex; boardState.tripTimes = boardSpec.tripTimes; boardState.serviceDay = boardSpec.serviceDay; boardState.route = route; boardState.walkDistance = oldState.walkDistance; boardState.tripId = boardSpec.tripId; for (RaptorState state : boardStates) { if (state.eDominates(boardState)) { continue TRYBOARD; } } for (RaptorState state : newStates) { if (state.eDominates(boardState)) { continue TRYBOARD; } } boardStates.add(boardState); } } createdStates.addAll(newStates); states.addAll(newStates); } } visitedLastRound = visitedThisRound; return createdStates; }