예제 #1
0
  private int doPreliminarySearch(
      RoutingRequest options,
      RoutingRequest walkOptions,
      RaptorSearch search,
      RaptorData trimmedData) {
    RaptorSearch rushSearch = new RaptorSearch(trimmedData, options);
    int bestElapsedTime = Integer.MAX_VALUE;
    int round;
    for (round = 0; round < options.getMaxTransfers() + 2; round++) {
      if (!round(trimmedData, options, walkOptions, rushSearch, round)) break;

      if (rushSearch.getTargetStates().size() > 0) {
        int oldBest = bestElapsedTime;
        for (RaptorState state : rushSearch.getTargetStates()) {
          final int elapsedTime = (int) Math.abs(state.arrivalTime - options.dateTime);
          if (elapsedTime < bestElapsedTime) {
            bestElapsedTime = elapsedTime;
          }
        }
        int improvement = oldBest - bestElapsedTime;
        if (improvement < 600) break;
      }
    }
    for (RaptorState state : rushSearch.getTargetStates()) {
      search.bounder.addBounder(state.walkPath);
      search.addTargetState(state);
    }
    return round;
  }
예제 #2
0
  /**
   * This does preliminary search over just routes and stops that have been used in the past between
   * these regions.
   */
  private int preliminaryRaptorSearch(
      RaptorData data, RoutingRequest options, RoutingRequest walkOptions, RaptorSearch search) {
    // find start/end regions
    List<Integer> startRegions = getRegionsForVertex(data.regionData, options.rctx.fromVertex);
    int startRegion;
    // for trips that span regions, we can safely pick either region
    startRegion = startRegions.get(0);
    List<Integer> endRegions = getRegionsForVertex(data.regionData, options.rctx.toVertex);
    int endRegion;
    endRegion = endRegions.get(0);

    // create a reduced set of RaptorData with only the stops/routes previously seen on trips
    // from the start region to the end region
    RaptorData trimmedData = new RaptorData();
    trimmedData.raptorStopsForStopId = new HashMap<AgencyAndId, RaptorStop>();
    HashSet<RaptorStop> stops = data.regionData.stops[startRegion][endRegion];
    for (RaptorStop stop : stops) {
      trimmedData.raptorStopsForStopId.put(stop.stopVertex.getStopId(), stop);
    }

    trimmedData.regionData = data.regionData;
    trimmedData.routes = data.regionData.routes[startRegion][endRegion];
    trimmedData.stops = data.stops;
    // trimmedData.allowedStops = stops;
    trimmedData.routesForStop = data.routesForStop;

    double walkDistance = options.getMaxWalkDistance();
    options = options.clone();
    walkOptions = walkOptions.clone();
    if (walkDistance > 4000) {
      // this is a really long walk. We'll almost never actually need this. So let's do our
      // preliminary search over just 4km first.
      options.setMaxWalkDistance(4000);
      walkOptions.setMaxWalkDistance(4000);
    }

    int round;
    if (trimmedData.routes.size() > 0) {
      log.debug(
          "Doing preliminary search on limited route set ("
              + trimmedData.routes.size()
              + ", "
              + stops.size()
              + ")");
      round = doPreliminarySearch(options, walkOptions, search, trimmedData);
    } else {
      round = 0;
    }

    if (search.getTargetStates().size() == 0 && walkDistance > 5000) {
      // nothing found in preliminary search
      // so we'll do a search with full set of routes & stops, but still limited distance
      log.debug("Doing preliminary search at limited distance");
      round = doPreliminarySearch(options, walkOptions, search, data);
    }

    return round;
  }
