MATSIM
TransitLeastCostPathTree.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * TransitDijkstra.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2009 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.pt.router;
22 
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 
31 import org.matsim.api.core.v01.Id;
47 import org.matsim.vehicles.Vehicle;
48 
72 
76  protected Network network;
77 
82 
86  private final TravelTime timeFunction;
87 
88  private final HashMap<Id<Node>, DijkstraNodeData> nodeData;
89  private Person person = null;
90  private Vehicle vehicle = null;
92  private Map<Node, InitialNode> fromNodes = null;
93 
95 
96  public TransitLeastCostPathTree(final Network network, final TransitTravelDisutility costFunction,
97  final TravelTime timeFunction,
98  final Map<Node, InitialNode> fromNodes, final Person person) {
99  this.network = network;
100  this.costFunction = costFunction;
101  this.timeFunction = timeFunction;
102 
103  this.nodeData = new HashMap<>((int)(network.getNodes().size() * 1.1), 0.95f);
104 
105  //create tree
106  this.resetNetworkVisited();
107  this.person = person;
108  this.customDataManager.reset();
109  this.fromNodes = fromNodes;
110 
111  pendingNodes = (RouterPriorityQueue<Node>) createRouterPriorityQueue();
112  for (Map.Entry<Node, InitialNode> entry : fromNodes.entrySet()) {
113  DijkstraNodeData data = getData(entry.getKey());
114  visitNode(entry.getKey(), data, pendingNodes, entry.getValue().initialTime, entry.getValue().initialCost, null);
115  }
116 
117  // do the real work
118  while (pendingNodes.size() > 0) {
119  Node outNode = pendingNodes.poll();
120  relaxNode(outNode, pendingNodes);
121  }
122  }
123 
124  public TransitLeastCostPathTree(final Network network, final TransitTravelDisutility costFunction,
125  final TravelTime timeFunction,
126  final Map<Node, InitialNode> fromNodes, final Map<Node, InitialNode> toNodes,
127  final Person person) {
128  this.network = network;
129  this.costFunction = costFunction;
130  this.timeFunction = timeFunction;
131 
132  this.nodeData = new HashMap<>((int)(network.getNodes().size() * 1.1), 0.95f);
133 
134  //create tree
135  this.resetNetworkVisited();
136  this.person = person;
137  this.customDataManager.reset();
138  this.fromNodes = fromNodes;
139 
140  pendingNodes = (RouterPriorityQueue<Node>) createRouterPriorityQueue();
141  for (Map.Entry<Node, InitialNode> entry : fromNodes.entrySet()) {
142  DijkstraNodeData data = getData(entry.getKey());
143  visitNode(entry.getKey(), data, pendingNodes, entry.getValue().initialTime, entry.getValue().initialCost, null);
144  }
145 
146  expandNodeData(toNodes);
147  }
148 
149  private int getIterationId() {
150 // TODO could delete all the now unnecessary occurrences of the IterationID especially in DijkstraNodeData and
151 // TODO replace it with a flag visited but that would interfere the useage of the MultiNodeDijkstra
152  return 0;
153  }
154 
158  private void resetNetworkVisited() {
159  for (Node node : this.network.getNodes().values()) {
160  DijkstraNodeData data = getData(node);
161  data.resetVisited();
162  }
163  }
164 
165  private void expandNodeData(final Map<Node, InitialNode> toNodes) {
166  Set<Node> endNodes = new HashSet<>(toNodes.keySet());
167  double minCost = Double.POSITIVE_INFINITY;
168 
169  // do the real work
170  while (endNodes.size() > 0) {
171  Node outNode = pendingNodes.poll();
172 
173  if (outNode == null) {
174  // seems we have no more nodes left, but not yet reached all endNodes...
175  endNodes.clear();
176  } else {
177  DijkstraNodeData data = getData(outNode);
178  boolean isEndNode = endNodes.remove(outNode);
179  if (isEndNode) {
180  InitialNode initData = toNodes.get(outNode);
181  double cost = data.getCost() + initData.initialCost;
182  if (cost < minCost) {
183  minCost = cost;
184  }
185  }
186  if (data.getCost() > minCost) {
187  endNodes.clear(); // we can't get any better now
188  } else {
189  relaxNode(outNode, pendingNodes);
190  }
191  }
192  }
193  }
194 
206  public InternalTransitPassengerRoute getTransitPassengerRoute(final Map<Node, InitialNode> toNodes) {
207  //find the best node
208  double minCost = Double.POSITIVE_INFINITY;
209  Node minCostNode = null;
210  for (Map.Entry<Node,InitialNode> e : toNodes.entrySet()) {
211  Node currentNode = e.getKey();
212  DijkstraNodeData r = this.nodeData.get(currentNode.getId());
213  if (r == null) {
214  expandNodeData(toNodes);
215  }
216  DijkstraNodeData data = getData(currentNode);
217  InitialNode initData = e.getValue();
218  double cost = data.getCost() + initData.initialCost;
219  if (data.getCost() != 0.0 || fromNodes.containsKey(currentNode)) {
220  if (cost < minCost) {
221  minCost = cost;
222  minCostNode = currentNode;
223  }
224  }
225  }
226 
227  if (minCostNode == null) {
228  return null;
229  }
230 
231  // now construct route segments, which are required for TransitPassengerRoute
232  List<RouteSegment> routeSegments = new ArrayList<>();
233 
235  TransitRouterNetworkLink downstreamLink = null;
236  Node previousFromNode = minCostNode;
237  double transferCost = 0.;
238 
239  while (link != null) {
240  TransitRouterNetworkNode fromNode = link.fromNode;
241  TransitRouterNetworkNode toNode = link.toNode;
242 
243  double travelTime = getData(toNode).getTime() - getData(fromNode).getTime();
244  Id<TransitLine> transitLineId = null;
245  Id<TransitRoute> routeId = null;
246 
247  boolean isTransferLeg = false;
248  if (link.line==null) isTransferLeg = true;
249  else {
250  transitLineId = link.line.getId();
251  routeId = link.route.getId();
252  }
253 
254  if (downstreamLink==null && isTransferLeg) {
255  // continuous transfers: see TransitRouterImplTest.testDoubleWalk.
256  // Another possibility is that trip start with transfer itself, see TransitRouterImplTest.testDoubleWalkOnly.
257  double tempTravelTime = 0.;
258  TransitStopFacility toStop = null;
259 
260  if (routeSegments.size()==0) { // very first leg starts with transfer
261  toStop = toNode.stop.getStopFacility();
262  } else {
263  RouteSegment routeSegment = routeSegments.remove(0);
264  travelTime = routeSegment.travelTime;
265  toStop = routeSegment.toStop;
266  }
267 
268  routeSegments.add(0,
269  new RouteSegment(fromNode.stop.getStopFacility(),
270  toStop,
271  tempTravelTime+travelTime,
272  transitLineId,
273  routeId));
274  //not sure, if transferCost will be included for every transfer or not. Currently, transfer cost will be accumulated for every transfer. Amit Sep'17
275  } else if (downstreamLink == null // very first pt leg or first pt leg after transfer
276  || isTransferLeg ) {
277  routeSegments.add(0, new RouteSegment( fromNode.stop.getStopFacility(),
278  toNode.stop.getStopFacility(),
279  travelTime,
280  transitLineId,
281  routeId
282  ));
283  } else if (downstreamLink.line.getId() == link.line.getId() && downstreamLink.route.getId() == link.route.getId() ){
284  //same route --> update the top routeSegment
285  RouteSegment routeSegment = routeSegments.remove(0);
286  routeSegments.add(0, new RouteSegment(fromNode.stop.getStopFacility(),
287  routeSegment.toStop,
288  routeSegment.travelTime+travelTime,
289  transitLineId,
290  routeId));
291  }
292 
293  if (isTransferLeg) {
294  // transfer cost
295  if ( ! (this.costFunction instanceof TransitRouterNetworkTravelTimeAndDisutility) ) {
296  throw new RuntimeException("TransitTravelDisutility is not instance of "+TransitRouterNetworkTravelTimeAndDisutility.class.getSimpleName()
297  +". An acc ");
298  }
299 
300  transferCost += ((TransitRouterNetworkTravelTimeAndDisutility) this.costFunction).defaultTransferCost(link,
301  Double.NEGATIVE_INFINITY,null,null);
302 
303  downstreamLink = null;
304  } else {
305  downstreamLink = link;
306  }
307 
308  previousFromNode = fromNode;
309  link = (TransitRouterNetworkLink) getData(fromNode).getPrevLink();
310  }
311 
312  DijkstraNodeData startNodeData = getData(previousFromNode);
313  DijkstraNodeData toNodeData = getData(minCostNode);
314 
315  double cost = toNodeData.getCost() - startNodeData.getCost()
316  + this.fromNodes.get(previousFromNode).initialCost
317  + toNodes.get(minCostNode).initialCost
318  + transferCost;
319 
320  // if there is no connection found, getPath(...) return a path with nothing in it, however, I (and AN) think that it should throw null. Amit Sep'17
321  if (routeSegments.size()==0) return null;
322  else return new InternalTransitPassengerRoute(cost, routeSegments);
323  }
324 
336  public Path getPath(final Map<Node, InitialNode> toNodes) {
337 
338  //find the best node
339  double minCost = Double.POSITIVE_INFINITY;
340  Node minCostNode = null;
341  for (Map.Entry<Node, InitialNode> e : toNodes.entrySet()) {
342  Node currentNode = e.getKey();
343  DijkstraNodeData r = this.nodeData.get(currentNode.getId());
344  if (r == null) {
345  expandNodeData(toNodes);
346  }
347  DijkstraNodeData data = getData(currentNode);
348  InitialNode initData = e.getValue();
349  double cost = data.getCost() + initData.initialCost;
350  if (data.getCost() != 0.0 || fromNodes.containsKey(currentNode)) {
351  if (cost < minCost) {
352  minCost = cost;
353  minCostNode = currentNode;
354  }
355  }
356  }
357 
358  if (minCostNode == null) {
359  return null;
360  }
361 
362  // now construct the path
363  List<Node> nodes = new LinkedList<>();
364  List<Link> links = new LinkedList<>();
365 
366  nodes.add(0, minCostNode);
367  Link tmpLink = getData(minCostNode).getPrevLink();
368  while (tmpLink != null) {
369  links.add(0, tmpLink);
370  nodes.add(0, tmpLink.getFromNode());
371  tmpLink = getData(tmpLink.getFromNode()).getPrevLink();
372  }
373 
374  DijkstraNodeData startNodeData = getData(nodes.get(0));
375  DijkstraNodeData toNodeData = getData(minCostNode);
376 
377  return new Path(nodes, links, toNodeData.getTime() - startNodeData.getTime(),
378  toNodeData.getCost() - startNodeData.getCost());
379  }
380 
384  /*package*/ RouterPriorityQueue<? extends Node> createRouterPriorityQueue() {
385  return new PseudoRemovePriorityQueue<>(500);
386  }
387 
405  protected void visitNode(final Node n, final DijkstraNodeData data,
406  final RouterPriorityQueue<Node> pendingNodes, final double time, final double cost,
407  final Link outLink) {
408  data.visit(outLink, cost, time, getIterationId());
409  pendingNodes.add(n, getPriority(data));
410  }
411 
421  protected void relaxNode(final Node outNode, final RouterPriorityQueue<Node> pendingNodes) {
422 
423  DijkstraNodeData outData = getData(outNode);
424  double currTime = outData.getTime();
425  double currCost = outData.getCost();
426  for (Link l : outNode.getOutLinks().values()) {
427  relaxNodeLogic(l, pendingNodes, currTime, currCost);
428  }
429  }
430 
435  /*package*/ void relaxNodeLogic(final Link l, final RouterPriorityQueue<Node> pendingNodes,
436  final double currTime, final double currCost) {
437  addToPendingNodes(l, l.getToNode(), pendingNodes, currTime, currCost);
438  }
439 
457  protected boolean addToPendingNodes(final Link l, final Node n,
458  final RouterPriorityQueue<Node> pendingNodes, final double currTime,
459  final double currCost) {
460 
461  this.customDataManager.initForLink(l);
462  double travelTime = this.timeFunction.getLinkTravelTime(l, currTime, this.person, this.vehicle);
463  double travelCost = this.costFunction.getLinkTravelDisutility(l, currTime, this.person, this.vehicle, this.customDataManager);
464  DijkstraNodeData data = getData(n);
465  double nCost = data.getCost();
466  if (!data.isVisited(getIterationId())) {
467  visitNode(n, data, pendingNodes, currTime + travelTime, currCost + travelCost, l);
468  this.customDataManager.storeTmpData();
469  return true;
470  }
471  double totalCost = currCost + travelCost;
472  if (totalCost < nCost) {
473  revisitNode(n, data, pendingNodes, currTime + travelTime, totalCost, l);
474  this.customDataManager.storeTmpData();
475  return true;
476  }
477 
478  return false;
479  }
480 
498  void revisitNode(final Node n, final DijkstraNodeData data,
499  final RouterPriorityQueue<Node> pendingNodes, final double time, final double cost,
500  final Link outLink) {
501  pendingNodes.remove(n);
502 
503  data.visit(outLink, cost, time, getIterationId());
504  pendingNodes.add(n, getPriority(data));
505  }
506 
512  private double getPriority(final DijkstraNodeData data) {
513  return data.getCost();
514  }
515 
524  protected DijkstraNodeData getData(final Node n) {
525  DijkstraNodeData r = this.nodeData.get(n.getId());
526  if (null == r) {
527  r = new DijkstraNodeData();
528  this.nodeData.put(n.getId(), r);
529  }
530  return r;
531  }
532 
533 }
boolean addToPendingNodes(final Link l, final Node n, final RouterPriorityQueue< Node > pendingNodes, final double currTime, final double currCost)
Map< Id< Node >, ? extends Node > getNodes()
TransitLeastCostPathTree(final Network network, final TransitTravelDisutility costFunction, final TravelTime timeFunction, final Map< Node, InitialNode > fromNodes, final Person person)
double getLinkTravelTime(Link link, double time, Person person, Vehicle vehicle)
Path getPath(final Map< Node, InitialNode > toNodes)
TransitLeastCostPathTree(final Network network, final TransitTravelDisutility costFunction, final TravelTime timeFunction, final Map< Node, InitialNode > fromNodes, final Map< Node, InitialNode > toNodes, final Person person)
void visit(final Link comingFrom, final double cost, final double time, final int iterID)
void visitNode(final Node n, final DijkstraNodeData data, final RouterPriorityQueue< Node > pendingNodes, final double time, final double cost, final Link outLink)
InternalTransitPassengerRoute getTransitPassengerRoute(final Map< Node, InitialNode > toNodes)
final HashMap< Id< Node >, DijkstraNodeData > nodeData
abstract TransitStopFacility getStopFacility()
double getLinkTravelDisutility(final Link link, final double time, final Person person, final Vehicle vehicle, final CustomDataManager dataManager)
Map< Id< Link >, ? extends Link > getOutLinks()
boolean add(final E o, final double priority)
void relaxNode(final Node outNode, final RouterPriorityQueue< Node > pendingNodes)
void expandNodeData(final Map< Node, InitialNode > toNodes)