Package org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern

Source Code of org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.TransferPatternsTask

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.onebusaway.collections.Counter;
import org.onebusaway.collections.FactoryMap;
import org.onebusaway.collections.Range;
import org.onebusaway.collections.tuple.Pair;
import org.onebusaway.collections.tuple.Tuples;
import org.onebusaway.geospatial.model.CoordinateBounds;
import org.onebusaway.geospatial.services.SphericalGeometryLibrary;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.calendar.ServiceDate;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.HasStopTimeInstanceTransitVertex;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.TPOfflineBlockArrivalVertex;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.TPOfflineNearbyStopsVertex;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.TPOfflineOriginVertex;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.TPOfflineTransferEdge;
import org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.graph.TPOfflineTransferVertex;
import org.onebusaway.transit_data_federation.impl.otp.GraphContext;
import org.onebusaway.transit_data_federation.impl.otp.OBAState;
import org.onebusaway.transit_data_federation.impl.otp.OBATraverseOptions;
import org.onebusaway.transit_data_federation.impl.otp.graph.HasStopTransitVertex;
import org.onebusaway.transit_data_federation.model.ServiceDateSummary;
import org.onebusaway.transit_data_federation.services.AgencyAndIdLibrary;
import org.onebusaway.transit_data_federation.services.FederatedTransitDataBundle;
import org.onebusaway.transit_data_federation.services.StopScheduleService;
import org.onebusaway.transit_data_federation.services.StopTimeService;
import org.onebusaway.transit_data_federation.services.StopTimeService.EFrequencyStopTimeBehavior;
import org.onebusaway.transit_data_federation.services.otp.OTPConfigurationService;
import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.tripplanner.ItinerariesService;
import org.onebusaway.transit_data_federation.services.tripplanner.StopTimeInstance;
import org.onebusaway.utility.IOLibrary;
import org.opentripplanner.routing.algorithm.GenericDijkstra;
import org.opentripplanner.routing.algorithm.strategies.SkipTraverseResultStrategy;
import org.opentripplanner.routing.core.Edge;
import org.opentripplanner.routing.core.EdgeNarrative;
import org.opentripplanner.routing.core.Graph;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.TraverseOptions;
import org.opentripplanner.routing.core.Vertex;
import org.opentripplanner.routing.pqueue.PriorityQueueImpl;
import org.opentripplanner.routing.services.GraphService;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.routing.spt.MultiShortestPathTree;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.springframework.beans.factory.annotation.Autowired;

public class TransferPatternsTask implements Runnable {

  private static StateDurationComparator _sptVertexDurationComparator = new StateDurationComparator();

  private FederatedTransitDataBundle _bundle;

  private TransitGraphDao _transitGraphDao;

  private GraphService _graphService;

  private OTPConfigurationService _otpConfigurationService;

  private StopScheduleService _stopScheduleService;

  private StopTimeService _stopTimeService;

  private ItinerariesService _itinerariesService;

  private int _serviceDateCount = 4;

  private double _transferPatternFrequencyCutoff = 0.1;

  private double _transferPatternFrequencySlack = 0.5;

  private double _transferPatternWeightImprovement = 0.66;

  private int _maxPathCountForLocalStop = 3;

  private int _maxPathCountForHubStop = 5;

  private double _nearbyStopsRadius = 100;

  private boolean _useHubStopsAsSourceStops = false;

  private boolean _useAllStopsAsSourceStops = false;

  @Autowired
  public void setBundle(FederatedTransitDataBundle bundle) {
    _bundle = bundle;
  }

  @Autowired
  public void setTransitGraphDao(TransitGraphDao transitGraphDao) {
    _transitGraphDao = transitGraphDao;
  }

  @Autowired
  public void setGraphProvider(GraphService graphService) {
    _graphService = graphService;
  }

  @Autowired
  public void setOtpConfigurationService(
      OTPConfigurationService otpConfigurationService) {
    _otpConfigurationService = otpConfigurationService;
  }

  @Autowired
  public void setStopScheduleService(StopScheduleService stopScheduleService) {
    _stopScheduleService = stopScheduleService;
  }

