-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtree.py
211 lines (172 loc) · 6.4 KB
/
tree.py
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/bin/python
from qtree import Qtree
from sympy import *
from sympy.core import symbols
from sympy.logic.boolalg import Or, And, Not, Implies, Equivalent
import copy
class TraversibleExpression(object):
"""
An expression in propositional logic that can generate a tree proof style tree
and generate a corresponding object using Python Sympy objects.
"""
def __init__(self):
self.stack = []
def __repr__(self):
return str(self)
def getSubTree(self, elideRoot=False):
"""
@return: A Qtree instance.
"""
print "TraversibleExpression getSubtree on", self.render()
myQtree = self.qtree(elideRoot=elideRoot)
if len(self.stack) > 0:
if not myQtree._branches:
# Either, we can deal with the extra work immediately if we
# have no further branches:
print "BEFORE STACK for", self.render(), ":", [s.render() for s in self.stack]
print "BEFORE BRANCHES for", myQtree, ":", myQtree._branches
myQtree._branches.append(
self.stack.pop().getSubTree(elideRoot=True))
print "ATFER STACK for", self.render(), ":", [s.render() for s in self.stack]
print "AFTER BRANCHES for", myQtree, ":", myQtree._branches
else:
# Or, we have branches, in which case the work is deferred
# ('punted') deeper into the tree.
print "Punting into stack of", self.render(), "<-", [s.render() for s in self.stack]
self.punt(copy.copy(self.stack))
print "CALLING qtree a second time for some reason who knows"
myQtree = self.qtree(elideRoot=elideRoot)
return myQtree
class Not_exp(TraversibleExpression):
"""
NOT expression. Can have one sub-expression.
"""
isComplex = True
def __init__(self, sub):
TraversibleExpression.__init__(self)
self.sub = sub
def render(self):
return "Not(%s)" % (self.sub.render(),)
#return "NOT " + self.sub.render()
def branch(self):
return r"%s" % (self.render())
def qtree(self, elideRoot=False):
return Qtree(self.render())
def punt(self, stuff):
print "Not(%s) punt(%s), extending own stack %s" % (
self.render(),
[s.render() for s in stuff],
[s.render() for s in self.stack],
)
self.stack.extend(stuff)
def sympy_me(self):
return ~(self.sub.sympy_me())
class Or_exp(TraversibleExpression):
"""
OR expression. Can have sub-expressions.
"""
isComplex = True
def __init__(self, lhs, rhs):
TraversibleExpression.__init__(self)
self.lhs = lhs
self.rhs = rhs
def render(self):
return "Or(%s, %s)" % (self.lhs.render(), self.rhs.render())
#return "(" + self.lhs.render() + " OR " + self.rhs.render() + ")"
def qtree(self, elideRoot=False):
if elideRoot:
text = ""
else:
text = self.render()
return Qtree(text, [self.lhs.getSubTree(), self.rhs.getSubTree()])
def punt(self, stuff):
print "Or(%s) punt(%s), extending lhs stack %s and rhs stack %s, my stack is %s" % (
self.render(), [s.render() for s in stuff],
[s.render() for s in self.lhs.stack],
[s.render() for s in self.rhs.stack],
[s.render() for s in self.stack],
)
self.lhs.stack.extend(stuff)
self.rhs.stack.extend(stuff)
def sympy_me(self):
return self.lhs.sympy_me() | self.rhs.sympy_me()
class And_exp(TraversibleExpression):
"""
AND expression. Can have sub-expressions.
"""
isComplex = True
def __init__(self, lhs, rhs):
TraversibleExpression.__init__(self)
self.lhs = lhs
self.rhs = rhs
def render(self):
return "And(%s, %s)" % (self.lhs.render(), self.rhs.render())
def _newlineHead(self):
return "%s\n%s" % (self.lhs.render(), self.rhs.render())
def qtree(self, elideRoot=False):
"""
For And expressions, render a subtree with each of the conjuncts
separated by a newline as the head, and then proceed to recursively
expand each conjunct in turn, one at a time.
"""
if self.lhs.isComplex and self.rhs.isComplex:
self.lhs.stack.append(self.rhs)
subQtreeBranches = []
if self.lhs.isComplex:
subQtreeBranches.append(self.lhs.getSubTree(elideRoot=True))
elif self.rhs.isComplex:
subQtreeBranches.append(self.rhs.getSubTree(elideRoot=True))
innerQtree = Qtree(self._newlineHead(), subQtreeBranches)
if elideRoot:
return innerQtree
else:
return Qtree(self.render(), [innerQtree])
def punt(self, stuff):
print "And(%s) punt(%s), extending lhs stack %s and rhs stack %s, my stack is %s" % (
self.render(), [s.render() for s in stuff],
[s.render() for s in self.lhs.stack],
[s.render() for s in self.rhs.stack],
[s.render() for s in self.stack],
)
self.lhs.stack.extend(stuff)
self.rhs.stack.extend(stuff)
def sympy_me(self):
return self.lhs.sympy_me() & self.rhs.sympy_me()
class PropVar(TraversibleExpression):
"""
E.g., 'p' or 'q'.
"""
isComplex = False
def __init__(self, name):
TraversibleExpression.__init__(self)
self.name = name
def render(self):
return self.name
def branch(self):
return r"%s" % (self.render())
def qtree(self, elideRoot=False):
"""
Given the expression that is self, return a Qtree which can be rendered
into the LaTeX we want to output.
"""
return Qtree(self.render())
def punt(self, stuff):
print "PropVar(%s) punt(%s), extending own stack %s" % (
self.render(), [s.render() for s in stuff],
[s.render() for s in self.stack],
)
for s in stuff:
if s not in self.stack:
self.stack.append(s)
else:
print "FOUND A DUPE, IGNORING IT"
#self.stack.extend(stuff)
def sympy_me(self):
"""
returns a sympy Symbol
"""
return sympify(self.name)
if __name__ == "__main__":
expr = And_exp(Or_exp(PropVar('p'), PropVar('q')), PropVar('r'))
print expr.sympy_me()
# testing