Fix negation.
2 Name: sml - Simple Modal Logic Lib.
3 Description: sml provides classes for simple modal logic formulae construction and reduction. It also features a buggy parser for the SML syntax.
4 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
9 # edit your formulae here
13 formula1 = Imp([Eq([p, q]), r])
14 formula2 = Not([Or([p, q])])
15 formula3 = Not([Not([p])])
16 formula = formula1 # choose your formula here
18 args = parse_arguments()
20 scanner = Scanner(TOKENS)
21 parser = Parser(SYNTAX, scanner)
22 (accepted, out, tree_nodes) = parser.parse(args.formula)
26 tree = SyntaxTree(out, tree_nodes)
29 print "formula: \t\t", formula
30 print "expanded -> and <->: \t", expand_imp_eq(formula)
31 print "reduced ~: \t\t", reduce_not(expand_imp_eq(formula))
33 def expand_imp_eq(formula):
34 map = {IMP: lambda (a, b): Or([Not([a]), b]),
35 EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])])}
38 return [expand_imp_eq(v) for v in formula.values]
40 if not isinstance(formula, Operator) or formula.id not in map:
42 return map[formula.id](values())
44 def reduce_not(formula):
45 negmap = {AND: lambda (a, b): Or([negate(a), negate(b)]),
46 OR: lambda (a, b): And([negate(a), negate(b)]),
47 VARIABLE: lambda (a,): Not([a]),
51 return [reduce_not(v) for v in formula.values]
54 return negmap[f.id](f.values)
56 if not isinstance(formula, Operator):
59 return negate(formula.values[0])
60 return formula.__class__(values())
65 map = {NOT: lambda (a,): not isinstance(a, Not)
66 and not isinstance(a.values[0], Not)
67 and a.__class__([Not([reduce2(v)]) for v in a.values]) or a.values[0]}
70 return [reduce2(v) for v in formula.values]
72 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
74 elif formula.id not in map:
75 return formula.__class__(values())
76 return map[formula.id](values())
89 class Operator(object):
90 def __init__(self, id, arity, values):
97 out = str(self.values[0])
99 out = self.id + str(self.values[0])
100 elif self.arity == 2:
101 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
106 def __init__(self, values):
107 Operator.__init__(self, NOT, Not.arity, values)
113 def __init__(self, values):
114 Operator.__init__(self, AND, And.arity, values)
118 def __init__(self, values):
119 Operator.__init__(self, OR, Or.arity, values)
123 def __init__(self, values):
124 Operator.__init__(self, IMP, Imp.arity, values)
128 def __init__(self, values):
129 Operator.__init__(self, EQ, Eq.arity, values)
133 def __init__(self, values):
134 Operator.__init__(self, BOX, Box.arity, values)
136 class Diamond(Operator):
138 def __init__(self, values):
139 Operator.__init__(self, DIAMOND, Diamond.arity, values)
141 class Variable(Operator):
143 def __init__(self, values):
144 Operator.__init__(self, VARIABLE, Variable.arity, values)
148 def __init__(self, values):
149 Operator.__init__(self, LB, Lb.arity, values)
153 def __init__(self, values):
154 Operator.__init__(self, RB, Rb.arity, values)
156 class Formula(object):
160 TOKENS = {re.compile("\("): Lb,
161 re.compile("\)"): Rb,
162 re.compile("~"): Not,
163 re.compile("&"): And,
164 re.compile("\|"): Or,
165 re.compile("->"): Imp,
166 re.compile("<->"): Eq,
167 re.compile("\[\]"): Box,
168 re.compile("<>"): Diamond,
169 re.compile("[a-z]+"): Variable}
171 class Scanner(object):
172 def __init__(self, tokens, source=None):
176 while self.i < len(self.source):
178 for p, token in self.tokens.iteritems():
179 m = p.match(self.source[self.i:])
183 return (token, value)
186 def reset(self, source):
201 SYNTAX = ((Variable,),
212 def __init__(self, parent, value):
216 def addChild(self, value):
217 self.children.append(self, node)
219 class Parser(object):
220 def __init__(self, syntax, scanner):
222 self.scanner = scanner
223 def parse(self, source):
224 table = {(S, Variable): 0,
233 (A, Variable, And): 5,
234 (A, Variable, Or): 6,
235 (A, Variable, Imp): 7,
236 (A, Variable, Eq): 8,
237 (A, Not, Variable, And): 5,
238 (A, Not, Variable, Or): 6,
239 (A, Not, Variable, Imp): 7,
240 (A, Not, Variable, Eq): 8}
245 self.scanner.reset(source)
246 (token, value) = self.scanner.next()
247 (lookahead, la_value) = self.scanner.next()
248 (lookahead2, la2_value) = self.scanner.next()
250 while token and len(stack):
253 tree_nodes.append((token, value))
255 #tree_nodes.append((stack.pop(), value))
256 (token, value) = (lookahead, la_value)
257 (lookahead, la_value) = (lookahead2, la2_value)
258 #(lookahead, _) = self.scanner.next()
259 (lookahead2, la2_value) = self.scanner.next()
262 if (top, token) in table:
263 action = table[(top, token)]
264 elif (top, token, lookahead) in table:
265 action = table[(top, token, lookahead)]
266 elif (top, token, lookahead, lookahead2) in table:
267 action = table[(top, token, lookahead, lookahead2)]
274 stack.extend(reversed(self.syntax[action]))
275 accepted = accepted and not len(stack)
276 return (accepted, out, tree_nodes)
278 class SyntaxTree(object):
279 def __init__(self, seq, tree_nodes):
282 self.root = self.compile(seq, tree_nodes)[0]
283 def compile(self, seq, tree_nodes):
288 c, v = tree_nodes.pop()
290 c, v = tree_nodes.pop()
291 stack.append(Variable(v))
293 stack.append(Not(self.compile(seq, tree_nodes)))
295 stack.extend(self.compile(seq, tree_nodes))
297 stack.append(Box(self.compile(seq, tree_nodes)))
299 stack.append(Diamond(self.compile(seq, tree_nodes)))
301 stack.append(And(self.compile(seq, tree_nodes)))
303 stack.append(Or(self.compile(seq, tree_nodes)))
305 stack.append(Imp(self.compile(seq, tree_nodes)))
307 stack.append(Eq(self.compile(seq, tree_nodes)))
310 from argparse import ArgumentParser
312 def parse_arguments():
313 parser = ArgumentParser(description="Parses simple modal logic syntax.")
314 parser.add_argument("-f", "--formula", help="your formula")
315 return parser.parse_args()
317 EXCUSE = """The formula was not accepted by the parser, because the parser doesn't like you or the rest of the world. It seems to have some real issues with formulae with inner nesting and generally suffers from its hasty implementation. The parser would like to thank you for your coorporation by providing the formula within the code file itself. Thank you."""
319 if __name__ == "__main__":