• No results found

Material för KTH-kursen

N/A
N/A
Protected

Academic year: 2022

Share "Material för KTH-kursen"

Copied!
88
0
0

Loading.... (view fulltext now)

Full text

(1)

Material för KTH-kursen

Logikprogrammering, del av DD1351

Thomas Sjöland sjoland@kth.se SCS, Software and Computer Systems

EECS - School of Electrical Engineering and Computer Science KTH, The Royal Institute of Technology

(2)

Efter godkänd kurs ska studenten kunna:

specificera allmänna egenskaper hos matematisk-datalogiska strukturer och bevisa dessa med hjälp av naturlig deduktion i satslogik och predikatlogik,

specificera induktiva definitioner hos datastrukturer och bevisa dessa med strukturell induktion, specificera och bevisa systemegenskaper med hjälp av temporal logik,

specificera och bevisa programegenskaper med hjälp av Hoarelogik,

tillämpa metoder för automatisk deduktion och utföra enkla bevis med modellprövning,

tillämpa och förklara grundläggande begrepp inom logikprogrammering: unifiering, backtracking, snitt, negering och olika programmeringstekniker som t.ex. generate- test

i syfte att

behärska de bevistekniker som behövs i kommande kurser i utbildningen.

För högre betyg ska studenten dessutom kunna:

argumentera för korrektheten hos en viss bevisteknik: sundhet och fullständighet, argumentera för bevisteknikers lämplighet till automatisk deduktion: avgörbarhet.

Lärandemål DD1351

(3)

Logik som programmeringsspråk - Prolog Likhet för termer - Unifiering

Rekursion, backtracking

DD1351 F1 12/9

(4)

Logikprogrammering 1 Thomas Sjöland, KTH

(från Dilian Gurov, KTH för DD1361, HT17)

DD1351

Logik för Dataloger HT18

(5)

• Logisk versus procedurell läsning

• Kontrollflöde: Unifiering, Backtracking, Snitt

• Induktiva datatyper och rekursion

• Inbyggda datatyper: listor

• Datatyper med Prolog-termer: träd

• Programmeringtekniker med Prolog

• Generera-och-testa

Delkursinnehåll

(6)

Den deklarativa aspekten:

• Problemdomänbeskrivning med relationer

• Fakta och regler

• Antagandet om en sluten värld, Prolog-negation

• Induktiva datatyper som termer

• Inbyggda och implicita i Prolog

• Strukturell induktion: en princip att garantera well-definedness

Den procedurella aspekten: Kontrollflödet

• Unifiering

• Backtrackning

• Typisk programstruktur: generera-och-testa

• Snitt

Lärandemål

(7)

• Se kurswebbsidorna: Före kursstart, Kursmaterial

• Kursbok: Learn Prolog Now!

P. Blackburn, J. Bos, och K. Striegnitz

Free online version: www.learnprolognow.org

• SWI-Prolog manual

• Föreläsningsanteckningar

• Prolog-l: *.pl

Delkurslitteratur och -material

(8)

Ämnen

• Deklarativ- och logik-programmering

• Satser: fakta och regler

• Logisk versus procedurell läsning

• Unifiering

• Backtracking

• Rekursion

Läsmaterial

• Boken: kap. 1-3

• Prolog-l: intro.pl

• Föreläsningsanteckningar

Idag

(9)

Deklarativ programmering

• Programmet är en beskrivning av problemdomänen

• Exekveringar resulterar från frågor (queries)

Logikprogrammering

• En konkret realisering av deklarativ programmering med hjälp av predikat som beskriver relationer mellan objekt

• Domänen beskrivs som en sammansättning av

predikatlogiska formler i så kallad Horn-klausul form

• Frågor besvaras med en sök-algoritm som kallas resolution

Deklarativ- och logikprogrammering

(10)

Om f är en funktion så kan vi skriva:

f (a) = b (a, b) ∈ f f (a, b)

funktion relation predikat

Relationer är dock mer generella: inte varje relation är en funktion.

Exempel: ”Fadern till a är b" kan deklareras:

o som funktion: far (a) = b o som predikat: far (a, b)

Däremot är ”a är dotter till b" en relation men ingen funktion!

Från funktioner till predikat

(11)

Relationer kan deklareras explicit, varje tupel för sig själv.

