1 / 26

Effektiv prolog

Effektiv prolog. 25/11 2002 Staffan Larsson Logikprogrammering. Effektivitet. Tidsåtgång Minnesåtgång Utvecklingstid Hur viktiga de olika aspekterna är kan variera 0.1-1 sek mindre viktigt än 10-100 minuter. Prolog vs. andra språk.

Download Presentation

Effektiv prolog

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Effektiv prolog 25/11 2002 Staffan Larsson Logikprogrammering

  2. Effektivitet • Tidsåtgång • Minnesåtgång • Utvecklingstid • Hur viktiga de olika aspekterna är kan variera • 0.1-1 sek mindre viktigt än 10-100 minuter

  3. Prolog vs. andra språk • Generellt sett ngt mindre effektivt m a p tid än många andra språk • Mer effektivt m a p utvecklingstid • Lättare att skriva, förstå och debugga • Speciellt lämpat för vissa typer av problem • Symbolisk icke-numerisk processning • Strukturerade dataobjekt och deras relationer • T ex: planering, generell problemlösning, databaser, rapid prototyping, simulering, maskininlärning, natural language processing, AI • Mindre lämpat för matematik

  4. Några sätt att öka effektiviteten • Kompilerad kod istället för tolkad • Effektivare algoritmer • Cachning • spara resultat som kan bli användbara längre fram

  5. Effektivare algoritmer • Kräver • att man uppmärksammar de procedurella aspekterna av Prolog • Djupare förståelse av problemet (ev.) • Exempel • Förbättra ordningen på klausuler • Förbättra ordningen på mål i klausulernas ”body” • Användning av cut • Användning av ackumulatorer • Öka sökeffektivitet: undvik onödig backtracking, avsluta processning av onödiga alternativ snabbt • Mer ändamålsenliga datastrukturer, effektivare operationer

  6. Ändra ordning för att spara tid • Exempel: Färgläggning av karta • Varje land på en karta ska få en färg • Inga angränsande länder får ha samma färg • Kartan definieras av ngb/2 • ngb(Land, Grannar) • Där Grannar är alla länder som gränsar till Land

  7. databas ngb(albanien, [grekland, makedonien, jugoslavien]). ngb(andorra, [frankrike, spanien]). … ngb(österrike, [tjeckien, tyskland, italien, lichtenstein, slovakien, slovenien, schweiz]).

  8. Givet: en databas över länder och deras grannar • T ex de europeiska länderna • En lösning har formen av en lista av par Land/Färg • [albanien/C1, andorra/C2, … , österrike/Cn] • Problem: instansiera C1, C2, …, Cn • Vi definierar • färger(Land_färg_lista) • Sant om Land_färg_lista satisfierar begränsningen att inga angränsande länder har samma färg • Färger: gul, blå, röd, grön

  9. färger([]). färger([Land/Färg|Rest]):- färger(Rest), member(Färg, [gul, blå, röd, grön]), \+ ( member(Land1/Färg, Rest), granne(Land, Land1) ). granne(Land, Land1):- ngb(Land, Grannar), member(Land1, Grannar).

  10. Innan vi anropar färger/1 sätter vi ihop listan • [albanien/C1, andorra/C2, … , österrike/Cn] • Ci, 1<=i<=n, är oinstansierade • Vi definierar därför land(C):- ngb(C,_). ?- setof(Lnd/Färg, land(Lnd), LandFärgLista), färger(LandFärgLista).

  11. Denna lösning blir dock mycket ineffektiv; för Europa tar det väldans lång tid • Varför? • Länderna är ordnade alfabetiskt! • De tilldelas färger i alfabetisk ordning, utan hänsyn till geografiska relationer • Algoritmen hoppar ”slumpmässigt” omkring på kartan • Problem om en tidig tilldelning visar sig omöjlig först mot slutet, när dess sista granne ska få en färg

  12. Intuition: en bättre lösning vore… • Att börja från ett land med många grannar (t ex Tyskland) • Fortsätt till dess grannar • Fortsätt till grannarnas grannar, etc. • Detta kan göras manuellt, eller… • Definiera makelist/1 som konstruerar listan av land/färg-par

  13. makelist(List):- collect([tyskland], [], List). collect([], Closed, Closed). collect([X|Open], Closed, List):- member(X,Closed), !, collect(Open, Closed, List). collect([X|Open], Closed, List):- ngb(X, Ngbs), append(Ngs, Open, Open1), collect(Open1, [X|Closed], List).

  14. Differenslistor; sparar tid och minne • Exempel: konkatenering ?- append([1,2],[3,4],X). X=[1,2,3,4] • Standarddefinition: append([],L,L). append([X|L1], L2, [X|L3]):- append(L1,L2,L3).

  15. Exempelkörning: append([a,b],[c,d],L) append([b],[d,e], L’) där L=[a|L’] append([],[d,e], L’’) där L’=[b|L’’] true där L’’=[d,e] • Går igenom hela första listan, element för element • Går det att hoppa direkt till slutet av den först listan och direkt lägga till den andra listan?

  16. Kräver ett annat sätt att representera listor: differenslistor • Exempel: • [a,b] kan istället representeras av två listor • L1 = [a,b,c,d] • L2 = [c,d] • Paret L1-L2, d v s [a,b,c,d]-[c,d] representerar differensen mellan L1 och L2 • Kräver att L2 är ett suffix till L1

  17. Samma lista kan representeras av flera olika par: • [a,b]-[] • [a,b,c]-[c] • [a,b,c,d|T]-[c,d|T] • [a,b,c|T]-[c|T] • Tomma listan kan representeras som L-L • Den andra listan i paret representerar listans slut • Slutet på listan är direkt tillgängligt

  18. Differenslistor i appendDL/3: append_DL(A1-Z1, Z1-Z2, A1-Z2). • Tänk på A1, Z1, A2, Z2 som positioner i listan A1 Z1 A2 Z2 A2=Z1 L3 • Körning: ?- append_DL([a,b|T1]-T1, [c,d|T2]-T2, L). L = [a,b,c,d|T2]-T2, T1 = [d,e|T2] L1 L2

  19. . . . . . . . . . . . . . . . . . A1 A1-Z1 . . . . . . . . . . . . Z1 (A2) Z1-Z2 . . . . . . . Z2 . . . . . . . . . . . . . . . . . A1-Z2

  20. Svansrekursion • Rekursiva anrop tar upp minne • Minnet inte frigörs förrän anropet terminerar • Stort antal nästade rekursiva anrop kan leda till minnesbrist • I vissa fall kan nästade rekursiva anrop skrivas så att de har konstant minnesåtgång

  21. Detta kräver att proceduren har en speciell form: svansrekursion • Bara ett rekursivt anrop • I slutet på procedurens sista klausul • Prolog upptäcker detta och exekverar svansrekursion som iteration • reverse/2 med svansrekursion och ackumulator: reverse(List, Reversed):- reverse(List, [], Reversed). reverse([], Reversed, Reversed). reverse([X|Rest], PartRev, TotalRev):- reverse(Rest, [X|PartRev], TotalRev).

  22. Cachning • Ibland måste samma mål satisfieras om och om igen • Exempel: Fibonacci-tal • 1,1,2,3,5,8,13,21,34,55,89,… • Varje tal är summan av de två närmast föregående talen

  23. Vi definierar fib(+N,?F), där F är det N-te Fibonacci-talet fib(1,1). fib(2,1). fib(N,F):- N>2, N1 is N-1, fib(N1, F1), N2 is N-2, fib(N2, F2), F is F1+F2. • Detta är dock inte särsiklt effektivt

  24. Vi använder assert/1 för att spara varje uträknat Fibonacci-tal: fib2(1,1). fib2(2,1). fib2(N,F):- N>2, N1 is N-1, fib2(N1, F1), N2 is N-2, fib2(N2, F2), F is F1+F2, assert( fib2(N, F) ).

  25. Arrayer • Skapa en struktur med 100 element: • functor(A,f,100) • Imperativa språk: • A[60]:=1 • Prolog: • arg(60,A,1) • A=f(_, …, 1, …, _)

  26. Uppdatera arrayen? • Ha en lista av succesiva värden istället för ett värde, med ett ”hål” för framtida värdenm i slutet • X:=1 -> X=[1|Rest1] • X:=2 -> Rest1= [2|Rest2] • X:=3 -> Rest2 = [3|Rest3] • Resultat: X = [1,2,3|Rest3]

More Related