Axiomatische Semantik der Beispielsprache


... [ Seminar Programmierkonzepte und -sprachen ] ... [↑ Gliederung] ... [← Spezifikation des Sprachkonstrukts C und Schwächste Vorbedingung] ... [→ Partielle vs. totale Korrektheit] ...

Übersicht: Axiomatische Semantik der Beispielsprache


Axiomatische Semantik der Beispielsprache

P → L
L → L1 ';' L2 | S
S → I ':=' E
    | 'if' E 'then' L1 'else' L2 'fi'
    | 'while' E 'do' L 'od'

Legende:

Abkürzung

Bedeutung

P Programm
L Anweisungsliste / statement list
L1, L2 Anweisungsliste 1/2 / statement list 1/2
S einfache Anweisung / single statement
I Variable
E Ausdruck / Expression

Assignment Statements

Die Definition von assignment statements ist folgende:

wp(I := E, Q) = Q[E/I]

Die neue Notation Q[E/I] bedeutet, dass alle E alle freien Vorkommen von I ersetzt. Freie Vorkommen bedeutet, dass I nicht drch All- oder Existenzquantoren gebunden ist. (Ein Beispiel für freie und nicht-freie Vorkommen: Q = (for all i, a[i] > a[j]) j ist frei, i ist gebunden)
Wenn keine Quantoren vorhanden sind, dann bedeutet Q[E/I] einfach, dass alle I durch E ersetzt werden.


Assignment Statements Beispiele

Beispiel 1:

wp(a := b / 2 - 1, a < 10)
= Q[b / 2 - 1 / a]
  = (b / 2 - 1 < 10)
  = (b < 22)

 

Ergebnis:
{b < 22} a := b / 2 - 1 {a < 10}

Beispiel 2:

wp(x := x + y - 3, x > 10) = Q[x + y - 3 / x]
  = (x + y - 3 > 10)
  = (y > 13 - x)

Ergebnis:
{y > 13 - x} x := x + y - 3 {x > 10}


Statement-Listen

Für Statement-Listen gilt folgendes:

wp(L1; L2, Q) = wp(L1, wp(L2, Q))

Das bedeutet, dass die Vorbedingung von L2 die Nachbedingung von L1 ist. Also muss man wieder rückwärts gehen, nämlich die Vorbedingung von L2 ausrechnen, diese dann benutzen, um die Vorbedingung von L1 zu berechnen. Die Positionen von L1 und L2 werden nicht, wie das in der denotationellen Semantik passiert, getauscht.


Statement-Listen Beispiel

wp(y := 3 * x + 1; x := y + 3, x < 10) = wp(y := 3 * x + 1, wp(x := y + 3, x < 10))

Zwischenrechnung: wp(x := y + 3, x < 10)
= Q[y + 3 / x]
  = (y + 3 < 10)
  = (y < 7)

Ergebnis der Zwischenrechnung einsetzen und wp für L1 ausrechnen:
wp(y := 3 * x + 1, y < 7) = Q[3 * x + 1 / y]
  = (3 * x + 1 < 7)
  = (3 * x < 6)
  = (x < 2)


Ergebnis:
wp(y := 3 * x + 1; x := y + 3, x < 10) = (x < 2)


If-Anweisungen

Die Semantik der If-Anweisung in der Beispielsprache war:

if E then L1 else L2 fi

Dies bedeutet, dass wenn E > 0 ist, dann wird L1 ausgeführt, bei E <= 0 wird L2 ausgeführt. Also:

wp(if E then L1 else L2 fi, Q) = (E > 0 → wp(L1, Q)) and (E <= 0 → wp(L2, Q))


If-Anweisungen Beispiel

wp(if x then x := 1 else x := -1 fi, x = 1) = (x > 0 → wp (x := 1, x = 1)) and (x <= 0 → wp(x := -1, x = 1))

Als nächtes werden die schwächsten Vorbedingungen ausgerechnet:

wp(x := 1, x = 1) = Q[1 / x] = (1 = 1)
wp(x := -1, x = 1) = Q[-1 / x] = (-1 = 1)

Setzt man dies in die erste Gleichung ein, erhält man

wp(if x then x := 1 else x := -1 fi, x = 1) = (x > 0 → (1 = 1)) and (x <= 0 → (-1 = 1))
Grundlagen der Programmierung: P → Q äquivalent zu not(P) or Q
  = (not(x > 0) or (1 = 1)) and (not(x <= 0) or (-1 = 1))
  = true and (not(x <= 0))
  = not(x <= 0) = (x > 0)