  @Autowired
  public void setStopTimeService(StopTimeService stopTimeService) {
    _stopTimeService = stopTimeService;
  }

  @Autowired
  public void setItinerariesService(ItinerariesService itinerariesService) {
    _itinerariesService = itinerariesService;
  }

  public void setServiceDateCount(int serviceDateCount) {
    _serviceDateCount = serviceDateCount;
  }

  public void setTransferPatternFrequencyCutoff(
      double transferPatternFrequencyCutoff) {
    _transferPatternFrequencyCutoff = transferPatternFrequencyCutoff;
  }

  public void setTransferPatternFrequencySlack(
      double transferPatternFrequencySlack) {
    _transferPatternFrequencySlack = transferPatternFrequencySlack;
  }

  public void setMaxPathCountForLocalStop(int maxPathCountForLocalStop) {
    _maxPathCountForLocalStop = maxPathCountForLocalStop;
  }

  public void setMaxPathCountForHubStop(int maxPathCountForHubStop) {
    _maxPathCountForHubStop = maxPathCountForHubStop;
  }

  public void setUseHubStopsAsSourceStops(boolean useHubStopsAsSourceStops) {
    _useHubStopsAsSourceStops = useHubStopsAsSourceStops;
  }

  public void setUseAllStopsAsSourceStops(boolean useAllStopsAsSourceStops) {
    _useAllStopsAsSourceStops = useAllStopsAsSourceStops;
  }

  @Override
  public void run() {

    long tIn = System.currentTimeMillis();

    List<StopEntry> hubStops = loadHubStops();
    List<StopEntry> stops = loadSourceStops(hubStops);

    Set<StopEntry> hubStopsAsSet = new HashSet<StopEntry>(hubStops);

    Graph graph = _graphService.getGraph();
    GraphContext context = _otpConfigurationService.createGraphContext();

    Map<AgencyAndId, MutableTransferPattern> patternsByStopId = new HashMap<AgencyAndId, MutableTransferPattern>();

    for (StopEntry stop : stops) {

      Map<StopEntry, Integer> nearbyStopsAndWalkTimes = getNearbyStopsAndWalkTimes(stop);

      boolean isHubStop = hubStopsAsSet.contains(stop);
      System.out.println("stop=" + stop.getId() + " hub=" + isHubStop);

      List<ServiceDate> serviceDates = computeServiceDates(stop);

      Map<StopEntry, Counter<List<Pair<StopEntry>>>> pathCountsByStop = new FactoryMap<StopEntry, Counter<List<Pair<StopEntry>>>>(
          new Counter<List<Pair<StopEntry>>>());

      for (ServiceDate serviceDate : serviceDates) {

        System.out.println("  serviceDate=" + serviceDate);

        List<StopTimeInstance> instances = getStopTimeInstancesForStopAndServiceDate(
            stop, serviceDate);
        System.out.println("      instances=" + instances.size());

        if (instances.isEmpty())
          continue;

        StopTimeInstance first = instances.get(0);
        long tFrom = first.getDepartureTime();

        Map<StopEntry, List<StopTimeInstance>> nearbyStopTimeInstances = getNearbyStopTimeInstances(
            nearbyStopsAndWalkTimes.keySet(), serviceDate);

        OBATraverseOptions options = _otpConfigurationService.createTraverseOptions();

        options.maxComputationTime = -1;
        options.waitAtBeginningFactor = 1.0;
        options.extraSpecialMode = true;
        if (isHubStop)
          options.maxTransfers = Integer.MAX_VALUE;
        else
          options.maxTransfers = 2;

        GenericDijkstra dijkstra = new GenericDijkstra(graph, options);
        dijkstra.setSkipTraverseResultStrategy(new SkipVertexImpl(stop, tFrom));
        dijkstra.setShortestPathTreeFactory(MultiShortestPathTree.FACTORY);
        dijkstra.setPriorityQueueFactory(PriorityQueueImpl.FACTORY);

        TPOfflineOriginVertex origin = new TPOfflineOriginVertex(context, stop,
            instances, nearbyStopsAndWalkTimes, nearbyStopTimeInstances);
        State state = new OBAState(tFrom, origin, options);

        MultiShortestPathTree spt = (MultiShortestPathTree) dijkstra.getShortestPathTree(state);

        processTree(spt, stop, pathCountsByStop);
      }

      MutableTransferPattern pattern = new MutableTransferPattern(stop);

      System.out.println("arrivalStops=" + pathCountsByStop.size());

      for (Map.Entry<StopEntry, Counter<List<Pair<StopEntry>>>> entry : pathCountsByStop.entrySet()) {
        boolean verbose = false;// entry.getKey().getId().toString().equals("1_29430");
        Counter<List<Pair<StopEntry>>> pathCounts = entry.getValue();
        List<List<Pair<StopEntry>>> keys = pathCounts.getSortedKeys();
        int maxCount = isHubStop ? _maxPathCountForHubStop
            : _maxPathCountForLocalStop;
        if (verbose) {
          for (List<Pair<StopEntry>> path : keys)
            System.out.println(pathCounts.getCount(path) + "\t" + path);
        }
        while (keys.size() > maxCount)
          keys.remove(0);
        for (List<Pair<StopEntry>> path : keys)
          pattern.addPath(path);
      }

      avgPaths(pattern, stop);

      patternsByStopId.put(stop.getId(), pattern);
    }

    writeData(patternsByStopId);

    long tOut = System.currentTimeMillis();
    int duration = (int) ((tOut - tIn) / 1000);
    System.out.println("duration=" + duration);
  }

