@Override public State traverse(State s0) { RoutingRequest options = s0.getOptions(); // Ignore this edge if its stop is banned if (!options.bannedStops.isEmpty()) { if (options.bannedStops.matches(((TransitStop) fromv).getStop())) { return null; } } if (!options.bannedStopsHard.isEmpty()) { if (options.bannedStopsHard.matches(((TransitStop) fromv).getStop())) { return null; } } if (options.arriveBy) { /* Traverse backward: not much to do */ StateEditor s1 = s0.edit(this); TransitStop fromVertex = (TransitStop) getFromVertex(); // apply board slack s1.incrementTimeInSeconds(options.boardSlack); s1.alightTransit(); s1.setBackMode(getMode()); return s1.makeState(); } else { /* Traverse forward: apply stop(pair)-specific costs */ // Do not pre-board if transit modes are not selected. // Return null here rather than in StreetTransitLink so that walk-only // options can be used to find transit stops without boarding vehicles. if (!options.modes.isTransit()) return null; // If we've hit our transfer limit, don't go any further if (s0.getNumBoardings() > options.maxTransfers) return null; /* apply transfer rules */ /* * look in the global transfer table for the rules from the previous stop to this stop. */ long t0 = s0.getTimeSeconds(); long slack; if (s0.isEverBoarded()) { slack = options.transferSlack - options.alightSlack; } else { slack = options.boardSlack; } long board_after = t0 + slack; long transfer_penalty = 0; // penalize transfers more heavily if requested by the user if (s0.isEverBoarded()) { // this is not the first boarding, therefore we must have "transferred" -- whether // via a formal transfer or by walking. transfer_penalty += options.transferPenalty; } StateEditor s1 = s0.edit(this); s1.setTimeSeconds(board_after); long wait_cost = board_after - t0; s1.incrementWeight(wait_cost + transfer_penalty); s1.setBackMode(getMode()); return s1.makeState(); } }
/** * @param options * @param walkOptions * @param nBoardings * @param createdStates * @return whether search should continue */ public boolean walkPhase( RoutingRequest options, RoutingRequest walkOptions, int nBoardings, List<RaptorState> createdStates) { double distanceToNearestTransitStop = 0; if (options.rctx.target != null) { distanceToNearestTransitStop = options.rctx.target.getDistanceToNearestTransitStop(); } final int boardSlack = nBoardings == 1 ? options.getBoardSlack() : (options.getTransferSlack() - options.getAlightSlack()); ShortestPathTree spt; GenericDijkstra dijkstra = new GenericDijkstra(walkOptions); dijkstra.setShortestPathTreeFactory(bounder); List<State> transitStopStates = new ArrayList<State>(); if (nBoardings == 0) { // TODO: retry min-time bounding with this and with maxtime if (options.rctx.target != null && bounder.getTargetDistance(options.rctx.origin) < options.getMaxWalkDistance()) dijkstra.setHeuristic(bounder); MaxWalkState start = new MaxWalkState(options.rctx.origin, walkOptions); spt = dijkstra.getShortestPathTree(start); for (State state : spt.getAllStates()) { if (state.getVertex() instanceof TransitStop || state.getVertex() instanceof TransitStopArrive || state.getVertex() instanceof TransitStopDepart) transitStopStates.add(state); } // also, compute an initial spt from the target so that we can find out what transit // stops are nearby and what // the time is to them, so that we can start target bounding earlier if (maxTimeDayIndex > 0) { RoutingRequest reversedWalkOptions = walkOptions.clone(); reversedWalkOptions.setArriveBy(!walkOptions.isArriveBy()); GenericDijkstra destDijkstra = new GenericDijkstra(reversedWalkOptions); start = new MaxWalkState(options.rctx.target, reversedWalkOptions); ShortestPathTree targetSpt = destDijkstra.getShortestPathTree(start); for (State state : targetSpt.getAllStates()) { final Vertex vertex = state.getVertex(); if (!(vertex instanceof TransitStop)) continue; RaptorStop stop = data.raptorStopsForStopId.get(((TransitStop) vertex).getStopId()); if (stop == null) { // we have found a stop is totally unused, so skip it continue; } // Skip banned stops if (options.getBannedStops().matches(stop.stopVertex.getStop())) { continue; } if (options.getBannedStopsHard().matches(stop.stopVertex.getStop())) { continue; } addStopNearTarget(stop, state.getWalkDistance(), (int) state.getElapsedTimeSeconds()); } } } else { final List<MaxWalkState> startPoints = new ArrayList<MaxWalkState>(); for (RaptorState state : createdStates) { // bounding states // this reduces the number of initial vertices // and the state space size Vertex stopVertex = options.isArriveBy() ? state.stop.departVertex : state.stop.arriveVertex; if (stopVertex == null) { stopVertex = state.stop.stopVertex; } if (options.rctx.target != null) { double minWalk = distanceToNearestTransitStop; double targetDistance = bounder.getTargetDistance(stopVertex); if (targetDistance + state.walkDistance > options.getMaxWalkDistance()) { // can't walk to destination, so we can't alight at a local vertex if (state.stop.stopVertex.isLocal()) continue; } if (minWalk + state.walkDistance > options.getMaxWalkDistance()) { continue; } } StateEditor dijkstraState = new MaxWalkState.MaxWalkStateEditor(walkOptions, stopVertex); dijkstraState.setInitialWaitTimeSeconds(state.initialWaitTime); dijkstraState.setStartTimeSeconds(options.dateTime); dijkstraState.setNumBoardings(state.nBoardings); dijkstraState.setWalkDistance(state.walkDistance); dijkstraState.setTimeSeconds(state.arrivalTime); dijkstraState.setExtension("raptorParent", state); dijkstraState.setOptions(walkOptions); dijkstraState.incrementWeight(state.weight); MaxWalkState newState = (MaxWalkState) dijkstraState.makeState(); startPoints.add(newState); } if (startPoints.size() == 0) { return false; } System.out.println("walk starts: " + startPoints.size() + " / " + visitedEver.size()); dijkstra.setPriorityQueueFactory( new PrefilledPriorityQueueFactory(startPoints.subList(1, startPoints.size()))); bounder.addSptStates(startPoints.subList(1, startPoints.size())); bounder.prepareForSearch(); dijkstra.setSearchTerminationStrategy(bounder); if (options.rctx.target != null) { dijkstra.setSkipTraverseResultStrategy(bounder); dijkstra.setHeuristic(bounder); } // Do local search spt = dijkstra.getShortestPathTree(startPoints.get(0)); transitStopStates = bounder.getTransitStopsVisited(); } List<? extends State> targetStates = null; if (walkOptions.rctx.target != null) targetStates = spt.getStates(walkOptions.rctx.target); if (targetStates != null) { TARGET: for (State targetState : targetStates) { RaptorState parent = (RaptorState) targetState.getExtension("raptorParent"); RaptorState state; if (parent != null) { state = new RaptorState(parent); state.nBoardings = parent.nBoardings; state.rentingBike = targetState.isBikeRenting(); } else { state = new RaptorState(options); } state.weight = targetState.getWeight(); state.walkDistance = targetState.getWalkDistance(); state.arrivalTime = (int) targetState.getTimeSeconds(); state.walkPath = targetState; for (Iterator<RaptorState> it = getTargetStates().iterator(); it.hasNext(); ) { RaptorState oldState = it.next(); if (oldState.eDominates(state)) { continue TARGET; } else if (state.eDominates(oldState)) { it.remove(); } } addTargetState(state); log.debug("Found target at: " + state + " on " + state.getTrips()); } } for (State state : bounder.removedBoundingStates) { removeTargetState(state); } SPTSTATE: for (State state : transitStopStates) { final Vertex vertex = state.getVertex(); RaptorStop stop = data.raptorStopsForStopId.get(((OffboardVertex) vertex).getStopId()); if (stop == null) { // we have found a stop is totally unused, so skip it continue; } // Skip banned stops if (options.getBannedStops().matches(stop.stopVertex.getStop())) { continue; } if (options.getBannedStopsHard().matches(stop.stopVertex.getStop())) { continue; } if (options.rctx.target != null) { double minWalk = distanceToNearestTransitStop; double targetDistance = bounder.getTargetDistance(vertex); final double remainingWalk = options.maxWalkDistance - state.getWalkDistance(); if (maxTimeDayIndex > 0 && remainingWalk < 3218) { double minTime = (targetDistance - minWalk) / Raptor.MAX_TRANSIT_SPEED + minWalk / options.getStreetSpeedUpperBound(); if (targetDistance > remainingWalk) minTime += boardSlack; int maxTimeForVertex = 0; int region = vertex.getGroupIndex(); final int elapsedTime = (int) state.getElapsedTimeSeconds(); for (StopNearTarget stopNearTarget : stopsNearTarget.values()) { int destinationRegion = stopNearTarget.stop.stopVertex.getGroupIndex(); final int maxTimeFromThisRegion = data.maxTransitRegions.maxTransit[maxTimeDayIndex][destinationRegion][region]; int maxTime = elapsedTime + maxTimeFromThisRegion + stopNearTarget.time; if (maxTime > maxTimeForVertex) { maxTimeForVertex = maxTime; } } if (maxTimeForVertex < maxTime) { maxTime = maxTimeForVertex; } else { if (elapsedTime + minTime > maxTime * 1.5) { continue; } } } } List<RaptorState> states = statesByStop[stop.index]; if (states == null) { states = new ArrayList<RaptorState>(); statesByStop[stop.index] = states; } RaptorState parent = (RaptorState) state.getExtension("raptorParent"); RaptorState newState; if (parent != null) { newState = new RaptorState(parent); } else { // this only happens in round 0 newState = new RaptorState(options); } newState.weight = state.getWeight(); newState.nBoardings = nBoardings; newState.walkDistance = state.getWalkDistance(); newState.arrivalTime = (int) state.getTimeSeconds(); newState.walkPath = state; newState.stop = stop; newState.rentingBike = state.isBikeRenting(); for (RaptorState oldState : states) { if (oldState.eDominates(newState)) { continue SPTSTATE; } } visitedLastRound.add(stop); visitedEver.add(stop); states.add(newState); } return true; }