Basic MCNF.
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 formula4 = Imp([Box([Imp([Diamond([p]), p])]), Box([Imp([p, Box([p])])])])
17 formula = formula4 # choose your formula here
19 args = parse_arguments()
21 scanner = Scanner(TOKENS)
22 parser = Parser(SYNTAX, scanner)
23 (accepted, out, tree_nodes) = parser.parse(args.formula)
27 tree = SyntaxTree(out, tree_nodes)
30 print "formula: \t\t\t%s (%i)" % (formula, formula.depth())
31 formula = expand_imp_eq(formula)
32 print "expanded -> and <->: \t\t%s (%i)" % (formula, formula.depth())
33 formula = de_morgan(formula)
34 print "reduced ~: \t\t\t%s (%i)" % (formula, formula.depth())
35 formula = reduce_iter(formula)
36 print "reduced iterated modalities: \t%s (%i)" % (formula, formula.depth())
37 formula = reduce_iter(dist_mod((formula)))
38 print "distributed modalities+: \t%s (%i)" % (formula, formula.depth())
39 formula = mcnf(formula)
40 print "alpha mcnf: \t\t\t%s (%i)" % (formula, formula.depth())
43 return [fun(v) for v in f.values]
45 def expand_imp_eq(formula):
46 expmap = {IMP: lambda (a, b): Or([Not([a]), b]),
47 EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])])}
48 if not isinstance(formula, Operator):
50 if formula.id in expmap:
51 return expmap[formula.id](values(expand_imp_eq, formula))
52 return formula.__class__(values(expand_imp_eq, formula))
54 def de_morgan(formula):
55 negmap = {AND: lambda (a, b): Or([negate(a), negate(b)]),
56 OR: lambda (a, b): And([negate(a), negate(b)]),
57 BOX: lambda (a,): Diamond([negate(a)]),
58 DIAMOND: lambda (a,): Box([negate(a)]),
59 VARIABLE: lambda (a,): Not([Variable([a])]),
62 return negmap[f.id](f.values)
63 if not isinstance(formula, Operator):
66 return negate(formula.values[0])
67 return formula.__class__(values(de_morgan, formula))
69 def reduce_iter(formula):
70 redset = set(((BOX, BOX), (DIAMOND, DIAMOND), (DIAMOND, BOX), (BOX, DIAMOND)))
71 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
73 ids = (formula.id, formula.values[0].id)
75 return reduce_iter(formula.values[0])
76 return formula.__class__(values(reduce_iter, formula))
78 def dist_mod(formula):
79 distmap = {(BOX, AND): lambda (a, b): And([Box([a]), Box([b])]),
80 (DIAMOND, OR): lambda (a, b): Or([Diamond([a]), Diamond([b])]),
81 (BOX, OR): lambda (a, b): (isinstance(a, Box) or isinstance(b, Box))
82 and Or([Box([a]), Box([b])]) or Box([Or([a, b])]),
83 (DIAMOND, AND): lambda (a, b): (isinstance(a, Diamond) or isinstance(b, Diamond))
84 and And([Diamond([a]), Diamond([b])]) or Diamond([And([a, b])])}
85 if not isinstance(formula, Operator) or not isinstance(formula.values[0], Operator):
87 ids = (formula.id, formula.values[0].id)
89 return distmap[ids](values(dist_mod, formula.values[0]))
90 return formula.__class__(values(dist_mod, formula))
94 conj_id = int(formula.values[1].id == AND)
95 return And([Or([formula.values[conj_id].values[0], formula.values[1 - conj_id]]),
96 Or([formula.values[conj_id].values[1], formula.values[1 - conj_id]])]);
109 class Operator(object):
110 def __init__(self, id, arity, values):
117 if self.id in (BOX, DIAMOND):
118 return 1 + self.values[0].depth()
120 return self.values[0].depth()
121 return max(self.values[0].depth(), self.values[1].depth())
125 out = str(self.values[0])
127 out = self.id + str(self.values[0])
128 elif self.arity == 2:
129 out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
134 def __init__(self, values):
135 Operator.__init__(self, NOT, Not.arity, values)
141 def __init__(self, values):
142 Operator.__init__(self, AND, And.arity, values)
146 def __init__(self, values):
147 Operator.__init__(self, OR, Or.arity, values)
151 def __init__(self, values):
152 Operator.__init__(self, IMP, Imp.arity, values)
156 def __init__(self, values):
157 Operator.__init__(self, EQ, Eq.arity, values)
161 def __init__(self, values):
162 Operator.__init__(self, BOX, Box.arity, values)
164 class Diamond(Operator):
166 def __init__(self, values):
167 Operator.__init__(self, DIAMOND, Diamond.arity, values)
169 class Variable(Operator):
171 def __init__(self, values):
172 Operator.__init__(self, VARIABLE, Variable.arity, values)
176 def __init__(self, values):
177 Operator.__init__(self, LB, Lb.arity, values)
181 def __init__(self, values):
182 Operator.__init__(self, RB, Rb.arity, values)
184 class Formula(object):
188 TOKENS = {re.compile("\("): Lb,
189 re.compile("\)"): Rb,
190 re.compile("~"): Not,
191 re.compile("&"): And,
192 re.compile("\|"): Or,
193 re.compile("->"): Imp,
194 re.compile("<->"): Eq,
195 re.compile("\[\]"): Box,
196 re.compile("<>"): Diamond,
197 re.compile("[a-z]+"): Variable}
199 class Scanner(object):
200 def __init__(self, tokens, source=None):
204 while self.i < len(self.source):
206 for p, token in self.tokens.iteritems():
207 m = p.match(self.source[self.i:])
211 return (token, value)
214 def reset(self, source):
229 SYNTAX = ((Variable,),
240 def __init__(self, parent, value):
244 def addChild(self, value):
245 self.children.append(self, node)
247 class Parser(object):
248 def __init__(self, syntax, scanner):
250 self.scanner = scanner
251 def parse(self, source):
252 table = {(S, Variable): 0,
261 (A, Variable, And): 5,
262 (A, Variable, Or): 6,
263 (A, Variable, Imp): 7,
264 (A, Variable, Eq): 8,
265 (A, Not, Variable, And): 5,
266 (A, Not, Variable, Or): 6,
267 (A, Not, Variable, Imp): 7,
268 (A, Not, Variable, Eq): 8}
273 self.scanner.reset(source)
274 (token, value) = self.scanner.next()
275 (lookahead, la_value) = self.scanner.next()
276 (lookahead2, la2_value) = self.scanner.next()
278 while token and len(stack):
281 tree_nodes.append((token, value))
283 #tree_nodes.append((stack.pop(), value))
284 (token, value) = (lookahead, la_value)
285 (lookahead, la_value) = (lookahead2, la2_value)
286 #(lookahead, _) = self.scanner.next()
287 (lookahead2, la2_value) = self.scanner.next()
290 if (top, token) in table:
291 action = table[(top, token)]
292 elif (top, token, lookahead) in table:
293 action = table[(top, token, lookahead)]
294 elif (top, token, lookahead, lookahead2) in table:
295 action = table[(top, token, lookahead, lookahead2)]
302 stack.extend(reversed(self.syntax[action]))
303 accepted = accepted and not len(stack)
304 return (accepted, out, tree_nodes)
306 class SyntaxTree(object):
307 def __init__(self, seq, tree_nodes):
310 self.root = self.compile(seq, tree_nodes)[0]
311 def compile(self, seq, tree_nodes):
316 c, v = tree_nodes.pop()
318 c, v = tree_nodes.pop()
319 stack.append(Variable(v))
321 stack.append(Not(self.compile(seq, tree_nodes)))
323 stack.extend(self.compile(seq, tree_nodes))
325 stack.append(Box(self.compile(seq, tree_nodes)))
327 stack.append(Diamond(self.compile(seq, tree_nodes)))
329 stack.append(And(self.compile(seq, tree_nodes)))
331 stack.append(Or(self.compile(seq, tree_nodes)))
333 stack.append(Imp(self.compile(seq, tree_nodes)))
335 stack.append(Eq(self.compile(seq, tree_nodes)))
338 from argparse import ArgumentParser
340 def parse_arguments():
341 parser = ArgumentParser(description="Parses simple modal logic syntax.")
342 parser.add_argument("-f", "--formula", help="your formula")
343 return parser.parse_args()
345 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"""
347 if __name__ == "__main__":