master > master: allgemeine Aufräumung
This commit is contained in:
parent
a0dee82659
commit
61ec2d7df3
19
code/.gitignore
vendored
19
code/.gitignore
vendored
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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
9
code/grammars/README.md
Normal 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**.
|
35
code/grammars/grammar.lark
Normal file
35
code/grammars/grammar.lark
Normal 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
|
39
code/main.py
39
code/main.py
@ -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
|
||||
|
@ -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;
|
@ -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
19
codego/.gitignore
vendored
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
################################
|
5
codego/scripts/requirements
Normal file
5
codego/scripts/requirements
Normal 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
|
@ -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(){
|
Loading…
Reference in New Issue
Block a user