10.10.2013 Aufrufe

Aufgaben Logische Programmierung

Aufgaben Logische Programmierung

Aufgaben Logische Programmierung

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>Aufgaben</strong> <strong>Logische</strong> <strong>Programmierung</strong><br />

Elmar Eder<br />

20. Juni 2013<br />

Aufgabe 1 Programm verwandtschaft.pl erweitern<br />

Dateiname: verwandtschaft.pl<br />

Erweitern Sie das Programm verwandtschaft.pl:<br />

• Datenbank erweitern (weitere Personen)<br />

• Weitere Verwandtschaftsbeziehungen hinzfügen<br />

Aufgabe 2 Anfragen stellen<br />

Dateiname: verwandtschaft.dialog<br />

Konsultieren Sie die ursprüngliche Datei http://www.cosy.sbg.ac.at/~eder/lehre/<strong>Logische</strong>_<br />

<strong>Programmierung</strong>/verwandtschaft.pl in Prolog! Stellen Sie an Prolog Anfragen zur Beantwortung<br />

der folgenden Fragen (ohne das ursprüngliche Programm zu verändern und ohne neue<br />

Klauseln hinzuzufügen):<br />

0. Wessen Kind ist Emil?<br />

1. Wer ist Kind von Dora?<br />

2. Wer ist Kind von wem?<br />

3. Wer ist Kind von sich selbst?<br />

4. Welche zwei Personen sind die Eltern (Vater bzw. Mutter) von welcher dritten Person?<br />

5. Wer ist Großmutter von Gustav?<br />

Fragen Sie Prolog dabei gegebenenfalls mit Strichpunkt „;“ nach allen Antworten! Kopieren<br />

Sie nun Ihren Dialog mit Prolog in eine Datei verwandtschaft.dialog und laden Sie diese<br />

auf https://prolog.cosy.sbg.ac.at/ hoch! Der Anfang der Datei verwandtschaft.dialog<br />

könnte etwa folgendermaßen ausschauen:<br />

?- [verwandtschaft].<br />

% verwandtschaft compiled 0.00 sec, 2,016 bytes<br />

true.<br />

?- kind(emil,P).<br />

P = anton ;<br />

P = berta.<br />

?-<br />

Aufgabe 3 Programm nationalratswahl.pl mit Kommentaren versehen und erweitern<br />

Dateiname: nationalratswahl.pl<br />

1


Bei der österreichischen Nationalratswahl 2008 hat die SPÖ 57 Mandate bekommen, die ÖVP<br />

51, die FPÖ 34, das BZÖ 21 und die Grünen 20. Für die Bildung einer Mehrheitsregierung<br />

musste eine Koalition mit insgesamt mindestens 92 Mandaten gebildet werden. Lassen Sie das<br />

Programm nationalratswahl.pl mit der Anfrage<br />

?- mehrheitsregierung(SPOe,OeVP,FPOe,BZOe,Gruene).<br />

laufen! Lassen Sie sich dabei von Prolog alle Antworten ausgeben, indem Sie nach jeder Antwort<br />

einen Strichpunkt eingeben! Erklären Sie, was die Ausgaben von Prolog in Bezug auf die anschließende<br />

Regierungsbildung bedeuteten! Erklären Sie, was die im Prologprogramm definierten<br />

Prädikate nullodereins/1 und mehrheitsregierung/5 bedeuten! Fügen Sie dem Programm<br />

entsprechende Kommentare mit all diesen Erklärungen hinzu! Ändern Sie das Programm nun so<br />

ab, dass Prolog anstatt 0 und 1 in den Antworten nein bzw. ja ausgibt!<br />

Aufgabe 4 Fortbewegung von Tieren<br />

Dateiname: tiere.pl<br />

Drücken Sie die folgenden Aussagen über verschiedene Tiergruppen und ihre bevorzugten Fortbewegungsmethoden<br />

in Form eines Prologprogramms aus:<br />

1. Löwe, Rind, Wal und Fledermaus sind Säugetiere.<br />

2. Star, Strauß und Wasseramsel sind Vögel.<br />

3. Löwe, Rind und Strauß gehen gerne.<br />

4. Forelle, Wasseramsel und Wal schwimmen gerne.<br />

5. Fledermaus, Star und Wasseramsel fliegen gerne.<br />

Fragen Sie Prolog<br />

1. nach einem Säugetier, das gerne schwimmt<br />

2. nach einem Vogel, der gerne fliegt<br />

3. nach einem Vogel, der gerne fliegt und gerne schwimmt<br />

Schreiben Sie diese Anfragen als Kommentare in das Programm hinein!<br />

Aufgabe 5 Cliquen-Problem<br />

Dateiname: clique.pl<br />

Ein bekanntes schwieriges Problem der Informatik ist das Cliquenproblem. In einer Menge von<br />

Personen gibt es einige Paare von miteinander befreundeten Personen. Eine Clique ist nun eine<br />

Teilmenge von Personen, in der jede Person mit jeder anderen Person befreundet ist. Hier ein<br />

Beispiel:<br />

• Anton und Berta sind miteinander befreundet.<br />

• Anton und Christa sind miteinander befreundet.<br />

• Anton und Dora sind miteinander befreundet.<br />

• Anton und Ernst sind miteinander befreundet.<br />

• Berta und Dora sind miteinander befreundet.<br />

• Berta und Ernst sind miteinander befreundet.<br />

• Berta und Franz sind miteinander befreundet.<br />

• Christa und Dora sind miteinander befreundet.<br />

• Christa und Ernst sind miteinander befreundet.<br />

• Dora und Ernst sind miteinander befreundet.<br />

• Dora und Franz sind miteinander befreundet.<br />

• Ernst und Franz sind miteinander befreundet.<br />

2


Schreiben Sie ein Prolog-Programm, mit dem Sie alle Cliquen von vier Personen finden können!<br />

Das Cliquen-Problem gehört zur Klasse der sogenannten NP-vollständigen Probleme. Für diese<br />

Probleme ist es bis heute keinem Forscher gelungen, einen effizienten Algorithmus anzugeben.<br />

Es wird vermutet, dass es für NP-vollständige Probleme keine effizienten Algorithmen gibt, aber<br />

auch das konnte bisher niemand beweisen. Die Frage, ob es einen effizienten Algorithmus dafür<br />

gibt (P=NP? seit 1971), ist das bekannteste bis heute ungelöste Problem der Theoretischen<br />

Informatik. Für kleine Mengen von Personen ist das Problem mit Prolog leicht lösbar, aber für<br />

große Mengen wird der Rechenaufwand gigantisch.<br />

Aufgabe 6 Nachkomme<br />

Dateiname: nachkomme.pl<br />

Kopieren Sie das ursprüngliche Programm verwandtschaft.pl von meiner Web-Seite in eine<br />

neue Datei nachkomme.pl und fügen Sie noch zwei Fakten hinzu, die besagen, dass Heinz Kind<br />

von Emil ist und dass Inge Kind von Heinz ist.<br />

Der Begriff des Nachkommen ist durch die folgenden Regeln definiert:<br />

1. Jedes Kind einer Person ist Nachkomme dieser Person.<br />

2. Jeder Nachkomme eines Kindes einer Person ist Nachkomme dieser Person.<br />

Erweitern Sie Ihr Prologprogramm um entsprechende Klauseln und testen Sie es mit verschiedenen<br />

