clingo-hmknf-test/logic/logic.py

105 lines
2.8 KiB
Python
Raw Permalink Normal View History

2022-06-30 16:55:42 -06:00
from abc import abstractmethod
from dataclasses import dataclass
from itertools import product
from typing import Dict, Iterable, Set
from antlr4 import ParseTreeVisitor, InputStream, CommonTokenStream
from logic.grammars.OLexer import OLexer
from logic.grammars.OParser import OParser
class Expr:
@abstractmethod
def eval(self, assignment: Dict[str, bool]):
pass
@dataclass
class AtomExpr(Expr):
name: str
def eval(self, assignment: Dict[str, bool]):
return assignment[self.name]
@dataclass
class NotExpr(Expr):
expr: Expr
def eval(self, assignment: Dict[str, bool]):
return not self.expr.eval(assignment)
@dataclass
class BinExpr(Expr):
op: str
left: Expr
right: Expr
def eval(self, assignment: Dict[str, bool]):
if self.op == "|":
return self.left.eval(assignment) or self.right.eval(assignment)
if self.op == "&":
return self.left.eval(assignment) and self.right.eval(assignment)
if self.op == "->":
return (not self.left.eval(assignment)) or self.right.eval(assignment)
if self.op == "<->":
return self.left.eval(assignment) == self.right.eval(assignment)
@dataclass
class Formula:
alphabet: Set[str]
root: Expr
def models(self) -> Iterable[Iterable[str]]:
alphabet = tuple(self.alphabet)
for bools in product((True, False), repeat=len(alphabet)):
assignment = {atom: v for atom, v in zip(alphabet, bools)}
if self.root.eval(assignment):
yield assignment
class FormulaBuilder(ParseTreeVisitor):
alphabet: Set[str]
def __init__(self) -> None:
self.alphabet = set()
def visitParenth(self, ctx: OParser.ParenthContext):
return self.visit(ctx.expr())
def visit_bin_op(self, ctx):
return BinExpr(ctx.op.text, self.visit(ctx.expr(0)), self.visit(ctx.expr(1)))
def visitLog_neg(self, ctx:OParser.Log_negContext):
return NotExpr(self.visit(ctx.expr()))
def visitLog_or(self, ctx: OParser.Log_orContext):
return self.visit_bin_op(ctx)
def visitLog_impl(self, ctx: OParser.Log_implContext):
return self.visit_bin_op(ctx)
def visitLog_iff(self, ctx: OParser.Log_iffContext):
return self.visit_bin_op(ctx)
def visitLog_and(self, ctx: OParser.Log_andContext):
return self.visit_bin_op(ctx)
def visitAtom(self, ctx: OParser.AtomContext):
text = ctx.getText()
self.alphabet.add(text)
return AtomExpr(text)
def build(self, tree):
expr = self.visit(tree)
return Formula(self.alphabet, expr)
def parse(text: str):
input_stream = InputStream(text)
lexer = OLexer(input_stream)
stream = CommonTokenStream(lexer)
parser = OParser(stream)
tree = parser.expr()
formula = FormulaBuilder().build(tree)
return formula