Elemente der kĂŒnstlichen Intelligenz 4. Teil: Automatisches Beweisen
EinfĂŒhrung in die Problematik
In der letzten Folge haben wir zusammen die ersten logischen Terms umgeformt und dabei gesehen, daĂ Sprachen wie PROLOG und LISP die logischen Termumformungen weitgehend ĂŒbernehmen können. Viel interessanter ist natĂŒrlich das Problem, dem Computer die selbstĂ€ndige FĂŒhrung eines mathematischen Beweises unter Benutzung logischer Termumformungen zu ĂŒbertragen. Einem mathematisch wenig gebildeten Menschen bereitet es meist erhebliche Schwierigkeiten, einem mathematischen Beweis auch nur zu folgen. Einen mathematisch korrekten Beweisgang werden sich deshalb wohl auch die wenigsten Leser Zutrauen. Sie werden sicher zustimmen, wenn man ein GerĂ€t, das diese Beweise selbstĂ€ndig durchfĂŒhrt, als intelligent bezeichnet. Und da die Logik die âHaus- und Hofwissenschaftâ der Informatiker ist, ist es nicht weiter verwunderlich, wenn auf dem Gebiet der automatischen BeweisfĂŒhrung SpektakulĂ€res geleistet wurde.
Grundlagen der Aussagenlogik
ZunĂ€chst brauchen wir natĂŒrlich wieder einige Begriffe aus der Aussagenlogik. Ich darf bei dieser Gelegenheit wieder einmal auf das wirklich ausgezeichnete Buch von D. R. Hofstadter (siehe Literaturhinweise) hinweisen, in dem Sie eine sehr eigenwillige, gut lesbare EinfĂŒhrung in die Aussagenlogik finden. Generell ist es die Aufgabe eines Beweises, zu zeigen, daĂ eine wohlgeformte Aussage (d. h. eine Aussage, deren syntaktischer Aufbau den Regeln der Aussagenlogik genĂŒgt) immer den Wahrheitswert wahr erhĂ€lt, egal welchen Wahrheitswert die einzelnen in der Aussage vorhandenen Variablen annehmen. Z. B. ist die Aussage a v ~ a immer wahr, egal welchen Wert a annimmt. Um zu beweisen, daĂ diese Aussage immer wahr ist, wĂŒrde es genĂŒgen, wenn man die Wahrheitstafel der Aussage niederschreibt. Bei komplizierten Aussagen fĂŒhrt dieses Verfahren schnell an die Grenzen der Anschaulichkeit. Dann ist es einfacher, durch erlaubte Umformungen zum gewĂŒnschten Ergebnis zu kommen. Nehmen wir an, daĂ die AusdrĂŒcke a und b wohlgeformt sind. Dann sind es auch alle mit Hilfe der Junktoren ~ ,&,v gebildeten AusdrĂŒcke: ~ a, a v b, a & b. AuĂerdem ist natĂŒrlich ein atomarer Ausdruck wohlgeformt. Weiterhin gelten die folgenden Ăquivalenzen, d. h., der Ausdruck rechts von = kann ersetzt werden durch den Ausdruck links von = und umgekehrt:
- 
~ ~a = a
Gesetz der doppelten Verneinung
 
- 
~(a v b) = ~a & ~b
De Morganâsches Gesetz
 
- 
~ (a & b) = ~ a v ~ b
De Morganâsches Gesetz
 
- 
a v (b & c) = (a v b) & (a v c )
Distributivgesetz
 
- 
a -> b = ~avb
Implikation
 
Die resultierenden AusdrĂŒcke sind dann wieder wohlgeformt. Weiterhin benötigt man zur Herleitung neuer Aussagen noch sogenannte SchluĂregeln:
- Modus Ponens (bejahende Abtrennungsregel)
 
A â> b
a
b
Beispiel: Wenn es regnet, dann ist der Rasen feucht.
Es regnet.
Der Rasen ist feucht.
- Modus Tollens (verneinende Abtrennungsregel)
a â> b
~b
~a 
Beispiel: Wenn es regnet, dann ist der Rasen feucht.
Der Rasen ist nicht feucht.
Es regnet nicht.
- KettenschluĂ
 