  private void writeData(
      Map<AgencyAndId, MutableTransferPattern> patternsByStopId) {

    File path = _bundle.getTransferPatternsPath();

    try {

      PrintWriter out = new PrintWriter(IOLibrary.getFileAsWriter(path));

      long index = 0;
      for (MutableTransferPattern pattern : patternsByStopId.values()) {
        index = pattern.writeTransferPatternsToPrintWriter(out, index);
      }
      out.close();
    } catch (Throwable ex) {
      throw new IllegalStateException("error writing output to " + path, ex);
    }
  }

  private void avgPaths(MutableTransferPattern pattern, StopEntry origin) {
    /*
     * DoubleArrayList values = new DoubleArrayList(); for (StopEntry stop :
     * pattern.getStops()) { TransferParent root = new TransferParent();
     * pattern.getTransfersForStop(stop, root); values.add(root.size()); }
     *
     * if (values.isEmpty()) return;
     *
     * values.sort();
     *
     * System.out.println("    mu=" + Descriptive.mean(values));
     * System.out.println("median=" + Descriptive.median(values));
     * System.out.println("   max=" + Descriptive.max(values));
     */
  }

  private List<StopEntry> loadSourceStops(List<StopEntry> hubStops) {

    List<StopEntry> stops = new ArrayList<StopEntry>();

    String key = _bundle.getKey();
    String totalTaskCountValue = System.getProperty("totalTaskCount");

    if (key != null && totalTaskCountValue != null) {
      int taskIndex = Integer.parseInt(key);
      int totalTaskCount = Integer.parseInt(totalTaskCountValue);

      List<StopEntry> allStops = _transitGraphDao.getAllStops();
      if (_useHubStopsAsSourceStops)
        allStops = hubStops;

      double stopsPerTask = (double) allStops.size() / totalTaskCount;
      int from = (int) (taskIndex * stopsPerTask);
      int to = (int) ((taskIndex + 1) * stopsPerTask);

      for (int i = from; i < to; i++) {
        stops.add(allStops.get(i));
      }

      return stops;
    }

    if (_useAllStopsAsSourceStops)
      return _transitGraphDao.getAllStops();

    if (_useHubStopsAsSourceStops)
      return hubStops;

    File path = _bundle.getTransferPatternsSourceStopsPath();

    try {
      BufferedReader reader = new BufferedReader(new FileReader(path));
      String line = null;
      while ((line = reader.readLine()) != null) {
        AgencyAndId stopId = AgencyAndIdLibrary.convertFromString(line);
        StopEntry stop = _transitGraphDao.getStopEntryForId(stopId, true);
        stops.add(stop);
      }
    } catch (IOException ex) {
      throw new IllegalStateException("error reading hub stops", ex);
    }

    return stops;
  }

