Listenverarbeitung bisher Verschachtelte Listen, Differenzlisten, Graphen member/2 append/3 delete/3 reverse/2 reverse/3 permute/2 sort/2 qs/2 partition/4 Prolog Grundkurs WS 99/00 Christof Rumpf [email protected] 29.11.99 deleteall/3 Listenelemente finden Listen konkatenieren Listenelemente löschen/einfügen Liste umkehren (naiv) Liste umkehren (mit Akkumulator) Liste permutieren (n!) Liste permutationssortieren (n!) Liste mit Quicksort sortieren (n log n) Liste in Teillisten partitionieren GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 2 makeset/3 % deleteall(Term,Liste1,Liste2) deleteall(_,[],[]). Termination deleteall(X,[X|T1],L):Lösche X aus Kopf deleteall(X,T1,L). Lösche X aus Rest T1 deleteall(X,[H|T1],[H|T2]):Behalte Kopf H, X \= H, falls H ≠ X deleteall(X,T1,T2). Lösche X aus Rest T1 % makeset(Liste1,Liste2) makeset([],[]). makeset([H|T1],[H|T2]):deleteall(H,T1,L), makeset(L,T2). Termination. Behalte Kopf H. Löschen aller H aus T1 liefert L. Entferne alle Duplikate aus L. makeset/2 entfernt mit Hilfe von deleteall/3 alle Duplikate aus Liste1 und liefert Liste2 als Ergebnis. deleteall/3 löscht alle Vorkommen eines Terms aus einer Liste, während delete/3 genau ein Vorkommen eines Terms löscht und scheitert, wenn der Term nicht vorkommt. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 3 29.11.99 Verschachtelte Listen Das Prädikat flatten/2 wandelt eine verschachtelte Liste in flache Liste um. [1,2,3,[a,b,[x,y],c],4,5,[],6] ?- flatten([1,2,3,[a,b,[x,y],c],4,5,[],6],L). L = [1,2,3,a,b,x,y,c,4,5,6] yes Die Verarbeitung von Listen von Listen erfordert häufig doppelte Rekursion, sodaß bei einer Zerlegung nicht nur der Rest, sondern auch der Kopf rekursiv weiterverarbeitet wird. GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 4 Verflachen von Listen Als Listenelemente können beliebige Terme auftreten, also auch Listen. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 5 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 6 1 Effizienz von flatten/2 flatten/2 %flatten(VerschachtelteListe, FlacheListe) flatten([],[]). Leere Liste ist schon flach. flatten([H|T],FL):flatten(H,FH), flatten(T,FT), append(FH,FT,FL). flatten/2 hat nach dem zweiten rekursiven Aufruf einen Aufruf von append/3. Dies drückt die Performance ähnlich nach unten, wie wir es schon beim naiven reverse/2 gesehen haben. Zerlege verschachtelte Liste. Verflache Kopf. Verflache Rest. Konkateniere verflachten Kopf und Rest zu Ergebnis. Verbesserung: flatten/3 mit Akkumulator! flatten(X,[X]):Term in flache Liste packen, X \= [], X \= [_|_]. falls Term keine Liste ist. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 7 29.11.99 flatten/3 flatten(VL,FL):flatten(VL,[],FL). flatten([],[],[]). flatten([],[H|Acc],FL):flatten(H,Acc,FL). flatten([H|T],Acc,FL):is_list(H), flatten(H,[T|Acc],FL). flatten([H|T1],Acc,[H|T2]):not is_list(H), flatten(T1,Acc,T2). 29.11.99 (2) (5) (8) (11) (13) (16) (19) (21) (24) (27) (30) (34) (35) (38) (40) (41) (44) (47) (47) (44) (41) (40) (38) (35) (34) (31) (30) (27) (24) (21) (19) (16) (13) (11) (8) (5) (2) CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: CALL: EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): EXIT(N): 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 8 is_list/1 flatten/2 ruft flatten/3 auf. Initialisierung des Akkumulators. Termination. Falls verschachtelte Liste leer, verflache Kopf des Akkumulators. Falls Kopf von VL nichtleere Liste, nimm Rest von VL in Akkumulator und verflache H. Falls Kopf von VL keine Liste ist, übernimm den Kopf in flache Liste und verflache Rest von VL. flatten([1,2,3,[a,b,[x,y,z],c],4,[],5,6], [], _0098) flatten( [2,3,[a,b,[x,y,z],c],4,[],5,6], [], _0AB8) flatten( [3,[a,b,[x,y,z],c],4,[],5,6], [], _0C14) flatten( [[a,b,[x,y,z],c],4,[],5,6], [], _0D70) flatten( [a,b,[x,y,z],c], [[4,[],5,6]], _0D70) flatten( [b,[x,y,z],c], [[4,[],5,6]], _11E4) flatten( [[x,y,z],c], [[4,[],5,6]], _1340) flatten( [x,y,z], [[c],[4,[],5,6]], _1340) flatten( [y,z], [[c],[4,[],5,6]], _17B4) flatten( [z], [[c],[4,[],5,6]], _1910) flatten( [], [[c],[4,[],5,6]], _1A6C) flatten( [], [[4,[],5,6]], _1D00) flatten( [4,[],5,6], [], _1D00) flatten( [[],5,6], [], _1F94) flatten( [], [[5,6]], _1F94) flatten( [5,6], [], _1F94) flatten( [6], [], _2540) flatten( [], [], _269C) flatten( [], [], []) flatten( [6], [], [6]) flatten( [5,6], [], [5,6]) flatten( [], [[5,6]], [5,6]) flatten( [[],5,6], [], [5,6]) flatten( [4,[],5,6], [], [4,5,6]) flatten( [], [[4,[],5,6]], [4,5,6]) flatten( [c], [[4,[],5,6]], [c,4,5,6]) flatten( [], [[c],[4,[],5,6]], [c,4,5,6]) flatten( [z], [[c],[4,[],5,6]], [z,c,4,5,6]) flatten( [y,z], [[c],[4,[],5,6]], [y,z,c,4,5,6]) flatten( [x,y,z], [[c],[4,[],5,6]], [x,y,z,c,4,5,6]) flatten( [[x,y,z],c], [[4,[],5,6]], [x,y,z,c,4,5,6]) flatten( [b,[x,y,z],c], [[4,[],5,6]], [b,x,y,z,c,4,5,6]) flatten( [a,b,[x,y,z],c], [[4,[],5,6]], [a,b,x,y,z,c,4,5,6]) flatten( [[a,b,[x,y,z],c],4,[],5,6], [], [a,b,x,y,z,c,4,5,6]) flatten( [3,[a,b,[x,y,z],c],4,[],5,6], [], [3,a,b,x,y,z,c,4,5,6]) flatten( [2,3,[a,b,[x,y,z],c],4,[],5,6], [], [2,3,a,b,x,y,z,c,4,5,6]) flatten([1,2,3,[a,b,[x,y,z],c],4,[],5,6], [],[1,2,3,a,b,x,y,z,c,4,5,6]) GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 9 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? > > > > > > > > > > > > > > > > > > 11 Das Prädikat is_list/1 ist beweisbar, wenn das Argument eine leere oder nichtleere Liste ist. is_list([]). is_list([_|_]). Aus Effizienzgründen verzichten wir auf Korrektheit für is_list/1 , indem wir auf den rekursiven is_list/1 -Beweis für Restlisten nichtleerer Listen verzichten. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 10 Graphen Viele Probleme lassen sich graphentheoretisch modellieren. Ein Graph ist ein mathematisches Objekt mit klar definierten Eigenschaften und Methoden. Bäume sind Graphen mit speziellen Eigenschaften. Wir nähern uns jetzt Bäumen an, indem wir von gerichteten Graphen über DAGs zu geordneten Bäumen kommen. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 12 2 Gerichteter Graph Prolog-Repräsentation: Graph Ein gerichteter Graph G ist ein Tupel <N, E>, wobei N(odes) eine Menge von Knoten und E(dges) eine Menge E ⊆ N × N von Kanten ist. a G1 = <{a,b,c,d,e}, {<a,b>,<a,c>, <b,d>,<d,c>, <d,e>,<d,a>}> 29.11.99 b c d als Fakten: als Struktur: node(a). ... node(e). edge(a,b). ... edge(d,a). ([a,b,c,d,e], [(a,b),(a,c), (b,d),(d,c), (d,e),(d,a)]) e GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 13 29.11.99 Transitive Hülle Transitive Hülle für Faktenrepräsentation: closure(X,Y):- edge(X,Y). closure(X,Y):- edge(X,Z), closure(Z,Y) 1. E ⊆ H(G) 2. <x, y> ∈ H(G) ∧ <y, z> ∈ H(G) ⇒ <x, z> ∈ H(G) Transitive Hülle für Listenrepräsentation: Die transitive Hülle liefert uns alle Verbindungen, die zwischen Knoten bestehen. GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 14 Berechnung in Prolog Die transitive Hülle eines Graphen G= <N, E> ist die Menge H(G) ⊆ N × N, sodaß gilt: 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 15 closure(X,Y,E):- member((X,Y),E). closure(X,Y,E):- member((X,Z),E), closure(Z,Y,E). % E = [(N1,N2),...,(Ni,Nk)] 29.11.99 DAG GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 16 Bäume Ein gerichteter azyklischer Graph (DirectedAcyclicGraph) G = <N, E> ist ein Graph, für den gilt: Ein DAG G = <N, E> ist ein Baum, wenn gilt: ∀x,y,z ∈ N: <x, z> ∈ E ∧ <y, z> ∈ E ⇒ x = y ∀<x, y> ∈ H(G): x ≠ y Jeder Knoten in einem Baum hat maximal einen Vorgänger. Kein Knoten ist in H(G) mit sich selbst verbunden. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 17 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 18 3 Geordnete Bäume Beispiel Syntaxbaum Ein geordneter Baum G = <N, E, O> ist ein Baum mit einer totalen Ordnungsrelation O ⊆ N × N, sodaß gilt: ∀x,y,z ∈ N: <x, y> ∈ E ∧ <x, z> ∈ E ∧ y ≠ z ⇒ <y, z> ∈ O ∨ <z, y> ∈ O Zwei Relationen: S NP Det unmittelbare Dominanz zwischen Mutter- und Tochterknoten VP N V NP lineare Präzedenz zwischen Tocherknoten Jeder Mann liebt Det N Die unmittelbaren Nachfolger eines Knotens stehen in einer linearen Ordnung. 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen eine Frau 19 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen Lineare Repräsentation in Prolog als Struktur: ?- det(ein) =.. L. L = [det,ein], yes ?- S =.. [det,ein]. S = det(ein), yes als Liste: [s, [np, [det, [jeder]], [n, [mann]]], [vp, [v, [liebt]], [np, [det, [eine]], [n, [frau]]]]] GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen Univ Strukturen und Listen können ineinander überführt werden. Prolog stellt dazu das eingebaute Prädikat =.. (Univ) zur Verfügung. s(np(det(jeder),n(mann)), vp(v(liebt),np(det(eine),n(frau)))) 29.11.99 21 29.11.99 Listen vs. Strukturen GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen ?- np(det(ein),n(mann)) =.. L. L = [np,det(ein),n(mann)] Allgemein: p(A1 ,...An ) =.. [p,A1 ,...An ] GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 22 Pretty Printing ?- pp(s(np(det(jeder),n(mann)), vp(v(liebt),np(det(eine),n(frau))))) s np det jeder Ein Pretty-Printer für Bäume ist n ein Programm, das die lineare mann vp Repräsentation eines Baumes als v eingerückten Baum auf den liebt np Bildschirm ausgeben kann. det eine n frau Strukturen sind zwar für das menschliche Auge leichter zu überblicken, dafür sind Listenrepräsentationen allerdings flexibler zu verarbeiten. – Strukturen: Zugriff auf Argumente nur bei bekanntem Funktor und bekannter Stelligkeit möglich. – Listen: Zerlegung in Kopf und Rest für jede nichtleere Liste in gleicher Weise. 29.11.99 20 23 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 24 4 Handwerkszeug zum Drucken pprint/1 Wir benötigen ein paar eingebaute Prädikate, um einen Pretty-Printer implementieren zu können: write(Term) nl tab(Integer) Number is Expr Schreibt Term auf den Bildschirm. Bewirkt einen Zeilenvorschub. Schreibt 0-n Leerzeichen. Führt Berechnungen durch. pprint(Term):- pprint(Term,0). Initialisierung. pprint(Term,N):Term =.. [Atom|[]], Termination. Term ist Blatt im Baum. tab(N), write(Atom), nl. pprint(Term,N):- Ausgabe des Blatts. Rekursion Term =.. [F|Args], Args \= [], Term ist Mutterknoten mit Töchtern. tab(N), write(F), nl, N1 is N+3, Ausgabe des Knotens. Tabulator erhöhen. pprintl(Args,N1). pprintl([H|T],N):pprint(H,N), pprintl(T,N). pprintl([],_). 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 25 29.11.99 Eine Differenzliste ist ein Paar von Listen (L1,L2), wobei L2 ein Suffix von L1 repräsentiert. Die Elemente einer Differenzliste sind die nach Abzug von Suffix L2 verbleibenden Elemente in L1. Differenzliste gewöhnliche Liste ([E1,...,En|T],T) [E1,...,En] (L,[]) L (L,L) [] GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 27 26 [1,2,3] ⇔ ⇔ ⇔ ⇔ 29.11.99 ([1,2,3],[]) ([1,2,3,4,5],[4,5]) ([1,2,3,a,b|T],[a,b|T]) ([1,2,3|T],T) GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 28 append_dl/3 Differenzlisten haben einen entscheidenden Vorteil gegenüber gewöhnlichen Listen: Man kann sie in konstanter Zeit konkatenieren. Genauer: in einem Schritt. ?- D1 = ([1,2,3|T1],T1), D2 =([4,5,6|T2],T2), append_dl(D1,D2,D3). D3 = ([1,2,3,4,5,6|T2],T2), yes GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen Termination. GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen Für jede gewöhnliche Liste gibt es unendlich viele Darstellungen als Differenzliste, weil es beliebige Suffixe geben kann. Konkatenation von Diff-Listen 29.11.99 Drucke eine Schwester. Drucke die anderen Schwestern. [1,2,3] als Differenzliste Differenzlisten 29.11.99 Unterbäume drucken. Schwesterknoten drucken. append_dl((A,B),(B,C),(A,C)). 29 29.11.99 GK Prolog - Verschachtelte Listen, Differenzlisten, Graphen 30 5