@Override public void foundShortcut( int u_fromNode, int w_toNode, double existingDirectWeight, EdgeIterator outgoingEdges, int skippedEdge1, int incomingEdgeOrigCount) { // FOUND shortcut // but be sure that it is the only shortcut in the collection // and also in the graph for u->w. If existing AND identical weight => update setProperties. // Hint: shortcuts are always one-way due to distinct level of every node but we don't // know yet the levels so we need to determine the correct direction or if both directions // minor improvement: if (shortcuts.containsKey(sc) // then two shortcuts with the same nodes (u<->n.endNode) exists => check current shortcut // against both Shortcut sc = new Shortcut(u_fromNode, w_toNode, existingDirectWeight); if (shortcuts.containsKey(sc)) { return; } else { Shortcut tmpSc = new Shortcut(w_toNode, u_fromNode, existingDirectWeight); Shortcut tmpRetSc = shortcuts.get(tmpSc); if (tmpRetSc != null) { tmpRetSc.flags = scBothDir; return; } } shortcuts.put(sc, sc); sc.skippedEdge1 = skippedEdge1; sc.skippedEdge2 = outgoingEdges.getEdge(); sc.originalEdges = incomingEdgeOrigCount + getOrigEdgeCount(outgoingEdges.getEdge()); }
@Test public void testGetAllEdges() { graph = createGraph(); graph.edge(0, 1, 2, true); graph.edge(3, 1, 1, false); graph.edge(3, 2, 1, false); EdgeIterator iter = graph.getAllEdges(); assertTrue(iter.next()); int edgeId = iter.getEdge(); assertEquals(0, iter.getBaseNode()); assertEquals(1, iter.getAdjNode()); assertEquals(2, iter.getDistance(), 1e-6); assertTrue(iter.next()); int edgeId2 = iter.getEdge(); assertEquals(1, edgeId2 - edgeId); assertEquals(1, iter.getBaseNode()); assertEquals(3, iter.getAdjNode()); assertTrue(iter.next()); assertEquals(2, iter.getBaseNode()); assertEquals(3, iter.getAdjNode()); assertFalse(iter.next()); }
/** Finds shortcuts, does not change the underlying graph. */ void findShortcuts(ShortcutHandler sch) { long tmpDegreeCounter = 0; EdgeIterator incomingEdges = vehicleInExplorer.setBaseNode(sch.getNode()); // collect outgoing nodes (goal-nodes) only once while (incomingEdges.next()) { int u_fromNode = incomingEdges.getAdjNode(); // accept only uncontracted nodes if (g.getLevel(u_fromNode) != 0) continue; double v_u_weight = incomingEdges.getDistance(); int skippedEdge1 = incomingEdges.getEdge(); int incomingEdgeOrigCount = getOrigEdgeCount(skippedEdge1); // collect outgoing nodes (goal-nodes) only once EdgeIterator outgoingEdges = vehicleOutExplorer.setBaseNode(sch.getNode()); // force fresh maps etc as this cannot be determined by from node alone (e.g. same from node // but different avoidNode) algo.clear(); tmpDegreeCounter++; while (outgoingEdges.next()) { int w_toNode = outgoingEdges.getAdjNode(); // add only uncontracted nodes if (g.getLevel(w_toNode) != 0 || u_fromNode == w_toNode) { continue; } // Limit weight as ferries or forbidden edges can increase local search too much. // If we decrease the correct weight we only explore less and introduce more shortcuts. // I.e. no change to accuracy is made. double existingDirectWeight = v_u_weight + outgoingEdges.getDistance(); algo.setLimitWeight(existingDirectWeight) .setLimitVisitedNodes((int) meanDegree * 100) .setEdgeFilter(levelEdgeFilter.setAvoidNode(sch.getNode())); dijkstraSW.start(); dijkstraCount++; int endNode = algo.findEndNode(u_fromNode, w_toNode); dijkstraSW.stop(); // compare end node as the limit could force dijkstra to finish earlier if (endNode == w_toNode && algo.getWeight(endNode) <= existingDirectWeight) // FOUND witness path, so do not add shortcut continue; sch.foundShortcut( u_fromNode, w_toNode, existingDirectWeight, outgoingEdges, skippedEdge1, incomingEdgeOrigCount); } } if (sch instanceof AddShortcutHandler) { // sliding mean value when using "*2" => slower changes meanDegree = (meanDegree * 2 + tmpDegreeCounter) / 3; // meanDegree = (meanDegree + tmpDegreeCounter) / 2; } }
@Override public void foundShortcut( int u_fromNode, int w_toNode, double existingDirectWeight, EdgeIterator outgoingEdges, int skippedEdge1, int incomingEdgeOrigCount) { shortcuts++; originalEdgesCount += incomingEdgeOrigCount + getOrigEdgeCount(outgoingEdges.getEdge()); }
@Test public void testExtract2() { Graph g = createGraph(); g.edge(1, 2, 10, false); g.edge(2, 3, 20, false); EdgeExplorer explorer = g.createEdgeExplorer(carOutEdges); EdgeIterator iter = explorer.setBaseNode(1); iter.next(); PathBidirRef pw = new PathBidirRef(g, carEncoder); pw.edgeEntry = new EdgeEntry(iter.getEdge(), 2, 10); pw.edgeEntry.parent = new EdgeEntry(EdgeIterator.NO_EDGE, 1, 0); explorer = g.createEdgeExplorer(new DefaultEdgeFilter(carEncoder, true, false)); iter = explorer.setBaseNode(3); iter.next(); pw.edgeTo = new EdgeEntry(iter.getEdge(), 2, 20); pw.edgeTo.parent = new EdgeEntry(EdgeIterator.NO_EDGE, 3, 0); Path p = pw.extract(); assertEquals(Helper.createTList(1, 2, 3), p.calcNodes()); assertEquals(30, p.getDistance(), 1e-4); }
@Test public void testCreateDuplicateEdges() { graph = createGraph(); graph.edge(2, 1, 12, true); graph.edge(2, 3, 12, true); graph.edge(2, 3, 13, false); assertEquals(3, GHUtility.count(carOutExplorer.setBaseNode(2))); // no exception graph.getEdgeProps(1, 3); // raise exception try { graph.getEdgeProps(4, 3); assertTrue(false); } catch (Exception ex) { } try { graph.getEdgeProps(-1, 3); assertTrue(false); } catch (Exception ex) { } EdgeIterator iter = carOutExplorer.setBaseNode(2); assertTrue(iter.next()); EdgeIteratorState oneIter = graph.getEdgeProps(iter.getEdge(), 3); assertEquals(13, oneIter.getDistance(), 1e-6); assertEquals(2, oneIter.getBaseNode()); assertTrue(carEncoder.isBool(oneIter.getFlags(), FlagEncoder.K_FORWARD)); assertFalse(carEncoder.isBool(oneIter.getFlags(), FlagEncoder.K_BACKWARD)); oneIter = graph.getEdgeProps(iter.getEdge(), 2); assertEquals(13, oneIter.getDistance(), 1e-6); assertEquals(3, oneIter.getBaseNode()); assertFalse(carEncoder.isBool(oneIter.getFlags(), FlagEncoder.K_FORWARD)); assertTrue(carEncoder.isBool(oneIter.getFlags(), FlagEncoder.K_BACKWARD)); graph.edge(3, 2, 14, true); assertEquals(4, GHUtility.count(carOutExplorer.setBaseNode(2))); }
boolean prepareEdges() { // In CH the setProperties (speed) are ignored as calculating the new setProperties for a // shortcut is often not possible. // Also several shortcuts would be necessary with the different modes (e.g. fastest and // shortest) // So calculate the weight and store this as weight, then use only weight instead of calcWeight EdgeIterator iter = g.getAllEdges(); int c = 0; while (iter.next()) { c++; iter.setDistance(prepareWeighting.calcWeight(iter)); setOrigEdgeCount(iter.getEdge(), 1); } return c > 0; }