Anfragen! Anschließend laden Sie es hoch!<br />

Aufgabe 7 Nuklide<br />

Dateiname: nuklide.pl<br />

Wir haben uns bisher hauptsächlich mit zwei Arten von Prolog-Termen beschäftigt:<br />

• Konstanten. Dazu gehören<br />

– Prolog-Atome. Beispiel: berta<br />

– Zahlen. Beispiel: 3.456<br />

• Variablen. Beispiel: X<br />

In Prolog gibt es aber auch zusammengesetzte Terme, auch Strukturen genannt. Eine Struktur<br />

hat die Form funktor(Term,...,Term), wobei der Funktor ein Prologatom ist, also klein zu<br />

schreiben ist.<br />

• Strukturen. Beispiel: nuklid(kohlenstoff,12)<br />

Mit diesem Prolog-Term können wir z.B. ein Nuklid – dh. eine bestimmte Sorte von Atomkernen<br />

– bezeichnen, hier das Nuklid Kohlenstoff 12. Jedes Nuklid ist eindeutig bestimmt durch Angabe<br />

des chemischen Elements (hier Kohlenstoff) und der Massenzahl (hier 12). Zu einem Element<br />

kann es mehrere verschiedene Nuklide geben, z.B. Kohlenstoff 12 und Kohlenstoff 14. Man sagt<br />

dann, diese Nuklide sind Isotope voneinander.<br />

Schreiben Sie ein Prologprogramm, das nur aus Fakten besteht, die die folgenden Aussagen<br />

wiedergeben.<br />

• Wasserstoff 1 ist stabil.<br />

• Wasserstoff 2 ist stabil.<br />

• Helium 3 ist stabil.<br />

• Helium 4 ist stabil.<br />

• Beryllium 9 ist stabil.<br />

• Kohlenstoff 12 ist stabil.<br />

• Kohlenstoff 13 ist stabil.<br />

3


• Wasserstoff 3 hat eine Halbwertszeit von 3, 9 · 10 8 Sekunden.<br />

• Beryllium 7 hat eine Halbwertszeit von 4, 6 · 10 6 Sekunden.<br />

• Kohlenstoff 11 hat eine Halbwertszeit von 1200 Sekunden.<br />

• Kohlenstoff 14 hat eine Halbwertszeit von 1, 8 · 10 11 Sekunden.<br />

• Uran 234 hat eine Halbwertszeit von 7, 7 · 10 12 Sekunden.<br />

• Uran 235 hat eine Halbwertszeit von 2, 2 · 10 16 Sekunden.<br />

• Uran 237 hat eine Halbwertszeit von 580000 Sekunden.<br />

• Uran 238 hat eine Halbwertszeit von 1, 4 · 10 17 Sekunden.<br />

Ihr Programm sollte sich folgendermaßen verhalten (hier nur jeweils die ersten zwei Antworten,<br />

es gibt aber mehr):<br />

?- stabil(Nuklid).<br />

Nuklid = nuklid(wasserstoff, 1) ;<br />

Nuklid = nuklid(wasserstoff, 2)<br />

?- halbwertszeit(Nuklid,Zeit).<br />

Nuklid = nuklid(wasserstoff, 3),<br />

Zeit = 3.9e+08 ;<br />

Nuklid = nuklid(beryllium, 7),<br />

Zeit = 4.6e+06<br />

Wir wollen nun ein Nuklid kurzlebig nennen, wenn seine Halbwertszeit höchstens 30 Tage beträgt.<br />

Wir wollen es langlebig nennen, wenn es stabil ist oder seine Halbwertszeit mehr als 10 12 Sekunden<br />

beträgt. Ergänzen Sie nun Ihr Programm, indem Sie Prädikate kurzlebig/1, langlebig/1<br />

und isotope/2 definieren. Dabei bedeute kurzlebig(N), dass N ein kurzlebiges Nuklid ist; analog<br />

langlebig(N). Weiter soll isotope(L,S) bedeuten, dass L und S Isotope voneinander sind,<br />

wobei L das leichtere und S das schwerere von den beiden ist. Verwenden Sie in Ihrem Programm<br />

nicht das in Prolog eingebaute Konstrukt „oder“. Stattdessen definieren Sie z.B. das Prädikat<br />

langlebig/1 durch zwei Regeln. Das Programm sollte sich folgendermaßen verhalten:<br />

?- kurzlebig(Nuklid).<br />

Nuklid = nuklid(kohlenstoff, 11) ;<br />

Nuklid = nuklid(uran, 237)<br />

?- langlebig(Nuklid).<br />

Nuklid = nuklid(wasserstoff, 1) ;<br />

Nuklid = nuklid(wasserstoff, 2)<br />

?- isotope(Leichteres,Schwereres).<br />

Leichteres = nuklid(wasserstoff, 1),<br />

Schwereres = nuklid(wasserstoff, 2) ;<br />

Leichteres = nuklid(wasserstoff, 1),<br />

Schwereres = nuklid(wasserstoff, 3)<br />

Aufgabe 8 Bevölkerungsdichte<br />

Dateiname: bevoelkerungsdichte.pl<br />

Die Unifikation (also das Gleichungslösen) in Prolog arbeitet mit rein formalen Ausdrücken.<br />

Dabei wird nichts mit Zahlen gerechnet. Probieren Sie das aus mit der Anfrage<br />

4


?- 2*3 = 1+5.<br />

Wenn man in Prolog mit Zahlen rechnen will, muss man explizit ein Prädikat verwenden, das<br />

arithmetische Terme mit Zahlen auswertet. Die folgenden Prädikate werten beide Seiten einer<br />

Gleichung oder Ungleichung aus: =:= (gleich), =\= (ungleich), < (kleiner als), > (größer als), =<<br />

(kleinergleich), >= (größergleich). is wertet nur die rechte Seite aus. Probieren Sie die Anfragen<br />

?- 2*3 =:= 1+4.<br />

?- 2*3 =:= 1+5.<br />

?- 2*3 =\= 1+4.<br />

?- 2*3 =\= 1+5.<br />

?- X is 1+5.<br />

?- 2*3 is 1+5.<br />

aus. Sie können auch kompliziertere Ausdrücke, auch mit **, sqrt, sin, cos, exp, log, usw.<br />

verwenden. Wenn Ihr primäres Interesse ist, einen arithmetischen Ausdruck auszuwerten (also<br />

auszurechnen, was heraukommt), dann verwenden Sie bitte das Prolog-Prädikat is !<br />

Hier ist eine Tabelle mit den geschätzten Einwohnerzahlen für das Jahr 2005 und den Flächen<br />

einiger Länder (aus Wikipedia):<br />

Land Einwohnerzahl Fläche [km 2 ]<br />

USA 301 140 000 9 629 091<br />

Russland 143 201 600 17 098 242<br />

V.R. China 1 323 324 000 9 596 961<br />

Kanada 33 390 141 9 970 610<br />

Australien 21 050 000 7 682 300<br />

Deutschland 82 689 210 357 022<br />

Österreich 8 189 444 83 858<br />

Schreiben Sie diese Angaben in Form eines Prologprogramms und definieren Sie dazu ein zweistelliges<br />

Prologprädikat bevoelkerungsdichte/2, sodass Sie z.B. die Bevölkerungsdichte von<br />

Österreich mit der Anfrage<br />

