Skip to content

Instantly share code, notes, and snippets.

@yonran
Last active December 7, 2018 07:25
Show Gist options
  • Save yonran/3879981f30c1293c30fe8f091a3eb255 to your computer and use it in GitHub Desktop.
Save yonran/3879981f30c1293c30fe8f091a3eb255 to your computer and use it in GitHub Desktop.
Print all combinations of associative operators acting on values
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import *
from functools import reduce
def all_trees_given_stack(stack, rest, operators):
if len(stack) == 1 and len(rest) == 0:
yield stack[0]
if len(stack) > 1:
rhs = stack[-1]
lhs = stack[-2]
for operator in operators:
if isinstance(rhs,tuple) and rhs[0] == operator:
# Since each operator is associative, we want to include
# only left-associative variants
# and exclude right-associative variants
pass
elif isinstance(lhs,tuple) and lhs[0] == operator:
# Simplify ((A x B) x C) as (A x B x C)
(_, operands) = lhs
new_stack = stack[:-2] + [(operator, operands + [rhs])]
for result in all_trees_given_stack(new_stack, rest, operators):
yield result
else:
new_stack = stack[:-2] + [(operator, [lhs, rhs])]
for result in all_trees_given_stack(new_stack, rest, operators):
yield result
if len(rest) > 0:
new_stack = stack + [rest[0]]
new_rest = rest[1:]
for result in all_trees_given_stack(new_stack, new_rest, operators):
yield result
def gen_trees(values, operators):
return all_trees_given_stack([values[0]], values[1:], operators)
def tree_to_string(tree):
if isinstance(tree,tuple):
(operator, operands) = tree
return "({})".format(" {} ".format(operator).join(tree_to_string(x) for x in operands))
else:
return str(tree) # leaf value
def tree_traverse(func):
def tree_to_whatever(tree):
if isinstance(tree, tuple):
(operator, operands) = tree
return func(operator, [tree_to_whatever(x) for x in operands])
else:
return tree
return tree_to_whatever
def tree_to_value(tree):
def calculate(operator,operands):
return sum(operands) if operator == '+' else 1/sum(1/x for x in operands)
return tree_traverse(calculate)(tree)
def combine_trees(x, tree):
val = tree_to_value(tree)
if val in x:
x[val] = x[val] + [tree_to_string(tree)]
else:
x[val] = [tree_to_string(tree)]
return x
values = [1, 1, 1, 1]
operators = ["+", "∥"]
trees = list(gen_trees(values, operators))
for tree in trees:
print(tree_to_string(tree), tree_to_value(tree))
print("Deduplicated by value:")
for value, tree_string in reduce(combine_trees, trees, {}).items(): # replace 4 with however many resistors
print("{:.02f}".format(value), ", ".join(tree_string))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment