MATSIM
SpeedyALT.java
Go to the documentation of this file.
1 package org.matsim.core.router.speedy;
2 
3 import org.apache.logging.log4j.LogManager;
4 import org.apache.logging.log4j.Logger;
11 import org.matsim.vehicles.Vehicle;
12 
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.List;
17 
36 public class SpeedyALT implements LeastCostPathCalculator {
37 
38  private final static Logger LOG = LogManager.getLogger(SpeedyALT.class);
39 
40  private final SpeedyGraph graph;
41  private final SpeedyALTData astarData;
42  private final TravelTime tt;
43  private final TravelDisutility td;
44  private final double[] data; // 3 entries per node: cost to node, time, distance
45  private int currentIteration = Integer.MIN_VALUE;
46  private final int[] iterationIds;
47  private final int[] comingFrom;
48  private final int[] usedLink;
50  private final DAryMinHeap pq;
51 
52  public SpeedyALT(SpeedyALTData astarData, TravelTime tt, TravelDisutility td) {
53  this.graph = astarData.graph;
54  this.astarData = astarData;
55  this.tt = tt;
56  this.td = td;
57  this.data = new double[this.graph.nodeCount * 3];
58  this.iterationIds = new int[this.graph.nodeCount];
59  this.comingFrom = new int[this.graph.nodeCount];
60  this.usedLink = new int[this.graph.nodeCount];
61  this.pq = new DAryMinHeap(this.graph.nodeCount, 6);
62  this.outLI = this.graph.getOutLinkIterator();
63  Arrays.fill(this.iterationIds, this.currentIteration);
64  }
65 
66  public double getCost(int nodeIndex) {
67  return this.data[nodeIndex * 3];
68  }
69 
70  private double getTimeRaw(int nodeIndex) {
71  return this.data[nodeIndex * 3 + 1];
72  }
73 
74  private double getDistance(int nodeIndex) {
75  return this.data[nodeIndex * 3 + 2];
76  }
77 
78  private void setData(int nodeIndex, double cost, double time, double distance) {
79  int index = nodeIndex * 3;
80  this.data[index] = cost;
81  this.data[index + 1] = time;
82  this.data[index + 2] = distance;
83  this.iterationIds[nodeIndex] = this.currentIteration;
84  }
85 
86  @Override
87  public Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Person person, Vehicle vehicle) {
88  this.currentIteration++;
89  if (this.currentIteration == Integer.MAX_VALUE) {
90  // reset iteration as we overflow
91  Arrays.fill(this.iterationIds, this.currentIteration);
92  this.currentIteration = Integer.MIN_VALUE;
93  }
94  boolean hasTurnRestrictions = this.graph.hasTurnRestrictions();
95  int startNodeIndex = startNode.getId().index();
96  int endNodeIndex = endNode.getId().index();
97 
98  int startDeadend = this.astarData.getNodeDeadend(startNodeIndex);
99  int endDeadend = this.astarData.getNodeDeadend(endNodeIndex);
100 
101  double estimation = estimateMinTravelcostToDestination(startNodeIndex, endNodeIndex);
102 
103  this.comingFrom[startNodeIndex] = -1;
104  setData(startNodeIndex, 0, startTime, 0);
105  this.pq.clear();
106  this.pq.insert(startNodeIndex, 0 + estimation);
107  boolean foundEndNode = false;
108 
109  while (!this.pq.isEmpty()) {
110  final int nodeIdx = this.pq.poll();
111  if (nodeIdx == endNodeIndex) {
112  foundEndNode = true;
113  break;
114  }
115  // if turn restrictions are used, we might be on a colored node, so check for the original node
116  if (hasTurnRestrictions && this.graph.getNode(nodeIdx).getId().index() == endNodeIndex) {
117  foundEndNode = true;
118  endNodeIndex = nodeIdx;
119  break;
120  }
121 
122  // ignore dead-ends
123  int deadend = this.astarData.getNodeDeadend(nodeIdx);
124  if (deadend >= 0 && deadend != startDeadend && deadend != endDeadend) {
125  continue; // it's a dead-end we're not interested in
126  }
127 
128  double currTime = getTimeRaw(nodeIdx);
129  double currCost = getCost(nodeIdx);
130  double currDistance = getDistance(nodeIdx);
131 
132  this.outLI.reset(nodeIdx);
133  while (this.outLI.next()) {
134  int linkIdx = this.outLI.getLinkIndex();
135  Link link = this.graph.getLink(linkIdx);
136  int toNode = this.outLI.getToNodeIndex();
137 
138  double travelTime = this.tt.getLinkTravelTime(link, currTime, person, vehicle);
139  double newTime = currTime + travelTime;
140  double travelCost = this.td.getLinkTravelDisutility(link, currTime, person, vehicle);
141  double newCost = currCost + travelCost;
142 
143  if (this.iterationIds[toNode] == this.currentIteration) {
144  // this node was already visited in this route-query
145  double oldCost = getCost(toNode);
146  if (newCost < oldCost) {
147  estimation = estimateMinTravelcostToDestination(toNode, endNodeIndex);
148  this.pq.decreaseKey(toNode, newCost + estimation);
149  setData(toNode, newCost, newTime, currDistance + link.getLength());
150  this.comingFrom[toNode] = nodeIdx;
151  this.usedLink[toNode] = linkIdx;
152  }
153  } else {
154  estimation = estimateMinTravelcostToDestination(toNode, endNodeIndex);
155  setData(toNode, newCost, newTime, currDistance + link.getLength());
156  this.pq.insert(toNode, newCost + estimation);
157  this.comingFrom[toNode] = nodeIdx;
158  this.usedLink[toNode] = linkIdx;
159  }
160  }
161  }
162 
163  if (foundEndNode) {
164  return constructPath(endNodeIndex, startTime);
165  }
166  LOG.warn("No route was found from node " + startNode.getId() + " to node " + endNode.getId() + ". Some possible reasons:");
167  LOG.warn(" * Network is not connected. Run NetworkCleaner().") ;
168  LOG.warn(" * Network for considered mode does not even exist. Modes need to be entered for each link in network.xml.");
169  LOG.warn(" * Network for considered mode is not connected to starting or ending point of route. Setting insertingAccessEgressWalk to true may help.");
170  LOG.warn("This will now return null, but it may fail later with a NullPointerException.");
171  return null;
172  }
173 
174  private double estimateMinTravelcostToDestination(int nodeIdx, int destinationIdx) {
175  /* The ALT algorithm uses two lower bounds for each Landmark:
176  * given: source node S, target node T, landmark L
177  * then, due to the triangle inequality:
178  * 1) ST + TL >= SL --> ST >= SL - TL
179  * 2) LS + ST >= LT --> ST >= LT - LS
180  * The algorithm is interested in the largest possible value of (SL-TL) and (LT-LS),
181  * as this gives the closest approximation for the minimal travel time required to
182  * go from S to T.
183  */
184  double best = 0;
185  for (int i = 0, n = this.astarData.getLandmarksCount(); i < n; i++) {
186  double estimate = estimateMinTravelcostToDestinationForLandmark(nodeIdx, destinationIdx, i);
187  if (estimate > best) {
188  best = estimate;
189  }
190  }
191  return best;
192  }
193 
194  private double estimateMinTravelcostToDestinationForLandmark(int nodeIdx, int destinationIdx, int landmarkIdx) {
195  double sl = this.astarData.getTravelCostToLandmark(nodeIdx, landmarkIdx);
196  double ls = this.astarData.getTravelCostFromLandmark(nodeIdx, landmarkIdx);
197  double tl = this.astarData.getTravelCostToLandmark(destinationIdx, landmarkIdx);
198  double lt = this.astarData.getTravelCostFromLandmark(destinationIdx, landmarkIdx);
199  double sltl = sl - tl;
200  double ltls = lt - ls;
201  return Math.max(sltl, ltls);
202  }
203 
204  private Path constructPath(int endNodeIndex, double startTime) {
205  double travelCost = getCost(endNodeIndex);
206  double arrivalTime = getTimeRaw(endNodeIndex);
207  if (Double.isInfinite(arrivalTime)) {
208  throw new RuntimeException("Undefined time on end node");
209  }
210  double travelTime = arrivalTime - startTime;
211 
212  List<Node> nodes = new ArrayList<>();
213  List<Link> links = new ArrayList<>();
214 
215  int nodeIndex = endNodeIndex;
216 
217  nodes.add(this.graph.getNode(nodeIndex));
218 
219  int linkIndex = this.usedLink[nodeIndex];
220  nodeIndex = this.comingFrom[nodeIndex];
221 
222  while (nodeIndex >= 0) {
223  nodes.add(this.graph.getNode(nodeIndex));
224  links.add(this.graph.getLink(linkIndex));
225 
226  linkIndex = this.usedLink[nodeIndex];
227  nodeIndex = this.comingFrom[nodeIndex];
228  }
229 
230  Collections.reverse(nodes);
231  Collections.reverse(links);
232 
233  return new Path(nodes, links, travelTime, travelCost);
234  }
235 
236 }
Path constructPath(int endNodeIndex, double startTime)
Definition: SpeedyALT.java:204
void setData(int nodeIndex, double cost, double time, double distance)
Definition: SpeedyALT.java:78
double estimateMinTravelcostToDestinationForLandmark(int nodeIdx, int destinationIdx, int landmarkIdx)
Definition: SpeedyALT.java:194
double getLinkTravelTime(Link link, double time, Person person, Vehicle vehicle)
double getLinkTravelDisutility(final Link link, final double time, final Person person, final Vehicle vehicle)
final SpeedyGraph.LinkIterator outLI
Definition: SpeedyALT.java:49
double estimateMinTravelcostToDestination(int nodeIdx, int destinationIdx)
Definition: SpeedyALT.java:174
SpeedyALT(SpeedyALTData astarData, TravelTime tt, TravelDisutility td)
Definition: SpeedyALT.java:52
Path calcLeastCostPath(Node startNode, Node endNode, double startTime, Person person, Vehicle vehicle)
Definition: SpeedyALT.java:87