3 Spezifikation und Verifikation
3.1
1
Spezifikation (specification) einer Prozedur/Methode/Routine/...
= Beschreibung ihres Kopfes („Syntax“)
und ihres von außen sichtbaren Verhaltens („Semantik“)
- unter vollständiger Abstraktion von ihrer Implementierung (Rumpf)
Verifikation (verification) einer Prozedur/Methode/Routine/...
= Nachweis, dass die Implementierung der Spezifikation genügt
und zwar nicht durch Testen - denn das ist zum Scheitern verurteilt.
( Dijkstra (1972): „Testing can be used to show the presence of bugs,
but never to show their absence!“)
3.1
2
3.1 Spezifikation
beschreibt für eine Prozedur/Methode/Operation/Routine/...
ihren Kopf (Signatur),
„Syntax“
ihre Voraussetzung (precondition)
betr. nichtlokale Variable und Parameter
ihren Effekt (postcondition)
„Semantik“
betr. nichtlokale Variable und Parameter
ihr Ergebnis (result) (falls nicht void)
beschreibt für Anweisungen lediglich und .
3.1
3
Warum spezifizieren ?
Dokumentation/„Gebrauchsanweisung“ für fremde Anwender
Vorgabe für die Implementierung
Wie spezifizieren ?
Umgangssprache und/oder
mathematische Formelsprache und/oder
formale Sprache
3.1
4
Beispiel für Spezifikation einer Funktionsprozedur:
double sqrt(double x)
Voraussetzung x ≥ 0
kein Effekt
Das Ergebnis w hat die Eigenschaften | w2 - x | < ε , w ≥ 0 .
Beachte: die Spezifikation ist unvollständig („lose“):
w wird nicht eindeutig festgelegt;
das Verhalten bei nicht erfüllter Voraussetzung
ist nicht festgelegt.
3.1
5
3.1.1 Formale Spezifikation von Anweisungen
mittels Aussagenlogik/Prädikatenlogik
Zur Erinnerung (1.3): eine Anweisung überführt
einen Anfangszustand z in einen Endzustand z‘.
Beispiel, zunächst umgangssprachliche Spezifikation:
„Die Anweisung S operiert auf dem Feld a = new int[n] ,
das mindestens eine positive Zahl b enthält.
Nach Ausführung von S sind alle Feldelemente gleich b.“
3.1
6
Formal:
Zustand:
final int[] a = new int[n];
Voraussetzung:
P(a) ≡ ∃i∈[0,n-1] a[i] > 0
Effekt:
Q(a, a‘) ≡ ∃i∈[0,n-1] ( a[i] > 0 ∧ ∀k∈[0,n-1] a‘[k] = a[i] )
( a‘ = „der neue Wert von a“)
oder
Q('a, a) ≡ ∃i∈[0,n-1] ('a[i] > 0 ∧ ∀k∈[0,n-1] a[k] = 'a[i] )
( 'a = „der alte Wert von a“)
oder
Q(A, a) ≡ ∃i∈[0,n-1] (A[i] > 0 ∧ ∀k∈[0,n-1] a[k] = A[i] )
( A = „der alte Wert von a“)
3.1
7
Formalsprachlich - z.B. mittels Haskell:
Zustand:
[Int]
Voraussetzung:
p = any(>0)
-- p a = ...
Effekt:
q a = any(\ai -> ai>0 &&
all(\ak -> ak==ai) a)
-- q a 'a = ... !
(Zur Erinnerung:
3.1
any, all :: (t->Bool) -> [t] -> Bool
any p = or . map p
all p = and. map p
)
8
? Alternative:
Neuer Zustand als Ergebnis einer Zustandsüberführungsfunktion ?
(Vgl. denotationelle Semantik, 1.3)
f a = [ rep(length a)x | x <- a, x>0 ]
bestimmt Lösungsmenge,
stellt ein Verfahren zur Gewinnung dieser Lösungen dar,
d.h. gibt die neuen Zustände explizit an statt sie implizit zu charakterisieren.
Vorteil: prototypische Problemlösung, „ausführbare Spezifikation“
Nachteile: meist aufwendiger und schwerer verständlich,
u.U. gar nicht praktikabel (z.B. y = sqrt(x); )
3.1
9
3.1.2 Eigenschaften von Spezifikationen
Notation:
terminierende Anweisung A
Zustandsmenge Z
Spezifikation (P,Q) (Voraussetzung und Effekt)
Sonderfälle:
3.1
(T,Q)
A bewirkt Q „ohne Voraussetzung“
(P,T)
A bewirkt „irgendetwas“ (egal ob P erfüllt ist)
(F,Q)
A bewirkt „irgendetwas“ (da F nicht erfüllbar)
(P,F)
fehlerhafte Spezifikation (da F nicht erfüllbar)
(P,P)
(P≠T,F) P ist Invariante unter A
10
Def. 1: (P,Q) heißt konsistent (consistent), wenn
∃z∈Z P(z) , d.h. P ist erfüllbar
∀z∈Z ( P(z) ⇒ ∃z‘∈Z Q(z,z‘) )
PQ(z)
schwächste Voraussetzung für Q
(weakest precondition)
d.h. wenn P erfüllt ist, ist Q erfüllbar
Def. 2: (P,Q) heißt vollständig (complete), wenn
∀z∈Z ( P(z) ⇒ | { z‘ | z‘∈Z , Q(z,z‘) } | = 1 )
d.h. der Folgezustand ist stets eindeutig festgelegt.
3.1
11
Beispiel:
Z = R , (P,Q) ≡ ( z > 0 , | z - z‘2 | < ε )
ist konsistent, weil
es existieren z∈R mit z>0.
für jedes z>0 erfüllt z‘ = √z sogar | z - z‘2 | = 0
Schwächste Voraussetzung ist
PQ(z) ≡ ∃z‘∈R | z - z‘2 | < ε
≡ z>-ε
d.h. z>0 ist unnötig stark, z.B. z≥0 genügt auch
ist nicht vollständig, weil
verschiedene Näherungswerte sind erlaubt,
mit jedem z‘ ist auch -z‘ erlaubt.
3.1
12
Def. 3:
(P1,Q1) heißt stärker als (P2,Q2)
- in Zeichen (P1,Q1) ⇒ (P2,Q2) wenn Q1 ⇒ Q2 ∧ P1 ⇐ P2 ;
d.h. wenn eine Anweisung der Spezifikation (P1,Q1)
genügt, dann genügt sie auch der Spezifikation (P2,Q2) :
{ P2 } { P1 } A { Q1 } { Q2 }
3.1
13
3.1.3 Spezifikation von Prozeduren
Zur Erinnerung: folgende Informationen sind anzugeben:
Kopf (Signatur),
„Syntax“
Voraussetzung (precondition)
betr. nichtlokale Variable und Parameter
Effekt (postcondition)
„Semantik“
betr. nichtlokale Variable und Parameter
Ergebnis (result) (falls nicht void)
... zwar umgangssprachlich und/oder formal und/oder
formalsprachlich - und eventuell mit Beispielen.
3.1
14
Dokumentation einer Prozedur besteht aus
Problembeschreibung
Spezifikation - abstrahiert von der Implementierung
Beschreibung des Lösungsverfahrens, z.B.
„Einschachtelungsverfahren“ für ein Suchproblem
Kommentare im Code
Häufig wird nicht nur , sondern auch im Code untergebracht.
Java:
Standardisierte Kommentare erlauben Erzeugung einer
separaten HTML-Dokumentation mit javadoc MyClass.java
http://java.sun.com/j2se/javadoc/
3.1
15
/**
* Documented class example
* <br>
* <br>Time of day
*/
public class Time { // non-public items will remain hidden
public int hrs, min;
/**
* Delivers time of day in readable format.
* <br>
* <br><b>pre: </b> -* <br>
* <br><b>post:</b> -* <br>
* @param ampm
asks for "hh.mm am/pm" or "hh:mm" format
* @return
the time in desired format,
*
e.g., "5.30am" or "12.15pm" or "1.0pm"(!) or "17:50"
* <pre>
* | ampm
= if hrs<12 then show hrs ++ "." ++ show min ++ "am"
*
else if hrs==12 then "12." ++ show min ++ "pm"
*
else show(hrs-12) ++ "." ++ show min ++ "pm"
* | otherwise = show hrs ++ ":" ++ show min
* </pre>
**/
public String time(boolean ampm) {.....}
.....
.....
/**
* Advances time of day by one minute.
* <br>
* <br><b>pre: </b> -* <br>
* <br><b>post:</b>
* <pre>
* | min == 59 = min' == 0 &&
*
if hrs == 23 then hrs' == 0 else hrs' == hrs+1
* | otherwise = hrs' == hrs && min' == min+1
* </pre>
**/
public void step() {..... }
.....
3.1
17
.....
/**
* Sets time of day.
* <br>
* <br><b>pre: </b>
* <pre>
* 0 <= h && h < 24 &&
-- else "hours?"
* 0 <= m && m < 60
-- else "minutes?"
* </pre>
* <b>post: </b>
* <pre>
* hrs' == h && min' == m
* </pre>
* @param h
hours
* @param m
minutes
* @throws Exception
**/
public void set(int h, int m) throws Exception { ..... }
}
3.1
18
Konvention:
In der Spezifikation nicht erwähnte
Variable werden nicht verändert !
Beispiel ohne Variable - Effekt nur über Parameter:
/** move element from one stack to another
* pre: a /= []
* post: a'==tail a && b'==head a : b
*/
void move(Stack a, Stack b) {..... }
Bemerkungen:
- Typ Stack („Stapel“) sei als Liste spezifiziert.
- Spezifikation benutzt dereferenzierte a und b.
3.1
19
Spezifikation von Funktionsprozeduren:
entweder: zusätzlich zur Effektbeschreibung wird
der Ergebniswert explizit beschrieben
oder:
zusätzlich zur Effektbeschreibung wird der
Ergebniswert implizit charakterisiert - z.B. durch
ein Prädikat über die Pseudovariable result
oder:
3.1
Q charakterisiert zusammenfassend Effekt und result
20
Verschiedene Parameter-Mechanismen bei
T p( M X x) :
M = IN - Wertparameter:
Die Effektbeschreibung sollte nicht x' enthalten
- da irrelevant nach Beendigung der Prozedur.
M = OUT - Ergebnisparameter:
Die Spezifikation sollte sich nicht auf x beziehen
- da irrelevant für die Ausführung der Prozedur.
M = IN OUT - Wert/Ergebnisparameter
M = VAR - Variablenparameter
Keine Einschränkung.
3.1
21