28.11.2014 Aufrufe

Allgemeine Hinweise 1 Prolog Aussagenlogik und Resolution

Allgemeine Hinweise 1 Prolog Aussagenlogik und Resolution

Allgemeine Hinweise 1 Prolog Aussagenlogik und Resolution

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

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

Lehrstuhl für Softwaretechnik <strong>und</strong> Programmiersprachen<br />

Professor Dr. Michael Leuschel<br />

Softwaretechnik <strong>und</strong> Programmiersprachen – Sommersemester 2010<br />

<strong>Prolog</strong> Übungsaufgaben<br />

<strong>Allgemeine</strong> <strong>Hinweise</strong><br />

In diesem Dokument finden Sie eine Sammlung von Übungsaufgaben zum Thema <strong>Prolog</strong><br />

Die Übungsleiter werden Sie informieren welche Aufgaben in welcher Übung besprochen werden<br />

Ansprechpartner, Sprechst<strong>und</strong>en<br />

Bei Fragen wenden Sie sich bitte an Jens Bendisposto, bendisposto@cs.uni-duesseldorf.de,<br />

oder die Übungsleiter<br />

1 <strong>Prolog</strong><br />

Verwendete <strong>Prolog</strong>-Systeme<br />

Ein Großteil der Aufgaben zu <strong>Prolog</strong> werden Programmieraufgaben sein. Zum Lösen der Aufgaben benötigen Sie<br />

einen <strong>Prolog</strong>-Interpreter. SWI-<strong>Prolog</strong> (www.swi-prolog.org) ist eine freie, umfangreiche <strong>Prolog</strong>-Implementierung,<br />

die Sie verwenden können.<br />

Andere <strong>Prolog</strong>-Systeme sind XSB <strong>und</strong> das kommerzielle SICStus. Zu SICStus gibt es eine Campuslizenz.<br />

Falls Sie das System installieren möchten, sprechen Sie uns bitte an.<br />

Wir gehen im Folgenden davon aus, dass sie SWI verwenden.<br />

Arbeitszyklus Komandozeile<br />

Programme können in einem beliebigen Texteditor entwickelt werden. Auf der Kommandozeile werden diese<br />

dann folgendermaßen ausgeführt:<br />

swipl -s programm.pl<br />

?-<br />

Sie sehen dann ein paar Status-Informationen <strong>und</strong> das interaktive <strong>Prolog</strong>-Prompt:<br />

Es kann auch als Anfrage consult(’programm.pl’). eingegeben werden. Um ein Programm nach Änderungen<br />

erneut zu Laden, wird reconsult(’programm.pl’). verwendet.<br />

Sie verlassen das Programm mit halt..<br />

Kleiner Ratschlag<br />

Es wird dringend empfohlen, die Übungen zu machen <strong>und</strong> sich mit Arbeitsweise <strong>und</strong> Programmierung von<br />

<strong>Prolog</strong> vertraut zu machen. Eine neue Programmiersprache – insbesondere ein neues Programmierkonzept –<br />

erlernt man nur durch Üben, nicht nur durch das Ansehen von Beispielen.<br />

Weiterhin sind die Übungsaufgaben so aufgebaut, dass sie für das Lösen der Projektaufgabe extrem nützlich<br />

sein werden.<br />

<strong>Aussagenlogik</strong> <strong>und</strong> <strong>Resolution</strong><br />

Formalisieren Sie die folgenden Aussagen in <strong>Aussagenlogik</strong>:<br />

1. Das System heizt, wenn der Deckel geschlossen ist <strong>und</strong> Strom an ist.<br />

2. Wenn das Lämpchen leuchtet, ist der Strom an.<br />

3. Das Lämpchen leuchtet.<br />

4. Der Deckel ist geschlossen.<br />

Bringen Sie die Aussagen in die konjunktive Normalform <strong>und</strong> beweisen Sie mittels linearer <strong>Resolution</strong>, dass das<br />

System heizt.


Spaß mit Zahlen<br />

In der Vorlesung haben sie die Beschreibung der natürlichen Zahlen mittels der folgenden zwei Axiome gesehen<br />

