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>
15 formula1 = Imp([Eq([p, q]), r])
16 formula2 = Not([Or([p, q])])
17 formula3 = Not([Not([p])])
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)
31 print "formula: \t\t", formula
32 print "expanded -> and <->: \t", expand_imp_eq(formula)
33 print "reduced ~: \t\t", reduce_not(expand_imp_eq(formula))
35 def expand_imp_eq(formula):
36 map = {IMP: lambda (a, b): Or([Not([a]), b]),
37 EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])])}
40 return [expand_imp_eq(v) for v in formula.values]
42 if not isinstance(formula, Operator) or formula.id not in map:
44 return map[formula.id](values())
46 def reduce_not(formula):
47 negmap = {AND: lambda (a, b): Or([negate(a), negate(b)]),
48 OR: lambda (a, b): And([negate(a), negate(b)]),
49 VARIABLE: lambda (a,): Not([a]),
53 return [reduce_not(v) for v in formula.values]
56 return negmap[f.id](f.values)
58 if not isinstance(formula, Operator):
61 return negate(formula.values[0])
62 return formula.__class__(values())
67 map = {NOT: lambda (a,): not isinstance(a, Not)
68 and not isinstance(a.values[0], Not)
69 and a.__class__([Not([reduce2(v)]) for v in a.values]) or a.values[0]}
72 return [reduce2(v) for v in formula.values]
74 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
76 elif formula.id not in map:
77 return formula.__class__(values())
78 return map[formula.id](values())
91 class Operator(object):
92 def __init__(self, id, arity, values):
99 out = str(self.values[0])
101 out = self.id + str(self.values[0])
102 elif self.arity == 2:
103 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
108 def __init__(self, values):
109 Operator.__init__(self, NOT, Not.arity, values)
115 def __init__(self, values):
116 Operator.__init__(self, AND, And.arity, values)
120 def __init__(self, values):
121 Operator.__init__(self, OR, Or.arity, values)
125 def __init__(self, values):
126 Operator.__init__(self, IMP, Imp.arity, values)
130 def __init__(self, values):
131 Operator.__init__(self, EQ, Eq.arity, values)
135 def __init__(self, values):
136 Operator.__init__(self, BOX, Box.arity, values)
138 class Diamond(Operator):
140 def __init__(self, values):
141 Operator.__init__(self, DIAMOND, Diamond.arity, values)
143 class Variable(Operator):
145 def __init__(self, values):
146 Operator.__init__(self, VARIABLE, Variable.arity, values)
150 def __init__(self, values):
151 Operator.__init__(self, LB, Lb.arity, values)
155 def __init__(self, values):
156 Operator.__init__(self, RB, Rb.arity, values)
158 class Formula(object):
162 TOKENS = {re.compile("\("): Lb,
163 re.compile("\)"): Rb,
164 re.compile("~"): Not,
165 re.compile("&"): And,
166 re.compile("\|"): Or,
167 re.compile("->"): Imp,
168 re.compile("<->"): Eq,
169 re.compile("\[\]"): Box,
170 re.compile("<>"): Diamond,
171 re.compile("[a-z]+"): Variable}
173 class Scanner(object):
174 def __init__(self, tokens, source=None):
178 while self.i < len(self.source):
180 for p, token in self.tokens.iteritems():
181 m = p.match(self.source[self.i:])
185 return (token, value)
188 def reset(self, source):
203 SYNTAX = ((Variable,),
214 def __init__(self, parent, value):
218 def addChild(self, value):
219 self.children.append(self, node)
221 class Parser(object):
222 def __init__(self, syntax, scanner):
224 self.scanner = scanner
225 def parse(self, source):
226 table = {(S, Variable): 0,
235 (A, Variable, And): 5,
236 (A, Variable, Or): 6,
237 (A, Variable, Imp): 7,
238 (A, Variable, Eq): 8,
239 (A, Not, Variable, And): 5,
240 (A, Not, Variable, Or): 6,
241 (A, Not, Variable, Imp): 7,
242 (A, Not, Variable, Eq): 8}
247 self.scanner.reset(source)
248 (token, value) = self.scanner.next()
249 (lookahead, la_value) = self.scanner.next()
250 (lookahead2, la2_value) = self.scanner.next()
252 while token and len(stack):
255 tree_nodes.append((token, value))
257 #tree_nodes.append((stack.pop(), value))
258 (token, value) = (lookahead, la_value)
259 (lookahead, la_value) = (lookahead2, la2_value)
260 #(lookahead, _) = self.scanner.next()
261 (lookahead2, la2_value) = self.scanner.next()
264 if (top, token) in table:
265 action = table[(top, token)]
266 elif (top, token, lookahead) in table:
267 action = table[(top, token, lookahead)]
268 elif (top, token, lookahead, lookahead2) in table:
269 action = table[(top, token, lookahead, lookahead2)]
276 stack.extend(reversed(self.syntax[action]))
277 accepted = accepted and not len(stack)
278 return (accepted, out, tree_nodes)
280 class SyntaxTree(object):
281 def __init__(self, seq, tree_nodes):
284 self.root = self.compile(seq, tree_nodes)[0]
285 def compile(self, seq, tree_nodes):
290 c, v = tree_nodes.pop()
292 c, v = tree_nodes.pop()
293 stack.append(Variable(v))
295 stack.append(Not(self.compile(seq, tree_nodes)))
297 stack.extend(self.compile(seq, tree_nodes))
299 stack.append(Box(self.compile(seq, tree_nodes)))
301 stack.append(Diamond(self.compile(seq, tree_nodes)))
303 stack.append(And(self.compile(seq, tree_nodes)))
305 stack.append(Or(self.compile(seq, tree_nodes)))
307 stack.append(Imp(self.compile(seq, tree_nodes)))
309 stack.append(Eq(self.compile(seq, tree_nodes)))
312 from argparse import ArgumentParser
314 def parse_arguments():
315 parser = ArgumentParser(description="Parses simple modal logic syntax.")
316 parser.add_argument("-f", "--formula", help="your formula")
317 return parser.parse_args()
319 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."""
321 if __name__ == "__main__":