MATSIM
PreProcessLandmarks.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * PreProcessLandmarks.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.awt.geom.Rectangle2D;
24 import java.util.Comparator;
25 import java.util.Map;
26 import java.util.PriorityQueue;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.TimeUnit;
30 
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
37 
48 
49  private final int landmarkCount;
50 
51  private final Landmarker landmarker;
52 
53  private Node[] landmarks;
54 
55  private int numberOfThreads = 8;
56 
57  private static final Logger log = LogManager.getLogger(PreProcessLandmarks.class);
58 
60  this(costFunction, new Rectangle2D.Double());
61  }
62 
63  public PreProcessLandmarks(final TravelDisutility costFunction, final int landmarkCount) {
64  this(costFunction, new Rectangle2D.Double(), landmarkCount);
65  }
66 
73  final Rectangle2D.Double travelZone) {
74  this(costFunction, travelZone, 16);
75  }
76 
83  public void setNumberOfThreads(int numberOfThreads) {
84  this.numberOfThreads = numberOfThreads;
85  }
86 
93  public PreProcessLandmarks(final TravelDisutility costFunction, final Rectangle2D.Double travelZone, final int landmarkCount) {
94  this( costFunction ,
95  new PieSlicesLandmarker( travelZone ),
96  landmarkCount );
97  }
98 
101  final Landmarker landmarker,
102  final int landmarkCount) {
103  super(costFunction);
104 
105  this.landmarkCount = landmarkCount;
106  this.landmarker = landmarker;
107  }
108 
109  @Override
110  public void run(final Network network) {
111  super.run(network);
112 
113  log.info("Putting landmarks on network...");
114  long now = System.currentTimeMillis();
115  landmarks = landmarker.identifyLandmarks( landmarkCount , network );
116  log.info("done in " + (System.currentTimeMillis() - now) + " ms");
117 
118  log.info("Initializing landmarks data");
119  for (Node node : network.getNodes().values()) {
120  this.nodeData.put(node, new LandmarksData(this.landmarkCount));
121  }
122 
123  int nOfThreads = this.numberOfThreads;
124  if (nOfThreads > this.landmarks.length) {
125  nOfThreads = this.landmarks.length;
126  }
127  if (nOfThreads < 2) {
128  nOfThreads = 2; // always use at least two threads
129  }
130  log.info("Calculating distance from each node to each of the " + this.landmarkCount + " landmarks using " + nOfThreads + " threads...");
131  now = System.currentTimeMillis();
132 
133 
134  ExecutorService executor = Executors.newFixedThreadPool(nOfThreads);
135  for (int i = 0; i < this.landmarks.length; i++) {
136  executor.execute(new Calculator(i, this.landmarks[i], this.nodeData, this.costFunction));
137  }
138  executor.shutdown();
139  while (!executor.isTerminated()) {
140  log.info("wait for landmarks Calculator to finish...");
141  try {
142  if (!executor.awaitTermination(10, TimeUnit.MINUTES)) {
143  throw new RuntimeException("Landmarks pre-processing timeout.");
144  }
145  } catch (InterruptedException e) {
146  throw new RuntimeException(e);
147  }
148  }
149 
150  for (Node node : network.getNodes().values()) {
151  LandmarksData r = getNodeData(node);
152  r.updateMinMaxTravelTimes();
153  }
154 
155  for (Node node : network.getNodes().values()) {
156  LandmarksData r = getNodeData(node);
157  for (int i = 0; i < this.landmarks.length; i++) {
159  log.info("Min > max for node " + node.getId() + " and landmark " + i);
160  }
161  }
162  }
163 
164  log.info("done in " + (System.currentTimeMillis() - now) + " ms");
165  }
166 
167  private static class Calculator implements Runnable {
168 
169  private final int landmarkIdx;
170  private final Node landmark;
171  private final Map<Node, DeadEndData> nodeData;
173 
174  public Calculator(final int landmarkIdx, final Node landmark, final Map<Node, DeadEndData> nodeData, final TravelDisutility costFunction) {
175  this.landmarkIdx = landmarkIdx;
176  this.landmark = landmark;
177  this.nodeData = nodeData;
178  this.costFunction = costFunction;
179  }
180 
181  @Override
182  public void run() {
185  }
186 
187  private void expandLandmarkFrom() {
188  LandmarksFromTravelTimeComparator comparator = new LandmarksFromTravelTimeComparator(this.nodeData, this.landmarkIdx);
189  PriorityQueue<Node> pendingNodes = new PriorityQueue<>(100, comparator);
190  LandmarksData role = (LandmarksData) this.nodeData.get(this.landmark);
191  role.setToLandmarkTravelTime(this.landmarkIdx, 0.0);
192  role.setFromLandmarkTravelTime(this.landmarkIdx, 0.0);
193  pendingNodes.add(this.landmark);
194  while (!pendingNodes.isEmpty()) {
195  Node node = pendingNodes.poll();
196  double fromTravTime = ((LandmarksData) this.nodeData.get(node)).getFromLandmarkTravelTime(this.landmarkIdx);
197  LandmarksData role2;
198  for (Link l : node.getOutLinks().values()) {
199  Node n;
200  n = l.getToNode();
201  double linkTravTime = this.costFunction.getLinkMinimumTravelDisutility(l);
202  role2 = (LandmarksData) this.nodeData.get(n);
203  double totalTravelTime = fromTravTime + linkTravTime;
204  if (role2.getFromLandmarkTravelTime(this.landmarkIdx) > totalTravelTime) {
205  role2.setFromLandmarkTravelTime(this.landmarkIdx, totalTravelTime);
206  pendingNodes.add(n);
207  }
208  }
209  }
210  }
211 
212  private void expandLandmarkTo() {
213  LandmarksToTravelTimeComparator comparator = new LandmarksToTravelTimeComparator(this.nodeData, this.landmarkIdx);
214  PriorityQueue<Node> pendingNodes = new PriorityQueue<>(100, comparator);
215  LandmarksData role = (LandmarksData) this.nodeData.get(this.landmark);
216  role.setToLandmarkTravelTime(this.landmarkIdx, 0.0);
217  role.setFromLandmarkTravelTime(this.landmarkIdx, 0.0);
218  pendingNodes.add(this.landmark);
219  while (!pendingNodes.isEmpty()) {
220  Node node = pendingNodes.poll();
221  double toTravTime = ((LandmarksData) this.nodeData.get(node)).getToLandmarkTravelTime(this.landmarkIdx);
222  LandmarksData role2;
223  for (Link l : node.getInLinks().values()) {
224  Node n = l.getFromNode();
225  double linkTravTime = this.costFunction.getLinkMinimumTravelDisutility(l);
226  role2 = (LandmarksData) this.nodeData.get(n);
227  double totalTravelTime = toTravTime + linkTravTime;
228  if (role2.getToLandmarkTravelTime(this.landmarkIdx) > totalTravelTime) {
229  role2.setToLandmarkTravelTime(this.landmarkIdx, totalTravelTime);
230  pendingNodes.add(n);
231  }
232  }
233  }
234  }
235 
236  }
237 
238  public Node[] getLandmarks() {
239  return this.landmarks.clone();
240  }
241 
242  @Override
243  public LandmarksData getNodeData(final Node n) {
244  DeadEndData r = this.nodeData.get(n);
245  if (r == null) {
246  r = new LandmarksData(this.landmarkCount);
247  this.nodeData.put(n, r);
248  }
249  // would be better to work with a Map<Node,LandmarksData>, but for some reason the implementor of this class
250  // decided to inherit from PreProcessEuclidean, which inherits from PreprocessDijkstra, which is wehre the field
251  // is..
252  // Before I casted here, the cast was done from whithin AStarLandmarks algorithm, which is even worse.
253  // td dec 15
254  return (LandmarksData) r;
255  }
256 
257  public static class LandmarksData extends DeadEndData {
258 
259  private final double[] landmarkTravelTime1;
260  private final double[] landmarkTravelTime2;
261 
262  LandmarksData(final int landmarkCount) {
263  this.landmarkTravelTime2 = new double[landmarkCount];
264  this.landmarkTravelTime1 = new double[landmarkCount];
265  for (int i = 0; i < this.landmarkTravelTime2.length; i++) {
266  this.landmarkTravelTime2[i] = Double.POSITIVE_INFINITY;
267  this.landmarkTravelTime1[i] = Double.POSITIVE_INFINITY;
268  }
269  }
270 
271  void setToLandmarkTravelTime(final int landmarkIndex, final double travelTime) {
272  this.landmarkTravelTime2[landmarkIndex] = travelTime;
273  }
274 
275  void setFromLandmarkTravelTime(final int landmarkIndex, final double travelTime) {
276  this.landmarkTravelTime1[landmarkIndex] = travelTime;
277  }
278 
279  double getToLandmarkTravelTime(final int landmarkIndex) {
280  return this.landmarkTravelTime2[landmarkIndex];
281  }
282 
283  double getFromLandmarkTravelTime(final int landmarkIndex) {
284  return this.landmarkTravelTime1[landmarkIndex];
285  }
286 
287  void updateMinMaxTravelTimes() {
288  for (int i = 0; i < this.landmarkTravelTime1.length; i++) {
289  setTravelTimes(i, this.landmarkTravelTime2[i], this.landmarkTravelTime1[i]);
290  }
291  }
292 
293  private void setTravelTimes(final int landmarkIndex, final double travelTime1,
294  final double travelTime2) {
295  if (travelTime1 > travelTime2) {
296  this.landmarkTravelTime2[landmarkIndex] = travelTime1;
297  this.landmarkTravelTime1[landmarkIndex] = travelTime2;
298  } else {
299  this.landmarkTravelTime1[landmarkIndex] = travelTime1;
300  this.landmarkTravelTime2[landmarkIndex] = travelTime2;
301  }
302  }
303 
304  public double getMinLandmarkTravelTime(final int landmarkIndex) {
305  return this.landmarkTravelTime1[landmarkIndex];
306  }
307 
308  public double getMaxLandmarkTravelTime(final int landmarkIndex) {
309  return this.landmarkTravelTime2[landmarkIndex];
310  }
311  }
312 
319  private static class LandmarksToTravelTimeComparator implements Comparator<Node>, MatsimComparator {
320  private final Map<Node, DeadEndData> roleData;
321  private final int landmarkIndex;
322 
323  protected LandmarksToTravelTimeComparator(final Map<Node, DeadEndData> roleData, final int landmarkIndex) {
324  this.roleData = roleData;
325  this.landmarkIndex = landmarkIndex;
326  }
327 
328  @Override
329  public int compare(final Node n1, final Node n2) {
330 
331  double c1 = ((LandmarksData) this.roleData.get(n1)).getToLandmarkTravelTime(this.landmarkIndex);
332  double c2 = ((LandmarksData) this.roleData.get(n2)).getToLandmarkTravelTime(this.landmarkIndex);
333 
334  if (c1 < c2) {
335  return -1;
336  }
337  if (c1 > c2) {
338  return +1;
339  }
340  return n1.getId().compareTo(n2.getId());
341  }
342  }
343 
350  private static class LandmarksFromTravelTimeComparator implements Comparator<Node>, MatsimComparator {
351  private final Map<Node, DeadEndData> roleData;
352  private final int landmarkIndex;
353 
354  protected LandmarksFromTravelTimeComparator(final Map<Node, DeadEndData> roleData, final int landmarkIndex) {
355  this.roleData = roleData;
356  this.landmarkIndex = landmarkIndex;
357  }
358 
359  @Override
360  public int compare(final Node n1, final Node n2) {
361 
362  double c1 = ((LandmarksData) this.roleData.get(n1)).getFromLandmarkTravelTime(this.landmarkIndex);
363  double c2 = ((LandmarksData) this.roleData.get(n2)).getFromLandmarkTravelTime(this.landmarkIndex);
364 
365  if (c1 < c2) {
366  return -1;
367  }
368  if (c1 > c2) {
369  return +1;
370  }
371  return n1.getId().compareTo(n2.getId());
372  }
373  }
374 
375 }
Map< Id< Node >, ? extends Node > getNodes()
LandmarksToTravelTimeComparator(final Map< Node, DeadEndData > roleData, final int landmarkIndex)
Map< Id< Link >, ? extends Link > getInLinks()
PreProcessLandmarks(final TravelDisutility costFunction)
PreProcessLandmarks(final TravelDisutility costFunction, final Rectangle2D.Double travelZone, final int landmarkCount)
PreProcessLandmarks(final TravelDisutility costFunction, final Rectangle2D.Double travelZone)
Node [] identifyLandmarks(int nLandmarks, Network network)
void setTravelTimes(final int landmarkIndex, final double travelTime1, final double travelTime2)
LandmarksFromTravelTimeComparator(final Map< Node, DeadEndData > roleData, final int landmarkIndex)
PreProcessLandmarks(final TravelDisutility costFunction, final Landmarker landmarker, final int landmarkCount)
double getLinkMinimumTravelDisutility(final Link link)
Map< Id< Link >, ? extends Link > getOutLinks()
PreProcessLandmarks(final TravelDisutility costFunction, final int landmarkCount)
Calculator(final int landmarkIdx, final Node landmark, final Map< Node, DeadEndData > nodeData, final TravelDisutility costFunction)