?- bevoelkerungsdichte(oesterreich,Bevoelkerungsdichte).<br />

erfragen können. Definieren Sie nun ein Prädikat dichtbevoelkert/1, das genau auf diejenigen<br />

Länder zutrifft, die eine Bevölkerungsdichte von mehr als 80 Einwohnern pro Quadratkilometer<br />

haben! Probieren Sie dieses Prädikat mit einer entsprechenden Anfrage aus!<br />

Aufgabe 9 EL · MAR = EDER<br />

Dateiname: elmareder.pl<br />

Lösen Sie das folgende Rätsel mit Prolog! In der Rechnung<br />

EL · MAR = EDER<br />

ist jeder Buchstabe durch eine Ziffer zu ersetzen – gleiche Buchstaben durch gleiche Ziffern und<br />

verschiedene Buchstaben durch verschiedene Ziffern – so, dass eine wahre Gleichung herauskommt.<br />

Keine der auftretenden Zahlen soll mit der Ziffer 0 anfangen. Z.B. ist A = 3, D = 8,<br />

E = 0, L = 6, M = 1, R = 4 als Lösung nicht erlaubt, obwohl 06 · 134 = 0804 ist, da 06 und<br />

0804 mit der 0 anfangen.<br />

5


Aufgabe 10 Komplexe Zahlen<br />

Dateiname: komplex.pl<br />

In der Mathematik, Physik und Technik werden oft komplexe Zahlen verwendet. Dabei wird<br />

√ −1 mit i (unter Technikern auch mit j) bezeichnet. Dann hat jede komplexe Zahl die Form<br />

A + Bi, wobei A und B reelle Zahlen sind (der Realteil bzw. der Imaginärteil der komplexen<br />

Zahl). In Prolog kann man eine solche komplexe Zahl darstellen als zusammengesetzten Term,<br />

also als Struktur komplex(A,B). Die Zahl 2 + 3i wird dann z.B. dargestellt durch die Struktur<br />

komplex(2,3). Schreiben Sie ein Prologprogramm zur Addition zweier komplexer Zahlen, zur<br />

Multiplikation zweier komplexer Zahlen und zur Berechnung des Betrags einer komplexen Zahl!<br />

Beispiele:<br />

Addition: (2 + 3i) + (10 + 20i) = 12 + 23i<br />

Multiplikation: (2 + 3i) · (10 + 20i) = −40 + 70i<br />

Betrag: |2 + 3i| ≈ 3, 60555<br />

Ihr Programm sollte sich also so verhalten:<br />

?- add(komplex(2,3),komplex(10,20),Summe).<br />

Summe = komplex(12, 23).<br />

?- mal(komplex(2,3),komplex(10,20),Produkt).<br />

Produkt = komplex(-40, 70).<br />

?- betrag(komplex(2,3),Betrag).<br />

Betrag = 3.60555.<br />

Aufgabe 11 Euklidischer Algorithmus<br />

Dateiname: ggT.pl<br />

Probieren Sie zunächst die folgende Anfrage zur Berechnung des Restes von 100 bei der Division<br />

durch 7 aus:<br />

?- X is 100 mod 7.<br />

Der Euklidische Algorithmus zur Berechnung des größten gemeinsamen Teilers (ggT) zweier<br />

natürlicher Zahlen beruht auf der folgenden Idee:<br />

Nehmen wir an, wir wollen z.B. ggT(18,42) berechnen. Jeder gemeinsame Teiler von 18 und<br />

42 muss auch Teiler von 42 − 18, also von 24 sein und damit gemeinsamer Teiler von 18 und<br />

24. Umgekehrt ist jeder gemeinsame Teiler von 18 und 24 auch gemeinsamer Teiler von 18<br />

und 42. Daher ist ggT(18, 42) = ggT(18, 24). Allgemein ist ggT(a, b) = ggT(a, b − a), wenn<br />

b die größere der beiden Zahlen ist. Man kann das gleiche Argument nun wiederholen und<br />

sagen, ggT(18, 24) = ggT(18, 24 − 18), also ggT(18, 24) = ggT(18, 6). Nun ist 18 die größere der<br />

beiden Zahlen und wir rechnen 18 − 6 = 12 und daher ggT(18, 6) = ggT(12, 6). Allgemein gilt<br />

ggT(a, b) = ggT(a − b, b), wenn a > b ist. Wenn man das so weiter führt, erhält man insgesamt<br />

6


die Rechnung<br />

ggT(18, 42) = ggT(18, 24)<br />

= ggT(18, 6)<br />

= ggT(12, 6)<br />

= ggT(6, 6)<br />

= 6.<br />

Das ganze kann man noch etwas effizienter machen, indem man etwa die beiden Substraktionen<br />

42-18=24 und 24-18=6 auf einmal durchführt mittels der Funktion mod (Rest einer<br />

Zahl modulo einer Zahl): 42 mod 18 = 6. Daher ist ggT(18, 42) = ggT(18, 6). Allgemein ist<br />

ggT(a, b) = ggT(a, b mod a). Das bringt uns natürlich nicht weiter, wenn b < a ist. Dann muss<br />

man mit ggT(a, b) = ggT(a mod b, b) vereinfachen. Zum Beispiel ist 18 mod 6 = 0. Also<br />

ggT(18, 42) = ggT(18, 6)<br />

= ggT(0, 6)<br />

= 6.<br />

Da jede Zahl ein Teiler der 0 ist, ist ggT(0, 6) = 6. Man kann sich die Abfrage, ob b < a ist,<br />

ersparen, wenn man die Argumente von ggT jedesmal vertauscht und die folgenden Gleichungen<br />

zur Vereinfachung verwendet:<br />

ggT(0, b) = b<br />

ggT(a, b) = ggT(b mod a, a), wenn a > 0.<br />

Schreiben Sie ein Prolog-Programm, das durch Rekursion den größten gemeinsamen Teiler zweier<br />

beliebiger natürlicher Zahlen mit Hilfe dieser beiden Gleichungen berechnen kann:<br />

?- ggT(18,42,T).<br />

T = 6<br />

Testen Sie Ihr Programm, indem Sie es mit dieser Anfrage und mit ähnlichen Anfragen laufen<br />

lassen! Tun Sie das bitte auch im Trace-Modus, z.B.<br />

?- trace, ggT(18,42,T).<br />

und beobachten Sie dabei die rekursiven Aufrufe von ggT, die Prolog dabei durchführt (Calls<br />

von ggT), und die Fakten über ggT, die Prolog dabei zurückliefert (Exits von ggT)!<br />

Aufgabe 12 Multiplikation natuerlicher Zahlen<br />

Dateiname: multiplikation_nat.pl<br />

Wir haben gesehen, dass man in Prolog natürliche Zahlen auch ohne den eingebauten Datentyp<br />

der Integers darstellen kann mittels einer Konstanten 0 und eines einstelligen Funktors n<br />

für die Nachfolgerfunktion. Man kann z.B. die 3 darstellen durch n(n(n(0))). In der Datei<br />

natuerliche_Zahlen.pl wird ein Prolog-Prädikat nat/1 definiert, das alle natürlichen Zahlen<br />

in dieser Darstellung erzeugen oder testen kann. Lassen Sie das Programm mit der dort angegebenen<br />

Anfrage laufen und fragen Sie Prolog mit „;“ nach immer weiteren Lösungen!<br />

