MATSIM
SpeedyDijkstra.java
Go to the documentation of this file.
1 package org.matsim.core.router.speedy;
2 
10 
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collections;
14 import java.util.List;
15 
22 public class SpeedyDijkstra implements LeastCostPathCalculator {
23 
24  private final SpeedyGraph graph;
25  private final TravelTime tt;
26  private final TravelDisutility td;
27  private final double[] data; // 3 entries per node: time, cost, distance
28  private int currentIteration = Integer.MIN_VALUE;
29  private final int[] iterationIds;
30  private final int[] comingFrom;
31  private final int[] usedLink;
33  private final DAryMinHeap pq;
34 
36  this.graph = graph;
37  this.tt = tt;
38  this.td = td;
39  this.data = new double[graph.nodeCount * 3];
40  this.iterationIds = new int[graph.nodeCount];
41  this.comingFrom = new int[graph.nodeCount];
42  this.usedLink = new int[graph.nodeCount];
43  this.pq = new DAryMinHeap(graph.nodeCount, 6);
44  this.outLI = graph.getOutLinkIterator();
45  }
46 
47  private double getCost(int nodeIndex) {
48  return this.data[nodeIndex * 3];
49  }
50 
51  private double getTimeRaw(int nodeIndex) {
52  return this.data[nodeIndex * 3 + 1];
53  }
54 
55  public double getDistance(int nodeIndex) {
56  return this.data[nodeIndex * 3 + 2];
57  }
58 
59  private void setData(int nodeIndex, double cost, double time, double distance) {
60  int index = nodeIndex * 3;
61  this.data[index] = cost;
62  this.data[index + 1] = time;
63  this.data[index + 2] = distance;
64  this.iterationIds[nodeIndex] = this.currentIteration;
65  }
66 
67  @Override
68  public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Person person, Vehicle vehicle) {
69  this.currentIteration++;
70  if (this.currentIteration == Integer.MAX_VALUE) {
71  // reset iteration as we overflow
72  Arrays.fill(this.iterationIds, this.currentIteration);
73  this.currentIteration = Integer.MIN_VALUE;
74  }
75 
76  boolean hasTurnRestrictions = this.graph.hasTurnRestrictions();
77  int startNodeIndex = startNode.getId().index();
78  int endNodeIndex = endNode.getId().index();
79 
80  this.comingFrom[startNodeIndex] = -1;
81  setData(startNodeIndex, 0, startTime, 0);
82  this.pq.clear();
83  this.pq.insert(startNodeIndex, 0);
84  boolean foundEndNode = false;
85 
86  while (!this.pq.isEmpty()) {
87  final int nodeIdx = this.pq.poll();
88  if (nodeIdx == endNodeIndex) {
89  foundEndNode = true;
90  break;
91  }
92  // if turn restrictions are used, we might be on a colored node, so check for the original node
93  if (hasTurnRestrictions && this.graph.getNode(nodeIdx).getId().index() == endNodeIndex) {
94  foundEndNode = true;
95  endNodeIndex = nodeIdx;
96  break;
97  }
98 
99  double currTime = getTimeRaw(nodeIdx);
100  if (Double.isInfinite(currTime)) {
101  throw new RuntimeException("Undefined Time");
102  }
103  double currCost = getCost(nodeIdx);
104  double currDistance = getDistance(nodeIdx);
105 
106  this.outLI.reset(nodeIdx);
107  while (this.outLI.next()) {
108  int linkIdx = this.outLI.getLinkIndex();
109  Link link = this.graph.getLink(linkIdx);
110  int toNode = this.outLI.getToNodeIndex();
111 
112  double travelTime = this.tt.getLinkTravelTime(link, currTime, person, vehicle);
113  double newTime = currTime + travelTime;
114  double newCost = currCost + this.td.getLinkTravelDisutility(link, currTime, person, vehicle);
115 
116  if (this.iterationIds[toNode] == this.currentIteration) {
117  // this node was already visited in this route-query
118  double oldCost = getCost(toNode);
119  if (newCost < oldCost) {
120  this.pq.decreaseKey(toNode, newCost);
121  setData(toNode, newCost, newTime, currDistance + link.getLength());
122  this.comingFrom[toNode] = nodeIdx;
123  this.usedLink[toNode] = linkIdx;
124  }
125  } else {
126  setData(toNode, newCost, newTime, currDistance + link.getLength());
127  this.pq.insert(toNode, newCost);
128  this.comingFrom[toNode] = nodeIdx;
129  this.usedLink[toNode] = linkIdx;
130  }
131  }
132  }
133 
134  if (foundEndNode) {
135  return constructPath(endNodeIndex, startTime);
136  }
137  return null;
138  }
139 
140  private Path constructPath(int endNodeIndex, double startTime) {
141  double travelCost = getCost(endNodeIndex);
142  double arrivalTime = getTimeRaw(endNodeIndex);
143  if (Double.isInfinite(arrivalTime)) {
144  throw new RuntimeException("Undefined time on end node");
145  }
146  double travelTime = arrivalTime - startTime;
147 
148  List<Node> nodes = new ArrayList<>();
149  List<Link> links = new ArrayList<>();
150 
151  int nodeIndex = endNodeIndex;
152 
153  nodes.add(this.graph.getNode(nodeIndex));
154 
155  int linkIndex = this.usedLink[nodeIndex];
156  nodeIndex = this.comingFrom[nodeIndex];
157 
158  while (nodeIndex >= 0) {
159  nodes.add(this.graph.getNode(nodeIndex));
160  links.add(this.graph.getLink(linkIndex));
161 
162  linkIndex = this.usedLink[nodeIndex];
163  nodeIndex = this.comingFrom[nodeIndex];
164  }
165 
166  Collections.reverse(nodes);
167  Collections.reverse(links);
168 
169  return new Path(nodes, links, travelTime, travelCost);
170  }
171 }
SpeedyDijkstra(SpeedyGraph graph, TravelTime tt, TravelDisutility td)
final SpeedyGraph.LinkIterator outLI
void setData(int nodeIndex, double cost, double time, double distance)
double getLinkTravelTime(Link link, double time, Person person, Vehicle vehicle)
double getLinkTravelDisutility(final Link link, final double time, final Person person, final Vehicle vehicle)
Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Person person, Vehicle vehicle)
Path constructPath(int endNodeIndex, double startTime)