1

I have a problem in applied math that can be almost perfectly mapped to finding the longest path in a multiway tree.

I have a function child() which gives child nodes (points in space satisfying a condition). The only caveat is that child() requires all previous nodes connected to it including the root node. It is here where I am struggling to write my code recursively. So far, I have something like below.

def multitree(node):
     tmp_list = child(node)
     for child2 in tmp_list:
           if len(child(child2)))==0:       #if you hit a leaf (dead end), go to next element
                 continue
           else:
                 multitree(child2)

But at this point, I'm not sure what to return. I essentially want to map the entire multiway tree until i reach a leaf for everything. Any ideas or tips? thanks guys.

edit:

Update 1: For completeness sake, I sketched out a rough idea of what input child() requires: https://i.stack.imgur.com/QDyNj.png Basically to find the child nodes of the node marked by the arrow child() requires the list of nodes between root and the node itself, i.e. the nodes marked with a red dot.

Update 2:

I've written child(node) as below and I am currently working on it --

def pathwalk(node):

    children = child(node)
    paths = [child(node.append(kid)) for kid in children]

    return paths
Bari Tala
  • 37
  • 8
  • Do you just want to find the longest path, or get all the paths and find the longest from there? – Iluvatar Dec 11 '16 at 01:41
  • Any reason not to use a standard depth-first-search or breadth-first-search returning all the paths in the tree and just `max(paths, key=len)` across that? BTW: I find it simpler to use a simple stack or queue vs. recursion to do these searches. – AChampion Dec 11 '16 at 01:54
  • If runtime is not significantly different, I'd like to see all paths in addition to the longest one. Any idea how I would implement DFS or BFS this in the above case? Every example I've seen of DFS or BFS has been with trees that are already "mapped" so to speak. In this, I can only recursively find child nodes until I hit a leaf. I also have this caveat that child() HAS to take input not just the node but all nodes between it and and the root node. – Bari Tala Dec 11 '16 at 23:32
  • Running time *is* significantly different. There is a linear time solution to finding the longest path in a directed acyclic graph (which yours seems to be). But generating all paths in a directed acyclic graph is a different and probably much more time consuming problem. See https://en.wikipedia.org/wiki/Longest_path_problem – Jim Mischel Dec 13 '16 at 16:53

2 Answers2

1

You can do something like this to get just the longest path. Here it gets you a list of nodes, from there you can extract any relevant information:

def longest_path(node):
    children = child(node)

    if not children: # leaf node
        return [node]

    children_vals = [longest_path(c) for c in children]
    longest = max(children_vals, key=len)
    return [node] + longest

Doesn't handle ties, or rather chooses one option arbitrarily.

(note: semi-tested)

Iluvatar
  • 1,537
  • 12
  • 13
  • A tiny suggestion: `if not children` is considered a bit more pythonic than `if len(children) == 0`.. – UltraInstinct Dec 11 '16 at 02:06
  • I actually got a "maximum recrusion depth exceeded in cmp" error. Any ideas? – Bari Tala Dec 11 '16 at 23:29
  • That means that the max length was longer than the max recursion depth. How large are the trees you're using? If they're quite large, you may want to try something like this http://www.geeksforgeeks.org/iterative-method-to-find-height-of-binary-tree/ – Iluvatar Dec 11 '16 at 23:33
  • Found an error in my child() routine. Updated accordingly, and just re-submitted the job. Will let you know the results. The root node itself has 170 child nodes. and each node subsequent to it has less and less. – Bari Tala Dec 11 '16 at 23:50
  • Same error. Root node has only 18 children this time. – Bari Tala Dec 12 '16 at 00:47
  • You're still hitting the recursion limit then. How deep is the tree? – Iluvatar Dec 12 '16 at 00:48
  • The tree is at most 30-40 children deep – Bari Tala Dec 12 '16 at 01:50
  • My nodes are points in euclidean space i.e. "tuples" therefore. "node" has to be a list of tuples, I modified my child(*nodes) routine accordingly. But I'm not sure how to modify longest_path in the same way.... – Bari Tala Dec 12 '16 at 02:23
  • The way it's written, `node` was meant to be a single thing (ie tuple) and `child()` would take that and figure out which children it has, and returns a list of those. Without knowing what you're doing, it's hard to say what implications your change has. One thing you might do is pass in another parameter that's initially 0, so `longest_path(node, num)`, and when you recurse, increment it, so `children_vals = [longest_path(c, num+1) for c in children]`. Then, print out `num` as the first line of the method, and you make sure that you're not hitting the recursion limit. – Iluvatar Dec 12 '16 at 03:05
  • See my edit made above. child() requires the entire list of nodes from root node to the node in question. With child() I am only able to decide what is a child if I check all nodes added from root to node itself. Therefore child will take a list of tuples as input, and return a list of tuples of children. E – Bari Tala Dec 12 '16 at 19:32
0

I think I've found the issue. Since I wanted to keep a running list of all nodes you find the children of (you keep track of the path you walk, see imgur pic). I edited Illuvatar's routine by adding

children_vals = [longest_path(node+[c]) for c in children]

In this way, you recursively concatenate every parent with its child.

Bari Tala
  • 37
  • 8