  private List<StopEntry> loadHubStops() {

    List<StopEntry> hubStops = new ArrayList<StopEntry>();
    File path = _bundle.getHubStopsPath(false);

    if (path.exists()) {
      try {
        BufferedReader reader = new BufferedReader(new FileReader(path));
        String line = null;
        while ((line = reader.readLine()) != null) {
          int index = line.indexOf('\t');
          if (index != -1)
            line = line.substring(index + 1);
          AgencyAndId stopId = AgencyAndIdLibrary.convertFromString(line);
          StopEntry stop = _transitGraphDao.getStopEntryForId(stopId, true);
          hubStops.add(stop);
        }
      } catch (IOException ex) {
        throw new IllegalStateException("error loading HubStops file: " + path,
            ex);
      }
    }
    return hubStops;
  }

  private Map<StopEntry, Integer> getNearbyStopsAndWalkTimes(StopEntry stop) {

    CoordinateBounds bounds = SphericalGeometryLibrary.bounds(
        stop.getStopLocation(), _nearbyStopsRadius);

    Map<StopEntry, Integer> nearbyStopsAndWalkTimes = new HashMap<StopEntry, Integer>();

    OBATraverseOptions opts = _otpConfigurationService.createTraverseOptions();
    Date now = new Date();

    List<StopEntry> stops = _transitGraphDao.getStopsByLocation(bounds);
    for (StopEntry nearbyStop : stops) {

      if (nearbyStop == stop)
        continue;

      GraphPath path = _itinerariesService.getWalkingItineraryBetweenStops(
          stop, nearbyStop, now, opts);
      if (path == null)
        continue;

      int duration = (int) (path.getDuration() / 1000);
      nearbyStopsAndWalkTimes.put(nearbyStop, duration);
    }

    return nearbyStopsAndWalkTimes;
  }

  private Map<StopEntry, List<StopTimeInstance>> getNearbyStopTimeInstances(
      Iterable<StopEntry> nearbyStops, ServiceDate serviceDate) {
    Map<StopEntry, List<StopTimeInstance>> nearbyStopTimeInstances = new HashMap<StopEntry, List<StopTimeInstance>>();
    for (StopEntry nearbyStop : nearbyStops) {
      List<StopTimeInstance> nearbyInstances = getStopTimeInstancesForStopAndServiceDate(
          nearbyStop, serviceDate);
      nearbyStopTimeInstances.put(nearbyStop, nearbyInstances);
    }
    return nearbyStopTimeInstances;
  }

  private List<ServiceDate> computeServiceDates(StopEntry stop) {

    List<ServiceDateSummary> summaries = _stopScheduleService.getServiceDateSummariesForStop(
        stop.getId(), false);
    Collections.sort(summaries);

    List<ServiceDate> serviceDates = new ArrayList<ServiceDate>();

    int floor = Math.max(0, summaries.size() - _serviceDateCount);

    for (int i = summaries.size() - 1; i >= floor; i--) {
      ServiceDateSummary summary = summaries.get(i);
      List<ServiceDate> dates = summary.getDates();
      serviceDates.add(dates.get(dates.size() / 2));
    }

    return serviceDates;
  }

  private List<StopTimeInstance> getStopTimeInstancesForStopAndServiceDate(
      StopEntry stop, ServiceDate serviceDate) {

    Range interval = _stopTimeService.getDepartureForStopAndServiceDate(
        stop.getId(), serviceDate);

    if (interval.isEmpty())
      return Collections.emptyList();

    long tFrom = (long) interval.getMin();
    long tTo = (long) interval.getMax();

    return _stopTimeService.getStopTimeInstancesInTimeRange(stop, new Date(
        tFrom), new Date(tTo), EFrequencyStopTimeBehavior.INCLUDE_INTERPOLATED);
  }

