HW_SOURCE_FILE = 'hw03.py' ######### # Trees # ######### def tree(label, branches=[]): """Construct a tree with the given label value and a list of branches.""" for branch in branches: assert is_tree(branch), 'branches must be trees' return [label] + list(branches) def label(tree): """Return the label value of a tree.""" return tree[0] def branches(tree): """Return the list of branches of the given tree.""" return tree[1:] def is_tree(tree): """Returns True if the given tree is a tree, and False otherwise.""" if type(tree) != list or len(tree) < 1: return False for branch in branches(tree): if not is_tree(branch): return False return True def is_leaf(tree): """Returns True if the given tree's list of branches is empty, and False otherwise. """ return not branches(tree) def print_tree(t, indent=0): """Print a representation of this tree in which each node is indented by two spaces times its depth from the root. >>> print_tree(tree(1)) 1 >>> print_tree(tree(1, [tree(2)])) 1 2 >>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])]) >>> print_tree(numbers) 1 2 3 4 5 6 7 """ print(' ' * indent + str(label(t))) for b in branches(t): print_tree(b, indent + 1) def copy_tree(t): """Returns a copy of t. Only for testing purposes. >>> t = tree(5) >>> copy = copy_tree(t) >>> t = tree(6) >>> print_tree(copy) 5 """ return tree(label(t), [copy_tree(b) for b in branches(t)]) ############# # Questions # ############# def intersection(st, ave): """Represent an intersection using the Cantor pairing function.""" return (st+ave)*(st+ave+1)//2 + ave def street(inter): return w(inter) - avenue(inter) def avenue(inter): return inter - (w(inter) ** 2 + w(inter)) // 2 w = lambda z: int(((8*z+1)**0.5-1)/2) def taxicab(a, b): """Return the taxicab distance between two intersections. >>> times_square = intersection(46, 7) >>> ess_a_bagel = intersection(51, 3) >>> taxicab(times_square, ess_a_bagel) 9 >>> taxicab(ess_a_bagel, times_square) 9 """ "*** YOUR CODE HERE ***" def flatten(lst): """Returns a flattened version of lst. >>> flatten([1, 2, 3]) # normal list [1, 2, 3] >>> x = [1, [2, 3], 4] # deep list >>> flatten(x) [1, 2, 3, 4] >>> x # Ensure x is not mutated [1, [2, 3], 4] >>> x = [[1, [1, 1]], 1, [1, 1]] # deep list >>> flatten(x) [1, 1, 1, 1, 1, 1] >>> x [[1, [1, 1]], 1, [1, 1]] """ "*** YOUR CODE HERE ***" def replace_leaf(t, old, new): """Returns a new tree where every leaf value equal to old has been replaced with new. >>> yggdrasil = tree('odin', ... [tree('balder', ... [tree('thor'), ... tree('freya')]), ... tree('frigg', ... [tree('thor')]), ... tree('thor', ... [tree('sif'), ... tree('thor')]), ... tree('thor')]) >>> laerad = copy_tree(yggdrasil) # copy yggdrasil for testing purposes >>> print_tree(replace_leaf(yggdrasil, 'thor', 'freya')) odin balder freya freya frigg freya thor sif freya freya >>> laerad == yggdrasil # Make sure original tree is unmodified True """ "*** YOUR CODE HERE ***" # Mobiles def mobile(left, right): """Construct a mobile from a left side and a right side.""" assert is_side(left), "left must be a side" assert is_side(right), "right must be a side" return ['mobile', left, right] def is_mobile(m): """Return whether m is a mobile.""" return type(m) == list and len(m) == 3 and m[0] == 'mobile' def left(m): """Select the left side of a mobile.""" assert is_mobile(m), "must call left on a mobile" return m[1] def right(m): """Select the right side of a mobile.""" assert is_mobile(m), "must call right on a mobile" return m[2] def side(length, mobile_or_weight): """Construct a side: a length of rod with a mobile or weight at the end.""" assert is_mobile(mobile_or_weight) or is_weight(mobile_or_weight) return ['side', length, mobile_or_weight] def is_side(s): """Return whether s is a side.""" return type(s) == list and len(s) == 3 and s[0] == 'side' def length(s): """Select the length of a side.""" assert is_side(s), "must call length on a side" return s[1] def end(s): """Select the mobile or weight hanging at the end of a side.""" assert is_side(s), "must call end on a side" return s[2] def weight(size): """Construct a weight of some size.""" assert size > 0 "*** YOUR CODE HERE ***" def size(w): """Select the size of a weight.""" assert is_weight(w), 'must call size on a weight' "*** YOUR CODE HERE ***" def is_weight(w): """Whether w is a weight.""" return type(w) == list and len(w) == 2 and w[0] == 'weight' def examples(): t = mobile(side(1, weight(2)), side(2, weight(1))) u = mobile(side(5, weight(1)), side(1, mobile(side(2, weight(3)), side(3, weight(2))))) v = mobile(side(4, t), side(2, u)) return (t, u, v) def total_weight(m): """Return the total weight of m, a weight or mobile. >>> t, u, v = examples() >>> total_weight(t) 3 >>> total_weight(u) 6 >>> total_weight(v) 9 """ if is_weight(m): return size(m) else: assert is_mobile(m), "must get total weight of a mobile or a weight" return total_weight(end(left(m))) + total_weight(end(right(m))) def balanced(m): """Return whether m is balanced. >>> t, u, v = examples() >>> balanced(t) True >>> balanced(v) True >>> w = mobile(side(3, t), side(2, u)) >>> balanced(w) False >>> balanced(mobile(side(1, v), side(1, w))) False >>> balanced(mobile(side(1, w), side(1, v))) False """ "*** YOUR CODE HERE ***" def totals_tree(m): """Return a tree representing the mobile with its total weight at the root. >>> t, u, v = examples() >>> print_tree(totals_tree(t)) 3 2 1 >>> print_tree(totals_tree(u)) 6 1 5 3 2 >>> print_tree(totals_tree(v)) 9 3 2 1 6 1 5 3 2 """ "*** YOUR CODE HERE ***" ################### # Extra Questions # ################### def zero(f): return lambda x: x def successor(n): return lambda f: lambda x: f(n(f)(x)) def one(f): """Church numeral 1: same as successor(zero)""" "*** YOUR CODE HERE ***" def two(f): """Church numeral 2: same as successor(successor(zero))""" "*** YOUR CODE HERE ***" three = successor(two) def church_to_int(n): """Convert the Church numeral n to a Python integer. >>> church_to_int(zero) 0 >>> church_to_int(one) 1 >>> church_to_int(two) 2 >>> church_to_int(three) 3 """ "*** YOUR CODE HERE ***" def add_church(m, n): """Return the Church numeral for m + n, for Church numerals m and n. >>> church_to_int(add_church(two, three)) 5 """ "*** YOUR CODE HERE ***" def mul_church(m, n): """Return the Church numeral for m * n, for Church numerals m and n. >>> four = successor(three) >>> church_to_int(mul_church(two, three)) 6 >>> church_to_int(mul_church(three, four)) 12 """ "*** YOUR CODE HERE ***" def pow_church(m, n): """Return the Church numeral m ** n, for Church numerals m and n. >>> church_to_int(pow_church(two, three)) 8 >>> church_to_int(pow_church(three, two)) 9 """ "*** YOUR CODE HERE ***"