about summary refs log tree commit diff
path: root/users/wpcarro/scratch/facebook/recursion-and-dynamic-programming/parenthesize-bools.py
blob: f406d64e657f83a2124145a5249bee9a8e99a33a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# BNF
# expression -> bool ( ( '|' | '&' | '^' ) bool )*
# bool       -> '0' | '1'

def tokenize(xs):
    result = []
    for c in xs:
        if c == '0':
            result.append(0)
        elif c == '1':
            result.append(1)
        elif c in "&|^":
            result.append(c)
        else:
            raise Exception("Unexpected token, \"{}\"".format(c))
    return result

class Parser(object):
    def __init__(self, tokens):
        self.tokens = tokens
        self.i = 0

    def prev(self):
        return self.tokens[self.i - 1]

    def curr(self):
        return self.tokens[self.i]

    def match(self, xs):
        if self.exhausted():
            return False
        if (self.curr() in xs):
            self.consume()
            return True
        return False

    def consume(self):
        result = self.curr()
        self.i += 1
        return result

    def exhausted(self):
        return self.i >= len(self.tokens)

def recursive_descent(tokens):
    parser = Parser(tokens)
    return parse_expression(parser)

def parse_expression(parser):
    lhs = parse_bool(parser)
    while parser.match(['|', '&', '^']):
        op = parser.prev()
        rhs = parse_expression(parser)
        lhs = [op, lhs, rhs]
    return lhs

def parse_bool(parser):
    if parser.curr() == 0:
        parser.consume()
        return False
    elif parser.curr() == 1:
        parser.consume()
        return True
    else:
        raise Exception("Unexpected token: {}".format(parser.curr()))

def f(expr, result):
    tokens = tokenize(expr)
    tree = recursive_descent(tokens)
    return do_f(tree, result)

def do_f(tree, result):
    if type(tree) == bool:
        if tree == result:
            return 1
        else:
            return 0

    op, lhs, rhs = tree[0], tree[1], tree[2]
    truth_tables = {
        True: {
            '|': [
                (True, True),
                (True, False),
                (False, True),
            ],
            '&': [
                (True, True),
            ],
            '^': [
                (True, False),
                (False, True),
            ],
        },
        False: {
            '|': [
                (False, False),
            ],
            '&': [
                (False, False),
                (True, False),
                (False, True),
            ],
            '^': [
                (True, True),
                (False, False),
            ],
        }
    }

    return sum([do_f(lhs, x) * do_f(rhs, y) for x, y in truth_tables[result][op]])

print(f("1^0|0|1", False))
print(f("1|0|1|1", False))