master > master: allgemeine Aufräumung

This commit is contained in:
RD 2021-05-10 14:32:52 +02:00
parent a0dee82659
commit 61ec2d7df3
17 changed files with 303 additions and 244 deletions

19
code/.gitignore vendored
View File

@ -1,12 +1,21 @@
*
!/.gitignore
!/README.md
!/build.sh
!/test.sh
!/data.env
!/requirements
!/README.md
## Scripts
!/scripts
!/scripts/requirements
!/scripts/build.sh
!/scripts/test.sh
## Für Erzeugung von Grammatiken:
!/grammars
!/grammars/README.md
!/grammars/*.lark
## Python Source
!/aussagenlogik
!/utests
!/**/*.py

View File

@ -6,24 +6,23 @@ Diese dienen nur zur Demonstration / konkreten Verwirklichung von Verfahren, die
Der Gebrauch dieser Skripte unterliegt der Eigenverantwortung von Studierenden.
Da ich kein Informatiker bin, sind auch einige Aspekt bestimmt nicht optimal programmiert/strukturiert.
Da ich kein Informatiker bin,
sind auch einige Aspekt bestimmt nicht optimal programmiert/strukturiert.
Dafür kann jeder in seiner Kopie einfach alles anpassen.
Das hier soll einfach funktionieren.
## Systemvoraussetzungen ##
- bash (auch bash-for-windows).
- python (mind. 3.9.x)
Natürlich wäre eine Implementierung in einer besseren Sprache wie **go** idealer, aber vielleicht in Zukunft.
## Voreinstellungen ##
- In einer bash-console zu diesem Ordner navigieren und folgenden Befehl ausführen:
```bash
chmod +x build.sh test.sh
## oder
chmod +x *.sh
chmod +x scripts/*.sh
```
- In `build.sh` gibt es eine Zeile, die zur Ausführung der Python-Skripte notwendigen Module über PIP installieren lässt. (Die Liste der Packages findet man in der Datei `requirements`). Diese Zeile kann man ruhig nach der ersten Ausführung rauskommentieren.
- In `scripts/build.sh` gibt es eine Zeile, die zur Ausführung der Python-Skripte notwendigen Module über PIP installieren lässt. (Die Liste der Packages findet man in der Datei `requirements`). Diese Zeile kann man ruhig nach der ersten Ausführung rauskommentieren.
## Daten ##
@ -33,7 +32,7 @@ In `data.env` kann man Daten (aktuell: auszuwertenden Ausdruck + Interpretation/
In einer bash-console zu diesem Ordner navigieren und
```bash
./build.sh
source build.sh
## oder (für Linux)
python3 main.py
## oder (für Windows)
@ -56,14 +55,19 @@ Wer etwas standardisierter seine Methoden testen will, kann automatisiertes Test
- In der Console (wenn noch nicht geschehen) folgenden Befehl einmalig ausführen:
```bash
chmod +x test.sh
chmod +x scripts/test.sh
```
- In `utests/u_rekursion.py` beim relevanten Testteil eine oder mehrere der Zeilen
- In `utests/rekursion_test.py` beim relevanten Testteil eine oder mehrere der Zeilen
```python
@unittest.skip('Methode noch nicht implementiert')
```
rauskommentieren/löschen.
- Jetzt
```bash
source test.sh
```
ausführen.
Jetzt `test.sh` ausführen. Die unittests testen Methoden gegen mehrere vorkonstruierte Testfälle samt erwarteten Ergebnissen geprüft. Sollten einige Tests scheitern, dann Fehlermeldung durchlesen, und Methode entsprechend der Kritik überarbeiten.
Die unit tests testen Methoden gegen mehrere vorkonstruierte Testfälle samt erwarteten Ergebnissen geprüft. Sollten einige Tests scheitern, dann Fehlermeldung durchlesen, und Methode entsprechend der Kritik überarbeiten.
Die geschriebenen Unittests sind natürlich nicht ausführlich. Man kann diese nach Bedarf ergänzen. Am sinnvollsten baut man welche, die wirklich scheitern können, sonst sagen die Tests nichts aus.
Die geschriebenen unit tests sind natürlich nicht ausführlich. Man kann diese nach Bedarf ergänzen. Am sinnvollsten baut man welche, die wirklich scheitern können, sonst sagen die Tests nichts aus.

View File

@ -1,37 +0,0 @@
%import common.WS
%import common.NUMBER
%import common.WORD
%ignore WS
// Schemata für Ausdrücke
// 'open' = äußerste Klammern fehlen, wenn nötig.
// 'closed' = sonst
?expr: open | closed
?closed: atomic | not | "(" open ")"
?open: and | and_long | or | or_long | impl
// Schemata für atomische Ausdrücke
?atomic: false | true | atom | generic
?false: /0|false/ -> kontr
?true: /1|true/ -> taut
?atom: /A[0-9]+/ -> atom
// als 'generische' Formeln schreibe bspw. {F}, {G}, {F1}, usw.
?generic: "{" /((?!({|})).)+/ "}" -> beliebig
// Symbole (erlaube mehrere Varianten)
?symb_not: /!|~|not/ -> symb
?symb_and: /&+|\^|and/ -> symb
?symb_or: /\|+|v|or/ -> symb
?symb_impl: /->|=>/ -> symb
// Schema für Negation: ¬ F
?not: symb_not closed -> neg
// Schemata für Konjunktion: F1 ⋀ F2 bzw. F1 ⋀ F2 ⋀ ... ⋀ Fn
?and: closed symb_and closed -> konj
?and_long: [ closed ( symb_and closed )+ ] -> konj_lang
// Schemata für Disjunktion: F1 F2 bzw. F1 F2 ... Fn
?or: closed symb_or closed -> disj
?or_long: [ closed ( symb_or closed )+ ] -> disj_lang
// Schema für Implikation: F1 ⟶ F2
?impl: closed symb_impl closed -> impl

View File

@ -5,21 +5,9 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 isLongConjunction;
from aussagenlogik.schema import isDisjunction;
from aussagenlogik.schema import isLongDisjunction;
from aussagenlogik.schema import isImplication;
from aussagenlogik.schema import SyntaxBaum;
from aussagenlogik.syntaxbaum import SyntaxBaum;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBALE KONSTANTEN
@ -31,53 +19,69 @@ from aussagenlogik.schema import SyntaxBaum;
# METHODEN
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def rekursiv_eval(fml: SyntaxBaum, I: List[str]) -> int:
def rekursivEval(fml: SyntaxBaum, I: List[str]) -> int:
subfml = fml.children;
if isAtom(fml):
########
# FÄLLE AUS DER VORLESUNG
########
# Fall Atom
if fml.isAtom():
name = fml.expr;
return 1 if (name in I) else 0;
if isBeliebig(fml):
name = fml.expr;
return 1 if (name in I) else 0;
elif isTrueSymbol(fml):
return 1;
elif isFalseSymbol(fml):
return 0;
elif isNegation(fml):
val0 = rekursiv_eval(subfml[0], I);
# Fall ¬F
elif fml.isNegation():
val0 = rekursivEval(subfml[0], I);
return 1 - val0;
elif isConjunction(fml):
val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(subfml[1], I);
# Fall F1 ⋀ F2
elif fml.isConjunction2():
val0 = rekursivEval(subfml[0], I);
val1 = rekursivEval(subfml[1], I);
return min(val0, val1);
elif isLongConjunction(fml):
values = [rekursiv_eval(t, I) for t in subfml];
return min(values);
elif isDisjunction(fml):
val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(subfml[1], I);
# Fall F1 F2
elif fml.isDisjunction2():
val0 = rekursivEval(subfml[0], I);
val1 = rekursivEval(subfml[1], I);
return max(val0, val1);
elif isLongDisjunction(fml):
values = [rekursiv_eval(t, I) for t in subfml];
return max(values);
elif isImplication(fml):
val0 = rekursiv_eval(subfml[0], I);
val1 = rekursiv_eval(subfml[1], I);
########
# WEITERE FÄLLE NICHT IN VORLESUNG
########
# Sonderfall: generische Formel als Variable
if fml.isGeneric():
name = fml.expr;
return 1 if (name in I) else 0;
# Sonderfall: Tautologiesymbol
elif fml.isTautologySymbol():
return 1;
# Sonderfall: Kontradiktionssymbol
elif fml.isContradictionSymbol():
return 0;
# Fall Implikation: F1 ⟶ F2
elif fml.isImplication():
val0 = rekursivEval(subfml[0], I);
val1 = rekursivEval(subfml[1], I);
return 0 if val0 == 1 and val1 == 0 else 1;
# Fall F1 ⋀ F2 ⋀ ... ⋀ Fn
elif fml.isConjunction():
values = [rekursivEval(t, I) for t in subfml];
return min(values);
# Fall F1 F2 ... Fn
elif fml.isDisjunction():
values = [rekursivEval(t, I) for t in subfml];
return max(values);
raise Exception('Evaluation nicht möglich!');
def rekursiv_atoms(fml: Tree) -> List[str]:
def rekursivAtoms(fml: SyntaxBaum) -> List[str]:
## Herausforderung: schreibe diese Funktion!
return [];
def rekursiv_depth(fml: Tree) -> int:
def rekursivDepth(fml: SyntaxBaum) -> int:
## Herausforderung: schreibe diese Funktion!
return 0;
def rekursiv_length(fml: Tree) -> int:
def rekursivLength(fml: SyntaxBaum) -> int:
## Herausforderung: schreibe diese Funktion!
return 0;
def rekursiv_parentheses(fml: Tree) -> int:
def rekursivParentheses(fml: SyntaxBaum) -> int:
## Herausforderung: schreibe diese Funktion!
return 0

View File

@ -6,8 +6,6 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
# install: lark; lark-parser; lark-parser[regex].
# https://lark-parser.readthedocs.io/en/latest/grammar.html
from lark import Lark;
from aussagenlogik.syntaxbaum import SyntaxBaum;
@ -16,10 +14,10 @@ from aussagenlogik.syntaxbaum import SyntaxBaum;
# GLOBALE KONSTANTEN
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## lexer
with open('aussagenlogik/grammar.lark', 'r') as fp:
# lexer durch LARK erzeugen
with open('grammars/grammar.lark', 'r') as fp:
grammar = ''.join(fp.readlines());
lexerAussagenlogik = Lark(grammar, start='expr', regex=True);
lexer = Lark(grammar, start='expr', regex=True);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODE: string -> Syntaxbaum
@ -27,43 +25,6 @@ with open('aussagenlogik/grammar.lark', 'r') as fp:
def stringToSyntaxbaum(expr: str) -> SyntaxBaum:
try:
return SyntaxBaum(lexerAussagenlogik.parse(expr));
return SyntaxBaum(lexer.parse(expr));
except:
raise Exception('Ausdruck \033[1m{}\033[0m konnte nicht erkannt werden!'.format(expr));
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODEN: Erkennung von Formeltypen
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def isAtom(fml: SyntaxBaum) -> bool:
return fml.kind == 'atom';
def isLiteral(fml: SyntaxBaum) -> bool:
return isAtom(fml) or (isNegation(fml) and isAtom(fml.child));
def isBeliebig(fml: SyntaxBaum) -> bool:
return fml.kind == 'beliebig';
def isTrueSymbol(fml: SyntaxBaum) -> bool:
return fml.kind == 'taut';
def isFalseSymbol(fml: SyntaxBaum) -> bool:
return fml.kind == 'kontr';
def isNegation(fml: SyntaxBaum) -> bool:
return fml.kind == 'neg';
def isConjunction(fml: SyntaxBaum) -> bool:
return fml.kind == 'konj';
def isLongConjunction(fml: SyntaxBaum) -> bool:
return fml.kind in ['konj', 'konj_lang'];
def isDisjunction(fml: SyntaxBaum) -> bool:
return fml.kind == 'disj';
def isLongDisjunction(fml: SyntaxBaum) -> bool:
return fml.kind in ['disj', 'disj_lang'];
def isImplication(fml: SyntaxBaum) -> bool:
return fml.kind == 'impl';

View File

@ -6,7 +6,7 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
from lark import Tree;
from lark import Tree as larkTree;
from typing import Generator;
from typing import List;
@ -21,37 +21,31 @@ from typing import List;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SyntaxBaum(object):
expr: str;
kind: str;
expr: str;
valence: int;
children: List[SyntaxBaum];
tree: Tree;
def __init__(self, fml: Tree):
def __init__(self, fml: larkTree):
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 subfml in fml.children:
if isinstance(subfml, str):
signature_parts.append(subfml);
elif subfml.data == 'symb':
symb = str(subfml.children[0]);
signature_parts.append(symb);
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' ]:
lbrace = '(' if self.expr.startswith('(') else '( ';
rbrace = ')' if self.expr.endswith(')') else ' )';
self.expr = lbrace + self.expr + rbrace;
self.children = [];
self.valence = 0;
expr_parts = []
for child in fml.children:
if isinstance(child, str):
expr_parts.append(child);
## subfml is instance larkTree:
elif child.data == 'symb':
symb = str(child.children[0]);
expr_parts.append(symb);
else:
subtree = SyntaxBaum(child);
self.children.append(subtree);
self.valence += 1;
expr_parts.append(subtree.expr);
self.expr = ' '.join(expr_parts);
if self.valence > 1:
self.expr = '(' + self.expr + ')';
return;
def __str__(self):
@ -65,5 +59,58 @@ class SyntaxBaum(object):
def child(self) -> SyntaxBaum:
return self.children[0];
def pretty(self):
return self.tree.pretty(indent_str='- ');
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHOD: Pretty
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def pretty(self, preindent: str = '', tab: str = ' ', prepend: str = '', depth: int = 0) -> str:
indent = preindent + tab*depth;
if self.valence == 0 and self.kind in [ 'atom', 'generic' ]:
return indent + prepend + self.kind + ' ' + self.expr;
return '\n'.join(
[indent + prepend + self.kind] \
+ [subtree.pretty(preindent, tab, '|__ ', depth+1) for subtree in self.children]
);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS: Erkennung von Formeltypen
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def isIrreducible(self) -> bool:
return self.valence == 0;
def isAtom(self) -> bool:
return self.kind == 'atom';
def isLiteral(self) -> bool:
return self.isAtom() or (self.isNegation() and self.child.isAtom());
def isGeneric(self) -> bool:
return self.kind == 'generic';
def isTautologySymbol(self) -> bool:
return self.kind == 'taut';
def isContradictionSymbol(self) -> bool:
return self.kind == 'contradiction';
def isConnective(self) -> bool:
return self.valence > 0;
def isNegation(self) -> bool:
return self.kind == 'not';
def isConjunction2(self) -> bool:
return self.kind == 'and2';
def isConjunction(self) -> bool:
return self.kind in ['and', 'and2'];
def isDisjunction2(self) -> bool:
return self.kind == 'or2';
def isDisjunction(self) -> bool:
return self.kind in ['or', 'or2'];
def isImplication(self) -> bool:
return self.kind == 'implies';

9
code/grammars/README.md Normal file
View File

@ -0,0 +1,9 @@
# LARK #
Die Grammatik wird hier in `.lark` Format präsentiert und gelext+geparsed.
Für Python braucht man `lark`, `lark-parser`, `lark-parser[regex]` über **PIP** zu installieren.
Siehe
<https://lark-parser.readthedocs.io/en/latest/grammar.html>
und
<https://github.com/lark-parser/lark>
für mehr Informationen zu **LARK**.

View File

@ -0,0 +1,35 @@
%import common.WS
%import common.NUMBER
%import common.WORD
%ignore WS
// Schemata für Ausdrücke
?expr: open | closed
?closed: atomic | not | "(" open ")"
?open: and | and2 | or | or2 | implies
// Schemata für atomische Ausdrücke
?atomic: taut | contradiction | atom | generic
?taut: /1|true/ -> taut
?contradiction: /0|false/ -> contradiction
?atom: /A[0-9]+/ -> atom
// als 'generische' Formeln schreibe bspw. {F}, {G}, {F1}, usw.
?generic: "{" /((?!({|})).)+/ "}" -> generic
// Symbole (erlaube mehrere Varianten)
?symb_not: /!|~|not/ -> symb
?symb_and: /&+|\^|and/ -> symb
?symb_or: /\|+|v|or/ -> symb
?symb_impl: /->|=>/ -> symb
// Schema für Negation: ¬ F
?not: symb_not closed
// Schemata für Konjunktion: F1 ⋀ F2 bzw. F1 ⋀ F2 ⋀ ... ⋀ Fn
?and2: closed symb_and closed
?and: [ closed ( symb_and closed )+ ]
// Schemata für Disjunktion: F1 F2 bzw. F1 F2 ... Fn
?or2: closed symb_or closed
?or: [ closed ( symb_or closed )+ ]
// Schema für Implikation: F1 ⟶ F2
?implies: closed symb_impl closed

View File

@ -17,11 +17,11 @@ sys.path.insert(0, os.getcwd());
from aussagenlogik.schema import stringToSyntaxbaum;
from aussagenlogik.syntaxbaum import SyntaxBaum;
from aussagenlogik.rekursion import rekursiv_eval;
from aussagenlogik.rekursion import rekursiv_atoms;
from aussagenlogik.rekursion import rekursiv_depth;
from aussagenlogik.rekursion import rekursiv_length;
from aussagenlogik.rekursion import rekursiv_parentheses;
from aussagenlogik.rekursion import rekursivEval;
from aussagenlogik.rekursion import rekursivAtoms;
from aussagenlogik.rekursion import rekursivDepth;
from aussagenlogik.rekursion import rekursivLength;
from aussagenlogik.rekursion import rekursivParentheses;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBALE KONSTANTEN
@ -37,17 +37,17 @@ def main():
## Daten einlesen:
expr, I = getData();
## Formel in Teilformeln zerlegen:
fml = stringToSyntaxbaum(expr);
tree = stringToSyntaxbaum(expr);
## Methoden ausführen:
results = dict(
eval = rekursiv_eval(fml, I),
atoms = rekursiv_atoms(fml),
d = rekursiv_depth(fml),
l = rekursiv_length(fml),
p = rekursiv_parentheses(fml),
eval = rekursivEval(tree, I),
atoms = rekursivAtoms(tree),
depth = rekursivDepth(tree),
length = rekursivLength(tree),
nParentheses = rekursivParentheses(tree),
);
## Resultate anzeigen:
display_results(expr, fml, I, results);
display_results(tree, I, results);
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -60,22 +60,23 @@ def getData():
I = eval(data['interpretation'] or '[]');
return expr, I;
def display_results(expr: str, fml: SyntaxBaum, I: List[str], results: dict):
def display_results(tree: SyntaxBaum, I: List[str], results: dict):
print(dedent(
'''
Syntaxbaum von
F := \033[92;1m{F}\033[0m:
'''.format(F=fml)
F := \033[92;1m{expr}\033[0m:
'''.format(expr=tree.expr)
));
print(fml.pretty());
print(tree.pretty(' '))
print(dedent(
'''
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[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[2m#parentheses(F) = \033[94;1m{p}\033[0m; \033[91;1m<- *\033[0m
\033[2mdepth(F) = \033[94;1m{depth}\033[0m; \033[91;1m<- *\033[0m
\033[2mlength(F) = \033[94;1m{length}\033[0m; \033[91;1m<- *\033[0m
\033[2m#parentheses(F) = \033[94;1m{nParentheses}\033[0m; \033[91;1m<- *\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

View File

@ -18,7 +18,7 @@ function check_requirements() {
function run_unittests(){
echo -e "\033[1mUNITTESTS\033[0m\n";
local output="$(call_python -m unittest discover -v --top-level-directory "." --start-directory "utests" --pattern "u_*.py" 2>&1)";
local output="$(call_python -m unittest discover -v --top-level-directory "." --start-directory "utests" --pattern "*_test.py" 2>&1)";
echo -e "$output";
if ( echo "$output" | grep -E -q "^[[:space:]]*(FAIL:|FAILED)" ); then
echo -e "[\033[91;1mERROR\033[0m] Unit tests versagt!" && return 1;

View File

@ -9,11 +9,11 @@ import unittest;
from unittest import TestCase;
from aussagenlogik.schema import stringToSyntaxbaum;
from aussagenlogik.rekursion import rekursiv_atoms;
from aussagenlogik.rekursion import rekursiv_depth;
from aussagenlogik.rekursion import rekursiv_length;
from aussagenlogik.rekursion import rekursiv_parentheses;
from aussagenlogik.rekursion import rekursiv_eval;
from aussagenlogik.rekursion import rekursivEval;
from aussagenlogik.rekursion import rekursivAtoms;
from aussagenlogik.rekursion import rekursivDepth;
from aussagenlogik.rekursion import rekursivLength;
from aussagenlogik.rekursion import rekursivParentheses;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBALE KONSTANTEN
@ -29,34 +29,34 @@ from aussagenlogik.rekursion import rekursiv_eval;
class TestRekursivEval(TestCase):
def test_literale(self):
fml = stringToSyntaxbaum('A0');
val = rekursiv_eval(fml, [ 'A0' ]);
val = rekursivEval(fml, [ 'A0' ]);
assert val == 1;
fml = stringToSyntaxbaum('A0');
val = rekursiv_eval(fml, []);
val = rekursivEval(fml, []);
assert val == 0;
fml = stringToSyntaxbaum('! A0');
val = rekursiv_eval(fml, [ 'A0' ]);
val = rekursivEval(fml, [ 'A0' ]);
assert val == 0;
fml = stringToSyntaxbaum('! A0');
val = rekursiv_eval(fml, []);
val = rekursivEval(fml, []);
assert val == 1;
def test_complex1(self):
fml = stringToSyntaxbaum('( ! A0 || (( A0 && A3 ) || A2 ))');
val = rekursiv_eval(fml, [ 'A0', 'A2' ]);
val = rekursivEval(fml, [ 'A0', 'A2' ]);
assert val == 1;
val = rekursiv_eval(fml, [ 'A0', 'A3' ]);
val = rekursivEval(fml, [ 'A0', 'A3' ]);
assert val == 1;
val = rekursiv_eval(fml, [ 'A0' ]);
val = rekursivEval(fml, [ 'A0' ]);
assert val == 0;
val = rekursiv_eval(fml, [ 'A4', 'A8' ]);
val = rekursivEval(fml, [ 'A4', 'A8' ]);
assert val == 1;
def test_complex2(self):
fml = stringToSyntaxbaum('( ! A0 || (( A0 && A3 ) || ! A2 ))');
val = rekursiv_eval(fml, [ 'A0', 'A2' ]);
val = rekursivEval(fml, [ 'A0', 'A2' ]);
assert val == 0;
val = rekursiv_eval(fml, [ 'A0', 'A3' ]);
val = rekursivEval(fml, [ 'A0', 'A3' ]);
assert val == 1;
pass;
@ -68,22 +68,22 @@ class TestRekursivEval(TestCase):
class TestRekursivAtoms(TestCase):
def test_noduplicates(self):
fml = stringToSyntaxbaum('( A4 && ( A4 || A4 ))');
val = sorted(rekursiv_atoms(fml));
val = sorted(rekursivAtoms(fml));
assert len([_ for _ in val if _ == 'A4']) == 1, 'Atome dürfen nicht mehrfach vorkommen!';
def test_nononatoms(self):
fml = stringToSyntaxbaum('( {F} || A3 )');
val = sorted(rekursiv_atoms(fml));
val = sorted(rekursivAtoms(fml));
assert 'F' not in val, 'Nichtatomare Formeln dürfen nicht vorkommen!';
def test_calc1(self):
fml = stringToSyntaxbaum('A0');
val = sorted(rekursiv_atoms(fml));
val = sorted(rekursivAtoms(fml));
assert val == ['A0'], 'computed {}'.format(val);
def test_calc2(self):
fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )');
val = sorted(rekursiv_atoms(fml));
val = sorted(rekursivAtoms(fml));
assert val == ['A0', 'A3', 'A4', 'A8'], 'computed {}'.format(val);
pass;
@ -95,27 +95,27 @@ class TestRekursivAtoms(TestCase):
class TestRekursivDepth(TestCase):
def test_calc1(self):
fml = stringToSyntaxbaum('A0');
val = rekursiv_depth(fml);
val = rekursivDepth(fml);
assert val == 0, 'computed {}'.format(val);
def test_calc2(self):
fml = stringToSyntaxbaum('!! A8');
val = rekursiv_depth(fml);
val = rekursivDepth(fml);
assert val == 2, 'computed {}'.format(val);
def test_calc3(self):
fml = stringToSyntaxbaum('( ! A0 && A3 )');
val = rekursiv_depth(fml);
val = rekursivDepth(fml);
assert val == 2, 'computed {}'.format(val);
def test_calc4(self):
fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_depth(fml);
val = rekursivDepth(fml);
assert val == 4, 'computed {}'.format(val);
def test_calc5(self):
fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_depth(fml);
val = rekursivDepth(fml);
assert val == 5, 'computed {}'.format(val);
pass;
@ -127,27 +127,27 @@ class TestRekursivDepth(TestCase):
class TestRekursivLength(TestCase):
def test_calc1(self):
fml = stringToSyntaxbaum('A0');
val = rekursiv_length(fml);
val = rekursivLength(fml);
assert val == 1, 'computed {}'.format(val);
def test_calc2(self):
fml = stringToSyntaxbaum('!! A8');
val = rekursiv_length(fml);
val = rekursivLength(fml);
assert val == 3, 'computed {}'.format(val);
def test_calc3(self):
fml = stringToSyntaxbaum('( ! A0 && A3 )');
val = rekursiv_length(fml);
val = rekursivLength(fml);
assert val == 4, 'computed {}'.format(val);
def test_calc4(self):
fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_length(fml);
val = rekursivLength(fml);
assert val == 8, 'computed {}'.format(val);
def test_calc5(self):
fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_length(fml);
val = rekursivLength(fml);
assert val == 9, 'computed {}'.format(val);
pass;
@ -159,26 +159,26 @@ class TestRekursivLength(TestCase):
class TestRekursivParentheses(TestCase):
def test_calc1(self):
fml = stringToSyntaxbaum('A0');
val = rekursiv_parentheses(fml);
val = rekursivParentheses(fml);
assert val == 0, 'computed {}'.format(val);
def test_calc2(self):
fml = stringToSyntaxbaum('!! A8');
val = rekursiv_parentheses(fml);
val = rekursivParentheses(fml);
assert val == 0, 'computed {}'.format(val);
def test_calc3(self):
fml = stringToSyntaxbaum('( ! A0 && A3 )');
val = rekursiv_parentheses(fml);
val = rekursivParentheses(fml);
assert val == 2, 'computed {}'.format(val);
def test_calc4(self):
fml = stringToSyntaxbaum('((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_parentheses(fml);
val = rekursivParentheses(fml);
assert val == 6, 'computed {}'.format(val);
def test_calc5(self):
fml = stringToSyntaxbaum('! ((( ! A0 && A3 ) || A4 ) && A8 )');
val = rekursiv_parentheses(fml);
val = rekursivParentheses(fml);
assert val == 6, 'computed {}'.format(val);
pass;

19
codego/.gitignore vendored
View File

@ -3,8 +3,18 @@
!/data.env
!/README.md
!/build.sh
!/test.sh
## Scripts
!/scripts
!/scripts/requirements
!/scripts/build.sh
!/scripts/build.sh
!/scripts/test.sh
## Für Erzeugung von Grammatiken:
!/grammars
!/grammars/README.md
!/grammars/*.g4
## Go Source
!/aussagenlogik
@ -14,11 +24,6 @@
!/core
!/core/environment
!/core/utils
!/grammars
!/**/*.go
!/go.mod
!/go.sum
## Für Erzeugung von Grammatiken:
!/grammars/README.md
!/grammars/*.g4

View File

@ -6,24 +6,30 @@ Diese dienen nur zur Demonstration / konkreten Verwirklichung von Verfahren, die
Der Gebrauch dieser Skripte unterliegt der Eigenverantwortung von Studierenden.
Da ich kein Informatiker bin, sind auch einige Aspekt bestimmt nicht optimal programmiert/strukturiert.
Da ich kein Informatiker bin,
sind auch einige Aspekt bestimmt nicht optimal programmiert/strukturiert.
Dafür kann jeder in seiner Kopie einfach alles anpassen.
Das hier soll einfach funktionieren.
## Systemvoraussetzungen ##
- bash (auch bash-for-windows).
- golang (mind. 1.6.x)
- Java11
- Java8+
Um Schemata in Lexer und Parser zu verwandeln, wird **ANTLR4** gebraucht,
(welches wiederum mithilfe eines Java-Archives kompiliert wird, weshalb man Java benötigt).
Siehe
<https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/>
für weitere Informationen dazu.
Dieses Projekt macht von ANTLR4 Gebrauch, um Schemata in Lexer und Parser zu verwandeln. Siehe <https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/> für mehr Informationen dazu.
## Voreinstellungen ##
- In einer bash-console zu diesem Ordner navigieren und folgenden Befehl ausführen:
```bash
chmod +x build.sh test.sh
## oder
chmod +x *.sh
chmod +x scripts/*.sh
```
- In `build.sh` gibt es eine Zeile, die zur Kompilierung des Go-Projektes notwendigen Module über **go** installieren lässt.
- In `scripts/build.sh` gibt es eine Zeile, die zur Kompilierung des Go-Projektes notwendigen Module über **go** installieren lässt.
(Die Liste der Packages findet man in der Datei `requirements`).
Diese Zeile kann man ruhig nach der ersten Ausführung rauskommentieren.
- Dazu kommt, dass **antlr4.jar** heruntergeladen wird.
@ -37,7 +43,7 @@ In `data.env` kann man Daten (aktuell: auszuwertenden Ausdruck + Interpretation/
In einer bash-console zu diesem Ordner navigieren und
```bash
./build.sh
source scripts/build.sh
## oder
go build main.go && ./main
```
@ -72,14 +78,20 @@ Wer etwas standardisierter seine Methoden testen will, kann automatisiertes Test
- In der Console (wenn noch nicht geschehen) folgenden Befehl einmalig ausführen:
```bash
chmod +x test.sh
chmod +x scripts/test.sh
```
- In `aussagenlogik/rekursion/rekursion_test.go` beim relevanten Testteil eine oder mehrere der Zeilen
```go
test.Skip("Methode noch nicht implementiert")
```
rauskommentieren/löschen.
- Jetzt
```bash
source scripts/test.sh
```
ausführen.
Jetzt `test.sh` ausführen. Die unittests testen Methoden gegen mehrere vorkonstruierte Testfälle samt erwarteten Ergebnissen geprüft. Sollten einige Tests scheitern, dann Fehlermeldung durchlesen, und Methode entsprechend der Kritik überarbeiten.
Die unittests testen Methoden gegen mehrere vorkonstruierte Testfälle samt erwarteten Ergebnissen geprüft.
Sollten einige Tests scheitern, dann Fehlermeldung durchlesen, und Methode entsprechend der Kritik überarbeiten.
Die geschriebenen Unittests sind natürlich nicht ausführlich. Man kann diese nach Bedarf ergänzen. Am sinnvollsten baut man welche, die wirklich scheitern können, sonst sagen die Tests nichts aus.

View File

@ -17,7 +17,7 @@ function call_go() {
function check_requirements() {
[ -f "go.sum" ] && rm "go.sum";
call_go get "$( cat requirements )";
call_go get "$( cat scripts/requirements )";
}
function get_antlr() {
@ -37,6 +37,7 @@ function precompile_grammars() {
local name;
! [ -f "grammars/antlr.jar" ] && get_antlr; # <- lädt antl.jar herunter, wenn fehlt
pushd grammars >> $NULL;
rm -rf .antlr; # <- wird automatisch erzeugt, aber wir brauche dies nicht
while read fname; do
( [ "$fname" == "" ] || ! [ -f "$fname" ] ) && continue;
name="$( echo "$fname" | sed -E "s/^(.*)\.g4$/\1/g" )";
@ -50,11 +51,14 @@ function compile_programme() {
[ -f "main" ] && rm "main";
echo -e "\033[92;1mGO\033[0m kompiliert \033[1mmain.go\033[0m";
call_go build "main.go";
! [ -f "main" ] && exit 1;
! [ -d "dist" ] && mkdir "dist";
mv "main" "dist";
}
function run_programme() {
echo -e "\033[92;1mGO\033[0m kompiliertes Programm wird ausgeführt";
./main;
./dist/main;
}
################################

View File

@ -0,0 +1,5 @@
github.com/joho/godotenv@v1.3.0
github.com/lithammer/dedent
github.com/antlr/antlr4/runtime/Go/antlr
github.com/stretchr/testify
golang.org/x/tools

View File

@ -17,7 +17,7 @@ function call_go() {
function check_requirements() {
[ -f "go.sum" ] && rm "go.sum";
call_go get "$( cat requirements )";
call_go get "$( cat scripts/requirements )";
}
function run_unittests(){