Last active
December 7, 2018 07:25
-
-
Save yonran/3879981f30c1293c30fe8f091a3eb255 to your computer and use it in GitHub Desktop.
Print all combinations of associative operators acting on values
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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