Algoritmusok helyességének bizonyítása A Floyd-módszer
Algoritmusok végrehajtása Egy A algoritmus esetében a változókat három változótípusról beszélhetünk, melyeket az X, Y és Z vektorokba csoportosítjuk a következőképpen: X = (X 1,X 2, X n ) bemeneti változók (ismerteknek tekinthetőek) Z = (Z 1,Z 2, Z o ) az algoritmus által kapott eredmények Y = (Y 1,Y 2, Y p ) a köztes eredmények eltárolására használt változók A V = (V 1,V 2, V k ) vektor ezek egyesítése, mely az algoritmus összes változóját tartalmazza A végrehajtás bármely pillanatában, minden változónak lehet egy adott értéke, vagy még nem inicializált. Az A algoritmus állapotának nevezzük azt az s = (a 1,a 2, a k ) vektort, amely az algoritmus k változójának aktuális értékeit tartalmazza Amennyiben egy V j változó még nem inicializált, az a j érték ismeretlen (jelölés:?) Az algoritmus által végrehajtott számítást az s 0,s 1,,s m állapotsor határozza meg (s 0 kezdeti állapot, s m futás utáni végállapot)
Algoritmusok végrehajtása Példa: osztók számának meghatározása Az algoritmus: BEGIN NoDivisors READ X; Y:=2; Z:=0; WHILE X>Y DO IF X mod Y = 0 THEN Z:=Z+1 ENDIF Y:=Y+1; ENDWHILE WRITE X, Z END NoDivisors Az algoritmus által végrehajtott számítás: s 0 =(?,?,?) P 1 (s 0 ) = s 1 = (6,?,?) P 2 (s 1 ) = s 2 = (6,2,?) P 3 (s 2 ) = s 3 = (6,2,0) P 4 (s 3 ) = s 4 = (6,2,1) P 5 (s 4 ) = s 5 = (6,3,1) P 6 (s 5 ) = s 6 = (6,3,2) P 7 (s 6 ) = s 7 = (6,4,2) P 8 (s 7 ) = s 8 = (6,4,2) P 9 (s 8 ) = s 9 = (6,5,2) P 10 (s 9 ) = s 10 = (6,5,2) P 11 (s 10 ) = s 11 = (6,6,2) P 12 (s 11 ) = s 12 = (6,6,2) Legyen D az X bemeneti vektor által felvehető értékek halmaza. Egy adott i D bemenetre az A algoritmus egy s végállapotban fejeződik be. A Z kimeneti vektorban kapott értékek az A algoritmus i bemeneten végrehajtott számításainak eredménye. Ha az R halmaz az összes lehetséges eredmények halmaza, az A algoritmus egy A:D R függvényként értelmezhető.
Algoritmusok helyessége Egy program helyes, ha megfelel a specifikációnak, azaz azon bemenetekre, amelyek megfelelnek a specifikációknak, a program futtatása helyes eredményekhez vezet. A helyesség ellenőrzésekor nem vesszük figyelembe más szempontokat (pl. komplexitás stb.) Egy probléma nem értelmezhető bármilyen bemenetre. A ϕ(x) bemeneti predikátum (prekondíció/előfeltétel) határozza meg azokat a bemeneteket, amelyekre a probléma értelmezhető. (a program futtatásának csak az előfeltételt teljesítő X bemenetekre van értelme) Az X bemeneti értékek és Z eredmények között kapcsolatok állnak fent, melyet a ψ(x,z) kimeneti predikátum (postkondíció/utófeltétel) ad meg. Ez az X és Y vektor azon a és b értékeire igaz, melyek esetében az a bemenetre kapott eredmény b. Ha a bemeneti adatokra futtatva a programot b eredményeket kapunk és ψ(a, b ) hamis, akkor a kapott eredmények nem helyesek. A program specifikációja megadható a fenti két predikátum által (az X és Z vektoroknak ismerteknek kell lenniük). Példa: az r négyzetgyök kiszámítása: ϕ(x): x>0 ; ψ(x,z)> r 2 =x Programozók számára is helyesen: ϕ(x): x>0 ε>0 ; ψ(x,z)> r 2 -x < ε
Algoritmusok helyessége Def. 1: A P program megáll ϕ-re nézve, ha minden olyan x inputra, amelyre ϕ(x) teljesül, P(x) definiált. Def. 2: A P program parciálisan helyes ϕ-re és ψ-re nézve, ha minden olyan x inputra, amelyre ϕ(x) teljesül és P(x) definiált, ψ(x,p(x)) teljesül. Def. 3: A P program totálisan helyes (teljesen helyes) ϕ-re és ψ-re nézve, ha minden olyan x inputra, amelyre ϕ(x) teljesül, P(x) definiált, és ψ(x,p(x)) teljesül. Másképpen: A P program totálisan helyes a probléma specifikációjára nézve, ha megáll és parciálisan helyes az illető specifikációra nézve Megjegyzések: a parciális helyesség ellenőrzése a fontosabb, ha a program nem áll le azt észrevesszük A továbbiakban helyességen a totális helyességet értjük
Algoritmusok helyessége Példák Két szám közül a nagyobbik meghatározása: FUNCTION MAX(x,y) IF x y THEN MAX:=y ELSE MAX:=x ENDIF END MAX Helyes: - nem tartalmaz ciklust, tehát biztosan véget ér - A ψ:=(max x) (MAX y) ((MAX=x) (MAX=y)) kimeneti feltétel igaz Két vektor elemeinek összehasonlítása: FUNCTION EQUAL(n,X,Y) i:=1 WHILE i n DO IF x i =y i THEN EQUAL:=TRUE ELSE EQUAL:=FALSE ENDIF ENDWHILE END EQUAL Nem helyes: - nem ér véget, mivel az i értéke nem módosul - ha kiegészítjük az i:=i+1 megfeleltetéssel: nem parciálisan helyes: pl. n=2, X=(5,55) és Y=(9,55) re TRUE
Floyd 1968: az induktív állítások módszere Vágási pontok elhelyezése a programban: egy vágási pont az elejére (a beolvasás után) egy-egy vágási pont minden ciklushoz egy vágási pont a végére Komplexebb esetben: egy-egy vágási pont minden minden alprogram -ba/-ból történő be/ki lépéshez Mindenik vágási ponthoz hozzárendelünk egy induktív állítást (predikátumot): a bemeneti vágási pontnál ez ϕ(x), a kimenetinél ψ(x,z) Egy (i,j) vágási pont pár esetében több út vezethet i-ből j-be. Az olyan α utakat vesszük figyelembe, amelyek nem tartalmaznak más vágási pontokat. R α (X,Y) al jelöljük azt a predikátumot, ami az út bejárásának feltételét adja r α (X,Y) al jelöljük a függvényt, mely az illető úton az Y közbeeső változókra alkalmazott transzformációkat adja.
Mindenik úthoz hozzárendelhető egy ellenőrzési feltétel: X Y (P i (X,Y) R α (X,Y) P j (X, r α (X,Y))) azaz: ha a i indulási pontban a P i igaz és az i, j pontok közötti α út bejárása megtörténik, a j érkezési pontnak megfelelő P j feltétel igaz. Tétel 1: Ha minden ellenőrzési feltétel igaz, akkor a P program parciálisan helyes a ϕ(x) és ψ(x,z) által megadott specifikációra (a bizonyítás a logikai implikáció tranzitivitásán alapszik, valamint azon, hogy a kezdeti pont ellenőrzési feltétele ϕ(x), a végponté ψ(x,z).
Példa: legnagyobb közös osztó PROCEDURE LNKO(n1,n2,d) d:=n1; i:=n2; WHILE (d i) and (i>0) DO IF d>i THEN d:=d-i; ELSE i:=i-d; ENDIF ENDWHILE END LNKO {A: P A : ϕ(x): n1 N n2 N} {B: P B : (d,i)=(n1,n2)} {C: P C : ψ(x,z): d=(n1,n2)} A használt változók: X=(n1,n2), Y=(d,i), Z=(d)
A megfelelő utak bejárásának feltételei: R α1 (X,Y) = (d i) (i>0) R α2 (X,Y) = (d i) (i>0) b R α3 (X,Y) = not ((d i) (i>0)) (d=i) (i=0) B logikai kifejezés, amely az IF két ágától függ Az α2 út tulajdonképpen két másik egyesítése (a d<i és d>i esetek) Az utaknak megfelelő transzformációk: r α1 (X,Y) = (n1,n2) r α2 (X,Y) = if d>i then (d-i, i) else (d,i-d) r α3 (X,Y) = r α2 (X,Y) Az utaknak megfelelő ellenőrzési feltételek: C α1 = (n1 n2) (0 n2) ((n1,n2)=(n1,n2)) C α2 = ((d,i)=(n1,n2)) (d i) (i 0) ((d>i) (d-i,i) =(n1,n2)) ((d<i) (d,i-d) = (n1,n2)) C α3 = ((d,i)=(n1,n2)) ((d=i) (i=0)) (d=(n1,n2))
Def. 4: Egy (W,<) parciálisan rendezett halmazt megalapozottnak nevezünk, ha nincs benne végtelen csökkenő sorozat. Megállás ellenőrzéséhez bevezetett feltételek: az egyik vágási pontból a másikba történő eljutás során egy választott megalapozott halmazon bizonyos függvények értéke csökken (következéséképpen nem járhatunk végig egy utat végtelenszer, tehát a program megáll) Minden i vágási ponthoz egy u i : D X D Y M függvényt rendelünk Az α útra a megállási feltétel a következő: X Y (P i (X,Y) R α (X,Y) u i (X,Y)>u j (X, r α (X,Y))) Tétel 2: Ha minden megállási feltétel igaz, akkor a P program megáll a ϕ(x) specifikációra. (raa módszerrel bizonyítható: ha feltételezzük, hogy a program nem áll le, akkor egy végtelen csökkenő sorozatot kapunk, ami ellentmond a megalapozott halmazzal)
Az LNKO példa vágási pontjaihoz kiválasztjuk a következő függvényeket: u 1 (X,Y) = 2*n1 + 2*n2 u 2 (X,Y) = d+i u 3 = 0; Az utaknak megfelelő megállási feltételek: T α1 = (n1 n2) (n2>0) (2*n1 + 2*n2) > n1 + n2 T α2 = (P B (d>i) (i>0) d+i>d) (P B (d<i) (i>0) d+i>i) T α3 = TRUE Ellenőrizhető, hogy mindhárom feltétel teljesül n1>0 ra, de T α2 hamis, ha n1=0, mivel d értéke 0 lesz és az i>i hamis. Ebben az esetben az α2 út végtelenszer lenne bejárva, mivel d és i értéke nem módosulna az út bejárása során. Ahhoz, hogy egy totálisan helyes algoritmust kapjunk, úgy kell módosítanunk az LNKO algoritmust, hogy ne lépjen be az α2 útra, ha d=0
Példa: legnagyobb közös osztó PROCEDURE LNKO(n1,n2,d) {A: P A : ϕ(x): n1 N n2 N} IF n1=0 THEN d:=n2; i=0; ELSE d:=n1; i:=n2; WHILE (d i) and (i>0) DO {B: P B : (d,i)=(n1,n2)} IF d>i THEN d:=d-i; ELSE i:=i-d; ENDIF ENDWHILE END LNKO {C: P C : ψ(x,z): d=(n1,n2)} A használt változók: X=(n1,n2), Y=(d,i), Z=(d)