Denition der Hilfsprädikate fct sorted = (seq nat s) bool: if #s < 2 then true else rst(s) rst(rest(s)) sorted(rest(s)) a s = ( nat k: k#a = k#s) mit k# = 0 k# j s = if k == j then 1+ k#s else k#s 1
Annotierte Anweisungen Eine (zusammengesetzte) Anweisung heißt vollständig (durch Zuweisungen) annotiert, wenn vor und nach jeder Anweisung eine Zusicherung steht. Die Annotation, die zu Beginn steht, heißt Vorbedingung. Ein annotiertes Programm heißt korrekt (annotiert), wenn für jede Ausführung des Programms ausgehend von einem Zustand, in dem die Vorbedingung gilt, alle durchlaufenen Zusicherungen in den jeweils dann eingenommen Zuständen immer gelten. 2
Bubblesort auf Sequenzen - annotiert mit Zusicherungen var seq nat a, var seq nat z :=, s; {a = z = s} do z then {sorted(a) a z s z } if a == then {a = z s z } a, z := rst(z), rest(z) {sorted(a) a z s } [] a =/= last(a) rst(z) then {sorted(a) a z s last(a) rst(z)} a, z := a rst(z), rest(z) {sorted(a) a z s } [] a =/= last(a) > rst(z) then {sorted(a) a z s last(a) > rst(z)} a, z := lrest(a), rst(z) last(a) rest(z) {sorted(a) a z s } {sorted(a) a z s } od {sorted(a) a z s z = } {sorted(a) a s} 3
Sinn annotierter Programme Ein annotiertes Programm kann durch (manuelle) Inspektion der Zusicherungen auf Korrektheit überprüft werden. Dazu wird für jede Anweisung überprüft, dass für jede Ausführung des Programms ausgehend von einem Zustand, in dem die Vorbedingung der Anweisung gilt, nach Ausführung der Anweisung die Zusicherung nach der Anweisung gilt. Für jede Art von Anweisungen gibt es formale Regeln, die diesen Zusammenhang herstellen (Zusicherungskalkül, Hoare-Kalkül) 4
Die Regel für Zuweisungen Für Zuweisungen gilt folgende Regel ( Zuweisungsaxiom ): { Q[E/x] } x := E { Q } falls E nur einfache Namen für Variablen enthält (kein Aliasing, keine Referenzen auf Variable). Beispiel: { 0 < x+1 } x := x+1 { 0 < x } {sorted(a) a z s last(a) rst(z) } {sorted(a rst(z) ) a rst(z) rest(z) s } a, z := a rst(z), rest(z) {sorted(a) a z s } 5
Die Regel für bedingte Anweisungen Für bedingte Anweisungen gilt: { Q } if C then { C Q } S1 { R } [] C then { C Q } S2 { R } { R } falls { C Q } S1 { R } und { C Q } S2 { R } gilt 6
Beispiel: Die Regel für bedingte Anweisungen Für bedingte Anweisungen gilt: { x > 1 y > 1 } if x y then { x y x > 1 y > 1 } z := x { z = min(x, y) x > 1 y > 1 } [] x > y then { x > y x > 1 y > 1 } z := y { z = min(x, y) x > 1 y > 1 } { z = min(x, y) x > 1 y > 1 } falls { x y x > 1 y > 1 } z := x { z = min(x, y) x > 1 y > 1 } und { x > y x > 1 y > 1 } z := y { z = min(x, y) x > 1 y > 1 } gilt 7
Die Regel für aufeinander folgende Zusicherungen Sind in einem annotierten Programm zwei Zusicherungen nicht durch eine Anweisung getrennt sondern folgen sie unmittelbar aufeinander, so gilt die Annotation falls { Q } gilt und { Q } { R } Q R 8
Die Regel für die Wiederholungsanweisung: Invariante Gilt für eine Wiederholungsanweisung die Annotation do C then S od {C Q } S { Q } dann ist folgendes Programm korrekt annotiert { Q } do C then {C Q } S { Q } od { C Q } Die Zusicherung Q heißt dann Invariante. Durch Invariante lassen sich Wiederholungsanweisungen verizieren. Nebenbedingungen: C enthält keine Seiteneffekte 9
Invarianten - Bubblesort {a = z = s} {sorted(a) a z s} do z then {sorted(a) a z s z }... {sorted(a) a z s } od {sorted(a) a z s z = } Invariante: Q = sorted(a) a z s 10
Bubblesort auf Feldern - annotiert mit Zusicherungen [1:n] array var nat a, var nat i := s, 1; // sei 1 n {a = s i = 1} {sorted(a[1:i]) a s i n} do i < n then {sorted(a[1:i]) a s i < n } if i == 0 then {a s i < n } i := 1 {sorted(a[1:i]) a s i < n } [] i =/= 0 a[i] a[i+1] then {sorted(a[1:i]) a s a[i] a[i+1] i < n } i := i+1 {sorted(a[1:i]) a s i n} [] i =/= 0 a[i] > a[i+1] then {sorted(a[1:i]) a s a[i] > a[i+1] i < n } a[i], a[i+1], i := a[i+1], a[i], i-1 {sorted(a[1:i]) a s i n} {sorted(a[1:i]) a s i n} od {sorted(a[1:i]) a s i n i n } {sorted(a) a s} 11
Terminierung Ist E ein totaler Ausdruck der Sorte nat und ist t ein Identikator der Sorte nat, der in C und S nicht vorkommt und ist eine Wiederholungsanweisung wie folgt korrekt annotiert { Q } do C then {C Q E = t } S { Q E < t } od { C Q } dann gilt, dass die Wiederholungsanweisung do C then S od terminiert, wenn in einem Zustand ausgeführt wird, für den die Zusicherung Q gilt. Nebenbedingung: C enthält keine Seiteneffekte, S wirft keine exceptions, es treten keine Ausdrücke auf, die den Wert liefern. 12
Beispiel: Suchen in sortiertem Feld Gegeben a : [1:n] Array Data, d : Data : sorted(a) Variable i, j : Var Nat precondition {i = 1 j = n} postcondition {1 i = j n ( (d in a) a[i] d) (a[i] = d))} wobei d in a = ( nat k: 1 k n a[k] = d ) 13
Beispiel: Suchen in sortiertem Feld - Annotation Gegeben [1:n] array data a, data d mit sorted(a) und 1 n var nat i, j := 1, n; { (d in a d in a[i:j]) 1 i j n } do i < j then { (d in a d in a[i:j]) 1 i < j n } nat m := (i+j)/2; { (d in a d in a[i:j]) 1 i m j n } if a[m] == d then i := j := m [] a[m] =/= d a[m] < d then i := m+1 ] a[m] =/= d a[m] d then j := m { (d in a d in a[i:j]) 1 i j n } od { (d in a d in a[i:j]) 1 i j n i j } { (d in a d in a[i:j]) i = j } 14
Beispiel: Suchen in sortiertem Feld - Terminierung Terminierungsausdruck: abs(j-i) var nat i, j := 1, n; { (d in a d in a[i:j]) 1 i j n } while i < j do { (d in a d in a[i:j]) 1 i < j n abs(j-i) = t} nat m := (i+j)/2; { (d in a d in a[i:j]) 1 i m < j n abs(j-i) = t} if a[m] == d then i := j := m [] a[m] =/= d a[m] < d then i := m+1 [] a[m] =/= d a[m] d then j := m { (d in a d in a[i:j]) 1 i j n abs(j-i) < t} od 15
Bubblesort auf Feldern - Terminierung Terminierungsfunktion: mit 2*inversionszahl(a) + n-i inversionszahl(a) = {(j, k): 1 j < k n a[j] > a[k] } {sorted(a[1:i]) a s i n} do i < n then {sorted(a[1:i]) a s i < n 2*inversionszahl(a) + n-i = t } if i == 0 then {z s i < n } i := 1 {sorted(a[1:i]) a s i < n } [] i == 0 a[i] a[i+1] then {sorted(a[1:i]) a s a[i] a[i+1] i < n } i := i+1 {sorted(a[1:i]) a s i n} [] i == 0 a[i] > a[i+1] then {sorted(a[1:i]) a s a[i] > a[i+1] i < n } a[i], a[i+1], i := a[i+1], a[i], i-1 {sorted(a[1:i]) a s i n} {sorted(a[1:i]) a s i n 2*inversionszahl(a) + n-i < t } od 16
Beispiel: Quicksort fct quicksort = (s : Seq Nat) Seq Nat: { var stack seq nat k, var seq nat v := estack, ; push(s, k); while k estack do seq nat a = rst(k); pop(k); if #a < 2 then v := a v else push(partle(rst(a), rest(a)), k); push( rst(a), k); push(partg(rst(a), rest(a)), k); od; v } Terminierungsfunktion: h(k) = 0 falls k = estack und h(k) = (#rst(k)) 2 +h(rest(k)) sonst Invariante: sum(k)+#v = #s mit sum(k) = 0 falls k = estack und sum(k) = #rst(k)+sum(rest(k)) 17