diff --git a/opentripplanner-routing/pom.xml b/opentripplanner-routing/pom.xml index 2d200e987a3..1fbefcb85d1 100644 --- a/opentripplanner-routing/pom.xml +++ b/opentripplanner-routing/pom.xml @@ -43,6 +43,11 @@ org.springframework spring-aop + + edu.syr.pcpratts + rootbeer + 0.1.0 + junit junit @@ -113,6 +118,59 @@ ${project.basedir}/../.git + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + package + + single + + + + jar-with-dependencies + + opentripplanner-routing + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + rootbeer + package + + run + + + + + + + + + + + + + + + + + + + diff --git a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/Raptor.java b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/Raptor.java index 485c67f3086..b660567b1e7 100644 --- a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/Raptor.java +++ b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/Raptor.java @@ -100,7 +100,7 @@ public List getPaths(RoutingRequest options) { TraverseModeSet modes = options.getModes().clone(); modes.setTransit(false); walkOptions.setModes(modes); - RaptorSearch search = new RaptorSearch(data, options); + RaptorSearch search = new RaptorSearchGPU(data, options); if (data.maxTransitRegions != null) { Calendar tripDate = Calendar.getInstance(graph.getTimeZone()); @@ -126,6 +126,7 @@ public List getPaths(RoutingRequest options) { long searchBeginTime = System.currentTimeMillis(); int bestElapsedTime = Integer.MAX_VALUE; + options.setMaxTransfers(7); RETRY: do { for (int i = 0; i < options.getMaxTransfers() + 2; ++i) { round(data, options, walkOptions, search, i); diff --git a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearch.java b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearch.java index 3effca5cbad..d312c0bf4b8 100644 --- a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearch.java +++ b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearch.java @@ -40,7 +40,7 @@ public class RaptorSearch { List[] statesByStop; - private List targetStates = new ArrayList(); + protected List targetStates = new ArrayList(); Set visitedEver = new HashSet(); @@ -58,7 +58,7 @@ public class RaptorSearch { public int maxTimeDayIndex; - private RaptorData data; + protected RaptorData data; @SuppressWarnings("unchecked") RaptorSearch(RaptorData data, RoutingRequest options) { diff --git a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearchGPU.java b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearchGPU.java new file mode 100644 index 00000000000..05e38f6ffb3 --- /dev/null +++ b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/RaptorSearchGPU.java @@ -0,0 +1,271 @@ +/* This program is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +package org.opentripplanner.routing.impl.raptor; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.opentripplanner.common.pqueue.BinHeap; +import org.opentripplanner.common.pqueue.OTPPriorityQueue; +import org.opentripplanner.common.pqueue.OTPPriorityQueueFactory; +import org.opentripplanner.routing.algorithm.GenericDijkstra; +import org.opentripplanner.routing.core.RoutingRequest; +import org.opentripplanner.routing.core.State; +import org.opentripplanner.routing.core.StateEditor; +import org.opentripplanner.routing.graph.Vertex; +import org.opentripplanner.routing.spt.ShortestPathTree; +import org.opentripplanner.routing.vertextype.TransitStop; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import edu.syr.pcpratts.rootbeer.runtime.Kernel; +import edu.syr.pcpratts.rootbeer.runtime.Rootbeer; + +class LocalSearchKernel implements Kernel { + private GenericDijkstra search; + + private RaptorSearchGPU raptor; + + private State initialState; + + private int nBoardings; + + public LocalSearchKernel(int nBoardings, State state, GenericDijkstra search, RaptorSearchGPU raptor) { + this.nBoardings = nBoardings; + this.initialState = state; + this.search = search; + this.raptor = raptor; + } + + @Override + public void gpuMethod() { + ShortestPathTree spt = search.getShortestPathTree(initialState); + SPTSTATE: for (State state : spt.getAllStates()) { + final Vertex vertex = state.getVertex(); + if (!(vertex instanceof TransitStop)) + continue; + + RaptorStop stop = raptor.data.raptorStopsForStopId.get(((TransitStop) vertex).getStopId()); + if (stop == null) + // we have found a stop is totally unused, so skip it + continue; + + 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(state.getOptions().arriveBy); + } + newState.weight = state.getWeight(); + newState.nBoardings = nBoardings; + newState.walkDistance = state.getWalkDistance(); + newState.arrivalTime = (int) state.getTime(); + newState.walkPath = state; + newState.stop = stop; + + synchronized(raptor) { + + List states = raptor.statesByStop[stop.index]; + if (states == null) { + states = new ArrayList(); + raptor.statesByStop[stop.index] = states; + } + + for (RaptorState oldState : states) { + if (oldState.eDominates(newState)) { + continue SPTSTATE; + } + } + states.add(newState); + } + synchronized(raptor.visitedLastRound) { + raptor.visitedLastRound.add(stop); + raptor.visitedEver.add(stop); + } + } + } + +} + +public class RaptorSearchGPU extends RaptorSearch { + private static final Logger log = LoggerFactory.getLogger(RaptorSearchGPU.class); + + @SuppressWarnings("unchecked") + RaptorSearchGPU(RaptorData data, RoutingRequest options) { + super(data,options); + } + public void walkPhase(RoutingRequest options, RoutingRequest walkOptions, int nBoardings, + List createdStates) { + + final double distanceToNearestTransitStop = options.rctx.target + .getDistanceToNearestTransitStop(); + ShortestPathTree spt; + GenericDijkstra dijkstra = new GenericDijkstra(walkOptions); + //dijkstra.setShortestPathTreeFactory(bounder); + + if (nBoardings == 0) { + //TODO: retry min-time bounding with this and with maxtime + + if (bounder.getTargetDistance(options.rctx.origin) < options.getMaxWalkDistance()) + dijkstra.setHeuristic(bounder); + + MaxWalkState start = new MaxWalkState(options.rctx.origin, walkOptions); + spt = dijkstra.getShortestPathTree(start); + SPTSTATE: for (State state : spt.getAllStates()) { + final Vertex vertex = state.getVertex(); + if (vertex instanceof TransitStop) { + RaptorStop stop = data.raptorStopsForStopId.get(((TransitStop) vertex).getStopId()); + if (stop == null) { + // we have found a stop is totally unused, so skip it + continue; + } + + List states = statesByStop[stop.index]; + if (states == null) { + states = new ArrayList(); + statesByStop[stop.index] = states; + } + + RaptorState newState = new RaptorState(options.arriveBy); + newState.weight = state.getWeight(); + newState.nBoardings = nBoardings; + newState.walkDistance = state.getWalkDistance(); + newState.arrivalTime = (int) state.getTime(); + newState.walkPath = state; + newState.stop = stop; + + for (RaptorState oldState : states) { + if (oldState.eDominates(newState)) { + continue SPTSTATE; + } + } + + visitedLastRound.add(stop); + visitedEver.add(stop); + states.add(newState); + } + } + + } else { + + final List startPoints = new ArrayList(); + + List jobs = new ArrayList(); + for (RaptorState state : createdStates) { + + // bounding states + // this reduces the number of initial vertices + // and the state space size + + Vertex stopVertex = state.stop.stopVertex; + + 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.setStartTime(options.dateTime); + dijkstraState.setNumBoardings(state.nBoardings); + dijkstraState.setWalkDistance(state.walkDistance); + dijkstraState.setTime(state.arrivalTime); + dijkstraState.setExtension("raptorParent", state); + dijkstraState.setOptions(walkOptions); + dijkstraState.incrementWeight(state.weight); + MaxWalkState newState = (MaxWalkState) dijkstraState.makeState(); + jobs.add(new LocalSearchKernel(nBoardings, newState, dijkstra, this)); + + } + 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); + dijkstra.setSkipTraverseResultStrategy(bounder); + + Rootbeer rootbeer = new Rootbeer(); + rootbeer.runAll(jobs); + System.out.println("Ran " + jobs.size() + " jobs"); + } + + final List targetStates = bounder.bounders; + 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; + } else { + state = new RaptorState(options.arriveBy); + } + state.weight = targetState.getWeight(); + state.walkDistance = targetState.getWalkDistance(); + state.arrivalTime = (int) targetState.getTime(); + state.walkPath = targetState; + for (Iterator 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); + } + } + for (State state : bounder.removedBoundingStates) { + removeTargetState(state); + } + } + + class PrefilledPriorityQueueFactory implements OTPPriorityQueueFactory { + + private List startPoints; + + public PrefilledPriorityQueueFactory(List startPoints) { + this.startPoints = startPoints; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public OTPPriorityQueue create(int maxSize) { + BinHeap heap = new BinHeap(); + for (State state : startPoints) { + heap.insert(state, state.getWeight()); + } + return heap; + } + + } + +} diff --git a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/TargetBound.java b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/TargetBound.java index e45b2da1c28..02ab66af89d 100644 --- a/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/TargetBound.java +++ b/opentripplanner-routing/src/main/java/org/opentripplanner/routing/impl/raptor/TargetBound.java @@ -107,11 +107,12 @@ public boolean shouldSearchContinue(Vertex origin, Vertex target, State current, } if (vertex == realTarget) { addBounder(current); + return false; } return true; } - private void addBounder(State bounder) { + private synchronized void addBounder(State bounder) { for (Iterator it = bounders.iterator(); it.hasNext(); ) { State old = it.next(); if (bounder.dominates(old)) { @@ -141,22 +142,8 @@ private void addBounder(State bounder) { public boolean shouldSkipTraversalResult(Vertex origin, Vertex target, State parent, State current, ShortestPathTree spt, RoutingRequest traverseOptions) { final Vertex vertex = current.getVertex(); - int vertexIndex = vertex.getIndex(); - if (vertexIndex < distance.length) { - if (distance[vertexIndex] > 0.0) { - targetDistance = distance[vertexIndex]; - } else { - targetDistance = distanceLibrary.fastDistance(realTargetCoordinate.y, realTargetCoordinate.x, - vertex.getY(), vertex.getX()); - distance[vertexIndex] = targetDistance; - if (vertex instanceof TransitStop && targetDistance < bestTargetDistance) { - bestTargetDistance = targetDistance; - } - } - } else { - targetDistance = distanceLibrary.fastDistance(realTargetCoordinate.y, realTargetCoordinate.x, - vertex.getY(), vertex.getX()); - } + targetDistance = distanceLibrary.fastDistance(realTargetCoordinate.y, realTargetCoordinate.x, + vertex.getY(), vertex.getX()); final double remainingWalk = traverseOptions.maxWalkDistance - current.getWalkDistance(); @@ -316,7 +303,7 @@ public ShortestPathTree create(RoutingRequest options) { public void addSptStates(List states) { for (MaxWalkState state : states) { if (state.getVertex() instanceof TransitStop) { - transitStopsVisited.add(state); + //transitStopsVisited.add(state); } spt.add(state); } diff --git a/pom.xml b/pom.xml index 0aca8f5d51a..4d67cd7827b 100644 --- a/pom.xml +++ b/pom.xml @@ -268,6 +268,18 @@ + + lib + lib + + true + ignore + + + false + + file:///home/novalis/otp/opentripplanner/opentripplanner/lib +