Als nächstes schauen Sie sich die Datei addition_nat.pl an! Dort stehen in einem Kommentar<br />

die beiden Rekursionsgleichungen, mit denen man in der Mathematik die Addition zweier natürlichen<br />

Zahlen definiert. Schauen Sie sich genau an, wie ich diese Gleichungen dann als zwei<br />

7


Prolog-Klauseln umformuliert habe! Lassen Sie das Programm dann laufen mit den in der Datei<br />

angegebenen Anfragen, wobei Sie Prolog ggf. mit „;“ nach weiteren Antworten fragen! Verfolgen<br />

Sie auch mit trace, wie Prolog die Anfragen löst! Sie sehen, dass dieses extrem kurze Programm<br />

sehr vielseitig verwendbar ist. Achtung! Prolog antwortet nicht immer so, wie man vielleicht<br />

zunächst erwarten würde. Warum?<br />

Für die Multiplikation zweier natürlicher Zahlen gibt es, ebenso wie für die Addition, zwei Rekursionsgleichungen:<br />

A · 0 = 0<br />

A · n(B) = A · B + A<br />

Erstellen Sie eine neue Datei multiplikation_nat.pl und kopieren Sie in diese Datei zunächst<br />

die beiden Klauseln der Datei addition_nat.pl! Formulieren Sie nun die beiden Rekursionsgleichungen<br />

für die Multiplikation um als zwei Prolog-Klauseln zur Definition eines Prolog-Prädikats<br />

mul/3 ähnlich, wie ich das zuvor für die Addition gemacht hatte. Verwenden Sie dabei das<br />

Prädikat add/3! Ihr Programm sollte also jetzt vier Klauseln enthalten: die zwei Klauseln aus<br />

addition_nat.pl, die das Prädikat add/3 definieren, und zwei Klauseln, die das Prädikat mul/3<br />

definieren. Auf die Anfrage<br />

?- mul(n(n(0)), n(n(n(0))), Produkt).<br />

sollte Prolog jetzt<br />

Produkt = n(n(n(n(n(n(0))))))<br />

antworten, da 2 · 3 = 6 ist.<br />

Aufgabe 13 Quadratzahlen<br />

Dateiname: quadratzahl.pl<br />

Schreiben Sie ein Prologprogramm, das ein Prädikat quadratzahl/1 definiert, das alle Quadratzahlen<br />

aufzählt:<br />

?- quadratzahl(Q).<br />

Q = 0 ;<br />

Q = 1 ;<br />

Q = 4 ;<br />

Q = 9 ;<br />

Q = 16 ;<br />

Q = 25 ;<br />

Q = 36 ;<br />

Q = 49<br />

Die Menge der Quadratzahlen wird von diesem Programm zusammen mit der Anfrage aufgezählt.<br />

Wir sagen, die Menge der Quadratzahlen ist rekursiv aufzählbar. Das Wort „rekursiv“ in<br />

„rekursiv aufzählbar“ bezieht sich darauf, dass eine Aufzählung der Quadratzahlen durch Rekursion<br />

möglich ist. Prolog basiert ja auf Rekursion. Schauen Sie sich Ihr Programm daraufhin an,<br />

an welcher Stelle oder an welchen Stellen darin eine Rekursion auftritt.<br />

Aufgabe 14 Translation und Rotation von geometrischen Objekten<br />

Dateiname: a14_Bewegung.pl<br />

8


In einem Geometrie-Software-System werden die folgenden Arten von geometrischen Objekten<br />

der Ebene als Prologterme dargestellt:<br />

Punkt (X,Y)<br />

als Prologterm punkt(X,Y).<br />

Beispiel: punkt(3,5).<br />

Strecke AB, wobei A und B Punkte sind<br />

als Prologterm strecke(A,B).<br />

Beispiel: strecke(punkt(3,5),punkt(2,1)).<br />

Dreieck ABC<br />

als Prologterm dreieck(A,B,C).<br />

Beispiel: dreieck(punkt(3,5),punkt(2,1),punkt(-1,4)).<br />

Kreis mit Mittelpunkt M und Radius R<br />

als Prologterm kreis(M,R).<br />

Beispiel: kreis(punkt(3,5),2).<br />

Weiter stellt das Geometrie-Software-System dar:<br />

Vektor (F,G)<br />

als Prologterm vektor(F,G).<br />

Beispiel: vektor(2,1).<br />

sowie die folgenden Arten von Transformationen (Bewegungen):<br />

Translation (Verschiebung) um einen Vektor V<br />

als Prologterm translation(V).<br />

Beispiel: translation(vektor(2,1)).<br />

Rotation (Drehung) um einen Drehpunkt D herum und um einen Drehwinkel Phi (Radians und<br />

entgegen dem Uhrzeigersinn)<br />

als Prologterm rotation(D,Phi).<br />

Beispiel: rotation(punkt(3,5),3.14159).<br />

Definieren Sie ein Prologprädikat transformiere/3 zum Transformieren (Verschieben, Drehen)<br />

von Objekten mit der Spezifikation<br />

% transformatiere(+Objekt,+Transformation,-Objekt_neu) bedeutet:<br />

% Objekt_neu ergibt sich durch Anwendung von Transformation auf Objekt.<br />

Hier ist ein Beispiel für eine mögliche Anfrage und Antwort von Prolog:<br />

?- A = punkt(1,3), B = punkt(4,4), AB = strecke(A,B), D = punkt(2,1),<br />

Pi_halbe is 3.14159265/2, Rot = rotation(D,Pi_halbe),<br />

transformiere(AB,Rot,Strecke_neu).<br />

A = punkt(1, 3),<br />

B = punkt(4, 4),<br />

AB = strecke(punkt(1, 3), punkt(4, 4)),<br />

D = punkt(2, 1),<br />

Pi_halbe = 1.570796325,<br />

Rot = rotation(punkt(2, 1), 1.570796325),<br />

Strecke_neu = strecke(punkt(-1.794896453688466e-9, 3.5897930298375673e-9),<br />

punkt(-0.9999999964102071, 3.0000000053846896)).<br />

In der Anfrage wurden zunächst zwei Punkte A = (1, 3) und B = (4, 4) spezifiziert, dann die<br />

9


Strecke AB und der Punkt D = (2, 1), dann die Zahl π/2 ausgerechnet sowie die Transformation<br />

Rot= „Vierteldrehung gegen den Uhrzeigersinn um den Drehpunkt D herum“ spezifiziert.<br />

Schließlich wurde das Prädikat transformiere/3 aufgerufen, um diese Transformation auf die<br />

gegebene Strecke anzuwenden. Das Ergebnis der Transformation ist eine neue Strecke vom Punkt<br />

(0, 0) zum Punkt (−1, 3). Da ich π nur näherungsweise angegeben habe und auch beim Rechnen<br />

durch Prolog kleine Rundungsfehler auftreten, ist die Ausgabe von Prolog auch nur näherungsweise.<br />

In SWI-Prolog (aber nicht in allen Prologs) kann man statt 3.14159265 auch einfach pi<br />

schreiben.<br />

Aufgabe 15 Strukturbäume<br />

Dateiname: a15_Strukturbaeume.pdf<br />

Lassen Sie sich von jedem der folgenden Terme mit write_canonical die kanonische Form<br />

anzeigen! Zeichnen Sie dann den Strukturbaum für den betreffenden Term! Fassen Sie all diese<br />