(Peano-Arithmetik):<br />

0 ∈ N<br />

∀X X ∈ N → s(X) ∈ N<br />

Eine etwas andere Schreibweise, die wir im folgenden nutzen, ist:<br />

nat(0)<br />

∀X nat(X) → nat(s(X))<br />

Die Addition (add(X, Y, Z): Z ist die Summe von X <strong>und</strong> Y ) wurde folgendermaßen definiert:<br />

• Setzten Sie die Addition in <strong>Prolog</strong> um.<br />

• Definieren Sie die Multiplikation in <strong>Prolog</strong>.<br />

• Definieren Sie “kleiner als”.<br />

• Implementieren Sie Modulo.<br />

2 Unifikation<br />

∀X add(0, X, X)<br />

∀X, Y, Z add(X, Y, Z) → add(s(X), Y, s(Z))<br />

Geben Sie zu den folgenden Paaren von Termen an, ob sie unifizierbar sind <strong>und</strong> –wenn ja– geben sie einen<br />

allgemeinsten Unifkator σ (most general unificator – mgu) an.<br />

1. punkt <strong>und</strong> punkt<br />

2. loves(brad, janet) <strong>und</strong> loves(brad, X)<br />

3. punkt(1, 2, 3) <strong>und</strong> punkt(1, R)<br />

4. nat(nat(X)) <strong>und</strong> nat(Y )<br />

5. greater(nat(0), nat(nat(X))) <strong>und</strong> greater(nat(X), nat(Y ))<br />

6. cons(A, cons(B, nil)) <strong>und</strong> cons(val, cons(C, R))<br />

7. snafu(foo, A) <strong>und</strong> snafu(A, bar)<br />

8. triple(pair(X), pair(Y ), Z) <strong>und</strong> triple(Z, pair(X), pair(Z))<br />

Ein Zoo<br />

Wir betrachten einen Zoo mit den folgenden Tieren: Löwe, Tieger, Papagei, Pinguin, Zebra, Kolibri, Adler,<br />

Nashorn.<br />

1. Entwickeln Sie eine Datenbank, die die Tiere des Zoos verwaltet, es uns also ermöglicht herauszufinden,<br />

ob ein bestimmtes Tier im Zoo ist.<br />

2. Erweitern Sie das Program, so dass wir herausfinden können, ob ein Tier ein Raubtier ist.<br />

3. Wenn Sie nun fragen, ob ein Wolf ein Raubtier ist, welche Antwort bekommen Sie? Warum? Ist es die<br />

erwartete Antwort? Wie könnte man das Programm erweitern, um die erwartete Antwort zu bekommen?<br />

4. Erweitern Sie nun das Program, so dass wir herausfinden können, ob ein Tier ein Vogel ist; erweitern Sie<br />

das Programm, so dass wir herausfinden können, ob ein Tier fliegen kann.<br />

5. Überlegen Sie sich eine elegante Lösung um sicherzustellen, dass ein Pinguin als nicht-fliegender Vogel<br />

erkannt wird.


<strong>Prolog</strong> als Datenbank<br />

Sie sollen ein Sicherheitssystem für ein Büro entwerfen. Das Büro hat zwei Haupteingänge, <strong>und</strong> die einzelnen<br />

Räume sind mit Buchstaben bezeichnet:<br />

Aufgabe 1<br />

Halten Sie die Topologie des Büros in einem <strong>Prolog</strong>-Programm fest. Nach der Fertigstellung wollen wir mit der<br />

folgenden Abfrage feststellen können, ob zwei Räume verb<strong>und</strong>en sind:<br />

% Sind Raum a <strong>und</strong> b verb<strong>und</strong>en?<br />

?- tuer(a, b).<br />

true<br />

Aufgabe 2<br />

Wenn eine Tür von a nach b geht, geht diese natürlich auch von b nach a. Unterstützt Ihr Programm das? Stellen<br />

Sie sicher, dass Ihr Programm das unterstützt. Stellen Sie weiterhin sicher, dass Abfragen wie tuer(X, a)<br />