Sådana definitioner kallas för fakta:

far(agnes, petter).

far(per, petter).

far(anton, per).

mor(agnes, annika).

mor(per, annika).

mor(kia, agnes).

mor(anton, agnes).

Satser: fakta

(12)

Nu när vi har skapat en relationell databas, vill vi kunna ställa

frågor (queries) till den.

?- far(agnes, per).

?- far(anton, per).

?- far(monika, per). % Closed world assumption!

Notera att Prolog inte vet vad vi menar med alla symboler: den resonerar helt symboliskt, utan tolkning!

Prolog vet inte om far(a, b) betyder ”fadern till a är b", eller ”a är fader till b", eller t.o.m. att ”himlen har färgen a och det är b stycken moln på den".

Queries

(13)

Vi kan också ställa frågor som involverar variabler:

?- far(agnes, X). % Vem är far till agnes?

% Eller, för vilka X är det sant % att fadern till agnes är X?

?- far(X, petter). % Vems fader är petter?

% Flera svar möjliga!

% Fås fram med 'n' eller ";"

?- far(X, Y).

Fler queries

(14)

Relationer kan också definieras med regler:

farmor(X, Y) :- far(X, Z), mor(Z, Y).

Läs: farmodern till X är Y

om fadern till X är (någon) Z och modern till Z är Y.

Vi kan observera att:

":-" läses som "om", dvs implikation ”<-" i omvänd riktning

"," läses som "och", dvs konjunktion "^"

variablerna är (implicit) universellt kvantifierade Sådana formler (satser) kallas för Horn-klausuler

Satser: regler

(15)

Disjunktiva regler kan ges som separata regler:

foralder(X, Y) :- far(X, Y).

foralder(X, Y) :- mor(X, Y).

Läs:

en förälder till X är Y (OBS: relation, inte funktion!) om fadern till X är Y

eller modern till X är Y.

Följer logiska ekvivalensen:

p v q -> r  (p -> r ) ^ (q -> r )

Satser: regler

(16)

Predikatlogikens syntax har både

predikatsymboler såsom funktionssymboler, tagna från olika syntaktiska mängder. I Prolog däremot finns det ingen syntaktisk skillnad mellan dem, och båda representeras som atomer. Det är

kontexten som bestämmer hur symbolerna tolkas.

Tex i satsen:

a(b, c(X)).

är a en 2-ställig predikatsymbol, c en 1-ställig funktionssymbol,

b en konstant (dvs en 0-ställig funktionssymbol), och X en variabel.

Prolog-termer

(17)

En riktad graf består av en mängd noder och en mängd riktade bågar mellan noderna. Hur kan vi representera grafer i Prolog?

Representation som Prolog-fakta:

• node(a). deklarerar en nod

• edge(a, b). deklarerar en båge

Varför inte bara edge-deklarationer?

Representationen kan vara svår att arbeta med, tex att skicka som argument till ett predikat.

Problemdomänbeskrivning: Grafer

(18)

Representation som Prolog-term:

• noder är atomer a, b, c, . . .

• bågar är termer edge(a, b)

• grafer är termer graph(Nodes, Edges) där

Nodes är en lista av noder, och Edges är en lista av bågar

Problemdomänbeskrivning: Grafer

(19)

Två termer kan unifieras om det finns en substitution (med termer) för variablerna i termerna, så att båda termerna blir syntaktiskt identiska.

Exempel:

• X och agnes unifierar med substitutionen X = agnes

• far(X, petter) och far(agnes, petter) unifierar med substitutionen X = agnes

• far(agnes, Y) och far(agnes, petter) unifierar med substitutionen Y = petter

• far(X, petter) och far(agnes, Y) unifierar med substitutionen X = agnes, Y = petter

• Kan far(X, petter) och far(agnes, X) unifiera?

Term-unifiering

(20)

Logisk läsning

 som en predikatlogisk formel, deklarativt

Procedurell läsning

 proceduren som Prolog följer för att hitta ett bevis

 Prolog läser fakta och regler uppifrån och ned, och klausuler från vänster till höger

 Prolog försöker instansiera variablerna med termer så att målet blir sant: unifiering

 om detta misslyckas med ett faktum eller en regel, går Prolog till föregående klausul inom regelns kropp om en sådan finns, och annars till nästa faktum eller regel i programmet: backtracking

