31
31
32
32
class NodeBasedNodeContractor extends AbstractNodeContractor {
33
33
private final Map <Shortcut , Shortcut > shortcuts = new HashMap <>();
34
- private final AddShortcutHandler addScHandler = new AddShortcutHandler ();
35
- private final CalcShortcutHandler calcScHandler = new CalcShortcutHandler ();
36
34
private final Params params = new Params ();
37
35
private PrepareCHEdgeExplorer allEdgeExplorer ;
38
36
private NodeBasedWitnessPathSearcher prepareAlgo ;
@@ -42,6 +40,9 @@ class NodeBasedNodeContractor extends AbstractNodeContractor {
42
40
// meanDegree is the number of edges / number of nodes ratio of the graph, not really the average degree, because
43
41
// each edge can exist in both directions
44
42
private double meanDegree ;
43
+ // temporary counters used for priority calculation
44
+ private int originalEdgesCount ;
45
+ private int shortcutsCount ;
45
46
46
47
NodeBasedNodeContractor (PrepareCHGraph prepareGraph , PMap pMap ) {
47
48
super (prepareGraph );
@@ -78,24 +79,24 @@ public void close() {
78
79
}
79
80
80
81
/**
81
- * Warning: the calculated priority must NOT depend on priority(v) and therefore findShortcuts should also not
82
+ * Warning: the calculated priority must NOT depend on priority(v) and therefore handleShortcuts should also not
82
83
* depend on the priority(v). Otherwise updating the priority before contracting in contractNodes() could lead to
83
84
* a slowish or even endless loop.
84
85
*/
85
86
@ Override
86
87
public float calculatePriority (int node ) {
87
- if (prepareGraph .getLevel (node ) != maxLevel ) {
88
+ if (prepareGraph .getLevel (node ) != maxLevel )
88
89
throw new IllegalArgumentException ("Priority should only be calculated for not yet contracted nodes" );
89
- }
90
- CalcShortcutsResult calcShortcutsResult = calcShortcutCount (node );
91
90
92
91
// # huge influence: the bigger the less shortcuts gets created and the faster is the preparation
93
92
//
94
93
// every adjNode has an 'original edge' number associated. initially it is r=1
95
94
// when a new shortcut is introduced then r of the associated edges is summed up:
96
95
// r(u,w)=r(u,v)+r(v,w) now we can define
97
96
// originalEdgesCount = σ(v) := sum_{ (u,w) ∈ shortcuts(v) } of r(u, w)
98
- int originalEdgesCount = calcShortcutsResult .originalEdgesCount ;
97
+ shortcutsCount = 0 ;
98
+ originalEdgesCount = 0 ;
99
+ handleShortcuts (node , this ::countShortcut );
99
100
100
101
// # lowest influence on preparation speed or shortcut creation count
101
102
// (but according to paper should speed up queries)
@@ -124,7 +125,7 @@ public float calculatePriority(int node) {
124
125
// |shortcuts(v)| − |{(u, v) | v uncontracted}| − |{(v, w) | v uncontracted}|
125
126
// meanDegree is used instead of outDegree+inDegree as if one adjNode is in both directions
126
127
// only one bucket memory is used. Additionally one shortcut could also stand for two directions.
127
- int edgeDifference = calcShortcutsResult . shortcutsCount - degree ;
128
+ int edgeDifference = shortcutsCount - degree ;
128
129
129
130
// according to the paper do a simple linear combination of the properties to get the priority.
130
131
return params .edgeDifferenceWeight * edgeDifference +
@@ -135,8 +136,8 @@ public float calculatePriority(int node) {
135
136
@ Override
136
137
public void contractNode (int node ) {
137
138
shortcuts .clear ();
138
- long degree = findShortcuts ( addScHandler . setNode ( node ) );
139
- addedShortcutsCount += addShortcuts (shortcuts .keySet ());
139
+ long degree = handleShortcuts ( node , this :: addOrUpdateShortcut );
140
+ addedShortcutsCount += writeShortcuts (shortcuts .keySet ());
140
141
// put weight factor on meanDegree instead of taking the average => meanDegree is more stable
141
142
meanDegree = (meanDegree * 2 + degree ) / 3 ;
142
143
}
@@ -153,15 +154,15 @@ public String getStatisticsString() {
153
154
* Returns the 'degree' of the handler's node (disregarding edges from/to already contracted nodes). Note that
154
155
* here the degree is not the total number of adjacent edges, but only the number of incoming edges
155
156
*/
156
- private long findShortcuts ( ShortcutHandler sch ) {
157
+ private long handleShortcuts ( int node , ShortcutHandler handler ) {
157
158
int maxVisitedNodes = getMaxVisitedNodesEstimate ();
158
159
long degree = 0 ;
159
- PrepareCHEdgeIterator incomingEdges = inEdgeExplorer .setBaseNode (sch . getNode () );
160
+ PrepareCHEdgeIterator incomingEdges = inEdgeExplorer .setBaseNode (node );
160
161
// collect outgoing nodes (goal-nodes) only once
161
162
while (incomingEdges .next ()) {
162
163
int fromNode = incomingEdges .getAdjNode ();
163
164
// accept only not-contracted nodes, do not consider loops at the node that is being contracted
164
- if (fromNode == sch . getNode () || isContracted (fromNode ))
165
+ if (fromNode == node || isContracted (fromNode ))
165
166
continue ;
166
167
167
168
final double incomingEdgeWeight = incomingEdges .getWeight (true );
@@ -172,14 +173,14 @@ private long findShortcuts(ShortcutHandler sch) {
172
173
int incomingEdge = incomingEdges .getEdge ();
173
174
int inOrigEdgeCount = getOrigEdgeCount (incomingEdge );
174
175
// collect outgoing nodes (goal-nodes) only once
175
- PrepareCHEdgeIterator outgoingEdges = outEdgeExplorer .setBaseNode (sch . getNode () );
176
+ PrepareCHEdgeIterator outgoingEdges = outEdgeExplorer .setBaseNode (node );
176
177
// force fresh maps etc as this cannot be determined by from node alone (e.g. same from node but different avoidNode)
177
178
prepareAlgo .clear ();
178
179
degree ++;
179
180
while (outgoingEdges .next ()) {
180
181
int toNode = outgoingEdges .getAdjNode ();
181
182
// add only not-contracted nodes, do not consider loops at the node that is being contracted
182
- if (toNode == sch . getNode () || isContracted (toNode ) || fromNode == toNode )
183
+ if (toNode == node || isContracted (toNode ) || fromNode == toNode )
183
184
continue ;
184
185
185
186
// Limit weight as ferries or forbidden edges can increase local search too much.
@@ -195,7 +196,7 @@ private long findShortcuts(ShortcutHandler sch) {
195
196
196
197
prepareAlgo .setWeightLimit (existingDirectWeight );
197
198
prepareAlgo .setMaxVisitedNodes (maxVisitedNodes );
198
- prepareAlgo .ignoreNode (sch . getNode () );
199
+ prepareAlgo .ignoreNode (node );
199
200
200
201
dijkstraSW .start ();
201
202
dijkstraCount ++;
@@ -207,7 +208,7 @@ private long findShortcuts(ShortcutHandler sch) {
207
208
// FOUND witness path, so do not add shortcut
208
209
continue ;
209
210
210
- sch . foundShortcut (fromNode , toNode , existingDirectWeight ,
211
+ handler . handleShortcut (fromNode , toNode , existingDirectWeight ,
211
212
outgoingEdges .getEdge (), getOrigEdgeCount (outgoingEdges .getEdge ()),
212
213
incomingEdge , inOrigEdgeCount );
213
214
}
@@ -216,11 +217,11 @@ private long findShortcuts(ShortcutHandler sch) {
216
217
}
217
218
218
219
/**
219
- * Adds the given shortcuts to the graph.
220
+ * Actually writes the given shortcuts to the graph.
220
221
*
221
222
* @return the actual number of shortcuts that were added to the graph
222
223
*/
223
- private int addShortcuts (Collection <Shortcut > shortcuts ) {
224
+ private int writeShortcuts (Collection <Shortcut > shortcuts ) {
224
225
int tmpNewShortcuts = 0 ;
225
226
NEXT_SC :
226
227
for (Shortcut sc : shortcuts ) {
@@ -267,11 +268,6 @@ private int addShortcuts(Collection<Shortcut> shortcuts) {
267
268
return tmpNewShortcuts ;
268
269
}
269
270
270
- private CalcShortcutsResult calcShortcutCount (int node ) {
271
- findShortcuts (calcScHandler .setNode (node ));
272
- return calcScHandler .calcShortcutsResult ;
273
- }
274
-
275
271
private String getCoords (PrepareCHEdgeIterator edge , NodeAccess na ) {
276
272
int base = edge .getBaseNode ();
277
273
int adj = edge .getAdjNode ();
@@ -347,87 +343,51 @@ public String toString() {
347
343
}
348
344
}
349
345
346
+ @ FunctionalInterface
350
347
private interface ShortcutHandler {
351
- void foundShortcut (int fromNode , int toNode , double existingDirectWeight ,
352
- int outgoingEdge , int outOrigEdgeCount ,
353
- int incomingEdge , int inOrigEdgeCount );
354
-
355
- int getNode ();
348
+ void handleShortcut (int fromNode , int toNode , double existingDirectWeight ,
349
+ int outgoingEdge , int outOrigEdgeCount ,
350
+ int incomingEdge , int inOrigEdgeCount );
356
351
}
357
352
358
- private class CalcShortcutHandler implements ShortcutHandler {
359
- int node ;
360
- CalcShortcutsResult calcShortcutsResult = new CalcShortcutsResult ();
361
-
362
- @ Override
363
- public int getNode () {
364
- return node ;
365
- }
366
-
367
- public CalcShortcutHandler setNode (int node ) {
368
- this .node = node ;
369
- calcShortcutsResult .originalEdgesCount = 0 ;
370
- calcShortcutsResult .shortcutsCount = 0 ;
371
- return this ;
372
- }
373
-
374
- @ Override
375
- public void foundShortcut (int fromNode , int toNode , double existingDirectWeight ,
376
- int outgoingEdge , int outOrigEdgeCount ,
377
- int incomingEdge , int inOrigEdgeCount ) {
378
- calcShortcutsResult .shortcutsCount ++;
379
- calcShortcutsResult .originalEdgesCount += inOrigEdgeCount + outOrigEdgeCount ;
380
- }
353
+ private void countShortcut (int fromNode , int toNode , double existingDirectWeight ,
354
+ int outgoingEdge , int outOrigEdgeCount ,
355
+ int incomingEdge , int inOrigEdgeCount ) {
356
+ shortcutsCount ++;
357
+ originalEdgesCount += inOrigEdgeCount + outOrigEdgeCount ;
381
358
}
382
359
383
- private class AddShortcutHandler implements ShortcutHandler {
384
- int node ;
385
-
386
- @ Override
387
- public int getNode () {
388
- return node ;
389
- }
390
-
391
- public AddShortcutHandler setNode (int node ) {
392
- shortcuts .clear ();
393
- this .node = node ;
394
- return this ;
360
+ /**
361
+ * Adds a new shortcut to the temporary set of shortcuts or updates/merges it with an
362
+ * existing one.
363
+ */
364
+ private void addOrUpdateShortcut (int fromNode , int toNode , double existingDirectWeight ,
365
+ int outgoingEdge , int outOrigEdgeCount ,
366
+ int incomingEdge , int inOrigEdgeCount ) {
367
+ // FOUND shortcut
368
+ // but be sure that it is the only shortcut in the collection
369
+ // and also in the graph for u->w. If existing AND identical weight => update setProperties.
370
+ // Hint: shortcuts are always one-way due to distinct level of every node but we don't
371
+ // know yet the levels so we need to determine the correct direction or if both directions
372
+ Shortcut sc = new Shortcut (fromNode , toNode , existingDirectWeight );
373
+ if (shortcuts .containsKey (sc ))
374
+ return ;
375
+
376
+ Shortcut tmpSc = new Shortcut (toNode , fromNode , existingDirectWeight );
377
+ Shortcut tmpRetSc = shortcuts .get (tmpSc );
378
+ // overwrite flags only if skipped edges are identical
379
+ if (tmpRetSc != null && tmpRetSc .skippedEdge2 == incomingEdge && tmpRetSc .skippedEdge1 == outgoingEdge ) {
380
+ tmpRetSc .flags = PrepareEncoder .getScDirMask ();
381
+ return ;
395
382
}
396
383
397
- @ Override
398
- public void foundShortcut (int fromNode , int toNode , double existingDirectWeight ,
399
- int outgoingEdge , int outOrigEdgeCount ,
400
- int incomingEdge , int inOrigEdgeCount ) {
401
- // FOUND shortcut
402
- // but be sure that it is the only shortcut in the collection
403
- // and also in the graph for u->w. If existing AND identical weight => update setProperties.
404
- // Hint: shortcuts are always one-way due to distinct level of every node but we don't
405
- // know yet the levels so we need to determine the correct direction or if both directions
406
- Shortcut sc = new Shortcut (fromNode , toNode , existingDirectWeight );
407
- if (shortcuts .containsKey (sc ))
408
- return ;
409
-
410
- Shortcut tmpSc = new Shortcut (toNode , fromNode , existingDirectWeight );
411
- Shortcut tmpRetSc = shortcuts .get (tmpSc );
412
- // overwrite flags only if skipped edges are identical
413
- if (tmpRetSc != null && tmpRetSc .skippedEdge2 == incomingEdge && tmpRetSc .skippedEdge1 == outgoingEdge ) {
414
- tmpRetSc .flags = PrepareEncoder .getScDirMask ();
415
- return ;
416
- }
417
-
418
- Shortcut old = shortcuts .put (sc , sc );
419
- if (old != null )
420
- throw new IllegalStateException ("Shortcut did not exist (" + sc + ") but was overwriting another one? " + old );
421
-
422
- sc .skippedEdge1 = incomingEdge ;
423
- sc .skippedEdge2 = outgoingEdge ;
424
- sc .originalEdges = inOrigEdgeCount + outOrigEdgeCount ;
425
- }
426
- }
384
+ Shortcut old = shortcuts .put (sc , sc );
385
+ if (old != null )
386
+ throw new IllegalStateException ("Shortcut did not exist (" + sc + ") but was overwriting another one? " + old );
427
387
428
- private static class CalcShortcutsResult {
429
- int originalEdgesCount ;
430
- int shortcutsCount ;
388
+ sc . skippedEdge1 = incomingEdge ;
389
+ sc . skippedEdge2 = outgoingEdge ;
390
+ sc . originalEdges = inOrigEdgeCount + outOrigEdgeCount ;
431
391
}
432
392
433
393
public static class Params {
0 commit comments