1 / 19

Topological Ordering

Topological Ordering. public Maybe<List<Node>> topologicalOrder(){ List<Node> orderedNodes = new ArrayList<Node>(); while ( true ){ List<Node> sources = sourceNodes (); if (sources.size()==0) break ; Node n = sources.get(0); orderedNodes.add(n); ==> nodes .remove(n); <== }

aurorat
Download Presentation

Topological Ordering

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Topological Ordering

  2. public Maybe<List<Node>> topologicalOrder(){ List<Node> orderedNodes = new ArrayList<Node>(); while(true){ List<Node> sources = sourceNodes(); if(sources.size()==0) break; Node n = sources.get(0); orderedNodes.add(n); ==>nodes.remove(n); <== } if(nodes.size() > 0 ){ returnnew None<List<Node>>(); } returnnew Some<List<Node>>(orderedNodes); }

  3. public List<Node> sourceNodes(){ List<Node> sources = new ArrayList<Node>(); for (Node node : nodes) { if (predCountOf(node) == 0){ sources.add(node); } } return sources; }

  4. publicint predCountOf(Node node){ int predCount = 0; for (Node n : nodes) { if(n.getSuccessors().contains(node)){ predCount++; } } return predCount; }

  5. Optimization Opportunity (1) The method sourceNodes() is invoked several times, in the control flow of an invocation of topologicalOrder(), with the same implicit this argument destructively updated by the statement nodes.remove(n) between consecutive invocations of sourceNodes().

  6. Dynamizing sourceNodes() (1) It is sound to memoize sourceNodes() as long as we provide a maintenance advice that restores cache consistency after the execution of nodes.remove(n). One approach to restore cache consistency is to use an incrementalized/dynamized version of sourceNodes() under Graph.nodes.remove(Node).

  7. Dynamizing sourceNodes() (2) public List<Node> sourceNodes(){ List<Node> sources = new ArrayList<Node>(); for (Node node : nodes) { if (predCountOf(node) == 0){ sources.add(node); } } return sources; } • How should we change what this method returns if a node was removed from nodes?

  8. Dynamizing sourceNodes() (3) • If a node is removed from the graph, it can no longer be returned by sourceNodes(). • If a node is removed from the graph, all of it’s successors are going to lose a predecessor. 8

  9. public Maybe<List<Node>> topologicalOrderSrcNodesOpt(){ List<Node> orderedNodes = new ArrayList<Node>(); List<Node> sources = sourceNodes(); while(sources.size()>0){ Node n = sources.get(0); orderedNodes.add(n); nodes.remove(n); /*SrcNodeOpt*/ sources.remove(n); /*SrcNodeOpt*/for(Node succ: n.getSuccessors()){ /*SrcNodeOpt*/if(!sources.contains(succ)){ /*SrcNodeOpt*/if(predCountOf(succ) == 0){ /*SrcNodeOpt*/sources.add(succ); /*SrcNodeOpt*/} /*SrcNodeOpt*/} /*SrcNodeOpt*/ } } if(nodes.size() > 0 ) returnnew None<List<Node>>(); returnnew Some<List<Node>>(orderedNodes); }

  10. Optimization Opportunity (2) The method predCountOf(Node) is invoked several times, in the control flow of an invocation of topologicalOrder(), with the same implicit this argument destructively updated by the statement nodes.remove(n) between consecutive invocations of predCountOf(Node). However, not all invocations have the same Node argument. Would memoization alone be enough to gain the best performance?

  11. Reordering the Computation • Instead of lazily computing Graph.predCountOf(Node) on demand, we can eagerly compute the predCount of all nodes in the graph. • What does that save? 11

  12. Reordering the Computation(2) • publicint predCountOf(Node node){ • int predCount = 0; • for (Node n : nodes) { • if(n.getSuccessors().contains(node)){ • predCount++; • } • } • return predCount; • } • Can we compute the predCount of all nodes together more efficiently than computing them one by one?

  13. Reordering the Computation(3) • Computing the predCount of one node requires a complete graph traversal. • Computing the predCount of any number of nodes can be done by a single graph traversal as well. • Amortizing the cost of graph traversal. 13

  14. Dynamizing predCountOf() (1) It is sound to memoize predCountOf() as long as we provide a maintenance advice that restores cache consistency after the execution of nodes.remove(n). One approach to restore cache consistency is to use an incrementalized/dynamized version of predCountOf() under Graph.nodes.remove(Node).

  15. Dynamizing predCountOf() (2) publicint predCountOf(Node node){ int predCount = 0; for (Node n : nodes) { if(n.getSuccessors().contains(node)){ predCount++; } } return predCount; } • How should we change what this method returns if a node was removed from nodes?

  16. Dynamizing predCountOf() (2) • If a node is removed from the graph, it can no longer have predCount in that graph. • If a node is removed from the graph, all of it’s successors are no longer going to have the removed node as a predecessor. 16

  17. public Maybe<List<Node>> topologicalOrderPredecessorsOpt(){ /*PredecessorsOpt*/for(Node n: this.nodes){ /*PredecessorsOpt*/n.predCount = 0; /*PredecessorsOpt*/ } /*PredecessorsOpt*/for(Node n : this.nodes){ /*PredecessorsOpt*/for(Node succ: n.successors){ /*PredecessorsOpt*/succ.predCount++; /*PredecessorsOpt*/} /*PredecessorsOpt*/ } List<Node> orderedNodes = new ArrayList<Node>(); while(true){ List<Node> sources = sourceNodes(); if(sources.size() == 0 ) break; Node n = sources.get(0); orderedNodes.add(n); nodes.remove(n); /*PredecessorsOpt*/for(Node succ: n.getSuccessors()){ /*PredecessorsOpt*/succ.predCount--; /*PredecessorsOpt*/} /*PredecessorsOpt*/n.predCount = 0; } if(nodes.size() > 0 ) returnnew None<List<Node>>(); returnnew Some<List<Node>>(orderedNodes); }

  18. Combining Both Optimizations • Both optimizations add maintenance code right after nodes.remove(n). • When combining them which one should come first? Why? 18

  19. public Maybe<List<Node>> topologicalOrderSrcNodesOptAndPredecessorsOpt(){ /*PredecessorsOpt*/for(Node n: this.nodes){ /*PredecessorsOpt*/n.predCount = 0; /*PredecessorsOpt*/ } /*PredecessorsOpt*/for(Node n : this.nodes){ /*PredecessorsOpt*/for(Node succ: n.successors){ /*PredecessorsOpt*/succ.predCount++; /*PredecessorsOpt*/} /*PredecessorsOpt*/ } List<Node> orderedNodes = new ArrayList<Node>(); List<Node> sources = sourceNodes(); while(sources.size()>0){ Node n = sources.get(0); orderedNodes.add(n); nodes.remove(n); /*PredecessorsOpt*/for(Node succ: n.getSuccessors()){ /*PredecessorsOpt*/succ.predCount--; /*PredecessorsOpt*/} /*PredecessorsOpt*/n.predCount = 0; /*SrcNodeOpt*/ sources.remove(n); /*SrcNodeOpt*/for(Node succ: n.getSuccessors()){ /*SrcNodeOpt*/if(!sources.contains(succ)){ /*SrcNodeOpt*/if(/*PredecessorsOpt*/succ.predCount == 0){ /*SrcNodeOpt*/sources.add(succ); /*SrcNodeOpt*/} /*SrcNodeOpt*/} /*SrcNodeOpt*/ } } if(nodes.size() > 0 ) returnnew None<List<Node>>(); returnnew Some<List<Node>>(orderedNodes); }

More Related