From 6f6de00296ea38f2a698eb399f738dd990c6c4fd Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Thu, 6 May 2021 15:29:44 +0200 Subject: [PATCH] master > master: Teile auslagern + Vereinfachungen --- code/aussagenlogik/rekursion.py | 83 +++++++++++----------- code/aussagenlogik/schema.py | 55 ++++++++++++++- code/main.py | 4 +- code/utests/u_rekursion.py | 120 ++++++++++++++++---------------- 4 files changed, 153 insertions(+), 109 deletions(-) diff --git a/code/aussagenlogik/rekursion.py b/code/aussagenlogik/rekursion.py index cc8bf92..8818897 100644 --- a/code/aussagenlogik/rekursion.py +++ b/code/aussagenlogik/rekursion.py @@ -9,6 +9,17 @@ from __future__ import annotations; from lark import Tree; from typing import List; +from aussagenlogik.schema import isAtom; +from aussagenlogik.schema import isBeliebig; +from aussagenlogik.schema import isTrueSymbol; +from aussagenlogik.schema import isFalseSymbol; +from aussagenlogik.schema import isNegation; +from aussagenlogik.schema import isConjunction; +from aussagenlogik.schema import isDisjunction; +from aussagenlogik.schema import isImplication; +from aussagenlogik.schema import getTeilformeln; +from aussagenlogik.schema import getName; + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # GLOBALE KONSTANTEN # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -19,6 +30,35 @@ from typing import List; # METHODEN # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def rekursiv_eval(fml: Tree, I: List[str]) -> int: + teilfml = getTeilformeln(fml); + if isAtom(fml): + name = getName(fml); + return 1 if (name in I) else 0; + if isBeliebig(fml): + name = getName(fml); + return 1 if (name in I) else 0; + elif isTrueSymbol(fml): + return 1; + elif isFalseSymbol(fml): + return 0; + elif isNegation(fml): + val0 = rekursiv_eval(teilfml[0], I); + return 1 - val0; + elif isConjunction(fml): + val0 = rekursiv_eval(teilfml[0], I); + val1 = rekursiv_eval(teilfml[1], I); + return min(val0, val1); + elif isDisjunction(fml): + val0 = rekursiv_eval(teilfml[0], I); + val1 = rekursiv_eval(teilfml[1], I); + return max(val0, val1); + elif isImplication(fml): + val0 = rekursiv_eval(teilfml[0], I); + val1 = rekursiv_eval(teilfml[1], I); + return 0 if val0 == 1 and val1 == 0 else 1; + raise Exception('Evaluation nicht möglich!'); + def rekursiv_atoms(fml: Tree) -> List[str]: ## Herausforderung: schreibe diese Funktion! return []; @@ -34,46 +74,3 @@ def rekursiv_length(fml: Tree) -> int: def rekursiv_parentheses(fml: Tree) -> int: ## Herausforderung: schreibe diese Funktion! return 0 - -def rekursiv_eval(fml: Tree, I: List[str]) -> int: - teilfml = getTeilformeln(fml); - if fml.data in ['atom', 'beliebig']: - name = getText(fml); - return 1 if (name in I) else 0; - elif fml.data == 'wahr': - return 1; - elif fml.data == 'falsch': - return 0; - elif fml.data == 'negation': - val1 = rekursiv_eval(teilfml[0], I); - return 1 - val1; - elif fml.data == 'konjunktion': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return min(val1, val2); - elif fml.data == 'disjunktion': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return max(val1, val2); - elif fml.data == 'implikation': - val1 = rekursiv_eval(teilfml[0], I); - val2 = rekursiv_eval(teilfml[1], I); - return 0 if val1 == 1 and val2 == 0 else 1; - raise Exception('Evaluation nicht möglich!'); - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# HILFSMETHODEN -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def getText(fml: Tree) -> str: - text = fml.children[0]; - if isinstance(text, str): - return text; - raise Exception('Konnte Textinhalt nicht ablesen!'); - -def getTeilformeln(fml: Tree) -> List[Tree]: - return [ - part for part in fml.children - if isinstance(part, Tree) - and not part.data == 'junktor' - ]; diff --git a/code/aussagenlogik/schema.py b/code/aussagenlogik/schema.py index cf05f7a..c4f1a08 100644 --- a/code/aussagenlogik/schema.py +++ b/code/aussagenlogik/schema.py @@ -6,11 +6,11 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from __future__ import annotations; -import re; # install: lark; lark-parser; lark-parser[regex]. # https://lark-parser.readthedocs.io/en/latest/grammar.html from lark import Lark; from lark import Tree; +from typing import List; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # GLOBALE KONSTANTEN @@ -53,12 +53,61 @@ lexerAussagenlogik = Lark( ); # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# MAIN METHOD string -> parts +# METHODE: string -> Syntaxbaum # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -def string_to_parts(u: str) -> Tree: +def stringToSyntaxbaum(u: str) -> Tree: try: u_lexed = lexerAussagenlogik.parse(u); return u_lexed; except: raise Exception('Ausdruck \033[1m{}\033[0m konnte nicht erkannt werden!'.format(u)); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# METHODEN: Erkennung von Formeltypen +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def isAtom(fml: Tree) -> bool: + return fml.data == 'atom'; + +def isBeliebig(fml: Tree) -> bool: + return fml.data == 'beliebig'; + +def isTrueSymbol(fml: Tree) -> bool: + return fml.data == 'wahr'; + +def isFalseSymbol(fml: Tree) -> bool: + return fml.data == 'falsch'; + +def isNegation(fml: Tree) -> bool: + return fml.data == 'negation'; + +def isConjunction(fml: Tree) -> bool: + return fml.data == 'konjunktion'; + +def isDisjunction(fml: Tree) -> bool: + return fml.data == 'disjunktion'; + +def isImplication(fml: Tree) -> bool: + return fml.data == 'implikation'; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# METHODEN: Formel -> Teilformeln +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def getTeilformeln(fml: Tree) -> List[Tree]: + 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]; + if isinstance(text, str): + return text; + raise Exception('Konnte Textinhalt nicht ablesen!'); diff --git a/code/main.py b/code/main.py index cd87a1a..637c785 100644 --- a/code/main.py +++ b/code/main.py @@ -16,7 +16,7 @@ from typing import List; sys.path.insert(0, os.getcwd()); -from aussagenlogik.schema import string_to_parts; +from aussagenlogik.schema import stringToSyntaxbaum; from aussagenlogik.rekursion import rekursiv_eval; from aussagenlogik.rekursion import rekursiv_atoms; from aussagenlogik.rekursion import rekursiv_depth; @@ -37,7 +37,7 @@ def main(): ## Daten einlesen: expr, I = getData(); ## Formel in Teilformeln zerlegen: - tree = string_to_parts(expr); + tree = stringToSyntaxbaum(expr); ## Methoden ausführen: results = dict( eval = rekursiv_eval(tree, I), diff --git a/code/utests/u_rekursion.py b/code/utests/u_rekursion.py index d90ac66..2b7b4e9 100644 --- a/code/utests/u_rekursion.py +++ b/code/utests/u_rekursion.py @@ -8,7 +8,7 @@ import unittest; from unittest import TestCase; -from aussagenlogik.schema import string_to_parts; +from aussagenlogik.schema import stringToSyntaxbaum; from aussagenlogik.rekursion import rekursiv_atoms; from aussagenlogik.rekursion import rekursiv_depth; from aussagenlogik.rekursion import rekursiv_length; @@ -21,6 +21,45 @@ from aussagenlogik.rekursion import rekursiv_eval; # +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TESTFALL eval(·, ·) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# @unittest.skip('Methode noch nicht implementiert') +class TestRekursivEval(TestCase): + def test_literale(self): + fml = stringToSyntaxbaum('A0'); + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 1; + fml = stringToSyntaxbaum('A0'); + val = rekursiv_eval(fml, []); + assert val == 0; + fml = stringToSyntaxbaum('! A0'); + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 0; + fml = stringToSyntaxbaum('! A0'); + val = rekursiv_eval(fml, []); + assert val == 1; + + def test_complex1(self): + fml = stringToSyntaxbaum('( ! A0 || (( A0 && A3 ) || A2 ))'); + val = rekursiv_eval(fml, [ 'A0', 'A2' ]); + assert val == 1; + val = rekursiv_eval(fml, [ 'A0', 'A3' ]); + assert val == 1; + val = rekursiv_eval(fml, [ 'A0' ]); + assert val == 0; + val = rekursiv_eval(fml, [ 'A4', 'A8' ]); + assert val == 1; + + def test_complex2(self): + fml = stringToSyntaxbaum('( ! A0 || (( A0 && A3 ) || ! A2 ))'); + val = rekursiv_eval(fml, [ 'A0', 'A2' ]); + assert val == 0; + val = rekursiv_eval(fml, [ 'A0', 'A3' ]); + assert val == 1; + pass; + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # TESTFALL Atome(·) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -28,22 +67,22 @@ from aussagenlogik.rekursion import rekursiv_eval; @unittest.skip('Methode noch nicht implementiert') class TestRekursivAtoms(TestCase): def test_noduplicates(self): - fml = string_to_parts('( A4 && ( A4 || A4 ))'); + fml = stringToSyntaxbaum('( A4 && ( A4 || A4 ))'); val = sorted(rekursiv_atoms(fml)); assert len([_ for _ in val if _ == 'A4']) == 1, 'Atome dürfen nicht mehrfach vorkommen!'; def test_nononatoms(self): - fml = string_to_parts('( {F} || A3 )'); + fml = stringToSyntaxbaum('( {F} || A3 )'); val = sorted(rekursiv_atoms(fml)); assert 'F' not in val, 'Nichtatomare Formeln dürfen nicht vorkommen!'; def test_calc1(self): - fml = string_to_parts('A0'); + fml = stringToSyntaxbaum('A0'); val = sorted(rekursiv_atoms(fml)); assert val == ['A0'], 'computed {}'.format(val); def test_calc2(self): - fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )'); val = sorted(rekursiv_atoms(fml)); assert val == ['A0', 'A3', 'A4', 'A8'], 'computed {}'.format(val); pass; @@ -55,27 +94,27 @@ class TestRekursivAtoms(TestCase): @unittest.skip('Methode noch nicht implementiert') class TestRekursivDepth(TestCase): def test_calc1(self): - fml = string_to_parts('A0'); + fml = stringToSyntaxbaum('A0'); val = rekursiv_depth(fml); assert val == 0, 'computed {}'.format(val); def test_calc2(self): - fml = string_to_parts('!! A8'); + fml = stringToSyntaxbaum('!! A8'); val = rekursiv_depth(fml); assert val == 2, 'computed {}'.format(val); def test_calc3(self): - fml = string_to_parts('( ! A0 && A3 )'); + fml = stringToSyntaxbaum('( ! A0 && A3 )'); val = rekursiv_depth(fml); assert val == 2, 'computed {}'.format(val); def test_calc4(self): - fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_depth(fml); assert val == 4, 'computed {}'.format(val); def test_calc5(self): - fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_depth(fml); assert val == 5, 'computed {}'.format(val); pass; @@ -87,32 +126,31 @@ class TestRekursivDepth(TestCase): @unittest.skip('Methode noch nicht implementiert') class TestRekursivLength(TestCase): def test_calc1(self): - fml = string_to_parts('A0'); + fml = stringToSyntaxbaum('A0'); val = rekursiv_length(fml); assert val == 1, 'computed {}'.format(val); def test_calc2(self): - fml = string_to_parts('!! A8'); + fml = stringToSyntaxbaum('!! A8'); val = rekursiv_length(fml); assert val == 3, 'computed {}'.format(val); def test_calc3(self): - fml = string_to_parts('( ! A0 && A3 )'); + fml = stringToSyntaxbaum('( ! A0 && A3 )'); val = rekursiv_length(fml); assert val == 4, 'computed {}'.format(val); def test_calc4(self): - fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_length(fml); assert val == 8, 'computed {}'.format(val); def test_calc5(self): - fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_length(fml); assert val == 9, 'computed {}'.format(val); pass; - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # TESTFALL Anzahl Klammern(·) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -120,67 +158,27 @@ class TestRekursivLength(TestCase): @unittest.skip('Methode noch nicht implementiert') class TestRekursivParentheses(TestCase): def test_calc1(self): - fml = string_to_parts('A0'); + fml = stringToSyntaxbaum('A0'); val = rekursiv_parentheses(fml); assert val == 0, 'computed {}'.format(val); def test_calc2(self): - fml = string_to_parts('!! A8'); + fml = stringToSyntaxbaum('!! A8'); val = rekursiv_parentheses(fml); assert val == 0, 'computed {}'.format(val); def test_calc3(self): - fml = string_to_parts('( ! A0 && A3 )'); + fml = stringToSyntaxbaum('( ! A0 && A3 )'); val = rekursiv_parentheses(fml); assert val == 2, 'computed {}'.format(val); def test_calc4(self): - fml = string_to_parts('((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_parentheses(fml); assert val == 6, 'computed {}'.format(val); def test_calc5(self): - fml = string_to_parts('! ((( ! A0 && A3 ) || A4 ) && A8 )'); + fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )'); val = rekursiv_parentheses(fml); assert val == 6, 'computed {}'.format(val); pass; - - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# TESTFALL eval(·, ·) -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# @unittest.skip('Methode noch nicht implementiert') -class TestRekursivEval(TestCase): - def test_literale(self): - fml = string_to_parts('A0'); - val = rekursiv_eval(fml, [ 'A0' ]); - assert val == 1; - fml = string_to_parts('A0'); - val = rekursiv_eval(fml, []); - assert val == 0; - fml = string_to_parts('! A0'); - val = rekursiv_eval(fml, [ 'A0' ]); - assert val == 0; - fml = string_to_parts('! A0'); - val = rekursiv_eval(fml, []); - assert val == 1; - - def test_complex1(self): - fml = string_to_parts('( ! A0 || (( A0 && A3 ) || A2 ))'); - val = rekursiv_eval(fml, [ 'A0', 'A2' ]); - assert val == 1; - val = rekursiv_eval(fml, [ 'A0', 'A3' ]); - assert val == 1; - val = rekursiv_eval(fml, [ 'A0' ]); - assert val == 0; - val = rekursiv_eval(fml, [ 'A4', 'A8' ]); - assert val == 1; - - def test_complex2(self): - fml = string_to_parts('( ! A0 || (( A0 && A3 ) || ! A2 ))'); - val = rekursiv_eval(fml, [ 'A0', 'A2' ]); - assert val == 0; - val = rekursiv_eval(fml, [ 'A0', 'A3' ]); - assert val == 1; - pass;