FEN KbP/seminar1: ProgUdsagn1 Kontraktbaseret programmering Seminar 1 Programudsagn og programbeviser
FEN KbP/seminar1: ProgUdsagn2 Programudsagn Definition:"Et programudsagn er et prædikat, hvis frie variabler er algoritmens variabler.” {Q} S {R} Hvis Q er sand før S, så er R sand efter udførelse af S Ex.: {x=X y=Y}{x=X y=Y} x:= x + y ; y:= x y ; x:= x y {x=Y y=X}{x=Y y=X} {Q}S{R} kaldes et udsagn i programlogik. Udtryk af formen {Q}S{R} kaldes også Hoare Triples. Gammelt programmørtrick: sparer en variabel Sir Tony
FEN KbP/seminar1: ProgUdsagn3 Gyldighed og korrekthed Gyldighed: Et udsagn i en algoritme er gyldigt såfremt det er opfyldt hver gang det passeres. En algoritme er gyldig såfremt alle udsagn i algoritmen er gyldige. Korrekthed (total korrekthed): En algoritme er korrekt med hensyn til en specifikation såfremt enhver udførelse af algoritmen terminerer med slutbetingelsen opfyldt. Hvis vi havde sagt at slutbetingelsen R gælder hvis S terminerer, taler vi om partiel korrekthed som altså et svagere krav. Vi anvender notationen {Q} S {R} i betydningen total korrekthed.
FEN KbP/seminar1: ProgUdsagn4 Invarianter Ved en invariant forstås et udsagn, som er knyttet til en løkke. Invarianten skal være gyldig umiddelbart før og efter hvert gennemløb af løkken: do {P} B 1 -> S 1 B 2 -> S 2... B n -> S n od Invariant
FEN KbP/seminar1: ProgUdsagn5 Eksempel Summering: |[N: int ; b: array [0..N) of int ; s: int ; s : [N 0, s = ( i | 0 i < N : b[i])] ; |[n: int ; n, s:= 0, 0 ; do {s = ( i | 0 i < n : b[i]) 0 n N} n N s, n:= s + b[n], n + 1 od ]| InvariantOmgivelser Ramme
FEN KbP/seminar1: ProgUdsagn6 Gyldighed: For at bevise gyldighed af invarianten skal vi vise, at denne er opfyldt før den første iteration, og at enhver iteration bevarer invarianten. Initialt: {N 0} n, s:= 0, 0 {s = ( i | 0 i < n : b[i]) 0 n N} Bevarelse af invarianten: { s = ( i | 0 i < n : b[i]) 0 n N n N} s, n:= s + b[n], n + 1 {s = ( i | 0 i < n : b[i]) 0 n N} Svarer til et induktionsbevis
FEN KbP/seminar1: ProgUdsagn7 Korrekthed: For at vise korrekthed skal vi dels vise, at løkken terminerer og dels, at responskravet da er opfyldt. –Terminering: (N n) er antallet af resterende elementer, den aftager for hver iteration og nedadtil begrænset. (N-n) kaldes en begrænsningsfunktion. –Responsbetingelsen er opfyldt i sluttilstanden: s = ( i | 0 i < n : b[i]) n = N s = ( i | 0 i < N : b[i]) ≡ R Heraf konkluderes, at Sum er korrekt.
FEN KbP/seminar1: ProgUdsagn8 Programlogik Notation: P 1, P 2,..., P n K hvor P i, 1 i n, og K betegner udsagn i programlogikken. Betydningen er, at konklusionen K følger af præmisserne P 1, P 2,..., P n. Sagt på en anden måde: For at kunne slutte, at K gælder, skal man vise, at konjunktionen af P i 'erne gælder.
FEN KbP/seminar1: ProgUdsagn9 {P} skip {P} (forbløffende !!!:-)) {P(x e)} x:= e {P} hvis P(x e) (P med e indsat i stedet for x) gælder inden x:= e udføres, så gælder P bagefter. Sekvens (semikolon, ‘;’) {Q} S 1 {P}, {P} S 2 {R} {Q} S 1 ; S 2 {R}
FEN KbP/seminar1: ProgUdsagn10 Selektion {Q}{Q} if B 1 S 1 B2 S2 B2 S2... Bn Sn Bn Sn fi {R}{R} Q BB, ( i | 1 i n: {Q B i } S i {R} {Q} IF {R} hvor BB betegner B 1 B 2 ... B n = ( i | 1 i n : B i ), og IF den generelle if-sætning
FEN KbP/seminar1: ProgUdsagn11 Iteration Slutningsreglen for DO kan formuleres sådan ( i | 1 i n : {P B i } S i {P}), P BB t >0, ( i | 1 i n: {P B i t = T} S i {t < T}) {P} DO {P BB} Første linie af præmisserne udtrykker, at enhver iteration af løkken bevarer P. Anden linie af præmisserne udtrykker, at løkken terminerer. Dette er udtrykt i termer af en funktion, t, som er nedadtil begrænset af 0. Det, der står i præmisserne, er, at hvis P BB gælder, så er t positiv; til gengæld vil enhver iteration sikre, at t aftager. Men vi vil hellere bruge checklisten for løkker: do {P} B 1 -> S 1 B 2 -> S 2... B n -> S n od
FEN KbP/seminar1: ProgUdsagn12 Checkliste for løkker For at vise: {Q} S 0 ; do {P} B S od {R} Skal følgende fire skridt vises: 1. {Q} S 0 {P} (initiering) 2. {P B} S {P}(bevarelse af invariant) 3. Terminering af løkken 4. P B R(korrekthed)
FEN KbP/seminar1: ProgUdsagn13 Eksempel Fibonacci-talfølgen F(i), i 1, kan defineres rekursivt ved F(1) = 1, F(2) = 1 F(n) = F(n 2) + F(n 1), n > 2 Rekursiv implementering er lige ud ad landevejen. Her er en iterativ:
FEN KbP/seminar1: ProgUdsagn14 linearFib: |[n, r: int ; r : [n > 2, r = F(n)] ; |[a, b, i: int ; a, b, i:= 1, 1, 2 ; do {a = F(i 1) b = F(i) 2 i n} i n a, b, i:= b, a + b, i + 1 od ; r:= b ]| Invariant: skal være sand ved hver iteration Checklisten: 1. {Q} S 0 {P} 2. {P B} S {P} 3. Terminering 4. P B R
FEN KbP/seminar1: ProgUdsagn15 For at vise korrekthed skal vi vise de fire punkter fra checklisten. I det konkrete tilfælde skal vi vise: i){n 2} a, b, i:= 1, 1, 2 {a = F(i 1) b = F(i) 2 i n} ii){a = F(i 1) b = F(i) 2 i n i n} a, b, i:= b, a+b, i+1 {a = F(i 1) b = F(i) 2 i n} iii)Terminering: n-i aftager med én for hver iteration og er nedadtil begrænset af 0 iv){a = F(i 1) b = F(i) 2 i n i = n} r:= b {r = F(n)} Hvert af disse trin er relativt trivielle. Vagten B a, b, i:= 1, 1, 2 ; do {a = F(i 1) b = F(i) 2 i n} i n a, b, i:= b, a + b, i + 1 od ; r:= b
FEN KbP/seminar1: ProgUdsagn16 Udvikling af løkker For at vise: {Q} S 0 do {P} B S od {R} Checklisten: 1. {Q} S 0 {P} 2. {P B} S {P} 3. Terminering 4. P B R
FEN KbP/seminar1: ProgUdsagn17 Skal følgende vises: {Q} S 0 {P} -- etablering af invarianten {P B} S {P} -- bevarelse af invarianten Terminering af løkken (find en funktion, der er nedadtil begrænset af eksempelvis 0), og som aftager for hver iteration -- {P B t = T} S {t < T}) P B R -- korrekthed Vi står med Q og R, og skal skrive en løkke: Checklisten bruges konstruktivt: Vi skal udvikle: invarianten P, vagten B, “programmerne” S 0 og S. {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn18 1)”Vælg” (gæt eller opfind) en invariant P og en vagt B, der tilfredsstiller (P B) R Det P ”mangler” i forhold til R, sættes til B, hvorefter vi finder B ved at negere dette. 2)Lav et “program”, der under betingelse af at {Q} er sand, etablerer invarianten {P}. Dette program svarer til S 0. {Q} S 0 {P} 3)Det ”eneste” vi mangler nu er loop-kroppen S. Først skal vi sikre terminering. Vi skal finde sætninger, så t aftager (skridt mod terminering) og til sidst gør B falsk. (Ofte gøres det ved at flytte en iterator, eller tælle en tæller op eller ned). 4)Invarianten beskriver sammenhængen mellem algoritmens variabler. Så når vi tager skridt mod terminering, så ændrer vi en (nogle) af de frie variable. Herved brydes invarianten evt., og andre frie variable skal opdateres for at genetablere invarianten eller bevare invarianten: {P B} S {P}. {Q} S 0 do {P} B S od {R} Checklisten: 1. {Q} S 0 {P} 2. {P B} S {P} 3. Terminering 4. P B R ?
FEN KbP/seminar1: ProgUdsagn19 Udledning af invarianten fra postbetingelsen Invarianten P skal være sand ved hver iteration, dvs., invarianten er et udsagn, som skal være sandt både i programtilstande, som tilfredsstiller præbetingelsen Q og postbetingelsen R. Dette illustreres sommetider med ”ballon- metaforen”:
“The Balloon Theory” (Gries81) Programtilstande, som tilfredsstiller P svarer til den oppustede ballon. Termineringsudtrykket svarer til ventilen, hvor luften lukkes ud af ballonen. Når ballonen er flad igen, så er sluttilstanden nået Hver iteration lukker lidt luft ud af ballonen. FEN KbP/seminar1: ProgUdsagn20
FEN KbP/seminar1: ProgUdsagn21 Afsvækkelse af postbetingelsen P kan findes ved passende afsvækkelse af R: –Slet en konjunkt –Erstat en konstant med en variabel –(Udvid værdimængden for en variabel) –(Tilføje en disjunkt) Kun de tre første er praktisk interessante, og vi vil kun se på de to første.
FEN KbP/seminar1: ProgUdsagn22 Slet en konjunkt Eksempel: Lineær søgning. Omgivelse: [var N: int; b: array [0..N) of int; i, x: int;] Ramme: i:[N>0 x b[0..N), 0 i N ( j| 0 j < i: x b[j]) x=b[i] ]
FEN KbP/seminar1: ProgUdsagn23 Slet en konjunkt i R: 0 i N ( j| 0 j < i: x b[j]) x=b[i] Hvilken skal slettes? Slet den der er sværest at etablere initialt: x=b[i] Negation heraf anvendes som vagt: x b[i] Resten er invarianten. Etabler invarianten initialt: i:=0
FEN KbP/seminar1: ProgUdsagn24 Vi har nu: i:=0; do {0 i N ( j| 0 j < i: x b[j])} x b[i] S od Det ses, at N-i er en passende begrænsningsfunktion. Vi mangler at bestemme S: Invaríanten skal bevares, og der skal tages skridt mod terminering. Begge dele opnås ved S:i:= i+1 idet pre-betingelsen siger, at x findes i arrayet {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn25 Programmet bliver: {N>0 x b[0..N)} i:=0; do {0 i N ( j| 0 j < i: x b[j])} x b[i] i:= i+1 od {0 i N ( j| 0 j < i: x b[j]) x=b[i]} {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn26 Erstat en konstant med en variabel. Eksempel: Summering af elementerne i et array. Ramme:sum:[N>0, sum=( j| 0 j<N : b[j])] Vi kan afsvække postbetingelsen ved at erstatte konstanten N med variablen n og tilføje en begrænsning på n. Invarianten bliver: 0 n N sum = ( j | 0 j<n : b[j]) Vagten findes udfra kravet P ¬B R. Dvs. hvad mangler P i at medføre R? (n=N): B: n N Vi skal finde en initialisering af sum og n, som etablerer invarianten:sum, n := 0, 0 {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn27 Hermed har vi følgende skabelon for løkken: n, sum := 0, 0; do {0 n N sum = ( j | 0 j<n : b[j])} n N S(?) od Begrænsningsfunktionen må blive N-n. Skridt mod terminering sikres ved kommandoen n:= n+1: n, sum := 0, 0; do {0 n N sum = ( j | 0 j<n : b[j])} n N (?) n:= n+1 od {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn28 Invarianten skal bevares. Sum skal være summen af elementerne op til n. Når n tælles op, så må summen forøges med næste element. Det færdige loop: n, sum := 0, 0; do {0 n N sum = ( j | 0 j<n : b[j])} n N n, sum:= n+1, sum+b[n] od {Q} S 0 do {P} B S od {R}
FEN KbP/seminar1: ProgUdsagn29 Øvelser Udvikl programmet til summering af et array ved at erstatte konstanten 0 med en variabel i stedet for at erstatte konstanten N med en variabel. Udvikl en algoritme med følgende specifikation: OddCount:[N:int; b: array[0..N) of int; r: int; r: [N 0, r = (#i | 0 i<N : Odd(b[i]))] ] –Opgaven skal løses i to varianter: Udled invarianten ved at erstatte konstanten N med en variabel Udled invarianten ved at erstatte konstanten 0 med en variabel Udvikl en algoritme til bestemmelse af heltalsapproksimationen af kvadratroden af et heltal. Specifikation (fra OH): SquareRootAppr:|[ n, r: int; r : [n 0, 0 r 2 n < (r+1) 2 ] ]| Vink: Find en invariant ved at slette en konjunkt. {Q} S 0 do {P} B S od {R} Checklisten: 1. {Q} S 0 {P} 2. {P B} S {P} 3. Terminering 4. P B R