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