Logisk versus procedurell läsning

(21)

Hur Prolog exekverar

En fråga?- p(Args).

Bevisas med resolution

- leta efter alla klausuler som definierar p - välj den första, spara de kvarvarande som

alternativ

- matcha argumenten Args med termerna i

klausulens huvud, skapa nödvändiga variabel- bindningar med unifiering

- om unifieringen misslyckas, prova nästa alternativa klausul

- bevisa annars målen i kroppen från vänster till

höger; om detta misslyckas, prova alternativklausul - om alla bevis är klara, presentera bindningarna,

annars resultatet ”no” eller ”fail”.

(22)

Mål: farmor(anton, X).

Skapar regelinstans:

farmor(X1, Y1) :- far(X1, Z1), mor(Z1, Y1).

unifierar X1=anton, Y1=X Delmål: far(anton, Z1).

unifierar Z1=per

Delmål: mor(per, X).

unifierar X=annika Svar: X=annika

Kontrollflödet i Prolog: Exempel 1

(23)

 Mål: foralder(kia, X).

 Skapar regelinstans: foralder(X1, Y1) :- far(X1, Y1).

unifierar X1=kia, Y1=X

 Delmål: far(kia, X).

Kan inte unifieras. Backtrackar till nästa regel.

 Skapar regelinstans: foralder(X2, Y2) :- mor(X2, Y2).

unifierar X2=kia, Y2=X

 Delmål: mor(kia, X).

unifierar X=agnes

 Svar: X=agnes

Kontrollflödet i Prolog: Exempel 2

(24)

Regler kan vara rekursiva, dvs referera till sig själv:

forfader(X, Y) :- foralder(X, Y).

forfader(X, Y) :- foralder(X, Z), forfader(Z, Y).

Betrakta frågan:

?- forfader(kia, X).

Vad blir kontrollflödet till första svaret?

Och till andra svaret? (';' leder till backtracking!)

Vad skulle hända om vi vänder om ordningen på de två reglerna?

Och på de två konjunkterna i andra regeln?

Rekursion

(25)

För att få en bättre förståelse av

kontrollflödet i Prolog och trace-funktionen, läs också om lådmodellen: se handouts.

Kontrollflödet i Prolog: Lådmodellen

(26)

Induktiva datatyper: Listor (inbyggt)

DD1351 F2 17/9

(27)

Logikprogrammering 2 Thomas Sjöland, KTH

(från Dilian Gurov, KTH för DD1361, HT17)

DD1351

Logik för Dataloger HT18

(28)

Induktiva datatyper: Listor (inbyggt)

• Listor

• Strukturell induktion över listor

• Kontrollflöde

• Generera och testa

• Strängar

Läsmaterial

• Boken: kap. 4, 6

• Prolog-l: list.pl

• Handouts: Föreläsningsanteckningar

Idag

(29)

Listorna utgör en oändlig mängd av Prolog-termer.

Induktiv definition:

en lista är antingen tom [], eller en konstruktion [H | T]

av ett element H ("huvud") och en lista T ("svans").

Listor

(30)

Definition i Backus-Naur Form (BNF):

<Lst> ::= [] | [<El>|<Lst>]

där <El> är vilken som helst Prolog-term.

Därmed matchar varje lista l antingen []

eller [H | T] , och vi kan använda detta för att ta isär (destruera) listor för att definiera predikat över listor med strukturell

induktion.

Listor

(31)

Notationskonvention:

Vi skriver [a, b, c]

istället för

[a | [b | [c | []]]],

detta gör också Prologs "pretty-print".

OBS även konvention! ’.’(H,T)= [H|T]

Listor

(32)

För induktivt definierade datatyper kan vi använda oss av strukturell induktion för att definiera predikat över dem.

Konkret, för listor:

• för tomma listan [], definiera predikatet icke-rekursivt;

• för sammansatta listan [H | T] , definiera predikatet med användning av samma predikat, men bara över svansen T.

Om man följer principen garanterar man att predikatet blir

"väldefinierat" över alla listor.

Läs också texten: "The Principle of Structural Induction" !

Strukturell induktion över listor

(33)

is_list([]).

is_list([ _ | T]) :- is_list(T).

first_element([ E | _],E).

last_element([E],E).

last_element([ _ | T],E) :- last_element(T,E),

