Q2: Weights
def planet(size):
"""Construct a planet of some size."""
assert size > 0
return ['planet', size]
def size(w):
"""Select the size of a planet."""
assert is_planet(w), 'must call size on a planet'
return w[1]
Q3: Balanced
def balanced(m):
"""Return whether m is balanced.
>>> t, u, v = examples()
>>> balanced(t)
True
>>> balanced(v)
True
>>> w = mobile(arm(3, t), arm(2, u))
>>> balanced(w)
False
>>> balanced(mobile(arm(1, v), arm(1, w)))
False
>>> balanced(mobile(arm(1, w), arm(1, v)))
False
>>> from construct_check import check
>>> # checking for abstraction barrier violations by banning indexing
>>> check(HW_SOURCE_FILE, 'balanced', ['Index'])
True
"""
if is_planet(m):
return True
def torque(arm):
return length(arm) * total_weight(end(arm))
left_arm = left(m)
right_arm = right(m)
left_torque = torque(left_arm)
right_torque = torque(right_arm)
return left_torque == right_torque and balanced(end(left_arm)) and balanced(end(right_arm))
Q4: Totals
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
>>> from construct_check import check
>>> # checking for abstraction barrier violations by banning indexing
>>> check(HW_SOURCE_FILE, 'totals_tree', ['Index'])
True
"""
if is_planet(m):
return [size(m)]
label = total_weight(m)
branch = [totals_tree(_) for _ in [end(left(m)), end(right(m))]]
return tree(label, branch)
Q5: Replace Loki at Leaf
def replace_loki_at_leaf(t, lokis_replacement):
"""Returns a new tree where every leaf value equal to "loki" has
been replaced with lokis_replacement.
>>> yggdrasil = tree('odin',
... [tree('balder',
... [tree('loki'),
... tree('freya')]),
... tree('frigg',
... [tree('loki')]),
... tree('loki',
... [tree('sif'),
... tree('loki')]),
... tree('loki')])
>>> laerad = copy_tree(yggdrasil) # copy yggdrasil for testing purposes
>>> print_tree(replace_loki_at_leaf(yggdrasil, 'freya'))
odin
balder
freya
freya
frigg
freya
loki
sif
freya
freya
>>> laerad == yggdrasil # Make sure original tree is unmodified
True
"""
if is_leaf(t) and label(t) == 'loki':
return tree(lokis_replacement)
branch = [replace_loki_at_leaf(_, lokis_replacement) for _ in branches(t)]
return tree(label(t), branch)
Q6: Has Path
def has_path(t, word):
"""Return whether there is a path in a tree where the entries along the path
spell out a particular word.
>>> greetings = tree('h', [tree('i'),
... tree('e', [tree('l', [tree('l', [tree('o')])]),
... tree('y')])])
>>> print_tree(greetings)
h
i
e
l
l
o
y
>>> has_path(greetings, 'h')
True
>>> has_path(greetings, 'i')
False
>>> has_path(greetings, 'hi')
True
>>> has_path(greetings, 'hello')
True
>>> has_path(greetings, 'hey')
True
>>> has_path(greetings, 'bye')
False
>>> has_path(greetings, 'hint')
False
"""
assert len(word) > 0, 'no path for empty word.'
if is_leaf(t) or len(word) == 1:
return label(t) == word
if label(t) != word[0]:
return False
else:
for _ in branches(t):
if has_path(_, word[1:]):
return True
return False
Q7: Preorder
def preorder(t):
"""Return a list of the entries in this tree in the order that they
would be visited by a preorder traversal (see problem description).
>>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])])
>>> preorder(numbers)
[1, 2, 3, 4, 5, 6, 7]
>>> preorder(tree(2, [tree(4, [tree(6)])]))
[2, 4, 6]
"""
order = [label(t)]
if is_leaf(t):
return order
for _ in branches(t):
order += preorder(_)
return order
Q8: Interval Abstraction
def lower_bound(x):
"""Return the lower bound of interval x."""
return x[0]
def upper_bound(x):
"""Return the upper bound of interval x."""
return x[1]
Q9: Interval Arithmetic
def mul_interval(x, y):
"""Return the interval that contains the product of any value in x and any
value in y."""
p1 = lower_bound(x) * lower_bound(y)
p2 = lower_bound(x) * upper_bound(y)
p3 = upper_bound(x) * lower_bound(y)
p4 = upper_bound(x) * upper_bound(y)
return interval(min(p1, p2, p3, p4), max(p1, p2, p3, p4))
def sub_interval(x, y):
"""Return the interval that contains the difference between any value in x
and any value in y."""
p1 = lower_bound(x) - lower_bound(y)
p2 = lower_bound(x) - upper_bound(y)
p3 = upper_bound(x) - lower_bound(y)
p4 = upper_bound(x) - upper_bound(y)
return interval(min(p1, p2, p3, p4), max(p1, p2, p3, p4))
def div_interval(x, y):
"""Return the interval that contains the quotient of any value in x divided by
any value in y. Division is implemented as the multiplication of x by the
reciprocal of y."""
assert upper_bound(y)*lower_bound(y) > 0, "y spans zero!Fuck you!"
reciprocal_y = interval(1 / upper_bound(y), 1 / lower_bound(y))
return mul_interval(x, reciprocal_y)