예제 #3
0
  @Override
  public List<GraphPath> getPaths(RoutingRequest options) {

    final Graph graph = graphService.getGraph(options.getRouterId());
    if (options.rctx == null) {
      options.setRoutingContext(graph);
      options.rctx.pathParsers =
          new PathParser[] {new BasicPathParser(), new NoThruTrafficPathParser()};
    }

    if (!options.getModes().isTransit()) {
      return sptService.getShortestPathTree(options).getPaths();
    }

    // also fall back to A* for short trips
    double distance =
        distanceLibrary.distance(
            options.rctx.origin.getCoordinate(), options.rctx.target.getCoordinate());
    if (distance < shortPathCutoff) {
      log.debug("Falling back to A* for very short path");
      return shortPathService.getPaths(options);
    }

    RaptorDataService service = graph.getService(RaptorDataService.class);
    if (service == null) {
      log.warn("No raptor data.  Rebuild with RaptorDataBuilder");
      return Collections.emptyList();
    }
    RaptorData data = service.getData();

    // we multiply the initial walk distance to account for epsilon dominance.
    double initialWalk = options.getMaxWalkDistance() * WALK_EPSILON;
    options.setMaxWalkDistance(initialWalk);

    // do not even bother with obviously impossible walks
    double minWalk =
        options.rctx.origin.getDistanceToNearestTransitStop()
            + options.rctx.target.getDistanceToNearestTransitStop();
    if (options.getMaxWalkDistance() < minWalk) {
      options.setMaxWalkDistance(minWalk);
    }

    RoutingRequest walkOptions = options.clone();
    walkOptions.rctx.pathParsers = new PathParser[0];
    TraverseModeSet modes = options.getModes().clone();
    modes.setTransit(false);
    walkOptions.setModes(modes);
    RaptorSearch search = new RaptorSearch(data, options);

    if (data.maxTransitRegions != null) {
      Calendar tripDate = Calendar.getInstance(graph.getTimeZone());
      tripDate.setTime(new Date(1000L * options.dateTime));

      Calendar maxTransitStart = Calendar.getInstance(graph.getTimeZone());
      maxTransitStart.set(Calendar.YEAR, data.maxTransitRegions.startYear);
      maxTransitStart.set(Calendar.MONTH, data.maxTransitRegions.startMonth);
      maxTransitStart.set(Calendar.DAY_OF_MONTH, data.maxTransitRegions.startDay);

      int day = 0;
      while (tripDate.after(maxTransitStart)) {
        day++;
        tripDate.add(Calendar.DAY_OF_MONTH, -1);
      }
      if (day > data.maxTransitRegions.maxTransit.length || options.isWheelchairAccessible()) {
        day = -1;
      }

      search.maxTimeDayIndex = day;
    }

    int rushAheadRound = preliminaryRaptorSearch(data, options, walkOptions, search);

    long searchBeginTime = System.currentTimeMillis();

    double expectedWorstTime =
        1.5
            * distanceLibrary.distance(
                options.rctx.origin.getCoordinate(), options.rctx.target.getCoordinate())
            / options.getWalkSpeed();

    int foundSoFar = 0;

    double firstWalkDistance = 0;
    List<RaptorState> targetStates = new ArrayList<RaptorState>();

    do {
      int bestElapsedTime = Integer.MAX_VALUE;
      RETRY:
      do {
        for (int round = 0; round < options.getMaxTransfers() + 2; ++round) {
          if (!round(data, options, walkOptions, search, round)) break;

          long elapsed = System.currentTimeMillis() - searchBeginTime;
          if (elapsed > multiPathTimeout * 1000 && multiPathTimeout > 0 && targetStates.size() > 0)
            break RETRY;

          ArrayList<RaptorState> toRemove = new ArrayList<RaptorState>();
          for (RaptorState state : search.getTargetStates()) {
            if (state.nBoardings == 0 && options.getMaxWalkDistance() > initialWalk) {
              toRemove.add(state);
            }
          }
          if (search.getTargetStates().size() > 0) {
            if (firstWalkDistance == 0) {
              firstWalkDistance = options.getMaxWalkDistance();
            }
            for (RaptorState state : toRemove) {
              search.removeTargetState(state.walkPath);
            }
          }
          if (targetStates.size() >= options.getNumItineraries() && round >= rushAheadRound) {
            int oldBest = bestElapsedTime;
            for (RaptorState state : search.getTargetStates()) {
              final int elapsedTime = (int) Math.abs(state.arrivalTime - options.dateTime);
              if (elapsedTime < bestElapsedTime) {
                bestElapsedTime = elapsedTime;
              }
            }

            int improvement = oldBest - bestElapsedTime;
            if (improvement < 600 && bestElapsedTime < expectedWorstTime) break RETRY;
          }
        }

        if (foundSoFar < search.getTargetStates().size()) {
          foundSoFar = search.getTargetStates().size();
        } else if (foundSoFar > 0) {
          // we didn't find anything new in this round, and we already have
          // some paths, so bail out
          break;
        }
        options = options.clone();
        walkOptions = walkOptions.clone();
        if (search.getTargetStates().size() > 0 && bestElapsedTime < expectedWorstTime) {
          // we have found some paths so we no longer want to expand the max walk distance
          break RETRY;
        } else {
          options.setMaxWalkDistance(options.getMaxWalkDistance() * 2);
          walkOptions.setMaxWalkDistance(options.getMaxWalkDistance());

          options.setWalkReluctance(options.getWalkReluctance() * 2);
          walkOptions.setWalkReluctance(options.getWalkReluctance());
        }
        search.reset(options);

      } while (options.getMaxWalkDistance() < initialWalk * MAX_WALK_MULTIPLE
          && initialWalk < Double.MAX_VALUE);

      options = options.clone();
      walkOptions = walkOptions.clone();
      for (RaptorState state : search.getTargetStates()) {
        for (AgencyAndId trip : state.getTrips()) {
          options.bannedTrips.add(trip);
        }
      }

      if (search.getTargetStates().size() == 0) break; // no paths found; searching more won't help

      options.setMaxWalkDistance(firstWalkDistance);
      walkOptions.setMaxWalkDistance(firstWalkDistance);

      targetStates.addAll(search.getTargetStates());
      search = new RaptorSearch(data, options);

    } while (targetStates.size() < options.getNumItineraries());

    collectRoutesUsed(data, options, targetStates);

    if (targetStates.isEmpty()) {
      log.info("RAPTOR found no paths");
    }
    Collections.sort(targetStates);

    if (targetStates.size() > options.getNumItineraries())
      targetStates = targetStates.subList(0, options.getNumItineraries());

    List<GraphPath> paths = new ArrayList<GraphPath>();
    for (RaptorState targetState : targetStates) {
      // reconstruct path
      ArrayList<RaptorState> states = new ArrayList<RaptorState>();
      RaptorState cur = targetState;
      while (cur != null) {
        states.add(cur);
        cur = cur.getParent();
      }
      // states is in reverse order of time
      State state = getState(targetState.getRequest(), data, states);
      paths.add(new GraphPath(state, true));
    }

    return paths;
  }