% OBS syntax: [A] = ’.’(A,[]) = [A|[]]

Predikat över listor

(34)

Längden på en lista L är antalet element N i listan.

Definition med strukturell induktion:

• längden på tomma listan [] är 0;

• längden på sammansatta listan [H | T] är längden på svansen T plus 1.

Låt oss använda detta för att implementera listLength(L, N).

Längden på en lista

(35)

I Prolog:

listLength([], 0).

listLength([ _ | T], N) :- listLength(T, NT), N is NT + 1.

Notera att vi använder operatorn "is" istället för "=". Varför?

Notera också hur vi använder mönster-matchning i första argumentet för att åstadkomma datatyp-destruktionen som är

nödvändig för strukturella induktionen.

Kan vi vända på ordningen på de två konjunkterna?

Finns även inbyggd som length(L, N).

listLength(L, N)

(36)

Mål: listLength([a, b], N).

skapar en instans av andra regeln:

listLength([A1 | T1], N1) :- listLength(T1, NT1), N1 is NT1 + 1.

unifierar A1=a, T1=[b], N1=N

Delmål: listLength([b], NT1).

skapar instans av andra regeln:

listLength([A2 | T2], N2) :- listLength(T2, NT2), N2 is NT2 + 1.

unifierar A2=b, T2=[], N2=NT1

Delmål : listLength([], NT2).

matchar första regeln, unifierar NT2=0

Delmål : NT1 is 0 + 1.

evaluerar 0+1 till 1, unifierar NT1=1

Delmål : N is 1 + 1.

evaluerar 1+1 till 2, unifierar N=2

Svar: N=2

Kontrollflödet vid listLength([a, b], N).

(37)

Från KS:en HT15:

Fråga: length(L, 2).

- misslyckas med första regeln, därför att 0 och 2 inte kan unifieras;

- skapar instans av andra regeln:

length([A1|T1], N1) :- length(T1, NT1), N1 is NT1+1.

unifierar: L=[A1|T1], N1=2;

-- length(T1, NT1).

--- lyckas med första regeln;

unifierar: T1=[], NT1=0;

-- 2 is 0+1.

--- evaluerar 0+1 till 1;

--- misslyckas, därför att 2 och 1 inte kan unifieras;

--- backtrackar;

….. (forts på nästa bild)

Kontrollflödet vid listLength(L, 2).

(38)

Från KS:en HT15:

….

(Forts från föregående bild) -- length(T1, NT1).

--- skapar instans av andra regeln:

length([A2|T2], N2) :- length(T2, NT2), N2 is NT2+1.

unifierar: T1=[A2|T2], N2=NT1;

---- length(T2, NT2).

--- lyckas med första regeln;

unifierar: T2=[], NT2=0;

---- NT1 is 0+1.

--- evaluerar 0+1 till 1;

--- unifierar: NT1=1;

-- 2 is 1+1.

--- evaluerar 1+1 till 2;

--- lyckas, därför att 2 kan unifieras med 2.

Svar: L=[A1|[A2|[]]] som presenteras som L=[A1, A2].

Kontrollflödet vid listLength(L, 2). (forts)

(39)

Medlemstest som ska vara sant om och bara om X finns i listan L.

in(H, [H | _]).

in(X, [_ | T]) :- in(X, T).

Strukturella induktionen är över listan L (dvs andra argumentet).

in(X, []) är alltid falskt, därför ingen regel för tom lista!

Finns även inbyggd som member(X, L).

Medlemskap i en lista: in(X, L)

(40)

Mål: in(2, L), in(1, L).

Delmål: in(2, L).

skapar instans av första regeln:

in(H1, [H1 | A1]).

unifierar H1=2, L=[2 | A1]

Delmål : in(1, [2 | A1]).

skapar instans av första regeln:

in(H2, [H2 | A2]).

misslyckas med unifieringen (varför?)

skapar instans av andra regeln:

in(X1, [A3 | T1]) :- in(X1, T1).

unifierar X1=1, A3=2, T1=A1

Delmål : in(1, A1).

skapar instans av första regeln:

in(H3, [H3 | A4]).

unifierar H3=1, A1=[1 | A4]

Svar: L =[2, 1 | A4] Finns det fler svar?

Kontrollflödet vid in(2, L), in(1, L).

(41)