Strukturbäume in einer Datei a15_Strukturbaeume.pdf zusammen!<br />

a<br />

f(g(a,h(b,c),a),h(c,a))<br />

f(X,g(Y,X),a)<br />

3*sin(2*x)-2*cos(3*x)+X<br />

C is sqrt(A**2+B**2)<br />

[1,2,3,4]<br />

[1,2,3|4]<br />

[[a1,a2,a3],[b1,b2],[c1,c2]]<br />

[]<br />

[a]<br />

[[a]]<br />

Vektor = [3,4,8]<br />

Aufgabe 16 dag<br />

Dateiname: a16_dag.pdf<br />

Lassen Sie das Programm a16_dag.pl mit den darin als Kommentare angegebenen Anfragen<br />

laufen! Beantworten Sie die folgenden Fragen und schreiben Sie Ihre Antworten in eine Datei<br />

a16_dag.pdf!<br />

1. Wieviele a’s enthält der Term, den Prolog bei der Anfrage ?- p(0,T). für T ausgibt?<br />

2. Wieviele a’s enthält der Term, den Prolog bei der Anfrage ?- p(1,T). für T ausgibt?<br />

3. Wieviele a’s enthält der Term, den Prolog bei der Anfrage ?- p(2,T). für T ausgibt?<br />

4. Wieviele a’s enthält der Term, den Prolog bei der Anfrage ?- p(3,T). für T ausgibt?<br />

5. Allgemein: Sei n eine natürliche Zahl. Wieviele a’s enthält der Term, den Prolog bei der<br />

Anfrage ?- p(n,T). für T ausgibt?<br />

6. Wieviele a’s enthält der Term, den Prolog bei der Anfrage ?- p(1000,T). für T ausgibt?<br />

7. Was sagt das über die interne Darstellung des Terms im Computer aus?<br />

Aufgabe 17 Buchstabieren<br />

Dateiname: a17_buchstabieren.pl<br />

Beim Buchstabieren verwendet man zwecks Vermeidung von Missverständnissen gerne eine Buchstabiertafel,<br />

die jedem Buchstaben ein Wort zuordnet. Hier ist ein Ausschnitt aus einer solchen<br />

Buchstabiertafel:<br />

10


a Anton<br />

b Berta<br />

c Caesar<br />

d Dora<br />

e Emil<br />

f Friedrich<br />

Wenn man nun ein Wort buchstabieren will, sucht man jeden Buchstaben dieses Wortes in der<br />

linken Spalte dieser Tabelle und wandelt ihn in das entsprechende Wort der rechten Spalte der<br />

Tabelle um. Aus dem Wort „Affe“ wird so z.B. „Anton Friedrich Friedrich Emil“.<br />

Für ein Prolog-Programm zum Buchstabieren stellen wir jeden Buchstaben der linken Spalte<br />

der Tabelle dar als ein Prologatom, das nur aus einem Kleinbuchstaben besteht, z.B. a. Jedes<br />

Wort der rechten Spalte der Tabelle stellen wir ebenfalls als Prologatom dar, das aber mit<br />

einem Großbuchstaben beginnt. Wir müssen es daher zwischen einfache Anführungszeichen setzen,<br />

z.B. ’Anton’. Das zu buchstabierende Wort (z.B. „Affe“) stellen wir in Prolog als Liste von<br />

Kleinbuchstaben dar, z.B. [a,f,f,e]. Das Ergebnis des Buchstabierens stellen wir in Prolog<br />

als Liste von Atomen dar. So soll z.B. die Liste [a,f,f,e] umgewandelt werden in die Liste<br />

[’Anton’,’Friedrich’,’Friedrich’,’Emil’] und umgekehrt. Der Einfachheit halber beschränken<br />

wir uns dabei auf die Kleinbuchstaben a, b, c, d, e und f und auf die oben abgebildete<br />

Buchstabiertafel.<br />

Schreiben Sie nun ein Prolog-Programm, das diese Aufgabe löst, indem Sie ein Prolog-Prädikat<br />

buchstabiere/2 definieren, sodass z.B.<br />

buchstabiere([a,f,f,e],[’Anton’,’Friedrich’,’Friedrich’,’Emil’])<br />

gilt! Testen Sie Ihr Programm auch mit Anfragen wie<br />

?- buchstabiere([a,f,f,e],Woerterliste).<br />

?- buchstabiere(Buchstabenliste,[’Anton’,’Friedrich’,’Friedrich’,’Emil’]).<br />

Aufgabe 18 Bitlisten<br />

Dateiname: a18_bitliste.pdf<br />

In heutigen digitalen Computern werden Informationen als endliche Folgen von Bits 0 oder 1<br />

dargestellt. Eine solche Folge kann man in Prolog darstellen als Bitliste, also als Liste von Bits<br />

0 oder 1, z.B. [1,1,0,1]. Wir wollen uns überzeugen, dass die Menge aller Bitlisten rekursiv<br />

aufzählbar ist. Dazu schreiben wir ein Prologprogramm und dazu eine Anfrage, die die Menge<br />

aller Bitlisten aufzählen soll. In der Datei a18_bitliste.pl steht ein solches Programm und<br />

einige Anfragen dazu. Lassen Sie das Programm mit jeder der vier Anfragen laufen, wobei Sie<br />

sich jeweils mit Strichpunkt nacheinander Antworten ausgeben lassen! Beantworten Sie dann die<br />

folgenden Fragen:<br />

1. Zwei der dort definierten Prädikate sind zueinander logisch äquivalent. Welche Prädikate<br />

sind das? Geben Sie sie in der Form „Prädikatsname/Stelligkeit“ an!<br />

2. Welche der Anfragen 1) bis 4) zählen die Menge aller Bitlisten auf?<br />

3. Warum zählen diese Anfragen die Menge auf und warum tun die anderen Anfragen es<br />

nicht?<br />

4. Worin unterscheidet sich das Antwortverhalten der vier Anfragen und warum?<br />

Aufgabe 19 Teillisten<br />

Dateiname: a19_teilliste.pl<br />

11


Unter einer Teilliste einer Liste L wollen wir eine Liste T verstehen, die sich dadurch ergibt,<br />

dass man aus L null oder mehr Elemente auswählt und daraus eine Liste bildet, in der die<br />

Reihenfolge der ausgewählten Elemente gleich wie in L ist. So ist z.B. [s,b,g] eine Teilliste der<br />

Liste [s,a,l,z,b,u,r,g]. Definieren Sie ein Prädikat teilliste/2, sodass Prolog z.B. auf die<br />

Anfrage<br />

?- teilliste(T,[s,a,l,z,b,u,r,g]).<br />

bei wiederholter Eingabe des Strichpunkts für T alle 256 Teillisten der Liste [s,a,l,z,b,u,r,g]<br />

liefert! Eine der Antworten lautet dann T=[s,b,g].<br />

Lassen Sie sich mit dem in Prolog eingebauten Prädikat findall/3 durch die Anfrage<br />

?- findall(T, teilliste(T,[a,b]), Teillisten).<br />

die Liste aller Teillisten T der Liste [a,b] ausgeben! Was Prolog dabei macht, ist, dass es für jede<br />

Lösung des Ziels teilliste(T,[a,b]) den entsprechenden Wert von T in eine Liste aufnimmt<br />