ebenfalls funktionieren.<br />

Ein Hinweis: Eine Triviale Lösung wäre es, jede Tür zweimal in die Datenbank aufzunehmen (für beide<br />

Richtungen). Versuchen Sie, eine Lösung ohne Red<strong>und</strong>anz zu finden.<br />

Aufgabe 3<br />

Erstellen Sie eine Regel erreichbar(Raum1, Raum2), die true ergibt, wenn zwei Räume verb<strong>und</strong>en sind.<br />

Erstellen Sie eine Regel erreichbar(Raum1, Raum2, Weg), die den Weg zwischen zwei Räumen ausdruckt.<br />

Dazu ein paar <strong>Hinweise</strong>:<br />

(1) Sie können Weg erstellen, indem Sie einfach die Teile als String zusammensetzen, etwa folgendermaßen:<br />

verbinde(X, Y, X -> Y).<br />

Ausgeführt würde das folgendermaßen aussehen:<br />

?- verbinde (a, b, AB).<br />

AB = a->b<br />

(2) Ein bessere Möglichkeit wäre, eine Liste für Weg zu benutzen. Listen wurden in der Vorlesung jedoch<br />

noch nicht behandelt. Sie dürfen sich aber trotzdem gern daran versuchen, wenn Sie wollen.<br />

Aufgabe 4<br />

Nun sollen Nutzer eingeführt werden, die nur Zugang zu bestimmten Räumen haben.<br />

Datenstruktur, die das festhält.<br />

Entwickeln Sie eine<br />

Aufgabe 5<br />

Nutzer müssen von Außerhalb (also “outside” im Plan) zu den Räumen kommen, zu denen sie Zugang haben.<br />

Schreiben Sie also ein Programm das prüft, ob ein Nutzer zu einem Raum Zugangsrechte hat, <strong>und</strong> diesen Raum<br />

auch von outside erreichen kann (also muss der Nutzer auch für alle Räume, die zwischen outside <strong>und</strong> dem<br />

Raum liegen, Zugangsrechte haben).


Listen, Listen, Listen<br />

Aufgabe 1<br />

Schreiben Sie ein Programm, das eine Liste de-dupliziert, also mehrfach enthaltene Elemente löscht, also<br />

[a, b, a, c] wird zu [a, b, c] oder [b, a, c].<br />

Aufgabe 2<br />

Schreiben Sie ein Programm, das jedes Element einer Liste verdoppelt, also [a, b, c] wird zu [a, a, b, b, c, c].<br />

Aufgabe 3<br />

Es gibt verschiedene Möglichkeiten, Listen umzudrehen. Hier sind zwei mögliche Programme:<br />

% reverse Version a<br />

reverse([], []).<br />

reverse([X|Xs], Zs) :- reverse(Xs, Ys), append(Ys, [X], Zs).<br />

% reverse Version b<br />

reverse([], []).<br />

reverse(Xs, Ys) :- reverse(Xs, [], Ys).<br />

reverse([X|Xs], Acc, Ys) :- reverse(Xs, [X|Acc], Ys).<br />

reverse([], Ys, Ys).<br />

• Welche der beiden Versionen gefällt Ihnen besser? Warum?<br />

• Zeichnen Sie den Proof-Tree für beide Programme, wenn der folgende Ausdruck ausgewertet wird:<br />

reverse([a, b, c], [c, b, a]).<br />

• Wie ist die Laufzeit der beiden Programme?<br />

Inspektion von Strukturen<br />

Aufgabe 1<br />

Was ergeben die folgenden Ausdrücke? Und warum?<br />

?- compo<strong>und</strong>(a).<br />

?- atom(a).<br />

?- compo<strong>und</strong>(X).<br />

?- atom(X).<br />

?- compo<strong>und</strong>(a(b)).<br />

?- atom(a(b)).<br />

?- compo<strong>und</strong>([]).<br />

?- atom([]).<br />

?- compo<strong>und</strong>([[]]).<br />

?- atom([[]]).<br />

