MATSIM
MultiNodeDijkstra.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * MultiNodeDijkstra.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2013 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.core.router;
22 
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Map;
27 
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.matsim.api.core.v01.Coord;
31 import org.matsim.api.core.v01.Id;
41 import org.matsim.vehicles.Vehicle;
42 
66 public class MultiNodeDijkstra extends Dijkstra implements MultiNodePathCalculator {
67 
68  private final static Logger log = LogManager.getLogger(MultiNodeDijkstra.class);
69 
70  /*
71  * If this value is true, the algorithm tries to find routes to all end nodes.
72  * Otherwise only the one(s) with the lowest costs are found.
73  *
74  * When enabling this option, select end nodes with care! If only one of them
75  * is in a not reachable part of the network, the algorithm will process the
76  * entire reachable part of the network before terminating.
77  */
78  private boolean searchAllEndNodes;
79 
81  super(network, costFunction, timeFunction);
82  this.searchAllEndNodes = searchAllEndNodes;
83  }
84 
86  final PreProcessDijkstra preProcessData, boolean searchAllEndNodes) {
87  super(network, costFunction, timeFunction, preProcessData);
88  this.searchAllEndNodes = searchAllEndNodes;
89  }
90 
91  public static ImaginaryNode createImaginaryNode(Collection<? extends InitialNode> nodes) {
92  return new ImaginaryNode(nodes);
93  }
94 
95  public static ImaginaryNode createImaginaryNode(Collection<? extends InitialNode> nodes, Coord coord) {
96  return new ImaginaryNode(nodes, coord);
97  }
98 
99  /*
100  * We have to extend this method from the original Dijkstra. The given input nodes might be
101  * ImaginaryNodes which contain multiple start / end nodes for the routing process. Those
102  * nodes should be part of the routing network, therefore we perform the check for each of them.
103  *
104  * Regular nodes are directly passed to the super class.
105  *
106  * cdobler, jun'14
107  */
108  /*package*/ @Override
109  void checkNodeBelongToNetwork(Node node) {
110  if (node instanceof ImaginaryNode) {
111  ImaginaryNode imaginaryNode = (ImaginaryNode) node;
112  for (InitialNode initialNode : imaginaryNode.initialNodes) super.checkNodeBelongToNetwork(initialNode.node);
113  } else super.checkNodeBelongToNetwork(node);
114  }
115 
116  @Override
117  /*package*/ Node searchLogic( final Node fromNode, final Node toNode, final RouterPriorityQueue<Node> pendingNodes, Person person,
118  Vehicle vehicle ) {
119 
120  // If it is an imaginary node...
121  if (toNode instanceof ImaginaryNode) {
122 
123  Map<Id<Node>, InitialNode> endNodes = new HashMap<>();
124 
125  Collection<? extends InitialNode> initialNodes = ((ImaginaryNode) toNode).initialNodes;
126  for (InitialNode initialNode : initialNodes) endNodes.put(initialNode.node.getId(), initialNode);
127 
128  // find out which one is the cheapest end node
129  double minCost = Double.POSITIVE_INFINITY;
130  Node minCostNode = null;
131 
132  // continue searching as long as unvisited end nodes are available
133  boolean stillSearching = endNodes.size() > 0;
134 
135  while (stillSearching) {
136  Node outNode = pendingNodes.poll();
137 
138  if (outNode == null) {
139  /*
140  * This is not necessarily a problem. Some of the out nodes might be reachable only
141  * by passing another out node. Those nodes will never become the cheapest out node.
142  * Therefore only print a warning if no path to any of the out nodes was found.
143  */
144  if (minCostNode == null) {
145  if ( log.isTraceEnabled() ) {
146  log.trace("No route was found from node " + fromNode.getId() + " to any of the destination nodes was found.");
147  log.trace( Dijkstra.createInfoMessage( person, vehicle ) );
148  // seems we have no more nodes left, but not yet reached all endNodes...
149  StringBuffer sb = new StringBuffer("\tnot reached destionation nodes: ");
150  for (InitialNode endNode : endNodes.values()) {
151  sb.append(endNode.node.getId().toString());
152  sb.append("; ");
153  }
154  log.trace(sb.toString());
155  }
156  }
157 
158  if (searchAllEndNodes && endNodes.size() > 0) {
159  for (InitialNode endNode : endNodes.values()) {
160  log.trace("No route was found from node " + fromNode.getId() + " to destination node " + endNode.node.getId() + ".");
161  log.trace( Dijkstra.createInfoMessage( person, vehicle ) );
162  }
163  }
164 
165  endNodes.clear();
166  stillSearching = false;
167  } else {
168  DijkstraNodeData data = getData(outNode);
169  InitialNode initData = endNodes.remove(outNode.getId());
170 
171  /*
172  * If the node is an end node.
173  * Note:
174  * The node was head of the priority queue, i.e. the shortest path to the
175  * node has been found. The algorithm will not re-visit the node on another
176  * route!
177  */
178  if (initData != null) {
179  double cost = data.getCost() + initData.initialCost;
180  if (cost < minCost) {
181  minCost = cost;
182  minCostNode = outNode;
183  }
184  }
185 
186  if (searchAllEndNodes) {
187  relaxNode(outNode, null, pendingNodes);
188  stillSearching = endNodes.size() > 0;
189  } else {
190  if (data.getCost() > minCost) {
191  endNodes.clear(); // we can't get any better now
192  stillSearching = false;
193  } else {
194  relaxNode(outNode, null, pendingNodes);
195  }
196  }
197  }
198  }
199 
200  return minCostNode;
201  }
202  // ... otherwise: default behaviour.
203  else return super.searchLogic(fromNode, toNode, pendingNodes, person, vehicle );
204  }
205 
206  /*
207  * initFromNode -> first Node in pendingNodes -> calcLeastCostPath will relax that node
208  * -> we relax that dummy node here
209  */
210  @Override
211  /*package*/ void initFromNode(final Node fromNode, final Node toNode, final double startTime,
212  final RouterPriorityQueue<Node> pendingNodes) {
213 
214  // If it is an imaginary node, we relax it.
215  if (fromNode instanceof ImaginaryNode) {
216  relaxImaginaryNode((ImaginaryNode) fromNode, pendingNodes, startTime);
217  }
218  // ... otherwise: default behaviour.
219  else super.initFromNode(fromNode, toNode, startTime, pendingNodes);
220  }
221 
222  protected void relaxImaginaryNode(final ImaginaryNode outNode, final RouterPriorityQueue<Node> pendingNodes,
223  final double currTime) {
224 
225  double currCost = 0.0; // should be 0
226 
227  for (InitialNode initialNode : outNode.initialNodes) {
228  double travelTime = initialNode.initialTime;
229  double travelCost = initialNode.initialCost;
230  DijkstraNodeData data = getData(initialNode.node);
231  Link l = null; // fromLink - use a dummy link here??
232  visitNode(initialNode.node, data, pendingNodes, currTime + travelTime, currCost + travelCost, l);
233  }
234  }
235 
236  @Override
237  protected Path constructPath(Node fromNode, Node toNode, double startTime, double arrivalTime) {
238  ArrayList<Node> nodes = new ArrayList<Node>();
239  ArrayList<Link> links = new ArrayList<Link>();
240 
241  nodes.add(0, toNode);
242  Link tmpLink = getData(toNode).getPrevLink();
243 
244  // Only this part has been adapted. Could probably also be changed in the super class.
245  while (tmpLink != null) {
246  links.add(0, tmpLink);
247  nodes.add(0, tmpLink.getFromNode());
248  tmpLink = getData(tmpLink.getFromNode()).getPrevLink();
249  }
250  // Ignore the initial time and cost of the start node!
251  DijkstraNodeData startNodeData = getData(nodes.get(0));
252  DijkstraNodeData toNodeData = getData(toNode);
253  Path path = new Path(nodes, links, toNodeData.getTime() - startNodeData.getTime(), toNodeData.getCost() - startNodeData.getCost());
254 // double travelTime = arrivalTime - startTime;
255 // Path path = new Path(nodes, links, travelTime, toNodeData.getCost());
256 
257  return path;
258  }
259 
268  public Path constructPath(Node fromNode, Node toNode, double startTime) {
269  if (toNode == null || fromNode == null) return null;
270  else {
271  DijkstraNodeData toData = getData(toNode);
272  if (!toData.isVisited(this.getIterationId())) return null;
273 
274  DijkstraNodeData fromData = getData(fromNode);
275  if (!fromData.isVisited(this.getIterationId())) return null;
276 
277  double arrivalTime = toData.getTime();
278 
279  // now construct and return the path
280  return constructPath(fromNode, toNode, startTime, arrivalTime);
281  }
282  }
283 
284  public boolean isSearchAllEndNodes() {
285  return searchAllEndNodes;
286  }
287 
288  public void setSearchAllEndNodes(boolean searchAllEndNodes) {
289  this.searchAllEndNodes = searchAllEndNodes;
290  }
291 }
void visitNode(final Node n, final DijkstraNodeData data, final RouterPriorityQueue< Node > pendingNodes, final double time, final double cost, final Link outLink)
Definition: Dijkstra.java:553
DijkstraNodeData getData(final Node n)
Definition: Dijkstra.java:606
void relaxImaginaryNode(final ImaginaryNode outNode, final RouterPriorityQueue< Node > pendingNodes, final double currTime)
final PreProcessDijkstra preProcessData
Definition: Dijkstra.java:127
final TravelDisutility costFunction
Definition: Dijkstra.java:98
static ImaginaryNode createImaginaryNode(Collection<? extends InitialNode > nodes, Coord coord)
final TravelTime timeFunction
Definition: Dijkstra.java:103
void setSearchAllEndNodes(boolean searchAllEndNodes)
Path constructPath(Node fromNode, Node toNode, double startTime)
void relaxNode(final Node outNode, final Node toNode, final RouterPriorityQueue< Node > pendingNodes)
Definition: Dijkstra.java:400
static ImaginaryNode createImaginaryNode(Collection<? extends InitialNode > nodes)
Path constructPath(Node fromNode, Node toNode, double startTime, double arrivalTime)