und die Variable Teillisten dann mit der resultierenden Liste unifiziert. Lassen Sie sich nun<br />

die Anzahl der Teillisten der Liste [s,a,l,z,b,u,r,g] mit der Anfrage<br />

?- findall(T, teilliste(T,[s,a,l,z,b,u,r,g]), Teillisten),<br />

length(Teillisten, Anzahl_der_Teillisten).<br />

ausgeben! Das Prädikat length/2 zur Berechnung der Länge einer Liste ist in vielen Prologs<br />

eingebaut. Man kann es wie in der Datei listenlaenge.pl gezeigt aber auch leicht selbst definieren.<br />

Die Teillisten der Liste [s,a,l,z,b,u,r,g] entsprechen genau den Teilmengen der<br />

Menge {s, a, l, z, b, u, r, g}. Davon gibt es 2 8 = 256.<br />

Aufgabe 20 Cliquen-Problem 2<br />

Dateiname: a20_clique2.pl<br />

Lesen Sie sich nochmals die Angabe von Aufgabe 5 (Cliquen-Problem) durch! Man kann die<br />

Situation durch einen ungerichteten Graphen darstellen (Datei clique.ps). Eine Clique ist dann<br />

eine Menge von Knoten des Graphen, von denen jeder mit jedem anderen verbunden ist. In<br />

unserem Beispiel ist {franz, berta, dora} eine Clique, da jeder darin genannte Knoten mit jedem<br />

anderen verbunden ist. Eine solche Menge kann man in Prolog als Liste darstellen, etwa als Liste<br />

[franz,berta,dora]. Definieren Sie nun ein Prädikat clique/1, das von einer solchen Liste<br />

testen kann, ob sie eine Clique darstellt. Z.B. sollte die Anfrage<br />

?- clique([franz,berta,dora]).<br />

die Antwort yes oder true liefern. Die Anfrage<br />

?- clique([berta,dora,franz]).<br />

sollte die gleiche Antwort liefern. Alle Cliquen aus mehr als einer Person haben also mehrere<br />

Darstellungen als Liste. Verwenden Sie nun das Prädikat der vorigen Aufgabe und stellen Sie die<br />

Anfrage<br />

?- teilliste(Clique, [anton,berta,christa,dora,ernst,franz]),<br />

clique(Clique).<br />

12


Warum liefert Prolog nun jede Clique nur einmal als Antwort? Schreiben Sie Ihre Antwort auf<br />

diese Frage als Kommentar ans Ende Ihrer Programmdatei! Hier erzeugen (englisch: generate)<br />

wir uns nacheinander alle Teillisten der gegebenen Liste. Von jeder Teilliste testen wir dabei, ob<br />

sie eine Clique darstellt. Man nennt dieses Verfahren „generate and test“. Es wird in der logischen<br />

<strong>Programmierung</strong> häufig verwendet.<br />

Aufgabe 21 Arithmetische Ausdrücke auswerten<br />

Dateiname: a21_ausdruck.pl<br />

Wir betrachten alle arithmetischen Ausdrücke, die man aus Zahlen und dem Buchstaben x mittels<br />

der Zeichen +, -, *, / für die vier Grundrechenarten sowie mittels Klammern ( und ) bilden<br />

kann. Ein Beispiel für einen solchen Ausdruck ist x*x+2*x-7. Definieren Sie ein Prolog-Prädikat<br />

wert/3 mit dem Aufrufmodus wert(+Ausdruck,+Zahl,?Zahl) zur Berechnung des Wertes des<br />

Ausdrucks zu einem gegebenen x-Wert! Beispiel:<br />

?- wert(x*x+2*x-7, 5, W).<br />

W = 28.<br />

berechnet den Wert W des Ausdrucks x*x+2*x-7 für x=5, also W = 5 · 5 + 2 · 5 − 7 = 28. Die<br />

Antwort für W sollte die gleiche sein wie bei der Anfrage<br />

?- X = 5, W is X*X+2*X-7.<br />

Nur, dass oben die Mathematikvariable x dargestellt ist als Prolog-Atom x, während sie darunter<br />

dargestellt ist als Prolog-Variable X.<br />

Testen Sie Ihr Programm mit verschiedenen – auch geklammerten und komplizierter geschachtelten<br />

– Ausdrücken und mit verschiedenen x-Werten!<br />

Aufgabe 22 Wertetabelle<br />

Dateiname: a22_wertetabelle.pl<br />

Definieren Sie als Ergänzung zur vorigen Aufgabe ein Prolog-Prädikat tabelle/3 mit dem Aufrufmodus<br />

tabelle(+Ausdruck,+ganzeZahl,+ganzeZahl), sodass für einen arithmetischen Ausdruck<br />

A wie in der vorigen Aufgabe sowie für zwei ganze Zahlen m und n mit m ≤ n ein Aufruf<br />

des Ziels tabelle(A,m,n) bewirkt, dass eine Wertetabelle für den Ausdruck A und alle ganzen<br />

Zahlen x mit m ≤ x ≤ n ausgegeben wird. Die erste Zeile der Tabelle soll das Zeichen x gefolgt<br />

von einem Leerzeichen und vom Ausdruck A enthalten, die zweite Zeile soll nur 8 Minuszeichen<br />

enthalten. Danach soll nacheinander für jedes x von m bis n eine Zeile kommen, in der zuerst<br />

der Wert von x steht, dann ein Leerzeichen, dann der Wert von A für diesen x-Wert. Beispiel:<br />

?- tabelle(x*x+2*x-7, 3, 6).<br />

x x*x+2*x-7<br />

--------<br />

3 8<br />

4 17<br />

5 28<br />

6 41<br />

Verwenden Sie in Ihrem Programm das Prädikat wert/3 aus der vorigen Aufgabe! Konsultieren<br />

Sie beim Testen beide Dateien, etwa mit<br />

13


?- [a21_ausdruck, a22_wertetabelle].<br />

Aufgabe 23 Plus-Minus-Terme<br />

Dateiname: a23_plusminus.pl<br />

In dieser Aufgabe betrachten wir Ausdrücke, die aus Zahlen mit Hilfe von + und − und Klammern<br />

gebildet sind, z.B. den Ausdruck 8 − (2 + 3). Die übliche Darstellung eines solchen Ausdrucks,<br />

z.B. 8-(2+3) stellt zugleich einen Term in Prolog dar. Wir wollen einen solchen Term einen Plus-<br />

Minus-Term nennen. Wir wollen aber noch eine alternative Darstellung eines solchen Ausdrucks<br />

als Prologterm betrachten. Dazu definieren wir induktiv den Begriff „add-sub-Term“. add-sub-<br />

Terme sind spezielle Prologterme. Hier die induktive Definition:<br />

1. Für jede Zahl z ist der Prologterm zahl(z) ein add-sub-Term.<br />

2. Wenn t1 und t2 zwei add-sub-Terme sind, dann sind auch add(t1,t2) und sub(t1,t2) addsub-Terme.<br />

Jeder Plus-Minus-Term hat auch eine Darstellung als add-sub-Term und umgekehrt. Z.B. entspricht<br />

dem Plus-Minus-Term 8-(2+3) der add-sub-Term sub(zahl(8),add(zahl(2),zahl(3))).<br />

Stellen wir uns nun vor, wir haben bereits ein Programm, das mit dieser Darstellung arbeitet,<br />

