3 Logikprogrammierung

Transcription

3 Logikprogrammierung
Logik für Informatiker
3
Wintersemester 2012/13
Logikprogrammierung
P ROLOG ermöglicht
• deklarative Programmierung
• kompakte Programme
• agile Softwareentwicklung, rapid Prototyping
Die Auswertungsstrategie der SLDNF–Resolution benutzt
• Tiefensuche
• Backtracking
• Unifikation
Prof. Dr. Dietmar Seipel
298
Logik für Informatiker
3.1
Wintersemester 2012/13
Grundlagen von P ROLOG
Datentypen und Datenstrukturen
• Die Beschränkung auf wenige Basisdatentypen und einen einzigen
komplexen Datentyp, nämlich die Strukturen (Terme), der generisch ist
und alle anderen Datentypen subsumiert, standardisiert die
Datenstrukturen ganz entscheident.
• Es gibt keine expliziten Typdeklarationen.
Man kann aber rein syntaktisch zwischen P ROLOG–Atomen (Strings),
Zahlen und Variablensymbolen unterscheiden; aus diesen kann man
komplexere Strukturen (Terme) bilden.
• Es gibt eine große Kollektion von generischen Operationen, die auf alle
Strukturen (Terme) anwendbar sind – und somit auf alle Datentypen.
Prof. Dr. Dietmar Seipel
299
Logik für Informatiker
Wintersemester 2012/13
Methoden und Kontrollstrukturen
• Prädikate realisieren Methoden. Alle Parameter – auch die
Rückgabewerte – werden als Argumente eines Prädikats übergeben.
Kommentare helfen zu erkennen, welche Argumente die Eingabe bzw.
die Ausgabe bilden.
• Manche Prädikate kann man mit unterschiedlichen Bindungsmustern
aufrufen, und für dieselbe Eingabe kann es unterschiedliche Ausgaben
geben (relationales Programmieren).
Die meisten Prädikate sind aber funktional.
• Häufig werden Meta–Prädikate verwendet.
Auch Kontrollstrukturen basieren auf Meta–Prädikaten. Zusätzlich zu
den Standardkontrollstrukturen, wie Verzweigungen (if–then–else),
Schleifen (for, while), und Rekursion, können benutzerdefinierte
Kontrollstrukturen in Form von Meta–Prädikaten gebildet werden.
Prof. Dr. Dietmar Seipel
300
Logik für Informatiker
Wintersemester 2012/13
Strukturen in P ROLOG
P ROLOG–Atom: z.B. a, books, ’Books’, kt_321_xy
Konstante: P ROLOG–Atom | Number: z.B. books, 0, 123
Variable: beginnend mit Großbuchstaben oder mit “_”
z.B. X, Y, Books, _, _A, _a
Funktor (Funktions– bzw. Prädikatensymbol):
Operator | P ROLOG–Atom: z.B. +, -, ≤, ancestor
Struktur: Konstante | Variable | Funktor(Struktur, . . . , Struktur)
z.B. +(1,7), ancestor(’William’,’Elizabeth’)
Listen sind spezielle Strukturen zum Funktor “.”:
[a,b,c,d] = .(a, [b,c,d])
+(1,7) ist äquivalent zu 1+7 (Infix–Notation).
Prof. Dr. Dietmar Seipel
301
Logik für Informatiker
Wintersemester 2012/13
P ROLOG–Klauseln
Eine P ROLOG–Klausel (Regel, Fakt) ist eine Infix–Struktur der Form
Kopf :– Rumpf.
“:-” spricht man dabei als “falls” aus. Falls der Rumpf leer ist (Fakt), so
kann man “:-” weglassen und kurz “Kopf” schreiben.
Der Regelrumpf kann folgende Junktoren enthalten:
• Konjunktion “,”,
• Disjunktion “;”, und
• Negation “\+”, “not”.
Eine negierte Formel kann man als “\+ F” oder als “not(F)” schreiben.
Prof. Dr. Dietmar Seipel
302
Logik für Informatiker
Wintersemester 2012/13
Prädikatensymbole: ancestor, parent
Regel:
ancestor(X, Z) :ancestor(X, Y), parent(Y, Z).
Eine Elternteil Z eines Vorfahren Y von X ist ebenfalls ein Vorfahre.
In der PL1 könnte man das wie folgt schreiben:
∀X∀Y ∀Z ( ancestor(X, Y ) ∧ parent(Y, Z) → ancestor(X, Z) )
Fakten:
parent(a, b).
parent(b, c).
parent(c, d).
Goal:
?- ancestor(a, Z).
Prof. Dr. Dietmar Seipel
303
Logik für Informatiker
Wintersemester 2012/13
Prädikatensymbole: likes, woman, nice, loves
Regeln:
likes(george, Y) :woman(Y),
likes(Y, books).
likes(mary, Y) :( nice(Y)
; loves(Y, cats) )
Fakten:
woman(mary).
likes(mary, books).
loves(george, cats).
Goal:
?- likes(george, Y).}
Prof. Dr. Dietmar Seipel
304
Logik für Informatiker
Wintersemester 2012/13
Das Prädikat likes besteht aus 2 Regeln und einem Fakt. Diese decken
unterschiedliche Fälle ab:
• Die erste Regel besagt, daß George alle Frauen mag, die Bücher mögen.
• Die zweite Regel besagt, daß Mary alles, was schön (nice) ist, und
alle Lebewesen, die Katzen lieben, mag.
Ein Fakt besagt außerdem, daß Mary Bücher mag.
In der prozeduralen Programmierung könnte man eine Fallunterscheidung
in einem case–Statement ausdrücken.
Die likes–Regel zu Mary mit dem disjunktiven Rumpf könnte man in
zwei separate Regeln zerlegen. Die Bündelung der Information zu Mary –
zu der man eventuell auch noch das Fakt hinzunehmen könnte – erscheint
aber softwaretechnisch auch sehr sinnvoll. Da uns momentan keine
Information zu nice vorliegt, ist der erste Teil der Regel inaktiv.
Prof. Dr. Dietmar Seipel
305
Logik für Informatiker
Wintersemester 2012/13
Die Bündelung liefert folgende Regel mit einem disjunktiven Regelrumpf:
likes(mary, Y) :( nice(Y)
; loves(Y, cats)
; Y = books ).
Diese ist äquivalent zu drei einzelnen Regeln:
likes(mary,
nice(Y).
likes(mary,
loves(Y,
likes(mary,
Y) :Y) :cats).
books).
Die Reihenfolge der Regeln und Fakten zum selben Prädikatensymbol ist –
wie in klassischen Programmiersprachen auch – wichtig.
Prof. Dr. Dietmar Seipel
306
Logik für Informatiker
Wintersemester 2012/13
Notation
Wenn man geeignete Operatoren (Infix, Präfix, Postfix) definiert, dann kann
man die P ROLOG–Klauseln etwas natürlicher notieren:
X has_ancestor Z :X has_ancestor Y and
Y has_parent Z.
george likes Y :Y is_a_woman and Y likes books.
mary likes Y :Y is_nice or Y loves cats.
mary is_a_woman.
mary likes books.
george loves cats.
Man könnte H :- B sogar als B implies H schreiben.
Prof. Dr. Dietmar Seipel
307
Logik für Informatiker
Wintersemester 2012/13
Anfragen in P ROLOG
Ein P ROLOG–Interpreter versucht ein Goal durch Inferenz zu beweisen.
Dies erfolgt Top–Down vom Goal ausgehend durch DFS–Durchlauf
(Tiefensuche, Depth–First–Search) des SLD–Baumes.
Beispiel (Anfragen)
?- likes(george, Y).
Y = mary
?- likes(X,
X = george,
X = mary, Y
X = mary, Y
Prof. Dr. Dietmar Seipel
Y).
Y = mary ;
= george ;
= books
308
Logik für Informatiker
Wintersemester 2012/13
P ROLOG gibt eine Antwort auf eine Anfrage zurück:
• Falls die Anfrage erfolgreich beantwortet wurde, so gibt P ROLOG die
erzeugte Variablenbelegung als Antwort zurück; falls keine Variablen
belegt wurden, so ist die Antwort true.
• Falls die Anfrage erfolglos beantwortet wurde, so ist die Antwort
false.
Bei erfolgreicher Beantwortung der Anfrage kann man hinter der Antwort
einen Strichpunkt gefolgt von Return eingeben. Dieser stößt Backtracking
an, so daß P ROLOG versucht eine weitere Antwort zu finden.
Wenn man nur Return eingibt, so ist die Anfrageauswertung beendet.
Ebenso ist die Anfrageauswertung nach der Antwort false automatisch
sofort beendet.
Prof. Dr. Dietmar Seipel
309
Logik für Informatiker
Wintersemester 2012/13
Auswertung von Anfragen in P ROLOG
• Die Auswertung von P ROLOG–Regeln erfolgt Top–Down mittels der
Methode der SLDNF–Resolution: aus einer Anfrage an das Kopfatom
einer Regel werden Unteranfragen an die Rumpfatome erzeugt.
• Dies entspricht dem Vorgehen bei der Abarbeitung von prozeduralen
Programmiersprachen.
• Falls ein Rumpfatom mehrere Antworten liefert, so wird zuerst mit
einer solchen Antwort weitergerechnet (Tiefensuche); falls die
Berechnung später fehlschlägt, so kann mit der nächsten Antwort
fortgefahren werden (Backtracking).
• In der Praxis sind viele P ROLOG–Prädikate aber funktional: aus einer
Eingabe wird genau eine Ausgabe erzeugt.
Prof. Dr. Dietmar Seipel
310
Logik für Informatiker
Wintersemester 2012/13
Aus der Anfrage
← likes(X, Y )
wird mittels der Ersetzung X 7→ george und der Regel
r1 = likes(george, Y ) ← woman(Y ) ∧ likes(Y , books)
eine Folge von Unteranfragen erzeugt:
← woman(Y ) ∧ likes(Y , books)
Aufgrund des Fakts f1 wird die erste Unteranfrage mit Y 7→ mary
beantwortet. Der neue Wert für Y wird in der zweiten Unteranfrage sofort
berücksichtigt, so daß wir also
← likes(mary, books)
zu beantworten haben. Aufgrund des Fakts f2 ist die Antwort dafür ja.
Prof. Dr. Dietmar Seipel
311
Logik für Informatiker
Wintersemester 2012/13
SLD–Baum
← likes(X, Y )
r1
9
← woman(Y ) ∧ likes(Y, books)
f1
?
← likes(mary, books)
r2
← nice(books)
∨ loves(books, cats)
failure
r2
?
f2
q
← nice(Y ) ∨ loves(Y, cats)
2
{X 7→ mary, Y 7→ books}
f3
success
?
2
{X →
7 mary, Y 7→ george}
f2
j
success
2
{X 7→ george, Y 7→ mary}
success
Der SLD–Baum faßt alle SLD–Ableitungen zusammen. Jeder success–Ast
gibt eine Antwort.
Prof. Dr. Dietmar Seipel
312
Logik für Informatiker
Wintersemester 2012/13
Kontrollprimitive, welche über die PL1 hinausgehen:
• assert und retract verändern die interne Datenbank von
P ROLOG; clause sucht in dieser.
• call und apply rufen Goals auf, die vorher zusammengebaut
werden können.
• Der Cut “!” friert die bisherige Variablenbelegung in der aktuellen
Regel ein.
• fail ist ein Goal, das immer fehl schlägt.
• Meta–Prädikate wir findall und maplist realisieren komplexe
Kontrollstrukturen.
• ...
Prof. Dr. Dietmar Seipel
313
Logik für Informatiker
Wintersemester 2012/13
Anfrage mit einem Meta–Prädikat
Mit dem Meta–Prädikat findall/3 kann man alle Antworten auf eine
Anfrage bestimmen:
?- findall( [X, Y],
likes(X, Y),
Pairs ).
Pairs = [[george,mary], [mary,george], [mary,books]].
Das D DK erlaubt sogar folgende äquivalente Mengenschreibweise:
?- Pairs <= { [X, Y] | likes(X, Y) }.
Pairs wird als die Liste aller Paare [X, Y] bestimmt, für die
likes(X, Y) gilt.
Prof. Dr. Dietmar Seipel
314
Logik für Informatiker
Wintersemester 2012/13
Listen sind spezielle P ROLOG–Strukturen mit dem binären Funktor “.”.
Liste: [a,b,c,d] = .(a,.(b,.(c,.(d,[]))))
Listenkonstruktion:
Falls X und Xs bereits gebunden (mit Werten belegt) sind,
so ist [X|Xs] die Liste, die man erhält, wenn man
das Element X an die Liste Xs vorne anhängt.
Für X = a und Xs = [b,c,d] ist [X|Xs] = [a,b,c,d].
Listenzerlegung:
Falls X und Xs ungebunden sind, so liefert der Aufruf [X|Xs] =
[a,b,c,d] die Belegungen X = a und Xs = [b,c,d]; man
kann eine Liste also in ihren Kopf X und den Rest Xs zerlegen.
leere Liste: []
Prof. Dr. Dietmar Seipel
315
Logik für Informatiker
Wintersemester 2012/13
Listenkonstruktion und Listenzerlegung erfolgen also mittels desselben
Aufrufs Xs = [Head|Tail].
Die folgenden beiden Prädikate bestimmen das erste Listenelement Head
und den Rest Tail der Liste.
list_to_head(Xs, Head) :Xs = [Head|_].
list_to_tail(Xs, Tail) :Xs = [_|Tail].
Um eine “singleton variable warning” zu vermeiden, wird der
jeweils nicht benötigte Listenteil mittels einer anonymen Variable “_”
(Wildcard) bezeichnet.
Prof. Dr. Dietmar Seipel
316
Logik für Informatiker
Wintersemester 2012/13
Die Listenschreibweise
[X1 , . . . ,Xn ]
nennt man Syntactic Sugar. Eine Liste ist eigentlich eine stark
verschachtelte binäre Struktur:
.( X1 , .(X2 , . . . ,.(Xn ,[]))).
{z
}
|{z}
|
Tail
Head
Somit ist Xs = [Head|Tail] = .(Head, Tail).
Für Xs = [a,b,c,d] = .(a,.(b,.(c,.(d,[])))) bestimmt
der Aufruf Xs = [Head|Tail], oder
.(a,.(b,.(c,.(d,[])))) = .(Head, Tail),
mittels Unifikation Head = a und Tail = .(b,.(c,.(d,[]))).
Prof. Dr. Dietmar Seipel
317
Logik für Informatiker
Wintersemester 2012/13
Die Listenkonstruktion aus einem gegebenen Kopf und einem Rest erfolgt –
wie bereits gezeigt – auch mittels des Aufrufs Xs = [Head|Tail]:
head_and_tail_to_list(Head, Tail, Xs) :Xs = [Head|Tail].
Dasselbe Prädikat kann man auch benutzen, um eine gegebene Liste in
Kopf und Rest zu zerlegen:
?- head_and_tail_to_list([a], [b,c,d], Xs).
Xs = [a,b,c,d].
?- head_and_tail_to_list(Head, Tail, [a,b,c,d]).
Head = [a], Tail = [b,c,d].
Prof. Dr. Dietmar Seipel
318
Logik für Informatiker
Wintersemester 2012/13
Arbeiten mit Termen
• Aufbau und Zerlegung: =../2
• functor/3
• arg/3
?- likes(mary, books) =.. Xs.
Xs = [likes, mary, books].
?- functor([a,b,c,d], F, N).
F = ’.’, N = 2.
?- arg(N, [a,b,c,d], A).
N = 1, A = a ;
N = 2, A = [b,c,d].
Prof. Dr. Dietmar Seipel
319
Logik für Informatiker
Wintersemester 2012/13
Eingabe und Ausgabe
• Einlesen einer P ROLOG–Datei: consult/1, [...]
• Eingabe von Termen: read/1,2
• Ausgabe von Termen: write/1,2
?- [’sources/projects/teaching/likes.pl’].
% sources/.../likes.pl compiled 0.00 sec, 0 bytes
?- read(X).
|: likes(mary, cats).
X = likes(mary, cats).
?- write(likes(mary, cats)).
likes(mary, cats)
Die zweistelligen Prädikate read/2 und write/2 greifen auf Dateien zu.
Prof. Dr. Dietmar Seipel
320
Logik für Informatiker
Wintersemester 2012/13
Man kann mittels assert/1 auch dynamisch die Datenbasis von P ROLOG
erweitern:
?- read(X), assert(X).
|: likes(mary, cats).
X = likes(mary, cats).
Nachfolgende Aufrufe können die erweiterte Datenbasis benutzen:
?- likes(mary, cats).
true.
Mittels retract/1 kann man in der Datenbasis von P ROLOG löschen.
Prof. Dr. Dietmar Seipel
321
Logik für Informatiker
Wintersemester 2012/13
Aufruf dynamischer Goals
Man kann zur Laufzeit mittels =../2 Goals zusammenbauen und mittels
call/1 aufrufen:
?- read(P), Goal =.. [P, X, Y], call(Goal).
|: likes.
P = likes, Goal = likes(X, Y),
X = george, Y = mary.
Dies geht noch eleganter, wenn man stattdessen apply/2 verwendet, denn
Goal =.. [P,X1,...,Xn], call(Goal) ist äquivalent zu
apply(P, [X1,...,Xn]).
Der Aufruf read(P), P(X,Y) ist in P ROLOG nicht erlaubt, da eine
Variable – hier P – nicht an der Stelle eines Prädikatensymbols stehen kann.
Prof. Dr. Dietmar Seipel
322
Logik für Informatiker
Wintersemester 2012/13
Rekursion: das Prädikat member
/* member(?X, +Xs) <X is a member of the list Xs. */
member(X, [X|_]).
member(X, [_|Xs]) :member(X, Xs).
?- member(b, [a,b,c]).
true.
Ein Element liegt in einer Liste, falls es das erste Listenelement
(Listenkopf) ist, oder falls es in der Restliste liegt (rekursiver Aufruf).
Genauer gesagt wird eine Substitution gesucht, die X mit einem Element der
Liste Xs unifiziert.
Prof. Dr. Dietmar Seipel
323
Logik für Informatiker
Wintersemester 2012/13
In dieser kompakten Notation wird die Eingabeliste bereits im Regelkopf in
den Listenkopf und die Restliste zerlegt.
1. Der Kopf der ersten Regel testet auch gleich, ob der Listenkopf mit
dem gesuchten Element unifizierbar ist.
2. Die zweite Regel sucht in der Restliste rekursiv weiter.
Zur Verdeutlichung geben wir im folgenden die entsprechende Langfassung
an:
member(X, Xs) :list_to_head(Xs, Head),
X = Head.
member(X, Xs) :list_to_tail(Xs, Tail),
member(X, Tail).
Prof. Dr. Dietmar Seipel
324
Logik für Informatiker
Wintersemester 2012/13
Relationales Programmieren
member: Element × List 7→ Boolean
?- member(b, [a,b,c]).
true.
?- member(X, [a,b,c]).
X = a ;
X = b ;
X = c
Beim Aufruf member(X, Xs) sind X und Xs nicht funktional
voneinander abhängig. Stattdessen realisiert member/2 eine
n : m–Beziehung (Relation) zwischen Listen und ihren Elementen.
Prof. Dr. Dietmar Seipel
325
Logik für Informatiker
Wintersemester 2012/13
Das Prädikat member/2 definiert eine virtuelle Relation:
member
Element
List
a
[a,b,c]
b
[a,b,c]
c
[a,b,c]
a
[a,b]
...
...
Diese Relation ist unendlich, sie wird aber nie berechnet.
Es werden meist nur die Elemente einer gegebenen Liste bestimmt.
Prof. Dr. Dietmar Seipel
326
Logik für Informatiker
Wintersemester 2012/13
Tracing
Man kann die Anfrageauswertung in P ROLOG mittels trace schrittweise
verfolgen:
?- trace.
true.
[trace] ?- member(X, [a,b]).
Call: (6) member(X, [a, b]) ? creep
Exit: (6) member(a, [a, b]) ? creep
X = a ;
Der initiale Aufruf member(X, [a,b]) wird zuerst mit dem Fakt
member(X, [X|_]) unifiziert. Dabei wird X auf a gesetzt und die
anonyme Variable (Wildcard) _ auf [b].
Somit ergibt sich die erste Antwort X = a.
Prof. Dr. Dietmar Seipel
327
Logik für Informatiker
Wintersemester 2012/13
Die Eingabe des Strichpunkts hinter der Antwort X = a stößt
Backtracking an:
Redo:
Call:
Exit:
Exit:
X = b ;
(6)
(7)
(7)
(6)
member(X,
member(X,
member(b,
member(b,
[a, b]) ? creep
[b]) ? creep
[b]) ? creep
[a, b]) ? creep
Nun wird der Aufruf member(X, [a,b]) mit dem Kopf
member(X, [_|Xs]) der Regel unifiziert.
Dabei wird X belassen, und es wird _ auf a und Xs auf [b] gesetzt.
Der neue Aufruf member(X, [b]) ergibt sich aus dem Rumpf der
Regel. Er wird mittels des Fakts mit X = b beantwortet (zweite Antwort).
Prof. Dr. Dietmar Seipel
328
Logik für Informatiker
Wintersemester 2012/13
Die Eingabe des Strichpunkts hinter der Antwort X = b stößt noch einmal
Backtracking an:
Redo:
Call:
Fail:
Fail:
Fail:
Fail:
false.
(8)
(9)
(9)
(8)
(7)
(6)
member(X,
member(X,
member(X,
member(X,
member(X,
member(X,
[b]) ? creep
[]) ? creep
[]) ? creep
[b]) ? creep
[b]) ? creep
[a, b]) ? creep
Nun wird der Aufruf member(X, [b]) mit dem Kopf
member(X, [_|Xs]) der Regel unifiziert.
Dabei wird X belassen, und es wird _ auf b und Xs auf [] gesetzt.
Der neue Aufruf member(X, []) ergibt sich aus dem Rumpf der Regel.
Er kann nicht beantwortet werden. Also ergibt sich die Antwort false.
Prof. Dr. Dietmar Seipel
329
Logik für Informatiker
Wintersemester 2012/13
Bindungsmuster
Einige Prädikate, wie z.B. das boolean_and/3, können mit
unterschiedlichen Bindungsmustern für die Argumente aufgerufen werden:
/* boolean_and(U, V, W) <W is derived as the boolean conjunction
of the truth values U and V. */
boolean_and(0,
boolean_and(0,
boolean_and(1,
boolean_and(1,
0,
1,
0,
1,
0).
0).
0).
1).
Hier kann man beliebig viele (auch 0) Argumente mit Werten versehen und
die restlichen Werte berechnen.
Prof. Dr. Dietmar Seipel
330
Logik für Informatiker
Wintersemester 2012/13
Wenn die ersten beiden Argumente gebunden sind, dann realisiert das
Prädikat eine Funktion:
?- boolean_and(1, 0, W).
W = 0 .
Man kann die Berechnung umkehren, und nach allen Paaren von
Wahrheitswerten U und V fragen, deren Konjunktion 0 ist; dann realisiert
das Prädikat eine n : m–Beziehung (Relation):
?- boolean_and(U, V, 0).
U = 0, V = 0 ;
U = 0, V = 1 ;
U = 1, V = 0
Dabei wird durch die Eingabe von ; hinter einer Lösung die Berechnung
der nächsten Lösung angestoßen.
Prof. Dr. Dietmar Seipel
331
Logik für Informatiker
Wintersemester 2012/13
Arithmetik
Im Gegensatz zum Unifikationsprädikat =/2 wertet das Prädikat is/2 den
arithmetischen Ausdruck zu seiner rechten aus und unifiziert das Ergebnis
mit dem Ausdruck zu seiner linken:
?- X = 3, Y is e^X + sin(X).
X = 3, Y = 20.2267.
Der entsprechende Aufruf mit =/2 würde Y dagegen lediglich mit dem
Term e^3 + sin(3) unifizieren:
?- X = 3, Y = e^X + sin(X).
X = 3, Y = e^3 + sin(3).
Prof. Dr. Dietmar Seipel
332
Logik für Informatiker
Wintersemester 2012/13
Symbolisches Differenzieren
Das Prädikat diff/3 differenziert beim Aufruf diff(F, X, DF) einen
Funktionsterm F symbolisch nach der Variablen X – die beim Aufruf durch
eine Konstante instanziiert sein muß – und liefert DF als Ergebnis:
?- diff(e^x + sin(x), x, F).
F = e^x + cos(x).
?- diff(x^7 + 3 * x^6, x, F).
F = 7 * x^6 + 3 * 6 * x^5.
Dasselbe Prädikat diff/3 kann bei einem anderen Bindungsmuster zum
symbolischen Integrieren benutzt werden, wenn stattdessen X und DF
gebunden sind.
Bei den Aufrufen des folgenden Prädikats diff/3 muß die Unbekannte,
nach der differenziert wird, durch ein P ROLOG–Atom repräsentiert sein.
Prof. Dr. Dietmar Seipel
333
Logik für Informatiker
Wintersemester 2012/13
Die ersten beiden Regeln behandeln die Spezialfälle, daß F identisch ist
mit X, oder daß F ein anderes P ROLOG–Atom ist:
% diff(+F, +X, ?DF) <% diff(?F, +X, +DF) <diff(X, X, 1) :!.
diff(C, X, 0) :atomic(C).
Der Cut, “!”, weist P ROLOG an, keine weiteren Regeln zu versuchen, falls
die aktuelle Regel anwendbar ist. Ohne den Cut würde der Aufruf
diff(x,x,DF) sowohl das Resultat DF=1 (die richtige Antwort aus
Regel 1) als auch DF=0 (die falsche Antwort aus Regel 2) liefern.
Prof. Dr. Dietmar Seipel
334
Logik für Informatiker
Wintersemester 2012/13
diff(X^N, X, N*X^M) :N > 0,
M is N - 1.
diff(sin(X), X, cos(X)).
diff(e^X, X, e^X).
diff(F+G, X, DF+DG) :diff(F, X, DF),
diff(G, X, DG).
diff(C*F, X, C*DF) :atomic(C),
!,
diff(F, X, DF).
Der Cut in der letzten Regel ist hier eigentlich nicht erforderlich. Er wird
erst dann wichtig, wenn man das Regelsystem noch erweitert.
Prof. Dr. Dietmar Seipel
335
Logik für Informatiker
Wintersemester 2012/13
3.2
SLD– und SLDNF–Resolution
Definites Logikprogramm, Anfrage
1. Ein definites Logikprogramm besteht aus Horn–Klauseln in
Implikations–Notation mit jeweils genau einem Kopfatom:
Fakt:
A
Regel:
A ← B1 ∧ . . . ∧ Bm , m ≥ 0.
Fakten stellen Wissen ohne Vorbedingung dar, Regeln mit m ≥ 1
konditionales Wissen mit Vorbedingung β = B1 ∧ . . . ∧ Bm .
2. Horn–Klauseln in Implikations–Notation ohne Kopfatom
repräsentieren Anfragen:
Goal:
← B1 ∧ . . . ∧ Bm , m ≥ 0.
Dabei sind A und die Bi prädikatenlogische Atome.
Prof. Dr. Dietmar Seipel
336
Logik für Informatiker
Wintersemester 2012/13
Die SLD–Resolution (Linear Resolution with Selection Function for
Definite Clauses) wurde ursprünglich zum automatischen Theorembeweisen
für allgemeine Klauseln verwendet, vgl. J.A. Robinson (1965).
• Sei s eine Selektionsfunktion, die aus jedem Goal ein Atom auswählt.
• Sei G ein Goal und r = A ← β eine definite Regel:
G = ← β1 ∧ B ∧ β2 .
Dabei seien β1 und β2 Konjunktionen von Atomen und s(G) = B das
von s selektierte Atom. Falls M GU (A, B) = θ existiert, dann heißt
G′ = ← ( β1 ∧ β ∧ β2 ) θ
eine Resolvente von G und r bezüglich s.
Falls r ein Fakt ist (d.h. β ist leer), dann ist G′ um ein Atom kürzer als G.
Prof. Dr. Dietmar Seipel
337
Logik für Informatiker
Wintersemester 2012/13
Die SLD–Resolution ergibt sich aus der binären Resolution der PL1.
Bekanntlich ist ein Goal G = ← β1 ∧ B ∧ β2 äquivalent zu einer
Disjunktion
α1 = ¬β1 ∨ ¬B ∨ ¬β2 ,
und eine Regel r = A ← β ist äquivalent zu einer Disjunktion
α2 = A ∨ ¬β.
Durch die bekannte binäre Resolution der PL1 erhält man mittels eines
allgemeinsten Unifikators θ von A und B eine neue Disjunktion
α = (¬β1 ∨ ¬β ∨ ¬β2 )θ,
die wieder einem Goal G′ = ← ( β1 ∧ β ∧ β2 ) θ entspricht.
Prof. Dr. Dietmar Seipel
338
Logik für Informatiker
Wintersemester 2012/13
SLD–Widerlegung
• Sei P ein definites Logikprogramm und Q eine Anfrage.
Eine SLD–Widerlegung von h P, Q i ist eine endliche Folge
h Gi i0≤i≤n , wobei G0 = Q und Gn = 2,
von Goals zusammen mit einer Folge h ri i1≤i≤n von Regeln und einer
Folge h θi i1≤i≤n von Substitutionen, wobei für alle 1 ≤ i ≤ n gilt:
– ri ist eine Variante einer Regel aus P ,
– Gi ist eine Resolvente aus Gi−1 und ri bezüglich s, und
– θi ist der benutzte allgemeinste Unifikator.
Die Substitution θ = θ1 · θ2 · . . . · θn heißt Antwortsubstitution.
• Die SLD–Widerlegung einer atomaren Anfrage Q = ← A ist
äquivalent zu dem Beweis, daß die Instanz Aθ, welche man Antwort
nennt, aus P abgeleitet werden kann.
Prof. Dr. Dietmar Seipel
339
Logik für Informatiker
Wintersemester 2012/13
• Ein SLD–Widerlegungsbaum veranschaulicht eine SLD–Widerlegung:
G0
?
G1
?
G2
?
r1
r2
r3
G3
..
.
..
.
rn
?
Gn = 2
Man kann eine SLD–Widerlegung natürlich auch einfach als eine
r1
r2
r3
rn
lineare Kette G0 −→
G1 −→
G2 −→
. . . −→
Gn = 2 repräsentieren,
wenn man die Kanten mit den verwendeten Regeln markiert.
Prof. Dr. Dietmar Seipel
340
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Resolution)
Für das DATALOG–Programm P = { r, f1 , f2 }, mit
r = p ← a ∧ b,
f1 = a,
f2 = b,
erhalten wir mit der Selektionsfunktion sl eine SLD–Widerlegung zum
Goal Q = ← p.
←p
?
←a∧b
?
←b
?
2
Prof. Dr. Dietmar Seipel
r
f1
f2
341
Logik für Informatiker
Wintersemester 2012/13
In Klauselschreibweise
r = p ∨ ¬a ∨ ¬b,
f1 = a,
f2 = b,
erhalten wir folgende Folge von binären Resolutionen zum Goal Q = ¬p :
¬p
r
?
¬a ∨ ¬b
f1
?
¬b
f2
?
2
Prof. Dr. Dietmar Seipel
342
Logik für Informatiker
Wintersemester 2012/13
Nicht–Lineare Resolution
Für die inkonsistente Klauselmenge
F = { p ∨ q, p ∨ ¬q, ¬p ∨ q, ¬p ∨ ¬q }
gibt es keine lineare Widerlegung, aber folgende Resolutionsableitung:
p∨q
p ∨ ¬q ¬p ∨ q
Rp
¬p ∨ ¬q
R¬p
s
2
+
Diese Klauselmenge ist keine Hornklauselmenge.
Für eine inkonsistente Hornklauselmenge gibt es immer eine lineare
Ableitung der leeren Klausel, die mit einer Integritätsbedingung startet.
Prof. Dr. Dietmar Seipel
343
Logik für Informatiker
Wintersemester 2012/13
Substitutionen
Wir schreiben eine Substitution [X1 |t1 , . . . Xn |tn ], bei der alle Ersetzungen
parallel angewendet werden, als Menge θ = { X1 7→ t1 , . . . , Xn 7→ tn }.
θ definiert eine Abbildung von einer Struktur t auf eine neue Struktur tθ:
• Für eine Konstante c gilt cθ = t.
• Für eine Variable X erhalten wir Xθ = t, falls es eine Ersetzung
X 7→ t ∈ θ gibt, und ansonsten Xθ = X.
• Für eine komplexe Struktur gilt f (t1 , . . . , tn )θ = f (t1 θ, . . . , tn θ).
Dann entspricht die Substitution θ1 = [X|Z][Z|Y ] der Substitution
[X|Y, Z|Y ], da X zuerst durch Y und dieses dann durch Z ersetzt wird.
Sie ist damit verschieden von θ2 = [X|Z, Z|Y ].
Für t = f (X, Y, Z) gilt z.B. tθ1 = f (Y, Y, Y ) und tθ2 = f (Z, Y, Y ).
Prof. Dr. Dietmar Seipel
344
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Resolution)
Wir betrachten das nicht–rekursive, definite Logikprogramm
P = { r, f1 , f2 , f3 , f4 } und die Anfrage Q = ← grandparent(X, Z):
r = grandparent(X, Z) ← parent(X, Y ) ∧ parent(Y, Z),
f1 = parent(’Elizabeth’, ’Queen Mum’),
f2 = parent(’Elizabeth’, ’George’),
f3 = parent(’Charles’, ’Elizabeth’),
f4 = parent(’William’, ’Charles’).
Aus G0 = Q erhält man mittels r und θ1 = ∅ die Resolvente
G1 = ← parent(X, Y ) ∧ parent(Y, Z).
’Queen Mum’
’George’
f1
f2
’Elizabeth’
f3
’Charles’
f4
’William’
Daraus kann man mit der Selektionsfunktion sl , welche stets das linkeste
Literal eines Goals auswählt, z.B. folgende SLD–Widerlegungen erhalten:
Prof. Dr. Dietmar Seipel
345
Logik für Informatiker
Wintersemester 2012/13
• Mittels f3 und θ2 = { X 7→ ’Charles’, Y 7→ ’Elizabeth’ } erhalten wir
G2 = ← parent(’Elizabeth’, Z).
– Mittels f1 und θ3 = { Z 7→ ’Queen Mum’ } erhalten wir G3 = 2
und die Antwortsubstitution
θ = { X 7→ ’Charles’, Y 7→ ’Elizabeth’, Z 7→ ’Queen Mum’ }.
– Mittels f2 und θ3 = { Z 7→ ’George’ } erhalten wir ebenfalls
G3 = 2; nun ist die Antwortsubstitution
θ ′ = { X 7→ ’Charles’, Y 7→ ’Elizabeth’, Z 7→ ’George’ }.
• Mittels f4 und f3 erhalten wir aus G1 die Antwortsubstitution
θ ′′ = { X 7→ ’William’, Y 7→ ’Charles’, Z 7→ ’Elizabeth’ }.
Später werden wir alle SLD–Widerlegungen in einem SLD–Baum
zusammenfassen.
Prof. Dr. Dietmar Seipel
346
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Resolution)
Betrachten wir das rekursive, definite Logikprogramm P = { r, e, f } mit
den folgenden Regeln (bzw. Fakten):
r = anc(X, Y ) ← par (X, Z) ∧ anc(Z, Y ),
e = anc(X, X),
f = par (a, b).
Zur Vereinfachung benutzen wir anstelle der üblichen bereichsbeschränkten
Regel
e′ = anc(X, Y ) ← par (X, Y )
das Fakt e = anc(X, X) mit Variablen zusammen mit der rekursiven
Regel r. Dadurch wird hier anc als die reflexive, transitive Hülle von par
berechnet.
Prof. Dr. Dietmar Seipel
347
Logik für Informatiker
Wintersemester 2012/13
Dann kann das Goal G0 = ← anc(X, b) von allen Selektionsfunktionen
mittels der Regel r zu
G1 = ← A1 ∧ A2 ,
mit A1 = par (X, Z ′ ) und A2 = anc(Z ′ , b), resolviert werden.
Sei sl (sr ) die Selektionsfunktion, welche stets das linkeste (rechteste)
Literal eines Goals auswählt.
1. sl wählt das erste (linkeste) Atom A1 = par (X, Z ′ ) in G1 .
Dieses kann nur mit dem Fakt f = A = par (a, b) resolviert werden.
Mit M GU (A1 , A) = { X 7→ a, Z ′ 7→ b } erhält man das verkürzte Goal
G2 = ← anc(b, b).
Eine weitere Resolution mit dem Fakt e würde die leere Klausel
G3 = ← 2 liefern, und somit die Antwort anc(a, b).
Prof. Dr. Dietmar Seipel
348
Logik für Informatiker
Wintersemester 2012/13
2. sr wählt das zweite (rechteste) Atom A2 = anc(Z ′ , b) in G1 .
Dieses kann mit Varianten
r ′′ = anc(X ′′ , Y ′′ ) ← par (X ′′ , Z ′′ ) ∧ anc(Z ′′ , Y ′′ ),
e′′ = anc(X ′′ , X ′′ ),
der Regeln r bzw. e resolviert werden. Sei A′′ jeweils deren Regelkopf.
• Mit r ′′ , A′′ = anc(X ′′ , Y ′′ ) und
M GU (A2 , A′′ ) = { X ′′ 7→ Z ′ , Y ′′ 7→ b }
erhält man das verlängerte Goal
G′2 = ← par (X, Z ′ ) ∧ par (Z ′ , Z ′′ ) ∧ anc(Z ′′ , b).
• Mit e′′ , A′′ = anc(X ′′ , X ′′ ) und
M GU (A2 , A′′ ) = { X ′′ 7→ b, Z ′ 7→ b }
erhält man das verkürzte Goal
G′′2 = ← par (X, b).
Prof. Dr. Dietmar Seipel
349
Logik für Informatiker
Wintersemester 2012/13
Eine weitere Resolution mit dem Fakt f würde
M GU (par (X, b), f ) = { X 7→ a }
und die leere Klausel G′′3 = ← 2 liefern, und somit die Antwort
anc(a, b).
Mittels des Faktes e kann das Goal G0 = ← anc(X, Y ) von allen
Selektionsfunktionen zur leeren Klausel G′1 = ← 2 resolviert werden.
Dabei wird
M GU (anc(X, Y ), anc(X, X)) = { Y 7→ X }
berechnet, und somit die Antwort anc(X, X).
Diese Antwort enthält noch das Variablensymbol X.
Prof. Dr. Dietmar Seipel
350
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Widerlegungsbäume)
Wir betrachten weiterhin das definite Logikprogramm P = { r, e, f },
jetzt aber mit den Anfragen
Q1 = ← anc(X, b),
Q2 = ← anc(X, Y ).
Die Regeln (bzw. Fakten) sind folgende:
r
=
anc(X, Y ) ← par (X, Z) ∧ anc(Z, Y ),
e
=
anc(X, X),
f
=
par (a, b).
Anders als in Q1 , ist in Q2 auch die zweite Argumentposition mit einem
Variablensysmbol – hier Y – belegt. Deswegen kann eine Antwort
berechnet werden, die noch Variablensymbole enthält.
Prof. Dr. Dietmar Seipel
351
Logik für Informatiker
Wintersemester 2012/13
Im folgenden werden ein SLD–Widerlegungsbaum T1 für Q1 und die
zugehörige Grundversion T1 θ angegeben:
T1 :
← anc(X, b)
?9
← par (X, Z ′ ) ∧ anc(Z ′ , b)
?9
← anc(b, b)
r ′ = anc(X ′ , Y ′ ) ← par (X ′ , Z ′ ) ∧ anc(Z ′ , Y ′ )
θ1 = { X ′ 7→ X, Y ′ 7→ b }
f ′ = par (a, b)
θ2 = { X 7→ a, Z ′ 7→ b }
e′ = anc(X ′′ , X ′′ )
?9
2
θ3 = { X ′′ 7→ b }
Die berechnete Antwort ist anc(a, b).
Prof. Dr. Dietmar Seipel
352
Logik für Informatiker
Wintersemester 2012/13
Die Grundinstanz für die berechnete Antwort anc(a, b) ist folgende:
T1 θ:
← anc(a, b)
?9
← par (a, b) ∧ anc(b, b)
?9
← anc(b, b)
?9
2
Prof. Dr. Dietmar Seipel
r ′ θ = anc(a, b) ← par (a, b) ∧ anc(b, b)
f ′ θ = par (a, b)
e′ θ = anc(b, b)
θ = θ1 · θ2 · θ3 = { X 7→ a, X ′ 7→ a,
X ′′ 7→ b, Y ′ 7→ b, Z ′ 7→ b }
353
Logik für Informatiker
Wintersemester 2012/13
Die Top–Down–Auswertung kann auch nicht–bereichsbeschränkte definite
Logikprogramme behandeln.
Sie hat keine Probleme mit Fakten, die Variablen enthalten, wie etwa
e = anc(X, X).
T2 :
← anc(X, Y )
?)
2
e = anc(X, X)
θ = { Y 7→ X }
Allerdings ist die erzeugte Antwortsubstitution θ dann unter Umständen
keine Grundsubstitution. Im obigem Beispiel für Q2 = ← anc(X, Y ) ist
die berechnete Antwort anc(X, X) dann ein Fakt mit Variablen, das zeigt,
daß die beiden Grundinstanzen anc(a, a) und anc(b, b) aus P ableitbar sind.
Prof. Dr. Dietmar Seipel
354
Logik für Informatiker
Wintersemester 2012/13
Vollständigkeit und Korrektheit der SLD–Resolution
Sei P ein definites Logikprogramm und Q = ← A eine atomare Anfrage.
1. Es gibt genau dann eine SLD–Widerlegung mit der Antwort Aθ,
wenn Aθ im minimalen Modell MP von P liegt.
2. Dieses Resultat ist unabhängig von der verwendeten
Selektionsfunktion s.
P ROLOG verwendet immer die Selektionsfunktion sl , welche stets das
linkeste (erste) Literal eines Goals auswählt.
Durch Umstellung der Atome in den Regelrümpfen kann der
Programmierer de facto eine andere Selektionsfunktion simulieren.
Prof. Dr. Dietmar Seipel
355
Logik für Informatiker
Wintersemester 2012/13
SLD–Bäume
Sei P ein definites Logikprogramm, Q eine Anfrage und s eine
Selektionsfunktion.
s
Der SLD–Baum TP,Q
faßt alle möglichen SLD–Ableitungen zusammen:
s
1. Die Knoten von TP,Q
sind mit Goals markiert,
s
und die Kanten von TP,Q
sind mit Regeln r ∈ P markiert.
s
2. Die Wurzel von TP,Q
ist mit Q markiert.
3. Ein Knoten v, der mit einem Goal G markiert ist, hat für jede
SLD–Resolvente G′ , die man aus G und einer Regel r ∈ P bezüglich s
bilden kann, einen Nachfolgerknoten v ′ .
4. Dieser ist mit G′ markiert, und die Kante h v, v ′ i ist mit r markiert.
Prof. Dr. Dietmar Seipel
356
Logik für Informatiker
Wintersemester 2012/13
Jeder mit dem Goal G = 2 endende Ast eines SLD–Baumes entspricht
einer SLD–Widerlegung bzw. einem SLD–Widerlegungsbaum:
• Die Blätter dieser Äste werden als erfolgreich (success) markiert.
• Alle anderen Blätter werden als erfolglos (failure) markiert.
• Daneben kann es noch unendliche Äste im Baum geben.
s1
s2
Zwei SLD–Bäume TP,Q
und TP,Q
zu unterschiedlichen
Selektionsfunktionen s1 , s2 haben immer dieselben Antworten
(success–Äste).
Sie unterscheiden sich aber in der Regel hinsichtlich ihrer failure–Äste bzw.
ihrer unendlichen Äste.
Prof. Dr. Dietmar Seipel
357
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Bäume)
Wir betrachten das nicht–rekursive, definite Logikprogramm
P = { r, f1 , f2 , f3 , f4 } und die Anfrage Q = ← grandparent(X, Z):
r = grandparent(X, Z) ← parent(X, Y ) ∧ parent(Y, Z),
f1 = parent(’Elizabeth’, ’Queen Mum’),
f2 = parent(’Elizabeth’, ’George’),
f3 = parent(’Charles’, ’Elizabeth’),
f4 = parent(’William’, ’Charles’).
In diesem Falle sind alle SLD–Bäume – unabhängig von der
Selektionsfunktion – endlich.
sl
Wir zeigen unten den SLD–Baum TP,Q
zur Selektionsfunktion sl .
Prof. Dr. Dietmar Seipel
358
Logik für Informatiker
Wintersemester 2012/13
← grandparent(X, Z)
r
?
← parent(X, Y ) ∧ parent(Y, Z)
f1
9
f2
← parent(’Queen Mum’, Z )
← parent(’George’, Z )
failure
failure
)
2
{ X 7→ ’Charles’,
Y 7→ ’Elizabeth’,
Z 7→ ’Queen Mum’ }
success
Prof. Dr. Dietmar Seipel
f3
f4
j
z
← parent(’Elizabeth’, Z )
f1
f2
?
2
{X →
7 ’Charles’,
Y 7→ ’Elizabeth’,
Z →
7 ’George’ }
success
← parent(’Charles’, Z )
f3
?
2
{X →
7 ’William’,
Y →
7 ’Charles’,
Z 7→ ’Elizabeth’ }
success
359
Logik für Informatiker
Wintersemester 2012/13
Beispiel (SLD–Bäume)
Wir betrachten wieder das rekursive, definite Logikprogramm
P = { r, e, f } und die Anfrage Q = ← anc(X, b):
r = anc(X, Y ) ← par (X, Z) ∧ anc(Z, Y ),
e = anc(X, X),
f = par (a, b).
Die SLD–Bäume zu den Selektionsfunktionen sl bzw. sr haben dieselben
Antworten (success–Äste).
• Allerdings ist in diesem Falle Tl endlich,
• wohingegen Tr unendliche Äste hat.
Für sr könnte man in obigem Beispiel die unendlichen Äste vermeiden,
indem man die Reihenfolge der Rumpfatome invertiert.
Prof. Dr. Dietmar Seipel
360
Logik für Informatiker
Wintersemester 2012/13
Der SLD–Baum Tl zur Selektionsfunktion sl ist endlich:
← anc(X, b)
Tl :
r
← par (X, Z ′ ) ∧ anc(Z ′ , b)
f
?
← anc(b, b)
r
← par (b, Z ′′ ) ∧ anc(Z ′′ , b)
failure
Prof. Dr. Dietmar Seipel
e
R
2
{ X 7→ b }
success
e
R
2
{ X 7→ a }
success
361
Logik für Informatiker
Wintersemester 2012/13
Der SLD–Baum Tr zur Selektionsfunktion sr ist unendlich, hat aber die
gleichen Antwortsubstitutionen in den success–Blättern wie Tl :
← anc(X, b)
Tr :
r
e
R
← par (X, Z ′ ) ∧ anc(Z ′ , b)
r
e
←
par (X, Z ′ )
∧
par (Z ′ , Z ′′ )
r
)
← par (X, Z ′ ) ∧ par (Z ′ , Z ′′ )
∧ par(Z ′′ , Z ′′′ ) ∧ anc(Z ′′′ , b)
r
e
R
∧
R
anc(Z ′′ , b)
2
{ X 7→ b }
success
← par (X, b)
e
f
s
R
← par (X, Z ′ ) ∧ par (Z ′ , b)
f
?
2
{ X 7→ a }
success
← par (X, a)
failure
(unendlicher Ast)
Prof. Dr. Dietmar Seipel
362
Logik für Informatiker
Wintersemester 2012/13
Steuerung der SLD–Resolution
Der Logikprogrammierer kann bei gegebener Selektionsfunktion durch
• die Reihenfolge der Regeln und
• die Reihenfolge der Rumpfatome in den Regeln
die Abarbeitung steuern:
• Wenn wir in unserem letzten Beispiel die Regel e vor die Regel r
stellen, dann wandern im neuen SLD–Baum Tr′ zur Selektionsfunktion
sr die mit e markierten Kanten vor die mit r markierten.
• Bei Backtracking findet der LWR–Durchlauf von Tr′ nun die beiden
Antworten, bevor der unendliche Ast zu einer Dauerschleife führt.
• Wenn wir dagegen die Reihenfolge der Rumpfatome von r vertauschen,
dann hat der neue SLD–Baum Tr′′ zu sr dieselbe Struktur wie der alte
SLD–Baum Tl zu sl : r ′′ = anc(X, Y ) ← anc(Z, Y ) ∧ par (X, Z).
Prof. Dr. Dietmar Seipel
363
Logik für Informatiker
Wintersemester 2012/13
• Generell ist es am besten die nicht–rekursive Regel e vor die rekursive
Regel r zu stellen:
e = anc(X, X),
r = anc(X, Y ) ← par (X, Z) ∧ anc(Z, Y ).
• Für die Standard–Selektionsfunktion sl sollte in der rekursiven Regel r
der nicht–rekursive Aufruf par (X, Z) vor dem rekursiven Aufruf
anc(Z, Y ) stehen. Dies garantiert die Terminierung für azyklische
par –Relationen.
• Bei zyklischer par –Relation enthält der SLD–Baum Tl aber leider
trotzdem unendliche Äste. Für die Fakten
f1 = par (a, b),
f2 = par (b, a),
und die Anfrage Q = ← anc(a, Y ) generiert die alternierende
Verwendung von f1 und f2 abwechselnd die Antworten Y 7→ a und Y 7→ b.
Prof. Dr. Dietmar Seipel
364
Logik für Informatiker
Wintersemester 2012/13
← anc(a, Y )
Tl :
e
r
R
2
← par (a, Z ′ ) ∧ anc(Z ′ , Y )
{Y →
7 a}
success
f1
?
← anc(b, Y )
e
r
R
2
← par (b, Z ′′ ) ∧ anc(Z ′′ , Y )
{ Y 7→ b }
f2
success
?
← anc(a, Y )
(unendlicher Ast)
Prof. Dr. Dietmar Seipel
365
Logik für Informatiker
Wintersemester 2012/13
Beispiel (Redundanz in SLD–Bäumen)
Wir betrachten nun das etwas erweiterte rekursive, definite Logikprogramm
P = { r, e, f1 , f2 } und die Anfrage Q = ← anc(X, Y ):
r = anc(X, Y ) ← par (X, Z) ∧ anc(Z, Y ),
e = anc(X, X),
f1 = par (a, b), f2 = par (b, c).
Der SLD–Baum Tl zur Selektionsfunktion sl ist endlich.
Die success–Äste leiten der Reihe nach die folgenden Grundinstanzen ab:
• success–Äste 1 bis 3: tc(a, c), tc(a, b), tc(b, c);
• success–Ast 4: tc(a, a), tc(b, b), tc(c, c).
Die Unteranfrage ← anc(c, Y ) wurde redundant in zwei success–Ästen
(1 und 3) mit Y 7→ c beantwortet. Derartige Redundanz tritt bei Graphen
mit längeren Ketten (hier: a → b → c) noch verstärkt auf.
Prof. Dr. Dietmar Seipel
366
Logik für Informatiker
Wintersemester 2012/13
← anc(X, Y )
Tl :
r
e
R
2
← par (X, Z ′ ) ∧ anc(Z ′ , Y )
{ X 7→ Y }
success
f1
f2
R
← anc(b, Y )
r
e
←
par (b, Z ′′ )
f2
∧
← anc(c, Y )
r
R
anc(Z ′′ , Y
par (c, Z ′′ )
2
)
←
{ X 7→ a, Y 7→ b }
success
?
e
R
∧
z
anc(Z ′′ , Y
failure
2
)
{ X 7→ b, Y 7→ c }
success
← anc(c, Y )
r
e
R
← par (c, Z ′′′ ) ∧ anc(Z ′′′ , Y ) 2
{ X 7→ a, Y 7→ c }
failure
success
Prof. Dr. Dietmar Seipel
367
Logik für Informatiker
Wintersemester 2012/13
Normale Logikprogramme
Syntax:
1. Ein normales Logikprogramm besteht aus Regeln in
Implikations–Notation mit jeweils genau einem Kopfatom:
Fakt:
A
Regel:
A ← B1 ∧ . . . ∧ Bm ∧ not C1 ∧ . . . ∧ not Cn .
Fakten stellen Wissen ohne Vorbedingung dar,
Regeln mit m ≥ 1 oder n ≥ 1 konditionales Wissen mit Vorbedingung.
2. Regeln mit n = 0 und ohne Kopfatom repräsentieren Anfragen:
Goal:
← B1 ∧ . . . ∧ Bm .
Dabei sind A, die Bi und die Ci Atome. not nennt man Default–Negation.
In P ROLOG schreibt man diese als “not(C)” oder “\+ C”.
Prof. Dr. Dietmar Seipel
368
Logik für Informatiker
Wintersemester 2012/13
SLDNF–Resolution
Die SLDNF–Resolution erweitert die SLD–Resolution auf normale
Logikprogramme durch ein Konzept namens Negation–as–Finite–Failure
zur Behandlung negativer Literale not A:
• Wenn im Rahmen einer SLDNF–Resolution ein negatives Literal not A
abgeleitet werden soll, so wird eine neue SLDNF–Resolution für das
Goal G0 = ← A gestartet.
• Falls diese erfolglos abbricht, so ist not A abgeleitet; sonst war der
Ableitungsversuch für not A erfolglos.
not A bedeutet, daß A nicht ableitbar ist, und nicht etwa, daß ¬A ableitbar
ist. Damit sind die beiden wesentlich verschieden.
Zur Illustration der SLDNF–Resolution wollen wir damit im folgenden
Zwei–Personen–Gewinnspiele mit azyklischen Übergangsgraphen behandeln.
Prof. Dr. Dietmar Seipel
369
Logik für Informatiker
Wintersemester 2012/13
Beispiel (Zwei–Personen–Gewinnspiele)
• Bei Tic–Tac–Toe markieren die Spieler abwechselnd Felder auf einem
3 × 3–Brett. Ein Spieler gewinnt, wenn er als erster eine Reihe, Spalte
oder Diagonale zu besetzt.
• Wenn beide Spieler allerdings optimal spielen, so gehen die Spiele
Unentschieden aus:
Prof. Dr. Dietmar Seipel
370
Logik für Informatiker
Wintersemester 2012/13
• Für Tic–Tac–Toe ist der Übergangsgraph azyklisch:
Es gibt 765 wesentlich verschiedene Positionen. Achsenspiegelungen
erzeugen strukturell gleiche Positionen.
• Für Schach ist der Übergangsgraph zyklisch.
Prof. Dr. Dietmar Seipel
371
Logik für Informatiker
Wintersemester 2012/13
Beispiel (Zwei–Personen–Gewinnspiele mit SLDNF)
Wir betrachten das normale Logikprogramm P = { r, f1 , f2 } und die
Anfrage Q = ← win(X) :
r = win(X) ← move(X, Y ) ∧ not win(Y ),
f1 = move(b, c), f2 = move(a, b).
a
-
b
-
c
Ein Spieler kann in Position X gewinnen, wenn es einen Zug von X nach Y
gibt, so daß man in Position Y nicht gewinnen kann.
• Offenbar kann man in Position b gewinnen, da man nach c ziehen kann,
und da es keinen Zug von c aus gibt; c ist eine Verlustposition.
• In Position a kann man nicht gewinnen, da man nach b ziehen muß,
und da b ja dann eine Gewinnposition für den Gegner ist.
Prof. Dr. Dietmar Seipel
372
Logik für Informatiker
Wintersemester 2012/13
Sei G0 = Q:
• Wir starten eine SLDNF–Resolution für G0 = ← win(X) :
– h G0 , r i 7→ G1 = ← move(X, Y ) ∧ not win(Y )
– h G1 , f1 i 7→ G2 = ← not win(c)
• Wir starten eine SLDNF–Resolution für H0 = ← win(c) :
– h H0 , r i 7→ H1 = ← move(c, Y ) ∧ not win(Y )
– H1 kann bezüglich sl nicht weiter resolviert werden,
und es gibt keine Möglichkeit zum Backtracking.
– Deshalb schlägt die SLDNF–Resolution für H0 fehl.
• Damit ist die SLDNF–Resolution für G0 erfolgreich mit der
Substitution { X 7→ b, Y 7→ c }, und somit ist win(b) abgeleitet.
Prof. Dr. Dietmar Seipel
373
Logik für Informatiker
Wintersemester 2012/13
• Backtracking innerhalb der SLDNF–Resolution für G0 liefert:
– h G1 , f2 i 7→ G′2 = ← not win(b)
• Wir starten eine SLDNF–Resolution für H0′ = ← win(b) :
– h H0′ , r i 7→ H1′ = ← move(b, Y ) ∧ not win(Y )
– h H1′ , f1 i 7→ H2′ = ← not win(c)
– Da die SLDNF–Resolution für ← win(c) bekanntermaßen
fehlschlägt, ist die SLDNF–Resolution für H0′ = ← win(b)
erfolgreich.
• Damit bricht die aktuelle Berechnungslinie erfolglos ab.
• Jetzt gibt es keine weiteren Alternativen zum Backtracking innerhalb
der SLDNF–Resolution für G0 .
Prof. Dr. Dietmar Seipel
374
Logik für Informatiker
Wintersemester 2012/13
?- trace.
[trace]
Call:
Call:
Exit:
Call:
Call:
Call:
Fail:
Fail:
Exit:
Exit:
X = b ;
?- win(X).
(6) win(X)
(7) move(X, Y)
(7) move(b, c)
(7) not(win(c))
(8) win(c)
(9) move(c, Y’)
(9) move(c, Y’)
(8) win(c)
(7) not(win(c))
(6) win(b)
Fail:
Redo:
Exit:
Call:
Call:
Call:
Exit:
Call:
(7)
(7)
(7)
(7)
(8)
(9)
(9)
(9)
not(win(c))
move(X, Y)
move(a, b)
not(win(b))
win(b)
move(b, Y’)
move(b, c)
not(win(c))
Call:
Call:
Fail:
Fail:
Exit:
Exit:
Fail:
Fail:
Fail:
(10) win(c)
(11) move(c, Y’’)
(11) move(c, Y’’)
(10) win(c)
(9) not(win(c))
(8) win(b)
(7) not(win(b))
(7) move(X, Y)
(6) win(X)
false.
Prof. Dr. Dietmar Seipel
375
Logik für Informatiker
Wintersemester 2012/13
Zyklisches, nicht–terminierendes Verhalten
Wir betrachten nun das normale Logikprogramm P = { r, f3 } und die
Anfrage Q = ← win(X) :
r = win(X) ← move(X, Y ) ∧ not win(Y ),
f3 = move(c, c).
Die Relation move/2 ist hier zyklisch.
• In diesem Fall führt die SLDNF–Resolution für G0 = Q zu einer
Dauerschleife, da immer wieder das Goal ← win(c) auftritt.
• Deswegen kann weder win(c) noch ¬win(c) abgeleitet werden.
Das P ROLOG–System X SB kann solche Dauerschleifen durch eine
modifizierte Auswertung mit Zyklentest vermeiden.
Prof. Dr. Dietmar Seipel
376
Logik für Informatiker
Wintersemester 2012/13
führt zur Dauerschleife:
zyklische Relation move/2:
win(X) :move(X, Y),
not(win(Y)).
move(c, c).
Prof. Dr. Dietmar Seipel
[trace]
Call:
Call:
Exit:
^ Call:
Call:
Call:
Exit:
^ Call:
Call:
...
?- win(X).
(6) win(X)
(7) move(X, Y)
(7) move(c, c)
(7) not(win(c))
(8) win(c)
(9) move(c, Y’)
(9) move(c, c)
(9) not(win(c))
(10) win(c)
377
Logik für Informatiker
Wintersemester 2012/13
Abhängigkeitsgraph
Es gibt ein DDK–Tool zur Veranschaulichung der Abhängigkeitsgraphen
von P ROLOG–Programmen. Da hier die Regeln keine Namen haben,
werden die Regel–Knoten mit den entsprechenden File–Namen markiert.
Prof. Dr. Dietmar Seipel
378
Logik für Informatiker
3.3
Wintersemester 2012/13
Suche in Graphen
Labyrinth:
Prof. Dr. Dietmar Seipel
379
Logik für Informatiker
Wintersemester 2012/13
Berechnung einfacher Pfade mittels Backtracking
Das Prädikat graph_search/2 berechnet einen einfachen Pfad von
einem gegebenen Knoten zu einer Senke des Graphen:
% graph_search(+Node, ?Path) <graph_search(X, Path) :graph_search(X, [X], Path).
Es wird ein weiteres Prädikat graph_search/3 mit demselben
Prädikatensymbol aber einer anderen Stelligkeit aufgerufen.
Der Graph ist in Form von Fakten für die Prädikate graph_arc/2 und
graph_sink/1 gegeben.
Notation für die Argumente in der Kommentarzeile:
+: gebunden, -: frei, ?: gebunden oder frei
Prof. Dr. Dietmar Seipel
380
Logik für Informatiker
Wintersemester 2012/13
Path =
Visited [Y1 =Y, . . . ,Yn =Z]
-X -Y
-Z
• Beim Aufruf graph_search(X, Visited, Nodes) mit
einem gebundenen Argument X, das keine Senke ist, und einer Liste
Visited von bereits besuchten Knoten, wird
– eine Kante von X zu einem bisher nicht besuchten
Nachfolgerknoten Y benutzt, und dann
– ein Weg Path von Y zu einer Senke Z berechnet, der Y und die
Knoten in Visited nicht benutzt.
Falls kein Weg von Y zu einer Senke gefunden werden kann, so muß
ein anderer Nachfolgerknoten von X benutzt werden (Backtracking).
• Das Ergebnis Nodes = [X|Path] ist ein einfacher Pfad von X zu
einer Senke des Graphen.
Prof. Dr. Dietmar Seipel
381
Logik für Informatiker
Wintersemester 2012/13
Das Prädikat graph_search/3 ist aufgrund seiner zweiten Regel
rekursiv:
% graph_search(+Node, +Visited, ?Path) <graph_search(X, _, [X]) :graph_sink(X).
graph_search(X, Visited, [X|Path]) :Path =
graph_edge(X, Y),
[Y1 =Y,
Visited
-X-Y
not(member(Y, Visited)),
write(user, ’->’), write(user, Y),
graph_search(Y, [Y|Visited], Path).
. . . ,Yn =Z]
-Z
Die Terminierung wird dadurch gewährleistet, daß Knoten nicht mehrfach
besucht werden dürfen.
Prof. Dr. Dietmar Seipel
382
Logik für Informatiker
Wintersemester 2012/13
• Der initiale Aufruf graph_search(X, [X], Path) berechnet
einen einfachen Pfad von X zu einer Senke des Graphen.
– Falls X bereits eine Senke ist, so bestimmt die erste Regel für
graph_search/3 den Pfad Path als die leere Liste.
– Ansonsten wählt die rekursive zweite Regel mittels graph_edge
(X, Y) einen Nachfolgerknoten Y und sucht von dort aus weiter.
• Bei Backtracking können weitere einfache Pfade berechnet werden.
– Dazu können in der zweiten Regel alternative Nachfolgerknoten Y
betrachtet werden.
– In der obigen Implementierung kann über eine Senke hinaus zu
anderen Senken weitergesucht werden, indem man die zweite Regel
anstelle der ersten verwendet.
Prof. Dr. Dietmar Seipel
383
Logik für Informatiker
Wintersemester 2012/13
Implizites und explizites Backtracking
In P ROLOG wird automatisch (implizit) Backtracking verwendet.
In einer prozeduralen Sprache muß man das Backtracking explizit
implementieren.
Falls man obigen Code eins–zu–eins in einer prozeduralen Umgebung
umsetzen würde, so könnte ein Aufruf graph_edge(X, Y) nur einen
einzigen Nachfolgerknoten Y von X produzieren – falls es dann keinen Pfad
von Y zu einer Senke gibt, so würde die Berechnung fehlschlagen.
Außerdem könnte nur maximal eine Lösung ermittelt werden.
Wenn man die Graph–Suche prozedural mit explizitem Backtracking
realisiert, so ergibt sich mehr Code als bei der P ROLOG–Implementierung.
Prof. Dr. Dietmar Seipel
384
Logik für Informatiker
Wintersemester 2012/13
Repräsentation des Graphen mit P ROLOG–Fakten
Labyrinth:
a
b
c
d
e
f
g
h
i
6
Prof. Dr. Dietmar Seipel
-
graph_arc(i,
graph_arc(i,
graph_arc(h,
graph_arc(g,
graph_arc(d,
graph_arc(d,
graph_arc(a,
graph_arc(b,
f).
h).
g).
d).
e).
a).
b).
c).
graph_sink(c).
385
Logik für Informatiker
Wintersemester 2012/13
Die folgende Regel symmetrisiert das Prädikat graph_arc/2:
graph_edge(X, Y) :( graph_arc(X, Y)
; graph_arc(Y, X) ).
Dadurch ist es nicht nötig, für die Kanten die Rückrichtung explizit
anzugeben:
graph_edge(i,
graph_edge(f,
graph_edge(i,
graph_edge(h,
...
Prof. Dr. Dietmar Seipel
f).
i).
h).
i).
386
Logik für Informatiker
Wintersemester 2012/13
Berechnung
• Das Prädikat graph_search/2 benutzt Tiefensuche, und es
berechnet einfache Pfade (ohne doppelte Knoten).
• Beim Aufruf graph_search(+Node, ?Path) können alle
einfachen Pfade von Node zu einer Senke (graph_sink) über
Backtracking berechnet werden:
?- graph_search(i, Path).
->f->h->g->d->e->a->b->c
Path = [i, h, g, d, a, b, c]
?- graph_search(e, Path).
->d->a->b->c
Path = [e, d, a, b, c] ;
->g->h->i->f
false.
Prof. Dr. Dietmar Seipel
387
Logik für Informatiker
Wintersemester 2012/13
• Würde man eine weitere Kante graph_arc(e, b) in den Graphen
einfügen (die Wand zwischen e und b einreisen), so gäbe es einen
weiteren einfachen Pfad [e, b, c] von e zur Senke c.
• Man kann alle Antworten mittels Backtracking und findall/3
bestimmen:
graph_arc(e, b).
?- findall( Path,
graph_search(e, Path),
Paths ).
...
Paths = [ [e, d, a, b, c], [e, b, c] ]
Prof. Dr. Dietmar Seipel
388
Logik für Informatiker
Wintersemester 2012/13
Das Meta–Prädikat findall/3
Finden aller Lösungen für ein Goal:
findall( X,
goal(X),
Xs )
Das D DK erlaubt sogar folgende äquivalente Mengenschreibweise:
Xs <= { X | goal(X) }
Weitere wichtige Meta–Prädikate sind checklist/2 und maplist/3
für Listen sowie die Prädikate für Schleifen (Kontrollstrukturen) aus der
Loops–Bibliothek (z.B. foreach-do).
Prof. Dr. Dietmar Seipel
389
Logik für Informatiker
3.4
Wintersemester 2012/13
Sortieren und Suchbäume
Im folgenden werden einige wohlbekannte Algorithmen zum Sortieren und
Suchen in P ROLOG formuliert.
Vorzüge von P ROLOG liegen hierbei
• im einfachen Umgang mit Datenstruktuen (Listen, Bäume, X ML) und
• in der kompakten Realisierbarkeit von Fallunterscheidungen durch
verschiedene Regeln.
Die Algorithmen sind typischerweise rekursiv. Die Rekursion wird durch
die kompakten Listenzugriffe gut formulierbar.
Auch Meta–Prädikate tragen zur eleganten Implementierung bei.
Prof. Dr. Dietmar Seipel
390
Logik für Informatiker
Wintersemester 2012/13
Quicksort in P ROLOG
% quicksort(+List, ?Sorted_List) <quicksort([], []) :!.
quicksort([X|Xs], Ys) :quicksort_divide(X, Xs, Xs1, Xs2),
quicksort(Xs1, Ys1),
quicksort(Xs2, Ys2),
append(Ys1, [X|Ys2], Ys).
Der eigentliche Aufwand steckt in der Listenaufteilung (Divide); der
Merge–Schritt ist einfach (append).
Prof. Dr. Dietmar Seipel
391
Logik für Informatiker
Wintersemester 2012/13
[X|Xs] = [4,3,7,2,5,1,6]
quicksort_divide
R
Xs1 = [3,2,1]
Xs2 = [7,5,6]
quicksort
?
?
Ys1 = [1,2,3]
Ys2 = [5,6,7]
append
R
Ys = [ 1,2,3, 4, 5,6,7 ]
Prof. Dr. Dietmar Seipel
392
Logik für Informatiker
Wintersemester 2012/13
quicksort_divide(X, Xs, Xs1, Xs2) :findall( X1,
( member(X1, Xs),
X1 < X ),
Xs1 ),
findall( X2,
( member(X2, Xs),
X2 > X ),
Xs2 ).
append([], Ys, Ys).
append([X|Xs], Ys, [X|Zs]) :append(Xs, Ys, Zs).
Prof. Dr. Dietmar Seipel
393
Logik für Informatiker
Wintersemester 2012/13
Mittels des Meta–Prädikats sublist/3 kann man die Listenaufteilung
noch etwas kompakter formulieren:
quicksort_divide(X, Xs, Xs1, Xs2) :sublist(>(X), Xs, Xs1),
sublist(<(X), Xs, Xs2).
Ein Element X1 von Xs kommt nach Xs1, falls >(X, X1) gilt; in
Infix–Notation bedeutet dies X > X1. Analog kommen die Elemente X2 von
Xs mit <(X, X2) nach Xs2; in Infix–Notation bedeutet dies X < X2.
Falls ein Element mehrfach in der zu sortierenden Liste vorkommt, so ist es
trotzdem nur einmal in der Resultatsliste enthalten, denn das Pivot–Element
X wird nicht in Xs1 oder Xs2 aufgenommen.
Dies könnte man ändern, indem man > durch >= ersetzt, oder < durch =<.
Prof. Dr. Dietmar Seipel
394
Logik für Informatiker
Wintersemester 2012/13
Mergesort in P ROLOG
% mergesort(+List, ?Sorted_List) <mergesort(Xs, Xs) :length(Xs, N),
N =< 1,
!.
mergesort(Xs, Ys) :middle_split(Xs, Xs1, Xs2),
mergesort(Xs1, Ys1),
mergesort(Xs2, Ys2),
mergesort_merge(Ys1, Ys2, Ys).
Die Aufteilung (Divide mittels middle_split) ist einfach; der
eigentliche Aufwand steckt im Merge–Schritt.
Prof. Dr. Dietmar Seipel
395
Logik für Informatiker
Wintersemester 2012/13
mergesort_merge([], Xs, Xs) :!.
mergesort_merge(Xs, [], Xs) :!.
mergesort_merge([X1|Xs1], [X2|Xs2], [X|Xs]) :( X1 < X2 ->
X = X1,
mergesort_merge(Xs1, [X2|Xs2], Xs)
; X = X2,
mergesort_merge([X1|Xs1], Xs2, Xs) ).
middle_split(Xs,Xs1,Xs2) splittet eine Liste Xs in zwei etwa
gleich große Teile Xs1 und Xs2.
Hier wird die Kontrollstruktur If -> Then ; Else verwendet.
Prof. Dr. Dietmar Seipel
396
Logik für Informatiker
Wintersemester 2012/13
Binäre Suchbäume in P ROLOG
% search_in_binary_tree(+Key, +Tree) <search_in_binary_tree(Key, Tree) :binary_tree_parse(Tree, Root, Lson, Rson),
( Key = Root
; Key < Root ->
search_in_binary_tree(Key, Lson)
; Key > Root ->
search_in_binary_tree(Key, Rson) ).
Die Suchbäume können dabei in einer X ML–artigen Termnotation in
P ROLOG vorliegen (binary_tree_mode=xml) oder in einer
einfachen – aber schwerer zu lesenden – Listennotation.
Prof. Dr. Dietmar Seipel
397
Logik für Informatiker
Wintersemester 2012/13
Suchbaum in X ML–Darstellung
<node key="8">
<node key="4">
<node key="2">
<node key="1"/>
<node key="3"/>
</node>
<node key="6">
<node key="5"/>
<node key="7"/>
</node>
</node>
<node key="12">
<node key="10">
<node key="9"/>
<node key="11"/>
</node>
<node key="13"/>
</node>
</node>
Prof. Dr. Dietmar Seipel
Visualisierung in P ROLOG mittels
binary_tree_to_picture(Picture, Tree)
398
Logik für Informatiker
Wintersemester 2012/13
Suchbaum – verschiedene Darstellungen
X ML–Darstellung:
<node key="2">
<node key="1"/>
<node key="3"/>
</node>
P ROLOG–Darstellung:
node:[key:2]:[
node:[key:1]:[],
node:[key:3]:[] ]
alternative, einfache P ROLOG–Darstellung:
[ 2,
[1],
[3] ]
Prof. Dr. Dietmar Seipel
2
1
U
3
399
Logik für Informatiker
Wintersemester 2012/13
Der leere Baum wird in X ML als leerer Knoten
<node/>
dargestellt. Falls ein Knoten eines Suchbaumes nur genau einen Sohn hat,
so wird als anderer Sohn der leere Baum eingetragen:
<node key="2">
<node key="1"/>
<node/>
</node>
2
1
Dies gilt auch für die alternative P ROLOG–Darstellung
[ 2, [1], [] ]
Eine entsprechende JAVA–Klasse wäre folgende:
Class node { int key ; node lson, rson; ... }
Prof. Dr. Dietmar Seipel
400
Logik für Informatiker
Wintersemester 2012/13
Kapselung des Zugriffs:
% binary_tree_empty(?Tree) <binary_tree_empty(node:[]:[]).
binary_tree_empty([]).
Dabei ist “:” ein binärer, assoziativer Operator, und X:Y:Z wird wie
X:(Y:Z) geklammert.
Man braucht natürlich jeweils nur eines der beiden Fakten.
Das erste ist für die X ML–Repräsentation, das zweite für die alternative
P ROLOG–Repräsentation.
Prof. Dr. Dietmar Seipel
401
Logik für Informatiker
Wintersemester 2012/13
% binary_tree_parse(+Tree, ?Key, ?Lson, ?Rson) <% binary_tree_parse(?Tree, +Key, +Lson, +Rson) <binary_tree_parse(Tree, Key, Empty, Empty) :binary_tree_empty(Empty),
Tree = node:[key:Key]:[].
binary_tree_parse(Tree, Key, Lson, Rson) :Tree = node:[key:Key]:[Lson, Rson].
binary_tree_parse(Tree, Key, Empty, Empty) :binary_tree_empty(Empty),
Tree = [Key].
binary_tree_parse(Tree, Key, Lson, Rson) :Tree = [Key, Lson, Rson].
Diese Methode schlägt für den leeren Baum bewußt fehl.
Man braucht auch hier jeweils nur eines der beiden Regelpaare.
Prof. Dr. Dietmar Seipel
402
Logik für Informatiker
Wintersemester 2012/13
Einzelne Einfügeoperation
% insert_into_binary_tree(+Key, +Tree, ?New_Tree) <insert_into_binary_tree(Key, Tree, New_Tree) :binary_tree_parse(Tree, Root, Lson, Rson),
( Key = Root ->
New_Tree = Tree
; Key < Root ->
insert_into_binary_tree(Key, Lson, L),
binary_tree_parse(New_Tree, Root, L, Rson)
; Key > Root,
insert_into_binary_tree(Key, Rson, R),
binary_tree_parse(New_Tree, Root, Lson, R) ).
insert_into_binary_tree(Key, Empty, New_Tree) :binary_tree_empty(Empty),
binary_tree_parse(New_Tree, Key, Empty, Empty).
Prof. Dr. Dietmar Seipel
403
Logik für Informatiker
Wintersemester 2012/13
Aufbau eines Suchbaums
% keys_to_binary_tree(+Keys, ?Tree) <keys_to_binary_tree(Keys, Tree) :binary_tree_empty(Empty),
insert_into_binary_tree_(Keys, Empty, Tree).
% insert_into_binary_tree_(+Keys, +Tree, ?New_Tree) <insert_into_binary_tree_([], Tree, Tree).
insert_into_binary_tree_([Key|Keys], Tree, New_Tree) :insert_into_binary_tree(Key, Tree, Tree_2),
insert_into_binary_tree_(Keys, Tree_2, New_Tree).
Prof. Dr. Dietmar Seipel
404
Logik für Informatiker
Wintersemester 2012/13
Berechnung der Höhe eines Suchbaums
% binary_tree_to_height(+Tree, ?H) <-
binary_tree_to_height(Tree, -1) :binary_tree_empty(Tree),
L
!.
binary_tree_to_height(Tree, H) :binary_tree_parse(Tree, Root, Lson, Rson),
binary_tree_to_height(Lson, L),
binary_tree_to_height(Rson, R),
max(L, R, M),
H is M + 1.
j
R
1
max(L,R)
Funktional könnte man in P ROLOG auch H is max(L,R) + 1
schreiben.
Prof. Dr. Dietmar Seipel
405
Logik für Informatiker
Wintersemester 2012/13
Man kann in P ROLOG (im Gegensatz zur “reinen” Logikprogrammierung)
auch
• prozedural
• mit Seiteneffekten und
• mit globalen Variablen (realisiert mit Hilfe von assert und
retract)
programmieren.
Es gibt umfangreiche Programmbibliotheken und Erweiterungen:
• Datenstrukturen und Algorithmen, Kombinatorik,
• Datenbank– und Web–Programmierung,
• GUI–Programmierung, etc.
Prof. Dr. Dietmar Seipel
406
Logik für Informatiker
Wintersemester 2012/13
Anwendungsbereiche:
• regelbasierte Diagnosesysteme (Medizin, Technik)
• symbolische Informationsverarbeitung, Parsing
• Datenbanken mit komplexen Strukturen (Hierarchien, X ML)
• Datenintegration
• Semantic Web
• Default Reasoning
• kombinatorische Suchprobleme
(Graphenprobleme, Spiele wie Sudoku oder Minesweeper, etc.)
Prof. Dr. Dietmar Seipel
407