Ska vara sant om Z är konkateneringen av listan X med listan Y.

concatenate([], Y, Y).

concatenate([HX | TX], Y, [HX | TZ]) :- concatenate(TX, Y, TZ).

Strukturella induktionen är över listan X (dvs första argumentet).

Finns även inbyggd som append(X, Y, Z).

Listkonkatenering: concatenate(X, Y, Z)

(42)

Listor

Konkatenering av två listor

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append([a,b], [c,d], X). - sammansättning av två listor

. .

a b

[] . .

c d

[]

. .

a b

. .

c d

[]

(43)

Listor

“differens” mellan två listor

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, [c,d], [a,b,c,d]).

- finner “differensen” mellan listor

. .

a b

[] . .

c d

[]

. .

a b

. .

c d

[]

(44)

Listor

Att dela upp en lista i två delar (1)

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, Ys, [a,b,c,d]).

. .

a b

[] . .

c d

[]

. .

a b

. .

c d

[]

(45)

Listor

Att dela upp en lista i två delar (2)

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, Ys, [a,b,c,d]).

. .

a b

[] . .

c d

[]

. .

a b

. .

c d

[]

(46)

Listor

Att dela upp en lista i två delar (3)

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, Ys, [a,b,c,d]).

. .

a b

[] . .

c d

[]

. .

a b

. .

c d

[]

(47)

Listor

Att dela upp en lista i två delar (4)

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, Ys, [a,b,c,d]).

. .

a b

. .

c d

[]

. .

a b

. .

c d

[]

[]

(48)

Listor

Att dela upp en lista i två delar (5)

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs]) :- append(Xs, Y, Zs).

?- append(Xs, Ys, [a,b,c,d]).

. .

a b

. .

c d

[]

. .

a b

. .

c d

[]

[]

(49)

Listor

Att vända på en lista

reverse([], []).

reverse([H|T],R) :- reverse(T,S), append(S,[H],R).

?- reverse([a,b,c,d],R). - ger R=[d,c,b,a]

. .

a b

. .

c d

[]

. .

d c

. .

b a

[]

(50)

Ska vara sant om listan NL är listan L med elementet X tillagt i slutet.

appendEl(X, [], [X]).

appendEl(X, [H | T], [H | Y]) :- appendEl(X, T, Y).

Strukturella induktionen är över listan L (dvs andra argumentet).

Lägg till ett element: appendEl(X, L, NL)

(51)

Ska vara sant om Y är omvända listan X.

rev([], []).

rev([H | T], Y) :- rev(T, RT),

appendEl(H, RT, Y).

Finns även inbyggd som reverse(X, Y).

Listomvändning: rev(X, Y)

(52)

Ackumulerarnde parametrar

Reversering av listor

a) naive reverse (använder append I varje rekursionssteg) reverse([], []).

reverse([X|Xs], Ys) :-

reverse(Xs, Zs), append(Zs, [X], Ys).

b) reverse med ackumulator (arg 2 I hjälppredikatet)

reverse(Xs, Ys) :-

reverse(Xs, [], Ys).

reverse([], Acc, Acc).

reverse([X|Xs], Acc, Ys) :-

reverse(Xs, [X|Acc], Ys).

(53)

Strängar

• Är symbolsekvenser.

• Representeras i Prolog internt som listor av heltal. Varje tal representerar därmed en

symbol (ASCII-koden).

• Inbyggda predikatet atom_codes(X, Y) är sant när Y är strängen (dvs heltalslistan)

som motsvarar atomen X.

Strängar

(54)

Det finns många sätt att sortera listor.

Här ska vi implementera

permutationssortering, som illustration

av hur vi kan använda backtracking som en styrka för att realisera en

programmeringsteknik som kallas för generera och testa.

Listsortering

(55)

Denna programmeringsteknik använder sig av

backtracking för att successivt generera en möjlig lösning, testa om den uppfyller villkoren för att vara en korrekt

lösning, sedan backtracka och generera en möjlig lösning till, testa den, osv.

Generella strukturen ser ut så här:

problem(Problem, Solution) :-

generate(Problem, Solution), test(Solution).

För effektivitet behöver man ofta lägga in test i generatorn.

Generera och testa

(56)

Vi utgår från den matematiska definitionen av sortering: att sortera en lista kan definieras som att skapa (dvs beräkna) en sorterad permutation av ursprungliga listan:

permSort(X, Y) :-

permutation(X, Y), \\ generera permutation sorted(Y). \\ testa om sorterad

Programmet använder (inbyggda) predikatet

permutation(X, Y) för att generera en permutation av listan X, som sedan testas med predikatet sorted(Y) huruvida den är sorterad eller inte.

Listsortering: permSort(+X, ?Y)

(57)

Ska vara sant om Y är en permutation av X.

Strukturella induktionen är på första listan X.

Vi utgår från följande logiska karakterisering av permutation:

Y är en permutation av X om huvudet på X (E) finns i Y, och om E tagits bort från Y, den resulterade listan är en permutation av svansen på X.

permutation([], []).

permutation([E | X], Y) :- permutation(X, Y1),

append(Y2, Y3, Y1), % används för att dela upp Y1 append(Y2, [E | Y3], Y).

Del 1: permutation(+X, ?Y)

(58)

%Definieras här bara för listor av tal!

sorted([]).

sorted([X]).

sorted([X, Y | L]) :-

X =< Y,

sorted([Y | L]).

Del 2: sorted(X)

(59)

permutation(Xs, [Z|Zs]) :- select(Z, Xs, Ys), permutation(Ys, Zs).

permutation([], []).

select(X, [X|Xs], Xs).

select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).

Mer elegant permute

(60)

Induktiva datatyper (ej inbyggda)

DD1351 F3 18/9

(61)

Logikprogrammering 3 Thomas Sjöland, KTH

(från Dilian Gurov, KTH för DD1361, HT17)

DD1351

Logik för Dataloger HT18

(62)

Induktiva datatyper: Träd (inte inbyggt)

Binära träd utan data

Binära träd med data

Problemdomänbeskrivning

Läsmaterial

Prolog-l: tree.pl

Handouts: Föreläsningsanteckningar

Idag

(63)

Binära träd utan data utgör en oändlig mängd av Prolog-termer:

Ett binärt träd utan data är antingen ett löv, leaf, eller ett sammansatt träd, branch(t1, t2) , som består av ett vänster delträd t1 och ett höger delträd t2.

Induktiv definition (BNF)

<Tree> ::= leaf | branch(<Tree>, <Tree>) där leaf och branch kallas för konstruktorer.

Därmed matchar varje binärt träd utan data t antingen leaf eller branch(TL, TR).

Exempel på (stängda) träd-termer: leaf, branch(leaf, leaf), branch(leaf, branch(leaf, leaf)).

Träd-termer kan också innehålla variabler: branch(X, leaf).

Binära träd utan data

(64)

För att definiera ett predikat över binära träd utan data:

 för löven leaf, definiera predikatet utan rekursion;

 för sammansatta träden branch(TL, TR), definiera predikatet med användning av samma predikat över delträden TL och TR.

Då blir predikatet väldefinierat för alla binära träd utan data.

Strukturell induktion

(65)

Höjden på ett träd t är längden (antalet bågar) av längsta stigen från roten till något löv.

Definition med strukturell induktion?

 höjden på ett löv leaf är 0;

 höjden på ett sammansatt träd branch(TL, TR) är maximum av höjderna på delträden TL och TR plus 1.

Höjden på ett träd

(66)

max(X, Y, X) :- Y<X.

max(X, Y, Y) :- X=<Y.

height(leaf, 0).

height(branch(TL, TR), N) :- height(TL, NL),

height(TR, NR), max(NL, NR, M), N is M+1.

Höjden på ett träd: height(T, N)

(67)

Ett träd är komplett om det har alla sina löv på samma höjd.

Definition med strukturell induktion?

complete(leaf).

complete(branch(TL, TR)) :- complete(TL),

complete(TR), height(TL, N), height(TR, N).

Kompletta träd: complete(T)

(68)

Ett binärt träd med data är antingen ett löv leaf(d) med en data-term d, eller ett sammansatt träd branch(d, t1, t2) med en data-term d, ett vänster delträd t1, och ett höger delträd t2.

Induktiv definition (BNF)

<Tree> ::= leaf(<Data>) |

branch (<Data>, <Tree>, <Tree> )

Därmed matchar varje binärt träd med data t antingen leaf(D) eller branch(D, TL, TR).

