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