Aufgabe 2<br />

Was ergeben die folgenden Ausdrücke? Und warum?<br />

?- functor(a, F, A).<br />

?- functor(father(michael, tyler), F, A).


?- arg(1, father(michael, tyler), X).<br />

?- arg(2, father(michael, X), tyler).<br />

?- functor([], F, A).<br />

?- functor([a], F, A).<br />

?- arg(1, [a], X).<br />

?- arg(2, [a], X).<br />

?- arg(3, [a], X).<br />

?- arg(1, [], X).<br />

Schreiben Sie ein Programm subterm(T1, T2), das wahr ergibt, wenn T1 ein Unter-Term von T2 ist, also<br />

z.B.<br />

?- subterm(a, x(a)).<br />

true<br />

?- subterm(a, x(b)).<br />

false<br />

Sie dürfen annehmen, dass keiner der Terme Variablen enthält.<br />

Listen <strong>und</strong> Zahlen<br />

Aufgabe 1<br />

Schreiben Sie ein Programm, dass die Werte einer Liste aufaddiert. Z.B. sumlist([2, 3, 4], X) ergibt X=9.<br />

Aufgabe 2<br />

Schreiben Sie ein Programm, dass den größten gemeinsamen Teiler identifiziert. Z.B. ggt(6, 9, X) ergibt X=3.<br />

Aufgabe 3<br />

Schreiben Sie ein Programm, dass eine Liste von Zahlen erzeugt. Die Anfangs- <strong>und</strong> Endzahl wird als Argument<br />

gegeben. Z.B. range(1, 5, X) ergibt X=[1, 2, 3, 4, 5].<br />

Aufgabe 4<br />

Schreiben Sie ein Programm, dass alle Permuationen einer Liste erstellt. Z.B. perm([1, 2, 3], X) ergibt<br />

X=[1, 2, 3], X=[1, 3, 2], X=[2, 1, 3], X=[2, 3, 1], X=[3, 1, 2] <strong>und</strong> X=[3, 2, 1].<br />

Acht Damen<br />

Das Acht-Damen-Problem ist ein klassisches Schach-Rätsel. Es sollen jeweils acht Damen auf einem Schachbrett<br />

so aufgestellt werden, dass keine zwei Damen einander nach den Schachregeln schlagen können. Die Figurenfarbe<br />

wird dabei ignoriert <strong>und</strong> es wird angenommen, dass jede Figur jede andere angreifen könnte. Anders<br />

ausgedrückt, es sollen sich keine zwei Damen die gleiche Reihe, Linie oder Diagonale teilen. Es gibt mehrere<br />

Lösungen, eine davon ist zum Beispiel:


Aufgabe 1<br />

Schreiben Sie ein Programm, dass das 8-Damen-Problem löst.<br />

Aufgabe 2<br />

Statt dem 8-Damen-Problem, schreiben Sie das Programm generischer für das N-Damen-Problem (N ist die<br />

größe des Schachbrettes <strong>und</strong> die Anzahl der Damen).<br />

Aufgabe 3<br />

Versuchen Sie ein möglichst effizientes Programm zu schreiben.<br />

Puzzles<br />

Aufgabe 1<br />

Zum Warmwerden beschäftigen wir uns mit dem 15-Puzzle. Bei dem Puzzle sollen die Zahlen durch Verschieben<br />

sortiert werden.<br />

Schreiben Sie ein Programm, dass das 15-Puzzle-Problem löst.<br />

Die Datenstruktur für ein 15-Puzzle soll folgendermaßen aussehen:<br />

% Die Datenstruktur ist ein Prädikat c mit drei Listen, die die Zahlen 1-15 <strong>und</strong> x enthalten:<br />

% c([x, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]).<br />

Dann definieren Sie eine Übergangs-Funktion (Successor-Function), die das Puzzle von einem Zustand zum<br />

nächsten überführt, also z.B.:<br />

?- s(c([x, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]), R).<br />

R = c([4, 1, 2, 3], [x, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]) ;<br />

R = c([1, x, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]) .<br />

