[Erp5-report] r31556 nicolas.dumazet - /erp5/trunk/products/ERP5/Document/TradeCondition.py

nobody at svn.erp5.org nobody at svn.erp5.org
Mon Jan 4 06:39:27 CET 2010


Author: nicolas.dumazet
Date: Mon Jan  4 06:39:27 2010
New Revision: 31556

URL: http://svn.erp5.org?rev=31556&view=rev
Log:
algorithm: a topological sort in a graph can be much simpler

There were three surprising things in the previous version:
 * the XXX mention: leafs can indeed be detected at construction time
 * the need to track both children and parents of a node: usually only one
    or the other is enough to work efficiently on a graph
 * the idiom:
      if n in list: list.remove(n)
      list.append(n)

Replace it by a generic sort on node depth. A dictionary is used for lookups to
avoid linear list lookups, and only the successor relation is kept (parent_dict)

Also explicit in comments the graph we are building/the order expected for code
clarity (ie avoid confusion wrt what is the parent/child of the graph node)

Modified:
    erp5/trunk/products/ERP5/Document/TradeCondition.py

Modified: erp5/trunk/products/ERP5/Document/TradeCondition.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TradeCondition.py?rev=31556&r1=31555&r2=31556&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TradeCondition.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TradeCondition.py [utf8] Mon Jan  4 06:39:27 2010
@@ -203,39 +203,54 @@
             reference_list.append(reference)
             trade_model_line_composed_list.append(trade_model_line)
 
-      # build a graph
-      father_dict = {}
-      child_dict = {}
+      # build a graph of precedences
+      # B---\
+      #      \
+      # C-----> A
+      # A is parent of B and C, and returned order should be
+      #   (BC) A
+      # where (BC) cannot be sorted
+      parent_dict = {}
+      # B and C are leaves
+      leaf_line_list = []
       for line in trade_model_line_composed_list:
-        father_dict.setdefault(line, [])
+        has_child = False
         for other_line in trade_model_line_composed_list:
           if line == other_line:
             continue
-          child_dict.setdefault(other_line, [])
+          parent_dict.setdefault(other_line, [])
           for base_application in line.getBaseApplicationList():
             if base_application in other_line.getBaseContributionList():
-              father_dict[line].append(other_line)
-              child_dict[other_line].append(line)
+              parent_dict[other_line].append(line)
+              has_child = True
+        if not has_child:
+          leaf_line_list.append(line)
+
       final_list = []
-      if len(father_dict):
-        # find roots elements
-        # XXX maybe this can be done while building the graph
-        root_line_list = []
-        for k, v in child_dict.iteritems():
-          if len(v) == 0:
-            root_line_list.append(k)
-        # sort graph according to predecessors
-        f = root_line_list[:]
-        tmp = None
-        final_list = root_line_list[:]
-        while len(f):
-          tmp = f.pop(0)
-          for predecessors in father_dict[tmp]:
-            f.append(predecessors)
-            if predecessors in final_list:
-              final_list.remove(predecessors)
-            final_list.append(predecessors)
-        final_list.reverse()
+      if len(parent_dict):
+        # longest distance to a root (A)
+        depth = {}
+        tovisit = leaf_line_list
+        while tovisit:
+          node = tovisit[-1]
+          if node in depth:
+            tovisit.pop()
+            continue
+
+          parent_list = parent_dict.get(node, [])
+          if len(parent_list) == 0:
+            depth[node] = 0
+            tovisit.pop()
+          else:
+            for parent in parent_list:
+              if parent not in depth:
+                tovisit.append(parent)
+            if tovisit[-1] == node:
+              depth[node] = max(depth[p] for p in parent_list) + 1
+              tovisit.pop()
+
+        # the farther a line is from a root, the earlier it should be returned
+        final_list = sorted(depth.iterkeys(), key=depth.get, reverse=True)
 
       if len(final_list) == 0:
         # at least return original lines retrieved




More information about the Erp5-report mailing list