3

I'm stuck on a programming question involving a tree for a project. The problem itself is only a subproblem of the larger question (but I won't post that here as its not really relevant). Anyone the problem is:

I'm trying to go over each path in the tree and calculate the associated value.

The situation is for instance like in this tree:

     a
  b     b

Now the result i should get is the multiplications as follows:

leave1 = a * b

leave2 = a * (1-b)

leave3 = (1-a) * b

leave4 = (1-a) * (1-b)

And so the leaves on one level lower in the tree would basically be the results (note that they do not exist in reality, its just conceptual).

Now, I want to do this recursively, but there are a few problems: The values for a and b are generated during the traversal, but the value for b for instance should only be generated 1 time. All values are either 0 or 1. If taking the left child of a node A, you use the value A in the multiplication. the right path you use the value 1-A.

Furthermore, the tree is always perfect, i.e. complete and balanced.

Now what I have (I program in python, but its more the algorithm in general im interested in with this question):

def f(n):
  if n == 1:
     return [1]
  generate value #(a, b or whatever one it is)
  g = f(n/2)
  h = scalarmultiply(value,g)
  return h.append(g - h)

Note that g and h are lists. This code was giving by one of my professors as possible help, but I don't think this does what I want. At least, it wont give me as result a list h which has the result for each path. Especially, I don't think it differentiates between b and 1-b. Am I seeing this wrong and how should I do this?

I'm not very experienced at programming, so try and explain easy if you can :-)

Mythio
  • 671
  • 2
  • 7
  • 18
  • would it be correct to say: if `a=1` and `b=2` and `c=3`(the next row....) then you expect the output [6,-6,-6,6,-6,6,6,-6]? If no can you please include some example tree node values and their expected output. If I am correct then recursion is a little overkill – Sheena Jan 30 '13 at 16:01
  • you should check this out : http://stackoverflow.com/questions/5671486/enumerating-all-paths-in-a-tree – Ketouem Jan 30 '13 at 16:15
  • @Sheena In essence yes that would be correct output. However in the actual problem the values are binary (0 or 1) so the result for instance with a = 1, b = 0 would be [0,1,0,0], taking that -b stands for 1-b. I was trying to simplify the problem a bit in the description. Ketouem, thats not really the same as the tree that is supplied there already has values which is not the case here. Hence every level of the tree has to be done simultaneously for each path, else the value would have to be generated to many times. – Mythio Jan 30 '13 at 16:28
  • @Mythio: please for now on be more explicit in your questions - your simplification made the question mean something very different to what you just said in the comment. It would be good if you updated your question to reflect your actual question... – Sheena Jan 30 '13 at 23:07
  • @Sheena, I've made the modifications to the original question. Sorry about the confusion, its the first time i'm posting on here. – Mythio Jan 31 '13 at 19:42
  • If your tree is symmetric like you illustrated, you don't need to traverse every path. The code you've got from your prof does what you need then. `f(4)` will return a list of all leaves in the subtree of which `a` is the root node. – J. Katzwinkel Feb 01 '13 at 01:27

2 Answers2

0

Try something like this:

def f(element_count):
    if element_count == 1:  #<-------------------------------A
        return [1,] #at the root node - it has to be 1 otherwise this is pointless
    current_value = get_the_value_however_you_need_to()#<----B
    result_so_far = f(element_count/2)  #<-------------------C
    result = []
    for i in result_so_far:#<--------------------------------D
        result.append(i*current_value)
        result.append(i*(1-current_value))
        result.append((1-i)*current_value)
        result.append((1-i)*(1-current_value))
    return result

Here's how it works:

Say you wanted to work with a three layer pyramid. Then the element_count would be the number of elements on the third layer so you would call f(4). The condition at A fails so we continue to B where the next value is generated. Now at C we call f(2).

The process in f(2) is similar, f(2) calls f(1) and f(1) returns [1,] to f(2). Now we start working our way back to the widest part of the tree...

I'm not sure what your lecturer was getting at with the end of the function. The for loop does the multiplication you explained and builds up a list which is then returned

Sheena
  • 15,590
  • 14
  • 75
  • 113
  • Thanks for your help :-) I don't think this does what I need, but i've updated the problem to make it clearer how the tree should be viewed. In using the value of a node, it is critical whether the value you are multiplying with is either a left or a right child. And then it is critical whether that second value is approached from the left or right. I've made a picture of this...but i'm not allowed to upload it without having 10 reputation points...Sorry if i'm being really confusing. – Mythio Jan 31 '13 at 19:45
  • @Mythio: no worries. I think you should get have the reputation now. Can you please please update your question to include actual values of output and nodes? Run through an example. As I understand your question this approach works fine, so there must be something I am misunderstanding. If you include an example with two levels and another example with three levels that would probably be best – Sheena Feb 01 '13 at 12:16
0

If I'm understanding correctly, you want to build up a binary tree like this:

      A
     / \
    /   \
   /     \
  B       C
 / \     / \
D   E   F   G

Where the Boolean values (1, 0, or their Python equivalents, True and False) of lower level nodes are calculated from the values of their parent and grandparent using the following rules:

D = A and B
E = A and not B
F = not A and C
G = not A and not C

That is, each node's right descendents calculate their values based on it's inverse. You further stated that the tree is defined by a single root value (a) and another value that is used for both of the root's children (b).

Here's a function that will calculate the value of any node of such a tree. The tree positions are defined by an integer index in the same way a binary heap often is, with the parent of a node N being N//2 and it's children being 2*N and 2*N+1 (with the root node being 1). It uses a memoization dictionary to avoid recomputing the same values repeatedly.

def tree_value(n, a, b, memo=None):
    if memo is None:
        memo = {1:a, 2:b, 3:b} # this initialization covers our base cases

    if n not in memo: # if our value is unknown, compute it
        parent, parent_dir = divmod(n, 2)
        parent_val = tree_value(parent, a, b, memo) # recurse

        grandparent, grandparent_dir = divmod(parent, 2)
        grandparent_val = tree_value(grandparent, a, b, memo) # recurse again

        if parent_dir: # we're a right child, so invert our parent's value
            parent_val = not parent_val

        if grandparent_dir: # our parent is grandparent's right child, so invert
            grandparent_val = not grandparent_val

        memo[n] = parent_val and grandparent_val

    return memo[n]

You could probably improve performance slightly by noticing that the grandparent's value will always be in the memo dict after the parent's value has been calculated, but I've left that out so the code is clearer.

If you need to efficiently compute many values from the same tree (rather than just one), you probably want to keep a permanent memo dictionary somewhere, perhaps as a value in a global dict, keyed by an (a, b) tuple.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • Hmm, going to see if I can get this to work. I think it comes pretty close to what I want, but not entirely sure yet. – Mythio Jan 31 '13 at 21:37
  • Aren't all the nodes on one level supposed to have the same value though? I mean B=C, D=E=F=G – Sheena Feb 01 '13 at 12:18
  • @Sheena If I've understood the question correctly (and I may not have), there are two parts of the tree's definition. The first is the root and the first two children, which are defined to be `a`, `b` and `b` again. The second part of the definition is that grandchildren are defined by their parent and grandparent according to the direction of descent using rules I wrote out. At the top of the tree, `B` will indeed equal `C`, but in later sub-trees that won't always be the case. I don't think `D` through `G` will ever all be equal. – Blckknght Feb 03 '13 at 00:47