master > master: Schema robuster gemacht; simple class, um Aspekte leichter aufzurufen

This commit is contained in:
RD 2021-05-06 23:34:25 +02:00
parent 6f6de00296
commit 28a1e313b3
4 changed files with 131 additions and 73 deletions

View File

@ -5,7 +5,7 @@
# IMPORTS # IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations; from __future__ import annotations
from lark import Tree; from lark import Tree;
from typing import List; from typing import List;
@ -15,10 +15,12 @@ from aussagenlogik.schema import isTrueSymbol;
from aussagenlogik.schema import isFalseSymbol; from aussagenlogik.schema import isFalseSymbol;
from aussagenlogik.schema import isNegation; from aussagenlogik.schema import isNegation;
from aussagenlogik.schema import isConjunction; from aussagenlogik.schema import isConjunction;
from aussagenlogik.schema import isLongConjunction;
from aussagenlogik.schema import isDisjunction; from aussagenlogik.schema import isDisjunction;
from aussagenlogik.schema import isLongDisjunction;
from aussagenlogik.schema import isImplication; from aussagenlogik.schema import isImplication;
from aussagenlogik.schema import getTeilformeln;
from aussagenlogik.schema import getName; from aussagenlogik.schema import getName;
from aussagenlogik.schema import SyntaxBaum;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBALE KONSTANTEN # GLOBALE KONSTANTEN
@ -30,8 +32,8 @@ from aussagenlogik.schema import getName;
# METHODEN # METHODEN
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def rekursiv_eval(fml: Tree, I: List[str]) -> int: def rekursiv_eval(fml: SyntaxBaum, I: List[str]) -> int:
teilfml = getTeilformeln(fml); subfml = fml.children;
if isAtom(fml): if isAtom(fml):
name = getName(fml); name = getName(fml);
return 1 if (name in I) else 0; return 1 if (name in I) else 0;
@ -43,19 +45,25 @@ def rekursiv_eval(fml: Tree, I: List[str]) -> int:
elif isFalseSymbol(fml): elif isFalseSymbol(fml):
return 0; return 0;
elif isNegation(fml): elif isNegation(fml):
val0 = rekursiv_eval(teilfml[0], I); val0 = rekursiv_eval(subfml[0], I);
return 1 - val0; return 1 - val0;
elif isConjunction(fml): elif isConjunction(fml):
val0 = rekursiv_eval(teilfml[0], I); val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(teilfml[1], I); val1 = rekursiv_eval(subfml[1], I);
return min(val0, val1); return min(val0, val1);
elif isLongConjunction(fml):
values = [rekursiv_eval(t, I) for t in subfml];
return min(values);
elif isDisjunction(fml): elif isDisjunction(fml):
val0 = rekursiv_eval(teilfml[0], I); val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(teilfml[1], I); val1 = rekursiv_eval(subfml[1], I);
return max(val0, val1); return max(val0, val1);
elif isLongDisjunction(fml):
values = [rekursiv_eval(t, I) for t in subfml];
return max(values);
elif isImplication(fml): elif isImplication(fml):
val0 = rekursiv_eval(teilfml[0], I); val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(teilfml[1], I); val1 = rekursiv_eval(subfml[1], I);
return 0 if val0 == 1 and val1 == 0 else 1; return 0 if val0 == 1 and val1 == 0 else 1;
raise Exception('Evaluation nicht möglich!'); raise Exception('Evaluation nicht möglich!');

View File