Exempel:

branch(-3,branch(4,leaf(8),leaf(-2)),leaf(7))

Binära träd med data

(69)

Som member(X, L), fast för träd med data.

Definition med strukturell induktion?

lookup(D, leaf(D)).

lookup(D, branch(D, _, _)).

lookup(D, branch(_, TL, _)) :- lookup(D, TL).

lookup(D, branch(_, _, TR)) :- lookup(D, TR).

Medlemskap i ett träd: lookup(D, T)

(70)

Beräknar summan av alla tal i trädet (antar att allt data är tal).

Definition med strukturell induktion?

treesum(leaf(N), N).

treesum(branch(N, TL, TR), N1) :- treesum(TL, NL),

treesum(TR, NR), N1 is NL+NR+N.

Summering i ett träd: treesum(T, N)

(71)

Operationer

Att lägga till ett element.

Att ta bort ett element.

Problematiskt för binära träd!

Ofullständiga binära träd (utan data)

idé: tillåt också tomma träd

BNF-definition:

<Tree> ::= nil | leaf | branch(<Tree>, <Tree> )

exempel: branch(leaf, branch(nil, leaf))

Strukturella operationer på träd

(72)

Ett sorterat binärt träd

Att hitta och lägga till ett värde i ett ordnat binärt träd)

%lookup(+,?,?)

lookup(Key, tree(Key,Value, Left, Right), Value):- !.

lookup(Key, tree(Key1, Value1, Left, Right), Value) :- Key < Key1, lookup(Key, Left, Value).

lookup(Key, tree(Key1, Value1, Left, Right), Value) :-

Key > Key1, lookup(Key, Right, Value).

Exempel på användning:

?- lookup(1, D, fifi),lookup(2, D, mumu),lookup(1,D, X).

Svar:

D=tree(1, fifi, _C, tree(2, mumu, _B, _A)), X=fifi.

(73)

Datatypen hierarkiska mjukvarusystem kan definieras induktivt med två regler: ett mjukvarusystem är antingen en funktion (som i språket C), eller en modul bestående av mjukvarusystem.

1. Föreslå ett sätt att representera mjukvarusystem som Prolog- termer, där funktionerna representeras som atomer med samma namn som funktionen, t.ex. main, min, max.

2. Ge två exempel på termer som representerar mjukvarusystem med flera nästlade nivåer.

3. För din representation av datatypen mjukvarusystem, skriv ett predikat funcsMVS(S, FL) som är sant om och bara om FL är en lista som innehaller namnen pa alla funktioner i det hierarkiska mjukvarusystemet S (med möjlig upprepning).

Problemdomänbeskrivning:

Hierarkiska mjukvarusystem

(74)

1. Sammansättningar går enklast att representera som listor.

En möjlig BNF-grammatik vore:

<MVS> ::= func(<Name>) | mod(<MVSList>) <MVSList> ::= [] | [<MVS>|<MVSList>]

2. Exempel-termer:

 func(foo)

 mod([func(main),

mod([func(min), func(max), func(avg)])])

Hierarkiska mjukvarusystem: Prolog-termer

(75)

3. Om vi följer strukturella induktionsprincipen för

ömsesidigt rekursiva datatyper (se texten "The Principle of Structural Induction"), så får vi:

funcsMVS(func(N), [N]).

funcsMVS(mod(SL), FL) :-

funcsMVSList(SL, FL).

funcsMVSList([], []).

funcsMVSList([S|SL], FL) :- funcsMVS(S, FL1),

funcsMVSList(SL, FL2), append(FL1, FL2, FL).

Hierarkiska mjukvarusystem: funcsMVS(S, FL)

(76)

Cut, negation

Generera-testa i Prolog

DD1351 F4 24/9

(77)

Logikprogrammering 4 Thomas Sjöland, KTH

(från Dilian Gurov, KTH för DD1361, HT17)

DD1351

Logik för Dataloger HT18

(78)

Prolog-specika konstruktioner

Negation, snitt

Aritmetik, I/O

Kontrollpredikat, metapredikat

Generera och testa Läsmaterial

Boken: kap. 5, 9, 10

Prolog-l: misc.pl

Handouts: Föreläsningsanteckningar

Idag

(79)

Prolog utgår ifrån closed world assumption:

allt som Prolog inte lyckas bevisa betraktas som falskt!