Implementieren Sie nun ein Programm zur Lösungsfindung, dass den “konventionellen” Weg beschreitet: Sie<br />

suchen eine potentielle Lösung <strong>und</strong> lassen <strong>Prolog</strong> diese Lösung testen. Wie können Sie sicherstellen, dass das<br />

Programm immer eine Lösung findet, angenommen dass es eine gibt? Wie bewerten Sie die Performance?<br />

Aufgabe 2<br />

Nun wollen wir eine Lösung implementieren, die A* nutzt. Um A* zu implementieren, benötigen Sie eine pathcost-function<br />

g(x) <strong>und</strong> eine heuristic-function h(x). Implementieren Sie g(x) <strong>und</strong> h(x) Ihrer Wahl - aber nicht<br />

die in Aufgabe 3 geforderte!


Aufgabe 3<br />

Implementieren Sie eine Heuristik-Funktion, die die “Manhattan-Entfernung” berechnet. Bei der Manhattan-<br />

Entfernung werden die Entfernungen der X- <strong>und</strong> Y-Koordinate einfach zusammenaddiert. Z.B. hat “zwei nach<br />

rechts, einen nach oben” eine Entfernung von drei.<br />

Das Tantrix-Spiel<br />

Bei Tantrix handelt es sich um ein Legespiel, das mit sechseckigen Kacheln gespielt wird. Jede Kachel ist mit<br />

drei farbigen Linien bedruckt, die den Kanten der Kachel eine entsprechende Farbe zuordnen. Im folgenden<br />

sind einige typische Tantrix-Kacheln gezeigt.<br />

Das Ziel des Spieles ist, die Kacheln so anzuordnen, dass nur zusammenpassende Kacheln aneinander liegen.<br />

Es gib mehrere Variationen des Spieles, von denen wir nur eines hier bearbeiten werden.<br />

Das Tantrix-Rotationspuzzle<br />

Sie sollen das folgende Tantrix-Problem bearbeiten:<br />

Sie bekommen ein Anzahl angeordneter Tantrix-Kacheln. Schreiben Sie ein Programm, dass diese Kacheln<br />

so rotiert, dass alle Kanten zusammen passen. Das folgende Bild zeigt eine Aufgabe mit vier Kacheln (a) <strong>und</strong><br />

die dazugehörige Lösung (b). Beachten Sie, das wirklich nur rotiert wurde - nicht verschoben oder vertauscht.<br />

Die Details zu Tantrix<br />

1. Alle Linien auf einer Kachel haben unterschiedliche Farben (es gibt also immer genau drei Farben pro<br />

Kachel).<br />

2. Es gibt Tantrix-Spiele mit unterschiedlich vielen Farben. Ihr Programm muss das unterstützen können.<br />

Die Details zum Programm<br />

Das zu lösende Puzzle wird folgendermaßen an Ihr Programm übergeben: Für jede Kachel bekommen Sie zwei<br />

Koordinaten eines Koordinatensystems, das so aussieht:<br />

Zusätzlich bekommen Sie die Kantenfarben als einfache Bezeichner. Das in der Abbildung gezeigte Problem<br />

würde dann wie folgt aussehen:<br />

% Die Kacheln haben eine Position (x, y) <strong>und</strong> sechs Farben, im Uhrzeigersinn,<br />

% beginnend mit der unteren Kante<br />

setup(<br />

[kachel(0, 0, b, b, r, y, r, y),


kachel(1, 0, g, r, g, r, b, b),<br />

kachel(1, 1, y, b, r, y, r, b),<br />

kachel(0,-1, b, g, g, b, r, r)<br />

]<br />

).<br />

% Die Loesung ist eine Liste mit einer Liste pro Kachel. Die Kachel-Listen<br />

% enthalten drei Elemente: die Koordinaten der Kachel <strong>und</strong> die Anzahl der Schritte,<br />

% die die Kachel im Uhrzeigersinn gedreht werden muss.<br />

setup(P), solve(P,L), L = [[0, 0, 4], [1, 0, 3], [1, 1, 0], [0,-1, 5]].

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!