Diagram G script
From Geb
#18:30 Tuesday 21 March 2006
#By Evgeni Sergeev
#First, construct a tree. Then call propagateSubtreeWidths() on the root.
#Then call printTree() on the root.
import sys
class Node:
"""Represents a node in the tree. """
def __init__(self, content):
self.children = []
self.content = content
self.subtree_width = 1
self.root_offset = 0
def addChild(self, child):
self.children.append(child)
def propagateSubtreeWidths(self):
for child in self.children:
child.propagateSubtreeWidths()
if len(self.children) == 1:
self.subtree_width = self.children[0].subtree_width
self.root_offset = self.children[0].root_offset
elif len(self.children) == 0:
self.subtree_width = len(str(self.content)) + 1
self.root_offset = 0
else:
n = 0
for child in self.children:
n = n + child.subtree_width
self.subtree_width = n
right_child_relative_offset = self.subtree_width - \\
(self.children[len(self.children)-1].subtree_width - \\
self.children[len(self.children)-1].root_offset)
self.root_offset = (self.children[0].root_offset + \\
right_child_relative_offset) / 2
def printLineTwo(self):
n = self.root_offset - len(str(self.content))/2
if n < 0: n = 0
sys.stdout.write(' '*n)
sys.stdout.write(str(self.content))
sys.stdout.write(' '*(self.subtree_width - n - len(str(self.content))))
def printLineOne(self):
n = self.root_offset
sys.stdout.write(' '*n)
sys.stdout.write('|')
sys.stdout.write(' '*(self.subtree_width - n - 1))
def printLineThree(self, horizontal_char = '_'):
if len(self.children) > 0:
if len(self.children) == 1:
self.printLineOne()
elif len(self.children) == 0:
sys.stdout.write(' '*self.subtree_width)
else:
left_child_offset = self.children[0].root_offset
right_child_offset = self.subtree_width - \\
(self.children[len(self.children)-1].subtree_width - \\
self.children[len(self.children)-1].root_offset)
left_dashes = self.root_offset - left_child_offset - 1
right_dashes = right_child_offset - self.root_offset - 1
left_spaces = self.root_offset - left_dashes
right_spaces = self.subtree_width - left_spaces - left_dashes \\
- 1 - right_dashes
sys.stdout.write(' '*left_spaces)
sys.stdout.write(horizontal_char*left_dashes)
sys.stdout.write('|')
sys.stdout.write(horizontal_char*right_dashes)
sys.stdout.write(' '*right_spaces)
def addChildren(self, queue, levels, parent_level):
queue.extend(self.children)
new_levels = []
for child in self.children:
new_levels.append(parent_level + 1)
levels.extend(new_levels)
def printTree(self, upside_down = 0):
queue = [self]
levels = [0]
n = 0
#Breadth queue
while n < len(queue):
queue[n].addChildren(queue, levels, levels[n])
n = n + 1
#levels[n] contains the level of n
if not upside_down:
i = 0
while i < n:
start_of_level = i
end_of_level = i
while end_of_level < n and \\
levels[end_of_level] == levels[start_of_level]:
end_of_level = end_of_level + 1
end_of_level = end_of_level - 1
for item in range(start_of_level,end_of_level+1):
queue[item].printLineOne()
print ' '
for item in range(start_of_level,end_of_level+1):
queue[item].printLineTwo()
print ' '
for item in range(start_of_level,end_of_level+1):
queue[item].printLineThree()
print ' '
i = end_of_level + 1
else:
i = n - 1
while i >= 0:
start_of_level = i
end_of_level = i
while start_of_level >= 0 and \\
levels[end_of_level] == levels[start_of_level]:
start_of_level = start_of_level - 1
start_of_level = start_of_level + 1
for item in range(start_of_level,end_of_level+1):
queue[item].printLineThree('"')
print ' '
for item in range(start_of_level,end_of_level+1):
queue[item].printLineTwo()
print ' '
for item in range(start_of_level,end_of_level+1):
queue[item].printLineOne()
print ' '
i = start_of_level - 1
def outputTree(f, n):
n = n + 1
nodes = range(n-1)
i = 1
while i < n:
nodes[i-1] = Node(i)
if (f(i) != i):
nodes[f(i)-1].addChild(nodes[i-1])
i = i + 1
nodes[0].propagateSubtreeWidths()
nodes[0].printTree(upside_down = 1)
print "Diagram G up to n=55."
def G(n, cache={}): #cache is shared between calls (!)
if n == 0:
return 0
if n not in cache:
cache[n] = n - G(G(n-1))
return cache[n]
outputTree(G, 55)
print "\
\ Diagram H up to n=59."
def H(n, cache={}):
if n == 0:
return 0
if n not in cache:
cache[n] = n - H(H(H(n-1)))
return cache[n]
outputTree(H, 59)
print "\
\ Diagram I up to n=69."
def I(n, cache={}):
if n == 0:
return 0
if n not in cache:
cache[n] = n - I(I(I(I(n-1))))
return cache[n]
outputTree(I, 69)
print "\
\ Diagram J up to n=80."
def J(n, cache={}):
if n == 0:
return 0
if n not in cache:
cache[n] = n - J(J(J(J(J(n-1)))))
return cache[n]
outputTree(J, 80)
print "\
\ The tree for Q(n) up to n=64."
def Q(n, cache={}):
if n == 0:
return 0
if n not in cache:
cache[n] = n - Q(n-1)
return cache[n]
outputTree(Q, 64)
print "\
\ The mirror tree MG(n) up to n=55."
def L(n, cache={}):
if n == 1:
return 1
if n not in cache:
cache[n] = L(G(n)) + 1
return cache[n]
def F(n, cache={0:1, 1:1}):
if n == 1 or n == 0:
return 1
if n not in cache:
keys = cache.keys()
keys.sort(reverse=True)
max_known = keys[0]
a, b = F(max_known), F(max_known - 1)
for i in range(max_known + 1, n + 1):
a, b = a + b, a
cache[i] = a
return cache[n]
def M(n):
if n == 1:
return 1
return F(L(n)) - (n - F(L(n)-1)) + 1
def MG(n):
return M(G(M(n)))
outputTree(MG, 55)
#Debugging code.
#print nodes
#for node in nodes:
#print node.content, ': ',
#for child in node.children:
#print child.content, ' ',
#print ' '
See the Diagram G script output