Negation i Prolog betraktas som bevis-teoretisk negation, och inte som logisk negation.

snygg(kia).

ej_snygg(X) :- \+ snygg(X).

Vad blir svaren på dessa queries?

?- ej_snygg(nisse).

?- ej_snygg(kia).

?- ej_snygg(X).

Negation i Prolog

(80)

Vi implementerade medlemstestet för listor så här:

in(H, [H | _]).

in(X, [_ | T]) :- in(X, T).

Vad blir svaret till:

?- in(X, [1, 2]), \+ in(X, [1,3]).

?- in(X, [1, 2]), \+ in(X, Y).

Beskriv kontrollflödet (variant på uppgift från omtentan 2016-03-15).

disjoint(X, Y) :- \+ (in(Z, X), in(Z, Y)).

Negation i Prolog

(81)

Snitt skär bort backtrackingen för predikatet i vilkets kropp den förekommer. Kan användas för att förbättra prestandan genom att undvika onödig sökning..

Exempel:

in(H, [H | _]).

in(X, [_ | T]) :- in(X, T).

Hur många svar får vi på frågan:

?- in(2, [1, 2, 3, 1, 2, 3]).

För att eliminera svaren efter det första:

inCut(H, [H | _]) :- !.

inCut(X, [_ | T]) :- inCut(X, T).

Snitt (eng: cut)

(82)

i(1).

i(2).

j(1).

j(2).

j(3).

s(X, Y) :- q(X, Y).

s(0, 0).

q(X, Y) :- i(X), !, j(Y).

q(4, 4).

Vilka blir svaren pa frågan?

?- s(X, Y).

Exempel från Learn Prolog Now!

(83)

Betrakta programmet:

max(X, Y, Z) :- X>Y, Z=X.

max(X, Y, Z) :- Z=Y.

Vad blir svaret på:

?- max(4, 3, 3).

Rättad implementation:

maxCut(X, Y, Z) :- X>Y, !, Z=X.

maxCut(X, Y, Z) :- Z=Y.

När behövs snitt?

(84)

Betrakta programmet:

snygg(kia).

isnygg(X) :- snygg(X), !, fail.

isnygg(X).

Vad blir svaren på:

?- isnygg(nisse).

?- isnygg(kia).

Vad åstadkommer predikatet isnygg?

Mera snitt

(85)

Likhet = betyder syntaktisk likhet, inte "samma värde"!

Speciella predikatet is utvärderar andra termen och unifierar med första. Obs: andra termen måste vara tillräckligt instansierad!

Dubbelsidig utvärdering och jämförelse: =:=.

Aritmetiska operatorer: +, -, *, /, //, mod, etc.

Olikheter: <, >, =<, >=, etc.

Aritmetik i Prolog

(86)

Två nödvändiga predikat:

read(t): läs en term fram till nästa punkt och unifiera den med termen t;

write(t): skriv ut termen t till terminalen.

Vad händer vid frågan:

?- read(X+Y), write(Y-3).

I/O i Prolog

(87)

Vi betraktade redan fail, ett predikat som alltid misslyckas.

Predikatet call(X) betraktar termen som X är unierad med som ett predikat.

snygg(kia).

not(X) :- call(X), !, fail.

not(X).

Vad blir svaret på denna fråga?

?- not(snygg(nisse)).

Kontrollpredikat

(88)

Två predikat (båda finns i flera varianter).:

 assert(t): lägg klausulen t till programmet;

 retract(t): ta bort klausulen t från programmet.

Vad blir svaren på:

?- assert(cool(anna)).

?- assert(hip(X) :- cool(X)).

?- hip(anna).

?- retract(cool(anna)).

?- hip(anna).

Metapredikat

References

Related documents

Therefore, we have investigated whether lung T 1 can be used as a biomarker of COPD in man, if there is a direct effect of TS on lung T 1 in healthy current smokers, and

[r]

[r]

[r]

[r]

Chickerings resonemang om frihet och ordning för tankarna till kommunitarianernas betonande av sambandet mellan rättigheter och skyldigheter, även om han anser sig kunna integrera

[r]

– I vissa provinser får flickor inte ens gå i skolan eller till moskén för att be, och där skulle en flicka aldrig få träna boxning, säger Sharifi.. tre gånger i veckan