Anders Haraldsson 1 Anders Haraldsson 2 Dagens föreläsning Programmering i Lisp Fö 6-7 Rekursiva strukturer rekursiva definitioner rekursiva funktioner rekursiva bevis: induktion - rekursion strukturell induktion Metodik att skriva och verifiera rekursiva funktioner (kap 6.3, 8.1) flatten - platta ut lista olika löv i binärt träd reverse - vända lista sortering (avs 8.1.1) kombinationer (Övning 301) Rekursiva algoritmer sortering sökning mönstermatchning Detta ger mer information om sätt att lösa rekursiva problem i laboration och förutsättningarna för laboration 3 (ingående i TDDC67 Funktionell programmering och Lisp) Rekursiva definitioner: ett Lisp-uttryck är: - elementärt dataobjekt, t ex symbol, tal,... - en sekvens av Lisp-uttryck (Lisp-uttryck Lisp-uttryck... Lisp-uttryck) ett binärt träd är: - ett löv - ett par av två binära träd Fibonaccitalen kan definieras fib 0 = 0 fib 1 = 1 fib i = fib i-2 + fib i-1 fib 2 = fib 0 + fib 1 = 0 + 1 = 1 fib 3 = fib 1 + fib 2 = 1 + 1 = 2 fib 4 = fib 2 + fib 3 = 1 + 2 = 3 fib 5 = fib 3 + fib 4 = 2 + 3 = 5 Deriveringsregler: du ----- dx = 1 om u = x du ----- dx = 0 om u ej är en funktion i x d( u+ v) du dv ------------------- = ----- + ----- dx dx dx d u v ----------------- ) = v du ----- + u dv ----- dx dx dx d( 4x + 3) dx d4x d3 d4 dx = + = x + 4 = x 0 + 4 1 = 4 dx dx dx dx Anders Haraldsson 3 Anders Haraldsson 4 Rekursiva funktioner: Olika beräkningsmodeller: rekursiv processlösning iterativ processlösning (defun length (l) 0 (+ 1 (length (rest l))))) (defun leaves (bt) (if (leaves? bt) 1 (+ (leaves (car bt)) (leaves (cdr bt))))) (length (a b c)) -> (+ 1 (length (b c))) -> (+ 1 (+1 (length (c))) -> (+ 1 (+ 1 (+ 1 (length ))) -> (+ 1 (+ 1 (+ 1 0)))) -> (+ 1 (+ 1 1)) -> (+ 1 2) => 3 (leaves (a. (b. c))) -> (+ (leaves a) (leaves (b. c))) -> (+ (leaves a) (+ (leaves b) (leaves c))) -> -> (+ 1 (+ 1 1)) => 3 Induktionsbevis (= rekursivt bevis): För naturliga tal gäller: Om en egenskap gäller för n=0 samt om vi kan visa att: om egenskapen gäller för n=k gäller den även för n=k+1 => egenskapen gäller för alla n Ett krav är de objekt som vi gör induktion över måste vara välordnade (well-ordering principle). Det minsta (least) elementet är för heltalen 0. Vi kan ej göra induktionsbevis över t ex reella tal. n Visa att Σ i = n * (n + 1) / 2 5 Σ i = 1+2+3+4+5 = 5* 6 / 2 = 15 Bevis Visa för n = 1. Trivialt. 1 * (1+ 1) / 2 = 1 k Antag gäller för n = k, dvs Σ i = k * (k + 1) / 2 k+1 Visa att det gäller för n = k+1, dvs Σ i = (k + 1) * (k + 2) /2 k+1 k Σ i=σ i + (k + 1) = k * (k + 1) /2 + (k + 1) =.. = (k + 1) * (k + 2) /2
Anders Haraldsson 5 Anders Haraldsson 6 Låt oss ser hur vi implementerar det i ett program: (defun sum (n) (if (= n 1) 1 (+ (sum (- n 1)) n))) För att se att sambandet gäller med n= k + 1 kan vi stoppa in k+1 istället för n. (sum (+ k 1)) = (+ (sum (- (+ k 1) 1)) (+ k 1)) = (+ (sum k) (+ k 1)) Nu kan vi bevisa att funktionen är korrekt. För n=1 trivilt. Antag funktionen korrekt för n=k, dvs (sum k) ger korrekt värde, dvs skall ge det värde som är samma som k * (k+1) / 2. Vi visar det för n= k+1. Programmet säger att ta det antagna värdet av n=k, dvs k * (k+1) / 2 och lägg till k +1 då skall vi få (k+1) * (k+2) / 2 Lite räkning ger att båda uttrycken ger (k 2 +3k+2)/2 Vi har visat att programmet är korrekt! Induktion (strukturell): Om en egenskap gäller för den tomma sekvensen samt om vi kan visa att: om egenskapen gäller för en sekvens med k element gäller den även för en sekvens med k+1 element => egenskapen gäller för sekvenser av godtycklig längd Välordningsprincipen (well-ordering-principle) gäller för sekvenser med avseende på operationerna: lägg-tillett-element / ta-bort-ett-element. Det minsta (the least) elementet är tomma sekvensen. Vi kan alltså resonera om egenskaper hos sekvenser. Samma resonemang kan vi föra för binära träd: Om en egenskap gäller för alla löv samt att vi kan visa att: om egenskapen gäller för två binära träd bt 1 och bt 2 gäller den även för det binära träd som bildas av paret av bt 1 och bt 2. => egenskapen gäller för alla binära träd Anders Haraldsson 7 Anders Haraldsson 8 Vi skulle kunna använda denna princip för att bevisa att funktioner är korrekta (program verification). Detta är svårt! Vi skall använda induktionstänkandet mer informellt och använda det som metodik att definiera och informellt verifiera rekursiva funktioner. Platta ut lista - flatten På tavlan. Se läroboken. Att definiera rekursiva funktioner: A) Utgå från lämplig mall, hitta operationer att utföra i de olika fallen. Ta representativa testfall. Resonera analogt med induktionsbevis, antag det rekursiva anropet korrekt. ex: flatten B) Hitta sambandet mellan två rekursiva steg. ex: reverse, kombinationer Verifiera en lösning: A) Ta representativa testfall. Resonera igenom ett varv. Antag det rekursiva anropet korrekt. B) Utveckla ett exempel med substitutionsmetoden. Man måste ha ganska små exempel, annars kan det bli många steg att genomföra. Metod B beskriver även typ av processlösning (iterativ eller rekursiv) C) På dator använd tex trace
Anders Haraldsson 9 Anders Haraldsson 10 Metod: Fokusera operationerna! Ändra ej i mallstrukturen! Vilka olika löv finns i ett binärt träd? a c a b (leaves ((a. (a. b)). (c. b))) => (a b c) (leaves x) => (x) (defun leaves (bt) (if (atom bt)? (? (leaves (car bt)) (leaves (cdr bt))))) b Vända på lista - reverse Mall: rekursiv processlösning. Finn operationen mellan två steg. Beskriv den i naturligt språk. Definiera Vända på en lista. (reverse ) => () (reverse '(c)) => (c) (reverse '(b c)) => (c b) (reverse '(a b c)) => (c b a) Observera hur vi formar testfallen. Samma element bakifrån! (defun reverse (l) (? (first l) (reverse (rest l)))))? = (putlast 'q '(a b c)) => (a b c q) Anders Haraldsson 11 Anders Haraldsson 12 Exempel: sortering (insertsort (4 7 5 2 8)) => (2 4 5 7 8) Utgå från mall rekursiv processlösning: (defun insertsort (l) (? (first l) (insertsort (rest l))))) Försök karakterisera (i ord) vad funktionen? skall göra. Några exempel: (insertsort (6 7 5)) -> (? 6 (insertsort (7 5))) -> (? 6 (? 7 (insertsort (5)))) -> (? 6 (? 7 (? 5 ))) -> (? 6 (? 7 (5))) -> (? 6 (5 7)) => (5 6 7)? = (defun? (e l)... ) karakterisera de formella parametrarna e och l. Vilka slags värden kan de antaga? Kombinationer (se övning 301 i labkompendiet) Ta fram alla tupler som kan skapas av element från ett godtyckligt antal mängder av godtycklig storlek, (dvs den kartesiska produkten). Allt representerat som listor. (kombinationer ) => (()) (kombinationer ((x y))) => ((x) (y)) (kombinationer ((r s) (x y))) => ((r x) (r y) (s x) (s y)) (kombinationer ((a b) (r s) (x y)) => ((a r x) (a r y) (a s x) (a s y) (b r x) (b r y) (b s x) (b s y)) (defun kombinationer (mängdlista) (if (endp mängdlista)?a (?b (first mängdlista) (kombinationer (rest mängdlista))))) Karakterisera?a och?b.
Anders Haraldsson 13 Anders Haraldsson 14 Kombinationer (se övning 301 i labkompendiet) Ta fram alla tupler som kan skapas av element från ett godtyckligt antal mängder av godtycklig storlek, (dvs den kartesiska produkten). Allt representerat som listor. Vi måste då definiera en funktion?b. (?b (a b) ((r x) (r y) (s x) (s y))) => ((a r x) (a r y) (a s x) (a s y) (b r x) (b r y) (b s x) (b s y))?b tar 2 parametrar, en lista med element och en lista med listor med element. Vi skall skapa en ny lista där varje element i första parametern skall bli förstaelement i dellistorna i andra parametern. Sortering Det finns ett stort antal olika metoder. Vi illustrerar några här. De bygger på att vi skall skapa en ny struktur med de sorterade elementen. Metoderna kan modifieras så att man flyttar om elementen i samma struktur: Insert sort Ta ett element i taget och stoppa in det i den resulterande sorterade listan. Selection sort Hitta största elementet och lägg i resultatlista, hitta det näst största och lägg dit etc. Övning 303 i Lisplabbkompendiet. Quick sort Välj ett element, dela upp de övriga i två högar, de som är mindre resp de som är större. Sortera dessa högar. Skall löses i uppgift 3c. Anders Haraldsson 15 Anders Haraldsson 16 Insert sort Rekursiv processlösning (defun insertsort (l) (insert (first l) (insertsort (rest l))))) (defun insert (e sorted-l) (cond ((endp sorted-l) (list e)) ((< e (first sorted-l)) (cons e sorted-l)) (t (cons (first sorted-l) (insert e (rest sorted-l)))))) (insertsort (4 7 5 2 8)) 0: (INSERT 8 NIL) 0: returned (8) 0: (INSERT 2 (8)) 0: returned (2 8) 0: (INSERT 5 (2 8)) 1: (INSERT 5 (8)) 1: returned (5 8) 0: returned (2 5 8) 0: (INSERT 7 (2 5 8)) 1: (INSERT 7 (5 8)) 2: (INSERT 7 (8)) 2: returned (7 8) 1: returned (5 7 8) 0: returned (2 5 7 8) 0: (INSERT 4 (2 5 7 8)) 1: (INSERT 4 (5 7 8)) 1: returned (4 5 7 8) 0: returned (2 4 5 7 8) (2 4 5 7 8) Vi skapar den nya sorterade listan genom att lägga in elementen bakifrån från den osorterade listan. Insert sort Iterativ processlösning (defun insertsort (l) (insertsort-iter l )) (defun insertsort-iter (l sorted-res) sorted-res (insertsort-iter (rest l) (insert (first l) sorted-res)))) (defun insert (e sorted-l) (cond ((endp sorted-l) (list e)) ((< e (first sorted-l)) (cons e sorted-l)) (t (cons (first sorted-l) (insert e (rest sorted-l)))))) (insertsort (4 7 5 2 8)) 0: (INSERT 4 NIL) 0: returned (4) 0: (INSERT 7 (4)) 1: (INSERT 7 NIL) 1: returned (7) 0: returned (4 7) 0: (INSERT 5 (4 7)) 1: (INSERT 5 (7)) 1: returned (5 7) 0: returned (4 5 7) 0: (INSERT 2 (4 5 7)) 0: returned (2 4 5 7) 0: (INSERT 8 (2 4 5 7)) 1: (INSERT 8 (4 5 7)) 2: (INSERT 8 (5 7)) 3: (INSERT 8 (7)) 4: (INSERT 8 NIL) 4: returned (8) 3: returned (7 8) 2: returned (5 7 8) 1: returned (4 5 7 8) 0: returned (2 4 5 7 8) (2 4 5 7 8) Här tar vi elementen framifrån och lägger in i den sorterade listan.
Anders Haraldsson 17 Anders Haraldsson 18 Sökalgoritmer Algoritm där man provar olika alternativ och backar tillbaka beräkningen då ett alternativ ej leder fram till målet. C B D A F E I Hur backar man tillbaka beräkningen? G H Backtracking -algoritmer i läroboken - Ni har kanske arbetat med back-find som är ett exempel på en sådan algoritm. - Hitta väg i ett binärt träd (avs 7.1.2) - Grafsökning (avs 8.4) - Mönstermatchning (avs 8.5) Hitta väg i ett binärt träd (avs 6.4.5) Representationav ett löv: nod Representation av en intern nod: (nod vänster-delträd höger-delträd) (setq my-tree (a (b c d) (e (f g h) i))) (find-path h my-tree) => (a e f h) (find-path d my-tree) => (a b d) (find-path j my-tree) => () (find-path b my-tree) => () ; ty b är inget löv i det binära trädet Anders Haraldsson 19 Anders Haraldsson 20 Hitta väg i ett binärt träd (avs 6.4.5) (defun find-path (node bt) (if (leaf? bt) (if (same-label? node bt) ; önskat löv? (make-path bt); skapa väg av ett löv ) (let ((left-path (find-path node (left bt)))) ; försök hitta väg åt vänster (if (path? left-path) (add-path (label bt) left-path) (let ((right-path (find-path node (right bt)))) ; försök hitta väg åt höger (if (path? right-path) (add-path (label bt) right-path) ))) ))) ; fanns ingen väg (defun leaf? (bt) (atom bt)) (defun label (bt) (first bt)) (defun left (bt)(second bt)) (defun right (bt) (third bt)) (defun add-path (label p) (cons label p)) (defun make-path (label) (list label)) (defun path? (p) (not (eq p ))) (defun same-label? (n1 n2) (eq n1 n2)) Mönstermatchning används: - kommandospråk avslutande av kommandon cl-allegesc användning av sk wild-card delete a*.lsp - sökmotorer på Internet - naturligt språk hantering ett -godtyckligt antal ord- hus matchar ett hus, ett rött hus, ett litet rött hus
Anders Haraldsson 21 Anders Haraldsson 22 Mönstermatchning I detta exempel skall vi matcha listor. Vi skall ha följande mönstersymboler: & som matchar ett godtyckligt tecken -- som matchar inget, ett eller flera tecken, kallas segment Mönstret (a & b &) matchas av (a x b y), (a a b b) men matchas ej av (b x a y), (a b), (a x b y c) Mönstret (a -- b) matchas av (a b), (a x b), (a x y b), (a1234567890b), men matchas ej av (a x y), (a x b y) Matchningen behöver ej bli unik: Mönstret (a -- b --) matchar (a x b y b z) på två olika sätt: (a x b y b z) (a x b y b z) Mönstermatchning Det stora problement i mönstermatchning är segementmönstret. Vi måste här pröva oss fram. Vi kan inte från början säga hur många element som segmentmönstret skall matcha. Vi börjar matcha segmentmönstret med inget element och försöker matcha resten, går ej detta, matchar vi segmentmönstret med ett element, sedan två etc till ev alla elementen är slut. (a -- b) matchas mot (a x y b) Segementmönstret matchar inget element, försök matcha (b) med (x y b). Misslyckas. Låt segmentmönstret matcha x. Försök matcha (b) med (y b). Misslyckas. Låt segmentmönstret även matcha y, dvs både x och y. Försök matcha (b) med (b). Lyckas! Problement är att vi måste gå vidare och matcha resten. Om detta misslyckas skall vi backa tillbaka matchningen till hanteringen av segmentmönstret igen. Anders Haraldsson 23 Anders Haraldsson 24 Mönstermatchning patmatch (defun patmatch (l pat) (cond ((endp pat) (endp l)) ; slut på mönster och lista? ((eq (first pat) ' --) ; segmentmönster (cond ((patmatch l (rest pat)) t) ; matchar resten? ((endp l) nil) ; misslyckas, segmentmönstret ; matchade hela resten (t (patmatch (rest l) pat)))) ; låt segmentmönstret även ; matcha ett element ; inget att matcha emot ; matcha godtyckligt element ((endp l) nil) ((eq (first pat) '&) (patmatch (rest l) (rest pat))) ((eql (first pat) (first l)) ; lika match (patmatch (rest l) (rest pat))) (t nil))) ; misslyckas Exempel (patmatch (a b c d) (& & & &)) ; har listan 4 element? (patmatch ; slutar listan med d? (a b c d) (-- d)) (patmatch ; slutar listan med b och c? (a b c d b c) (-- b c)) (patmatch ; innehåller en lista b? (a b c d) (-- b --)) (patmatch ; innehåller en lista först b, sedan c och (a b c d e f) ; sedan e i tur och ordning (-- b -- c -- e --)) (patmatch (-- --)) = t
Anders Haraldsson 25 (patmatch ; slutar listan med b och c? (a b c d b c) (-- b c)) 0: (PATMATCH (A B C D B C) (-- B C)) 1: (PATMATCH (A B C D B C) (B C)) 1: returned NIL 1: (PATMATCH (B C D B C) (-- B C)) 2: (PATMATCH (B C D B C) (B C)) 3: (PATMATCH (C D B C) (C)) 4: (PATMATCH (D B C) NIL) 4: returned NIL 3: returned NIL 2: returned NIL 2: (PATMATCH (C D B C) (-- B C)) 3: (PATMATCH (C D B C) (B C)) 3: returned NIL 3: (PATMATCH (D B C) (-- B C)) 4: (PATMATCH (D B C) (B C)) 4: returned NIL 4: (PATMATCH (B C) (-- B C)) 5: (PATMATCH (B C) (B C)) 6: (PATMATCH (C) (C)) 7: (PATMATCH NIL NIL) 7: returned T 6: returned T 5: returned T 4: returned T 3: returned T 2: returned T 1: returned T 0: returned T