  private void processTree(MultiShortestPathTree spt, StopEntry originStop,
      Map<StopEntry, Counter<List<Pair<StopEntry>>>> pathCountsByStop) {

    Map<State, List<StopEntry>> parentsByState = new HashMap<State, List<StopEntry>>();
    Map<State, StopEntry> actualOriginStops = new HashMap<State, StopEntry>();

    Map<StopEntry, List<TPOfflineBlockArrivalVertex>> arrivalsByStop = new FactoryMap<StopEntry, List<TPOfflineBlockArrivalVertex>>(
        new ArrayList<TPOfflineBlockArrivalVertex>());

    for (Vertex v : spt.getVeritces()) {
      if (!(v instanceof TPOfflineBlockArrivalVertex))
        continue;

      TPOfflineBlockArrivalVertex bav = (TPOfflineBlockArrivalVertex) v;
      StopEntry stop = bav.getStop();
      arrivalsByStop.get(stop).add(bav);
    }

    for (Map.Entry<StopEntry, List<TPOfflineBlockArrivalVertex>> entry : arrivalsByStop.entrySet()) {
      processArrivalsForStop(entry.getKey(), entry.getValue(), originStop, spt,
          actualOriginStops, parentsByState, pathCountsByStop);
    }
  }

  private void processArrivalsForStop(StopEntry arrivalStop,
      List<TPOfflineBlockArrivalVertex> arrivals, StopEntry originStop,
      MultiShortestPathTree spt, Map<State, StopEntry> actualOriginStops,
      Map<State, List<StopEntry>> parentsByState,
      Map<StopEntry, Counter<List<Pair<StopEntry>>>> pathCountsByStop) {

    Collections.sort(arrivals);

    Counter<List<Pair<StopEntry>>> pathCounts = new Counter<List<Pair<StopEntry>>>();
    Map<List<Pair<StopEntry>>, List<State>> paths = new FactoryMap<List<Pair<StopEntry>>, List<State>>(
        new ArrayList<State>());

    SortedMap<Long, List<State>> m = new TreeMap<Long, List<State>>();
    m = FactoryMap.createSorted(m, new ArrayList<State>());

    Map<State, List<Pair<StopEntry>>> pathsByVertex = new HashMap<State, List<Pair<StopEntry>>>();

    boolean verbose = false;// arrivalStop.getId().toString().equals("1_29430");
    if (verbose)
      System.out.println("here!");

    long startTime = 0;
    int totalPathCount = 0;

    boolean atLeastOneArrivalWithProperOrigins = false;

    for (TPOfflineBlockArrivalVertex arrival : arrivals) {

      if (verbose)
        System.out.println(arrival);

      Collection<State> states = pruneSptVertices(spt.getStates(arrival));

      for (State state : states) {

        if (verbose)
          System.out.println("  " + state);

        StopEntry actualOriginStop = getActualOriginStop(state,
            actualOriginStops);
        boolean properOrigins = originStop == actualOriginStop;

        if (verbose)
          System.out.println("  origins=" + properOrigins);

        boolean cut = state.getStartTime() <= startTime;

        if (!cut) {

          if (properOrigins)
            atLeastOneArrivalWithProperOrigins = true;

          startTime = state.getStartTime();
          totalPathCount++;

          List<Pair<StopEntry>> path = constructTransferPattern(arrival, state,
              parentsByState);

          pathCounts.increment(path);
          paths.get(path).add(state);

          m.get(state.getTime()).add(state);
          pathsByVertex.put(state, path);

          if (verbose)
            System.out.println("  path=" + path);
        }
      }
    }

    if (!atLeastOneArrivalWithProperOrigins)
      return;

    List<Pair<StopEntry>> max = pathCounts.getMax();
    int maxCount = pathCounts.getCount(max);

    List<List<Pair<StopEntry>>> toKeep = new ArrayList<List<Pair<StopEntry>>>();

    for (List<Pair<StopEntry>> path : pathCounts.getSortedKeys()) {

      int count = pathCounts.getCount(path);

      if (count <= _transferPatternFrequencyCutoff * maxCount) {

        List<State> states = paths.get(path);
        boolean keep = false;

        for (State state : states) {

          long t = state.getTime();
          State nextState = getNextVertex(m, pathsByVertex, t, path);
          if (nextState == null) {
            keep = true;
            break;
          }
          int duration = (int) (Math.abs(state.getTime() - state.getStartTime()) / 1000);
          double additional = ((nextState.getTime() - state.getTime()) / 1000);
          if (additional / duration > _transferPatternFrequencySlack) {
            keep = true;
            break;
          }
        }

        if (!keep)
          continue;
      }

      if (path.get(0).getFirst() == originStop)
        toKeep.add(path);
    }

    Counter<List<Pair<StopEntry>>> counts = pathCountsByStop.get(arrivalStop);
    for (List<Pair<StopEntry>> path : toKeep) {
      int count = pathCounts.getCount(path);
      counts.increment(path, count);
      if (verbose)
        System.out.println(count + "\t" + path);
    }
  }