@ -11,6 +11,7 @@ from __future__ import annotations;
from lark import Lark; from lark import Lark;
from lark import Tree; from lark import Tree;
from typing import List; from typing import List;
from typing import Union;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBALE KONSTANTEN # GLOBALE KONSTANTEN
@ -24,42 +25,84 @@ lexerAussagenlogik = Lark(
%import common.WORD %import common.WORD
%ignore WS %ignore WS
?start: expr ?start: expr | open
?expr: atomic | expr_not | expr_and | expr_or | expr_implies ?expr: atomic | not | closed
?literal: atomic | "not" atomic ?open: and | and_long | or | or_long | impl
?closed: "(" open ")"
// atomische Ausdrücke // atomische Ausdrücke
?atomic: false | true | atom | generic ?atomic: false | true | atom | generic
?false: "0" -> wahr ?false: "0" -> kontr
?true: "1" -> falsch ?true: "1" -> taut
?atom: /A[0-9]+/ -> atom ?atom: /A[0-9]+/ -> atom
?generic: "{" /((?!({|})).)+/ "}" -> beliebig ?generic: "{" /((?!({|})).)+/ "}" -> beliebig
// Symbole // Symbole
?conn_not: "!" -> junktor ?symb_not: /!/ -> symb
?conn_and: /&+/ -> junktor ?symb_and: /&+/ -> symb
?conn_or: /\\|+/ -> junktor ?symb_or: /\\|+/ -> symb
?conn_impl: /->|=>/ -> junktor ?symb_impl: /->|=>/ -> symb
// Junktoren // Junktoren
?expr_not: conn_not expr -> negation ?not: symb_not expr -> neg
?expr_and: "(" expr conn_and expr ")" -> konjunktion ?and: expr symb_and expr -> konj
?expr_or: "(" expr conn_or expr ")" -> disjunktion ?and_long: [ expr ( symb_and expr )+ ] -> konj_lang
?expr_implies: "(" expr conn_impl expr ")" -> implikation ?or: expr symb_or expr -> disj
?or_long: [ expr ( symb_or expr )+ ] -> disj_lang
?impl: expr symb_impl expr -> impl
''', ''',
start="expr",
regex=True regex=True
); );
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# KLASSE: Syntaxbaum
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SyntaxBaum(object):
expr: str;
kind: str;
children: List[SyntaxBaum];
tree: Tree;
def __init__(self, fml: Tree):
self.kind = fml.data;
if len(fml.children) == 1 and isinstance(fml.children[0], str):
self.expr = fml.children[0];
self.children = [];
self.tree = Tree(self.kind, fml.children);
else:
self.children = [ SyntaxBaum(child) for child in fml.children if isinstance(child, Tree) and child.data != 'symb' ];
self.tree = Tree(self.kind, [child.tree for child in self.children]);
signature_parts = [];
i = 0;
for teilfml in fml.children:
if isinstance(teilfml, str):
signature_parts.append(teilfml);
elif teilfml.data == 'symb':
signature_parts.append(getText(teilfml));
else:
signature_parts.append('{{{}}}'.format(i));
i += 1;
signature = ' '.join(signature_parts);
self.expr = signature.format(*self.children);
if self.kind in [ 'konj', 'konj_lang', 'disj', 'disj_lang', 'impl' ]:
self.expr = '( {} )'.format(self.expr);
return;
def __str__(self):
return self.expr;
def pretty(self):
return self.tree.pretty();
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODE: string -> Syntaxbaum # METHODE: string -> Syntaxbaum
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def stringToSyntaxbaum(u: str) -> Tree: def stringToSyntaxbaum(u: str) -> SyntaxBaum:
try: try:
u_lexed = lexerAussagenlogik.parse(u); return SyntaxBaum(lexerAussagenlogik.parse(u));
return u_lexed;
except: except:
raise Exception('Ausdruck \033[1m{}\033[0m konnte nicht erkannt werden!'.format(u)); raise Exception('Ausdruck \033[1m{}\033[0m konnte nicht erkannt werden!'.format(u));
@ -67,47 +110,52 @@ def stringToSyntaxbaum(u: str) -> Tree:
# METHODEN: Erkennung von Formeltypen # METHODEN: Erkennung von Formeltypen
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def isAtom(fml: Tree) -> bool: def isAtom(fml: SyntaxBaum) -> bool:
return fml.data == 'atom'; return fml.kind == 'atom';
def isBeliebig(fml: Tree) -> bool: def isBeliebig(fml: SyntaxBaum) -> bool:
return fml.data == 'beliebig'; return fml.kind == 'beliebig';
def isTrueSymbol(fml: Tree) -> bool: def isTrueSymbol(fml: SyntaxBaum) -> bool:
return fml.data == 'wahr'; return fml.kind == 'taut';
def isFalseSymbol(fml: Tree) -> bool: def isFalseSymbol(fml: SyntaxBaum) -> bool:
return fml.data == 'falsch'; return fml.kind == 'kontr';
def isNegation(fml: Tree) -> bool: def isNegation(fml: SyntaxBaum) -> bool:
return fml.data == 'negation'; return fml.kind == 'neg';
def isConjunction(fml: Tree) -> bool: def isConjunction(fml: SyntaxBaum) -> bool:
return fml.data == 'konjunktion'; return fml.kind == 'konj';
def isDisjunction(fml: Tree) -> bool: def isLongConjunction(fml: SyntaxBaum) -> bool:
return fml.data == 'disjunktion'; return fml.kind == 'konj_lang';
def isImplication(fml: Tree) -> bool: def isDisjunction(fml: SyntaxBaum) -> bool:
return fml.data == 'implikation'; return fml.kind == 'disj';
def isLongDisjunction(fml: SyntaxBaum) -> bool:
return fml.kind == 'disj_lang';
def isImplication(fml: SyntaxBaum) -> bool:
return fml.kind == 'impl';
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODEN: Formel -> Teilformeln # METHODEN: Formel -> Textinhalt
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def getTeilformeln(fml: Tree) -> List[Tree]: def getText(fml: Tree) -> str:
return [
part for part in fml.children
if isinstance(part, Tree)
and not part.data == 'junktor'
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODEN: Formel (Atom/Beliebig) -> Name
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def getName(fml: Tree) -> str:
text = fml.children[0]; text = fml.children[0];
if isinstance(text, str): if isinstance(text, str):
return text; return text;
raise Exception('Konnte Textinhalt nicht ablesen!'); raise Exception('Konnte Textinhalt nicht ablesen!');
def getName(fml: SyntaxBaum) -> str:
return fml.expr;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODEN: Formel -> Textinhalt
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def prettifyTree(fml: Union[Tree, SyntaxBaum]) -> str:
return fml.pretty();

View File

@ -3,7 +3,7 @@
# expr = "( A0 && A1 )" # expr = "( A0 && A1 )"
# expr = "( A0 || A1 )" # expr = "( A0 || A1 )"
# expr = "( A0 -> A1 )" # expr = "( A0 -> A1 )"
expr = "( A0 -> ((A0 && A3) || ! A2) )" expr = "( A0 -> ((A0 && A3 && A4) || ! A2) )"
# expr = "( A0 -> ((A0 && A3) || A2) )" # expr = "( A0 -> ((A0 && A3) || A2) )"
# expr = "(( {G} || !{G} ) -> A5)" # expr = "(( {G} || !{G} ) -> A5)"
interpretation = "[ 'A0', 'A2' ]" interpretation = "[ 'A0', 'A2' ]"

View File

@ -5,7 +5,6 @@
# IMPORTS # IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
import os; import os;
import sys; import sys;
# sys.tracebacklimit = 0; # sys.tracebacklimit = 0;
@ -16,7 +15,9 @@ from typing import List;
sys.path.insert(0, os.getcwd()); sys.path.insert(0, os.getcwd());
from aussagenlogik.schema import prettifyTree;
from aussagenlogik.schema import stringToSyntaxbaum; from aussagenlogik.schema import stringToSyntaxbaum;
from aussagenlogik.schema import SyntaxBaum;
from aussagenlogik.rekursion import rekursiv_eval; from aussagenlogik.rekursion import rekursiv_eval;
from aussagenlogik.rekursion import rekursiv_atoms; from aussagenlogik.rekursion import rekursiv_atoms;
from aussagenlogik.rekursion import rekursiv_depth; from aussagenlogik.rekursion import rekursiv_depth;
@ -37,17 +38,17 @@ def main():
## Daten einlesen: ## Daten einlesen:
expr, I = getData(); expr, I = getData();
## Formel in Teilformeln zerlegen: ## Formel in Teilformeln zerlegen:
tree = stringToSyntaxbaum(expr); fml = stringToSyntaxbaum(expr);
## Methoden ausführen: ## Methoden ausführen:
results = dict( results = dict(
eval = rekursiv_eval(tree, I), eval = rekursiv_eval(fml, I),
atoms = rekursiv_atoms(tree), atoms = rekursiv_atoms(fml),
d = rekursiv_depth(tree), d = rekursiv_depth(fml),
l = rekursiv_length(tree), l = rekursiv_length(fml),
p = rekursiv_parentheses(tree), p = rekursiv_parentheses(fml),
); );
## Resultate anzeigen: ## Resultate anzeigen:
display_results(expr, tree, I, results); display_results(expr, fml, I, results);
return; return;
@ -61,17 +62,18 @@ def getData():
I = eval(data['interpretation'] or '[]'); I = eval(data['interpretation'] or '[]');
return expr, I; return expr, I;
def display_results(expr: str, tree: Tree, I: List[str], results: dict): def display_results(expr: str, fml: SyntaxBaum, I: List[str], results: dict):
print(dedent( print(dedent(
''' '''
Syntaxbaum von Syntaxbaum von
F := \033[92;1m{F}\033[0m: F := \033[92;1m{F}\033[0m:
'''.format(F=expr) '''.format(F=fml)
)); ));
print(tree.pretty()); print(prettifyTree(fml));
print(dedent( print(dedent(
''' '''
eval(F, I) = \033[94;1m{eval}\033[0m; Für I = [{I}] und F wie oben gilt
eval(F, I) = \033[94;1m{eval}\033[0m,
\033[2matoms(F) = \033[94;1m{atoms}\033[0m; \033[91;1m<- *\033[0m \033[2matoms(F) = \033[94;1m{atoms}\033[0m; \033[91;1m<- *\033[0m
\033[2mdepth(F) = \033[94;1m{d}\033[0m; \033[91;1m<- *\033[0m \033[2mdepth(F) = \033[94;1m{d}\033[0m; \033[91;1m<- *\033[0m
\033[2mlength(F) = \033[94;1m{l}\033[0m; \033[91;1m<- *\033[0m \033[2mlength(F) = \033[94;1m{l}\033[0m; \033[91;1m<- *\033[0m
@ -79,7 +81,7 @@ def display_results(expr: str, tree: Tree, I: List[str], results: dict):
\033[91;1m*\033[0m \033[2mnoch nicht implementiert!\033[0m \033[91;1m*\033[0m \033[2mnoch nicht implementiert!\033[0m
\033[1;2;4mChallenge:\033[0m \033[2mschreibe diese Methoden! (siehe README.md)\033[0m \033[1;2;4mChallenge:\033[0m \033[2mschreibe diese Methoden! (siehe README.md)\033[0m
'''.format(**results) '''.format(**results, I=', '.join(I))
)); ));
return; return;