from nltk.featstruct import FeatStruct

"""
Explanation: Übungsblatt 9
Präsenzaufgaben
Aufgabe 1 &nbsp;&nbsp;&nbsp; Unifikation I
End of explanation
"""


f1 = FeatStruct(
    '[Vorname=Max, Nachname=Mustermann,' + 
    'Privat=[Strasse=Hauptstrasse, Ort=[Muenchen]]]'
)
f2 = FeatStruct(
    '[Arbeit=[Strasse="Oettingenstrasse", Ort=(1)["Muenchen"]],' +
    'Privat=[Ort->(1)]]')
f3 = FeatStruct(
    '[Strasse="Hauptstrasse"]'
)
f4 = FeatStruct(
    '[Privat=[Strasse="Hauptstrasse", Ort=["Passau"]]]'
)

"""
Explanation: Gegeben seien folgende Merkmalstrukturen:
End of explanation
"""


print(f1.unify(f2).__repr__())

"""
Explanation: Unifizieren Sie:
- f1 mit f2
End of explanation
"""


print(f2.unify(f4).__repr__())

"""
Explanation: f2 mit f4
End of explanation
"""


grammar = """
S -> NP VP
NP -> DET NOM
NOM -> N NP | N
VP -> V

V -> "schläft"
DET[GEN=mask] -> "der" | "des"
DET[GEN=fem] -> "die" | "der"
DET[GEN=neut] -> "das" | "des"
N[GEN=mask] -> "Mann" | "Mannes"
N[GEN=fem] -> "Frau"
N[GEN=neut] -> "Kind" | "Kindes"
"""

import nltk
from typed_features import HierarchicalFeature, TYPE

"""
Explanation: Aufgabe 2 &nbsp;&nbsp;&nbsp; Typhierarchie im NLTK
Gegeben sei folgende Typhierarchie:
$$\bot \sqsubseteq \text{Genitiv}$$
$$\bot \sqsubseteq \text{nicht-Genitiv}$$
$$\text{nicht-Genitiv} \sqsubseteq \text{Nominativ-Akkusativ}$$
$$\text{nicht-Genitiv} \sqsubseteq \text{Dativ}$$
$$\text{Nominativ-Akkusativ} \sqsubseteq \text{Nominativ}$$
$$\text{Nominativ-Akkusativ} \sqsubseteq \text{Akkusativ}$$
Implementieren Sie mithilfe der Klasse HierarchicalFeature,
die Sie sich von der Kurs-Website herunterladen können, ein Feature CASE, das der vorgegebenen Typhierarchie entspricht.
Nutzen Sie dieses Feature dann, um Übergenerierung in folgender Grammatik zu vermeiden:
End of explanation
"""


type_hierarchy = {
    
}

CASE = HierarchicalFeature("CASE", type_hierarchy)
compiled_grammar = nltk.grammar.FeatureGrammar.fromstring(
    grammar, features=(CASE, TYPE)
)
parser = nltk.FeatureEarleyChartParser(compiled_grammar)

"""
Explanation: Hier muss die Typhierarchie in Form eines Dictionary definiert werden:
End of explanation
"""


for t in parser.parse("das Kind des Mannes schläft".split()):
    print(t)

"""
Explanation: Folgendes sollte funktionieren:
End of explanation
"""


list(parser.parse("des Mannes schläft".split()))

"""
Explanation: Folgendes sollte leer sein:
End of explanation
"""


print(f1.unify(f4).__repr__())

"""
Explanation: Hausaufgaben
Aufgabe 3 &nbsp;&nbsp;&nbsp; Unifikation II
Es seien wieder die Merkmalstrukturen aus Aufgabe 1 gegeben.
Unifizieren Sie:
- f1 mit f4
End of explanation
"""


print(f2.unify(f3).__repr__())

"""
Explanation: f2 mit f3
End of explanation
"""


redundant_grammar = """
S -> NP[KAS=nom] VP

NP[KAS=?y] -> DET[GEN=?x,KAS=?y] NOM[GEN=?x,KAS=?y]
NOM[GEN=?x,KAS=?y] -> N[GEN=?x,KAS=?y] NP[KAS=gen]
NOM[GEN=?x,KAS=?y] -> N[GEN=?x,KAS=?y]

DET[GEN=mask,KAS=nom] -> "der"
DET[GEN=mask,KAS=gen] -> "des"
DET[GEN=mask,KAS=dat] -> "dem"
DET[GEN=mask,KAS=akk] -> "den"
DET[GEN=fem,KAS=nom] -> "die"
DET[GEN=fem,KAS=gen] -> "der"
DET[GEN=fem,KAS=dat] -> "der"
DET[GEN=fem,KAS=akk] -> "die"
DET[GEN=neut,KAS=nom] -> "das"
DET[GEN=neut,KAS=gen] -> "des"
DET[GEN=neut,KAS=dat] -> "dem"
DET[GEN=neut,KAS=akk] -> "das"

N[GEN=mask,KAS=nom] -> "Mann"
N[GEN=mask,KAS=gen] -> "Mannes"
N[GEN=mask,KAS=dat] -> "Mann"
N[GEN=mask,KAS=akk] -> "Mann"
N[GEN=fem,KAS=nom] -> "Frau"
N[GEN=fem,KAS=gen] -> "Frau"
N[GEN=fem,KAS=dat] -> "Frau"
N[GEN=fem,KAS=akk] -> "Frau"
N[GEN=neut,KAS=nom] -> "Buch"
N[GEN=neut,KAS=gen] -> "Buches"
N[GEN=neut,KAS=dat] -> "Buch"
N[GEN=neut,KAS=akk] -> "Buch"

VP -> V NP[KAS=dat] NP[KAS=akk]
V -> "gibt" | "schenkt"
"""

pos_sentences = [
    "der Mann gibt der Frau das Buch",
    "die Frau des Mannes gibt dem Mann der Frau das Buch des Buches"
]

"""
Explanation: Aufgabe 4 &nbsp;&nbsp;&nbsp; Weniger Redundanz dank besonderer Merkmale
Beseitigen Sie die Redundanz in den lexikalischen Regeln (Zeilen 8 - 32) der folgenden Grammatik durch eine Typhierarchie (wo dies nötig ist). Achten Sie darauf, die Menge der akzeptierten Sätze weder zu verkleinern noch zu vergrößern!
Anzugeben sind die neuen Grammatikregeln, sowie Ihre Typhierarchie (z. B. in graphischer Form).
End of explanation
"""


neg_sentences = [
    
]

from IPython.display import display

def test_grammar(grammar, sentences):
    cfg = nltk.grammar.FeatureGrammar.fromstring(grammar)
    parser = nltk.parse.FeatureEarleyChartParser(cfg)
    
    for i, sent in enumerate(sentences, 1):
        print("Satz {}: {}".format(i, sent))
        results = parser.parse(sent.split())
        analyzed = False
        for tree in results:
            print(tree)  # oder display(tree)
            analyzed = True
        if not analyzed:
            print("Keine Analyse möglich", file=sys.stderr)

test_grammar(redundant_grammar, pos_sentences)

"""
Explanation: Testen Sie mit Ihren eigenen Negativbeispielen!
End of explanation
"""