  private Collection<State> pruneSptVertices(Collection<State> sptVerticesOrig) {

    if (sptVerticesOrig.size() == 1)
      return sptVerticesOrig;

    List<State> sptVertices = new ArrayList<State>(sptVerticesOrig);

    /**
     * This will put the spt vertices in order of increasing trip duration
     */
    Collections.sort(sptVertices, _sptVertexDurationComparator);

    double bestRatio = Double.MAX_VALUE;

    for (int i = 0; i < sptVertices.size(); i++) {
      State state = sptVertices.get(i);
      double duration = getStateDuration(state);
      double weight = state.getWeight();
      double ratio = weight / duration;

      if (ratio / bestRatio > _transferPatternWeightImprovement) {
        return sptVertices.subList(0, i);
      } else {
        bestRatio = ratio;
      }
    }

    return sptVertices;

  }

  private State getNextVertex(SortedMap<Long, List<State>> m,
      Map<State, List<Pair<StopEntry>>> pathsByVertex, long t,
      List<Pair<StopEntry>> currentPath) {

    SortedMap<Long, List<State>> after = m.tailMap(t + 1);

    for (List<State> sptVertices : after.values()) {
      for (State sptVertex : sptVertices) {
        List<Pair<StopEntry>> path = pathsByVertex.get(sptVertex);
        if (!path.equals(currentPath))
          return sptVertex;
      }
    }

    return null;
  }

  private StopEntry getActualOriginStop(State state,
      Map<State, StopEntry> actualOriginStops) {

    StopEntry actual = actualOriginStops.get(state);
    if (actual == null) {
      Vertex v = state.getVertex();
      if (v instanceof TPOfflineNearbyStopsVertex) {
        TPOfflineNearbyStopsVertex nsv = (TPOfflineNearbyStopsVertex) v;
        actual = nsv.getStop();
      } else if (v instanceof TPOfflineOriginVertex) {
        TPOfflineOriginVertex originVertex = (TPOfflineOriginVertex) v;
        actual = originVertex.getStop();
      } else {
        actual = getActualOriginStop(state.getBackState(), actualOriginStops);
      }
      actualOriginStops.put(state, actual);
    }

    return actual;
  }

  private List<Pair<StopEntry>> constructTransferPattern(
      TPOfflineBlockArrivalVertex arrival, State sptVertex,
      Map<State, List<StopEntry>> parentsByState) {

    List<StopEntry> path = computeParentsForState(sptVertex, parentsByState);

    path = new ArrayList<StopEntry>(path);
    path.add(arrival.getStop());

    if (path.size() % 2 != 0)
      throw new IllegalArgumentException();

    List<Pair<StopEntry>> pairs = new ArrayList<Pair<StopEntry>>();

    for (int i = 0; i < path.size(); i += 2)
      pairs.add(Tuples.pair(path.get(i), path.get(i + 1)));

    return pairs;
  }

