Hausaufgaben Logische Programmierung

Hausaufgaben Logische Programmierung
Elmar Eder
9. Juni 2016
Die Aufgaben sind auf dem Abgabesystem von Dominik Kaaser unter der Internetadresse https://prolog.cosy.sbg.ac.at/ bis zu dem dort angegebenen Termin abzugeben. Bitte alle Programme/Texte mit Return- oder Entertaste beenden!
Alle Aufgaben, bei denen nichts gegenteiliges vermerkt ist, sind selbständig in Teams
von zwei Studenten zu lösen. Am Anfang der von Ihnen fertiggestellten Lösung der Aufgabe müssen die Namen (Familienname Vorname) aller beteiligter Studenten angeführt
sein, im Fall eines Prolog-Programms als Kommentar (mit Prozentzeichen am Anfang
der Zeile). Einigen Sie sich bitte mit Ihrem Teampartner, wer von Ihnen die Datei auf
dem Abgabesystem abgibt!
Wenn bei einer Aufgabe ein Prolog-Programm und dazu ein oder mehr Anfragen an
Prolog zu erstellen sind, dann schreiben Sie bitte die Anfragen in einem Kommentar ans
Ende der Datei, etwa so:
% ?- vater(X,hans).
% ?- tochter(X,anna), tochter(Y,anna), aelter(X,Y).
Alle Programme sind vorher zu testen. Sie müssen unter Prolog lauffähig sein.
Als Dateinamen für Prolog-Programme wählen Sie – soweit nicht anders angegeben –
hN N .pl, wobei N N die zweistellige Nummer der Aufgabe ist (z.B. h07.pl bei Aufgabe
7); entsprechend hN N .txt für reine Text-Dateien! Zeichnungen erstellen Sie bitte als
pdf-Datei hN N .pdf oder (in einem Editor mit Monospace/fixed-width Font) als ASCIIGrafik! Als Alternative akzeptiere ich auch JPEG-Dateien (hN N .jpg).
Pdf-Dateien, die Grafiken enthalten, können Sie z.B. mit (pdf)LATEX und dem Paket
pgf/tikz oder pstricks erstellen. Auch die gängigen Zeichenprogramme können nach
pdf exportieren. Wenn Sie eine klare Handschrift haben, können Sie anstattdessen Ihre
Lösung händisch auf Papier erstellen und dann einscannen oder bei guten Lichtverhältnissen fotografieren. Stellen Sie in diesem Fall aber sicher, dass das Resultat gut lesbar
ist und z.B. deutlich erkennbar ist, ob ein Buchstabe ein Groß- oder Kleinbuchstabe ist
(z.B. x oder X)!
Hier ein fiktives Beispiel (Diese Aufgabe nicht abgeben!): Sie lösen die folgende fiktive
Aufgabe null:
1
Aufgabe 0 Übersetzen Sie die Aussagen
• Max mag Hans.
• Hans mag Max.
• Hans mag Eva.
in ein Prolog-Programm und fragen Sie Prolog danach, wen Hans mag! Zeichnen Sie einen Graphen, der die Relation des Mögens darstellt!
Sie können dann ein Programm h00.pl schreiben, das als Kommentare die Anfrage und
eine ASCII-Grafik enthält:
% Erika Mustermann, Max Mustermann
% mag(X,Y)
Person
mag(max,hans).
%
mag(hans,max).
%
mag(hans,eva).
%
X mag Person Y
Max mag Hans.
Hans mag Max.
Hans mag Eva.
% ?- mag(hans,Person).
%
%
%
%
+-------+
|
|
v
|
Max --> Hans --> Eva
Oder Sie erstellen h00.pl nur mit Programm und Anfrage:
% Erika Mustermann, Max Mustermann
% mag(X,Y)
Person
mag(max,hans).
%
mag(hans,max).
%
mag(hans,eva).
%
X mag Person Y
Max mag Hans.
Hans mag Max.
Hans mag Eva.
% ?- mag(hans,Person).
und dazu eine pdf-Grafik-Datei h00.pdf
Max
Hans
Eva
und laden beide Dateien auf das Abgabesystem hoch.
Auch wenn Sie von einer Aufgabe nur Teile gelöst haben, geben Sie bitte Ihre Lösung
ab! Einige Aufgaben bestehen aus mehreren Teilen, die aufeinander aufbauen. Auch
teilweise Lösungen können positiv in Ihre Bewertung einfließen.
2
Vorab etwas Terminologie und Syntax zu Prolog:
• Unter einer Klausel eines Programms versteht man ein Fakt oder eine Regel dieses
Programms.
• Jede Klausel muss mit einem Punkt „.“ enden.
• Eine Regel hat die Form Kopf :-Rumpf. , wobei der Rumpf die Form
Ziel1 ,. . . ,Zieln hat. Eine Regel hat also die Form Kopf :-Ziel1 ,. . . ,Zieln . .
• Anstatt vom „2-stelligen Prädikat kind“ zu sprechen, sagt man im Prolog-Jargon
kurz kind/2, d.h. man hängt an den Namen des Prädikats einen Schrägstrich und
dann die Stelligkeit an.
Aufgabe 1 Ich hoffe, Sie haben alle einen Partner für Ihr Zweierteam gefunden. Damit
ich weiß, wer mit wem ein Zweierteam bildet, erstellen Sie bitte in einer Datei mit dem
Dateinamen h01.pl ein Prolog-Programm mit einer Zeile
partner(Ihr_Name, Name_Ihres_Partners ).
und, falls für Sie wichtig ist, in welcher Gruppe Sie sind, einer Leerzeile gefolgt von einer
weiteren Zeile
gruppenwunsch(Ihr_Name, Gruppennummer, Grund ).
und testen Sie Ihr Programm (siehe unten) und geben Sie diese Datei auf dem Abgabesystem ab! Dabei schließen Sie bitte Ihren Namen, den Ihres Partners und den Grund
in einfache Anführungsstriche ein! Der Grund kann auch das leere Prologatom ’’ (zwei
einfache Anführungszeichen) sein. Schreiben Sie bitte Ihren Namen, indem Sie erst den
Familiennamen, dann einen Zwischenraum und dann Ihren Vornamen schreiben. Legen
Sie dabei die Schreibung zugrunde, mit der Sie auf PLUS Online gemeldet sind, wobei
Sie aber bitte :a statt ä, :o statt ö, :u statt ü und :s statt ß schreiben! Es gibt nämlich
verschiedene Kodierungssysteme und der Text ist nachher nicht lesbar, wenn jeder seine
eigene Kodierung verwendet.
Beispiel: Nehmen wir an, Sie heißen Hans-Jürgen Peter Höß und Ihre Teampartnerin
heißt Bärbel Kräßig. Sie wollen von 13 bis 15 Uhr die Vorlesung über Kryptographie
besuchen und wollen daher in Gruppe 2 zugeordnet sein. Dann geben Sie bitte eine
Datei h01.pl mit folgendem Inhalt auf dem Abgabesystem ab!
partner(’H:o:s Hans-J:urgen Peter’, ’Kr:a:sig B:arbel’).
gruppenwunsch(’H:o:s Hans-J:urgen Peter’, 2, ’13-15h VO Kryptographie’).
Wenn für Sie sowohl der Termin der ersten als auch der zweiten Gruppe möglich ist,
geben Sie nur eine Zeile, die mit partner( beginnt, ab!
Zum Testen des Programms laden Sie es bitte in Prolog und stellen die Anfragen
?- partner(Ich, Mein_Partner).
?- gruppenwunsch(Ich, Gruppe, Grund).
3
Den Test des Programms nicht abgeben! Bei dieser Aufgabe wird sich Ihre Datei natürlich
von der Ihres Partners unterscheiden. Also bitte jeder für sich bearbeiten!
Abzugeben: Programm h01.pl
Aufgabe 2 Laden Sie die Datei verwandtschaft.pl und fragen Sie Prolog:
(a) Wessen Kind ist Max?
(b) Wer ist Kind von Anna?
(c) Wer ist Kind von wem?
(d) Wer ist Kind von sich selbst?
(e) Welche zwei Personen sind die Eltern (Vater bzw. Mutter) von welcher dritten
Person?
(f) Wer ist Grußmutter von Eva?
Abzugeben: Datei h02.txt mit 6 Anfragen (darüber Ihre Namen!)
Aufgabe 3 Drücken Sie die folgenden Aussagen über verschiedene Tiergruppen und
ihre bevorzugten Fortbewegungsmethoden in Form eines Prologprogramms aus:
(a) Löwe, Rind, Wal und Fledermaus sind Säugetiere.
(b) Star, Strauß und Wasseramsel sind Vögel.
(c) Löwe, Rind und Strauß gehen gerne.
(d) Forelle, Wasseramsel und Wal schwimmen gerne.
(e) Fledermaus, Star und Wasseramsel fliegen gerne.
Fragen Sie Prolog
(a) nach einem Säugetier, das gerne schwimmt
(b) nach einem Vogel, der gerne fliegt
(c) nach einem Vogel, der gerne fliegt und gerne schwimmt
Schreiben Sie diese Anfragen als Kommentare in das Programm hinein!
Abzugeben: Programm mit Anfragen als Kommentare
Aufgabe 4 Definieren Sie drei Prädikate planet/1, rund/1 und eckig/1 durch Fakten,
die die folgenden Aussagen in Prolog-Syntax ausdrücken!
• Die Erde ist ein Planet.
• Der Mars ist ein Planet.
• Die Erde ist rund.
• Der Mars ist rund.
• Der Würfel ist eckig.
Definieren Sie weiter zwei nullstellige Prädikate es_gibt_einen_eckigen_Planeten/0
und es_gibt_einen_runden_Planeten/0 jeweils durch eine Regel unter Bezugnahme
auf die oben definierten Prädikate! Damit sollte Prolog auf folgende Anfragen mit folgenden Antworten reagieren:
?- es_gibt_einen_runden_Planeten.
true .
?- es_gibt_einen_eckigen_Planeten.
false.
4
In Prolog lässt man bei nullstelligen Prädikaten die Klammern weg.
Abzugeben: Programm
Aufgabe 5 Überlegen Sie sich zunächst ohne Verwendung des Computers, welche der
folgenden Zeichenfolgen Prolog-Atome, welche Prolog-Variablen sind!
(a) abc
(b) aBC
(c) 1abc
(d) -1234
(e) Abc
(f) 123.7
(g) -12.34e-23
(h) a_B_c
(i) A1
(j) ab-cd
(k) a1
(l) 2+3
(m) f(g(X,a),h(3,Y,b))
(n) Heinz Schmidt
(o) ’Heinz Schmidt’
Starten Sie nun am Computer Ihr Prolog-System! Für einen Term T liefert eine Anfrage
?- atom(T ). die Antwort yes oder true, wenn T ein Prolog-Atom ist. Wenn T kein
gültiger Prolog-Term ist, sollte eine Fehlermeldung produziert werden. Probieren Sie das
mit Aufrufen wie
?- atom(abc).
Entsprechend wie atom/1 gibt es in Prolog noch andere Typ-Test-Prädikate, z.B. var/1,
number/1, integer/1, float/1, compound/1 (testet, ob ein Term zusammengesetzt ist).
Testen Sie damit für jede der obigen Zeichenfolgen, ob es sich um einen Prolog-Term
handelt, und was jeweils der Typ dieses Terms ist!
Abzugeben: Datei mit Angabe zu Term-Typen
Aufgabe 6 Im Programm verwandtschaft.pl ist unter anderem ein zweistelliges Prädikat kind/2 definiert. Dieses Prädikat lässt sich durch einen Graphen darstellen, z.B.
die ersten beiden Fakten des Prädikats durch
Franz
Max
Christine
(a) Vervollständigen Sie diesen Graphen!
(b) Laden Sie das Programm verwandtschaft.pl in Prolog und fragen Sie Prolog,
wer Nachkomme von wem ist! Bei wiederholter Eingabe eines Strichpunkts sollten
Sie insgesamt 11 Antworten bekommen.
5
(c) Fragen Sie Prolog, wer Nachkomme von Franz ist! Prolog sollte 4 Antworten liefern.
(d) Verlassen Sie nun Prolog, kopieren Sie die Datei verwandtschaft.pl, ändern Sie
die letzte Klausel der Kopie ab zu
nachkomme(N,X) :nachkomme(N,K),
kind(K,X).
und laden Sie diese Datei in Prolog und fragen Sie Prolog wieder, wer Nachkomme
von Franz ist! Erklären Sie, was dabei passiert!
(e) Was passiert, wenn Sie die letzten fünf Zeilen abändern zu
nachkomme(N,X) :nachkomme(N,K),
kind(K,X).
nachkomme(N,X) :kind(N,X).
und wieder dieselbe Anfrage stellen? Wenn Prolog einen Fehler signalisiert und
nicht das Prompt ?- , sondern z.B. nur ein Fragezeichen ohne Minuszeichen ausgibt,
versuchen Sie mit a (= abort) abzubrechen!
(f) Alle diese drei Programme unterscheiden sich nur in der Reihenfolge der Klauseln
oder in der Reihenfolge der Teilziele innerhalb des Rumpfes einer Klausel. Logisch
sind sie zueinander äquvialent, aber im Verhalten beim Aufruf einer Anfrage unterscheiden sie sich voneinander. Schauen Sie sich das Verhalten bei (c) und bei
(d) noch einmal an und formulieren Sie eine Faustregel, wie man die Reihenfolge
der Teilziele bei einer rekursiven Klausel wählen sollte!
Abzugeben: (a) Graphik; (b),(c) Anfragen; (d),(e),(f) Text
Aufgabe 7 Ein Gatter (englisch: gate) ist eine einfache elektronische Schaltung mit
ein oder mehr Eingängen und einem Ausgang. An jedem der Eingänge kann ein Signal
angelegt werden und das Gatter verarbeitet die Eingangssignale zu einem Signal am
Ausgang. Für jedes Signal gibt es zwei mögliche Werte, die als Wahrheitswerte w (für
„wahr“) und f (für „falsch“) interpretiert werden. Ein Beispiel für ein Gatter ist das oderGatter. Bezeichnen wir die Eingangssignale mit A und B und das Ausgangssignal mit C.
Dann ist C=w genau dann, wenn A=w oder B=w ist. Hier ist eine graphische Darstellung
des oder-Gatters als Kasten mit zwei Eingängen A und B oben und einem Ausgang C
unten, daneben die Wahrheits(wert)tabelle (englisch truth table), in der jede Zeile eine
Möglichkeit für die Wahrheitswerte von A und B und den dazugehörigen Wahrheitswert
von C angibt. Daneben ist eine Darstellung der Wahrheitstabelle als Prolog-Programm:
A B
oder
C
A
w
w
f
f
B
w
f
w
f
C
w
w
w
f
% oder(A,B,C)
oder(w,w,w).
oder(w,f,w).
oder(f,w,w).
oder(f,f,f).
C = (A oder B)
Schreiben Sie das Programm in eine Datei h07.pl und stellen Sie die Anfrage
6
?- oder(A,B,C).
und lassen Sie sich durch wiederholte Eingabe eines Strichpunkts nacheinander alle Antworten von Prolog ausgeben! Es sollten nacheinander die folgenden Antworten kommen:
A=w,
A=w,
A=f,
A=f,
B=w,
B=f,
B=w,
B=f,
C=w ;
C=w ;
C=w ;
C=f
Die genaue Form, in der Prolog diese Antworten präsentiert, unterscheiden sich von
Prolog-System zu Prolog-System. Überzeugen Sie sich, dass die Antworten, die Ihr
Prolog-System liefert, äquivalent sind zu den oben angeführten Antworten!
Weitere Beispiele für Gatter sind das und-Gatter und das nicht-Gatter, hier graphisch
als Kästen dargestellt und rechts daneben jeweils die Wahrheitstabelle:
A
w
w
f
f
A B
und
C
B
w
f
w
f
C
w
f
f
f
A
nicht
B
A
w
f
B
f
w
Ergänzen Sie Ihr Programm h07.pl um Prädikate und/3 und nicht/2 gemäß dieser
beiden Wahrheitstabellen!
Gatter können zu komplexeren Schaltungen kombiniert werden. Hier ist ein Halbaddierer graphisch als Kasten dargestellt und im Detailaufbau aus Gattern gezeigt,
daneben die Definition der Relation zwischen Ein- und Ausgaben als Prolog-Prädikat
halbaddierer/4.
A B
und
A
oder
nicht
B
D
und
Halbaddierer
C
S
E
C
S
halbaddierer(A,B,C,S) :und(A,B,C),
nicht(C,D),
oder(A,B,E),
und(D,E,S).
Fügen Sie diese Definition Ihrem Programm hinzu und lassen Sie es mit der Anfrage
?- halbaddierer(A,B,C,S).
laufen! Erstellen Sie aus den Antworten, die Ihnen Prolog liefert, die Wahrheitstabelle
für den Halbaddierer!
Hier sind zwei Schaltungen mit Rückkoppelungen:
7
A
B
oder
oder
E
A
F
nicht
nicht
C
D
nicht
Die linke Schaltung ist instabil. Stellen Sie an Prolog die Anfrage
?- nicht(A,A).
Dann sehen Sie, dass es keine stabile Lösung gibt. Die rechte Schaltung ist ein Flipflop
und ist bistabil. Wenn die Eingangssignale A=f und B=f sind, gibt es zwei verschiedene
Lösungen für die Ausgangssignale C und D. Um das mit Prolog zu testen, definieren Sie
ein Prolog-Prädikat flipflop/4 durch eine Definition
flipflop(A,B,C,D) :...
für die stabilen Zustände des Flipflop und stellen Sie dann die Anfrage
?- flipflop(A,B,C,D).
Prolog gibt Ihnen alle Antworten für stabile Zustände des Flipflop. Erstellen Sie daraus
eine Wahrheitstabelle! Zu den Einbagesignalen A=f und B=f wird Ihre Tabelle zwei
Zeilen haben.
Abzugeben: Programm; Wahrheitstabellen für Halbaddierer und für stabile Zustände
des Flipflop
Aufgabe 8 In der vorigen Aufgabe haben wir uns mit Logikschaltungen beschäftigt.
Aber die Signale, mit denen wir es dort zu tun hatten, kann man auch als Zahlen
1 für w (wahr) und 0 für f (falsch) deuten. Meist wählt man dann die Reihenfolge der
Aufschreibung so, dass zuerst 0, dann 1 drankommt. Kopieren Sie das Programm h07.pl
nach h08.pl und schreiben Sie h08.pl wie oben angedeutet um, wobei Sie 0 statt f und
1 statt w schreiben!
Der Halbaddierer kann jetzt verwendet werden, um zwei einstellige Zahlen im Zweiersystem (=Dualsystem=Binärsystem) zu addieren. Dabei kann es einen Übertrag (englisch carry C) geben. Die Summe A+B kann also zweistellig werden:
02 + 02 = 002
02 + 12 = 012
12 + 02 = 012
12 + 12 = 102
8
Die erste Stelle der Summe (Zweierstelle) ist der Übertrag C und die zweite Stelle (Einerstelle) das S (für Summe). Probieren Sie das mit dem Programm h08.pl aus!
Beim Addieren mehrstelliger Zahlen, z.B.
10012 +
10112 =
101002
addiert man zunächst die rechten Stellen (Einerstellen) der Summanden. Das ergibt
hier Summe 0 (als Einerstelle des Ergebnisses) und Übertrag 1. Dann addiert man die
zweitletzten Stellen der Summanden (Zweierstellen) und muss noch den Übertrag, hier
1 dazuaddieren: 02 + 12 + 12 ergibt hier 2, also 102 , d.h. wieder Summe 0 (als Zweierstelle
des Ergebnisses) und Übertrag 1 auf die drittletzte Stelle (Viererstelle), u.s.w. Es müssen
also für die Berechnung einer jeden Stelle des Ergebnisses im Zweiersystem bis zu drei
einstellige Zahlen addiert werden. Dies tut der Volladdierer
A
B
Halbaddierer
A
Cout
S1
B
C1
Volladdierer
Cin
Halbaddierer
C2
Cin
oder
Cout
S
S
Ergänzen Sie das Programm h08.pl um die Definition des Prädikats volladdierer/5:
volladdierer(A,B,Cin,Cout,S) :...
Verwenden Sie dabei das Prädikat halbaddierer/4! Stellen Sie nun die Anfrage
?- volladdierer(A,B,Cin,Cout,S).
und lassen Sie sich von Prolog mit Strichpunkt alle Antworten ausgeben! Überzeugen Sie
sich, dass tatsächlich die Summe A+B+Cin im Zweiersystem ausgerechnet wird, wobei
das Ergebnis aus den zwei Ziffern Cout und S besteht. Aus vier Volladdierern kann man
nun einen Vier-Bit-Addierer bauen:
A3
C4
B3
Volladdierer
S3
A2
C3
B2
Volladdierer
A1
C2
S2
B1
Volladdierer
S1
9
A0
C1
B0
Volladdierer
S0
C0
Ergänzen Sie Ihr Programm h08.pl dementsprechend um ein Prädikat vierbitaddierer/14:
vierbitaddierer(A3,B3,A2,B2,A1,B1,A0,B0,C0,C4,S3,S2,S1,S0) :...
Normalerweise wird man C0=0 wählen. Um die Verwendung des Prädikats etwas übersichtlicher zu machen, kann man die Bits jedes Summanden und der Summe jeweils in
eine Liste zusammenfassen:
vierbitaddierer1([A3,A2,A1,A0],[B3,B2,B1,B0],[C4,S3,S2,S1,S0]) :vierbitaddierer(A3,B3,A2,B2,A1,B1,A0,B0,0,C4,S3,S2,S1,S0).
Stellen Sie für obiges Beispiel 10012 + 10112 = 101002 die Anfragen
?- vierbitaddierer1([1,0,0,1],[1,0,1,1],Summe).
?- vierbitaddierer1(Summand1,Summand2,[1,0,1,0,0]).
und vergewissern Sie sich, dass Prolog die richtigen Antworten liefert!
Abzugeben: Programm
Aufgabe 9 Bei dieser Aufgabe geht es um die Situation einer Familie und die Frage,
wer mit wem sein Hobby gemeinsam ausüben kann. Viele Hobbies kann man außerhalb der Urlaubs- oder Ferienzeit, etwa am Abend oder Wochenende ausüben, und zwei
Personen, die nahe beieinander wohnen, können dies gemeinsam tun. Andere Hobbies,
z.B. segeln auf hoher See erfordern eine mehrwöchige Urlaubs- oder Ferienzeit. Zwei
Menschen können ein solches Hobby gemeinsam ausüben, wenn sie zur gleichen Zeit frei
haben, unabhängig davon, wie weit entfernt voneinander sie wohnen.
Die Verwandtschaftsbeziehungen der Familie seien durch den folgenden Graphen gegeben:
Hans
Anna
Karl
Max
Dora
Franz
Eva
Bert
Karl ist z.B. ein Kind von Anna. Jede der Personen hat mindestens ein Hobby:
• Hans spielt Schach und segelt.
• Anna spielt Schach und geht gerne einkaufen.
• Karl geht gerne auf Parties.
• Max angelt und segelt.
• Dora spielt Tennis, segelt und geht gerne einkaufen.
• Franz geht wandern, segelt und spielt Schach.
• Eva reitet.
10
• Bert angelt, spielt Tennis, segelt und geht gerne einkaufen.
Die Familie ist über zwei Städte verstreut:
• Hans, Anna, Karl, Max und Dora wohnen in St. Pölten.
• Franz, Eva und Bert wohnen in Los Angeles.
Die Mitglieder der Familie haben in unterschiedlichen Monaten frei:
• Hans, Anna und Karl haben immer frei.
• Max und Dora haben im August frei.
• Franz, Eva und Bert haben im Juli frei.
Zur Lösung der Aufgabe noch die folgenden Informationen:
• Wenn zwei Personen in der gleichen Stadt wohnen, dann wohnen sie nahe beieinander.
• Wenn zwei Personen nahe beieinander wohnen und eines der Hobbies „Schach
spielen“, „einkaufen“, „auf Parties gehen“, „angeln“, „Tennis spielen“, „wandern“
und „reiten“ gemeinsam haben, können sie dieses Hobby gemeinsam ausüben.
• Wenn zwei Personen dasselbe Hobby haben, können sie es gemeinsam ausüben,
wenn sie im gleichen Monat frei haben.
Frage:
• Wer kann sein Hobby gemeinsam mit seinem Enkelkind ausüben? Gesucht sind
alle möglichen Antworten. Jede Antwort soll jeweils die Person, das Enkelkind und
das Hobby nennen.
Übersetzen Sie die hier angegebene Kind-Eltern-Beziehung und alle mit • gekennzeichneten Aussagen in ein Prolog-Programm, übersetzen Sie die ebenfalls mit • gekennzeichnete
Frage am Ende der Problemstellung in eine Prolog-Anfrage und fügen Sie diese Anfrage
am Ende der Datei als Kommentar dem Programm hinzu!
Abzugeben: Programm mit Anfrage
Aufgabe 10 Erweitern Sie das Programm verwandtschaft.pl um ein Prädikat bruder/2,
wobei bruder(B,P) bedeuten soll: B ist Bruder der Person P. Gehen Sie dazu zunächst
von der folgenden Definition aus:
B ist Bruder von P, wenn B Kind von X ist, B männlich ist und P Kind von
X ist.
Fragen Sie Prolog danach, wer Bruder vom wem ist! Was fällt Ihnen dabei auf? Definieren
Sie nun ein Prädikat verschieden/2, mit Fakten darüber, welche Personen voneinander
verschieden sind! Verwenden Sie dabei keine eingebauten Prädikate – die nehmen wir
erst später durch! Schreiben Sie stattdessen explizit z.B.
verschieden(max,franz).
und Entsprechendes für alle anderen Paare von zueinander verschiedenen Personen! Es
müssen insgesamt 30 Fakten für das Prädikat verschieden/2 sein. Wir werden später
sehen, wie man das in Prolog bequemer machen kann. Verwenden Sie dieses Prädikat,
um die Definition des Prädikats bruder/2 richtigzustellen! Dabei werden Sie aber noch
immer Antworten doppelt bekommen. Warum? Was würde passieren, wenn wir andere
11
Fakten für das Prädikat kind/2 hätten derart, dass eine Person Halbbruder einer anderen
Person ist? Ändern Sie schließlich die Definition des Prädikats bruder/2 so ab, dass
keine Antworten doppelt kommen und in Antworten nur echte Brüder, nicht Halbbrüder
genannt werden!
Abzugeben: Programm mit Anfrage und Text als Kommentar
Aufgabe 11 (Vierfarbenproblem) Österreich besteht aus den Bundesländern Vorarlberg, Tirol, Salzburg, Oberösterreich, Kärnten, Steiermark, Niederösterreich, Wien
und Burgenland (siehe Datei oesterreichkarte.png). Beim Vierfarbenproblem geht es
darum, mit vier Farben – sagen wir Rot, Grün, Blau und Gelb – eine Karte zu zeichnen, bei der jeweils zwei aneinander angrenzende1 Länder verschiedene Farben haben.
In unserem Beispiel muss etwa die Farbe von Tirol verschieden sein von der Farbe von
Kärnten, da die Länder Tirol und Kärnten aneinander angrenzen.
Zeichnen Sie zunächst einen Graphen, in dem jedes Bundesland als Knoten dargestellt ist und für je zwei aneinander angrenzende Bundesländer eine Kante die beiden
entsprechenden Knoten verbindet! Schreiben Sie dann ein Prolog-Programm mit Fakten
darüber, welche Farben voneinander verschieden sind! Verwenden Sie dabei keine eingebauten Prädikate – die nehmen wir erst später durch! Schreiben Sie stattdessen explizit
z.B.
verschieden(rot,gruen).
und Entsprechendes für alle anderen Paare von verschiedenen Farben. Es müssen insgesamt 12 Fakten sein. Fügen Sie schließlich eine Regel hinzu so, dass die Anfrage
?- loesung(Farbe_Vorarlberg,
Farbe_Tirol,
Farbe_Salzburg,
Farbe_Oberoesterreich,
Farbe_Kaernten,
Farbe_Steiermark,
Farbe_Niederoesterreich,
Farbe_Wien,
Farbe_Burgenland).
alle Lösungen des Vierfarbenproblems für die Landkarte von Österreich findet! Eine
Lösung ist zum Beispiel
Farbe_Burgenland = gruen
Farbe_Kaernten = blau
Farbe_Niederoesterreich = rot
Farbe_Oberoesterreich = gruen
Farbe_Salzburg = rot
Farbe_Steiermark = gelb
1
Gemeint ist, dass sie eine gemeinsame Grenzlinie (nicht nur einen gemeinsamen Grenzpunkt) haben.
12
Farbe_Tirol = gruen
Farbe_Vorarlberg = rot
Farbe_Wien = gruen
(hier die Ausgabe einer der Lösungen bei GNU-Prolog; bei SWI-Prolog kommt die gleiche Lösung – etwas anders dargestellt – heraus). Der Vierfarbensatz besagt, dass in
der Ebene (oder auch auf der Kugeloberfläche) jede Landkarte, bei der jedes Land zusammenhängend ist,2 sich mit vier Farben färben lässt. Seit 1852 haben Mathematiker
versucht, dies zu beweisen. Ein Beweis konnte erst 1976 mit Computerhilfe gefunden
werden und war so kompliziert, dass er von Menschen nicht nachvollzogen werden kann.
Abzugeben: Graph, Programm
Aufgabe 12 (Cliquen-Problem) Ein bekanntes schwieriges Problem der Informatik
ist das Cliquenproblem. In einer Menge von Personen gibt es einige Paare von miteinander befreundeten Personen. Eine Clique ist nun eine Teilmenge von Personen, in der
jede Person mit jeder anderen Person befreundet ist. Eine Clique aus n Personen wird
eine n-Clique oder n-er-Clique genannt. Hier ein Beispiel:
(a) Anton und Berta sind miteinander befreundet.
(b) Anton und Christa sind miteinander befreundet.
(c) Anton und Dora sind miteinander befreundet.
(d) Anton und Ernst sind miteinander befreundet.
(e) Berta und Dora sind miteinander befreundet.
(f) Berta und Ernst sind miteinander befreundet.
(g) Berta und Franz sind miteinander befreundet.
(h) Christa und Dora sind miteinander befreundet.
(i) Christa und Ernst sind miteinander befreundet.
(j) Dora und Ernst sind miteinander befreundet.
(k) Dora und Franz sind miteinander befreundet.
(l) Ernst und Franz sind miteinander befreundet.
Dann ist die Menge {Dora, Anton, Ernst, Berta} eine Vierer-Clique, da sie aus vier
Personen besteht, die alle miteinander befreundet sind. Ziel der Aufgabe ist es, für
dieses Beispiel ein Prologprogramm zu schreiben, das alle Vierer-Cliquen findet. Wir
könnten die oben genannte Vierer-Clique als Term menge(dora,anton,ernst,berta)
darstellen. Leider ist diese Darstellung aber nicht eindeutig, da etwa der Prologterm
menge(anton,berta,dora,ernst) dieselbe Clique darstellt. Jede Vierer-Clique hat 24
verschiedene Darstellungen als Prologterm. Um Eindeutigkeit zu erreichen, wollen wir
denjenigen Prologterm verwenden, bei dem die vier Mitglieder der Clique in lexikographischer (=alphabetischer) Reihenfolge genannt sind, also im Beispiel den Term
menge(anton,berta,dora,ernst).
Stellen Sie zunächst das Problem durch einen Graphen dar mit je einem Knoten für
jede beteiligte Person und einer Kante für jedes Paar von befreundeten Personen! Schreiben Sie dann ein Prologprogramm, in dem Sie ein Prädikat befreundet/2 gemäß (a)–(l)
2
Im Falle Österreichs ist Tirol nicht zusammenhängend, da Osttirol nicht mit dem Hauptteil von Tirol
zusammenhängt, aber die Landkarte Österreichs lässt sich trotzdem mit vier Farben färben.
13
durch Fakten definieren, wobei befreundet(A,B) bedeuten soll, dass die Personen A
und B miteinander befreundet sind und Person A in der lexikographischen Reihenfolge vor Person B steht! Definieren Sie nun ein Prädikat ist_Viererclique/1, wobei
ist_Viererclique(C) bedeuten soll, dass C eine Vierer-Clique ist! Dabei soll C als
Prologterm wie oben dargestellt sein, wobei die vier Mitglieder der Vierer-Clique in
lexikographischer Reihenfolge genannt sind. Schreiben Sie die Erklärungen, was die Prädikate bedeuten, jeweils als Kommentar vor die entsprechenden Klauseln. Ihr Programm
sollte alle Vierercliquen finden können und sich etwa so verhalten:
?- ist_Viererclique(Viererclique).
Viererclique = menge(anton, berta, dora, ernst) ;
Viererclique = menge(anton, christa, dora, ernst) ;
Viererclique = menge(berta, dora, ernst, franz)
Das Cliquen-Problem besteht darin, zu einem gegebenen endlichen ungerichteten Graphen (wie im Beispiel) und zu einer gegebenen natürlichen Zahl n festzustellen, ob es
eine n-Clique gibt. Es gehört zur Klasse der sogenannten NP-vollständigen Probleme.
Für diese Probleme ist es bis heute keinem Forscher gelungen, einen effizienten Algorithmus anzugeben. Es wird vermutet, dass es für NP-vollständige Probleme keine effizienten
Algorithmen gibt, aber auch das konnte bisher niemand beweisen. Die Frage, ob es einen
effizienten Algorithmus dafür gibt (P=NP? seit 1971), ist das bekannteste bis heute ungelöste Problem der Theoretischen Informatik. Für kleine Mengen von Personen ist das
Problem mit Prolog leicht lösbar, aber für große Mengen wird der Rechenaufwand gigantisch.
Abzugeben: Graph, Programm samt Kommentaren
Aufgabe 13 Geben Sie für jeden der folgenden Terme 1. den Funktor (samt Stelligkeit,
z.B. k/4), 2. die unmittelbaren Teilterme, 3. alle Teilterme an und zeichnen Sie 4. den
Strukturbaum:
(a) h(a,b,c)
(b) f(g(h(X,a),Y,h(Z,X)),c,3)
(c) d
(d) 10-5-4
(e) a*b+U*c-V/X
Hinweis: Bitte versuchen Sie zunächst die Aufgabe ohne Computerhilfe zu lösen. Danach (und bitte erst danach!) schauen Sie sich bitte die Dokumentation des eingebauten Prolog-Prädikats functor/3 an! In SWI-Prolog können Sie das etwa tun, indem
Sie ?- help. aufrufen und ins Eingabefeld in der Fußzeile des sich öffnenden HilfeFensters functor eingeben, gefolgt von einem RETURN oder einem Klick auf den HelpButton. Probieren Sie dieses eingebaute Prädikat aus:
?- functor(k(X,f(Y)),Funktor,Stelligkeit).
Funktor = k, Stelligkeit = 2
Wenn Sie den Funktor und die Stelligkeit haben, können Sie z.B. mit
14
?- k(Teilterm1,Teilterm2) = k(X,f(Y)).
Prolog nach den unmittelbaren Teiltermen des Terms fragen. Mit
?- arg(2,k(X,f(Y)),Teilterm2).
können Sie Prolog nach dem zweiten unmittelbaren Teilterm des Terms fragen. Lesen
Sie sich dazu auch die Dokumentation von arg/3 durch!
Abzugeben: jeweils Funktor, unmittelbare Teilterme, alle Teilterme, Strukturbaum
Aufgabe 14 Wir wollen einen Vektor (X, Y, Z) im dreidimensionalen euklidischen Raum
darstellen als Prologterm vektor(X,Y ,Z). Hier ist ein Programm zur Berechnung der
Summe zweier Vektoren und des Betrags, d.h. der Länge eines Vektors.
%vektorsumme(+Vektor,+Vektor,-Vektor)
%vektorsumme(V1,V2,V) Vektor V ist Summe der Vektoren V1 und V2.
vektorsumme(vektor(X1,Y1,Z1),vektor(X2,Y2,Z2),vektor(X,Y,Z)) :X is X1+X2,
Y is Y1+Y2,
Z is Z1+Z2.
%betrag(+Vektor,-Zahl)
%betrag(V,B) B ist der Betrag des Vektors V.
betrag(vektor(X,Y,Z),B) :B is sqrt(X*X+Y*Y+Z*Z).
In den Kommentaren bedeutet das + bei +Vektor, dass beim Aufruf des Prädikats das
betreffende Argument voll instantiiert sein soll, also z.B. nicht eine Variable. Das - in
-Vektor und -Zahl heißt, dass beim Aufruf des Prädikats das betreffende Argument
uninstantiiert (also eine Variable) sein soll.
Fragen Sie Prolog nach der Summe der beiden Vektoren (2, 5, 4) und (−3, 2, 1) und
nach dem Betrag des Vektors (2, 5, 4)! Um zu sehen, was passieren kann, wenn die
im Kommentar vorgeschriebene Instantiierung oder Nicht-Instantiierung nicht beachtet
wird, stellen Sie die Anfragen
?- betrag(X,B).
?- betrag(vektor(0,0,0),0).
Erklären Sie, warum es zu einer Fehlermeldung bzw. zu einer unerwarteten Antwort
kommt! Erweitern Sie das Programm nun um zwei Prologprädikate skalarprodukt/3
und vektorielles_Produkt/3 zur Berechnung des Skalarprodukts beziehungsweise des
vektoriellen Produkts zweier Vektoren!
Abzugeben: Anfragen, Erklärung, Programm
Aufgabe 15 Eine
√ komplexe Zahl hat die Form a + bi, wobei a und b reelle Zahlen
sind und i = −1 ist. Wir wollen eine solche komplexe Zahl a + bi darstellen als
Prologterm komplex(a,b). Definieren Sie Prologprädikate kompl_add/3, kompl_sub/3,
15
kompl_mul/3 und kompl_div/3 zur Addition, Subtraktion, Multiplikation und Division
zweier komplexer Zahlen und stellen Sie dazu Anfragen zur Berechnung von (1 + i)(1 − i)
3
und von 4−5i
!
Abzugeben: Programm, Anfragen
Aufgabe 16 Übersetzen Sie die folgenden Aussagen über Paare und ihre Wohnorte in
Prologfakten!
• Das Paar Max und Eva wohnt in Salzburg.
• Das Paar John und Jane wohnt in London.
• Das Paar Hans und Anna wohnt in Salzburg.
Stellen Sie dabei jedes Paar als zusammengesetzten Prologterm dar, z.B. das Paar Max
und Eva als den Prologterm paar(max,eva)! Fragen Sie nun Prolog nach den Paaren,
die in Salzburg wohnen. Prolog sollte darauf antworten mit
Paar = paar(max, eva) ;
Paar = paar(hans, anna).
Fragen Sie schließlich nach den Frauen, die einem Paar angehören, das in Salzburg wohnt!
Prolog sollte darauf antworten mit
Frau = eva ;
Frau = anna.
Hinweis: Schreiben Sie Ihre Anfrage zunächst so, dass Prolog antwortet mit
Mann = max, Frau = eva ;
Mann = hans, Frau = anna.
und ersetzen Sie dann die Variable Mann in der Anfrage durch die „anonyme Variable“ _
(Unterstreichungsstrich oder underscore)! Dann gibt Ihnen Prolog den Mann nicht aus.
Abzugeben: Programm und zwei Anfragen
Aufgabe 17 Stellen Sie an Prolog die Anfrage
?- f(A,B,C) = f(g(B,B),g(C,C),g(D,D)).
und beobachten Sie, was Prolog antwortet! Schreiben Sie eine entsprechende Anfrage
mit zehnstelligem Funktor f/10:
?- f(A,B,C,D,E,F,G,H,I,J) =
f(g(B,B),g(C,C),g(D,D),g(E,E),g(F,F),g(G,G),g(H,H),g(I,I),g(J,J),g(K,K)).
Schaun Sie sich die Antwort an, die Prolog liefert! Besonders der Term, zu dem Prolog
die Variable A instanziiert, ist recht lang. Je nach der Einstellung des Prologsystems
kann es sein, dass Prolog diesen Term dabei abkürzt. Bestimmen Sie trotzdem, wie oft
das K in diesem Term vorkommt! Begründen Sie Ihre Antwort!
Abzugeben: Text
16
Aufgabe 18 (Listen) In Prolog können wir mehrere Terme zu einer Liste zusammenfassen. Dazu schreiben wir die Terme zwischen eckige Klammern und durch Kommas
voneinander getrennt. Zum Beispiel ist [a,b,c] die Liste, die aus den Termen (Elementen) a, b und c besteht. Die leere Liste [] enthält keine Elemente, die Liste [a] nur ein
Element a. Prolog verwendet für Listen nicht einen eigenen Datentyp. Stattdessen sind
Listen ganz gewöhnliche Terme. Die leere Liste ist ein Prologatom []. Alle anderen Listen
sind zusammengesetzte Terme, die aus den Elementen der Liste und aus der leeren Liste
[] mit Hilfe des zweistelligen Funktors ./2 (also Punkt) aufgebaut sind.3 So ist [a,b,c]
nur eine abkürzende Schreibweise für den Prologterm .(a, .(b, .(c, []))) und kann
optional anstatt der kanonischen Schreibung .(a, .(b, .(c, []))) verwendet werden. Prolog verwendet in seinen Antworten standardmäßig stets die Listenschreibweise
[a,b,c]:
?- X = .(a, .(b, .(c, []))).
X = [a, b, c].
?- X = .(a, [b,c,d]).
X = [a, b, c, d].
Wie man sieht, dient hier der zweistellige Funktor ./2 dazu, ein neues Element a an
eine existierende Liste [b,c,d] vorne anzuhängen. Allgemein ist .(A,L) die Liste, die
entsteht, indem man an die Liste L vorne das neue Element A anhängt.
Man kann sich die kanonische Schreibweise mit write_canonical/1 ausgeben lassen:
?- write_canonical([a,b,c]).
’.’(a,’.’(b,’.’(c,[])))
Dabei hat Prolog den Funktor ./2 (Punkt) der Deutlichkeit halber in einfache Anführungszeichen gesetzt.
Der Strukturbaum der Liste [a,b,c] ist
.
.
a
.
b
c
[]
Listen können auch selbst wieder Listen als Elemente enthalten und beliebig tief verschachtelt sein. Geben Sie die kanonische Schreibung sowie den Strukturbaum für die
Liste [a,[b,c]] an!
Abzugeben: Text, Strukturbaum
3
In SWI-Prolog soll ist ab Version 7 der Name dieses Funktors ’[|]’ statt des Punktes, um den Punkt
für andere Dinge verwenden zu können.
17
Aufgabe 19 (Unifikation) Unifizieren Sie die beiden Terme f(X,h(Y,Z),a) und
f(g(U),U,Y) mit dem Unifikationsalgorithmus der Vorlesung! Kennzeichnen Sie dabei für jeden Schritt die Nichtübereinstimmungsmenge durch Hervorhebung in Farbe
oder Unterstreichung und geben Sie für jeden Schritt die Substitution σi an sowie den
resultierenden allgemeinsten Unifikator!
Aufgabe 20 (Listensumme) Schreiben Sie ein Prologprädikat listensumme/2 zur
Bestimmung der Summe einer Liste von Zahlen! Beispiel:
?- listensumme([3,5,9],Summe).
Summe = 17.
In vielen Prologs ist ein solches Prädikat bereits eingebaut. Implementieren Sie das
Prädikat aber bitte selber, wobei Sie keine eingebauten Prädikate außer dem Prädikat
is/2 verwenden sollen!
Abzugeben: Programm
Aufgabe 21 (Ableitung) In der Differentialrechnung gibt es einfache Regeln, um die
Ableitung einer Funktion nach einer Variablen x zu bestimmen, zum Beispiel
(a) Ableitung einer konstanten Funktion ergibt 0.
(b) Ableitung von x nach x ergibt 1.
(c) Summenregel
(d) Produktregel
Wir wollen hier annehmen, dass die Funktion gegeben ist durch einen einfachen arithmetischen Ausdruck, der aus den Zahlen 0 und 1 und aus den Buchstaben a und x mit
Addition und Multiplikation aufgebaut ist. Im Sinne der Differentialrechnung soll dabei
nach x differenziert werden, während 0, 1 und a als Konstanten behandelt werden.
In Prolog stellen wollen wir einen solchen Ausdruck darstellen durch einen Term, der
aufgebaut ist aus den Prolog-Konstanten 0, 1, a und x mit den Funktoren +/2 und */2, also durch einen Term aus dem Herbrand-Universum zur Menge {0/0, 1/0, a/0, x/0, +/2, */2}.
Beispiel: Der Prologterm a*x+(1+a)*x*(1+x) steht für die Funktion f , die definiert ist
durch f (x) = ax + (1 + a)x(1 + x). Beachten Sie, dass wir die Variable x, nach der
differenziert wird (ebenso wie den Buchstaben a) in Prolog als Konstante darstellen.
Unseren Begriff des „einfachen Ausdrucks“ kann man in Prolog definieren durch das
folgende Prädikat.
einfacher_Ausdruck(0).
einfacher_Ausdruck(1).
einfacher_Ausdruck(a).
einfacher_Ausdruck(x).
einfacher_Ausdruck(A+B) :einfacher_Ausdruck(A),
einfacher_Ausdruck(B).
einfacher_Ausdruck(A*B) :einfacher_Ausdruck(A),
einfacher_Ausdruck(B).
18
Die Anfrage ?- einfacher_Ausdruck(a*x+(1+a)*x*(1+x)). gelingt dann.
Definieren Sie ein Prädikat abl_x/2 zur Bestimmung der Ableitung eines einfachen
Ausdrucks nach x! Übersetzen Sie dazu die obigen Regeln (a)–(d) in Prologklauseln!
Beispiel einer Anfrage und einer möglichen Antwort von Prolog:
?- abl_x(a*x+(1+a)*x*(1+x),Ableitung).
Ableitung = 0*x+a*1+(((0+0)*x+(1+a)*1)*(1+x)+(1+a)*x*(0+1))
Den Ausdruck, den Prolog hier geliefert hat, könnte man noch deutlich vereinfachen,
was aber für diese Aufgabe nicht verlangt ist.
Abzugeben: Programm
Aufgabe 22 (Negation as failure) In Prolog kann man nicht direkt ausdrücken, dass
ein Prädikat auf bestimmte Objekte nicht zutrifft. Stattdessen nimmt man – ähnlich wie
in anderen Datenbank-Sprachen – an, dass ein Prädikat auf Objekte nicht zutrifft, wenn
im Programm nicht explizit steht oder es logisch aus dem Programm folgt, dass das
Prädikat auf diese Objekte zutrifft. Beispiel: Der Individuenbereich, also die Menge der
betrachteten Objekte bestehe aus den Vögeln Amsel, Strauß, Fink, Pinguin, Adler und
Habicht. Die Definition des Prädikats flugunfaehiger_Vogel/1 sei
flugunfaehiger_Vogel(strauss).
flugunfaehiger_Vogel(pinguin).
Dann besagt die Closed World Assumption, dass das Prädikat flugunfaehiger_Vogel/1
auf Amsel, Fink, Adler und Habicht nicht zutrifft, da z.B. flugunfaehiger_Vogel(amsel)
nicht logisch aus dem Programm folgt. Leider ist es oft schwierig zu beweisen, dass ein
Ziel wie z.B. flugunfaehiger_Vogel(amsel) nicht logisch aus einem Programm folgt.
Im Allgemeinen ist die Frage sogar unentscheidbar, d.h. es gibt grundsätzlich keinen
Algorithmus, der immer entscheiden könnte, ob ein gegebenes Ziel aus einem gegebenen
Programm folgt oder nicht. Als Annäherung an die Closed World Assumption verwendet Prolog die Negation as Failure (Negation als Fehlschlag). Die Negation as Failure
eines Ziels G wird mit \+G bezeichnet. Wenn das Ziel \+G aufgerufen wird, versucht
Prolog zunächst das Ziel G zu beweisen. Wenn der Aufruf von G gelingt, dann schlägt
der Aufruf von \+G fehl. Wenn der Aufruf von G fehlschlägt, dann gelingt der Aufruf
von \+G. Der Aufruf von G könnte aber auch in eine Endlosschleife führen.
Betrachten wir wieder das Beispiel von oben zusammen mit der folgenden Definition
eines Prädikats vogel/1:
vogel(amsel).
vogel(strauss).
vogel(fink).
vogel(pinguin).
vogel(adler).
vogel(habicht).
Wir möchten nun wissen, welche Vögel fliegen können. Dazu stellen wir die Anfrage
19
?- vogel(V), \+ flugunfaehiger_Vogel(V).
Wir fragen also Prolog nach einem Vogel, der nicht ein flugunfähiger Vogel ist. Prolog ruft
als erstes das Ziel vogel(V) auf. Dieses Ziel gelingt mit V=amsel. Nun ruft Prolog damit
das zweite Ziel der Anfrage auf, also \+ flugunfaehiger_Vogel(amsel). Da dies eine
Negation as Failure ist, ruft Prolog zunächst das Ziel flugunfaehiger_Vogel(amsel)
auf, was fehlschlägt. Daher gelingt der Aufruf von \+ flugunfaehiger_Vogel(amsel)
und Prolog liefert die Antwort V=amsel.
Wenn man mit einem Strichpunkt nach einer weiteren Antwort fragt, macht Prolog ein
Redo des ersten Ziels vogel(V) und findet dafür eine zweite Lösung V=strauss. Damit
ruft Prolog das zweite Ziel der Anfrage auf, also \+ flugunfaehiger_Vogel(strauss).
Da dies eine Negation as Failure ist, ruft Prolog zunächst das Ziel
flugunfaehiger_Vogel(strauss) auf, was gelingt. Daher schlägt der Aufruf von
\+ flugunfaehiger_Vogel(strauss) fehl. Dieser Fehlschlag des zweiten Ziels der Anfrage bewirkt ein Redo des ersten Ziels vogel(V). Prolog findet dafür eine dritte Lösung
V=fink. . . .
Setzen Sie bitte die Analyse des Programmablaufs ab hier fort! Sie können sich als
Hilfe von Prolog einen Trace anzeigen lassen. Der Trace, den GNU-Prolog ausgibt ist da
etwas detaillierter und für diese Aufgabe hilfreicher als der von SWI-Prolog. GNU-Prolog
ist ebenso wie SWI-Prolog auf unseren Rechnern installiert (Aufruf mit gprolog).
Stellen Sie nun die Anfrage umgekehrt:
?- \+ flugunfaehiger_Vogel(V), vogel(V).
Erklären Sie, was dabei passiert und warum die Reihenfolge der Ziele in der Anfrage für
die Menge der gelieferten Antworten eine Rolle spielt und daher die Negation as Failure
nicht exakt der logischen Negation entspricht!
Abzugeben: Text (Fortsetzung der Analyse des Programmablaufs, Erklärung)
Aufgabe 23 Unter dem Herbrand-Universum einer Menge von Funktoren versteht man
die Menge aller Terme, die man aus diesen Funktoren bilden kann. Betrachten wir zum
Beispiel einen zweistelligen Funktor f, in Prolog geschrieben als f/2, und eine Konstante a, in Prolog geschrieben a/0. Dann enthält das Herbrand-Universum der Menge
{f/2, a/0} den Term f(f(a,a),f(a,f(a,a))):
in_Herbrand_Universum_fa(a).
in_Herbrand_Universum_fa(f(T1,T2)) :in_Herbrand_Universum_fa(T1),
in_Herbrand_Universum_fa(T2).
?- in_Herbrand_Universum_fa(f(f(a,a),f(a,f(a,a)))).
yes
Schreiben Sie ein Prolog-Programm zur Ermittlung der Anzahl der Vorkommen der Konstanten a in einem Term aus dem Herbrand-Universum der Menge {f/2, a/0}! Beispiel
für eine Anfrage und Prologs Antwort:
20
?- anzahl_a(f(f(a,a),f(a,f(a,a))),Anzahl).
Anzahl = 5
Abzugeben: Programm
Aufgabe 24 Unter den Zahlen spielen die natürlichen Zahlen 0, 1, 2, 3, . . . eine besondere Rolle. Man kann sie induktiv charakterisieren durch die folgenden beiden Regeln:
• Die Zahl 0 ist eine natürliche Zahl.
• Wenn n eine natürliche Zahl ist, dann ist auch n + 1 eine natürliche Zahl.
Übersetzen Sie diese beiden Regeln in zwei Prolog-Programm-Klauseln, die durch Rekursion ein Prolog-Prädikat natuerliche_Zahl/1 mit folgendem Verhalten definieren!
?- natuerliche_Zahl(N).
N = 0 ;
N = 1 ;
N = 2 ;
N = 3 ;
...
Das Prädikat natuerliche_Zahl/1 zählt also bei Aufruf mit einer Variablen N als Argument genau die Menge der natürlichen Zahlen auf. Verwenden Sie in Ihrem Programm
keine eingebauten Prädikate von Prolog außer is/2!
Wenn M eine Menge ist und man durch Rekursion ein Prädikat definieren kann, das
die Menge M aufzählt, sagen wir auch, die Menge M sei rekursiv aufzählbar (englisch
recursively enumerable oder einfach r.e.). Die Menge der natürlichen Zahlen ist also
rekursiv aufzählbar.
Erweitern Sie nun Ihr Programm um ein weiteres Prädikat quadratzahl/1, das die
Menge der Quadratzahlen aufzählt:
?- quadratzahl(Q).
Q = 0 ;
Q = 1 ;
Q = 4 ;
Q = 9 ;
...
Sie sehen, dass auch die Menge der Quadratzahlen rekursiv aufzählbar ist.
Abzugeben: Programm
Aufgabe 25 Schreiben Sie ein Prolog-Programm, das zu jeder gegebenen Liste von a’s
und b’s die entsprechende Liste berechnet, bei der jedes a durch ein b und jedes b
durch ein a ersetzt ist! So wird z.B. aus der Liste [a,b,b,a,a] die Liste [b,a,a,b,b].
Verwenden Sie in Ihrem Programm keine eingebauten Prädikate von Prolog!
Abzugeben: Programm
Aufgabe 26 Schreiben Sie ein Prolog-Programm, das zu einer Liste von Zahlen die
Liste der Quadrate dieser Zahlen berechnet! So wird z.B. aus der Liste [2,8,3] die
21
Liste [4,64,9]. Verwenden Sie in Ihrem Programm keine eingebauten Prädikate von
Prolog außer is/2!
Abzugeben: Programm
Aufgabe 27 Wir wollen Punkte in der Ebene darstellen als zusammengesetzte Prologterme, z.B. den Punkt (2, 3) als Term punkt(2,3). Wenn man Punkte P1 , . . . , Pn
miteinander durch Strecken verbindet, und zwar P1 mit P2 , P2 mit P3 , . . . , Pn−1 mit
Pn , dann erhält man einen Streckenzug. Einen solchen Streckenzug wollen wir in Prolog
darstellen durch einen zusammengesetzten Term streckenzug([P1 , . . . ,Pn ]) mit Funktor streckenzug/1 und der Liste der Punkte als Argument. Beispiel: Die drei Punkte
P1 = (2, 3), P2 = (1, 1) und P3 = (3, 2) definieren einen Streckenzug
P1
P3
P2
,
den wir durch den Prologterm streckenzug([punkt(2,3),punkt(1,1),punkt(3,2)])
darstellen. Die Länge eines Streckenzuges ist die Summe der Längen seiner Strecken.
Schreiben Sie ein Prolog-Programm zur Bestimmung des Abstandes zweier Punkte voneinander sowie der Länge eines Streckenzuges! Beispiele für Anfragen an Prolog und
Prologs Antworten:
?- abstand(punkt(2,3),punkt(1,1),Abstand).
Abstand = 2.23606797749979
?- streckenzuglaenge(streckenzug([punkt(2,3),punkt(1,1),punkt(3,2)]),Laenge).
Laenge = 4.47213595499958
Abzugeben: Programm
Aufgabe 28 (Tail-Recursion mit Akkumulator) Für jede natürliche Zahl n sei f (n)
die Summe der reziproken Werte der ganzen Zahlen von 1 bis n, also
f (n) =
n
X
1
k=1
k
=
1 1 1
1
+ + + ··· + .
1 2 3
n
Dann ist z.B. f (3) = 1 + 12 + 13 = 1, 8333 . . . . Um f (n) mit Prolog zu berechnen, müssen
wir f als zweistelliges Prädikat, sagen wir sumrez/2 definieren, wobei sumrez(N,S)
bedeutet, dass S = f (N) ist. Definieren Sie zunächst das Prädikat sumrez/2 durch
Rekursion! Dann definieren Sie ein Prädikat sumrezakk/2, das dasselbe Ergebnis wie
sumrez/2 liefern soll, aber mit Tail-Recursion unter Verwendung eines Akkumulators!
Hierzu müssen Sie ein dreistelliges Hilfsprädikat, sagen wir sumrezakk1/3 verwenden,
wobei sumrezakk1(N,A,S) bedeutet, dass S = A+f (N) ist. Dabei ist A der Inhalt des Akkumulators. Stellen Sie eine Anfrage zur Berechnung von f (1 000 000) mit sumrezakk/2
sowie mit sumrez/2! Wie verhält sich Prolog in beiden Fällen?
Abzugeben: Programm, Anfragen, Text
22