sawine@12
|
1 |
"""
|
sawine@13
|
2 |
Name: sml - Simple Modal Logic Lib.
|
sawine@17
|
3 |
Description: sml provides classes for simple modal logic formulae construction and reduction. It also features a disfunctional parser for the SML syntax.
|
sawine@12
|
4 |
Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
|
sawine@12
|
5 |
"""
|
sawine@12
|
6 |
|
sawine@26
|
7 |
TMP_DIMACS = "dimacs~"
|
sawine@26
|
8 |
TMP_SOLUTION = "solution~"
|
sawine@26
|
9 |
|
sawine@12
|
10 |
def main():
|
sawine@15
|
11 |
# edit your formulae here
|
sawine@23
|
12 |
p = Variable("p")
|
sawine@23
|
13 |
q = Variable("q")
|
sawine@23
|
14 |
r = Variable("r")
|
sawine@23
|
15 |
s = Variable("s")
|
sawine@23
|
16 |
formula1 = Imp(Eq(p, q), r)
|
sawine@23
|
17 |
formula2 = Not(Or(p, q))
|
sawine@23
|
18 |
formula3 = Not(Not(p))
|
sawine@23
|
19 |
formula4 = Imp(Box(Imp(Diamond(p), p)), Box(Imp(p, Box(p))))
|
sawine@23
|
20 |
formula5 = Imp(And(Or(p, q), r), Not(s))
|
sawine@25
|
21 |
formula6 = And(Or(p, Or(q, Not(s))), And(Or(r, Not(s)), Or(Not(p), s)))
|
sawine@25
|
22 |
formula = formula6 # choose your formula here
|
sawine@12
|
23 |
|
sawine@25
|
24 |
args = parse_arguments()
|
sawine@12
|
25 |
if (args.formula):
|
sawine@12
|
26 |
scanner = Scanner(TOKENS)
|
sawine@12
|
27 |
parser = Parser(SYNTAX, scanner)
|
sawine@12
|
28 |
(accepted, out, tree_nodes) = parser.parse(args.formula)
|
sawine@12
|
29 |
if not accepted:
|
sawine@12
|
30 |
print EXCUSE
|
sawine@12
|
31 |
return
|
sawine@12
|
32 |
tree = SyntaxTree(out, tree_nodes)
|
sawine@12
|
33 |
formula = tree.root
|
sawine@12
|
34 |
|
sawine@22
|
35 |
original = formula
|
sawine@22
|
36 |
print "formula: \t\t\t%s [%i]" % (formula, formula.depth())
|
sawine@20
|
37 |
formula = expand_imp_eq(formula)
|
sawine@22
|
38 |
print "expanded -> and <->: \t\t%s [%i]" % (formula, formula.depth())
|
sawine@20
|
39 |
formula = de_morgan(formula)
|
sawine@22
|
40 |
print "reduced ~: \t\t\t%s [%i]" % (formula, formula.depth())
|
sawine@20
|
41 |
formula = reduce_iter(formula)
|
sawine@22
|
42 |
print "reduced iterated modalities: \t%s [%i]" % (formula, formula.depth())
|
sawine@20
|
43 |
formula = reduce_iter(dist_mod((formula)))
|
sawine@22
|
44 |
print "distributed modalities+: \t%s [%i]" % (formula, formula.depth())
|
sawine@21
|
45 |
formula = mcnf(formula)
|
sawine@22
|
46 |
print "alpha mcnf: \t\t\t%s [%i]" % (formula, formula.depth())
|
sawine@26
|
47 |
#cnf_formula = cnf(original)
|
sawine@26
|
48 |
#print "alpha cnf: \t\t\t%s [%i]" % (cnf_formula, cnf_formula.depth())
|
sawine@26
|
49 |
|
sawine@26
|
50 |
if not args.dimacs:
|
sawine@26
|
51 |
dimacs_file = TMP_DIMACS
|
sawine@26
|
52 |
else:
|
sawine@26
|
53 |
dimacs_file = args.dimacs
|
sawine@26
|
54 |
solution = sat_test(original, dimacs_file)
|
sawine@26
|
55 |
if solution:
|
sawine@26
|
56 |
print "satisfiable: \t\t\t%s " % (", ".join([str(s) for s in solution]))
|
sawine@26
|
57 |
else:
|
sawine@26
|
58 |
print "not satisfiable"
|
sawine@26
|
59 |
|
sawine@26
|
60 |
from subprocess import call, PIPE
|
sawine@19
|
61 |
|
sawine@26
|
62 |
def sat_test(formula, dimacs_file):
|
sawine@26
|
63 |
out, variables = dimacs(formula)
|
sawine@26
|
64 |
with open(dimacs_file, "w") as f:
|
sawine@26
|
65 |
f.write(out)
|
sawine@26
|
66 |
call(["minisat2", "-verb=0", dimacs_file, TMP_SOLUTION], stdout=PIPE)
|
sawine@26
|
67 |
with open(TMP_SOLUTION) as f:
|
sawine@26
|
68 |
solved, assignment = f.readlines()
|
sawine@26
|
69 |
solved = solved[0] == "S"
|
sawine@26
|
70 |
if solved:
|
sawine@26
|
71 |
positive = set()
|
sawine@26
|
72 |
for a in assignment.split():
|
sawine@26
|
73 |
neg = a[0] == "-"
|
sawine@26
|
74 |
if not neg:
|
sawine@26
|
75 |
positive.add(int(a))
|
sawine@26
|
76 |
solution = []
|
sawine@26
|
77 |
for v, n in variables.iteritems():
|
sawine@26
|
78 |
if n in positive:
|
sawine@26
|
79 |
solution.append(Variable(v))
|
sawine@26
|
80 |
else:
|
sawine@26
|
81 |
solution.append(Not(Variable(v)))
|
sawine@26
|
82 |
return solution
|
sawine@25
|
83 |
|
sawine@25
|
84 |
def dimacs(formula):
|
sawine@25
|
85 |
def clausify(f):
|
sawine@25
|
86 |
if f.id == AND:
|
sawine@25
|
87 |
c1 = clausify(f.values[0])
|
sawine@25
|
88 |
c2 = clausify(f.values[1])
|
sawine@25
|
89 |
if c1:
|
sawine@25
|
90 |
clauses.append(clausify(f.values[0]))
|
sawine@25
|
91 |
if c2:
|
sawine@25
|
92 |
clauses.append(clausify(f.values[1]))
|
sawine@25
|
93 |
if f.id == OR:
|
sawine@25
|
94 |
clause = []
|
sawine@25
|
95 |
clause.extend(clausify(f.values[0]))
|
sawine@25
|
96 |
clause.extend(clausify(f.values[1]))
|
sawine@25
|
97 |
return clause
|
sawine@25
|
98 |
if f.id == NOT:
|
sawine@25
|
99 |
return ["-" + clausify(f.values[0])]
|
sawine@25
|
100 |
if f.id == VARIABLE:
|
sawine@25
|
101 |
if f.values[0] in variables:
|
sawine@25
|
102 |
n = variables[f.values[0]]
|
sawine@25
|
103 |
else:
|
sawine@25
|
104 |
n = len(variables) + 1
|
sawine@25
|
105 |
variables[f.values[0]] = n
|
sawine@25
|
106 |
return str(n)
|
sawine@25
|
107 |
|
sawine@25
|
108 |
variables = {}
|
sawine@25
|
109 |
clauses = []
|
sawine@25
|
110 |
clausify(formula)
|
sawine@25
|
111 |
out = "c DIMACS CNF input file generated by sml\n"
|
sawine@25
|
112 |
out += "c Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>\n"
|
sawine@25
|
113 |
out += "p cnf %i %i\n" % (len(variables), len(clauses))
|
sawine@25
|
114 |
out += " 0\n".join([" ".join(c) for c in clauses]) + " 0\n"
|
sawine@26
|
115 |
return out, variables
|
sawine@25
|
116 |
|
sawine@19
|
117 |
def values(fun, f):
|
sawine@19
|
118 |
return [fun(v) for v in f.values]
|
sawine@12
|
119 |
|
sawine@14
|
120 |
def expand_imp_eq(formula):
|
sawine@23
|
121 |
expmap = {IMP: lambda (a, b): Or(Not(a), b),
|
sawine@23
|
122 |
EQ: lambda (a, b): And(Or(Not(a), b), Or(a, Not(b)))}
|
sawine@20
|
123 |
if not isinstance(formula, Operator):
|
sawine@12
|
124 |
return formula
|
sawine@20
|
125 |
if formula.id in expmap:
|
sawine@20
|
126 |
return expmap[formula.id](values(expand_imp_eq, formula))
|
sawine@23
|
127 |
return formula.__class__(*values(expand_imp_eq, formula))
|
sawine@14
|
128 |
|
sawine@20
|
129 |
def de_morgan(formula):
|
sawine@23
|
130 |
negmap = {AND: lambda (a, b): Or(negate(a), negate(b)),
|
sawine@23
|
131 |
OR: lambda (a, b): And(negate(a), negate(b)),
|
sawine@23
|
132 |
BOX: lambda (a,): Diamond(negate(a)),
|
sawine@23
|
133 |
DIAMOND: lambda (a,): Box(negate(a)),
|
sawine@23
|
134 |
VARIABLE: lambda (a,): Not(Variable(a)),
|
sawine@19
|
135 |
NOT: lambda (a,): a}
|
sawine@14
|
136 |
def negate(f):
|
sawine@20
|
137 |
return negmap[f.id](f.values)
|
sawine@14
|
138 |
if not isinstance(formula, Operator):
|
sawine@18
|
139 |
return formula
|
sawine@14
|
140 |
if formula.id == NOT:
|
sawine@14
|
141 |
return negate(formula.values[0])
|
sawine@23
|
142 |
return formula.__class__(*values(de_morgan, formula))
|
sawine@18
|
143 |
|
sawine@18
|
144 |
def reduce_iter(formula):
|
sawine@18
|
145 |
redset = set(((BOX, BOX), (DIAMOND, DIAMOND), (DIAMOND, BOX), (BOX, DIAMOND)))
|
sawine@18
|
146 |
if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
|
sawine@18
|
147 |
return formula
|
sawine@18
|
148 |
ids = (formula.id, formula.values[0].id)
|
sawine@18
|
149 |
if ids in redset:
|
sawine@18
|
150 |
return reduce_iter(formula.values[0])
|
sawine@23
|
151 |
return formula.__class__(*values(reduce_iter, formula))
|
sawine@19
|
152 |
|
sawine@20
|
153 |
def dist_mod(formula):
|
sawine@23
|
154 |
distmap = {(BOX, AND): lambda (a, b): And(Box(a), Box(b)),
|
sawine@23
|
155 |
(DIAMOND, OR): lambda (a, b): Or(Diamond(a), Diamond(b)),
|
sawine@19
|
156 |
(BOX, OR): lambda (a, b): (isinstance(a, Box) or isinstance(b, Box))
|
sawine@23
|
157 |
and Or(Box(a), Box(b)) or Box(Or(a, b)),
|
sawine@19
|
158 |
(DIAMOND, AND): lambda (a, b): (isinstance(a, Diamond) or isinstance(b, Diamond))
|
sawine@23
|
159 |
and And(Diamond(a), Diamond(b)) or Diamond(And(a, b))}
|
sawine@19
|
160 |
if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
|
sawine@19
|
161 |
return formula
|
sawine@19
|
162 |
ids = (formula.id, formula.values[0].id)
|
sawine@19
|
163 |
if ids in distmap:
|
sawine@24
|
164 |
return distmap[ids](values(dist_mod, formula.values[0]))
|
sawine@23
|
165 |
return formula.__class__(*values(dist_mod, formula))
|
sawine@21
|
166 |
|
sawine@21
|
167 |
def mcnf(formula):
|
sawine@21
|
168 |
if formula.id == OR:
|
sawine@21
|
169 |
conj_id = int(formula.values[1].id == AND)
|
sawine@23
|
170 |
return And(Or(formula.values[conj_id].values[0], formula.values[1 - conj_id]),
|
sawine@23
|
171 |
Or(formula.values[conj_id].values[1], formula.values[1 - conj_id]));
|
sawine@22
|
172 |
return formula
|
sawine@22
|
173 |
|
sawine@22
|
174 |
def cnf(formula):
|
sawine@22
|
175 |
def part(f):
|
sawine@22
|
176 |
for v in f.values:
|
sawine@22
|
177 |
if v.id != VARIABLE:
|
sawine@22
|
178 |
sub_formulae.append(v)
|
sawine@25
|
179 |
part(v)
|
sawine@25
|
180 |
|
sawine@25
|
181 |
def conjunct(f):
|
sawine@25
|
182 |
if len(bicon):
|
sawine@25
|
183 |
return And(f, conjunct(bicon.pop()))
|
sawine@25
|
184 |
return f
|
sawine@25
|
185 |
|
sawine@22
|
186 |
sub_formulae = [formula]
|
sawine@22
|
187 |
part(formula)
|
sawine@22
|
188 |
sub_formulae.reverse()
|
sawine@22
|
189 |
known = {}
|
sawine@22
|
190 |
bicon = []
|
sawine@22
|
191 |
for s in sub_formulae:
|
sawine@22
|
192 |
for i, v in enumerate(s.values):
|
sawine@22
|
193 |
if v in known:
|
sawine@22
|
194 |
s.values[i] = known[v]
|
sawine@23
|
195 |
bicon.append(Eq(Variable("x" + str(len(bicon))), s))
|
sawine@25
|
196 |
known[s] = bicon[-1].values[0]
|
sawine@22
|
197 |
return mcnf(dist_mod(reduce_iter(de_morgan(expand_imp_eq(conjunct(known[formula]))))))
|
sawine@22
|
198 |
|
sawine@22
|
199 |
""" The Parser - Do NOT look below this line! """
|
sawine@23
|
200 |
import re
|
sawine@22
|
201 |
|
sawine@12
|
202 |
NOT = "~"
|
sawine@12
|
203 |
AND = "&"
|
sawine@12
|
204 |
OR = "|"
|
sawine@12
|
205 |
IMP = "->"
|
sawine@12
|
206 |
EQ = "<->"
|
sawine@12
|
207 |
BOX = "[]"
|
sawine@12
|
208 |
DIAMOND = "<>"
|
sawine@14
|
209 |
VARIABLE = "VAR"
|
sawine@12
|
210 |
LB = "("
|
sawine@12
|
211 |
RB = ")"
|
sawine@12
|
212 |
|
sawine@12
|
213 |
class Operator(object):
|
sawine@23
|
214 |
def __init__(self, id, arity, *values):
|
sawine@12
|
215 |
self.id = id
|
sawine@12
|
216 |
self.arity = arity
|
sawine@23
|
217 |
self.values = list(values)
|
sawine@20
|
218 |
def depth(self):
|
sawine@20
|
219 |
if self.arity == 0:
|
sawine@20
|
220 |
return 0
|
sawine@20
|
221 |
if self.id in (BOX, DIAMOND):
|
sawine@20
|
222 |
return 1 + self.values[0].depth()
|
sawine@20
|
223 |
if self.id == NOT:
|
sawine@23
|
224 |
return self.values[0].depth()
|
sawine@20
|
225 |
return max(self.values[0].depth(), self.values[1].depth())
|
sawine@22
|
226 |
def __eq__(self, other):
|
sawine@22
|
227 |
return self.id == other.id and self.values == other.values # commutative types not considered yet
|
sawine@12
|
228 |
def __str__(self):
|
sawine@12
|
229 |
out = self.id
|
sawine@12
|
230 |
if self.arity == 0:
|
sawine@20
|
231 |
out = str(self.values[0])
|
sawine@12
|
232 |
if self.arity == 1:
|
sawine@12
|
233 |
out = self.id + str(self.values[0])
|
sawine@12
|
234 |
elif self.arity == 2:
|
sawine@12
|
235 |
out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
|
sawine@12
|
236 |
return out
|
sawine@12
|
237 |
|
sawine@12
|
238 |
class Not(Operator):
|
sawine@12
|
239 |
arity = 1
|
sawine@23
|
240 |
def __init__(self, *values):
|
sawine@23
|
241 |
Operator.__init__(self, NOT, Not.arity, *values)
|
sawine@12
|
242 |
def __call__(self):
|
sawine@12
|
243 |
pass
|
sawine@12
|
244 |
|
sawine@12
|
245 |
class And(Operator):
|
sawine@12
|
246 |
arity = 2
|
sawine@23
|
247 |
def __init__(self, *values):
|
sawine@23
|
248 |
Operator.__init__(self, AND, And.arity, *values)
|
sawine@12
|
249 |
|
sawine@12
|
250 |
class Or(Operator):
|
sawine@12
|
251 |
arity = 2
|
sawine@23
|
252 |
def __init__(self, *values):
|
sawine@23
|
253 |
Operator.__init__(self, OR, Or.arity, *values)
|
sawine@12
|
254 |
|
sawine@12
|
255 |
class Imp(Operator):
|
sawine@12
|
256 |
arity = 2
|
sawine@23
|
257 |
def __init__(self, *values):
|
sawine@23
|
258 |
Operator.__init__(self, IMP, Imp.arity, *values)
|
sawine@12
|
259 |
|
sawine@12
|
260 |
class Eq(Operator):
|
sawine@12
|
261 |
arity = 2
|
sawine@23
|
262 |
def __init__(self, *values):
|
sawine@23
|
263 |
Operator.__init__(self, EQ, Eq.arity, *values)
|
sawine@12
|
264 |
|
sawine@12
|
265 |
class Box(Operator):
|
sawine@12
|
266 |
arity = 1
|
sawine@23
|
267 |
def __init__(self, *values):
|
sawine@23
|
268 |
Operator.__init__(self, BOX, Box.arity, *values)
|
sawine@12
|
269 |
|
sawine@12
|
270 |
class Diamond(Operator):
|
sawine@12
|
271 |
arity = 1
|
sawine@23
|
272 |
def __init__(self, *values):
|
sawine@23
|
273 |
Operator.__init__(self, DIAMOND, Diamond.arity, *values)
|
sawine@12
|
274 |
|
sawine@12
|
275 |
class Variable(Operator):
|
sawine@12
|
276 |
arity = 0
|
sawine@23
|
277 |
def __init__(self, *values):
|
sawine@23
|
278 |
Operator.__init__(self, VARIABLE, Variable.arity, *values)
|
sawine@12
|
279 |
|
sawine@12
|
280 |
class Lb(Operator):
|
sawine@12
|
281 |
arity = -1
|
sawine@23
|
282 |
def __init__(self, *values):
|
sawine@23
|
283 |
Operator.__init__(self, LB, Lb.arity, *values)
|
sawine@12
|
284 |
|
sawine@12
|
285 |
class Rb(Operator):
|
sawine@12
|
286 |
arity = -1
|
sawine@23
|
287 |
def __init__(self, *values):
|
sawine@23
|
288 |
Operator.__init__(self, RB, Rb.arity, *values)
|
sawine@12
|
289 |
|
sawine@12
|
290 |
class Formula(object):
|
sawine@12
|
291 |
def __init__(self):
|
sawine@12
|
292 |
pass
|
sawine@12
|
293 |
|
sawine@12
|
294 |
TOKENS = {re.compile("\("): Lb,
|
sawine@12
|
295 |
re.compile("\)"): Rb,
|
sawine@12
|
296 |
re.compile("~"): Not,
|
sawine@12
|
297 |
re.compile("&"): And,
|
sawine@12
|
298 |
re.compile("\|"): Or,
|
sawine@12
|
299 |
re.compile("->"): Imp,
|
sawine@12
|
300 |
re.compile("<->"): Eq,
|
sawine@12
|
301 |
re.compile("\[\]"): Box,
|
sawine@12
|
302 |
re.compile("<>"): Diamond,
|
sawine@12
|
303 |
re.compile("[a-z]+"): Variable}
|
sawine@12
|
304 |
|
sawine@12
|
305 |
class Scanner(object):
|
sawine@12
|
306 |
def __init__(self, tokens, source=None):
|
sawine@12
|
307 |
self.tokens = tokens
|
sawine@12
|
308 |
self.reset(source)
|
sawine@12
|
309 |
def next(self):
|
sawine@12
|
310 |
while self.i < len(self.source):
|
sawine@12
|
311 |
re.purge()
|
sawine@12
|
312 |
for p, token in self.tokens.iteritems():
|
sawine@12
|
313 |
m = p.match(self.source[self.i:])
|
sawine@12
|
314 |
if m:
|
sawine@12
|
315 |
self.i += m.end(0)
|
sawine@12
|
316 |
value = m.group(0)
|
sawine@12
|
317 |
return (token, value)
|
sawine@12
|
318 |
self.i += 1
|
sawine@12
|
319 |
return (None, None)
|
sawine@12
|
320 |
def reset(self, source):
|
sawine@12
|
321 |
self.i = 0
|
sawine@12
|
322 |
self.source = source
|
sawine@12
|
323 |
|
sawine@12
|
324 |
S = Formula
|
sawine@12
|
325 |
A = "A"
|
sawine@12
|
326 |
#0 S: (Variable,),
|
sawine@12
|
327 |
#1 S: (Not, S),
|
sawine@12
|
328 |
#2 S: (Lb, A, Rb),
|
sawine@12
|
329 |
#3 S: (Box, S),
|
sawine@12
|
330 |
#4 S: (Diamond, S),
|
sawine@12
|
331 |
#5 A: (S, And, S),
|
sawine@12
|
332 |
#6 A: (S, Or, S),
|
sawine@12
|
333 |
#7 A: (S, Imp, S),
|
sawine@12
|
334 |
#8 A: (S, Eq, S)
|
sawine@12
|
335 |
SYNTAX = ((Variable,),
|
sawine@12
|
336 |
(Not, S),
|
sawine@12
|
337 |
(Lb, A, Rb),
|
sawine@12
|
338 |
(Box, S),
|
sawine@12
|
339 |
(Diamond, S),
|
sawine@12
|
340 |
(S, And, S),
|
sawine@12
|
341 |
(S, Or, S),
|
sawine@12
|
342 |
(S, Imp, S),
|
sawine@12
|
343 |
(S, Eq, S))
|
sawine@12
|
344 |
|
sawine@12
|
345 |
class Parser(object):
|
sawine@12
|
346 |
def __init__(self, syntax, scanner):
|
sawine@12
|
347 |
self.syntax = syntax
|
sawine@12
|
348 |
self.scanner = scanner
|
sawine@12
|
349 |
def parse(self, source):
|
sawine@12
|
350 |
table = {(S, Variable): 0,
|
sawine@12
|
351 |
(S, Not): 1,
|
sawine@12
|
352 |
(S, Lb): 2,
|
sawine@12
|
353 |
(S, Box): 3,
|
sawine@12
|
354 |
(S, Diamond): 4,
|
sawine@12
|
355 |
(A, S, And): 5,
|
sawine@12
|
356 |
(A, S, Or): 6,
|
sawine@12
|
357 |
(A, S, Imp): 7,
|
sawine@12
|
358 |
(A, S, Eq): 8,
|
sawine@12
|
359 |
(A, Variable, And): 5,
|
sawine@12
|
360 |
(A, Variable, Or): 6,
|
sawine@12
|
361 |
(A, Variable, Imp): 7,
|
sawine@12
|
362 |
(A, Variable, Eq): 8,
|
sawine@12
|
363 |
(A, Not, Variable, And): 5,
|
sawine@12
|
364 |
(A, Not, Variable, Or): 6,
|
sawine@12
|
365 |
(A, Not, Variable, Imp): 7,
|
sawine@12
|
366 |
(A, Not, Variable, Eq): 8}
|
sawine@12
|
367 |
stack = [S]
|
sawine@12
|
368 |
tree_nodes = []
|
sawine@12
|
369 |
tree = None
|
sawine@12
|
370 |
out = []
|
sawine@12
|
371 |
self.scanner.reset(source)
|
sawine@12
|
372 |
(token, value) = self.scanner.next()
|
sawine@12
|
373 |
(lookahead, la_value) = self.scanner.next()
|
sawine@12
|
374 |
(lookahead2, la2_value) = self.scanner.next()
|
sawine@12
|
375 |
accepted = True
|
sawine@12
|
376 |
while token and len(stack):
|
sawine@12
|
377 |
top = stack[-1]
|
sawine@12
|
378 |
if top == token:
|
sawine@12
|
379 |
tree_nodes.append((token, value))
|
sawine@12
|
380 |
stack.pop()
|
sawine@12
|
381 |
#tree_nodes.append((stack.pop(), value))
|
sawine@12
|
382 |
(token, value) = (lookahead, la_value)
|
sawine@12
|
383 |
(lookahead, la_value) = (lookahead2, la2_value)
|
sawine@12
|
384 |
#(lookahead, _) = self.scanner.next()
|
sawine@12
|
385 |
(lookahead2, la2_value) = self.scanner.next()
|
sawine@12
|
386 |
else:
|
sawine@12
|
387 |
action = None
|
sawine@12
|
388 |
if (top, token) in table:
|
sawine@12
|
389 |
action = table[(top, token)]
|
sawine@12
|
390 |
elif (top, token, lookahead) in table:
|
sawine@12
|
391 |
action = table[(top, token, lookahead)]
|
sawine@12
|
392 |
elif (top, token, lookahead, lookahead2) in table:
|
sawine@12
|
393 |
action = table[(top, token, lookahead, lookahead2)]
|
sawine@12
|
394 |
if action is None:
|
sawine@12
|
395 |
accepted = False
|
sawine@12
|
396 |
break
|
sawine@12
|
397 |
|
sawine@12
|
398 |
out.append(action)
|
sawine@12
|
399 |
stack.pop()
|
sawine@12
|
400 |
stack.extend(reversed(self.syntax[action]))
|
sawine@12
|
401 |
accepted = accepted and not len(stack)
|
sawine@12
|
402 |
return (accepted, out, tree_nodes)
|
sawine@12
|
403 |
|
sawine@12
|
404 |
class SyntaxTree(object):
|
sawine@12
|
405 |
def __init__(self, seq, tree_nodes):
|
sawine@12
|
406 |
seq.reverse()
|
sawine@12
|
407 |
tree_nodes.reverse()
|
sawine@12
|
408 |
self.root = self.compile(seq, tree_nodes)[0]
|
sawine@12
|
409 |
def compile(self, seq, tree_nodes):
|
sawine@12
|
410 |
stack = []
|
sawine@12
|
411 |
while len(seq):
|
sawine@12
|
412 |
s = seq.pop()
|
sawine@12
|
413 |
if s == 0:
|
sawine@12
|
414 |
c, v = tree_nodes.pop()
|
sawine@12
|
415 |
while c != Variable:
|
sawine@12
|
416 |
c, v = tree_nodes.pop()
|
sawine@12
|
417 |
stack.append(Variable(v))
|
sawine@12
|
418 |
elif s == 1:
|
sawine@12
|
419 |
stack.append(Not(self.compile(seq, tree_nodes)))
|
sawine@12
|
420 |
elif s == 2:
|
sawine@12
|
421 |
stack.extend(self.compile(seq, tree_nodes))
|
sawine@12
|
422 |
elif s == 3:
|
sawine@12
|
423 |
stack.append(Box(self.compile(seq, tree_nodes)))
|
sawine@12
|
424 |
elif s == 4:
|
sawine@12
|
425 |
stack.append(Diamond(self.compile(seq, tree_nodes)))
|
sawine@12
|
426 |
elif s == 5:
|
sawine@12
|
427 |
stack.append(And(self.compile(seq, tree_nodes)))
|
sawine@12
|
428 |
elif s == 6:
|
sawine@12
|
429 |
stack.append(Or(self.compile(seq, tree_nodes)))
|
sawine@12
|
430 |
elif s == 7:
|
sawine@12
|
431 |
stack.append(Imp(self.compile(seq, tree_nodes)))
|
sawine@12
|
432 |
elif s == 8:
|
sawine@12
|
433 |
stack.append(Eq(self.compile(seq, tree_nodes)))
|
sawine@12
|
434 |
return stack
|
sawine@12
|
435 |
|
sawine@12
|
436 |
from argparse import ArgumentParser
|
sawine@12
|
437 |
|
sawine@12
|
438 |
def parse_arguments():
|
sawine@22
|
439 |
parser = ArgumentParser(description="Tries to parse simple modal logic syntax and reduces the formula. Edit your formula directly in the code file for best results.")
|
sawine@22
|
440 |
parser.add_argument("-f", "--formula", help="provide your own formula here, or better don't")
|
sawine@25
|
441 |
parser.add_argument("-d", "--dimacs", help="output file for the CNF DIMACS output")
|
sawine@12
|
442 |
return parser.parse_args()
|
sawine@12
|
443 |
|
sawine@20
|
444 |
EXCUSE = """The formula was not accepted by me, because I do not like you. It is not personal. I seem to have some issues with formulae with inner nesting and I generally suffer from my hasty implementation. I would like to thank you for your coorporation by providing the formula within the code file itself. Thank you. ~The Parser"""
|
sawine@12
|
445 |
|
sawine@12
|
446 |
if __name__ == "__main__":
|
sawine@12
|
447 |
main()
|