Aufgabenblatt 3
P1 [[WiSe]] 04/05
Özgür Özcep
Aufgabe 1 (Grundbegriffe)
------------------------
Fakten: elementare Klauseln, die genau eine Grundstruktur enthalten.
Fakten dienen der Simulation relationaler DB's in Prolog. Fakten sind
die Elemente von Prädikaten der Logikprogrammierung. Mit ihnen wird
extensionales Wissen spezifiziert, d.h. mit Fakten definiert man
Eigenschaften eines Objektes bzw. Beziehungen zwischen Objekten durch
explizites Auflisten. Fakten können formal als Regeln (s.u.) ohne
Körper[[/Rumpf]] verstanden werden.
Regel: Komplexe Klausel der Form A :- B, die aus einem Kopf und einem
Körper besteht.
Regeln führen eine deduktive Komponente in relationale Datenbanken
ein: Ist das im Körper ausgedrückte Wissen bereits erschlossen worden,
so darf auf das im Kopf ausgedrückte Wissen geschlossen werden. Unter
einen anderen Perspektive formuliert: Um das im Kopf ausgedrückte Ziel
zu erfüllen muss das im Rumpf ausgedrückte Ziel erfüllen. Regeln
ermöglichen kompaktes Hinzufügen von intensionalem Wissen.
Anfrage oder Ziel: am Systemprompt eingegebene (elementare) Klausel.
Sie stellt eine Aufforderung dar, das in ihr angegebene Wissen auf
Konsistenz mit der Datenbasis zu überprüfen. Auch der Körper einer
Klausel ist als ein (komplexes) Ziel zu verstehen. Formal können
Anfragen[[/Ziele]] als Regeln ohne Kopf verstanden werden.
Aufgabe 2 (komplexe Anfragen)
-----------------------------
a)
?- mutter_von(X,Y),mutter_von(X,Z).
X ist Mutter von Y und X ist Mutter von Z, d.h. Y und Z haben dieselbe
Mutter und sind damit (Halb-)Geschwister; oder Y und Z bezeichnen
dieselbe Person. (Dieser Fall wird im folgenden ausgeklammert.)
?- mutter_von(A,X),mutter_von(A,B),mutter_von(B,Y), mutter_von(B,Z).
(1) A ist Mutter von X und
(2) A ist Mutter B und
(3) B ist Mutter von Y und
(4) B ist Mutter von Z
Bildlich:
A
/ \
X B
/ \
Y Z
Wie in a) folgt aus (1),(2):
(5) X und B sind (Halb-)Geschwister
und aus (3) und (4):
(6) Y und Z sind Halbgeschwister
Ausserdem gilt:
(7) X ist Onkel oder Tante von Y und Z
(8) A ist Grossmutter von Y und Z.
?-vater_von(B,X),vater_von(C,Y),vater_von(C,Z),vater_von(A,B),vater_von(A,C).
(1) B ist Vater von X
(2) C ist Vater von Y
(3) C ist Vater von Z
(4) A ist Vater von B
(5) A ist Vater von C.
Bildlich:
A
/ \
B C
| / \
X Y Z
Aus der obigen Darstellung ergeben sich folgende Verwandschaftsverhältnisse:
(6) B und C sind (Halb-)Geschwister
(7) Y und Z sind (Halb-)Geschwister
(8) X, Y und Z sind Enkelkinder von A; genauer:
A ist Grossvater von X und Y und Z
(9) X ist Cousin von Y und Z et vice versa
(10) B ist Onkel von Y und Z.
(11) C ist Onkel von X.
b)
% mutter_von( Mutter , Kind ).
% 'Mutter' und 'Kind' sind Argumentpositionen (Platzhalter, Variablen),
% so dass 'Mutter' die Mutter von 'Kind' ist.
:- dynamic mutter_von/2. % ermöglicht dynamische Veränderung
mutter_von( marie , hans ).
mutter_von( marie , helga ).
mutter_von( julia , otto ).
mutter_von( barbara , klaus ).
mutter_von( barbara , andrea ).
mutter_von( charlotte , barbara ).
mutter_von( charlotte , magdalena ).
mutter_von( helga , jana ).
mutter_von( helga , frida ).
mutter_von( frida , johannes ).
% vater_von( Vater , Kind ).
% 'Vater' und 'Kind' sind Argumentpositionen (Platzhalter, Variablen),
% so da"s 'Vater' der Vater von 'Kind' ist.
:- dynamic vater_von/2. % ermöglicht dynamische Veränderung
vater_von( otto , hans ).
vater_von( otto , helga ).
vater_von( gerd , otto ).
vater_von( johannes , klaus ).
vater_von( johannes , andrea).
vater_von( walter , barbara ).
vater_von( walter , magdalena ).
vater_von( ebbe , frida ).
vater_von( kaj , jana ).
vater_von( jan , johannes ).
% und nun brauchen wir noch das Geschlecht
% (zur Definition des Onkelprädikats):
weiblich(julia).
weiblich(marie).
weiblich(helga).
weiblich(frida).
weiblich(jana).
weiblich(charlotte).
weiblich(magdalena).
weiblich(barbara).
weiblich(andrea).
maennlich(gerd).
maennlich(otto).
maennlich(hans).
maennlich(ebbe).
maennlich(kaj).
maennlich(jan).
maennlich(walter).
maennlich(johannes).
maennlich(klaus).
% elternteil_von( Elternteil, Person ):
% 'Elternteil' und 'Person' sind Argumentpositionen, so dass
% 'Elterntei' ein Elternteil von 'Person' ist.
elternteil_von(E,P) :- vater_von(E,P).
elternteil_von(E,P) :- mutter_von(E,P).
% grossvater_von( Grossvater , Enkelkind )
% 'Grossvater' und 'Enkelkind' sind Argumentpositionen, so dass
% 'Grossvater' ein Grossvater von 'Enkelkind' ist.
grossvater_von(Grossvater , Person) :-
vater_von(Grossvater,Z),
elternteil_von(Z,Person).
% onkel_von
% Hier ist das Prädikatsschema uneindeutig:
% Die intendierte Bedeutung "Onkel" wird durch den zweiten
% Argumentsnamen 'Urenkel' gestört. Wir korrigieren das zu:
% onkel_von(Onkel, Person)
% 'Onkel' und 'Person' sind Argumentpositionen, so dass
% 'Onkel' ein Onkel von 'Person' ist.
% Ausserdem wird der Onkelbegriff so weit gefasst, dass auch Stiefonkel
% unter das Prädikat onkel_von fallen.
onkel_von(Onkel,Person) :-
maennlich(Onkel),
elternteil_von(X,Onkel),
elternteil_von(X,Geschwister),
Onkel \= Geschwister, % Das Geschwister sollte
% nicht der Onkel selbst sein
elternteil_von(Geschwister,Person).
% ---- Beispielanfragen ----
Yes
?- grossvater_von(otto,X). % Wer sind die Enkelkinder von otto?
X = jana ;
X = frida ;
No
?- grossvater_von(walter,Enkel). % Die Enkelkinder von walter?
Enkel = klaus ;
Enkel = andrea ;
No
?- grossvater_von(X,jana). % Wer sind die Grossväter von jana?
X = otto ;
No % Über den anderen Grossvater gibt es keine Auskunft in der DB
?- onkel_von(Onkel,Person). % Wer ist der Onkel von Wem?
Onkel = hans
Person = jana ;
Onkel = hans
Person = frida ;
Onkel = hans
Person = jana ;
Onkel = hans
Person = frida ;
No
% die redundante Information rührt von der Tatsache her,
% dass Prolog einmal die Vaterlinie
% und zum anderen die Mutterlinie testet.
?- halt.
Aufgabe 3 (komplexe Anfragen II)
--------------------------------
a)
Yes
?- consult('HAEUSER1.pl').
% HAEUSER1.pl compiled 0.00 sec, 1,320 bytes
Yes
?- listing.
% Foreign: rl_read_init_file/1
bew(1, 1, mueller, meier, 450000, '97.01.01').
bew(2, 3, schulze, schneider, 560000, '88.12.13').
bew(3, 3, schneider, mueller, 615000, '96.12.01').
bew(4, 5, bund, piepenbrink, 3500000, '91.06.01').
% Foreign: rl_add_history/1
obj(1, efh, gaertnerstr, 15, 1965).
obj(2, efh, bahnhofsstr, 27, 1943).
obj(3, efh, bahnhofsstr, 29, 1955).
obj(4, mfh, bahnhofsstr, 28, 1991).
obj(5, bahnhof, bahnhofsstr, 30, 1901).
obj(6, kaufhaus, bahnhofsstr, 26, 1997).
obj(7, efh, gaertnerstr, 17, 1982).
Yes
% i.) In welchen Strassen gibt es Einfamilienhäuser
?- obj(_,efh,Strassenname,_,_).
Strassenname = gaertnerstr ;
Strassenname = bahnhofsstr ;
Strassenname = bahnhofsstr ;
Strassenname = gaertnerstr ;
No
% i.') Dieselbe Anfrage mit dem findall-Prädikat
?- findall(Strassenname,obj(_,efh,Strassenname,_,_),L).
Strassenname = _G159
L = [gaertnerstr, bahnhofsstr, bahnhofsstr, gaertnerstr] ;
No
% ii.) Welche Häuser sind in den letzten Zehn Jahren gebaut worden?
?- obj(Objektnummer,_,_,_,X), X > 1993, X < 2005.
Objektnummer = 6
X = 1997 ;
No
% ii'.)
?- findall(haus(Objektnummer,Strassenname,Hausnummer),(obj(Objektnummer,_,Strassenname,Hausnummer,X),X > 1993, X < 2005),L).
Objektnummer = _G157
Strassenname = _G158
Hausnummer = _G159
X = _G165
L = [haus(6, bahnhofsstr, 26)] ;
No
% iii.) Auf welchen Grundstücken stehen keine Einfamilienhäuser?
?- obj(_,Objekttyp,Strassenname,Hausnummer,_),Objekttyp \= efh.
Objekttyp = mfh
Strassenname = bahnhofsstr
Hausnummer = 28 ;
Objekttyp = bahnhof
Strassenname = bahnhofsstr
Hausnummer = 30 ;
Objekttyp = kaufhaus
Strassenname = bahnhofsstr
Hausnummer = 26 ;
No
% iii'.)
?- findall(grundstueck(Strassenname,Hausnummer),(obj(_,Objekttyp,Strassenname,Hausnummer,_),Objekttyp \=efh),L).
Strassenname = _G157
Hausnummer = _G158
Objekttyp = _G161
L = [grundstueck(bahnhofsstr, 28), grundstueck(bahnhofsstr, 30), grundstueck(bahnhofsstr, 26)] ;
No
% iv.) Welches Haus wurde mit Gewinn weiterverkauft?
% Ausgespart wurden Ketten und Zyklen
?- bew(_,Objektnummer,_,Name,Betrag1,Datum1), bew(_,Objektnummer,Name,_,Betrag2,Datum2),Betrag2 > Betrag1,Datum2 @> Datum1, obj(Objektnummer,_,Strassenname,Hausnummer,_).
Objektnummer = 3
Name = schneider
Betrag1 = 560000
Datum1 = '88.12.13'
Betrag2 = 615000
Datum2 = '96.12.01'
Strassenname = bahnhofsstr
Hausnummer = 29 ;
No
No
b)
Durch Verwendung der anonymen Variablen '_' kann die Ausgabe unterdrückt
werden.
Auch kann eine Regel verwendet werden, um Variablen innerhalb
der Regel zu verstecken.
c)
Für diese Aufgabe modifizieren wir zunächst die Datenbasis, so dass
wir nicht mit dem "[[Y2K]]-Problem" zu kämpfen haben: Bsp.: aus der
Datumsangabe '97.01.01' mache '1997.01.01'.
% --- Datenbasis [[HAEUSER1_NEU]].pl ----
% obj(Objektnummer, Objekttyp, Strassenname, Hausnummer, Baujahr).
obj(1,efh,gaertnerstr,15,1965).
obj(2,efh,bahnhofsstr,27,1943).
obj(3,efh,bahnhofsstr,29,1955).
obj(4,mfh,bahnhofsstr,28,1991).
obj(5,bahnhof,bahnhofsstr,30,1901).
obj(6,kaufhaus,bahnhofsstr,26,1997).
obj(7,efh,gaertnerstr,17,1982).
% Modifiziert: 'Verkaufsdatum'! Bsp.: '97.01.01' --> '1997.01.01'
% bew(Vorgangsnr, Objektnr, Verkaeufer, Kaeufer, Preis, Verkaufsdatum)
:- dynamic bew/6.
bew(1,1,mueller,meier,450000,'1997.01.01').
bew(2,3,schulze,schneider,560000,'1988.12.13').
bew(3,3,schneider,mueller,615000,'1996.12.01').
bew(4,5,bund,piepenbrink,3500000,'1991.06.01').
% Neu eingefügt
bew(5,7,schiller,goethe,560000,'2002.12.13').
bew(6,7,goethe,herder,615000,'2002.12.14').
bew(8,5,piepenbrink,schmidt,50000,'2002.12.23').
bew(9,6,jonas,schmidt,500000,'2002.12.23').
bew(10,5,schmidt,meier,350000,'2003.04.12').
bew(11,3,schneider,schmidt,210000,'2003.01.02').
bew(12,1,meier,schmidt,400000,'2003.04.12').
bew(13,3,schmidt,hose,360000,'2003.02.30').
bew(14,1,schmidt,bund,580000,'2003.07.08').
bew(15,2,schneider,meier,210000,'2003.01.02').
bew(16,2,meier,schmidt,400000,'2003.08.06').
% neueigentuemer(Eigentuemer,Objektnummer).
% Eigentuemer hat Objekt mit Objektnummer nach 31.12.2001
% erworben und nicht weiterverkauft
neueigentuemer(Eig,[[ObjNr]]) :-
bew(_,[[ObjNr]],_,Eig,_,Datum),
Datum @> '2001.12.31',
\+((bew(_,[[ObjNr]],Eig,_,_,Datum2),Datum2 @>= Datum)).
% ---- Protokoll -----
?- consult('[[HAEUSER1_NEU]].PL').
% [[HAEUSER1_NEU]].PL compiled 0.00 sec, 4,176 bytes
Yes
% Liste zunächst die Neueigentümer auf
?- neueigentuemer(Eig,[[ObjNr]]).
Eig = herder
[[ObjNr]] = 7 ;
Eig = schmidt
[[ObjNr]] = 6 ;
Eig = meier
[[ObjNr]] = 5 ;
Eig = hose
[[ObjNr]] = 3 ;
Eig = bund
[[ObjNr]] = 1 ;
Eig = schmidt
[[ObjNr]] = 2 ;
No
% Neueigentümer in der Gärtnerstrasse?
?- neueigentuemer(Eig,[[ObjNr]]),obj([[ObjNr]],_,gaertnerstr,_,_).
Eig = herder
[[ObjNr]] = 7 ;
Eig = bund
[[ObjNr]] = 1 ;
No
% Neueigentümer mit benachbarten Immobilien?
?- neueigentuemer(Eig,Obj1),
neueigentuemer(Eig,Obj2),
Obj1 \= Obj2,
obj(Obj1,_,Strasse,Num1,_),
obj(Obj2,_,Strasse,Num2,_),
((Num1 =:=Num2-2);
(Num2 =:=Num1-2)).
No % Keine vorhanden.
% Füge einen solchen Eigentümer ein:
?- assert(bew(17,1,bund,herder,580000,'2004.07.08')).
Yes
?- neueigentuemer(Eig,Obj1),
neueigentuemer(Eig,Obj2),
Obj1 \= Obj2,
obj(Obj1,_,Strasse,Num1,_),
obj(Obj2,_,Strasse,Num2,_),
((Num1 =:=Num2-2);
(Num2 =:=Num1-2)).
Eig = herder
Obj1 = 7
Obj2 = 1
Strasse = gaertnerstr
Num1 = 17
Num2 = 15
Yes
?- halt.