a â> b
b â> c
a â> c
Beispiel: Wenn Peter wĂŒtend ist, dann hat er Hunger.
Wenn Peter Hunger hat, dann iĂt er Schokolade.
Wenn Peter wĂŒtend ist, dann iĂt er Schokolade.
Die fĂŒr uns interessante Form eines Beweises ist der sogenannte indirekte Beweis. Hier untersucht man die Negation des zu beweisenden Ausdrucks. Gelangt man durch Umformung der Negation zu einem Widerspruch, gilt also die negierte Aussage nicht, dann gilt nach dem Prinzip der doppelten Verneinung die originale Aussage. Schauen wir uns als Beispiel den Beweis des Kettenschlusses an:
ZunÀchst negieren wir den Term:
~((a -> b) & (b -> c) -> (a -> c)) =
~(~ ((~ a v b) & (~ b v c)) v (~ a v c))
Diesen Term bringen wir in die konjunktive Normalform, d. h. wir formen ihn so um, daà er nur noch einzelne, durch & verbundene Terme enthÀlt:
~((~ (~ a v b) v ~ (~ b v c)) v (~ a v c)) =
(~ a v b)&(~ b v c) & ~(~a v c) =
(~ a v b)&(~ bvc)& a & ~c
(Term in konkjunktiver Normalform.
Diese konjunktive Normalform eines logischen Termes heiĂt auch Klauselform, die einzelnen durch & verbundenen Terme Klauseln (also z. B. (~ a v b)). Das Prinzip der Resolution besteht nun darin, zu zeigen, daĂ sich zwei Klauseln widersprechen, d. h. daĂ in einem logischen Term ein Unterterm der Form ...& x & ~x & ... vorhanden ist. Das im folgenden Kapitel erlĂ€uterte Resolutionsprinzip geht von diesem leicht zu beweisenden Theorem aus:
(a v x) & (~ a v y) â> xvy
(Resolutionsschritt)
Damit wĂŒrde sich der Term in kon-unktiver Normalform darstellen lassen als:
(~a v b)&(~b v c)&a & ~c = (a v 0) & (~ a v b) & (~ b v c) & ~ c â>
(0 v b) & (~ b v c) & ~c = b & (~b v c) & ~c â> c & ~c (Widerspruch!)
%---------------------------------------------------------------------
% Interpreter fĂŒr musterorientierte Programmierung 
% nach I. Bratko, PROLOG Programming for artificial Intelligence.
:-op(800,xfx,--->).	% Definiert den "AusfĂŒhrungsoperator"
start :-					% Dieses PrÀdikat sucht in der
	Bedingung ---> Aktion,	% Datenbank nach einem Muster
	test(Bedingung),		% [] ----> []. Alle Elemente der
	fĂŒhre_aus(Aktion).		% ersten Liste werden als Bedingung
							% getestet. Wenn alle Bedingungen 
test([]).					% erfĂŒllt sind, werden alle Aktionen
test([Kopf|Rest]) :-		% der zweiten Liste ausgefĂŒhrt,
	call(Kopf), 
	test(Rest).
fĂŒhre_aus([stop]):- told,abolish(klausel,1). 
fĂŒhre_aus([]):- start. 
fĂŒhre_aus([Kopf|Rest]) 
	call(Kopf), 
	fĂŒhre_aus(Rest).
ersetze(A.B) :-
	retract(A), 
	assert(B).
%---------------------------------------------------------------------
% Ăbersetzung einer Aussage in Klauseln der Datenbasis
:- op(100,fy,~).	% Diese Direktiven definieren die logischen Operatoren
:- op(110,xfy,&).	% nicht C), und (&), oder (v) und die Implikation (=>)
:- op(120,xfy,v).	% Das erste Argument ist die PrioritÀt des Operators,
:- op(130,xfy,=>).	% Je kleiner die Zahl, desto gröĂer die PrioritĂ€t.
ĂŒbersetze(F & G)	% Dieses PrĂ€dikat ĂŒbersetzt logische Terme in der 
	ĂŒbersetze(F),	% konjunktiven Normalform mit Hilfe der weiter unten
	ĂŒbersetze(G).	% definierten erlaubten Umformungen. Ist keine weitere
					% Umformung mehr möglich, wird der Term als Klausel 
					% abgespeichert.