  private List<StopEntry> computeParentsForState(State state,
      Map<State, List<StopEntry>> parentsByState2) {

    List<StopEntry> parent = parentsByState2.get(state);

    if (parent != null)
      return parent;

    Vertex v = state.getVertex();

    if (v instanceof TPOfflineNearbyStopsVertex) {
      TPOfflineNearbyStopsVertex nsv = (TPOfflineNearbyStopsVertex) v;
      return Arrays.asList(nsv.getStop());
    } else if (v instanceof TPOfflineOriginVertex) {
      TPOfflineOriginVertex originVertex = (TPOfflineOriginVertex) v;
      return Arrays.asList(originVertex.getStop());
    }

    Edge payload = state.getBackEdge();
    EdgeNarrative narrative = state.getBackEdgeNarrative();

    if (payload instanceof TPOfflineTransferEdge) {

      TPOfflineBlockArrivalVertex fromV = (TPOfflineBlockArrivalVertex) narrative.getFromVertex();
      TPOfflineTransferVertex toV = (TPOfflineTransferVertex) narrative.getToVertex();

      List<StopEntry> incomingPattern = computeParentsForState(
          state.getBackState(), parentsByState2);
      ArrayList<StopEntry> extendedPattern = new ArrayList<StopEntry>(
          incomingPattern);

      extendedPattern.add(fromV.getStop());
      extendedPattern.add(toV.getStop());

      parent = extendedPattern;

    } else {
      parent = computeParentsForState(state.getBackState(), parentsByState2);
    }

    parentsByState2.put(state, parent);

    return parent;
  }

  private static int getStateDuration(State state) {
    return (int) (Math.abs(state.getTime() - state.getStartTime()) / 1000);
  }

  private static class SkipVertexImpl implements SkipTraverseResultStrategy {

    private final Set<StopEntry> _stops = new HashSet<StopEntry>();

    private final StopEntry _originStop;

    private final long _serviceDate;

    public SkipVertexImpl(StopEntry originStop, long serviceDate) {
      _originStop = originStop;
      _serviceDate = serviceDate;
    }

    @Override
    public boolean shouldSkipTraversalResult(Vertex origin, Vertex target,
        State parent, State current, ShortestPathTree spt,
        TraverseOptions traverseOptions) {

      EdgeNarrative narrative = current.getBackEdgeNarrative();
      Vertex vertex = narrative.getToVertex();

      /**
       * We prune any arrivals that loop back to the origin stop
       */
      if (vertex instanceof TPOfflineBlockArrivalVertex) {
        TPOfflineBlockArrivalVertex bav = (TPOfflineBlockArrivalVertex) vertex;
        StopTimeInstance instance = bav.getInstance();
        if (instance.getStop() == _originStop)
          return true;
      }

      /**
       * Skip a vertex that has moved on to the next service date
       */
      if (vertex instanceof HasStopTimeInstanceTransitVertex) {
        HasStopTimeInstanceTransitVertex v = (HasStopTimeInstanceTransitVertex) vertex;
        StopTimeInstance instance = v.getInstance();
        if (instance.getServiceDate() > _serviceDate + 12 * 60 * 60 * 1000)
          return true;
      }

      /**
       * Print the visited stop count as a show of progress
       */
      if (vertex instanceof HasStopTransitVertex) {
        HasStopTransitVertex v = (HasStopTransitVertex) vertex;
        StopEntry stop = v.getStop();
        if (_stops.add(stop) && _stops.size() % 100 == 0) {
          System.out.println("stops=" + _stops.size());
          if (_stops.size() == 13900)
            System.out.println("here");
        }
      }

      return false;
    }

  }

  private static class StateDurationComparator implements Comparator<State> {

    @Override
    public int compare(State o1, State o2) {
      int t1 = getStateDuration(o1);
      int t2 = getStateDuration(o2);
      if (t1 != t2)
        return (t1 < t2 ? -1 : 1);

      double w1 = o1.getWeight();
      double w2 = o2.getWeight();
      return Double.compare(w1, w2);
    }
  }
}
TOP

Related Classes of org.onebusaway.transit_data_federation.bundle.tasks.transfer_pattern.TransferPatternsTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.