aber auch ein von jemand anderem geschriebenes Programm mit ähnlicher Darstellung, nur dass<br />

die Funktoren anders benannt sind: sum statt add, dif statt sub und num statt zahl. Analog wie<br />

oben definieren wir: sum-dif-Terme sind spezielle Prologterme. Hier die induktive Definition:<br />

1. Für jede Zahl z ist der Prologterm num(z) ein sum-dif-Term.<br />

2. Wenn t1 und t2 zwei sum-dif-Terme sind, dann sind auch sum(t1,t2) und dif(t1,t2) sumdif-Terme.<br />

Jeder Plus-Minus-Term hat auch eine Darstellung als sum-dif-Term und umgekehrt. Z.B. entspricht<br />

dem Plus-Minus-Term 8-(2+3) der sum-dif-Term dif(num(8),sum(num(2),num(3))).<br />

Wir wollen beide Programme in einem größeren Softwaresystem verwenden und benötigen daher<br />

Prädikate zur Übersetzung von einer Darstellung in die andere. Definieren Sie dazu<br />

1. ein Prologprädikat addsub_sumdif/2 zur Übersetzung eines add-sub-Terms in einen sumdif-Term<br />

und umgekehrt! Z.B. sollte gelten<br />

addsub_sumdif(sub(zahl(8),add(zahl(2),zahl(3))),<br />

dif(num(8),sum(num(2),num(3))))<br />

2. ein Prologprädikat addsub_plusminus/2 zur Übersetzung eines add-sub-Terms in einen<br />

Plus-Minus-Term! Beispiel:<br />

?- addsub_plusminus(sub(zahl(8),add(zahl(2),zahl(3))), Plusminusterm).<br />

Plusminusterm = 8-(2+3)<br />

3. ein Prologprädikat plusminus_addsub/2 zur Übersetzung eines Plus-Minus-Terms in einen<br />

add-sub-Term! Beispiel:<br />

?- plusminus_addsub(8-(2+3), Addsubterm).<br />

Addsubterm = sub(zahl(8),add(zahl(2),zahl(3)))<br />

Hinweis: Schauen Sie sich die Dokumentation des Prolog-Prädikats number/1 an! Probieren<br />

Sie es auch aus mit Anfragen wie<br />

?- number(5).<br />

?- number(2+3).<br />

14


4. ein Prologprädikat addsub_Wert/2 zur Berechnung des Wertes eines add-sub-Terms als<br />

Zahl! Beispiel:<br />

?- addsub_Wert(sub(zahl(8),add(zahl(2),zahl(3))), Wert).<br />

Wert = 3<br />

Denn 8 − (2 + 3) = 3.<br />

Aufgabe 24 Unifikation<br />

Dateiname: a24_unifikation<br />

Zur Erinnerung: Unifikationsalgorithmus von Robinson:<br />

Vorab die Definition eines Hilfsbegriffs:<br />

Seien s und t zwei verschiedene Terme 1 . Die Nichtübereinstimmungsmenge (engl. disagreement<br />

set) D von s und t ist die Menge, die besteht aus den beiden Teiltermen von s und t, die an der<br />

ersten Stelle, an der sich s und t unterscheiden 2 , anfangen.<br />

Beispiel: Die Nichtübereinstimmungsmenge der Terme f(X,g(X)) und f(g(a),Y) ist die Menge<br />

{X, g(a)}.<br />

Um die Terme s und t zu unifizieren, müssen wir zumindest die Nichtübereinstimmung eliminieren,<br />

also zunächst die Terme der Nichtübereinstimmungsmenge miteinander unifizieren.<br />

Allgemein gilt: Die Nichtübereinstimmungsmenge D hat eine der folgenden beiden Formen:<br />

• {X, r} mit einer Variablen X und einem von X verschiedenen Term r. Dann gilt: Wenn X<br />

in r nicht vorkommt, dann ist {X ← r} ein mgu von D. Wenn X in r vorkommt, ist D<br />

nicht unifizierbar.<br />

• {f(s1, . . . , sm), g(t1, . . . , tn)} mit zwei voneinander verschiedenen Funktoren f/m und g/n. 3<br />

In diesem Fall ist D nicht unifizierbar.<br />

Nun zum Unfikationsalgorithmus. Wir wollen für zwei Terme s und t einen allgemeinsten Unifikator<br />

(mgu) berechnen. Der Ablauf soll hier nur informell am Beispiel der Terme<br />

f(X,g(X))<br />

f(g(a),Y)<br />

demonstriert werden. Wir bestimmen die Nichtübereinstimmungsmenge {X, g(a)} der beiden<br />

Terme und davon wie oben gezeigt einen mgu<br />

