smm.py
author Eugen Sawin <sawine@me73.com>
Tue, 17 May 2011 16:08:04 +0200
changeset 11 8dd28f6bf427
parent 10 c7ca4a177c90
permissions -rw-r--r--
Cleaned up.
     1 """
     2 Name: 
     3 
     4 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
     5 """
     6 from os import path
     7 import os
     8 import re
     9 import token
    10 
    11 def main():
    12     p = Variable(["p"])
    13     q = Variable(["q"])
    14     r = Variable(["r"])
    15     formula1 = Imp([Eq([p, q]), r])
    16     formula2 = Not([Or([p, q])])
    17     formula3 = Not([Not([p])])
    18     use = formula1
    19 
    20     args = parse_arguments()
    21     if (args.formula):
    22         scanner = Scanner(TOKENS)
    23         parser = Parser(SYNTAX, scanner)
    24         (accepted, out, tree_nodes) = parser.parse(args.formula)
    25         if not accepted:
    26             print EXCUSE 
    27             return
    28         tree = SyntaxTree(out, tree_nodes) 
    29         formula = tree.root
    30    
    31     print formula
    32     print "reduced"
    33     print reduce(formula)
    34     print reduce(formula)
    35 
    36 def reduce(formula):  
    37     map = {IMP: lambda (a, b): Or([Not([a]), b]),
    38            EQ: lambda (a, b): And([Or([Not([a]), b]), Or([a, Not([b])])]),
    39            NOT: lambda (a,): not isinstance(a, Not) 
    40            and not isinstance(a.values[0], Not) 
    41            and a.__class__([Not([v]) for v in a.values]) or a.values[0],
    42            AND: lambda (a, b): And([a, b]), 
    43            OR: lambda (a, b): Or([a, b])}
    44     def values():       
    45         return [reduce(v) for v in formula.values] 
    46 
    47     if not isinstance(formula, Operator) or formula.id not in map:       
    48         return formula
    49     return map[formula.id](values())    
    50  
    51 NOT = "~"
    52 AND = "&"
    53 OR = "|"
    54 IMP = "->"
    55 EQ = "<->"
    56 BOX = "[]"
    57 DIAMOND = "<>"
    58 VARIABLE = "p"
    59 LB = "("
    60 RB = ")"
    61 
    62 class Operator(object):
    63     def __init__(self, id, arity, values):
    64         self.id = id         
    65         self.arity = arity
    66         self.values = values
    67     def __str__(self):
    68         out = self.id
    69         if self.arity == 0:
    70             out = str(self.values[0])
    71         if self.arity == 1:
    72             out = self.id + str(self.values[0])
    73         elif self.arity  == 2:          
    74             out = "(" + str(self.values[0]) + " " + self.id + " " + str(self.values[1]) + ")"
    75         return out
    76 
    77 class Not(Operator):
    78     arity = 1
    79     def __init__(self, values):
    80         Operator.__init__(self, NOT, Not.arity, values)       
    81     def __call__(self):
    82         pass
    83 
    84 class And(Operator):
    85     arity = 2
    86     def __init__(self, values):
    87         Operator.__init__(self, AND, And.arity, values)
    88        
    89 class Or(Operator):
    90     arity = 2
    91     def __init__(self, values):
    92         Operator.__init__(self, OR, Or.arity, values)       
    93 
    94 class Imp(Operator):
    95     arity = 2
    96     def __init__(self, values):
    97         Operator.__init__(self, IMP, Imp.arity, values)
    98     
    99 class Eq(Operator):
   100     arity = 2
   101     def __init__(self, values):
   102         Operator.__init__(self, EQ, Eq.arity, values)
   103     
   104 class Box(Operator):
   105     arity = 1
   106     def __init__(self, values):
   107         Operator.__init__(self, BOX, Box.arity, values)
   108 
   109 class Diamond(Operator):
   110     arity = 1
   111     def __init__(self, values):
   112         Operator.__init__(self, DIAMOND, Diamond.arity, values)
   113     
   114 class Variable(Operator):
   115     arity = 0
   116     def __init__(self, values):
   117         Operator.__init__(self, VARIABLE, Variable.arity, values)   
   118 
   119 class Lb(Operator):
   120     arity = -1
   121     def __init__(self, values):
   122         Operator.__init__(self, LB, Lb.arity, values)
   123 
   124 class Rb(Operator):
   125     arity = -1
   126     def __init__(self, values):
   127         Operator.__init__(self, RB, Rb.arity, values)
   128 
   129 class Formula(object):
   130     def __init__(self):
   131         pass 
   132 
   133 TOKENS = {re.compile("\("): Lb,
   134           re.compile("\)"): Rb,
   135           re.compile("~"): Not,
   136           re.compile("&"): And,
   137           re.compile("\|"): Or,
   138           re.compile("->"): Imp,
   139           re.compile("<->"): Eq,
   140           re.compile("\[\]"): Box,
   141           re.compile("<>"): Diamond,
   142           re.compile("[a-z]+"): Variable}
   143          
   144 class Scanner(object):
   145     def __init__(self, tokens, source=None):
   146         self.tokens = tokens
   147         self.reset(source)
   148     def next(self):         
   149         while self.i < len(self.source):
   150             re.purge()
   151             for p, token in self.tokens.iteritems():
   152                 m = p.match(self.source[self.i:])               
   153                 if m:                  
   154                     self.i += m.end(0)
   155                     value = m.group(0)  
   156                     return (token, value)
   157             self.i += 1
   158         return (None, None)
   159     def reset(self, source):
   160         self.i = 0
   161         self.source = source
   162 
   163 S = Formula
   164 A = "A"
   165 #0 S: (Variable,),
   166 #1 S: (Not, S),
   167 #2 S: (Lb, A, Rb),
   168 #3 S: (Box, S),
   169 #4 S: (Diamond, S),
   170 #5 A: (S, And, S),
   171 #6 A: (S, Or, S),
   172 #7 A: (S, Imp, S),
   173 #8 A: (S, Eq, S)
   174 SYNTAX = ((Variable,),
   175           (Not, S),
   176           (Lb, A, Rb),
   177           (Box, S),
   178           (Diamond, S),
   179           (S, And, S),
   180           (S, Or, S),
   181           (S, Imp, S),
   182           (S, Eq, S))
   183 
   184 class Node(object):
   185     def __init__(self, parent, value):
   186         self.parent = parent
   187         self.value = value
   188         self.children = []
   189     def addChild(self, value):
   190         self.children.append(self, node)
   191 
   192 class Parser(object):
   193     def __init__(self, syntax, scanner):
   194         self.syntax = syntax
   195         self.scanner = scanner
   196     def parse(self, source):
   197         table = {(S, Variable): 0,
   198                  (S, Not): 1,
   199                  (S, Lb): 2,
   200                  (S, Box): 3,
   201                  (S, Diamond): 4,
   202                  (A, S, And): 5,
   203                  (A, S, Or): 6,
   204                  (A, S, Imp): 7,
   205                  (A, S, Eq): 8,
   206                  (A, Variable, And): 5,
   207                  (A, Variable, Or): 6,
   208                  (A, Variable, Imp): 7,
   209                  (A, Variable, Eq): 8,
   210                  (A, Not, Variable, And): 5,
   211                  (A, Not, Variable, Or): 6,
   212                  (A, Not, Variable, Imp): 7,
   213                  (A, Not, Variable, Eq): 8}
   214         stack = [S]
   215         tree_nodes = []
   216         tree = None
   217         out = []
   218         self.scanner.reset(source)
   219         (token, value) = self.scanner.next()
   220         (lookahead, la_value) = self.scanner.next()
   221         (lookahead2, la2_value) = self.scanner.next()
   222         accepted = True 
   223         while token and len(stack): 
   224             top = stack[-1]               
   225             if top == token:
   226                 tree_nodes.append((token, value))
   227                 stack.pop()
   228                 #tree_nodes.append((stack.pop(), value))
   229                 (token, value) = (lookahead, la_value)
   230                 (lookahead, la_value) = (lookahead2, la2_value)
   231                 #(lookahead, _) = self.scanner.next()
   232                 (lookahead2, la2_value) = self.scanner.next()
   233             else:
   234                 action = None
   235                 if (top, token) in table:
   236                     action = table[(top, token)]
   237                 elif (top, token, lookahead) in table:
   238                     action = table[(top, token, lookahead)]  
   239                 elif (top, token, lookahead, lookahead2) in table:
   240                     action = table[(top, token, lookahead, lookahead2)]    
   241                 if action is None:
   242                     accepted = False
   243                     break
   244                 
   245                 out.append(action)
   246                 stack.pop()
   247                 stack.extend(reversed(self.syntax[action]))
   248         accepted = accepted and not len(stack)
   249         return (accepted, out, tree_nodes) 
   250 
   251 class SyntaxTree(object):
   252     def __init__(self, seq, tree_nodes):
   253         seq.reverse()
   254         tree_nodes.reverse()      
   255         self.root = self.compile(seq, tree_nodes)[0]       
   256     def compile(self, seq, tree_nodes):
   257         stack = []     
   258         while len(seq):           
   259             s = seq.pop()
   260             if s == 0:
   261                 c, v = tree_nodes.pop()
   262                 while c != Variable:
   263                     c, v = tree_nodes.pop()
   264                 stack.append(Variable(v))
   265             elif s == 1:
   266                 stack.append(Not(self.compile(seq, tree_nodes)))
   267             elif s == 2:
   268                 stack.extend(self.compile(seq, tree_nodes))
   269             elif s == 3:
   270                 stack.append(Box(self.compile(seq, tree_nodes)))
   271             elif s == 4:
   272                 stack.append(Diamond(self.compile(seq, tree_nodes)))
   273             elif s == 5:
   274                 stack.append(And(self.compile(seq, tree_nodes)))
   275             elif s == 6:
   276                 stack.append(Or(self.compile(seq, tree_nodes)))
   277             elif s == 7:
   278                 stack.append(Imp(self.compile(seq, tree_nodes)))
   279             elif s == 8:
   280                 stack.append(Eq(self.compile(seq, tree_nodes)))       
   281         return stack   
   282 
   283 from argparse import ArgumentParser
   284 
   285 def parse_arguments():
   286     parser = ArgumentParser(description="Parses simple modal logic syntax.")
   287     parser.add_argument("-f", "--formula", help="your formula") 
   288     return parser.parse_args()
   289  
   290 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."""
   291 
   292 if __name__ == "__main__":
   293     main()