Hoare-Regel für die bedingte Anweisung Beispiel 1 zur Verifikation

Werbung
Hoare-Regel für die bedingte Anweisung
I1 :
I2 :
Beispiel 1 zur Verifikation eines bedingten
Anweisung
{B P } S1 {Q}
{ B P } → {Q}
{P } if (B) then S1 {Q}
{B P } S1 {Q}
{ B P } S2 {Q}
{P } if (B) then S1 else S2 {Q}
• In der Regel für bedingte Anweisungen wird die Bedingung der
Anweisung in weitere Bedingungen in den Zusicherungen
umgewandelt.
• Da die Handlungsstränge des Programmes wieder
zusammenlaufen, muss in beiden Alternativen die selbe
Nachbedingung erreicht werden.
• Eine gemeinsame Nachbedingung kann durch
Abschwächungsregeln erreicht werden:
{a ∈ Z}
if (a > 0) then
{a ∈ Z a > 0}
→ {a ∈ Z a > 0 a = a}
b := a;
{a ∈ Z a > 0 b = a}
→ {a ∈ Z b = |a|}
else
{a ∈ Z a > 0}
→ {a ∈ Z a ≤ 0 − a = −a}
b := −a;
{a ∈ Z a ≤ 0 b = −a}
→ {a ∈ Z b = |a|}
{a ∈ Z b = |a|}
Vorgehensweise bei bekannter Vorbedingung {P }
durch Abstraktion wie im Beispiel oder
durch disjunktive Verknüpfung der einzelnen
• Vorbedingung zu den Vorbedingungen {P B} im then-Teil
und {P B} im else-Teil ergänzen.
Nachbedingungen.
• then-Teil und else-Teil verifizieren mit Nachbedinugungen {Q1}
bzw. {Q2}.
• Nachbedinungen zu gemeinsamer Nachbedingung {Q}
abschwächen (z.B. Q ⇔ (Q1 Q2).
• Nachbedingung {Q} der bedingten Anweisung einfügen.
c LETTMANN 2003/04
Modellierung — Verifikation
V-31
c LETTMANN 2003/04
Modellierung — Verifikation
V-32
Beispiel 2 zur Verifikation eines bedingten
Anweisung
{a > 0 b > 0 a = b}
if (a > b) then
{
→{
a := a − b;
{
else
{
→{
b := b − a;
{
{
c LETTMANN 2003/04
Modellierung — Verifikation
Beispiel 2 zur Verifikation eines bedingten
Anweisung
{a > 0 b > 0 a = b}
if (a > b) then
{a > 0 b > 0 a = b a > b}
→ {a − b > 0 b > 0}
a := a − b;
{a > 0 b > 0}
else
{a > 0 b > 0 a = b a ≤ b}
→ {a > 0 b − a > 0}
b := b − a;
{a > 0 b > 0}
{a > 0 b > 0}
}
}
}
}
}
}
}
V-33
c LETTMANN 2003/04
Modellierung — Verifikation
V-34
Hoare-Regel für die Schleife
L:
Beispiel 1 zur Verifikation einer Schleife
{I B} S {I}
{I} while (B) do S {I B}
• Gilt die Zusicherung I vor Ausführung der Schleife und gilt
ferner, dass die Ausführung des Schleifenrumpfes S, falls sie
terminiert, einen Zustand erzeugt, in dem I gilt, vorausgesetzt
vor Ausführung der Schleife galt die Zusicherung (I B), so
gilt I nach jeder Ausführung des Schleifenrumpfes S.
• Da I nach jeder Ausführung des Schleifenrumpfes gilt, so gilt I
nach der Schleife, sofern diese terminiert. Zusätzlich gilt nach
der Schleife die Schleifenbedingung natürlich nicht und kann
daher negiert zur Nachbedingung ergänzt werden.
• Wenn die Schleifenbedingung von Anfang an nicht gilt, so wird
die Schleife nicht durchlaufen. Da I vor der Schleife gilt, so gilt
I daher auch nach der Schleife und damit auch (I B).
• Die Verifikation mit der Schleifenregel zeigt NICHT die
Terminierung der Schleife.
Das Finden der Invarianten stellt in der Programmverifikation
i.d.R. den schwierigsten Schritt dar.
{x + y = a x ≥ 0}
Invariante
while (x > 0) do
{x + y = a x ≥ 0 x > 0}
→ {x − 1 + y + 1 = a x − 1 ≥ 0}
x := x − 1;
{x + y + 1 = a x ≥ 0}
y := y + 1;
{x + y = a x ≥ 0}
{x + y = a x ≥ 0 x ≤ 0}
→ {x + y = a x = 0}
• Wie entdeckt man eine Invariante?
Bei der Programmerstellung eine Invariante zur Verifikation
vorgeben und als Kommentar in den Programmtext
einfügen.
Ansonsten ist die einzige Möglichkeit,
∗ die Implementation vollständig zu begreifen,
∗ aus Durchläufen durch den Schleifenrumpf mit
Beispielwerten ein Verständnis für die Veränderung der
Zustände zu entwickeln und
∗ dieses Verständnis in eine Invariante umzusetzen.
• Invarianten sind nicht eindeutig.
Die Verifikation einer Schleife entspricht einem induktiven Beweis.
Die Invariante entspricht der Induktionsbehauptung.
c LETTMANN 2003/04
Modellierung — Verifikation
V-35
c LETTMANN 2003/04
Modellierung — Verifikation
V-36
Beispiel zur Verifikation: Potenzieren (1)
Beispiel zur Verifikation: Potenzieren (2)
Spezifikation: Vorbedingung: {x ∈ R n ∈ N}
Nachbedingung: {b = xn }
Idee des Algorithmus:
{x ∈ R n ∈ N}
begin
{
→{
a := x;
{
→{
b := 1;
{
→{
i := n;
{
→{
while (i > 0) do begin
{
→{
→{
b := b ∗ a;
{
→{
i := i − 1;
{
end
{
→{
end
{b = xn}
Rückführung der Potenzierung auf die iterierte Multiplikation
Spezifikation: Vorbedingung: {x ∈ R n ∈ N}
Nachbedingung: {b = xn }
begin
a := x;
b := 1;
i := n;
while (i > 0) do begin
b := b ∗ a;
i := i − 1;
end
end
Variable x und n bleiben unverändert, damit Eingabewerte
zugreifbar bleiben.
Variable b speichert das Ergebnis.
c LETTMANN 2003/04
Modellierung — Verifikation
V-37
c LETTMANN 2003/04
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
Modellierung — Verifikation
V-38
Beispiel zur Verifikation: Potenzieren (3)
Beispiel zur Verifikation: Potenzieren(4)
Spezifikation: Vorbedingung: {x ∈ R n ∈ N}
Nachbedingung: {b = xn }
Suche nach einer Invarianten
• Tautologische Aussagen sind immer invariant, aber sie helfen
nicht.
• Betrachte Werteverlauf in der Schleife für beteiligte Variablen.
begin
a := x; b := 1; i := n;
while (i > 0) do begin
b := b ∗ a;
i := i − 1;
end
end
Variablenwerte bei Test der Bedingung in while
x
2
2
2
2
2
n
4
4
4
4
4
a
2
2
2
2
2
b
1
2
4
8
16
i
4
3
2
1
0
Invariante: {xn = b ∗ ai i ≥ 0}
c LETTMANN 2003/04
Modellierung — Verifikation
V-39
{x ∈ R n ∈ N}
begin
{x ∈ R n ∈ N}
→ {x ∈ R n ∈ N x = x}
a := x;
{x ∈ R n ∈ N a = x}
→ {x ∈ R n ∈ N a = x 1 = 1}
b := 1;
{x ∈ R n ∈ N a = x b = 1}
→ {x ∈ R n ∈ N a = x b = 1 n = n}
i := n;
{x ∈ R n ∈ N a = x b = 1 i = n}
Invariante
→ {xn = b ∗ ai i ≥ 0}
while (i > 0) do begin
{xn = b ∗ ai i ≥ 0 i > 0}
→ {xn = b ∗ ai i > 0}
→ {xn = b ∗ a ∗ ai−1 i > 0}
b := b ∗ a;
{xn = b ∗ ai−1 i > 0}
→ {xn = b ∗ ai−1 i − 1 ≥ 0}
i := i − 1;
{xn = b ∗ ai i ≥ 0}
end
{xn = b ∗ ai i ≥ 0 i ≤ 0}
→ {xn = b}
→ {xn = b ∗ ai i = 0}
end
{b = xn}
c LETTMANN 2003/04
Modellierung — Verifikation
V-40
Beispiel zur Verifikation: Effizientes Potenzieren (1)
Beispiel zur Verifikation: Effizientes Potenzieren (2)
Idee des Algorithmus:
Spezifikation: Vorbedingung: {x ∈ R n ∈ N}
Nachbedingung: {b = xn }
{x ∈ R n ∈ N}
begin
{x ∈ R n ∈ N}
a := x; b := 1; i := n;
{x ∈ R n ∈ N a = x b = 1 i = n}
Invariante
→ {xn = b ∗ ai i ≥ 0}
while (i > 0) do begin
{xn = b ∗ ai i ≥ 0 i > 0} → {xn = b ∗ ai i > 0}
if (i ) then
{xn = b ∗ ai i > 0 i }
→ {xn = b ∗ a ∗ (a2)[i/2] i > 0 i }
b := b ∗ a;
{xn = b ∗ (a2)[i/2] i > 0 i }
→ {xn = b ∗ (a2)[i/2] i > 0}
{xn = b ∗ ai i > 0 i }
→ {xn = b ∗ (a2)[i/2] i > 0 i }
→ {xn = b ∗ (a2)[i/2] i > 0}
{xn = b ∗ (a2)[i/2] i > 0}
a := a2;
{xn = b ∗ a[i/2] i > 0} → {xn = b ∗ a[i/2] [i/2] ≥ 0}
i := i/2;
{xn = b ∗ ai i ≥ 0}
end
{xn = b ∗ ai i ≥ 0 i ≤ 0}
→ {xn = b ∗ ai i = 0} → {xn = b}
end
{b = xn}
Quadrieren von Teilergebnissen spart die Hälfte der
Multiplikationen.
Sei nk nk−1 . . . n2n1n0 die Dualdarstellung von n, also n =
k
n i 2i .
i=0
Es gilt dann xn =
k
i
(x2 )ni , wobei in diesem Produkt nur die
i=0
Faktoren für ni = 1 eine Rolle spielen, und außerdem gilt
n/2i 1
ni =
0
Damit ergibt sich folgender Algorithmus zur Potenzierung:
Spezifikation: Vorbedingung: {x ∈ R n ∈ N}
Nachbedingung: {b = xn }
begin
a := x;
b := 1;
i := n;
while (i > 0) do begin
if (i ) then
b := b ∗ a;
a := a2;
i := i/2;
end
end
c LETTMANN 2003/04
Modellierung — Verifikation
V-41
c LETTMANN 2003/04
Modellierung — Verifikation
V-42
Invarianten
Terminierung
• Schleifeninvarianten sind Zusicherungen, d.h. sie beschreiben
Zusammenhänge von Programmgrößen.
Der Nachweis der totalen Korrekheit eines Programms erfordert
neben der bisher betrachteten partiellen Korrektheit den Nachweis
seiner Terminierung.
• Eine Invariante muss vor der Schleife gültig sein.
Wann ist Terminierung ein Problem?
• Eine Invariante muss nach Durchlauf durch den Schleifenrumpf
gültig sein, wenn sie vor dem Schleifenrumpf gültig war
(zusammen mit der Schleifenbedingung).
• Invarianten sind zum Zeitpunkt der Implementierung leichter zu
bestimmen.
• In Zuweisungen, falls der arithmetische Ausdruck nicht
berechenbar ist (z.B. Division durch 0, nicht initialisierte
Variable),
• in bedingten Anweisungen, falls die Bedingung nicht
entschieden werden kann oder falls die Anweisungen im
then-Teil oder im else-Teil nicht terminieren,
• in Anweisungsfolgen, falls eine Anweisung darin nicht
terminiert,
• aber vor allem in Schleifen.
Ausser in Schleifen kann die Terminierung garantiert werden,indem
man die Art der arithmetischen oder booleschen Ausdrücke auf
einfache Formen beschränkt (Komplexitätstheorie: Addition,
Subtraktion von 1, also x := x + 1; und Test auf 0, also if (x = 0) . . .).
Wir beschränken uns daher auf Terminierungsbeweise für
Schleifen.
c LETTMANN 2003/04
Modellierung — Verifikation
V-43
c LETTMANN 2003/04
Modellierung — Verifikation
V-44
Terminierung von Schleifen
Beispiel zum Terminierungsbeweis einer Schleife
Eine Schleife
while (B) do S
terminiert unter der Vorbedingung P genau dann, wenn jede
Ausführung von S terminiert und wenn ein ganzzahliger Ausdruck
T existiert, so dass folgende Aussagen gelten:
1. P ⇒ I
2. (T ≤ 0 I) ⇒ B
3. {T = i + 1 B I} S {T = i I}
T heißt auch Terminierungsfunktion oder Variante der Schleife.
Modellierung — Verifikation
Nachweis (T ≤ 0) I ⇒ B
x ≤ 0 (x + y = a x ≥ 0)
⇒ x=0
⇒ x≤0
Nachweis der Invarianz von I und der Dekrementierung von T
I bezeichnet dabei eine Invariante der Schleife und i ein
Bezeichner für eine ganzzahlige Variable ist, die weder in T noch
in der Schleife vorkommt, d.h. nicht in B und nicht in S.
c LETTMANN 2003/04
Ganzzahliger Ausdruck: T = x
Invariante: I = (x + y = a x ≥ 0)
Schleifenbedingung: B = (x > 0)
V-45
while (x > 0) do
{x = i + 1 x + y = a x ≥ 0 x > 0}
→ {x − 1 = i x − 1 + y + 1 = a x − 1 ≥ 0}
x := x − 1;
{x = i x + y + 1 = a x ≥ 0}
y := y + 1;
{x = i x + y = a x ≥ 0}
c LETTMANN 2003/04
Modellierung — Verifikation
V-46
Nachweis der Terminierung von Schleifen
Terminierung: Ein Problem?
• Insgesamt sind fünf Nachweise erforderlich:
• Manche Schleifen terminieren immer!
Terminierung des Schleifenrumpfes
Ganzzahligkeit von T
Folgerbarkeit der Nicht-Gültigkeit der Schleifenbedingung
aus T ≤ 0 und einer Invarianten I
Folgerbarkeit dieser Invarianten I aus der Vorbedingung der
Schleife
Nachweis der Invarianz von I und Nachweis der
{a > 0 b > 0}
while (a = b) do begin
while (a > b) do
a := a − b;
while (b > a) do
b := b − a;
end
• Manche Schleifen terminieren nicht immer!
Dekrementierung von T
{a > 0 b > 0}
while (a = b) do begin
while (a ≥ b) do
a := a − b;
while (b > a) do
b := b − a;
end
• Die Invariante I muss nicht mit der Invarianten für den
Nachweis der partiellen Korrektheit der Schleife
übereinstimmen.
Die Gestalt der Hoare-Regel für die Schleife erlaubt keinen
gleichzeitigen Nachweis von partieller Korrektheit und
Terminierung.
• Für manche Schleifen ist nicht bekannt, ob sie terminieren!
{n ∈ N n > 0}
while (n = 1) do
if (n ) then
n := n/2;
else
n := 3 ∗ n − 1;
Ulam’s Funktion
• Die Terminierung von Schleifen ist unentscheidbar.
c LETTMANN 2003/04
Modellierung — Verifikation
V-47
c LETTMANN 2003/04
Modellierung — Verifikation
V-48
Alternative Formulierung des
Terminierungsnachweises
Nicht-Terminierung von Schleifen
Eine Schleife
while (B) do S
• Zeige Terminierung des Schleifenrumpfes.
• Bestimme einen ganzzahligen Ausdruck T über den Variablen
des Programms.
terminiert nicht, wenn eine Zusicherung INT existiert, so dass
folgende Aussagen gelten:
• Zeige, dass T in jedem Durchlauf der Schleife verkleinert wird
(streng monoton fallend).
1. Es gibt Eingaben, so dass {B INT } vor der Schleife gültig
ist.
• Zeige, dass T nach unten beschränkt ist (T ≥ ist
invariant).
2. {B INT } ist Invariante der Schleife.
INT bezeichnet also eine Zusicherung, die nur in bestimmten
Eingabesituationen gültig ist.
Anstelle des streng monoton fallenden Ausdruckes T kann auch
ein streng monoton wachsender ganzzahliger Ausdruck gewählt
werden mit eine oberen Schranke.
Beim Nachweis der partiellen Korrektheit und der Terminierung
müssen die verwendeten Zusicherungen in allen denkbaren
Zuständen des Programmes an den entsprechenden Stellen
gelten.
Sind die beiden Formulierungen gleichwertig?
c LETTMANN 2003/04
Modellierung — Verifikation
V-49
c LETTMANN 2003/04
Modellierung — Verifikation
V-50
Anmerkungen zum Testen
Notwendigkeit von Verifikation
• Informationssicherheit (Security)
Tests können die Anwesenheit von Fehlern beweisen, aber nie
die Abwesenheit von Fehlern (bei unendlich vielen möglichen
Eingaben).
Vertraulichkeit
Integrität
Authentizität
Nicht-Rückweisbarkeit (Signaturgesetz)
Klassifikation von Testverfahren:
• Schnittstellentest (Blackbox-Test)
Zertifizierung von IT-Systemen durch das Bundesamt für
Sicherheit in der Informationstechnik. (Höhere Stufen der
Vertrauenswürdigkeit erfordern formale Spezifikation und
formale Verifikation.)
Die Ein- / Ausgaberelation wird auf Übereinstimmung mit der
Spezifikation geprüft.
• Programmabhängiger Test (Whitebox-Test)
Möglichst große Teile aller Pfade durch das Programm werden
getestet. Eine möglichst große Überdeckung (des
Programmcodes) ist erwünscht.
Beispiele
Home Banking
Geld- und Chipkarten
Systematische Auswahl von Testfällen:
• Schnittstellentest
• Systemsicherheit (Safety)
Software für sicherheitskritische Systeme ist formal zu
spezifizieren und zu verifizieren.
Beispiele:
Eingebettete Systeme (Embedded Systems) als
Regelungssysteme / reaktive Systeme unter Berücksichtigung
von Realzeitaspekten in
Autos,
Flugzeugen,
Raumfahrzeugen,
Anlagensteuerungen.
c LETTMANN 2003/04
Pro spezifizierter Bedingung mindestens einen Testfall prüfen,
Randbereiche (ggf. von beiden Seiten) prüfen, Maximal-,
Minmalwerte nicht vergessen, eine genügend große Anzahl
von Normalfällen prüfen.
• Überdeckungstest
Erwünscht, aber kaum machbar ist eine Wegüberdeckung d.h.
jeder Weg wird mindestens einmal durchlaufen. Auf jeden Fall
nötig ist eine Anweisungsüberdeckung, d.h. jede Anweisung
wird mindestens einmal durchlaufen.
Hauptproblem des Testens: Kombinatorische Explosion der
Testfälle
Modellierung — Verifikation
V-51
c LETTMANN 2003/04
Modellierung — Verifikation
V-52
Herunterladen