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 disfunctional 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])])])}
37 return [expand_imp_eq(v) for v in formula.values]
39 if not isinstance(formula, Operator) or formula.id not in map:
41 return map[formula.id](values())
43 def reduce_not(formula):
44 negmap = {AND: lambda (a, b): Or([negate(a), negate(b)]),
45 OR: lambda (a, b): And([negate(a), negate(b)]),
46 VARIABLE: lambda (a,): Not([a]),
49 return [reduce_not(v) for v in formula.values]
51 return negmap[f.id](f.values)
53 if not isinstance(formula, Operator):
56 return negate(formula.values[0])
57 return formula.__class__(values())
70 class Operator(object):
71 def __init__(self, id, arity, values):
78 out = str(self.values[0])
80 out = self.id + str(self.values[0])
82 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
87 def __init__(self, values):
88 Operator.__init__(self, NOT, Not.arity, values)
94 def __init__(self, values):
95 Operator.__init__(self, AND, And.arity, values)
99 def __init__(self, values):
100 Operator.__init__(self, OR, Or.arity, values)
104 def __init__(self, values):
105 Operator.__init__(self, IMP, Imp.arity, values)
109 def __init__(self, values):
110 Operator.__init__(self, EQ, Eq.arity, values)
114 def __init__(self, values):
115 Operator.__init__(self, BOX, Box.arity, values)
117 class Diamond(Operator):
119 def __init__(self, values):
120 Operator.__init__(self, DIAMOND, Diamond.arity, values)
122 class Variable(Operator):
124 def __init__(self, values):
125 Operator.__init__(self, VARIABLE, Variable.arity, values)
129 def __init__(self, values):
130 Operator.__init__(self, LB, Lb.arity, values)
134 def __init__(self, values):
135 Operator.__init__(self, RB, Rb.arity, values)
137 class Formula(object):
141 TOKENS = {re.compile("\("): Lb,
142 re.compile("\)"): Rb,
143 re.compile("~"): Not,
144 re.compile("&"): And,
145 re.compile("\|"): Or,
146 re.compile("->"): Imp,
147 re.compile("<->"): Eq,
148 re.compile("\[\]"): Box,
149 re.compile("<>"): Diamond,
150 re.compile("[a-z]+"): Variable}
152 class Scanner(object):
153 def __init__(self, tokens, source=None):
157 while self.i < len(self.source):
159 for p, token in self.tokens.iteritems():
160 m = p.match(self.source[self.i:])
164 return (token, value)
167 def reset(self, source):
182 SYNTAX = ((Variable,),
193 def __init__(self, parent, value):
197 def addChild(self, value):
198 self.children.append(self, node)
200 class Parser(object):
201 def __init__(self, syntax, scanner):
203 self.scanner = scanner
204 def parse(self, source):
205 table = {(S, Variable): 0,
214 (A, Variable, And): 5,
215 (A, Variable, Or): 6,
216 (A, Variable, Imp): 7,
217 (A, Variable, Eq): 8,
218 (A, Not, Variable, And): 5,
219 (A, Not, Variable, Or): 6,
220 (A, Not, Variable, Imp): 7,
221 (A, Not, Variable, Eq): 8}
226 self.scanner.reset(source)
227 (token, value) = self.scanner.next()
228 (lookahead, la_value) = self.scanner.next()
229 (lookahead2, la2_value) = self.scanner.next()
231 while token and len(stack):
234 tree_nodes.append((token, value))
236 #tree_nodes.append((stack.pop(), value))
237 (token, value) = (lookahead, la_value)
238 (lookahead, la_value) = (lookahead2, la2_value)
239 #(lookahead, _) = self.scanner.next()
240 (lookahead2, la2_value) = self.scanner.next()
243 if (top, token) in table:
244 action = table[(top, token)]
245 elif (top, token, lookahead) in table:
246 action = table[(top, token, lookahead)]
247 elif (top, token, lookahead, lookahead2) in table:
248 action = table[(top, token, lookahead, lookahead2)]
255 stack.extend(reversed(self.syntax[action]))
256 accepted = accepted and not len(stack)
257 return (accepted, out, tree_nodes)
259 class SyntaxTree(object):
260 def __init__(self, seq, tree_nodes):
263 self.root = self.compile(seq, tree_nodes)[0]
264 def compile(self, seq, tree_nodes):
269 c, v = tree_nodes.pop()
271 c, v = tree_nodes.pop()
272 stack.append(Variable(v))
274 stack.append(Not(self.compile(seq, tree_nodes)))
276 stack.extend(self.compile(seq, tree_nodes))
278 stack.append(Box(self.compile(seq, tree_nodes)))
280 stack.append(Diamond(self.compile(seq, tree_nodes)))
282 stack.append(And(self.compile(seq, tree_nodes)))
284 stack.append(Or(self.compile(seq, tree_nodes)))
286 stack.append(Imp(self.compile(seq, tree_nodes)))
288 stack.append(Eq(self.compile(seq, tree_nodes)))
291 from argparse import ArgumentParser
293 def parse_arguments():
294 parser = ArgumentParser(description="Parses simple modal logic syntax.")
295 parser.add_argument("-f", "--formula", help="your formula")
296 return parser.parse_args()
298 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."""
300 if __name__ == "__main__":