MATSIM
PreProcessDijkstra.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * PreProcessDijkstra.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 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.util;
22 
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.TreeMap;
27 import java.util.concurrent.ConcurrentHashMap;
28 
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.matsim.api.core.v01.Id;
35 
45 public class PreProcessDijkstra {
46 
47  private static final Logger log = LogManager.getLogger(PreProcessDijkstra.class);
48 
49  private boolean containsData = false;
50 
51  protected Map<Node, DeadEndData> nodeData = null;
52 
53  public void run(final Network network) {
54  markDeadEnds(network);
55  this.containsData = true;
56  }
57 
62  private void markDeadEnds(final Network network) {
63  long now = System.currentTimeMillis();
64 
65  /*
66  * We use a concurrentHashMap because if FastRouters are used for the re-routing,
67  * their parallel initialization in multiple threads may result in concurrent
68  * calls to getNodeData(...).
69  */
70  this.nodeData = new ConcurrentHashMap<Node, DeadEndData>(network.getNodes().size());
71 
72  DeadEndData deadEndData;
73  for (Node node : network.getNodes().values()) {
74  deadEndData = getNodeData(node);
75 
76  Map<Id<Node>, Node> incidentNodes = getIncidentNodes(node);
77  if (incidentNodes.size() == 1) {
78  ArrayList<Node> deadEndNodes = new ArrayList<Node>();
79 
80  while (deadEndData.getInDeadEndCount() == incidentNodes.size() - 1) {
81 
82  deadEndNodes.add(node);
83  deadEndNodes.addAll(deadEndData.getDeadEndNodes());
84  deadEndData.getDeadEndNodes().clear();
85 
86  // Just set a dummy DeadEndEntryNode, such that is
87  // isn't null. We use this as a flag to determine
88  // whether we already processed this node.
89  deadEndData.setDeadEndEntryNode(node);
90 
91  Iterator<? extends Node> it = incidentNodes.values().iterator();
92  while (deadEndData.getDeadEndEntryNode() != null && it.hasNext()) {
93  node = it.next();
94  deadEndData = getNodeData(node);
95  }
96  if (deadEndData.getDeadEndEntryNode() == null) {
97  deadEndData.incrementInDeadEndCount();
98  incidentNodes = getIncidentNodes(node);
99  } else {
100  log.error("All " + incidentNodes.size() + " incident nodes of node " + node.getId() + " are dead ends!");
101  return;
102  }
103  }
104  deadEndData.getDeadEndNodes().addAll(deadEndNodes);
105  }
106  }
107 
108  // Now set the proper deadEndEntryNode for each node
109  int deadEndNodeCount = 0;
110  for (Node node : network.getNodes().values()) {
111  deadEndData = getNodeData(node);
112  for (Node n : deadEndData.getDeadEndNodes()) {
113  DeadEndData r = getNodeData(n);
114  r.setDeadEndEntryNode(node);
115  deadEndNodeCount++;
116  }
117  deadEndData.getDeadEndNodes().clear();
118  }
119  log.info("nodes in dead ends: " + deadEndNodeCount
120  + " (total nodes: " + network.getNodes().size() + "). Done in "
121  + (System.currentTimeMillis() - now) + " ms");
122  }
123 
124  private static Map<Id<Node>, Node> getIncidentNodes(Node node) {
125  Map<Id<Node>, Node> nodes = new TreeMap<>();
126  for (Link link : node.getInLinks().values()) {
127  nodes.put(link.getFromNode().getId(), link.getFromNode());
128  }
129  for (Link link : node.getOutLinks().values()) {
130  nodes.put(link.getToNode().getId(), link.getToNode());
131  }
132  return nodes;
133  }
134 
140  public DeadEndData getNodeData(final Node n) {
141  DeadEndData r = this.nodeData.get(n);
142  if (null == r) {
143  r = new DeadEndData();
144  this.nodeData.put(n, r);
145  }
146  return r;
147  }
148 
153  public static class DeadEndData {
154  private Node deadEndEntryNode = null;
155 
156  private int inDeadEndCount = 0;
157 
158  private ArrayList<Node> deadEndNodes = new ArrayList<Node>(2);
159 
160  ArrayList<Node> getDeadEndNodes() {
161  return this.deadEndNodes;
162  }
163 
167  /*package*/ int getInDeadEndCount() {
168  return this.inDeadEndCount;
169  }
170 
175  /*package*/ void incrementInDeadEndCount() {
176  this.inDeadEndCount++;
177  }
178 
179 
187  return this.deadEndEntryNode;
188  }
189 
190  /*package*/ void setDeadEndEntryNode(final Node node) {
191  this.deadEndEntryNode = node;
192  }
193  }
194 
195  public boolean containsData() {
196  return this.containsData;
197  }
198 }
Map< Id< Node >, ? extends Node > getNodes()
Map< Id< Link >, ? extends Link > getInLinks()
Map< Id< Link >, ? extends Link > getOutLinks()
static Map< Id< Node >, Node > getIncidentNodes(Node node)