ĂŒbersetze(Aussage)
	forme_um(Aussage,NeueAussage),write('('),write(Aussage),write(') => ('), 
	write(NeueAussage),write(')'),nl,
	ĂŒbersetze(NeueAussage).
ĂŒbersetze(Aussage):-
	assert(klausel(Aussage)),write(klausel(Aussage)),nl. 
forme_um(~(~X),X) .					%	Prinzip der doppelten Negation
forme_um(X => Y,~X v Y).			%	Die	Implikation
forme_um(~(X & Y),~X v ~Y).			%	1. De Morgansches Gesetz
forme_um(~(X v Y),~X & ~Y).			%	2. De Morgansches Gesetz
forme_um(X & Y v Z,(X v Z) & (Y	v Z)).	%	1. Distributivgesetz
forme_um(X v Y & Z,(X v Y) & (X	v Z)).	%	2.	Distributivgesetz
forme_um(X v Y,X1 v Y) :- forme_um(X,X1).	%	Umformung von TeilausdrĂŒcken
forme_um(X v Y,X v Y1) :- forme_um(Y,Y1).	%	   "       "          "
forme_um(~X,~Xl) forme_um(X,X1) .	%	"
%---------------------------------------------------------------------
% Musterorientiertes Programm zur DurchfĂŒhrung der Resolution
% Widerspruch gefunden:
[klausel(X),klausel(~X)] --->
	[write('Widerspruch in der Negation gefunden!'),nl, 
	write('Aussage damit wahr.') ,nl,stop].
% (a v ~a v b) ist immer wahr.
[klausel(C),in(P,C),in(~P,C)]---> [write (klausel(C)) ,
	write(' ist immer wahr, wird also aus der Datenbank entfernt.'),nl, 
	retract(klausel(C))].
% (a v a v b) = (a v b) Idempotenzgesetz vereinfacht Terme.
[klausel(C),entferne(P,C,C1),in(P,C1)]  --->
	[write(klausel(C)), 
		ersetze(klausel(C),klausel(C1)),
		write(' wird ersetzt durch ') .write(klausel(C1)),nl].
% Resolution Spezialfall: a & (~a v b) => b
[klausel(P), klausel(C), entferne(~P,C,C1), not fertig (P,C,P) ]--->
	[assert(klausel(C1)),assert(fertig(P,C,P)),write('klausel('),write(P) 
	write(â) & klausel(â),write(C),write(') => '),write(klausel(C1)),nl].
% Resolution Spezialfall: ~a & (a v b) => b
[klausel(~P),klausel(C),entferne(P,C,C1),not fertig(~P,C,P)] --->
[assert(klausel(C1)), assert(fertig(~P,C,P)) ,write('klausel('),write ~P), 
write(') & klausel('),write(C),write('j => '),write(klausel(CI)),nl].
% Resolution allgemeiner Fall: (a v b) & (~a v c) => b v c
[klausel(C1),entferne(P,C1,CA),
klausel(C2),entferne(~P,C2,CB),not fertig(C1,C2,P)] --->
	[assert(klausel(CA v CB)),assert(fertig(C1,C2,P)), write('klausel('),write(C1), 
	write(') & klausel('),write(C2),write(') => '),write(klausel(CA v CB)),nl].