{X


{Y


Die Aufgabe:<br />

Wenden Sie nun den oben beschriebenen Unifikationsalgorithmus an, um jeweils die folgenden<br />

Terme miteinander zu unifizieren:<br />

a○ f(a,b) mit f(X,c)<br />

b○ f(g(X,Y),X) mit f(U,h(Y))<br />

c○ f(g(X,Y),X) mit f(U,h(Y,U))<br />

Schreiben Sie den Ablauf des Algorithmus in eine Datei a24_unifikation:<br />

Aufgabe 24a:<br />

...<br />

Aufgabe 24b:<br />

...<br />

Aufgabe 24c:<br />

...<br />

wobei Sie jeweils für „...“ die schematische Darstellung des Ablaufs des Algorithmus wie oben<br />

beschrieben einsetzen!<br />

Aufgabe 25 SLD-Baum nat<br />

Dateiname: a25_sldBaum.pdf<br />

Gegeben sei das Prologprogramm<br />

nat(0).<br />

nat(f(X)) :- nat(X).<br />

mit der Anfrage<br />

?- nat(f(f(0))).<br />

1. Zeichnen Sie dazu eine SLD-Widerlegung als Baum. Führen Sie dabei jedesmal, wenn Sie<br />

eine Programmklausel verwenden, neue Variablen ein.<br />

2. Schreiben Sie bei Ihrem Baum neben jeden Resolutionsschritt den jeweiligen allgemeinsten<br />

Unifikator.<br />

3. Bilden Sie die Komposition der allgemeinsten Unifikatoren aller Resolutionsschritte.<br />

4. Bestimmen Sie daraus die berechnete Antwortsubstitution.<br />

Aufgabe 26 Grammatik<br />

Dateinamen: a26_mannisstapfel.pdf und a26_saftigenapfel.pl<br />

Über Grammatiken<br />

17


Die folgende Aufgabe befasst sich mit dem Problem der Syntaxanalyse (englisch: parsing). Dabei<br />

geht es darum, Sätze in einer natürlichen Sprache (z.B. in Deutsch oder Englisch) oder Ausdrücke<br />

in einer formalen Sprache (z.B. in einer Programmiersprache geschriebene Programme)<br />

zu analysieren, d.h. in ihre Bestandteile zu zerlegen. Hierzu hat der Sprachwissenschaftler und<br />

Informatiker Noam Chomsky seine Grammatiken eingeführt. Insbesondere von Interesse sind hier<br />

die sogenannten kontextfreien Chomsky-Grammatiken.<br />

Nehmen wir hierzu als Beispiel (aus dem Buch „Programming in Prolog“ von Clocksin und<br />

Mellish) den Satz<br />

Der Mann isst den Apfel.<br />

Dieser Satz besteht aus zwei Teilen, und zwar aus einer Nominalphrase „der Mann“ und aus<br />

einer Verbalphrase „isst den Apfel“. Ein Satz kann also bestehen aus einer Nominalphase gefolgt<br />

von einer Verbalphrase. Wir schreiben das als Grammatikregel<br />

satz --> nominalphrase, verbalphrase.<br />

Die Nominalphrase „der Mann“ wiederum besteht aus einem Artikel „der“ und einem Nomen<br />

„Mann“ gemäß der Grammatikregel<br />

nominalphrase --> artikel, nomen.<br />

Die Verbalphrase „isst den Apfel“ besteht aus dem Verb „isst“ und der Nominalphrase „den<br />

Apfel“ gemäß der Grammatikregel<br />

verbalphrase --> verb, nominalphrase.<br />

Die Nominalphrase „den Apfel“ besteht aus dem Artikel „den“ und dem Nomen „Apfel“ gemäß<br />

der oben bereits erwähnten Grammatikregel<br />

nominalphrase --> artikel, nomen.<br />

Auch für die Vokabeln verwenden wir Grammatikregeln. Z.B. schreiben wir<br />

nomen --> [apfel].<br />

Die eckigen Klammern dienen der Unterscheidung zwischen grammatikalischen Begriffen wie<br />

satz, nominalphrase, verbalphrase usw. und Vokabeln wie der, mann, apfel usw. Insgesamt<br />

haben wir die folgende kontextfreie Chomsky-Grammatik (Datei mannisstapfel_gr.pl).<br />

satz --> nominalphrase, verbalphrase.<br />

nominalphrase --> artikel, nomen.<br />

verbalphrase --> verb, nominalphrase.<br />

artikel --> [der].<br />

artikel --> [den].<br />

nomen --> [mann].<br />

nomen --> [apfel].<br />

verb --> [isst].<br />

18


Die grammatikalische Struktur des Satzes „der mann isst den apfel“ lässt sich am anschaulichsten<br />

graphisch als Zerlegungsbaum (englisch: parse tree) darstellen:<br />

satz<br />

nominalphrase verbalphrase<br />

artikel nomen verb nominalphrase<br />

artikel nomen<br />

[der] [mann] [isst] [den] [apfel]<br />

Ein häufig auftretendes Problem ist, ein Programm zu schreiben, das Sätze wie „Der Mann isst<br />

den Apfel.“ analysieren kann, z.B. um automatisch sinnvoll darauf reagieren zu können. Ein<br />

naheliegender erster Schritt ist, den Satz in seine Wörter zu zerlegen. In Prolog würden wir dann<br />

etwa eine Liste<br />

[der,mann,isst,den,apfel]<br />

von Prolog-Atomen erhalten. Dieser erste Schritt ist relativ einfach und soll hier nicht weiter<br />

untersucht werden. Interessanter ist die Zerlegung dieser Liste in ihre Bestandteile (Phrasen).<br />

Ein Computerprogramm, das eine solche Zerlegung (englisch: parsing) durchführt, wird Parser<br />

genannt.<br />

Eine häufig verwendete Vorgangsweise beim Parsing ist die folgende. Wir wollen einen Satz (im<br />

Beispiel [der,mann,isst,den,apfel]) lesen und analysieren. Wir lesen ein Wort nach dem<br />

anderen. Zu jedem Zeitpunkt betrachten wir den noch nicht gelesenen Endteil der Liste. Dieser<br />

Endteil ist anfänglich die gesamte Liste [der,mann,isst,den,apfel] und nach vollständigem<br />

Lesen der Liste die leere Liste [].<br />

Wir wissen, dass ein Satz aus einer Nominalphrase und einer Verbalphrase besteht. Im Beispiel ist<br />

der nach Lesen der Nominalphrase [der,mann] übrig bleibende Endteil die Liste [isst,den,apfel].<br />

Wir wollen das in Prolog so schreiben:<br />

nominalphrase([der,mann,isst,den,apfel],[isst,den,apfel])<br />

Allgemein soll das zweistellige Prologprädikat nominalphrase/2 die folgende Bedeutung haben.<br />

nominalphrase(S0,S) soll genau dann gelten, wenn die Liste S0 mit einer Nominalphrase<br />

anfängt und der restliche Teil der Liste die Liste S ist.<br />

Sinngemäß analog soll die Bedeutung der Prädikate satz/2, verbalphrase/2, usw. sein.<br />

Wie müssen wir diese Prädikate in Prolog definieren? Betrachten wir dazu eine Liste S0 von<br />

Wörtern. Aufgrund unserer Grammatikregel<br />

satz --> nominalphrase, verbalphrase.<br />

19


esteht ein Satz aus einer Nominalphrase und einer Verbalphrase. Um einen Satz von der Liste<br />

S0 wegzulesen, lesen wir also zunächst eine Nominalphrase. Sei S1 der übrigbleibende Endteil der<br />

Liste S0, also nominalphrase(S0,S1). Von diesem Endteil lesen wir nun noch eine Verbalphrase<br />

weg und erhalten einen neuen Endteil S. Also verbalphrase(S1,S). Insgesamt haben wir von<br />

der ursprünglichen Liste S0 einen Satz weggelesen und der neue Endteil war S. Also satz(S0,S).<br />

Insgesamt lässt sich daher unsere Grammatikregel übersetzen in die Prologklausel<br />

satz(S0,S) :- nominalphrase(S0,S1), verbalphrase(S1,S).<br />

Zum Beispiel gilt<br />

nominalphrase([der,mann,isst,den,apfel],[isst,den,apfel]) und<br />

verbalphrase([isst,den,apfel],[]) und daher<br />

satz([der,mann,isst,den,apfel],[]).<br />

Die Aufgabe:<br />

Schauen Sie sich das Programm mannisstapfel.pl an. Erklären Sie die Klauseln für artikel/2,<br />

nomen/2 und verb/2. Stellen Sie Anfragen wie<br />

?- satz([der,mann,isst,den,apfel],[]).<br />

?- satz([der,mann,isst,den,apfel,x,y,z],S).<br />

?- satz(S,[]).<br />

?- satz(S,[x,y,z]).<br />

?- satz([mann,apfel,isst],[]).<br />

Erklären Sie, was dabei passiert. Nun starten Sie SWI-Prolog mit der Grammatik mannisstapfel_gr.pl<br />

als Prolog-Programm. Lassen Sie sich das Programm mit der Anfrage<br />

?- listing.<br />

auflisten. Was hat Prolog aus der Grammatik gemacht? Praktisch alle Prologs haben Unterstützung<br />

für Grammatikregeln eingebaut und statt einer Anfrage<br />

?- satz(S,[]).<br />

kann man die etwas benutzerfreundlichere Anfrage<br />

?- phrase(satz,S).<br />

stellen. Das kann man lesen als: S ist ein Satz. Statt satz kann man natürlich auch nominalphrase,<br />

verbalphrase, usw. verwenden. Probieren Sie das mit verschiedenen Anfragen aus.<br />

Warum liefert das Programm auch Antworten, die gemäß der deutschen Grammatik grammatikalisch<br />

falsch sind? Wie könnte man es verbessern? Fügen Sie weitere Klauseln hinzu, damit<br />

Sätze wie „Der Mann singt“ und „Der Mann isst den saftigen Apfel“ als grammatikalisch richtig<br />

erkannt werden.<br />

20

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!