Minor fix.
2 Name: sml - Simple Modal Logic Lib.
3 Description: sml provides classes for simple modal logic formulae construction and reduction. It also features a disfunctional parser for the SML syntax.
4 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
8 # edit your formulae here
13 formula1 = Imp(Eq(p, q), r)
14 formula2 = Not(Or(p, q))
15 formula3 = Not(Not(p))
16 formula4 = Imp(Box(Imp(Diamond(p), p)), Box(Imp(p, Box(p))))
17 formula5 = Imp(And(Or(p, q), r), Not(s))
18 formula = formula4 # choose your formula here
20 args = parse_arguments()
22 scanner = Scanner(TOKENS)
23 parser = Parser(SYNTAX, scanner)
24 (accepted, out, tree_nodes) = parser.parse(args.formula)
28 tree = SyntaxTree(out, tree_nodes)
32 print "formula: \t\t\t%s [%i]" % (formula, formula.depth())
33 formula = expand_imp_eq(formula)
34 print "expanded -> and <->: \t\t%s [%i]" % (formula, formula.depth())
35 formula = de_morgan(formula)
36 print "reduced ~: \t\t\t%s [%i]" % (formula, formula.depth())
37 formula = reduce_iter(formula)
38 print "reduced iterated modalities: \t%s [%i]" % (formula, formula.depth())
39 formula = reduce_iter(dist_mod((formula)))
40 print "distributed modalities+: \t%s [%i]" % (formula, formula.depth())
41 formula = mcnf(formula)
42 print "alpha mcnf: \t\t\t%s [%i]" % (formula, formula.depth())
43 cnf_formula = cnf(original)
44 print "alpha cnf: \t\t\t%s [%i]" % (cnf_formula, cnf_formula.depth())
47 return [fun(v) for v in f.values]
49 def expand_imp_eq(formula):
50 expmap = {IMP: lambda (a, b): Or(Not(a), b),
51 EQ: lambda (a, b): And(Or(Not(a), b), Or(a, Not(b)))}
52 if not isinstance(formula, Operator):
54 if formula.id in expmap:
55 return expmap[formula.id](values(expand_imp_eq, formula))
56 return formula.__class__(*values(expand_imp_eq, formula))
58 def de_morgan(formula):
59 negmap = {AND: lambda (a, b): Or(negate(a), negate(b)),
60 OR: lambda (a, b): And(negate(a), negate(b)),
61 BOX: lambda (a,): Diamond(negate(a)),
62 DIAMOND: lambda (a,): Box(negate(a)),
63 VARIABLE: lambda (a,): Not(Variable(a)),
66 return negmap[f.id](f.values)
67 if not isinstance(formula, Operator):
70 return negate(formula.values[0])
71 return formula.__class__(*values(de_morgan, formula))
73 def reduce_iter(formula):
74 redset = set(((BOX, BOX), (DIAMOND, DIAMOND), (DIAMOND, BOX), (BOX, DIAMOND)))
75 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
77 ids = (formula.id, formula.values[0].id)
79 return reduce_iter(formula.values[0])
80 return formula.__class__(*values(reduce_iter, formula))
82 def dist_mod(formula):
83 distmap = {(BOX, AND): lambda (a, b): And(Box(a), Box(b)),
84 (DIAMOND, OR): lambda (a, b): Or(Diamond(a), Diamond(b)),
85 (BOX, OR): lambda (a, b): (isinstance(a, Box) or isinstance(b, Box))
86 and Or(Box(a), Box(b)) or Box(Or(a, b)),
87 (DIAMOND, AND): lambda (a, b): (isinstance(a, Diamond) or isinstance(b, Diamond))
88 and And(Diamond(a), Diamond(b)) or Diamond(And(a, b))}
89 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
91 ids = (formula.id, formula.values[0].id)
93 return distmap[ids](values(dist_mod, formula.values[0]))
94 return formula.__class__(*values(dist_mod, formula))
98 conj_id = int(formula.values[1].id == AND)
99 return And(Or(formula.values[conj_id].values[0], formula.values[1 - conj_id]),
100 Or(formula.values[conj_id].values[1], formula.values[1 - conj_id]));
107 sub_formulae.append(v)
109 sub_formulae = [formula]
111 sub_formulae.reverse()
114 for s in sub_formulae:
115 for i, v in enumerate(s.values):
117 s.values[i] = known[v]
118 bicon.append(Eq(Variable("x" + str(len(bicon))), s))
119 known[s] = bicon[-1].values[0]
122 return And(f, conjunct(bicon.pop()))
124 return mcnf(dist_mod(reduce_iter(de_morgan(expand_imp_eq(conjunct(known[formula]))))))
126 """ The Parser - Do NOT look below this line! """
140 class Operator(object):
141 def __init__(self, id, arity, *values):
144 self.values = list(values)
148 if self.id in (BOX, DIAMOND):
149 return 1 + self.values[0].depth()
151 return self.values[0].depth()
152 return max(self.values[0].depth(), self.values[1].depth())
153 def __eq__(self, other):
154 return self.id == other.id and self.values == other.values # commutative types not considered yet
158 out = str(self.values[0])
160 out = self.id + str(self.values[0])
161 elif self.arity == 2:
162 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
167 def __init__(self, *values):
168 Operator.__init__(self, NOT, Not.arity, *values)
174 def __init__(self, *values):
175 Operator.__init__(self, AND, And.arity, *values)
179 def __init__(self, *values):
180 Operator.__init__(self, OR, Or.arity, *values)
184 def __init__(self, *values):
185 Operator.__init__(self, IMP, Imp.arity, *values)
189 def __init__(self, *values):
190 Operator.__init__(self, EQ, Eq.arity, *values)
194 def __init__(self, *values):
195 Operator.__init__(self, BOX, Box.arity, *values)
197 class Diamond(Operator):
199 def __init__(self, *values):
200 Operator.__init__(self, DIAMOND, Diamond.arity, *values)
202 class Variable(Operator):
204 def __init__(self, *values):
205 Operator.__init__(self, VARIABLE, Variable.arity, *values)
209 def __init__(self, *values):
210 Operator.__init__(self, LB, Lb.arity, *values)
214 def __init__(self, *values):
215 Operator.__init__(self, RB, Rb.arity, *values)
217 class Formula(object):
221 TOKENS = {re.compile("\("): Lb,
222 re.compile("\)"): Rb,
223 re.compile("~"): Not,
224 re.compile("&"): And,
225 re.compile("\|"): Or,
226 re.compile("->"): Imp,
227 re.compile("<->"): Eq,
228 re.compile("\[\]"): Box,
229 re.compile("<>"): Diamond,
230 re.compile("[a-z]+"): Variable}
232 class Scanner(object):
233 def __init__(self, tokens, source=None):
237 while self.i < len(self.source):
239 for p, token in self.tokens.iteritems():
240 m = p.match(self.source[self.i:])
244 return (token, value)
247 def reset(self, source):
262 SYNTAX = ((Variable,),
272 class Parser(object):
273 def __init__(self, syntax, scanner):
275 self.scanner = scanner
276 def parse(self, source):
277 table = {(S, Variable): 0,
286 (A, Variable, And): 5,
287 (A, Variable, Or): 6,
288 (A, Variable, Imp): 7,
289 (A, Variable, Eq): 8,
290 (A, Not, Variable, And): 5,
291 (A, Not, Variable, Or): 6,
292 (A, Not, Variable, Imp): 7,
293 (A, Not, Variable, Eq): 8}
298 self.scanner.reset(source)
299 (token, value) = self.scanner.next()
300 (lookahead, la_value) = self.scanner.next()
301 (lookahead2, la2_value) = self.scanner.next()
303 while token and len(stack):
306 tree_nodes.append((token, value))
308 #tree_nodes.append((stack.pop(), value))
309 (token, value) = (lookahead, la_value)
310 (lookahead, la_value) = (lookahead2, la2_value)
311 #(lookahead, _) = self.scanner.next()
312 (lookahead2, la2_value) = self.scanner.next()
315 if (top, token) in table:
316 action = table[(top, token)]
317 elif (top, token, lookahead) in table:
318 action = table[(top, token, lookahead)]
319 elif (top, token, lookahead, lookahead2) in table:
320 action = table[(top, token, lookahead, lookahead2)]
327 stack.extend(reversed(self.syntax[action]))
328 accepted = accepted and not len(stack)
329 return (accepted, out, tree_nodes)
331 class SyntaxTree(object):
332 def __init__(self, seq, tree_nodes):
335 self.root = self.compile(seq, tree_nodes)[0]
336 def compile(self, seq, tree_nodes):
341 c, v = tree_nodes.pop()
343 c, v = tree_nodes.pop()
344 stack.append(Variable(v))
346 stack.append(Not(self.compile(seq, tree_nodes)))
348 stack.extend(self.compile(seq, tree_nodes))
350 stack.append(Box(self.compile(seq, tree_nodes)))
352 stack.append(Diamond(self.compile(seq, tree_nodes)))
354 stack.append(And(self.compile(seq, tree_nodes)))
356 stack.append(Or(self.compile(seq, tree_nodes)))
358 stack.append(Imp(self.compile(seq, tree_nodes)))
360 stack.append(Eq(self.compile(seq, tree_nodes)))
363 from argparse import ArgumentParser
365 def parse_arguments():
366 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.")
367 parser.add_argument("-f", "--formula", help="provide your own formula here, or better don't")
368 return parser.parse_args()
370 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"""
372 if __name__ == "__main__":