[]---->	[write('Kein Widerspruch in	der	Negation entdeckt!'),nl,stop].
entferne(X,X v Y,Y).	%	Entfernt X aus X v Y. Ăbrig bleibt Y.
entferne(X,Y v X,Y).	%
entferne(X,Y v Z,Y v Z1) :- entferne(X,Z,Z1).	%	Entfernt	Teilausdruck
entferne(X,Y v Z,Y1 v Z) :- entferne(X,Y,Y1).	%	"	â
in(X,X).					% X ist in sich selbst enthalten.
in(X,Y) :- entferne(X,Y,_).	%	X ist in Y enthalten, wenn es entfernt werden
							% könnte.
%-----------------------------------------------------
% automatisches Beweisen
beweise(Aussage) :- ausgabe(GerĂ€t),teil(GerĂ€t),write(âZu beweisen: '), write(Aussage),nl,nl,nl,write('Negation: '),
write(~Aussage),nl,nl, ĂŒbersetze(~Aussage),start.
ausgabe(printer).	% Auf diesem GerÀt soll die Ausgabe des Beweises
					% erfolgen. Es sind alle legalen Datenströme (also 
					% auch Dateien) möglich.
end.
Listing 1: Definition einiger Operatoren
Das Resolutionsprinzip
Das Resolutionsprinzip stellt sich also folgendermaĂen dar.
- Negiere den zu beweisenden Term.
 
- ĂberfĂŒhre den negierten Term in die Klauselform (konjunktive Normalform)
 
- FĂŒhre wenn möglich den Resolutionsschritt durch.
 
- Durchforste die Menge der Klauseln auf Widerspruch.
 
- Wenn ein Widerspruch entdeckt wurde, dann ist die nicht negierte Aussage bewiesen.
 
Das in Listing 1 dargestellte PROLOG-Programm fĂŒhrt die hier beschriebene Resolution durch. Es benutzt einen in PROLOG geschriebenen Musterinterpreter aus dem sehr interessanten Buch von I. Bratko. Das Programm ist von mir so verĂ€ndert worden, daĂ man jederzeit die SchluĂweise der Maschine verfolgen kann. Gleichzeitig möchte ich an Hand dieses Programms die hervorragenden Eigenschaften von PROLOG bei der Definition eigener Operatoren erlĂ€utern.
Musterorientierte Programmierung
Unter musterorientierter Programmierung versteht man ein Programmschema, das nicht so starr reagiert wie die konventionellen Programmiermethoden. Normalerweise besteht ein Programm aus festen Modulen, deren Ablauf explizit vorgegeben ist. Ein musterorientiertes Programm besteht dagegen aus einer Sammlung von musterorientierten Modulen. Jedes Modul besteht aus zwei Teilen:
- einem Bedienungsmuster,
 
- Aktionen, die ausgefĂŒhrt werden sollen, wenn das Bedingungsmuster erfĂŒllt ist.
 
Die AusfĂŒhrung eines Moduls wird in Gang gesetzt, wenn ein passendes Muster in der Datenbasis entdeckt wird. Musterorientierte Programmierung kann damit also so etwas wie ein natĂŒrliches Modell fĂŒr parallele Datenverarbeitung angesehen werden, da jedes Modul auf einem separaten Prozessor implementiert werden kann, der auf die gemeinsame Datenbasis wirkt. Die ErfĂŒllung von Bedingungsmustern erinnert natĂŒrlich sofort an den PROLOG-UnifizierungsprozeĂ. In der Tat ist der PROLOG-Interpreter nichts anderes als ein musterorientiertes Programmsystem. Im Beispielprogramm Listing 1 werden die Module in der Form
[Bedingungen] â [aktionen]
dargestellt. Hierin bedeutet [Bedingungen] eine Liste von Bedingungen in klausaler Form und [aktionen] eine Liste mit PrĂ€dikaten, die im Falle eines erfolgreichen Tests ausgefĂŒhrt werden sollen. Das PrĂ€dikat Start setzt dann das musterorientierte Programm in Aktion, indem es das goal Bedingungen â Aktionen im PrĂ€dikat Start zu unifizieren versucht. Hat der PROLOG-Interpreter eine Instanz gefunden, dann wird ein Test ausgefĂŒhrt, der alle Klauseln in der Bedingungsliste zu unifizieren versucht. Ist das gelungen, dann werden die in der Liste Aktionen aufgefĂŒhrten PrĂ€dikate zur Unifizierung gebracht. Wenn alle PrĂ€dikate unifiziert worden sind, bleibt nur noch die leere Liste als Aktionsliste zurĂŒck. Dann wird durch erneuten Aufruf von Start nach dem nĂ€chsten Muster in der Datenbasis gesucht. Ist kein weiteres Muster vorhanden, hat der PROLOG-Interpreter einen MiĂerfolg und beendet das PrĂ€dikat Start.
Das PrÀdikat op/3
Zur Funktionsweise des Programms in Listing 1 trĂ€gt in ganz besonderer Weise die Möglichkeit bei, in PROLOG eigene Operatoren zu vereinbaren. Dies geschieht mit Hilfe des PrĂ€dikates op/3. Die Syntax des Aufrufs ist op(PrioritĂ€t,AssoziativitĂ€t,Name). Hierin bedeutet PrioritĂ€t eine Zahl zwischen 1 und 1200. Die Bedeutung dieser Zahl wird klar, wenn man sich an die EselsbrĂŒcke Punktrechnung geht vor Strichrechnung erinnert. In PROLOG erkennt man diese EselsbrĂŒcke in Form der Vereinbarung op(500,yfx,+) bzw. op(400,yfx,A) wieder. Man sieht: Je Kleiner die PrioritĂ€t ist, desto eher wird der entsprechende Operator ausgewertet.
Die AssoziativitĂ€t beschreibt gleichzeitig die Stelligkeit und Position des neu definierten Ăperators. Die AssoziativitĂ€t darf nur einen der folgenden Werte haben:
fx, fy, xfx, xfy, yfx, yfy, xf, yf
f steht fĂŒr Funktor und kennzeichnet seine Stellung innerhalb eines Terms: fx und fy geben an, daĂ der neue Operator in PrĂ€fix-Notation zu gebrauchen ist. xfx, xfy, yfy und yfx kennzeichnen einen in Infix-Notation zu verwendenden Operator. xf und yf schlieĂlich sind die AssoziativitĂ€t eines Postfix-Operators. Wie man sieht, sind + und * also Infix-Operatoren, d. h. PROLOG erwartet das Additionszeichen bzw. Multiplikationszeichen zwischen zwei Zahlen oder Termen. Und was bedeutet x und y? Ein x gibt an, daĂ auf der betreffenden Seite alle Terme Operatoren mit niedrigerer PrioritĂ€t haben mĂŒssen. Ein y lĂ€Ăt dagegen auch Operatoren mit niedriger oder gleicher PrioritĂ€t zu. Um das zu verdeutlichen, schauen wir uns einen beliebigen arithmetischen Term an:
	3*X + 7-Y/4
Dieser arithmetische Term ist Ă€quivalent zu ((3AX) + 7)-(Y/4). Ein Blick in TAb. 1 zeigt uns, warum auch PROLOG diese Interpretation mit uns teilt. Der erste Operator, auf den der Interpreter bei der Bearbeitung des Termes stöĂt, ist â
. Auf der linken Seite ist alles klar, der einzige Operand ist das numerische Atom 3. Mehrdeutig könnte es auf der rechten Seite werden, wenn nicht die AssoziativitĂ€t des â
-Operators den Wert yfx hĂ€tte. Damit besteht die Forderung, daĂ rechts vom â
-Zeichen nur Operatoren kleinerer PrioritĂ€t stehen dĂŒrfen. + hat aber die PrioritĂ€t 500 - und die ist um 100 gröĂer als die PrioritĂ€t 400, welche â
 besitzt. Folglich wird nur der Term 3^X bewertet und berechnet. Das Ergebnis steht nun zur VerfĂŒgung und
op(+,yfx,500). 
op(-,yfx,500). 
op(*,yfx,400). 
op(/,yfx,400).
Tabelle 1
Abb.1: Argumentbindung durch unterschiedliche PrioritÀten
der Interpreter nimmt diesen Wert als linke Seite des folgenden +-Operators. Da die rechte Seite nur kleinere und nicht gleiche PrioritĂ€t haben darf, gehört der auf - folgende Term nicht zur rechten Seite. Das Ergebnis ist als (3 â
 X) + 7. Dieses Ergebnis wiederum stellt nun die linke Seite des folgenden Subtraktionsoperators dar. Und da / eine niedrigere PrioritĂ€t besitzt als -, gehört der Term Y/4 in die rechte Seite des Subtraktionsoperators. Also wird jetzt erst der Term Y/4 bewertet. Die linke Seite des Divisionsoperators endet bei dem -Zeichen, da dieses eine höhere PrioritĂ€t besitzt. Also wird jetzt nur der Wert Y/4 berechnet. Das Ergebnis ist jetzt der rechte Teil des Subtraktionsoperators, der jetzt folgende Operation durchzufĂŒhren hat: ((3AX) + 7) - (Y/4). Abb. 1 zeigt diese Situation nochmals graphisch.
Im Programm Listing 1 werden nun die folgenden Operatoren definiert:
â> Der Aktionsoperator fĂŒr musterorientierte Programmierung. Er trennt die Bedingungsliste von der Aktionsliste.
~ Der Negationsoperator. Negiert die logischen Terme.
& Der Konjunktionsoperator. VerknĂŒpfung zweier Terme durch logisches und.
v Der Disjunktionsoperator. VerknĂŒpft zwei logische Terme durch oder.
â>	Der Implikationsoperator a â> b heiĂt: Wenn a gilt, dann gilt auch b.
Die PrioritĂ€ten der entsprechenden Operatoren ergeben sich entsprechend den Regeln der Logik, wonach die Negation vor der Konjunktion vor der Disjunktion vor der Implikation zu berĂŒcksichtigen ist. Die Negation wird als PrĂ€fixoperator definiert (~ steht immer vor dem logischen Term, der negiert wird), die ĂŒbrigen Operatoren werden als Infixoperatoren definiert (d. h. sie stehen zwischen zwei Termen). Nach der Definiton dieser Operatoren ist PROLOG in der Lage, logische Terme korrekt zu bearbeiten.
Diese PrÀdikate enthalten das Wissen um die Umformung logischer Terme.
So bedeutet z. B. forme_um(~(~X), X)., daĂ der Term ~(~X) durch den vereinfachten Term X ersetzt werden kann (Prinzip der doppelten Negation). Ăhnliche Umformungen finden sich fĂŒr die Eliminierung der Implikation, die De Morganâschen Gesetze und die Distributivgesetze. Falls ein Term noch Unterterme enthĂ€lt, die umgeformt werden können, sorgen die drei letzten Instanzen dieses PrĂ€dikates fĂŒr die entsprechende Umformung. Die Ăbersetzung eines Termes in Klauselform wird durch das PrĂ€dikat ĂŒbersetze/1 vorgenommen. Dieses ĂŒbersetzt einen Term in der Klauselform, indem es jeden einzelnen Term umformt. Ist keine weitere Umformung nach den Regeln forme_um mehr möglich, wird die so gefundene Formel in die Datenbasis aufgenommen.
:-beweise((mann(marcus) & pompejaner(marcus) & (pompejaner(X) => römer(X)) & herrscher(cĂ€sar) & (römer(X) => (loyal(X,cĂ€sar) v haĂt(X,cĂ€sar))) & (mann(X) v herrscher(Y) v versucht_mord(X,Y) => ~ loyal(X,Y)) & versucht_mord(marcus,cĂ€sar)) => haĂt(marcus,cĂ€sar)).
Listing 2: Die geschichtliche Frage an den Computer
Die Produktionsregeln fĂŒr das Resolutionsverfahren
Die Produktionsregeln, nach denen die Terme in konjunktiver Normalform abgearbeitet werden, sind in Form der oben beschriebenen Muster in der Datenbank enthalten. So lautet die Regel, die den Widerspruch in der Datenbank entdeckt:
[klausel(X),klausel(~X)] â> [write(âWiderspruch gefundenâ),...]
Wenn also in der Datenbank sowohl die Klausel X als auch ihre Negation enthalten ist, dann liegt ein Widerspruch vor und die Aktionsliste druckt die entsprechende Mitteilung aus und stoppt die weitere AusfĂŒhrung des Programms. In den Produktionsregeln taucht u. a. das PrĂ€dikat fertig/3 auf. Es dient dazu, einen Ăberlauf in der Datenbank zu verhindern. Die Resolution produziert ja neue Klauseln: (a v b) & (~ a v c) â> (b v c). Bei Existenz zweiter Klauseln der Form (a v b) & (~ a v c) wird folglich eine neue Klausel (b v c) produziert und in die Datenbank aufgenommen. Da aber die alten Klauseln (a v b) und (~ a v c) nicht aus der Datenbank entfernt werden, wĂŒrde beim nĂ€chsten Aufruf der Resolution wieder die gleiche Klausel produziert werden. Um das zu verhindern, wird bei der ersten Produktion einer Klausel das PrĂ€dikat fertig((a v b),( ~ a v c),a). in die Datenbank aufgenommen, was eine nochmalige Resolution obiger Klauseln verhindert, die Resolution von Untertermen aber noch zulĂ€Ăt. Falls schlieĂlich alle logischen Terme in der Datenbasis umgeformt sind und keine weitere Resolution mehr möglich ist, dann trifft PROLOG schlieĂlich auf die leere Bedingungsliste und weiĂ, daĂ kein Widerspruch in der Datenbasis gefunden wurde. In diesem Fall ist der Beweis des zu beweisenden Satzes gescheitert! Zur Ăbung sollten Sie sich den Beweis (a â b)&(b â c) â (aâc) einmal vom Programm vorfĂŒhren lassen. AnschlieĂend schauen wir uns die Arbeitsweise des Programms einmal an einem berĂŒhmten Beispiel an: Der Frage nĂ€mlich, ob Marcus CĂ€sar haĂte.
HaĂte Marcus CĂ€sar?
Dieses Beispiel stammt von Elaine Rieh und ist eine gute Demonstration fĂŒr die Instanzierung von Variablen in logischen Termen wĂ€hrend des Beweises. Hier die Postulate, von denen im Beweis ausgegangen wird:
mann(marcus). Marcus war ein Mann.
pompejaner(marcus). Marcus war ein Pompejaner.
pompejaner(X) â> römer(X). Alle Pompejaner waren Römer.
herrscher(cÀsar). CÀsar war ein Herrscher.
römer(X) â> loyal(X,cĂ€sar) v haĂt (X,cĂ€sar). Alle Römer waren entweder CĂ€sar gegenĂŒber loyal oder sie haĂten ihn.
mann(X) & herrscher(Y) & versucht_mord(X,Y)-> ~loyal(X,Y).
Wenn ein Mensch einen Herrscher zu ermorden versucht, dann ist er ihm nicht loyal gegenĂŒber, versucht_mord(marcus, cĂ€sar). Markus versuchte CĂ€sar zu ermorden.
Listing 2 zeigt nun die Eingabe, die fĂŒr den Beweis nötig ist, daĂ Marcus CĂ€sar haĂte, und Abb. 2 zeigt die Arbeit des Programmes.
(Dr. Sarnow)
Literaturhinweise:
1.) Bratko, Ivan. PROLOG Programming for artificial Intelligence.
Addison Wesley Publishing. 1986.
2.) Hofstadter, Douglas R. Gödel, Escher, Bach: ein endlos geflochtenes Band.
Ernst Klett Verlage. 1985.
3.) Rieh, Elaine. Artificial Intelligence.
McGraw-Hill 1983.
Abbildung 2: HaĂte Markus CĂ€sar? Ein neuzeitlicher Lösungsweg!