Ergebnis:
wp(if x then x := 1 else x := -1 fi, x = 1) = (x > 0)


While-Schleifen

Die while Schleifen

while E do L od

wird ausgeführt, so lange E > 0 ist. While-Schleifen sind das schwierigste Konstrukt, da man für die Schleifendurchläufe eine induktive Definition auf Basis der Schleife geben muss.

Hi(while E do L od, Q)

sei der Ausdruck, dass die Schleife i mal ausgeführt wird und dann in einem Status, der Q befriedigt terminiert. Dann ist für null Schleifendurchläufe

H0(while E do L od, Q) = E <= 0 and Q

und für einen Schleifendurchlauf

H1(while E do L od, Q) = E > 0 and wp(L, Q and E <= 0)
  = E > 0 and wp(L, H0(while E do L od, Q))

Verallgemeinert man diesen Ansatz, kommt man zu

Hi+1(while E do L od, Q) = E > 0 and wp(L, Hi(while E do L od, Q))

Nun definiert man

wp(while E do L od, Q) = es gibt ein i, für das gilt Hi(while E do L od, Q)

Diese Definition benötigt allerdings terminierende while-Schleifen. Nichtterminierende while-Schleifen haben immer false als Vorbedingung, da die Nachbedingung nie wahr werden kann:

wp(while 1 do L od, Q) = false, für alle L und Q


While-Schleifen Beispiele

Für diese Beispiele geht man von Integer-Werten aus. Ferner werden Vergleiche (da in der Beispielsprache der Datentyp boolean fehlt) nach C-Syntax (true bedeutet >= 1, false bedeutet < 1) ausgewertet: wird ein Vergleich als true ausgewertet, dann kommt der Wert 1 heraus, bei false 0.

Beispiel 1:

Gegeben ist die folgende while-Schleife mit Nachbedingung

while y != x do y := y + 1 od {y = x}

Um eine Vorbedingung zu finden kann man eine Methode ähnlich der Ermittlung der induktiven Hypothese in der mathematischen Induktion benutzen: Es wird die Bedingung für ein paar Fälle berechnet, mit der Hoffnung, dass man ien Muster erkennt.

H0     = (y = x)
H1(y := y + 1, y = x) = Q[y + 1 / y] = (y + 1 = x) = (y = x - 1)
H2(y := y + 1, y = x - 1) = Q[y + 1 / y] = (y + 1 = x - 1) = (y = x - 2)
H3(y := y + 1, y = x - 2) = Q[y + 1 / y] = (y + 1 = x - 2) = (y = x - 3)

Daraus kann man erkennen, dass

Hi(while y != x do y := y + 1 od, x = y) = ((y < x) and (i >= 1))
und
H0 = (y = x)

Kombiniert man beides, so erhält man

Hi = ((y <= x) and (i >= 0))

Diese while-Schleife terminiert immer, da, egal wie viel kleiner y als x ist, irgendwann ist y = x erreicht.

Beispiel 2:

while s > 1 do s := s / 2 od{s = 1}

Durch den gleichen Ansatz rechnet man H0 bis H3 aus:

H0     = (s = 1)
H1(s := s / 2, s = 1) = Q[s / 2 / s] = (s / 2 = 1) = ((s = 2) or (s = 3))
H2(s := s / 2, s = 2 or s = 3) = Q[s / 2 / s] = ((s / 2 = 2) or (s / 2 = 3)) = ((s = 4) or (s = 5) or (s = 6) or (s = 7))
H3(s := s / 2, (s = 4) or (s = 5) or (s = 6) or (s = 7)) = Q[s / 2 / s] = (s / 2 = 4) = ((s = 8) or (s = 9) or ... or (s = 15))

Daraus kann gefolgert werden, dass

Hi = ((s >= 2i) and (s < 2i+1))

Im Vergleich zum ersten Schleifen-Beispiel hat man mit dieser Methode nicht die schwächste Vorbedingung gefunden. Die Vorbedingung (s > 1) ist z.B. wesentlich schwächer.


... [ Seminar Programmierkonzepte und -sprachen ] ... [↑ Gliederung] ... [← Spezifikation des Sprachkonstrukts C und Schwächste Vorbedingung] ... [→ Partielle vs. totale Korrektheit] ...