Formale Methoden im Software Engineering Eine praktische Einführung Gerhard Schellhorn,Gidon Ernst, Dominik Haneberg Bogdan Tofan, Jörg Pfähler 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 1 / 318 Organisatorisches Vorlesung: Dienstag: 14:00 Uhr - 15:30 Uhr (1057 N) Versuche: (Raum 3017 N) (Freitag: 08:15 - 09:45 Uhr) (Freitag: 10:00 - 11:30 Uhr) Freitag: 12:15 - 13:45 Uhr Freitag: 14:00 - 15:30 Uhr (Freitag: 15:45 - 17:15 Uhr) anderer Termin wählbar, wenn für alle ok 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 2 / 318 Leistungspunkte und Sprechstunden Leistungspunkte 2 V + 4 Ü = 8 Creditpoints. Alte PO: Für den Bereich ”Softwaretechnik” oder für den Bereich ”Theoretische Informatik” Neue PO: Nur für den Bereich ”Softwaretechnik” Sprechstunden Gerhard Schellhorn: Raum 3016 N, Tel. 2124 Bogdan Tofan: Raum 3043 N, Tel. 2181 Gidon Ernst: Raum 3014 N, Tel. 2183 Jörg Pfähler: Raum 3014 N, Tel. 2229 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 3 / 318 Anmeldung • In Zweiergruppen in die Liste eintragen: Ergibt Gruppennummer • Vorausgesetzt: Kenntnisse aus Logik-Vorlesung • Spätestens am Montag auf Webseite: Welche Gruppen an welchen Terminen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 4 / 318 Prüfung Anwesenheitspflicht in den Übungen! • Vorbereitung der Aufgaben anhand der Doku! • • Abgabe der gelösten Aufgaben im SVN. • 2 Mündliche Abnahmen im Semester in Zweiergruppen: • 1. Abnahme nach ca. 6 Wochen (zu: Prädikatenlogik und Algebraische Spezifikationen) • 2. Abnahme am Ende (Programmbeweisen und TL) • Mit: Testaufgaben (KIV) & Fragen zur Vorlesung 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 5 / 318 Formale Methoden: Ziel 1 Ziel 1: Grundlagen für das Verständnis von Software • Vermeidung von Mißverständnissen und Unklarheiten • Was bedeutet eine UML-Spezifikation? • Welche Compileroptimierungen sind möglich? • Ermöglichung von präzisen Vorhersagen und Tests • Verständnisverbesserung • Was sind gute“, gut strukturierte“, gut dokumentierte“ ” ” ” Programme? • Was sind saubere“ Schnittstellen? ” gute“ Spezifikationssprache? • Was ist eine ” A computer is a mathematical machine. A program is a mathematical expression. A programming language is a mathematical theory. Programming is a mathematical activity. — C. Anthony R. Hoare, 1989 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 6 / 318 Formale Methoden: Ziel 2 und Vorgehen Ziel 2: Beweisbar korrekte Software Vorgehen 1 Formale Spezifikation der Anforderungen 2 Validierung/Nachweis von Sicherheitseigenschaften 3 Programmierung 4 Beweis, dass Programm die Spezifikation erfüllt Notwendig für beide Ziele Definition formaler Modelle und Aussagen ⇒ Logik 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 7 / 318 Warum Beweise über Programme? Fehler in Software sind eine nicht enden wollende Geschichte: Oft nur ärgerlich, manchmal sehr teuer oder sogar lebensgefährlich! • Softwarefehler in deutschen EC-Karten Anfang 2010 • Verlust aller Kontaktdaten der Sidekick- Nutzer von T-Mobile USA (Okt. 2009) • Gepäckverteilung Flughafen Denver (1994) und Terminal 5 London Heathrow (2008) • Strahlentherapiesystem Therac-25 • Ariane 5 Explosion beim ersten Start • Flash-Filesystem des Mars Rover Spirit (und vor ein paar Wochen Opportunity) • ... 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 8 / 318 Warum formale Beweise mit KIV? These: Eine detaillierte Analyse des Programms von Hand genügt, um seine Korrektheit nachzuweisen! Problem 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 9 / 318 Warum formale Beweise mit KIV? These: Eine detaillierte Analyse des Programms von Hand genügt, um seine Korrektheit nachzuweisen! Problem Beweise über Software sind häufig sehr langwierig (viele Details) und daher noch fehleranfälliger als die Programme selbst. ⇒ Systemunterstützung mit KIV (andere Systeme: ACL2, Isabelle, PVS, . . . ) Durch die Systemunterstützung wird die Korrektheit der Beweise (durch korrekte Anwendung der Kalkülregeln) sichergestellt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 9 / 318 Lernziele • Erlernen des Umgangs mit KIV • Strukturierte Spezifikation mit KIV • Formales Beweisen mit KIV • Umsetzen von Beweisen in einem Kalkül • Automatisierung durch Simplifikation und Heuristiken • Beweise für Datenstrukturen und Programme • Verschiedene Verfeinerungskonzepte um von abstrakten Spezifikationen zu konkreten Programmen zu kommen • Verifikationstechnik für nebenläufige Systeme 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 10 / 318 Praktische Anwendung • Einsatz von KIV durch KIV-Experten in sicherheitskritischen Anwendungen • Einsatz von automatischen (spezialisierten) Tools: • • • • Model Checking (HW-Design, eingebettete Systeme) Bounded Model Checking, SAT checking (z. B. Security-Protokolle) Datenflussanalyse (z. B. MS Kernel Treiber im SLAM-Projekt) Predicative Abstraction und Typechecking (z. B. Nullpointer-Exceptions, SPEC#) • Entscheidungsprozeduren für Arithmetik (z .B. für Zeitconstraints bei Echtzeitsystemen) • ... • Systematisches Testen mit aus Spezifikationen generierten Testfällen • Konstruktion von endlichen Gegenbeispielen (z. B. Alloy, MACE) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 11 / 318 Überblick 1. 2. 3. 4. 5. 6. 7. Aussagen- und Prädikatenlogik Beweise über Datenstrukturen (Listen, Heaps) Algebraische Spezifikationen Programmbeweise (Hoare, while-Schleifen) Data Refinement Temporallogik & Parallele Programme Programmieren von KIV in Scala 8. Juli 2013 (2 Wochen) (2 Wochen) (1 Woche) (1.5 Wochen) (1.5 Wochen) (2 Wochen) (2 Wochen) G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 12 / 318 Prädikatenlogik mit Sorten und der Sequenzenkalkül 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 13 / 318 Prädikatenlogik mit Sorten • In Logik für Inf.: n-stellige Funktionssymbole f ∈ F n Semantik: n-stellige Funktion über Grundbereich D • Hier: Gegeben ist eine endliche Menge S von Sorten. Semantik: Jede Sorte bezeichnet einen Grundbereich • Funktionen jetzt: f ∈ Fs→s 0 oder einfacher: f : s → s 0 wobei s = s1 , . . . , sn mit n ≥ 0 (n = 0: Konstante c : s 0 ) • Vorteile: • Theorie: • Praxis: 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 14 / 318 Prädikatenlogik mit Sorten • In Logik für Inf.: n-stellige Funktionssymbole f ∈ F n Semantik: n-stellige Funktion über Grundbereich D • Hier: Gegeben ist eine endliche Menge S von Sorten. Semantik: Jede Sorte bezeichnet einen Grundbereich • Funktionen jetzt: f ∈ Fs→s 0 oder einfacher: f : s → s 0 wobei s = s1 , . . . , sn mit n ≥ 0 (n = 0: Konstante c : s 0 ) • Vorteile: • Pro Datentyp eine Sorte, damit Typcheck wie in Prog.-sprachen • Theorie: Sorten können in Prädikate codiert werden ⇒ redundant • Praxis: Ohne Sorten zusätzliche Axiome und Deduktion notwendig! (Z. B. nat(x) ∧ nat(y ) → nat(x + y )) ⇒ schlecht • Es gibt immer eine vordefinierte Sorte bool. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 14 / 318 Die Sorte bool: Formeln sind auch Terme! • Mit einer vordefinierten Sorte bool wird es möglich, Formeln mit den Terme der Sorte bool zu identifizieren • Logische Operatoren sind jetzt vordefinierte boolesche Funktionen: . ∧ ., . ∨ ., . → ., . ↔ . : bool × bool → bool ¬ . : bool → bool true, false : bool • Formeln ϕ, ψ und Terme t heissen jetzt Ausdrücke e • Prädikate sind einfach Funktionen mit Zielsorte bool • Funktionen und Prädikate heissen jetzt Operationen OP 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 15 / 318 Signaturen und Variablen Eine Signatur Σ = (S, OP) ist ein Paar mit: • Endlicher Menge S von Sorten, mit bool ∈ S • Endlicher Familie S OP = • • • • s∈S ∗ ,s 0 ∈S OP s→s 0 von Operationssymbolen mit Argumentsorten s und Ergebnissorte s 0 (leere Liste von Argumentsorten: Konstante c) OP enthält immer die üblichen booleschen Operationen Wie üblich: Konstanten sind null-stellige Operationen Boolesche Konstanten = atomare Aussagen Aussagenlogik = atomare Aussagen + boolesche Ops., keine Variablen/ Quantoren Eine Variablenmenge X besteht aus einer abzählbar unendlichen Menge von Variablen Xs für jede Sorte s ∈ S 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 16 / 318 Syntax von Ausdrücken Ausdrücke e ∈ EXPR s (Σ, X ) der Sorte s ∈ S über der Signatur Σ und über den Variablen X sind rekursiv definiert durch • x aus Xs ist ein Ausdruck der Sorte s • Sind e1 , . . . , en Ausdrücke der Sorten s1 , . . . , sn und op : s1 , . . . , sn → s 0 , dann ist op(e1 , . . . , en ) ein Ausdruck der Sorte s 0 • Bem.: Schreibe c statt c() für Konstanten (n = 0) • Sind e1 , e2 Ausdrücke der Sorte s, so ist e1 = e2 eine Formel (i. e. ein Ausdruck der Sorte bool) • Ist ϕ eine Formel und x eine Variable, so sind ∀ x.ϕ und ∃ x.ϕ Formeln EXPR(Σ, X ) := S s∈S EXPR s (Σ, X ), For (Σ, X ) := EXPR bool (Σ, X ) Terme t ∈ T (Σ, X ) sind Ausdrücke ohne Quantoren und Gleichheit. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 17 / 318 KIV-Syntax für Signaturen sorts nat; list; constants 0 : nat; ϕ: bool; (: 0-stelliges Prädikat als boolesche Konstante :) functions f : nat × nat → nat; g : nat, nat -> nat; (: es geht auch ASCII :) predicates isprime : nat; . < . : nat × nat; variables x,y : nat; u : list; • Sorten, Funktionen, Prädikate, Variablen immer in dieser Reihenfolge • Aufzählungen mit derselben Sorte nur bei Variablen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 18 / 318 KIV: verfügbare Symbole • Sonderzeichen eintippen mit Funktionstaste F12, dann: not ¬ and ∧ or ∨ implies → equiv ↔ all ∀ ex ∃ follows ` neq 6= times × • F12 TAB zeigt alle Möglichkeiten (z.B. auch oplus für ⊕) • Eindeutiges Präfix reicht, z.B. imp oder fol für →, `. • KIV gibt sehr viel Freiheit für die Characters in Bezeichnern: Z.B. ist ⊕∀ ∧ x → y − < (keine Spaces) ein legaler Bezeichner! • Deshalb müssen Bezeicher, insbes. auch logische Operatoren von Trennzeichen umgeben sein • Trennzeichen sind Space, Klammern, Komma oder Strichpunkt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 19 / 318 KIV: Infix-Schreibweise und Bindungsstärken • Signatur: . ⊕ . : s1 × s2 → s, s1 , s2 , s ∈ S • Term (t1 ⊕ t2 ) • Infix-Funktionssymbole in KIV können priorisiert werden (∗ bindet stärker als +, ∧ bindet stärker als ∨) • Es gibt auch Postfix (z.B. für Fakultät “. !”) und Präfix (z.B. “# .” für Anzahl der Elemente: # ∅ = 0) Bindungsstärken {postfix} > {präfix} > {infix} > {¬} > {∧} > {∨} > {→} > {↔} > {∀, ∃} Außenklammern werden weggelassen Beispiel: ϕ → ψ ↔ χ ≡ ((ϕ → ψ) ↔ χ) Quantoren binden größtmögliche Formel: ∀ x.ϕ ↔ ψ ≡ ∀ x.(ϕ ↔ ψ) Aufzählungen mit ∧, ∨ ungeklammert: ϕ ∧ ψ ∧ χ ≡ ϕ ∧ (ψ ∧ χ). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 20 / 318 Sequenzenkalkül • Erfunden von Gerhard Gentzen (1934) • Nur einer von vielen möglichen Kalkülen: Hilbertkalkül, natürliches Schliessen, Tableaukalkül, Modellelimination • Charakteristik: Versucht, Beweisziel auf Axiome zu reduzieren (schrittweise Vereinfachung des Problems); am menschlichen Beweisen orientiert ϕ1 , . . . , ϕn ` ψ1 , . . . , ψm ϕ1 , . . . , ϕn ψ1 , . . . , ψm Sequenz Antezedent (n ≥ 0) Sukzedent (m ≥ 0) Beachte: “`” ist Sequenzenpfeil, “`PL ” ist Ableitbarkeit 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 21 / 318 Beispiel Ein erster Beweis. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 22 / 318 Sequenzenkalkül Notation Γ, Γ1 , ∆, . . . Listen von Formeln, Γ = ϕ1 , . . . , ϕn , ∆ = ψ1 , . . . , ψm Γ ` ∆ := ϕ1 , . . . , ϕn ` ψ1 , . . . , ψm Γ, ϕ ` ψ := ϕ1 , . . . , ϕn , ϕ ` ψ Γ, ϕ ∧ ψ, ∆ ` ^ [ϕ1 , . . . , ϕn ] ^ [] _ [ψ1 , . . . , ψm ] _ [] := ϕ1 , . . . , ϕn , ϕ ∧ ψ, ψ1 , . . . , ψm ` := ϕ1 ∧ . . . ∧ ϕn := true := ψ1 ∨ . . . ∨ ψm := false Bedeutung einer Sequenz: Γ ` ∆ = 8. Juli 2013 V Γ→ W ∆ G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 23 / 318 Sequenzenkalkül: Inferenzregeln Regel: (n ≥ 0) Γ1 ` ∆1 Γ2 ` ∆2 Γ`∆ ... Γn ` ∆n • Regeln werden von unten nach oben gelesen: Um Γ ` ∆ (die Konklusion) zu beweisen, beweise stattdessen einfachere Prämissen Γ1 ` ∆1 , . . . , Γn ` ∆n • Bei n = 0 ist die Konklusion direkt bewiesen • n = 1: Vereinfachung • n = 2: Fallunterscheidung 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 24 / 318 Sequenzenkalkül: Ableitbarkeit Γ ` ∆ ist aus einer Menge von Formeln (Axiomen) Ax ableitbar (kurz: Ax `PL Γ ` ∆) :⇔ Es gibt eine Ableitung (Baum) mit • Wurzel: Γ ` ∆ (Konklusion) • Blätter: ` ϕ mit ϕ ∈ Ax (Prämissen) • Innere Knoten durch Regelanwendungen gebildet 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 25 / 318 Kalkül für Aussagenlogik (axiom) (false left) (true right) ϕ, Γ ` ϕ, ∆ false, Γ ` ∆ Γ ` true, ∆ Γ ` ϕ, ∆ ϕ, Γ ` ∆ Γ0 ` ∆0 (weakening, Γ0 ⊆ Γ, ∆0 ⊆ ∆) (cut formula) Γ`∆ Γ`∆ Γ ` ϕ, ∆ ψ, Γ ` ∆ (negation left) (negation right) ¬ ϕ, Γ ` ∆ Γ ` ¬ ψ, ∆ ϕ, ψ, Γ ` ∆ Γ ` ϕ, ∆ Γ ` ψ, ∆ (conjunction left/right) ϕ ∧ ψ, Γ ` ∆ Γ ` ϕ ∧ ψ, ∆ ϕ, Γ ` ∆ ψ, Γ ` ∆ Γ ` ϕ, ψ, ∆ (disjunction left/right) ϕ ∨ ψ, Γ ` ∆ Γ ` ϕ ∨ ψ, ∆ Γ ` ϕ, ∆ ψ, Γ ` ∆ ϕ, Γ ` ψ, ∆ (implication left/right) ϕ → ψ, Γ ` ∆ Γ ` ϕ → ψ, ∆ Γ ` ϕ, ψ, ∆ ϕ, ψ, Γ ` ∆ ϕ, Γ ` ψ, ∆ ψ, Γ ` ϕ, ∆ (equivalence left/right) ϕ ↔ ψ, Γ ` ∆ Γ ` ϕ ↔ ψ, ∆ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 26 / 318 Bis zum Freitag Vorbereiten der ersten Hälfte von Übung 1 anhand der Doku (bitte von der Webpage laden)! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 27 / 318 KIV: Anmeldung und Starten • Anmelden im Praktikumsraum unter Windows mit DCE-Account • Starten der VMWare für Linux und KIV • Anmelden als user • Starten von KIV durch Click auf’s Logo 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 28 / 318 KIV: Organisation in Projekte Grundlegende Organisation: • In KIV arbeitet man in (SW-Entwicklungs-) Projekten • Im Praktikum: Projekte Exercise1“ . . . Exercise6“ für die 6 Versuche ” ” • Jedes Projekt definiert Spezifikationen (Σ + Ax + Weiteres) • Spezifikationen können aufeinander aufbauen ⇒ Entwicklungsgraph • Über jeder Spezifikation kann man Theoreme formulieren und beweisen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 29 / 318 KIV: Projektauswahl- und Projektebene 4 Ebenen: 1 Projektauswahlebene • Projekte anlegen, löschen, auf einem Projekt arbeiten 2 Projektebene • Zeigt den Entwicklungsgraph der Spezifikationen • Spezifikationen anlegen, ändern, löschen • Auf einer Spezifikation arbeiten 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 30 / 318 KIV: Spezifikations- und Beweisebene 3 Spezifikationsebene • Theoreme anlegen, ändern, löschen • Ein Theorem zum Beweisen wählen 4 Beweisebene • Beweise führen durch interaktive Anwendung von Regeln • Zwei Regelsätze: Basisregeln zum Lernen + für echte Beweisen optimierte Regeln • Backtracking, Pruning • Simplifikation + Heuristiken zur automatischen Anwendung von Regeln 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 31 / 318 KIV: Verzeichnisstruktur Verzeichnisstruktur: • Im projects“-Verzeichnis von KIV ” pro Projekt ein Verzeichnis <projektname> • <projektname> enthält alle relevanten Daten zum Projekt • Darin: • Ein Unterverzeichnis specs • [Eine Datei devgraph für den Entwicklungsgraph] • In specs: ein Unterverzeichnis <specname> für jede Spezifikation • Darin: • Eine Datei specification für Signatur, Axiome etc. • Eine Datei sequents für Theoreme • [Ein Verzeichnis proofs das geladene Theoreme, geführte Beweise etc. speichert] 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 32 / 318 Variablen und freie Variablen eines Ausdrucks Die Variablen eines Ausdrucks (Var (e)) Var (x) Var (op(e1 , . . . , en )) Var (e = e 0 ) Var (Qx.ϕ) = = = = {x} Sn x ∈X Var (e ) i i=1 Var (e) ∪ Var (e 0 ) {x} ∪ Var (ϕ) Q ∈ {∀, ∃} Die freien Variablen einer Formel (free(ϕ)) sind genauso definiert ausser: free(Qx.ϕ) = free(ϕ) \ {x} Q ∈ {∀, ∃} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 33 / 318 Substitution Die Substitution einer Variablen x durch einen Ausdruck t in e (ext ) xxt = t yxt = y op(e1 , . . . , en )tx = op((e1 )tx , . . . , (en )tx ) (e1 = e2 )tx t t = ((e 1 )x = (e2 )x ) Qy .ϕ falls y = x ∨ x 6∈ free(ϕ) Qy .ϕt falls y 6= x, y 6∈ free(t), x ∈ free(ϕ) x = z t Qz.(ϕy )x falls y 6= x, y ∈ free(t), x ∈ free(ϕ) (z neu, d. h. z 6∈ Var (ϕ) ∪ Var (t)) (Qy .ϕ)tx falls x 6= y (Q ∈ {∀, ∃}) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 34 / 318 Regeln für Gleichungen Γ ` τ = τ, ∆ (reflexivity right) x = τ, Γτx ` ∆τx (insert equation) x = τ, Γ ` ∆ • Statt x = τ ist auch τ = x erlaubt (Symmetrie) • KIV erlaubt auch: • Einsetzen von Gleichungen τ = τ 0 (beides keine Variable). Ersetzt τ nur dort, wo alle Variablen frei sind. • Einsetzen der Gleichung nur an spezifischen Positionen in Γ ` ∆ (selten gebraucht) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 35 / 318 Beispiel Ein Beweis mit Quantoren. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 36 / 318 Regeln für Quantoren • ϕτx , ∀ x.ϕ, Γ ` ∆ (all left) ∀ x.ϕ, Γ ` ∆ • ϕyx , Γ ` ∆ (exists left) ∃ x.ϕ, Γ ` ∆ Γ ` ϕτx , ∃ x.ϕ, ∆ (exists right) Γ ` ∃ x.ϕ, ∆ Γ ` ϕyx , ∆ (all right) Γ ` ∀ x.ϕ, ∆ ϕτx die Substitution von x durch einen beliebigen Term τ in ϕ. y ist eine neue Variable, i. e. eine, die nicht frei in Q x.ϕ, Γ, ∆ (Q ∈ {∀, ∃}) vorkommt. Genauer: y 6∈ (free(ϕ)\{x}) ∪ free(Γ) ∪ free(∆) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 37 / 318 Intuition für Quantorenregeln (1) all left: • Allquantor im Antezedent: ∀ x.ϕ wird als wahr angenommen • Aus der Annahme folgt, dass auch die Annahme ϕtx für einen beliebigen Term t wahr ist • Jede Formel ϕtx darf hinzugenommen werden • Einziges Problem: Welches t ist nützlich (kreativ!)? all right: • Allquantor im Sukzedent: ∀ x.ϕ soll bewiesen werden • Dazu muss ϕ für jedes beliebige, feste“ Element bewiesen werden ” • Eine Variable y bezeichnet so ein beliebiges Element, aber nur, wenn sie neu ist • Wenn die Variable nicht neu wäre, wäre ihr Wert nicht beliebig, sondern durch die Formeln eingeschränkt. • Statt ∀ x.ϕ zeige man also ϕyx mit neuem y . • Keine Kreativität erforderlich 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 38 / 318 Intuition für Quantorenregeln (2) ex right: • ∃ x.ϕ im Sukzedent soll bewiesen werden • Wenn ϕtx für einen Term t bewiesen werden kann, so ist ∃ x.ϕ wahr für den Wert den t bezeichnet. • Also darf man sich ein t (hoffentlich das richtige“) aussuchen, um ” einen Beweis für ϕtx zu führen. ex left: • ∃ x.ϕ im Antezedent darf angenommen werden. • Es gibt also eine Belegung von x mit einem Element, für die ϕ wahr ist • Über das Element weiss man nur, dass ϕ wahr wird. • Eine neue Variable y können wir mit dem Element belegen, da die Gültigkeit der Sequenz von der Belegung bisher nicht abhängt. • Die neue Variable gibt einen Namen“ für das existierende Element. ” • Statt ∃ x.ϕ wird also ϕyx mit neuem y als Annahme verwendet. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 39 / 318 Zusätzliche Regel: Insert Axiom `ϕ all right ` Cl∀ (ϕ) weakening Γ, Cl∀ (ϕ) ` ∆ Γ ` Cl∀ (ϕ), ∆ cut Γ`∆ Cl∀ (ϕ) := ∀ x1 , . . . , xn .ϕ, wobei {x1 , . . . , xn } = free(ϕ) Neue Regel im Basiskalkül, um obige Schritte abzukürzen: ` Ax Cl∀ (Ax), Γ ` ∆ (insert axiom) Γ`∆ • KIV bietet die erste Prämisse nicht mehr an • Später: Der KIV-Kalkül hat noch komfortablere Regeln: insert lemma & insert rewrite-lemma 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 40 / 318 Vorgriff: Induktion für natürliche Zahlen • Theoretisches zu Induktion später • In KIV gibt es pro Datentyp meist eine strukturelle Induktionsregel • Nat. Zahlen: Wenn für eine Formel ϕ(n) • ϕ(0) gilt • Für jedes n: Aus Ind.hyp. ϕ(n) folgt: ϕ(n +1) dann gilt für ∀ n. ϕ(n) • Im Sequenzenkalkül: ϕ ist jetzt die Sequenz Γ ` ∆ (für Induktionsformel in Formel umwandeln!) ` ϕ(0) ϕ(n) ` ϕ(n +1) Γ`∆ V W ϕ = ∀ y. Γ → ∆, y = free(Γ → ∆) \ {n} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 41 / 318 Semantik von Formeln und Sequenzen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 42 / 318 Grundidee der Verwendung von Logik im Softwareentwurf Menge von Formeln = Axiome Ax Syntax: beschreiben Semantik: Software-Systeme: Menge von Algebren {A, B, . . .} `K ,,ist beweisbar” O Vollständigkeit Formel ϕ Korrektkeit beschreibt |= ,,ist gültig in” Eigenschaft ϕA Ziel: Nachweis, dass ein reales Softwaresystem eine Eigenschaft hat. Technik: Formaler Beweis ( Rechnen mit Formeln“) in KIV. ” Korrektheit + Vollständigkeit garantieren, dass man das richtige tut 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 43 / 318 Grundidee der Verwendung von Logik im Softwareentwurf (1) Semantik (i. e. der Inhalt, dessen was wir tun): • 1. Schritt: Wir wollen Softwaresysteme und funktionale Anforderungen an solche beschreiben • SW-Systeme sind Datenstrukturen, Programme etc. Bei eingebetteten Systemen evtl. inclusive Umgebung • 2. Schritt: Gegeben eine beliebige Implementierung, die die Anforderungen erfüllt, wollen wir Eigenschaften wie z. B. Korrektheit und Sicherheit nachweisen Mathematik: Das allgemeinste Modell für ein SW-System ist eine Algebra A. Wir wollen also Algebren beschreiben, und Eigenschaften von Algebren nachweisen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 44 / 318 Grundidee der Verwendung von Logik im Softwareentwurf (2) Mathematik: Sprachen zum Beschreiben von Algebren und ihren Eigenschaften heissen Logiken Bem.: Auch Prog.sprachen sind spezielle Beschreibungen von Algebren! Syntax • Algebren kann man durch Formelmengen Ax beschreiben • Eigenschaften werden durch Formeln ϕ beschreiben • Statt informell zu überlegen ob eine Eigenschaft gilt, verwenden wir einen Kalkül K , und zeigen formal: Ax `K ϕ Gewinn: Garantie, dass SW-System Eingenschaft hat Keine absolute Garantie: Nur so gut, wie die Genauigkeit der Beschreibung des SW-Systems (insbes. die Umgebung bei eingebetteten Systemen!) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 45 / 318 Semantik: Σ-Algebren Eine Σ-Algebra A = ((As )s∈S , (op A )op∈OP ) zu einer Signatur Σ = (S, OP) ist ein Paar mit: • Nichtleeren Mengen As für jede Sorte s ∈ S (Trägermengen) • Die Trägermenge Abool ist immer gleich {tt,ff} • Funktionen op A : As1 × . . . × Asn → As 0 für alle op : s1 , . . . , sn → s 0 • Die vordefinierten booleschen Symbole haben in jedem A die “normale” Bedeutung (Wahrheitstafeln): trueA = tt, ∧A (tt,ff) = ff, ∨A (tt,ff) = tt etc. Die Menge aller Σ-Algebren über Σ wird mit Alg(Σ) bezeichnet. Merke: Sorten bedeuten Datenmengen, Operationssymbole bezeichen Funktionen Algebra = Datenstruktur, Σ entspricht Interface Bsp: Datenmenge = Menge aller Listen, Operation: Aneinanderhängen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 46 / 318 Semantik: Belegungen von Variablen Eine Belegung (engl. v aluation; auch: ein Zustand) S v : s∈S vs : Xs → As ist eine Abbildung, die jedem Variablensymbol in Xs einen Wert in As zuordnet Die Abänderung vxa der Belegung v für x ∈ Xs und a ∈ As ist definiert durch: v (y ) falls x 6= y a vx (y ) := a falls x = y 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 47 / 318 Semantik von Ausdrücken Gegeben eine Algebra A und eine Belegung v . Dann ist die Semantik [[e]]A,v eines Ausdrucks e der Sorte s das folgende Element aus As : • [[x]]A,v := v (x) für x ∈ Xs • [[op(e1 , . . . , en )]]A,v := op A ([[e1 ]]A,v , . . . , [[en ]]A,v ) für op ∈ OP und ei ∈ EXPR(Σ, X ) • [[e1 = e2 ]]A,v := tt, falls [[e1 ]]A,v = [[e2 ]]A,v (sonst := ff) • [[∀ x.ϕ]]A,v := tt, falls für alle a ∈ As 0 gilt: [[ϕ]]A,v a = tt (sonst := ff) (x ∈ Xs 0 ) x • [[∃ x.ϕ]]A,v := tt, falls es ein a ∈ As 0 gibt mit [[ϕ]]A,v a = tt (sonst := x ff) (x ∈ Xs 0 ) Hinweis: Falls ϕ eine Formel ist, so ist [[ϕ]]A,v immer tt oder ff. (“Die Formel ist wahr oder falsch in A mit v ”) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 48 / 318 Gültigkeit Für ϕ ∈ For (Σ, X ) und Ax ⊆ For (Σ, X ) definiert man: • A, v |= ϕ :⇔ [[ϕ]]A,v = tt Gesprochen: ϕ gilt in A unter Belegung v“ ” • A |= ϕ :⇔ für jedes v gilt: A, v |= ϕ Gesprochen: ϕ gilt in A“, A Modell von ϕ “ ” ” • A |= Ax :⇔ A |= ϕ für alle ϕ ∈ Ax • Ax |= ϕ :⇔ für alle A ∈ Alg(Σ) gilt: A |= Ax ⇒ A |= ϕ Gesprochen: ϕ folgt aus Ax“ ” • ϕ Tautologie, |= ϕ :⇔ für alle A ∈ Alg(Σ) gilt A |= ϕ Beachte: A |= p(x) genau dann, wenn pA konstant für alle Elemente wahr ist, also auch genau dann, wenn A |= ∀ x.p(x) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 49 / 318 Erfüllbarkeit Für ϕ ∈ For (Σ, X ) und Ax ⊆ For (Σ, X ) definiert man: • ϕ erfüllbar in der Algebra A :⇔ es gibt Belegung v mit A, v |= ϕ • Ax erfüllbar in der Algebra A :⇔ es gibt Belegung v mit A, v |= ϕ für alle ϕ ∈ Ax • ϕ erfüllbar, falls ϕ erfüllbar in einer Algebra • Ax erfüllbar, falls Ax erfüllbar in einer Algebra Beachte: p(x) ist erfüllbar in A, wenn pA für ein Element wahr liefert, also auch genau dann, wenn A |= ∃ x.p(x) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 50 / 318 Eigenschaften der Prädikatenlogik (1) 1 A, v |= ϕ ⇔ Nicht A, v |= ¬ ϕ (kurz: A, v 6|= ¬ ϕ) 2 A, v |= ϕ oder A, v |= ¬ ϕ 3 v (x) = v 0 (x) für alle x ∈ free(ϕ) ⇒ (A, v |= ϕ ⇔ A, v 0 |= ϕ) 4 Nur, wenn free(ϕ) = ∅: A |= ϕ oder A |= ¬ ϕ 5 Nur, wenn free(ϕ) = ∅: A |= ϕ ⇔ A 6|= ¬ ϕ 6 A |= ϕ ⇔ A |= Cl ∀ (ϕ) 7 {Ax1 , . . . , Axn } |= ϕ ⇔ {Cl ∀ (Ax1 ), . . . , Cl ∀ (Axn )} |= ϕ Bedeutung: Cl ∀ (ϕ)-Allquantifizierung aller freien Variablen in ϕ Beachte Nummer 7: Axiome sind immer allquantifiziert (Unterschied zur Vorlesung Logik f. Informatiker!) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 51 / 318 Eigenschaften der Prädikatenlogik (2) Substitutionstheorem [[t ]] A, vx A,v |= ϕ ⇔ A, v |= ϕtx Korollar (Instanzierung und Umbenennung) Es gilt: |= (∀ x. ϕ) → ϕtx Wenn z 6∈ free(ϕ) \ {y }, so gilt außerdem: • A, v |= ∀ y . ϕ ⇔ A, v |= ∀ z. ϕzy • |= (∀ y . ϕ) ↔ (∀ z. ϕzy ) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 52 / 318 Semantik von Sequenzen Definition (Semantik von V Sequenzen) W A, v |= Γ ` ∆ ⇔ A, v |= Γ→ ∆ Folgerungen Für ϕ ∈ For (Σ, X ) und Ax ⊆ For (Σ, X ) gilt 8. Juli 2013 A |= ϕ ⇔ A |= ` ϕ A |= ¬ ϕ ⇔ A |= ϕ ` Ax |= ϕ ⇔ Ax |= ` ϕ Ax |= ¬ ϕ ⇔ Ax |= ϕ ` G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 53 / 318 Korrektheit der Basisregeln Satz (Regelkorrektheit der Basisregeln) Für alle Basisregeln gilt: A |= {Γ1 ` ∆1 , . . . , Γn ` ∆n } ⇒ A |= (Γ ` ∆) Alles andere wäre nicht sehr sinnvoll! Satz (Invertierbarkeit der Basisregeln) Für alle Basisregeln außer Abschwächung gilt: A |= (Γ ` ∆) ⇒ A |= {Γ1 ` ∆1 , . . . , Γn ` ∆n } Wichtige Konsequenz: Durch Regelanwendung wird aus einer beweisbaren Sequenz nie eine unbeweisbare! (Man kann nichts falsch machen, nur Unnötiges und Umständliches) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 54 / 318 Korrektheit und Vollständigkeit von PL Kann man mit den Basisregeln einen Beweisbaum mit Konklusion ` ϕ und Prämissen in Ax konstruieren, dann schreibt man Ax `PL ϕ. Satz (Korrektheit) Für jede Formel ϕ und jede Formelmenge Ax gilt Ax `PL ϕ ⇒ Ax |= ϕ Satz (Vollständigkeit) Für jede Formel ϕ und jede Formelmenge Ax gilt Ax |= ϕ 8. Juli 2013 ⇒ Ax `PL ϕ G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 55 / 318 Unentscheidbarkeit von PL Satz (Unentscheidbarkeit von PL) Es gibt kein Entscheidungsverfahren für die Allgemeingültigkeit von prädikatenlogischen Formeln. Zählt man alle Beweise des Sequenzenkalküls auf, so wird darin jede allgemeingültige Formel irgendwann vorkommen, aber das Verfahren kann nicht so verschärft werden, daß es auch für alle nicht allgemeingültigen Formeln immer abbricht. Beachte: Für reine Aussagenlogik ist der Sequenzenkalkül ein Entscheidungsverfahren: Man kann blind einfach Regeln anwenden, das terminiert immer. Genau wenn der Beweis geschlossen wird ist die Formel allgemeingültig! Das Problem bei PL liegt wo? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 56 / 318 Unentscheidbarkeit von PL Satz (Unentscheidbarkeit von PL) Es gibt kein Entscheidungsverfahren für die Allgemeingültigkeit von prädikatenlogischen Formeln. Zählt man alle Beweise des Sequenzenkalküls auf, so wird darin jede allgemeingültige Formel irgendwann vorkommen, aber das Verfahren kann nicht so verschärft werden, daß es auch für alle nicht allgemeingültigen Formeln immer abbricht. Beachte: Für reine Aussagenlogik ist der Sequenzenkalkül ein Entscheidungsverfahren: Man kann blind einfach Regeln anwenden, das terminiert immer. Genau wenn der Beweis geschlossen wird ist die Formel allgemeingültig! Das Problem bei PL liegt bei der Frage, welche Terme τ man bei den Regeln all left/exists right wählen soll. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 56 / 318 Beweise über Datenstrukturen mit dem KIV-Kalkül: Simplifier und Heuristiken 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 57 / 318 KIV-Kalkül: Überblick • Versuch 1: Basisregeln, ab Versuch 2: KIV-Kalkül • Wechseln durch Use Basic Rules“ unter Menü Control-Options ” • Sequenzenkalkül kennt keine Beweisstrukturierung: ⇒ Lemmas + Regeln zum Anwenden von Lemmas • Beobachtung: Sequenzenkalkül ist sehr elementar: ⇒ Viele Regeln automatisch anwendbar • Deshalb: Definition eines Simplifiers, der alle unkritischen Regeln immer automatisch anwendet. • Regeln mit 2 Prämissen (disjunction left, conjunction right etc.) sind der Idee nach alle Fallunterscheidungen ⇒ Zusammenfassen zu einer Regel case distinction • Automatisches Anwenden von Regeln durch Heuristiken, die man jederzeit dazu- oder wegschalten kann 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 58 / 318 Spezifikation von Listen (1) list-basic = enrich nat with sorts elem; list; constants [] : list; functions .+. : elem × list → list; .+. : list × list → list; . .first : list → elem; . .rest : list → list ; # : list → nat ; predicates . < . : elem × elem; . ∈ . : elem × list; variables c, b, a: elem; z2 , y2 , x2 , z1 , y1 , x1 , z0 , y0 , x0 , z, y, x: list; induction list generated by [], + :: (elem × list → list); 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 59 / 318 Spezifikation von Listen (2) axioms irreflexivity : transitivity : totality : constructors : first : rest : append-base : append-rec : size-base : size-rec : In : end enrich 8. Juli 2013 ` ¬ a < a; ` a < b ∧ b < c → a < c; ` a < b ∨ a = b ∨ b < a; `[] 6= a + x; ` (a + x).first = a; ` (a + x).rest = x; `[] + x = x; ` (a + x) + y = a + x + y ; ` #([]) = 0; ` #(a + x) = #(x) + 1; ` a ∈ x ↔ (∃ y , z. x = y + a + z); used for : s,ls; used for : f,lf; used used used used used used used G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering for for for for for for for : : : : : : : s,ls; s,ls; s,ls; s,ls; s,ls; s,ls; s,ls; 60 / 318 Weitere KIV-Regeln: Induktion • Theoretisches zu Induktion später • In KIV gibt es pro Datentyp meist eine strukturelle Induktionsregel • Nat. Zahlen: Wenn für eine Formel ϕ(n) • ϕ(0) gilt • für jedes n: aus Ind.hyp. ϕ(n) folgt: ϕ(n +1) dann gilt für ∀ n. ϕ(n) • Im Sequenzenkalkül: ϕ ist jetzt die Sequenz Γ ` ∆ für Induktionsformel in Formel umwandeln! ` ϕ(0) ϕ = ∀ y. 8. Juli 2013 ϕ(n) ` ϕ(n +1) Γ`∆ V Γ→ W ∆, y = free(Γ → ∆) \ {n} G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 61 / 318 Induktion für Listen • Jede Liste ist entweder die leere Liste ([]) oder durch Addition von a vorne an x (a + x) gebildet • Achtung: append von zwei Listen wird auch x + y geschrieben • Es gilt ebenfalls strukturelle Induktion: Wenn für eine Formel ϕ(x) • ϕ([]) gilt • Für jede Liste x: aus Ind.hyp. ϕ(x) folgt für jedes a: ϕ(a + x) dann gilt für ∀ x. ϕ(x) ` ϕ([]) ϕ(x) ` ϕ(a + x) Γ `∆ V W ϕ = ∀ y. Γ → ∆, y = free(Γ → ∆) \ {x} Hinweis: Ind.hyp. weglassen entspricht Fallunterscheidung, ob Liste = [] oder = a + x (≡ Regel constructor cut) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 62 / 318 Pragmatik zur Listeninduktion • Viele Definitionen sind rekursiv • • • • append: [] + y = y , (a + x) + y = a + (x + y ) size: #([]) = 0, #(a + x) = 1 + # x isprefix: isprefix([],y ), ¬ isprefix(a + x,[]), isprefix(a + x, b + y ) ↔ a = b ∧ isprefix(x, y ) sorted: sorted([]), sorted(a + []), sorted((a + (b + x)) ↔ a < b ∧ sorted(b + x) Induktion, wann immer möglich, über Variable am rekursiven Argument. Also: Erstes Argument bei append und isprefix Wenn dort keine Variable, oft Generalisierung des Arguments zu Variable notwendig Anschliessend rekursive Definition anwenden (oft mit Simplifier!), dann Induktionshypothese Bei sorted geht Rekursion über 2 Stufen: Induktion für FU! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 63 / 318 Beispiel (1) Zu zeigen: ` # (x + y ) = # x + # y Erstes Vorkommen von x: An rekursiver Position von + Erstes Vorkommen von y: Nicht an rekursiver Position von + Zweites Vorkommen von x: An rekursiver Position von # Zweites Vorkommen von y: An rekursiver Position von # Daraus folgt: Sinnvoll für Induktion ist nur die Variable x! Beweis durch strukturelle Induktion über x: Induktions Anfang x = [] # ( [] + y ) = # y = 0 + # y = # x + # y Induktionsschritt x ⇒ a + x # ( (a + x) + y ) = # (a + x + y ) = # (x + y ) + 1 = # x + # y + 1 = # x + 1 + # y = # (a + x)+ # y 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 64 / 318 KIV-Kalkül: Lemmaanwendung Beim Anwenden von Axiomen will man nicht umständlich cut, all left (und evtl. insert equation) machen Γ0 ` ∆0 V Γ ` Θ( Γ0 ), ∆ Γ`∆ Θ( W ∆0 ), Γ ` ∆ (insert lemma) • Γ0 ` ∆0 ist das Lemma (Axiom oder anderes Theorem) • Θ ist eine Substitution für die freien Variablen des Lemmas • Die Prämisse mit dem Lemma wird vom System als geschlossen betrachtet 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 65 / 318 KIV-Kalkül: Ersetzungslemmas Γ0 ` ϕ → σ = τ V Γ ` Θ( Γ0 ∧ ϕ), ∆ Γ`∆ Γ00 ` ∆00 (insert rewrite lemma) • Γ0 ` ϕ → σ = τ ist das Lemma (Γ und Vorbedingung ϕ dürfen fehlen) • Θ ist eine Substitution für die freien Variablen des Lemmas • Γ00 ` ∆00 entsteht aus Γ ` ∆ durch Ersetzen von Θ(σ) durch Θ(τ ) • Lemmas der Form Γ0 ` ϕ → (ψ ↔ χ) mit ψ Literal erlaubt: Dann wird Θ(ψ) durch Θ(χ) ersetzt • Wird kontextsensitiv unterstützt: Klicken auf das führende Funktionssymbol von σ in der Sequenz bietet passende Rewrite-Regeln an 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 66 / 318 KIV-Kalkül: Der Simplifier Beobachtung: Viele Vereinfachungen macht man beim mathematischen Beweisen ohne darüber nachzudenken. Alle unkritischen Regeln wendet der Simplifier in einem Schritt immer an. Es gibt 2 Arten von Vereinfachung: Logische Vereinfachung • Beipiel: Ersetzen von A ∧ A durch A (für jede Formel A) • Sind von Axiomen unabhängig, werden immer angewandt Simplifierregeln • Beispiel (nat. Zahlen): n + 0 = n zum Ersetzen von τ + 0 durch τ • Benötigen eine als Simplifierregel markiertes Axiom oder Lemma 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 67 / 318 Simplifier: Logische Vereinfachung • Aussagenlogische Regeln mit einer Prämisse (wie implication right, con. left, dis. right etc.) • All right, Exists left, axiom, reflexivity • Aussagenlogik mit true und false • ∃ x. x = τ ∧ A kann zu Aτx vereinfacht werden, falls x 6∈ Vars(τ ). • Vereinfachung mit Hilfe des Kontexts Beispiele: A, Γtrue ` ∆true A A A, Γ ` ∆ Γfalse ` A, ∆false A A Γ ` A, ∆ Afalse → B, Γ ` ∆ B A → B, Γ ` , ∆ A ∨ BAfalse , Γ ` ∆ A ∨ B, Γ ` ∆ A → BAtrue , Γ ` ∆ A → B, Γ ` , ∆ Γ ` A ∧ BAtrue , ∆ Γ ` A ∧ B, ∆ Bsp.: A ∧ A ⇒ A ∧ Atrue = A ∧ true ⇒ A A 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 68 / 318 Simplifier: Datenstrukturabhängige Regeln • Simplifierregeln sind Axiome oder Theoreme (Sequenzen), die einen entsprechenden Verwendungseintrag haben • Die syntaktische Form bestimmt den Effekt • Es gibt mehrere Klassen: • Simplifierregeln • Forward-Regeln • Alle Regeln können lokal oder global sein Zentral für das Verständnis von KIV: Welche Simplifierregel hat welchen Effekt? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 69 / 318 Simplifier: Lokale und globale Regeln 2 Klassen von Simplifierregeln • Lokale Simplifierregeln: Werden in Beweisen über der Spezifikation, in der sie definiert sind, benutzt. • Globale Simplifierregeln: Werden in Beweisen in Spezifikationen, die über der, in der sie definiert sind, benutzt. Pragmatik • Lokal werden Axiome als Simplifierregeln verwendet • Global werden Theoreme verwendet, die “gute” Simplifierregeln sind Analog für Forward-Regeln 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 70 / 318 Simplifier: Eingabe von Simplifierregeln Theoreme werden als Simplifierregeln eingetragen, wahlweise durch: • Am Ende der Sequenz in der specification/sequents-Datei: used for: s, ls; used for: f, lf; • Auf Spezifikationsebene im Menü: Add (Local) Simplifierrules Add (Local) Forwardrules • Auf Spezifikationsebene: Durch Rechtsklick auf das Theorem und Anklicken der Checkbox 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 71 / 318 Simplifier: Typen von Simplifierregeln Simplifierregeln (mit Eintrag s und/oder ls) gehören zu einer der Klassen • Termersetzungsregel = Rewriteregel: Generelle Form: Γ ` ϕ → (σ = τ ) Effekt: (Instanzen von) σ durch τ ersetzen • Formelersetzungsregel = Äquivalenzregel Generelle Form: Γ ` ϕ → (ψ ↔ χ) Effekt: (Instanzen von) ψ durch χ ersetzen • Assoziativität und Kommutativität: Generelle Form: (a + b) + c = a + (b + c) und a + b = b + a Effekt: Alle anderen Regeln modulo Ass. und Komm. anwenden 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 72 / 318 Simplifier: Pragmatik von Bedingungen Rewrite- und Äquivalenzregeln haben die generelle Form Γ ` ϕ → σ = τ und Γ ` ϕ → (ψ ↔ χ) • Vorbedingungen Γ und ϕ: Als Formel dieselbe Bedeutung, aber unterschiedlich behandelt. • ϕ = ϕ1 ∧ . . . ∧ ϕn muss Konjunktion von Literalen sein • Literal = evtl. negierte atomare Formel • Atomare Formel = Anwendung von Gleicheit oder nicht vordefiniertem Prädikat (ungleich ∧, ∨, . . . ) auf Terme • (Instanzen von) ϕ1 , . . . , ϕn werden in Sequenz gesucht: Nichtnegierte Formeln im Antezedent, negierte im Sukzedent • Γ wird versucht durch rekursiven Simplifieraufruf zu beweisen • Γ darf beliebige Formeln enthalten 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 73 / 318 Simplifier: Pragmatik von Bedingungen Wann sollte man Vorbedingungen in Γ stecken, wann in ϕ1 , . . . ,ϕn ? • Vorbedingungen vor dem Sequenzenhaken in Γ sollten nur dann definiert werden, wenn sie in sinnvollen Sequenzen immer erfüllt sind. • Typische sinnvolle Vorbedingungen sind Definiertheitsbedingungen: • • • • m −1 (Vorgänger von m) ist nur für m 6= 0 definiert m − n ist nur für n ≤ m definiert .rest und .last sind nur für nichtleere Listen definiert Arrays: i < #ar sollte für Zugriff a[i] immer wahr sein • Wenn man die Pragmatik nicht befolgt: Viele nutzlose Simplifieraufrufe (wird schnell sehr langsam) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 74 / 318 Simplifier: Beispiele zu Vorbedingungen • n 6= 0 ` (m < n −1 ↔ m +1 < n) Vorbedingung ok im Antezedent, da 0 −1 nicht sinnvoll ist • ` m < n → (n < m + 2 ↔ m + 1 = n) Nicht im Antezedent, sonst, sobald Instanzen von n < m + 2 vorkommen: Viele unnötige Beweisversuche für m < n • m ≤ n ` (n − m) + m = m Beweist z. B. die Sequenz f(x) > 5 ` (f(x) − 3) + 3 = f(x) (da der Simplifier f(x) > 5 ` 3 ≤ f(x) beweisen kann) ` m ≤ n → (n − m) + m = m beweist die Sequenz nicht, da 3 ≤ f(x) nicht in der Sequenz vorkommt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 75 / 318 Simplifier: Rewrite-Regeln Γ`ϕ→σ=τ ersetzt (Instanzen von) σ durch τ , wenn Vorbedingungen ok Einschränkungen: • free(ϕ) ∪ free(σ) muß alle freien Variablen abdecken • σ und τ müssen Terme sein, σ darf keine Variable sein Beispiele: • (m + n) − n = m • i > 0 → sqrt(i ˆ 2) = i (i integer; warum nicht im Antezedent?) • (s1 ∪ s2) \ s2 = s1 \ s2 (Mengen) • x 6= [] → (x + y ).first = x.first (Listen, + = append, warum nicht Ant.?) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 76 / 318 Simplifier: Äquivalenzregeln Γ ` ϕ → (ψ ↔ χ) ersetzt (Instanzen von) ψ durch χ, wenn Vorbedingungen ok Einschränkungen: • free(ϕ) ∪ free(ψ) muß alle freien Variablen abdecken • ψ muss Literal sein, χ ist beliebige Formel • Vereinfachung: Falls ψ keine Gleichung, statt (ψ ↔ true) nur ψ • Vereinfachung: Statt (ψ ↔ false) nur ¬ ψ Beispiele: • sorted(a + []), # x = 0 ↔ x = [] (Listen) • m + n < m + n0 ↔ n < n0 • n 6= 0 ` (m < n −1 ↔ m +1 < n) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 77 / 318 Simplifier: Kommutativität und Assoziativität • Kommutativität: m + n = n + m • Assoziativität: (m + n) + k = n + (m + k) • Kurz: C(+), A(+), AC(+) für komm., ass., komm. und ass. • Werden nicht direkt verwendet (Warum?) • Ob eine Simplifierregel passt, wird “modulo” dieser Regeln geprüft • ` a + b ∗ c = c ∗ b + a wird mit C(+,*) sofort (per Reflexivität) bewiesen • ` b ∗ c ≤ (c ∗ a) ∗ b wird für AC(∗) mit der Regel m ≤ m ∗ n bewiesen • Viele Operatoren sind AC: +, ∗, min, ggt, ∪ • Nur assoziativ ist z. B. append auf Listen, ∗ auf Matrizen • Nur kommutativ ist sehr selten 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 78 / 318 Simplifier: Forwardregeln • Manchmal will man neue Information zu einer Sequenz dazunehmen • Fast nur für Transitivität von Ordnungs- und Äquivalenzrelationen: • m < n ∧ n < n0 → m < n0 • isperm(x, y ) ∧ isperm(y , z) → isperm(x, z) • Dazu gibt es Forward-Regeln der Form: Γ ` ϕ1 ∧ . . . ∧ ϕn → ϕ • Vorbedingungen werden wie bei Simplifierregeln behandelt • ϕ wird genau einmal zur Sequenz addiert 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 79 / 318 Simplifier: Hinweise zu Forwardregeln • Transitivität ist unkritisch (sollte man machen) • Häufig etliche Varianten notwendig: • m < n ∧ n ≤ n0 → m < n0 • m < n ∧ ¬ n0 < n → m < n0 • m ≤ n + 1 ∧ n < n0 → m ≤ n0 • Ein Lemma sollte nie Forward- und Simplifierregel sein. Warum? • Forward-Regeln geben sehr leicht Endlosschleifen im Simplifier! ⇒ Sehr vorsichtig, nur mit gutem Grund verwenden • Einfaches Bsp. für Endlosschleife: ` m < n → m < n + 1 • Bsp.: 0 < n ` (∗ n) ≤ m → m 6= 0 • Warum nur (∗ n) und nicht einfach n? Warum 0 < n im Antezedent? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 80 / 318 KIV-Kalkül: Elimination für Selektoren • Listen haben (Postfix-)Selektoren • .first (erstes Element) • .rest (Rest der Liste) • Trick: Selektoren loswerden mit Hilfe von insert elim lemma • Benötigt wird Lemma ` x 6= [] → (a = x.first ∧ y = x.rest ↔ x = a + y ) • Eliminationsregel sucht einen Term t.first oder t.rest • Wenn t 6= [] gilt, wird t = a + y ersetzt (neue Variablen a, y ) • Damit wird aus t.first bzw. t.rest jetzt a bzw. y t = a + y , Γ(a, y , a + y ) ` ∆(a, y , a + y ) t 6= [], Γ(t.first, t.rest, t) ` ∆(t.first, t.rest, t) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 81 / 318 KIV-Kalkül: Elimination für andere Funktionen • Manchmal geht Elimination auch für andere “unbeliebte” Funktionen • Beliebte Beispiele: Minus und Division • Lemma für Minus: n ≤ m ` n0 = m − n ↔ m = n0 + n • Vorteil: Man kann auf Simplifierregeln für − verzichten! • Nachteil: Neue Variable n0 wird eingeführt (manchmal unintuitiv) Γ(n0 + n, n, n0) ` ∆(n0 + n, n, n0) n ≤ m, Γ(m, n, m − n) ` ∆(m, n, m − n) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 82 / 318 Automatisierung in KIV: Heuristiken • Flexible Automatisierung ist zentral, um bei grossen Fallstudien nicht immer wieder die gleichen Beweisschritte wiederholen zu müssen • Deshalb in KIV: Automatisierung durch zuschaltbare Heuristiken • Speziell: Der Simplifier ist eine Heuristik ⇒ Sollte man (fast) immer benutzen • Für jedes Beweisziel werden alle Heuristiken der Reihen nach ausprobiert • Gewählte Heuristiken jederzeit änderbar Sehr wichtig für das Verständnis von KIV: Welche Heuristik hat welchen Effekt? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 83 / 318 Wichtige Heuristiken für PL in KIV (1) • Simplifier • Wendet die Simplifier-Regel an • pl case distinction • Wendet Regel case distinction an • Für einfache bis mittelschwere Beweise • Gefahr, unnötige Fallunterscheidungen zu machen • if-then-else-split • if-then-else-Operator: (ϕ ⊃ σ; τ ) bezeichnet σ, falls ϕ wahr ist, sonst τ • Wendet cut Regel mit ϕ an • Häufig einsetzbar, um sinnvolle Fallunterscheidungen zu erzwingen • Beispiel: Fallunterscheidung nach Anwendung von Rewrite-Regel abs(i) = (i ≥ 0 ⊃ i; − i) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 84 / 318 Wichtige Heuristiken für PL in KIV (2) • Quantifier closing • Sucht Instanzen, mit denen eine Prämisse direkt geschlossen werden kann • Immer verwenden • Einziges Problem: Bei sehr vielen Quantoren braucht die Heuristik viel unnötige Zeit • Deshalb Spezifikationsmethodik: Prädikat (+ Simplifierregeln) definieren statt grosse Quantorenformeln zu verwenden • Quantifier: • Sucht sinnvolle“ Instanzen für Quantoren ” • Kann Endlosschleifen verursachen! • Nur bei einfachen Quantorenbeweisen einsetzbar 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 85 / 318 Wichtige Heuristiken für PL in KIV (3) • structural induction: • Macht strukturelle Induktion über “sinnvolle” Terme • Idee für “sinnvoll”: Variablen an rekursiven Positionen: n ist sinnvoll in m + n, da + rekursiv über das zweite Argument definiert: m + 0 = m, m + (n +1) = (m + n) +1 • Klappt meistens, aber nicht immer • Heuristik wendet ausserdem einmal die Induktionshypothese an • module specific: • Eigentlich eine Meta-Heuristik: Erlaubt heuristische Anwendung von Regeln durch Patterns • Pattern: Gibt Formeln (oder Schemas für Formeln) an, die in der Sequenz vorkommen müssen bzw. nicht vorkommen dürfen + Regel die angewandt werden soll • Alle Patterns stehen in der Datei module-specific 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 86 / 318 Wichtige Heuristiken für PL in KIV (4) elimination: • Heuristik gesteuert durch Eliminationsregeln (analog zu: Simplifier durch Simplifierregeln) • KIV-Eingabe analog: used for: e; etc. • Beispiel: n ≤ m ` n0 = m − n ↔ m = n0 + n • Vorbedingung im Antezedent: n ≤ m muss beweisbar sein (analog zu Simplifierregeln) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 87 / 318 KIV-Kalkül: Heuristiksätze • In KIV: 3 vordefinierte Heuristiksätze: • PL Heuristics: Minimale Menge sinnvoller Heuristiken • PL Heuristics + Case Splitting: Keine Induktion, FU automatisch • PL Heuristics + Struct. Ind.: Versucht, Ziel induktiv zu beweisen und Fallunterscheidungen (FU) automatisch zu machen • Für grössere Projekte definiert man häufig seinen eigenen Standardsatz ⇒ Datei default-heuristics • Weitere Heuristiken für Programme (DL). Dort noch wichtiger, da Programme mehr Struktur haben (später) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 88 / 318 Formale Spezifikation und Induktion 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 89 / 318 Was ist ein SW-System mathematisch? 1. Sicht: Operational Ein SW-System ist ein Automat • mit Zustand, • Zustandsübergängen und • mit Abläufen. 2. Sicht: Algebraisch Ein SW-System ist eine Algebra = Datenstruktur, d. h. ein System von Daten und Operationen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 90 / 318 Was ist spezieller? Einen Automaten kann man als spezielle Algebra auffassen: • Zustand = Element einer Datenstruktur ⇒ Algebra! • Sorten = State, Input, Output mit Operationen • Anfangszustände: isinitial: State → Bool • Zustandsübergangsfunktion (oder auch Relation): exec: Input × State → (State × Output → Bool) • Z. B. Zustand eines Programms: Programm + Programmzähler + Speicherbelegung • Theoretisch: Algebraische Sicht genügt • Praktisch: Automatensicht hat viele Spezialeigenschaften (u. a. ist eine Idee von Zeit“ damit verbunden). ” Deshalb Codierung oft nicht die beste Idee. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 91 / 318 SW-Beschreibungsformalismen SW-System ist Datentyp: • Modellorientierte Spezifikation (Z, VDM): Alle Datentypen sind mit Mengenlehre gebildet (Tupel und Mengen z. B. für UML-Klassendiagramme) • Algebraische Spezifikation SW-System ist Menge von Abläufen: • Algorithmische Spezifikation, z. B. Programmiersprachen • Programme über algebraischen/modellorientierten Datentypen • Automaten, Harel/UML Statecharts, Abstract State Machines (ASMs) Eignung hängt von den Zielen ab (Was will ich beschreiben? Was beweisen?) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 92 / 318 Spezifikation Ziel: Ein bestimmter Datentyp (Algebra) soll spezifiziert werden. Fragen: 1 Was für Operationen brauche ich? 2 Welche Axiome brauche ich? 3 Welche Datentypen kann ich überhaupt spezifizieren? 4 Kann ich alle wahren Aussagen über dem Datentyp auch beweisen? Zunächst: Fragen 3 + 4 speziell für die natürlichen Zahlen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 93 / 318 Natürliche Zahlen: Die Peano-Axiome • Es gibt eine ausgezeichnete Zahl 0 ∈ IN. • Jede Zahl n ∈ IN hat einen Nachfolger succ(n) ∈ IN. • Zu zwei Zahlen gibt es Summe m + n und Produkt m ∗ n • Axiom 1: 0 ist kein Nachfolger. • Axiom 2: Die Nachfolgerfunktion ist injektiv. • Axiom 3: m + 0 = m, m + succ(n) = succ(m + n) • Axiom 4: m ∗ 0 = 0, m ∗ succ(n) = m ∗ n + m • Axiom 5: IN ist die kleinste Menge M mit: 0 ∈ M und wenn n ∈ M, dann succ(n) ∈ M Aus dem letzten Axiom folgt das Induktionsprinzip: Wenn ϕ(0) gilt, und sich ϕ von n auf n +1 vererbt, dann ist ϕ für alle n wahr Begründung: M := {n : ϕ(n)} ist mindestens so groß wie IN. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 94 / 318 Natürliche Zahlen: Mit PL nicht spezifizierbar! Satz (Charakterisierung der natürlichen Zahlen) Die Peano-Axiome charakterisieren ein Modell (eben die natürlichen Zahlen) bis auf Isomorphie (= Umbenennung). Beachte dabei: Peano-Axiom 5 ist kein prädikatenlogisches Axiom! Aber: Satz von Skolem Es gibt keine Menge Ax-Nat von prädikatenlogischen Formeln, die als einziges Modell (modulo Umbenennung) nur die natürlichen Zahlen hat. Beweisbar mit Vollständigkeitssatz Intuition: Prädikatenlogische Axiome können nicht ausdrücken, dass es neben den echten“ natürlichen Zahlen keine weiteren Zahlen gibt. ” 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 95 / 318 Natürliche Zahlen: Ein schwächeres Ziel Wir wissen schon: Jede Axiomenmenge hat auch andere Modelle als IN mit zusätzlichen Elementen. Wir versuchen es schwächer: Suche Axiomenmenge, mit der alle über IN wahren Aussagen bewiesen werden können (dass sie auch über anderen Modellen gelten, könnte uns ja egal sein). Die Axiomenmenge sollte entscheidbar sein, d. h. es gibt Programm, das immer terminiert und sagt: “ja, ist Axiom” oder “nein, ist kein Axiom”. Sonst Triviallösung: Nehme als Axiome sämtliche wahren Aussagen. Zum Beispiel: Nehme Induktionsschema zu den Axiomen dazu: ϕ0n ∧ (∀ n. ϕ → ϕnn +1 ) → ∀ n. ϕ; (: für jedes ϕ ∈ For(Σ,X) :) Die Formel ϕ(n) mit freier Variable n beschreibt die Menge {n : IN |= ϕ(n)}. Das Induktionsschema für ϕ entspricht Peano-Axiom 5 für diese Menge 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 96 / 318 Natürliche Zahlen: Unvollständigkeit Problem: Alle Formeln (abzählbar viele) beschreiben nicht alle Mengen (überabzählbar viele)! Es gilt leider: Gödelscher Unvollständigkeitssatz Es gibt keine entscheidbare Menge von Formeln über (0, succ, +, ∗), die die ersten 4 Peano-Axiome und n 6= 0 → ∃ n. n = succ(m) enthält oder impliziert, mit der sich alle in IN wahren Aussagen ableiten lassen (insbesondere ist das Induktionsschema auch unvollständig). Der Trick zum Beweis ist das Lügnerparadoxon ( ich lüge jetzt“) ” in Form einer Formel, die sagt: Ich bin nicht beweisbar“. ” Indem man die Formeln durchnumeriert (z.B. ASCII-Codierung), wird das Ich“ durch Meine Nummer“ ausdrückbar. ” ” 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 97 / 318 Natürliche Zahlen: Unvollständigkeit Intuition: • Leider findet man auch keine gute“ Axiomenmenge, mit der die ” wahren Aussagen herleitbar sind • Alle wahren Aussagen könnte man als Axiome trivialerweise nehmen. • Die Menge der wahren Aussagen ist also nicht entscheidbar. • Wahre Aussagen für die natürlichen Zahlen zu beweisen, ist kreativ. • Verursachte ziemlich viel Wirbel in den 30er Jahren: Die Idee, Mathematik auf ganz einfachen Grundlagen aufzubauen (Hilbert’sches Programm), war gescheitert • Heute: Komplizierte Mengenlehre (Zermelo-Fränkel, Gödel-Bernays) als Grundlage für Mathematik. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 98 / 318 Problem: Prädikatenlogik reicht nicht Problem: Prädikatenlogik kann nicht ausdrücken, dass es ausser den Zahlen 0, 1, 2 (= die aus 0 und +1 gebildeten Terme 0, 0 +1, 0 +1 +1, . . .) keine weiteren Elemente gibt. Dasselbe Problem gibt es auch für andere Datentypen: • Alle ganzen Zahlen sind mit 0, +1, −1 gebildet • Alle Listen sind die aus [] und + gebildeten Terme: [], a + [], a + b + [], . . . • Bei Listen: Terme dürfen Elementvariablen enthalten • Alle (endlichen) Graphen bekommt man aus dem leeren ∅, durch Addieren von Knoten (addnode) und Kanten (addedge) • Alle Arrays bekommt man durch: • mkarray(n) (erzeugt Array der Grösse n) • put(a, i, d) (schreibt an Position i das Datum d) Gemeinsame Idee: Alle Datenelemente durch endlich-malige Anwendung von Konstruktoren bildbar 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 99 / 318 Generiertheitsklauseln: Syntax Deshalb Idee: Wir definieren ein “Spezialaxiom”, genannt Generiertheitsklausel, das aussagt: Die Daten eines Datentyps sind genau die mit bestimmten Konstruktoren gebildeten Terme. Syntax s generated by C ist Termerzeugtheitsklausel (∈ Gen(Σ)) ⇔ • s ∈ S, C = {f1 , . . . , fn } ⊆ OP, • die Konstruktoren fi haben die Ergebnissorte s (Konstanten sind als Konstruktoren erlaubt) • für wenigstens ein fi sind alle Argumentsorten ungleich s (sonst gibt es keine Konstruktorterme!) Ein Konstruktorterm t hat die Sorte s, ist mit Konstruktoren aus C gebildet und enthält nur Variablen anderer Sorten, ist also aus Ts ((S, C), X \ Xs ). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 100 / 318 Generiertheitsklauseln: Semantik Idee: Jedes Element der generierten Sorte ist der Wert eines Konstruktorterms, wenn man die (Parameter)-Variablen geeignet belegt. Semantik A |= s generated by C :⇔ für jedes a ∈ As gibt es ein v und t ∈ Ts ((S, C ), X \ Xs ) mit a = [[t]]A,v . Beispiel: Zur Liste [2,5] gibt es den Konstruktorterm a + b + []. Mit einer Belegung v der Variablen a, b als v (a) = 2 und v (b) = 5 gilt: [[a + b + []]]A,v = [2,5]. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 101 / 318 Basisspezifikation Basisspezifikation Eine Spezifikation SP = (Σ, Ax, Gen) ist ein Tripel mit: • Σ = (S, OP) • Ax ⊆ For(Σ, X ) endlich • Gen ⊆ Gen(Σ) endlich Modell A ist Modell von SP (A |= SP, A ∈ Mod(SP)) A |= SP :⇔ A ∈ Alg(Σ), A |= Gen und A |= Ax. Gültigkeit SP |= ϕ :⇔ für alle A in Mod(SP): A |= ϕ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 102 / 318 Konsistenz und Monomorphie Definition Eine Spezifikation ist konsistent :⇔ Axiome nicht widersprüchlich ⇔ Kein Beweis von false möglich ⇔ Es gibt ein Modell A der Spezifikation ⇒ Das muss sein! Definition Eine Spezifikation ist monomorph :⇔ Axiome legen Verhalten eindeutig fest ⇔ Je zwei Modelle sind bis auf Umbenennung (Isomorphie) gleich ⇒ Sollte für Datentypen wie natürliche Zahlen etc. so sein (die Axiome sollten ja nicht versehentlich auch reelle Zahlen erlauben). ⇒ Für Systembeschreibungen oft nicht erforderlich bzw. wünschenswert. Man will ja gerade Details offenlassen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 103 / 318 Minimale Spez. der natürlichen Zahlen in KIV specification sorts nat; constants 0 : nat; functions . +1 : nat → induction nat generated by 0, +1; variables m, n : nat; axioms 0 6= n +1; m 6= n → m +1 6= n +1; end specification nat; ist konsistent und mononorph 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 104 / 318 Spez. der natürlichen Zahlen mit Add. und Mult. specification sorts nat; constants 0 : nat; functions . +1 : nat → . + . : nat × nat → . ∗ . : nat × nat → induction nat generated by 0, +1; variables m, n : nat; axioms 0 6= n +1; m 6= n → m +1 6= n +1; m + 0 = m; m + n +1 = (m + n) +1; m ∗ 0 = 0; m ∗ (n +1) = m * n + m; end specification nat; nat; nat; ist konsistent und mononorph 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 105 / 318 Minimale Spez. der Listen in KIV specification sorts elem; list; constants [] : list; functions . + . : elem × list induction list generated by [], +; variables a, b : elem; x, y : list; axioms [] 6= a + x; a 6= b ∨ x 6= y → a + x 6= b + y; end specification → list; ist konsistent und mononorph, wenn die Trägermenge für die Elemente vorgegeben ist (“monomorph modulo Parameter”) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 106 / 318 Kalkül mit struktureller Induktion Strukturelle Induktion Sorte s erzeugt von Konstruktoren c, f ⇒ Jedes Element der Trägermenge ist darstellbar als Konstruktorterm f (f (. . . f (c))) Induktionsformeln: Induktionsregel: ϕ(c) ∧ (∀ x. ϕ(x) → ϕ(f (x))) → ∀ x. ϕ(x) ` ϕ(c) ϕ = ∀ y. V ϕ(x) ` ϕ(f (x)) Γ`∆ Γ→ W ∆, y = free(Γ → ∆) \ {x} Ableitung Wenn man aus der Spezifikation SP durch Anwendung von Sequenzenkalkül + Induktions-Regel die Formel ϕ ableiten kann, dann schreibt man SP `IND ϕ. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 107 / 318 Kalkül mit struktureller Induktion: Korrektheit und Unvollständigkeit Satz (Korrektheit) Es gilt SP `IND ϕ ⇒ SP |= ϕ Satz (Unvollständigkeit) Es gibt Spezifikationen und Theoreme mit SP |= ϕ, die aber mit Induktion nicht beweisbar sind (SP 6`IND ϕ). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 108 / 318 Wie schlimm ist Unvollständigkeit? • Der Kalkül mit der Induktions-Regel ist fast vollständig“: • • • • • ” Wenn SP |= ϕ, dann gibt es eine Erweiterung SP 0 von SP um neue rekursiv definierte Hilfsfunktionen, so dass SP 0 `IND ϕ gilt. Praktisch gesehen: Mit den zusätzlichen Symbolen in SP 0 wird eine passend (verallgemeinerte) Induktionshypothese für den Beweis von ϕ ausdrückbar. Beachte: Mit der Generiertheitsklausel ist die Induktionsregel auch auf Formeln mit den Hilfsfunktionen anwendbar (die Menge der möglichen Ind. hypothesen wächst!) SP 0 ist je nach ϕ verschieden (kein uniformes SP 0 ). In jedem SP 0 gibt es neue Formeln ψ, die wahr aber nicht ableitbar sind. Kreativitität also für Verallgemeinerung und passende Hilfsfunktionen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 109 / 318 Strukturierte Spezifikation: Freie Datentypen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 110 / 318 Wie spezifiziert man Datentypen? Vorgehen: • Schritt 1: Definiere benötigte Sorten • Schritt 2: Datentypen auf Rechnern sind generiert ⇒ Definiere Konstruktoren und Generiertheitsklauseln • Schritt 3(?): Definiere weitere Operationen und ihre Axiome Problem: Wie geeignete, ,,richtige“ Axiome finden? Formal ,,richtig“: Sie sollten für den gewünschten Datentyp stimmen (keine Inkonsistenz!), und sollten ihn möglichst eindeutig charakterisieren. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 111 / 318 Freie und nichtfreie Datentypen nat ???? nat ???? integer???? set ???? set ???? stack ???? bintree???? graph ???? list by by by by by by by by ???? by 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 112 / 318 Freie und nichtfreie Datentypen Beobachtung: Manche Datentypen sind frei (erzeugt): Zwei verschiedene Konstruktorterme repräsentieren auch immer zwei verschiedene Elemente. nat nat integer set set stack bintree graph 0, +1 0, 1, + 0, +1, −1 ∅, ins ∅, {.}, ∪ empty, push mkleaf, mkbranch ∅, +node, +edge list [], + 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 112 / 318 Freie und nichtfreie Datentypen Beobachtung: Manche Datentypen sind frei (erzeugt): Zwei verschiedene Konstruktorterme repräsentieren auch immer zwei verschiedene Elemente. nat nat integer set set stack bintree graph freely generated by generated by generated by generated by generated by freely generated by freely generated by generated by 0, +1 0, 1, + 0, +1, −1 ∅, ins ∅, {.}, ∪ empty, push mkleaf, mkbranch ∅, +node, +edge list freely generated by [], + 8. Juli 2013 0+0=0 0 +1 −1 = 0 ins(a,ins(a,∅)) = ins(a,∅) {a} ∪ {a} = {a} ∅ +node n +node n = ∅ +node n G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 112 / 318 Axiome für freie Datentypen Beispiel: Konstante c, einstellige Funktion f , zweistellige Funktion g • Verschiedenheit der Konstruktoren c, f und g : c 6= f (x), f (x) 6= g (y , z), c 6= g (x, y ) • Injektivität der Konstruktoren: f (x) = f (y ) ↔ x = y , g (x, y ) = g (u, v ) ↔ x = u ∧ y = v Satz: Die Spezifikation mit diesen Axiomen ist monomorph und konsistent, sie charakterisiert also genau einen Datentyp. KIV: Schreibe freely generated by, Axiome werden generiert. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 113 / 318 Freie Erzeugtheitsklauseln Freie Erzeugtheitsklauseln A |= S 0 freely generated by C :⇔ • A |= S 0 generated by C • Für 2 Konstruktorterme t, t 0 ∈ T s ((S, C ), X \ Xs ) mit s ∈ S 0 gilt nur dann [[t]] A,v = [[t 0 ]] A,v 0 wenn sie mit den exakt gleichen Konstruktoren gebildet sind, und die Variablen an gleichen Positionen gleich belegt sind. Beispiel Listen: • [[[]]] A,v , [[a + []]] A,v 0 , [[a + b + []]] A,v 00 sind auf jeden Fall verschiedene Listen (egal wie die Belegungen v , v 0 , v 00 sind) • [[a + []]] A,v = [[b + []]] A,v 0 gdw. wenn v (a) = v 0 (b). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 114 / 318 Natürliche Zahlen als freier Datentyp Beispiel: Die natürlichen Zahlen Nat3 = specification sorts nat; constants 0 : nat; functions +1 : nat → nat; variables n : nat; induction nat freely generated by 0, +1; end specification ⇒ Neu: Axiome jetzt generiert. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 115 / 318 Listen als freier Datentyp Beispiel: Listen als freier Datentyp List2 = specification sorts list, elem; functions [] : → list; . + . : elem × list → list; variables a, b: elem; l, l1 , l2 : list; induction list freely generated by [], +; end specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 116 / 318 Generierte Axiome für Listen Generierte Axiome Spezifikation generiert: [] 6= a + l, a + l1 = b + l2 ↔ a = b ∧ l1 = l2 Induktionsregel für die Sorte list ∀ y. V Γ→ W ∆, Γa+l ` ∆a+l l l Γ`∆ [] [] Γ l ` ∆l y = free(Γ ` ∆) \ {l} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 117 / 318 Datentyp-Definion (Motivation) Häufige Situation: • Freie Erzeugbarkeit mit Konstruktoren ci • Selektoren, die aus ci (x1 , . . . xn ) die xj selektieren • Testprädikate ist mit Konstruktor cl gebildet“ ” • Ordnung: ist Unterterm von“ ” • Größenfunktion: Anzahl nichtkonstanter Konstruktoren“ ” ⇒ Eigenes Syntaxkonstrukt data specification vermeidet unnötige Schreibarbeit. In KIV typischerweise nie freely generated, sondern gleich data specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 118 / 318 Data Specification (Beispiel 1) Beispiel 1: Wochentage Weekday2 = data specification weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun; variables w : weekday; end data specification Generierte Axiome: Die Konstanten sind paarweise verschieden: Mon 6= Tue, Mon 6= Wed, Mon 6= Thu, Mon 6= Fri, . . . Induktionsregel: ΓMon ` ∆Mon w w . . . ΓSun ` ∆Sun w w Γ`∆ ⇒ Beweis durch Fallunterscheidung nach dem Tag Verallgemeinerung: Aufzählungstypen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 119 / 318 Data Specification (Beispiel 2) Beispiel 2: Paare Pair = data specification using Elem1, Elem2; pair = mkpair ( . .1 : elem1; . .2 : elem2 ) variables p : pair; end data specification Generierte Axiome: mkpair(a, b).1 = a; mkpair(a, b).2 = b Induktionsregel: mkpair(a,b) mkpair(a,b) Γp ` ∆p Γ`∆ ⇒ Expandiert Variable p zu mkpair(a, b) Verallgemeinerung: Tupel 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 120 / 318 Data Specification (Beispiel 3) Beispiel 3: natürliche Zahlen Nat = data specification nat = 0 | . +1 (. −1 : nat); variables n : nat → nat; order predicates . < . : nat × nat; end data specification Generierte Axiome: n +1 −1 = n; (: 0 −1 ist unspezifiziert :) ¬ n < n; m < n ∧ n < k → m < k; ¬ n < 0; m < n +1 ↔ (m = n ∨ m < n) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 121 / 318 Data Specification (Beispiel 4) Beispiel 4: Listen List = data specification using Nat, Elem; list = . + . (. .first : elem; . .rest : list) with consp | [] with nilp; variables l : list; (: ist Unterterm für Listen = ist Endstück :) order predicates . . : list × list; size functions length : list → nat; end data specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 122 / 318 Selektoren als partielle Funktionen Problem: Was tun, wenn ein Selektor auf den falschen Summand angewandt wird? Hier: Was sind [] .first und [] .rest? .first und .rest sollten für [] gar nicht definiert sein ⇒ Partielle Funktionen In KIV: []. first und [].rest sind unspezifiziert (i. e. kein Axiom) Semantik: [].rest ist in jeder Algebra (Datenstruktur) irgendeine andere Liste ⇒ Echte Implementierung muss irgendeine Liste zurückgeben Pragmatik: Formeln mit [].rest sollten nicht vorkommen. Wenn doch, muss die Sequenz ohne die Formeln beweisbar sein. Bem.: Alternativen sind möglich aber komplizierter (u. a. Fehlerelemente, echte Partialität, etc.) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 123 / 318 Data Specification (Beispiel 3) Neue Axiome für List3: nilp([]); ¬ nilp(a + l); ¬ consp([]); consp(a + l); (a + l).first = a; (: kein Axiom für [] .first :) (a + l).rest = l; (: kein Axiom für [] .rest :) ¬ l []; l (a + l1 ) ↔ l = l1 ∨ l l1 ; (: beweisbar, aber der Einfachheit halber generiert :) ¬ l l; l1 l2 ∧ l2 l3 → l1 l3 ; length([]) = 0; length(a + l) = length(l) +1; 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 124 / 318 Data Specification allgemein Definition (Datendefinition) Eine Datendefinition D hat die Form (optionales in eckigen Klammern): s = c1 (sel 1,1 : s1,1 ; . . . ; sel 1,n1 : s1,n1 ) [with p1 ] | ... | ck (sel k,1 : sk,1 ; . . . ; sel k,nk : sk,nk ) [with pk ]; [order predicate . . : s × s;][size function sz : s → nat;] Überladen: sel i,j = sel i 0 ,j 0 erlaubt, falls si,j = si 0 ,j 0 , ansonsten alle Operationen paarweise verschieden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 125 / 318 Eigenschaften von Data Specifications Satz: Alle Data Specifications sind immer konsistent. Sie sind immer monomorph bis auf unspezifizierte Selektoren und Parameter. Intuition bei Listen ist also: 1 Wir haben exakt den Datentyp der Listen beschrieben. 2 Für die Realisierung auf einem Rechner ist lediglich offen, • was für ein Elementtyp verwendet wird und • was für eine Element bzw. Liste [].first und [].rest zurückgeben. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 126 / 318 Datentyp-Definitionen in Java und Scala abstract class s { } /* Subklasse für Konstruktor c1 */ class c1 extends s { s11 sel11; // ein Feld pro Selektor s12 sel12; ... s1n1 sel1n1; abstract class s case class c1( val s11 sel11, val s12 sel12, ... ) extends s /* Konstruktor */ public c1(s11 sel11, s12 sel12, ...) { this.sel11 = sel1; this.sel12 = sel12; ... } } /* Subklasse für Konstruktor c2 */ class c2 extends s { ... } 8. Juli 2013 case class c2( ... ) extends s G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 127 / 318 Strukturierte Spezifikation: Anreicherung um nichtrekursive und rekursive Definitionen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 128 / 318 Strukturierte Spezifikationen Motivation Spezifikationen werden sehr schnell sehr groß ⇒ Strukturierung erforderlich 1 Übersichtlichkeit & Verständlichkeit 2 Wiederverwendung von Komponenten 3 Unabhängige Entwicklung von Komponenten 4 Strukturierung und Wiederverwendung von Beweisen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 129 / 318 Strukturierte Spezifikationen in KIV • KIV zeigt strukt. Spezifikationen als Spezifikationsgraph an • In KIV enthält jeder Knoten neben der Spezifikation außerdem eine Theorembasis • Die Theorembasis enthält eine Menge von Theoremen (Sequenzen) über der Gesamtsignatur • Für jede Sequenz kann ein Beweis vorhanden sein, der zeigt, daß die Sequenz aus SP und anderen Theoremen folgt (keine zyklischen Abhängigkeiten) • Theoreme aus darunterliegenden Spezifikation werden mit insert spec-lemma statt insert lemma angewandt • KIV hat ein Korrektheitsmanagement, um Abhängigkeiten zwischen Beweisen zu verwalten 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 130 / 318 Strukturierte Spez.: Vereinigung, Anreicherung • Vereinigung • Wirft Signaturen + Axiome zusammen • Syntax: union specification <SPEC1> + <SPEC2> + ... end union specification • Nichtdisjunkte Vereinigung nur, wenn gemeinsamer Teil in gleicher Unterspezifikation (sonst Gefahr der Inkonsistenz!) • Anreicherung • Addiert neue Signaturen + Axiome • Syntax: enrich <SPEC1>, <SPEC2>, ... with <signature> <induction> <axioms> end enrich • Implizit: Ausgangsspezifikation der Anreicherung ist die Vereinigung von <SPEC1>, <SPEC2>, ... 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 131 / 318 Anreicherung: Vorgehen • Neue Axiome hinzuzunehmen macht eine Spezifikation sehr schnell inkonsistent (siehe Versuch 3!) ⇒ Gewünscht: Nur konsistenzerhaltende“ Anreicherungen ” • Formaler Begriff: Konsistenzerhaltend = Hierarchiepersistent • Neue Operationen sollten monomorphieerhaltend“ sein: Wenn ” genau ein Datentyp spezifiziert, sollte die Operation ebenfalls eindeutig festgelegt sein • Formaler Begriff: Monomorphieerhaltend = Eindeutig Vorgehen: Anreicherung nur durch rekursive und nichtrekursive Definitionen für neue Operationen. Diese sind hierarchiepersistent und eindeutig. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 132 / 318 Nichtrekursive Definitionen (Motivation) • Grundidee: Definition als Abkürzung einer grossen Formel • Prädikat: p(x) ↔ ϕ (p kommt in Formel ϕ nicht vor) • Funktion: f (x) = t (f kommt im Term t nicht vor) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 133 / 318 Beispiel: Anreicherung um nichtrek. Prädikat NatDiv = enrich Nat with predicates | : nat × nat; axioms m | n ↔ ∃ k. k * m = n; end enrich Die Anreicherung NatDiv ist hierarchiepersistent und eindeutig. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 134 / 318 Beispiel: Anr. um nichtrek. Prädikat (mit FU) NatPrime = enrich NatDiv with predicates prime : nat; axioms ¬ prime(0); ¬ prime(1); n ≥ 2 → (prime(n) ↔ ∀ m. m | n → m = 1 ∨ m = n); end enrich Die Anreicherung NatPrime ist hierarchiepersistent und eindeutig (FU nach n = 0, n = 1, n ≥ 2 ist vollständig). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 135 / 318 Beispiel: Anreicherung um nichtrek. Fkt. Nat12max = enrich Nat with constants 1 : nat; 2 : nat; functions max : nat × nat → nat; axioms 1 = 0 +1; 2 = 0 +1 +1; m < n → max(m, n) = n; ¬ m < n → max(m, n) = m; end enrich Die Anreicherung Nat12max ist hierarchiepersistent und eindeutig (beachte: In KIV sind die Zahlen 1, 2 schon vordefiniert, die Axiome werden deshalb nicht benötigt). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 136 / 318 Gegenbeispiel 1: Keine nichtrek. Fkt.def. illegalNatmax = enrich Nat with functions max : nat × nat → nat; axioms max(m, n) = k ↔ (m < n ∧ k = n) ∨ (¬ m < n ∧ k = m) end enrich Dies ist keine nichtrekursive Definition Die Definition ist beweisbar äqueivant zu der in Nat12max (insofern kann sie gerechtfertigt werden). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 137 / 318 Gegenbeispiel 2: Keine nichtrek. Fkt.def. illegalNatdiv = enrich Nat with functions . / . : nat × nat → nat; axioms m / n = k ↔ ∃ r. r < n ∧ k * n + r = m end enrich Diese Definition ist sogar inkonsistent, es fehlt die Vorbed. n 6= 0. Generell: Ein Axiom der Form f(x) = y ↔ . . . bildet keine nichtrekursive Definition (dagegen p(x,y) ↔ . . . schon). Solche Axiome sollten vermieden werden, da sie leicht zu Inkonsistenz oder Uneindeutigkeit führen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 138 / 318 Weitere Beispiele für nichtrek. Def. m ≤ n ↔ ∃ k. m + k = n m < n ↔ m ≤ n ∧ m 6= n m>n↔n<m even(n) ↔ ∃ m. n = m + m odd(n) ↔ ¬ even(n) m < n → min(m, n) = m, ¬ m < n → min(m, n) = n x ≥ 0 → abs(x) = x, x < 0 → abs(x) = −x last(l + (a + [])) = a (: unvollst. Def :) ((a + l)).first = a (: unvollst. Def :) a ∈ l ↔ ∃ l 0 , l 00 . l 0 + a + l 00 = l nodups(l) ↔ ¬ ∃ l1 , l2 , l3 , a. l = l1 + a + l2 + a + l3 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 139 / 318 Nichtrekursive Definitionen allgemein • Prädikat: p(x) ↔ ϕ (p kommt in Formel ϕ nicht vor) • Funktion: f (x) = t (f kommt im Term t nicht vor) • Prädikat mit 2 vollständigen Fällen: ε → (q(x, y ) ↔ ϕ1 ), ¬ ε → (q(x, y ) ↔ ϕ2 ) (p kommt in ε, ϕ1 , ϕ2 nicht vor) • Funktionen mit 3 unvollständigen Fällen: ε ∧ δ → f (x, y ) = t1 , ε ∧ ¬ δ → f (x, y ) = t2 , ¬ ε ∧ δ → f (x, y ) = t3 (f kommt in ε, δ, t1 , t2 , t3 nicht vor) Satz: Die Hinzunahme einer neuen Operation (Funktion oder Prädikat) mit nichtrekursiver Definition ist immer hierarchiepersistent. Wenn die Fälle vollständig sind, ist die Erweiterung sogar eindeutig. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 140 / 318 Rekursive Definitionen (Motivation) • Datentypen bestehen aus (der Semantik von) Konstruktortermen • Rekursive Definitionen geben Definition durch Reduktion auf kleinere Konstruktorterme • Entsprechen einem rekursiven Programm, das den Term abläuft Length = enrich List with functions length : list → nat; axioms length([]) = 0; length(a + l) = length(l) +1; end enrich Satz: Die Hinzunahme einer neuen Operation mit rekursiver Definition zu einem freien Datentyp ist immer hierarchiepersistent. Wenn die Fälle vollständig sind, ist die Erweiterung immer eindeutig. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 141 / 318 Keine rekursive Definition illegalLength = enrich List with functions length : list → nat; axioms length([]) = 0; length(l) = length(l.rest) +1; end enrich 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 142 / 318 Keine rekursive Definition illegalLength = enrich List with functions length : list → nat; axioms length([]) = 0; length(l) = length(l.rest) +1; end enrich • Spezifikation ist inkonsistent: Vorbedingung l 6= [] → fehlt im zweiten Axiom • Mit Vorbedingung äquivalent zum vorigen Axiom • Aber: Nicht möglich als Simplifierregel (Endlosschleife!) • Ausserdem: Induktion/constructor cut/Elimination ergibt immer a + x, niemals x.rest • Deshalb: Rekursion immer mit Konstruktoren (niemals mit Selektoren) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 142 / 318 Beispiel: Anreicherung um rek. Definition Append = enrich List with functions . + . : list × list → list; axioms [] + l = l; (a + l) + l’ = a + (l + l’); end enrich Append ist hierarchiepersistent und eindeutig (+ ist überladen: Sowohl Element vor Liste hängen (rot und schwarz), als auch 2 Listen zusammenhängen (blau)). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 143 / 318 Beispiel: Anreicherung um rek. Prädikat (FU) Sorted = enrich List with predicates sorted : list axioms ordered([]), ordered(a + []), ordered(a + b + l) ↔ a < b ∧ ordered(b + l) end enrich Ordered ist hierarchiepersistent und eindeutig. Das zweite und dritte Axiom sind äquivalent zu: l’= [] → ordered(a + l’), l’= b + l → ordered(a + l’) ↔ a < b ∧ ordered(l’) (vollständige Fallunterscheidung). Die Gleichungen vor der Implikation wurden eingesetzt (bessere Simplifierregel!). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 144 / 318 Rekursive Definition allgemein Hier speziell: Funktionen/Prädikate mit 3 Argumenten (Definitionen im ersten rekursiv) und Listen. Allgemein: 1 Axiom pro Konstruktor • Prädikat: p-base: p([], y , z) ↔ ϕ1 p-rec : p(a + x, y , z) ↔ ϕ2 (x, y , z verschieden. ϕ1 hat keine Aufrufe von p. ϕ2 hat nur Aufrufe von p der Form p(x, t1 , t2 )) • Funktion: f-base: f ([], x, y ) = t0 f-rec: f (a + x, y , z) = t (x, y , z verschieden. t0 hat keine Aufrufe von f . t hat nur Aufrufe von f der Form f (x, t4 , t5 )) • Zusätzliche Fallunterscheidung in den Axiomen ist ok. Z. B. statt f (a + z, y , z) = t 3 unvollständige Fälle: ε ∧ δ → f (a + x, y , z) = t1 , ε ∧ ¬ δ → f (a + x, y , z) = t2 , ¬ ε ∧ δ → f (a + x, y , z) = t3 (ε, δ, t1 , t2 , t3 enthalten nur Aufrufe von f der Form f (x, t4 , t5 ) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 145 / 318 Strukturierte Spezifikationen: Umbenennung und Parameter 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 146 / 318 Strukturierte Spezifikationen: Umbenennung Umbenennung: • Benennt die Operationen einer Spezifikation um • Nützlich um 2 Kopien zu erhalten • Syntax: rename <SPEC> by morphism <renaming1>; ... <renamingn>; end rename • renaming = <sort/op/var> → <sort/op/var>; • Identische Umbenennungen weglassen (werden beim Ansehen der Spezifikation aber angezeigt) • Nicht 2 Symbole auf dasselbe abbilden: Injektiv umbenennen • Entweder alle Variablen oder keine umbenennen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 147 / 318 Beispiel Umbenennung: Listen zu Stacks rename List by morphism list → stack; [] → empty; (: Typangabe für überladenes Symbol :) + :: (elem × list → list) → push; (: pop nicht mehr postfix, Schreibweise also pop(x), default ist in/prae/postfix uebernehmen :) .rest → pop prio 0; (: top soll nun praefix sein :) .first → top .; (: eigentlich keine Stack-Operation, nur um Overloading zu zeigen :) + :: (list × list → list) → concat prio 0; x → st; y → st0; z → st1; end rename 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 148 / 318 Strukturierte Spez.: Generische Spezifikation Generische Spezifikation: • Syntax: generic specification parameter <SPEC> using <SPEC1>, ..., <SPECn> target <signature> <induction> <axioms> end generic specification • Wie Anreicherung (von <SPEC>, <SPEC1>, ..., <SPECn>), nur wird von <SPEC> explizit gesagt, dass es ein Parameter ist. • Vereinigung und Anreicherung übernimmt den (oder die) Parameter der Unterspezifikationen • Variante: generic data specification: Wie data specification nur mit Parameter 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 149 / 318 Strukturierte Spez. Aktualisierung (1) Aktualisierung: • Instanziert Parameter (oder einen Parameter) einer Spezifikation • Beispiel: Listen beliebiger Elemente → Listen von Zahlen • Syntax: actualize <SPEC> with <ASPEC1>,...,<ASPECn> by morphism <renaming1>; ... <renamingn>; end actualize • renaming = <sort/op/var> → <sort/op/var>; • Die Vereinigung von <ASPEC1>,...,<ASPECn> heisst aktuelle Spezifikation • Identische Umbenennungen weglassen • Entweder alle Variablen oder keine umbenennen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 150 / 318 Strukturierte Spez. Aktualisierung (2) Aktualisierung: • Der Parameter muss in die aktuelle Spez. abgebildet werden • Abbildung darf nicht-injektiv sein: pair(elem1 , elem2 ) → pair(nat, nat) • Der Nicht-Parameter-Teil darf nur injektiv und disjunkt zur aktuellen Spezifikation umbenannt werden, z. B. list → natlist • Die instanzierten Axiome des Parameters müssen Axiome in der aktuellen Spezifikation sein • Verallgemeinerung instantiated specification: • Axiome werden bewiesen • mapping statt morphism erlaubt es, eine Sorte auf ein Tupel von Sorten abzubilden 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 151 / 318 Aktualisierung: Beispiel (1) Order = specification sorts elem; constants d : elem; predicates : elem × elem; variables a, b, c : elem; axioms ¬ a a; a b ∧ b c → a c; ¬ a d; (: d ist minimal :) end specification List-Ord = generic data specification parameter Order using Nat list = [] | . + . (. .first : elem; . .rest : list); size functions length : list → nat; end generic data specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 152 / 318 Aktualisierung: Beispiel (2) NatList = actualize List-Ord with Nat by morphism list → natlist; elem → nat; → <; d → 0; a → n; b → n0; c → n1; end actualize Die instanzierten Axiome (u. a. ¬ n < 0) sind (modulo Umbenennung) in Nat vorhanden. Die Listenoperationen (+, .rest etc.) werden nicht umbenannt (sie bekommen nur die neuen Argumentsorten). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 153 / 318 Strukturierte Spezifikation: Nichtfreie Datentypen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 154 / 318 Nichtfreie Datentypen: Der typische Fehler Orderedlist = enrich List3 with predicates . < . : elem × elem ; ordered : list ; axioms ¬ a < a; a < b ∨ a = b ∨ b < a; a < b ∧ b < c → a < c; ordered([]); ordered(a + []); ordered(a + b + l) ↔ a < b ∧ ordered (b + l); end enrich NICHT ∀ l. ordered(l) addieren!!! Das wäre INKONSISTENT!!! Allgemein: Ein generierter Datentyp enthält immer alle Konstruktorterme. Man kann nicht nachträglich welche ausschliessen. Man kann nur einen nichtfreien Datentyp bilden, der Terme identifiziert 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 155 / 318 Spezifikation nichtfreier Datentypen • Spezifikationen nichtfreier Datentypen werden sehr leicht inkonsistent oder uneindeutig • Konstruiere nichtfreien Datentyp dadurch, daß alle Terme, die die gleichen Elemente repräsentieren sollen, in einer Klasse zusammengefaßt werden • Deshalb als erstes nach der Bestimmung der Konstruktoren: Definiere Gleichheit durch Extensionalitätsaxiom: x = y ↔ ϕ(x, y ) • Dann: Die in ϕ benutzten Operationen werden rekursiv definiert • Damit: Monomorph: Höchstens ein Datentyp spezifiziert • Vorsicht: Rek. Def. kann inkonsistent sein! • Jetzt: Arrays, im Praktikum: Mengen (einfacher) Einzige Ausnahme, bei der das Prinzip nicht funktioniert: integers (für die KIV-Axiome wurde ein Einzelbeweis für Monomorphie geführt) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 156 / 318 Beispiel: Arrayspezifikation, Teil 1 Array= specification using Nat; Elem; sorts array; functions mkar : nat × elem → . [ . ] : array × nat × elem → . [ . ] : array × nat → # . : array → induction array generated by mkar, []; variables d : elem; a, a’ : array; 8. Juli 2013 array; array; elem; nat; G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 157 / 318 Beispiel: Arrayspezifikation, Teil 2 Festlegungen: • Konstruktor mkar(n, d) bekommt Initialelement d (Alternative: Unspezifizierte Initialisierung) • Für m ≥ # a ist Selektion a[m] unspezifiziert • Für m ≥ # a ist Modifikation Identität: a[m, d] = a axioms a = a’ ↔ # a = # a’ ∧ ∀ n. n < # a → a[n] = a’[n]; # mkar(n,d) = n; # a[m , d] = # a; m < n → mkar(n,d)[m] = d; m < # a → a[m , d][m] = d; n 6= m → a[m , d][n] = a[n]; end specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 158 / 318 Inkonsistente rekursive Definition • Annahmen: • Mengen von nat. Zahlen definiert • Die Mengen sind von ∅ und insert generiert • Für Mengen gilt: insert(a,insert(a,∅)) = insert(a,∅) • Rekursive Definition: sum(∅) = 0, sum(insert(a, s)) = a + sum(s) • Inkonsistent, da aus insert(1,insert(1,∅))) = insert(1,∅) folgt: 2 = sum(insert(1,insert(1,∅))) = sum(insert(1,∅)) = 1 • Korrekte Definition: sum(∅) = 0, ¬ a ∈ s → sum(insert(a, s)) = a + sum(s) (im Fall a ∈ s ist insert(a, s) = s) • Operation sum muss mit der Definition der Gleichheit auf Mengen, i. e. dem Extensionalitätsaxiom verträglich sein! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 159 / 318 Konsistenz nichtfreier Datentypen 2 Alternativen, um Konsistenz sicherzustellen: 1 2 Semantische Überlegung: Es gibt den spezifizierten Datentyp auf Rechnern, und er erfüllt die Axiome ⇒ Konsistenz Beweise über dem freien Datentyp, den man erhält, wenn man: • Extensionalität x = y ↔ ϕ(x,y) weglässt. • generated by durch freely generated by ersetzt. • Idee: Der freie Datentyp ist konsistent und monomorph. • • • • Den nichtfreien erhält man, indem man Konstruktorterme, die per Extensionalität gleich“ sind, in Klassen zusammenwirft. ” Dazu muss ϕ eine Äquivalenzrelation sein: ϕ(a, a), ϕ(a, b) → ϕ(b, a), ϕ(a, b) ∧ ϕ(b, c) → ϕ(a, c) Für gleiche“ Terme t1 , t2 muss Operation f dasselbe liefern: ” ϕ(t1 , t2 ) → f (t1 ) = f (t2 ) bzw. ϕ(t1 , t2 ) → ϕ(f (t1 ), f (t2 )) Äquivalenzrel. + Verträglichkeit = Kongruenz Formeln über dem freien Datentyp beweisbar ⇒ Konsistenz 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 160 / 318 Korrekte Spez. der geordneten Listen (1) Orderedlist = specification sorts elem; ordlist; constants [] : ordlist; functions . + . : elem × ordlist → ordlist ; min : ordlist → elem ; butmin : ordlist → ordlist ; predicates . < . : elem × elem ; variables a, b, c : elem; l, l 0 : ordlist; induction ordlist generated by [], +; 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 161 / 318 Korrekte Spez. der geordneten Listen (2) axioms ¬ a < a; a < b ∨ a = b ∨ b < a; a < b ∧ b < c → a < c; l = l0 ↔ ∨ l = [] ∧ l’ = [] l 6= [] ∧ l’ 6= [] ∧ min(l) = min(l0 ) ∧ butmin(l) = butmin(l0 ); min(a + []) = a; a < b → min(a + b + l) = min(a + l); ¬ a < b → min(a + b + l) = min(b + l); butmin(a + []) = []; a < b → butmin(a + b + l) = b + butmin(a + l); ¬ a < b → butmin(a + b + l) = a + butmin(b + l); end specification 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 162 / 318 Zusammenfassung: Datentyp-Spezifikation Vorgehen zur Spezifikation von Datentypen: 1 Bestimme Datenmengen ⇒ Sorten 2 Bestimme Konstruktoren 3 Falls frei ⇒ data specification 4 Falls nichtfrei ⇒ Extensionalitätsaxiom + (rek. oder nichtrek.) Definition der dabei verwendeten Funktionen (evtl. Kongruenzbeweis) 5 Für weitere Funktionen: rek. oder nichtrek. Definitionen (enrichment) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 163 / 318 Noethersche Induktion 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 164 / 318 Motivation: Noethersche Relationen Noethersche Relationen sind direkt verknüpft mit Terminierung: • Wie kann man formal ausdrücken, dass die Schleife while test do prog anhält? • Betrachte Folge der Zustände zu Beginn der Schleife: s0 , s1 , s2 , . . .. • Terminierung gilt genau dann, wenn für jedes s0 die Folge endlich ist. • Definiere also: s 0 s ⇔ s erfüllt test und s 0 entsteht aus s durch Abarbeitung von prog • Analog für eine rekursive Definition einer Funktion/Methode f: s 0 s ⇔ Wenn man f mit s aufruft, findet ein rek. Aufruf mit s 0 statt (man erhält jetzt evtl. mehrere s 0 , i. e. einen Aufrufsbaum) • Kriterium für Terminierung ist: Die Relation enthält keine unendlichen absteigenden Folgen . . . s2 s1 s0 . 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 165 / 318 Noethersche Relationen Definition (Noethersche Relationen) Sei ⊆ A × A. Die Relation heißt noethersch (oder wohlfundiert, engl. well-founded) wenn es keine unendlichen -Ketten gibt: · · · a3 a2 a1 a0 Beispiele: • < auf natürlichen Zahlen ist noethersch, aber nicht > • < auf ganzen Zahlen ist nicht noethersch • m n ⇔ n = m + 1 ist noethersch (nicht transitiv) • ⊂ (echte Teilmenge) ist noethersch auf endlichen Mengen (Warum nicht auf unendlichen?) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 166 / 318 Eigenschaften noetherscher Relationen • ist immer irreflexiv • Die Relation muss nicht transitiv sein, ihre transitive Hülle ist aber auch noethersch (und transitiv) deshalb häufig o.B.d.A nur noethersche Ordnungen betrachtet • Die Relation muss kein eindeutiges kleinstes Element besitzen. Beispiel: Echte Teilmenge auf nichtleeren Mengen • Kleinstes Element existiert 6⇒ noethersch. Beispiel: < auf rationalen Zahlen, die ≥ 0 sind. • Wenn < noethersch und stärker, i. e. x y → x < y , dann erst Recht noethersch 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 167 / 318 Bedeutung noetherscher Relationen Bedeutung: • Betrachte Folge der Zustände, die ein Programm durchläuft. Definiere s0 s :⇔ s0 ist Nachfolgezustand von s Dann gilt: noethersch ⇔ Programm terminiert immer • Stärkeres Induktionsprinzip als strukturelle Induktion: Noethersche Induktion • Nicht behandelt: Zu noetherscher Induktion gehören wohlfundiert rekursive Definitionen. (Analog zu: Strukturelle Induktion vs. rekursive Definition) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 168 / 318 Beispiele für noethersche Prädikate Ordnungsprädikate: Ordnungsprädikate < von Datendefinitionen sind noethersch. Zur Erinnerung: x < y ⇔ x (als Konstr.term) ist echter ” Unterterm von y“. Z. Bsp. bei Listen: x < a + x, x < a + (b + x), x 6= [] → [] < x Keine Größenordnung, nicht: a + x < a + b + x (außer wenn a = b) Größenordnung: Sei size : s → nat. Dann ist noethersch mit x y :↔ size(x) < size(y ) Beispiele: Länge einer Liste, Anzahl der Knoten eines Baums, Kardinalität einer Menge etc. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 169 / 318 Noethersche Induktion Satz (Noethersche Induktion) Genau für noethersche Relationen gilt: Wenn für jedes a aus E (a0 ) für alle Elemente a0 a die Aussage E (a) gefolgert werden kann, so gilt E für alle Elemente: (∀ a. (∀ a0 . a0 a ⇒ E (a0 )) ⇒ E (a)) ⇒ ∀ b. E (b) Definition (Noethersche Induktionsregel) Sei y := free(Γ ` ∆) \ {x} und noethersch. Induktion über x: V W x0 ∀ y .∀ x 0 . x 0 x → ( Γ → ∆)x , Γ ` ∆ IND() Γ`∆ 0 ∀ y .∀ x 0 . x 0 x → ϕxx ` ϕ speziell für Formel `ϕ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 170 / 318 Noethersche Induktion (Beispiele) Beispiel: Natürliche Zahlen ∀ n0 . n0 < n → ϕ(n0 ) ` ϕ(n) ` ∀ n. ϕ(n) Beispiel: Listen ∀ l0 . (l0 l) → ϕ(l0 ) ` ϕ(l) ` ∀ l. ϕ(l) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 171 / 318 Noethersche Induktion in KIV • In KIV ist die Regel induction für noethersche Induktion vorhanden • Für Variablen x eines freien Datentyps wird angeboten • Ind. über vordefiniertes Ordnungsprädikat (pro Sorte eines; Induktion über x wird angeboten) • Ind. über vordefinierte Größenfunktion (pro Sorte eine Fkt. #; Induktion über # x) • Größenfunktionen für nichtfreie Datentypen kann man mit • • • • Unit-Add HeuristicInfo“ addieren ” Es ist auch möglich einen Term anzugeben, über dessen Größe induziert wird (z.Bsp. # x − # y ) Die Induktionshypothese wird in KIV mit Ind-Hyp abgekürzt Goal-Again with Ind-Hyp“ zeigt die Induktionshypothese an ” Anwendung der Induktionshypothese mit apply induction (statt all left) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 172 / 318 Sequentielle Programme und Dynamische Logik 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 173 / 318 Was ist ein SW-System mathematisch? 1. Sicht: Operational Ein SW-System ist ein Automat • mit Zustand, • Zustandsübergängen und • mit Abläufen. 2. Sicht: Algebraisch Ein SW-System ist eine Algebra, d. h. ein System von Daten und Operationen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 174 / 318 Grundidee für Programme Hilfsmittel: Begriffe von Signatur, Algebra und Belegung aus der Prädikatenlogik • Datentypen in den Programmen sind beliebige algebraisch spezifizierte Datentypen (daher heißen die Programme abstrakte Programme) • Programmvariablen sind Variablen der Prädikatenlogik • Ein Zustand eines Programms ist eine Belegung der Prädikatenlogik • Kopiersemantik, d. h. Änderung an einer Variablen ändert keine andere (eine Variable ist kein Zeiger auf ein Objekt) • Variablen haben keine Adressen (kein &x wie in C) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 175 / 318 Programme: Syntax Programme Prog(Σ,X ) (Notation: α, β, γ) • Parallele Zuweisung: x1 := t1 , x2 := t2 , . . . , xn := tn Variablen aus X , Terme aus T (Σ, X ), kurz: x := t • { α; β } (geschachtelte { } weglassen) • Schleife (ε ist quantorenfreie Formel): while ε do α • Fallunterscheidung: if ε then α else β • Lokale Variablen: let x1 = t1 , x2 = t2 , . . . , xn = tn in α • Das Programm, das nichts tut: skip (Abkürzung: if ε then α ≡ if ε then α else skip) • Das Programm, das nie terminiert: abort (kann als Abkürzung definiert werden: while true do skip) • Prozeduren später 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 176 / 318 Programme: Semantik (1) Für eine Σ-Algebra A betrachtet man die Menge S ST:={v | v : s∈S Xs → As } der Variablenbelegungen. Für sequentielle Programme sind nicht alle Zwischenzustände interessant; es genügt, Anfangs- und Endzustände zu betrachten. Erster Versuch: Ein Programm überführt einen Anfangszustand in einen Endzustand: [[α]] : ST → ST 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 177 / 318 Programme: Semantik (1) Für eine Σ-Algebra A betrachtet man die Menge S ST:={v | v : s∈S Xs → As } der Variablenbelegungen. Für sequentielle Programme sind nicht alle Zwischenzustände interessant; es genügt, Anfangs- und Endzustände zu betrachten. Erster Versuch: Ein Programm überführt einen Anfangszustand in einen Endzustand: [[α]] : ST → ST Probleme mit dieser Semantik: • Was ist die Semantik von abort? • Wie auf indeterministische Programme erweitern? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 177 / 318 Programme: Semantik (2) Deshalb: Relationale Semantik: [[α]] ⊆ ST × ST • (v , v 0 ) ∈ [[α]] bedeutet: Zustand v wird von α in v 0 überführt • Wenn zu v kein v 0 mit (v , v 0 ) ∈ [[α]] vorhanden ist: α terminiert nicht, wenn in v gestartet • Wenn {(v , v 0 ), (v , v 00 )} ⊆ [[α]], so ist das Programm in v gestartet indeterministisch mit 2 möglichen Endzuständen: v 0 und v 00 • Derzeit betrachtete Programme sind deterministisch: Zu jedem v höchstens ein v 0 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 178 / 318 Programme: Semantik (3) Man definiert die relationale Semantik eines Programmes bzgl. der Algebra A rekursiv wie folgt: [[abort]] := ∅ [[skip]] := {(v , v ) | v ∈ ST} [[t ]] [[x := t]] := {(v , w ) | w = vx A,v } [[α; β]] := {(u, w ) | es gibt v : (u, v ) ∈ [[α]] und (v , w ) ∈ [[β]]} [[if ε then α else β]] := {(v , w ) | A, v |= ε und (v , w ) ∈ [[α]] oder A, v |= ¬ε und (v , w ) ∈ [[β]]} [[t ]] v (x) [[let x = t in α]] := {(v , wx ) | (vx A,v , w ) ∈ [[α]]} [ [[while ε do α]] := [[(if ε then α)i ; if ε then abort ]] i∈N wobei α0 := skip, αi+1 := α; αi 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 179 / 318 Korrektheitsbegriffe für Programme Partielle Korrektheit: ϕ [α] ψ Falls zu Beginn ϕ gilt und α terminiert, dann gilt anschließend ψ Semantik: A |= ϕ [α] ψ ⇔ für jedes v mit A, v |= ϕ und jedes w mit (v , w ) ∈ [[α]] gilt A, w |= ψ Totale Korrektheit: ϕ hαi ψ Falls zu Beginn ϕ gilt, dann terminiert α und anschließend gilt ψ Semantik: A |= ϕ hαi ψ ⇔ für jedes v mit A, v |= ϕ gibt es w mit (v , w ) ∈ [[α]] es gilt A, w |= ψ ϕ [α] ψ und ϕ hαi ψ heissen häufig Hoare-Tripel 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 180 / 318 Beispiele zur Korrekheit Partielle Korrektheit: |= |= |= |= |= true x =2 x =y x =a∧y =b x =2 [ x := 2 ] [ x := x+1 ] [ x := x +1 ] [ x := y, y := x ] [ abort ] x =2 x =3 x −1 = y x =b ∧y =a x >2 Unterschied partielle und totale Korrektheit: |= 6|= |= true true y 6= 0 8. Juli 2013 [ if y=0 then abort else x := 1 ] hif y=0 then abort else x := 1 i hif y=0 then abort else x := 1 i x =1 x =1 x =1 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 181 / 318 Hoare-Kalkül Achtung: In der Literatur findet man nicht ϕ[α]ψ und ϕhαi ψ, sondern wahlweise {ϕ}α{ψ} oder ϕ{α}ψ (für beides) Allgemein bekannt ist der Hoare-Kalkül, der ein Kalkül zur Ableitung von Tripeln ϕ{α}ψ ist. Wir werden einen allgemeineren Kalkül betrachten. Literatur z.B.: • Loeckx & Sieber, The Foundations of Program Verificiation, 2nd ed., Teubner 1987, etwas älter, viele Beispiele, kompliziertere (denotationale) Semantik • Apt, de Boer, Olderog: Verification of Sequential and Concurrent Programs, 3rd ed, Sptinger 2009. 500 Seiten, PL + SOS informell, Hoare-Kalkül, Smallstep-Semantik, behandelt auch OO und nebenläufige Programme • Sperschneider, Antoniou: Logic, a foundation for computer science. Addison-Wesley 1991. 500 Seiten,mehrsortige Logik, Sequenzenkalkül, Resolution, Gleichungslogik (Rewriting), Hoare-Kalkül, Modul-Refinement 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 182 / 318 Dynamische Logik A. Salwicki 1970 (“algorithmische Logik”), V.R. Pratt 1976, D. Harel 1977 Idee: Erfinde nicht einfach einen komplett neuen Kalkül für neue Objekte (hier: Hoare-Tripel) sondern bilde Programmformeln und erweitere Kalkül um diese neuen Formeln. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 183 / 318 Dynamische Logik: Syntax Die Menge DLFor(Σ,X ) der DL-Formeln über der Signatur Σ und der Variablenmenge X enthält • Alle prädikatenlogischen Formeln von For(Σ,X ) • Für α ∈ DLProg(Σ,X ) und ϕ ∈ DLFor(Σ,X ) auch • [α]ϕ ( box alpha phi“) ” Informelle Bedeutung: Wenn α terminiert, gilt nachher ϕ“ ” • hαiϕ ( diamond alpha phi“) ” Informelle Bedeutung: α hält, und nachher gilt ϕ“ ” Klassifikation: • Dynamische Logik ist eine (Multi-)Modallogik. • Modallogik mit Formeln ϕ (und 2 ϕ) stammen aus der Philosophie: “ich weiss ϕ”, “ich glaube ϕ”, “ϕ ist möglich” • Temporallogik: “irgendwann wird ϕ wahr sein” 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 184 / 318 Bemerkungen zur Syntax • Boxen und Diamonds binden stärker als Aussagenlogik: [α]ψ ∧ χ bedeutet ([α]ψ) ∧ χ • Schachtelung möglich: hαihβiψ bedeutet hαi ( hβiψ ) • Auch gemischte Schachtelung ist erlaubt: [α] ∀ x. ϕ ∧ hβiψ • Auch in DL betrachtet man Sequenzen, z. B. hαiψ, Γ ` ∆. • Wenn x in α vorkommt, x0 aber nicht, so besagt hαi x = x0 : “Am Ende von α hat x den Wert, den x0 jetzt hat” • hαi x = x0 → hβi x = x0 bedeutet: “Wann immer α in x einen Wert x0 ausrechnet so tut das auch β” Man kann in DL also über Programmähnlichkeit reden • Es gilt: [α]ψ ↔ ¬ hαi¬ ψ Man könnte also Box mit Hilfe von Diamond definieren 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 185 / 318 Semantik der Dynamischen Logik Die Semantik von Formeln der Prädikatenlogik wird erweitert durch A, v |= [α]ψ A, v |= hαiψ :⇔ :⇔ für alle w : (v , w ) ∈ [[α]] ⇒ A, w |= ψ. es gibt w : (v , w ) ∈ [[α]] und A, w |= ψ. Damit gilt A, v |= ϕ[α]ψ A, v |= ϕhαi ψ ⇔ ⇔ A, v |= ϕ → [α]ψ A, v |= ϕ → hαiψ, Hoare-Tripel sind also spezielle Formeln der Dynamischen Logik. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 186 / 318 Dynamische Logik: Beispiele |= [x := 1] x = 1 |= x = x0 → [x := x + 1] x = x0 + 1 |= x = x0 → hx := x + 1i x = x0 + 1 Unterschied Box/Diamond: |= x = 5 → [abort] x = 5 6|= x = 5 → haborti x = 5 Sequenzen mit Programmen, Programme auch im Antezedent: |= x = x0 ` [x := x + 1] x = x0 + 1 |= x > 0 ` hwhile x > 1 do x := x -1i x = 1 |= hif x > 0 then y := 1 else aborti y = y 0 ` y 0 = 1 ∧ x > 0 |= [if x > 0 then y := 1 else abort] y = y 0 ` y 0 = 1 ∧ x > 0 ∨ x = 0 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 187 / 318 Kalkül für Dynamische Logik Grundidee: Symbolische Ausführung von Programmen Betrachte Ausführung des Programms α1 ; α2 ; . . . ; αn (αi ohne ; (compound) auf top-level) • Annahme: Initialer Zustand erfüllt Vorbedingung ϕ0 • Berechne ϕ1 , die stärkste Formel, die nach α1 gilt • Berechne ϕ2 , die stärkste Formel, die nach α1 ; α2 gilt • . . . solange bis das Programm verschwunden ist • Zum Schluss: Teste ob ϕn die Nachbedingung impliziert (nur noch Prädikatenlogik) • Symb. Ausführung geht sowohl im Antezedent als auch im Sukzedent! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 188 / 318 DL-Kalkül: Normalisierung normalize right Γ ` hαihβiψ, ∆ Γ ` hα; βiψ, ∆ Γ ` [α][β]ψ, ∆ Γ ` [α; β]ψ, ∆ normalize left hαihβiψ, Γ ` ∆ hα; βiψ, Γ ` ∆ [α][β]ψ, Γ ` ∆ [α; β]ψ, Γ ` ∆ In KIV: Nie explizit angewandt, die erste Anweisung wird bei jeder Regelanwendung (in allen Programmformeln) immer automatisch abgespalten. KIV rotiert immer die Programmformeln nach vorne. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 189 / 318 DL-Kalkül: Zuweisungen (1) assign right (so auch im Hoare-Kalkül) Γ ` ψxτ , ∆ Γ ` [x := τ ]ψ, ∆ assign right (Dynamische Logik) 0 0 Γxx , x = τxx ` [α]ψ, ∆xx Γ ` [x := τ ][α]ψ, ∆ 0 wobei x 0 eine neue Variable ist (bezeichnet den alten Wert von x) Beachte: config-Datei des Projekts setzt Option Hoare-assign rule“ ” (ohne Option wird x 0 eine Variable für den neuen Wert, und Programmvariablen werden umbenannt) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 190 / 318 DL-Kalkül: Zuweisungen (2) • In KIV: assign right kombiniert beide Regeln: • Original-Hoare-Regel, falls nach der Zuweisung ψ kein Programm mehr enthält • Sonst die DL Regel • Die Regel gilt genau gleich auch für Diamonds statt Boxen • Die Regel für Zuweisung auf der linken Seite sieht genauso aus: assign left 0 0 x = τxx , [α]ψ, Γxx ` ∆xx [x := τ ][α]ψ, Γ ` ∆ 0 wobei x 0 eine neue Variable ist (für den Wert vor der Zuweisung) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 191 / 318 DL-Kalkül: Regeln für if if right Γ, ε ` [α]ψ, ∆ Γ, ¬ ε ` [β]ψ, ∆ Γ ` [if ε then α else β]ψ, ∆ if positive right Γ, ε ` [α]ψ, ∆ Γ ` ε, ∆ Γ ` [if ε then α else β]ψ, ∆ Analog: if negative right, if left etc.. KIV versucht immer die Tests zu entscheiden (per Simplifier), damit nur eine Prämisse entsteht. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 192 / 318 Invarianten Definition: Eine (Schleifen-)Invariante ist eine Formel, die vor und nach jedem Schleifendurchlauf gilt. Beispiel: m = 0 ∧ n = n0 → [ while n 6= 0 do n := n −1; m := m +1 od ] m = n0 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 193 / 318 Invarianten Definition: Eine (Schleifen-)Invariante ist eine Formel, die vor und nach jedem Schleifendurchlauf gilt. Beispiel: m = 0 ∧ n = n0 → [ while n 6= 0 do n := n −1; m := m +1 od ] m = n0 Invariante: m + m = n0 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 193 / 318 Bestimmung von Invarianten Wie kommt man drauf? • Schreibe Werte nach k Durchläufen der Schleife auf • Kann man zunächst für ein konkrete Anfangswerte (z.B. n0 = 5) machen. • Bestimme Formel, wie m,n nach k Durchläufen aussehen: m = k und n = n0 − k • Daraus Invariante ∃ k. m = k ∧ n = n0 − k • Diese Formel vereinfachen ergibt m + m = n0 Nebenbemerkung: Die Invariante benötigt +, die Schleife selbst nicht ⇒ manchmal brauchen Invarianten (genau wie beim Verallgemeinern von Induktionshypothesen) neue Funktionen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 194 / 318 Notwendiges Kriterium für Invarianten Eine prädikatenlogische Formel INV ist eine Invariante, wenn sich zeigen lässt: • Die Formel gilt am Anfang der Schleife • Die Invariante wird von einem Schleifendurchlauf erhalten: Es gilt: INV ∧ ε → [α]INV Für jede Invariante gilt: Wenn die Schleife anhält, dann gilt am Ende die Invariante, und (offensichtlich) dass der Test am Ende falsch ist. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 195 / 318 Terminierung von Schleifen Eine Schleife terminiert nur dann, wenn in jedem Schleifendurchlauf “etwas” abnimmt bezueglich einer noetherschen Ordnung (dann kann es nicht unendlich oft abnehmen). Vorgehen also: • Bestimme einen Term t, der abnimmt • Häufig: heruntergezählte Variable; Abstand einer hochgezählten Variable zur oberen Schranke; Größe einer Datenstruktur (z.B. Listenlänge) • Um Abnehmen zu zeigen, zeige mit (neuer) Hilfsvariable z zum Merken des alten Werts: z = t ∧ ε ∧ INV → hαi t < z 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 196 / 318 DL-Kalkül: While-Regel invariant right Γ ` INV , ∆ INV , ε ` [α]INV INV , ¬ ε ` ψ Γ ` [while ε do α]ψ, ∆ invariant right Γ ` INV , ∆ INV , ε, v = t ` hαi(INV ∧ t v ) Γ ` hwhile ε do αiψ, ∆ INV , ¬ ε ` ψ KIV: Die Schleifeninvariante INV und im zweiten Fall auch die Schranke t muss von Hand eingegeben werden (v ist neue Variable) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 197 / 318 DL-Kalkül: Regeln für skip und abort skip right Γ ` ψ, ∆ Γ ` hskipiψ, ∆ Γ ` ψ, ∆ Γ ` [skip]ψ, ∆ skip left ψ, Γ ` ∆ hskipiψ, Γ ` ∆ ψ, Γ ` ∆ [skip]ψ, Γ ` ∆ abort right Γ`∆ Γ ` habortiψ, ∆ Γ ` [abort]ψ, ∆ abort left habortiψ, Γ ` ∆ 8. Juli 2013 Γ`∆ [abort]ψ, Γ ` ∆ G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 198 / 318 DL-Kalkül: Lokale Variablen vardecls right x0 x 0 = τ , Γ ` hαx iϕ Γ ` hlet x = τ in αiϕ vardecls left x0 hαx iϕ, x 0 = τ , Γ ` ∆ hlet x = τ in αiϕ, Γ ` ∆ x 0 sind neue Variablen (bezeichnen die lokalen Variablen). Dieselben Regeln gelten auch für Boxen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 199 / 318 Beispiel zur Korrekheit m := x.first, x0 := x.rest; while x0 6= [] do { if x0.first > m then m := x0.first ; x0 := x0.rest } 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 200 / 318 Beispiel zur Korrekheit Maximum einer nichtleeren Liste nat. Zahlen x: x 6= [] `h m := x.first, x0 := x.rest; while x0 6= [] do { if x0.first > m then m := x0.first ; x0 := x0.rest } i m = maxl(x) wobei maxl([]) = 0, maxl(n + x) = max(n,maxl(x)) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 200 / 318 Zur nächsten Aufgabe Invarianten vorher überlegen!!! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 201 / 318 Prozeduren und Heuristiken für Programme 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 202 / 318 Prozeduren: Syntax • Neues Programmkonstrukt: Prozeduraufruf p#(t;y) • p# ist Prozedurname (das # ist übliche KIV-Konvention) • Terme t der Sorten s sind Eingabe-Parameter • Paarweise verschiedene Variablen y der Sorten s 0 sind Ein-Ausgabe-Parameter • s : s 0 heisst auch der (Aufrufs-)Modus der Prozedur • Prozeduren p# ∈ Ps:s 0 sind neuer Bestandteil der Signatur einer Spezifikation • KIV: Deklaration zwischen predicates und variables per: procedures p# s1 × ...× sn : s’1 × ...× s’m; 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 203 / 318 Prozeduren: Semantik • Semantik: Prozeduren sind eine Relation über den Trägern der Parametersorten: [[p#]] ⊆ As × As 0 × As 0 • (a, b, c) ∈ [[p]] bedeutet: Die Prozedur p#, aufgerufen mit • Eingaben a für die Eingabe-Variablen • Eingaben b für die Ein/Ausgabe-Variablen terminiert mit Ausgabe c in den Ein/Ausgabe-Variablen • Damit das stimmt: Kein Zugriff auf globale Variablen! Ersatz: Zusätzliche Ein/Ausgabe-Parameter • Normalfall in KIV: Funktionale Prozeduren: Ein/Ausgabe-Variablen dienen nur zur Ausgabe: c (und Terminierung) hängen nicht von b ab. • Wenn nicht, Schlüsselwort nonfunctional am Ende der Prozedurdefinition 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 204 / 318 Prozedurdeklarationen • Möglich: Axiome für Prozeduren (Vor- und Nachbedingung) • Normalerweise (hinter den axioms) Prozedurdeklarationen declarations f#(x; y) { if x = 0 then y := 1 else { f#(x -1;y); y := y * x } } • Erlaubt: (Gegenseitige) Rekursion • Semantik: Prozeduraufruf erhält “die übliche” Semantik. Formal: Vereinigung aller tiefenbeschränkten Rekursionen (analog zu: Vereinigung über beschränkte Zahl von Schl.durchläufen) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 205 / 318 Regeln für Prozeduraufrufe Falls Prozedurdeklaration p#(y ; z).α gegeben: x y = σ, Γ ` hαz iϕ, ∆ Γ ` hp#(σ; x)iϕ, ∆ x call right y = σ, hαz iϕ, Γ ` ∆ hp#(σ; x)iϕ, Γ ` ∆ call left Dabei: y sind die lokalen Variablen auf denen p# rechnet. Sie dürfen in der Sequenz nicht frei vorkommen (evtl. umbenennen) Die Regel gilt auch für Boxen statt Diamonds. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 206 / 318 Ein Beispiel procedures MAXL# natlist : nat; MAX# nat, nat : nat; declaration MAX#(m,n; n0) { if m < n then n0 := n else n0 := m }; MAXL#(x; n) { if x = [] then n := 0 else { MAXL#(x.rest; n); MAX#(n,x.first;n) } } 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 207 / 318 Programme als Voraussetzungen: execute call Nützlich bei Induktion, um den Call aus der Induktionsvoraussetzung gegen den gerade aktuellen zu kürzen“. ” execute call Γ ` σ = τ, ∆ y y hp#(σ; x)i(x = y ), ϕx , Γ ` ψz , ∆ hp#(σ; x)iϕ, Γ ` hp#(τ ; z)iψ, ∆ contract call Γ`σ=τ y y hp#(σ; x)i(x = y ), ϕx , ψz , Γ ` ∆ hp#(σ; x)iϕ, hp#(τ ; z)iψ, Γ ` ∆ Regeln gelten (so) nur für funktionale (und damit auch deterministische) Prozeduren (y jeweils neu). Für nichtfunktionale Prozeduren muß in der ersten Prämisse x = z hinzugefügt werden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 208 / 318 Zwischenzustände einführen: split left Die folgende Regeln wird meist für α = Prozeduraufruf angewandt (x = modifizierte Variablen von α, x 0 neu): split left x0 hαix = x 0 , ϕx , Γ ` ∆ hαiϕ, Γ ` ∆ • Führt einen Zustand x 0 am Ende von α ein, über den man “reden” kann. • Dieser wird bei der Anwendung von Lemmata der Form hαi x = x0 ` ϕ als Instanz für x0 gebraucht 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 209 / 318 Einfache Heuristiken für Programme • symbolic execution: Wendet alle Regeln für Programme an, die keine Fallunterscheidung ergeben: assign, if positive/negative, skip, abort, let • split left: Wendet die Regel split left an • contract and execute: Wendet execute call, contract call an Im Heuristik-Satz DL heuristics“ enthalten (zusammen mit simplifier, ” quantifier closing, module specific). Kann immer verwendet werden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 210 / 318 Fallunterscheidungs-Heuristiken • conditional right split: wendet if right an • conditional left split: wendet if left an • dl case distinction: Fallunterscheidung (conjunction right etc.), aber nur für Programmformeln Im Heuristik-Satz DL Heuristics + Case Splitting“ enthalten. Sollte man ” verwenden, wenn Beweisstruktur der Kontrollstruktur der Programme folgt (meist der Fall). Heuristik-Satz DL heuristics + Induction“ enthält zusätzlich Heuristiken ” für (noethersche) Induktion (induction, apply ind once). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 211 / 318 Heuristiken für Prozeduraufrufe • calls nonrecursive: Führt alle nichtrekursiven Aufrufe aus • calls concrete: Führt alle Aufrufe aus, die konkrete Parameter haben, i. e. Terme die höchstens Parametervariablen enthalten • weak unfold: • Führt rekursive Prozeduren einmal aus, wenn sie in der Induktionshypothese vorkommen. Höher in der Aufrufshierarchie liegende Aufrufe bevorzugt. • Weitere Aufrufe werden ausgeführt, wenn festgestellt wird, dass deren Tests so ausgehen, dass kein weiterer rekursiver Aufruf auftritt. • unfold: Führt zusätzlich rekursive Prozeduren (einmal) aus, bei denen der rekursive Aufruf schon in der Sequenz vorkommt DL Heuristics“ enthält weak unfold, DL Heuristics + Induction“ enthält ” ” zusätzlich unfold. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 212 / 318 Nichtdeterministische Programme 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 213 / 318 Nichtdet. Programme: Syntax KIV kennt noch zwei Programmkonstrukte für nichtdeterministische Programme: • α or β: Wählt nichtdeterministisch eines der beiden Programme • choose x with ϕ in α ifnone β • Bindet lokale Variablen x (wie let) an irgendwelche Werte, die ϕ erfüllen • ϕ darf von anderen Programmvariablen als nur x abhängen • Führt mit den lokalen Variablen α aus. • Falls überhaupt keine passenden Werte für x existieren, die ϕ erfüllen, wird β (ohne lokale Variablen) ausgeführt. • ifnone abort kann weggelassen werden (default). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 214 / 318 Beispiele für choose Beispiele: • choose n with true in α: Rät beliebige natürliche Zahl • choose n with n < m in α ifnone β: Wählt natürliche Zahl n, die kleiner m ist, und führt α aus. Wenn m = 0 gilt, wird stattdessen β ausgeführt. • choose boolvar with true in if boolvar then α else β ist äquivalent zu α or β • if pre(x) choose y with post(x,y) in output := y else abort ist ein (das allgemeinste) Programm, das äquivalent zur totalen Korrektheitsaussage pre(x) → hαi post(x,y) ist. ⇒ Programm kann als Spezifikation eingesetzt werden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 215 / 318 Nichtdet. Programme: Semantik Semantik von or: [[α or β]] = [[α]] ∪ [[β]] Semantik von choose: [[choose x with ϕ in α ifnone β]] v (x) a a = {(v , wx ) | es gibt a mit A, vx |= ϕ und (vx , w ) ∈ [[α]]} a ∪ {(v , w ) | (v , w ) ∈ [[β]] und es gibt kein a mit A, vx |= ϕ} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 216 / 318 Ein Zusatzproblem für die Semantik Was ist die Semantik von skip? Was ist die Semantik von skip or abort? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 217 / 318 Ein Zusatzproblem für die Semantik Was ist die Semantik von skip? Was ist die Semantik von skip or abort? Antwort: Beide sind gleich: Identität auf allen Zuständen Verhalten sich die Programme unterschiedlich? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 217 / 318 Ein Zusatzproblem für die Semantik Was ist die Semantik von skip? Was ist die Semantik von skip or abort? Antwort: Beide sind gleich: Identität auf allen Zuständen Verhalten sich die Programme unterschiedlich? Antwort: Ja, skip terminiert garantiert, skip or abort nicht. Also: Die relationale Semantik kann nicht ausdrücken, dass ein nichtdeterministisches Programm garantiert terminiert. Damit kann es auch die dynamische Logik nicht: hskip or aborti true besagt, dass es einen terminierenden Ablauf gibt. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 217 / 318 Garantierte Terminierung Definiere die Teilmenge α ↓ ⊆ ST der Zustände (ST = Menge der Variablenbelegungen), für die α garantiert terminiert. Einige einfache Fälle (while und Rekursion sind schwierig) sind: • abort ↓ = ∅ • skip ↓ = ST • x := e ↓ = ST • (α ∨ β) ↓ = α ↓ ∩ β ↓ • {α; β} ↓ = {v | v ∈ α ↓ und für alle w mit (v , w ) ∈ [[α]] gilt: w ∈ β ↓} Beachte: Die Definition der garantierten Terminierung von compounds benutzt die relationale Semantik! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 218 / 318 Neuer Operator: strong diamond Wir addieren einen neuen Operator ( strong diamond“) zur Logik. ” h|α|i ϕ besagt: α terminiert garantiert, und in allen Endzuständen gilt ϕ Formal: A, v |= h|α|iψ :⇔ v ∈ α ↓ und für alle w : (v , w ) ∈ [[α]] gilt: A, w |= ψ. Bemerkung: Der Operator wurde von E.W. Dijkstra 1976 erfunden, und schreibt sich in der Literatur meist wp(α,ϕ) (von weakest ” precondition“). Der Kalkül heisst deshalb auch wp-Kalkül. Bemerkung: Die strong diamond-Klammern bekommt man mit F12 (KIV-Symbol) und dann { bzw. }. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 219 / 318 Kalkülregeln für or Das Gute an strong diamonds: Für deterministische Programme sind die Regeln für strong diamonds genau dieselben wie für diamonds. or right Γ ` hαi ψ, hβi ψ, ∆ Γ ` hα ∨ βi ψ, ∆ Γ ` [α] ψ, ∆ Γ ` [β] ψ, ∆ Γ ` [α ∨ β] ψ, ∆ Γ ` h|α|i ψ, ∆ Γ ` h|β|i ψ, ∆ Γ ` h|α ∨ β|i ψ, ∆ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 220 / 318 Kalkülregeln für choose choose right y y Γ ` ∃ y .ϕx ∧ hαx i ψ, (∀ x.¬ ϕ) ∧ hβi ψ, ∆ Γ ` hchoose x with ϕ in α ifnone βi ψ, ∆ y y ϕx , Γ ` [αx ] ψ, ∆ ∀ x.¬ ϕ, Γ ` [β] ψ, ∆ Γ ` [choose x with ϕ in α ifnone β] ψ, ∆ y y ϕx , Γ ` h|αx |i ψ, ∆ ∀ x.¬ ϕ, Γ ` h|β|i ψ, ∆ Γ ` h|choose x with ϕ in α ifnone β|i ψ, ∆ Die Variablen y sind neue Variablen (für die lokalen Versionen von x). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 221 / 318 Kontrakte und Abstrakte Datentypen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 222 / 318 Motivation Bisher: • Spezifikation von Datenstrukturen • Verifikation von Einzelprogrammen Ziel: Integration von formalen Methoden in die Entwicklung sicherheitskritischer Software mit höchsten Korrektheitsanforderungen Fragestellungen: • Wie kommt man zu Softwaresystemen? ⇒ formaler Begriff: Abstrakter Datentyp • Wie kommt man von einer abstrakten (Anforderungs-)Spezifikation über Design-Spezifikationen bis zu konkretem Code? ⇒ Refinement (entfällt dieses Jahr) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 223 / 318 Vor- und Nachbedingungen, Kontrakte Ein Kontrakt für eine Prozedur p (oder auch für eine Methode) besteht (mindestens) aus • einer Vorbedingung ϕ (präd.log. Formel) • einer Nachbedingung ψ (präd.log. Formel) • der Angabe der input-Parameter (incl. gelesene globale Variablen) • der Angabe der output-Parameter (incl. geschrieben globale Variablen). • Dazu kommt natürlich eine informelle Beschreibung: U.a. Name und Zweck der Operation, Querverweise zu Use Cases, etc. Bemerkung: Für KIV-Prozeduren fehlen die globalen Variablen. Sie müssen als I/O-Parameter addiert werden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 224 / 318 Vor- und Nachbedingungen, Kontrakte Definition: Eine Methode mit Implementierung mit Rumpf α erfüllt einen Kontrakt, falls die Parameter korrekt gegeben und der Rumpf total korrekt bzgl. Vor- und Nachbedingung ist. Formal also muss gelten: • Im Hoare-Kalkül: ϕ hαi ψ • In Dynamischer Logik: ϕ → hαi ψ • für indet. Programme: ϕ → h|α|i ψ Bemerkung:(Vorbedingung in Kontrakten) Wenn die Vorbedingung nicht eingehalten wird, darf beliebiges passieren: Absturz, Exception, Nichtterminierung, reguläres Ergebnis, illegaler Speicher etc. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 225 / 318 Zwei Beispiekontrakte Beispiel 1 (Revertieren einer Liste): • Eingabe und Ausgabe: Liste x • Vorbedingung: x = y • Nachbedingung x = reverse(y) Beispiel 2 (Entfernen eines Element von einem Stack): • Eingabe: Stack st • Ausgabe: Modifizierter Stack st und Element a • Vorbedingung: st = st0 ∧ st 6= emptystack • Nachbedingung st = pop(st0 ) ∧ a = top(st0 ) y und st0 sind logische Variablen, die nur zur Spezifikation benötigt werden. Alles andere sind Programmvariablen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 226 / 318 Kontrakte für Java • Für Java oder C# sind die Argumente Eingabeparameter und das Ergebnis der einzige Ausgabeparameter. • Es gibt immer genau einen IO-Parameter: Den Speicher • Der Speicher wird gelesen/modifiziert“ ist nicht aussagekräftig ” • Deshalb: Genauere Angaben, welche Objekte/Assoziationen gelesen/geschrieben/erzeugt werden sind, in Vor- und Nachbedingung erforderlich! • Die Nachbedingung kann auch: Wirft für bestimmte Eingaben eine ” bestimmte Exception“ lauten. Sinnvollerweise teilt man die Nachbedingung deshalb in einen regulären und einen Exception-Teil. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 227 / 318 Abstrakte Datentypen Eine Grundidee zur mathematischen Beschreibung eines Softwaresystems ist die eines Automaten mit Zuständen und Abläufen. Es gibt dann: • Eine Menge möglicher Systemzustände (in Vorlesung SWT durch Klassendiagramm beschrieben). • Einen Anfangszustand (oder mehrere). • Eine Anzahl Systemoperationen (Vorlesung SWT!). Die Operationen bekommen Eingaben, modifizieren den Systemzustand und produzieren Ausgaben. Dadurch entstehen Abläufe. Für die Modellierung verwenden wir: • Belegungen von Variablen mit algebraisch spezifizierten Datenstrukturen zur Beschreibung von Zuständen • Kontrakte zur Beschreibung der Systemoperationen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 228 / 318 Abstrakte Datentypen Ein Abstrakter Datentyp DT = (S, INIT, {OPi }i∈I ) besteht aus • Einer Zustandsmenge S. Typischerweise besteht S aus der Belegung eines Vektors von Variablen mit algebraisch spezifizierten Datentypen. • Einer Menge von Initialzuständen INIT ⊆ S. • Einer Menge (für i ∈ I) von (relational definierten) Kontrakten: OPi ⊆ INi × S × S × OUTi • Die Kontrakte werden auch Operationen genannt. • Jede Operation • hat Eingaben aus INi (kann für einzelne Operationen wegfallen) • modifiziert den Zustand S • hat eine Eingabe aus OUTi (kann für einzelne Operationen wegfallen) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 229 / 318 Beispiele: Objekte/Klassen Ein Java-Objekt kann als Datentyp aufgefasst werden: • S ist die Menge der möglichen Belegungen der Felder • INIT sind die Ergebnisse der Konstruktoren • OPi sind Kontrakte für die Methoden des Objekts • Die Felder des Objekts sind private (nur über die Methoden zugänglich) Eine Java-Klasse kann als Datentyp aufgefasst werden: • S ist die Menge der möglichen Objektmengen einer Klasse • INIT (einelementig) ist das Ergebnis der statischen Initialisierung • OPi sind Kontrakte für die Methoden der Klasse 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 230 / 318 Beispiel: Softwaresysteme Auch ein ganzes Softwaresystem kann als Datentyp aufgefasst werden (siehe Softwaretechnik!) • S ist die Menge der Systemzustände (z.Bsp. die Menge der möglichen Instanzen eines Konzeptmodells) • INIT sind Initialzustände • OPi sind Kontrakte für die Systemoperationen 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 231 / 318 Programmieren in Scala 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 232 / 318 Motivation • Aus Sicht unseres Sotwaretechnik-Lehrstuhls: Scala ist eine der derzeit modernsten Programmiersprachen • KIV wird derzeit nach Scala portiert (fast fertig) • KIV ist dann mit Scala und Java (GUI) programmiert. • Scala unterstützt Konzepte die vieles mit den Konzepten der KIV-Spezifikationen gemeinsam haben. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 233 / 318 Was ist Scala? • Scala ist entwickelt an der Uni Lausanne von Prof. Odersky http://www.scala-lang.org • Viele Dokus (Tutotial, etc.) kann man dort finden • Eclipse-IDE: //http://www.scala-ide.org • Scala ist eine objektorientierte Sprache • Alle Konzepte von Java (Methoden, Klassen, Vererbung etc.) gibt es (z.T. in verbesserter Form) auch in Scala • Scala wird in ByteCode der JVM compiliert • Scala unterstützt auch die Konzepte aus funktionalen Sprachen (Higher-Order Funktionen Pattern Matching etc.) • Die Syntax von Scala ist etwas anders, und deutlich verbessert 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 234 / 318 Scala: Typen • Scala kennt wie Java Klassen und generische Klassen • Oberster Typ ist Any statt Object • Scala kennt keine primitiven Typen: • statt int und Integer gibt es nur Int • analog: bool, Boolean ⇒ Boolean, array, Array ⇒ Array • generische Typen werden mit eckigen Klammern geschrieben: Array[Int] statt Array<Int> • Array-Zugriff mit runden Klammern a(i) (statt a[i]) • Fest vordefiniert sind Tupel mit (für 3-Tupel) Typ (A,B,C). Sie werden auch als (a,b,c) konstruiert. Die Felder werden z.B. mit (a,b,c). 2 selektiert (liefert b) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 235 / 318 Scala: Methodendefinition • Scala kennt wie Java statische und dynamische Methoden • Java: type method(argty1 arg1, argty2 arg2, ...){ body } • Scala: def method(arg1:argty1,arg2:argty, ...):type = { body } • Der Typ void heisst Unit in Scala • Methoden ohne Resultat können vereinfacht als def method(arg1:argty1, ... ) { body } geschrieben werden (kein Typ und kein Gleichheitszeichen) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 236 / 318 Scala: Methodenaufruf • Aufruf wie in Java für statische und dynamische Methoden type . smethod (arg1, arg2, . . . ) object . dmethod (arg1, arg2, . . . ) • Bei Methoden ohne Argumente dürfen Leerklammern weggelassen werden (auch schon bei der Definition) • Konvention: Leerklammern weglassen gdw. keine Seiteneffekte: z.B. Selektoren (“getter”) und Tests: list.length, list.isEmpty • Vorteil: Feldzugriff kann lokal auf get-Methode (gleichen Namens) geändert werden (keine Änderung in anderen Klassen!) • Dynamischen Methoden mit einem Argument darf man mit object method arg aufrufen (Infix: weder Punkt noch Klammern!) • Vorteil: +, * etc. haben keine Sonderrolle mehr (sie können auch überladen werden). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 237 / 318 Ausprobieren von Scala • Scala kann man wie Java compilieren und ein Programm main(arglist:Array[String]):Unit in einem object ausführen. • Scala kann aber auch mit einem Kommandozeileninterpreter (entweder von innerhalb Eclipse oder standalone) bedienen • Aufruf von scala gibt scala>-prompt • Eintippen von Ausdrücken wertet diese aus scala> "Hello scala> 7 scala> 2 scala> 6 "Hello" + " World!" World!" 3 + 4 new Array(4,5).length new Array(5,6)(1) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 238 / 318 Scala: Felder und lokale Variablen • Scala unterscheidet bei Feldern und Variablen überschreibbare (var) und nicht überschreibbare (val; Java: final) • nicht überschreibare Felder/Variablen val x:Int = 5 • überschreibare Felder/Variablen var x:Int = 5 • Scala implementiert eine Typinferenz: Für die meisten Variablen und initialisierten Felder kann die Typangabe wegfallen. • Für das obige Beispiel: val x = 5 ist ok 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 239 / 318 Scala: Methodenrümpfe • Scala kennt keinen Unterschied zwischen Statement und Expression. • Statements sind einfach Expressions vom Typ Unit • Deshalb ist mischen erlaubt, z.B.: val x = if (y > 5) { val y = 3; y + 2} else 5 • Der ?-Operator von Java ist in Scala überflüssig • In Scala werden Strichpunkte nur benötigt, wenn zwei Statements auf derselben Zeile stehen (sehr selten) • Zeilenumbruch fügt (wo sinnvoll) implizit einen Strichpunkt ein • Wenn return expr das letzte Statement einer Methode ist, darf nur expr geschrieben werden. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 240 / 318 Scala: Beispele für Methoden • Fakultätsfunktion: def fac(x:Int):Int = {if (x == 0) 0 else fac(x - 1)} • Länge (wie in Listenklasse vordefiniert): def length:Int = {if (isEmpty) 0 else tail.length + 1} • Letztere Funktion würde in Java so aussehen: int length() {if (isEmpty) return 0; else return tail.length() + 1;} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 241 / 318 Scala: Klassendefinitionen (1) • Java Klassen enthalten sowohl statische als auch dynamische Methoden • Scala teilt die Methoden auf in dynamische in der Klasse und statische, die im sog. companion object gleichen Namens stehen • Beide müssen in dieselbe Datei, eines von beiden darf fehlen • Wenn nur object ⇒ Singleton. object A { def staticmethod(arg:Int):Int = { 2 * arg } } class A { val field = 5 def dynamicmethod(arg:Int):Int = { this.field + arg} } 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 242 / 318 Scala: Klassendefinitionen (2) • Java Klassen haben immer einen (häufig nutzlosen) nullstelligen Konstruktor • meist muss einer definiert werden, der einfach nur Felder initialisiert. • In Scala stattdessen: Felder, die im Konstruktor initialisiert werden sollen, als Argumente der Klasse. Kein nullstelliger Konstruktor. class A(val field1:Int, var field2:Int) {...} ergibt als möglichen Konstruktoraufruf new A(3,5). Ein nullstelliger Konstruktoraufruf ist nicht möglich. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 243 / 318 Scala: Abstrakte Datentypen (1) Scala unterstützt freie Datentypen analog zu KIV-Specs. Beispiel: arithmetische Ausdrücke. sealed abstract classed AExp case class Binop(val e1:AExp, val str:String, val e2:AExp) extends AExp case class Unop(val str:String, val e:AExp) extends AExp case class Val(val v:Int) extends AExp case class Var(val id:String) extends AExp erlaubt zu schreiben: Binop(Var("x"),"+",Unop("-",Val(4)))) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 244 / 318 Scala: Abstrakte Datentypen (2) • Ein abstrakter Datentyp besteht aus einer abstrakten (Summen-)Klasse (AExp) und einer Anzahl Unterklassen (Summanden; hier Binop, Unop, Val, Id) • Alle Klassen werden zusammen in die Datei AExp der Summenklasse geschrieben • sealed ⇒ keine (weiteren) Unterklassen in anderen Dateien • case class: erlaubt Konstruktoraufruf ohne Schlüsselwort new (und Pattern matching; siehe später) • Die Felder sind meist nicht schreibbar (val), sie werden nur vom Konstruktor initialisiert (“immutable” datatype; entspricht algebraischen Datentypen). • Gleichheit (i.e. ==) vergleicht case classes strukturell (nicht wie in Java auf Referenz-Gleichheit). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 245 / 318 Scala: Listen (1) Listen sind ein vordefinierter freier Datentyp sealed abstract class List[+A] case class ::[A](val head:A, tail:List[A]) extends List[A] case object Nil extends List[Nothing] erlaubt Konstruktion mit 1::2::Nil Bem: eigentlich ::(1,::(2::Nil)), aber “::” ist auch eine Infixfunktion auf Listen, die mit Doppelpunkt endet. Solche Infixfunktionen drehen die Argumentreihenfolge um! Alternativ: List(1,2) (durch Aufruf der statischen Methode List mit variabler Argumentzahl im companion object der Klasse List) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 246 / 318 Scala: Listen (2) • Listen erlauben kein Überschreiben des head oder tail. • Listen sind kovariant (das bedeuet das + vor dem Typparameter): jedes x:List[Int] ist auch ein x:List[Any] jedes x:List[Binop] ist auch ein x:List[AExp] • allgemein x:List[type1] ist Subtyp von x:List[type2] falls type1 ein Subtyp (Unterklasse) von type2 ist. • Arrays sind dagegen nicht kovariant (weil modifizierbar) • Nothing ist der leere Typ ohne jedes Element (Subtyp von jedem Typ). Nil ist deshalb vom Typ List[type] für jeden Typ type • Listen haben viele vordefinierte Funktionen, u.a. ++ (append), x(i) (get für das i-te Element, 0-basiert); siehe scaladoc 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 247 / 318 Scala: Pattern Matching • Scala erlaubt Pattern Matching für ADTs • match verallgemeinert Java’s switch. • Methode allids (in Klasse AExp) sammelt alle vorkommenden Variablen des Ausdrucks • Funktion ++ hängt Listen aneinander. • Ein Underscore steht für wildcard (beliebig) def allids:List[String] = { this match { case Var(id) => List(id) case Binop(e1, ,e2) => e1.allids ++ e2.allids case Unop( ,e0) => allids(e0) case Val( ) => Nil } } Binop(Var(”x”),”+”,Val(4)).allids ergibt List(”x”) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 248 / 318 Scala: Higher-Order Funktionen • Scala erlaubt Higher-Order Functions, i.e. Funktionen, die Funktionen als Argumente bekommen. • Funktionstypen werden A => B geschrieben. • Beispiel: Funktion map (in Klasse List[A] definiert) wendet eine Funktion f auf alle Listenelemente an def map[B](f:A => B):List[B] = { this match { Nil => Nil x :: xs => f(x) :: xs.map(f) }} oder alternativ: def map[B](f:A => B):List[B] = { if (isEmpty) Nil else f(head) :: tail.map(f) } 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 249 / 318 Scala: lambda-Abstraktionen • Das Funktionsargument von map kann eine Funktion sein, die mit def definiert wurde • Da die Funktion meist nur einmal verwendet wird, gibt es auch die Möglichkeit, sie als lambda-Abstraktion anzugeben • x:Int => x + 1 ist die Funktion, die eins addiert • (x:Int,y:Int) => x + y ist die Additionsfunktion • Verwendung z.B mit map: List(1,2,3).map((x:Int) => 2 * x) ergibt List(2,4,6) • Kurzschreibweise: e(_) statt (x:Int => e(x)) (manchmal ist Typangabe notwendig: e(_:Int) • Beispiel: List((1,2),(4,5)).map(_._1) == List(1,4) (mit Selektor . 1 für Paare) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 250 / 318 Scala: Datentyp Map • Eine Map bildet endlich viele Schlüssel (keys) auf Werte (values) ab. • Analog zu Liste von Paaren, aber keine doppelten Schlüssel • Paare kann man sowohl mit (a,b) als auch mit a -> b konstruieren. • Konstruktion aus Paaren mit Map("x" -> 3, "y" -> 4) • Das letzte zählt: Map("x" -> 3, "x" -> 4) == Map("x" -> 4) • Zugriff über Map("x" -> 3, "y" -> 4)("x") ergibt 3 • Addieren: Map("x" -> 3) + ("y" -> 4) ergibt Map("x" -> 3, "y" -> 4)("x") • Löschen mit Map("x" -> 3, "y" -> 4) - "x" gibt Map("y" -> 4) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 251 / 318 Scala: viele weitere Features Scala hat noch viele andere Features, auf die wir hier nicht eingehen: • lazy Funktionen und Felder • interfaces erweitert scala zu traits. Diese dürfen auch Code definieren. • implizite Argumente • selbstdefiniertes Pattern Matching • erweiterte generische Syntax für Schleifen • ... 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 252 / 318 KIV-Beweise in Scala 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 253 / 318 Scala und KIV • Im zweiten Scala-Versuch wollen wir “Beweise programmieren”. • Zunächst einen Aussagenlogik-Beweiser, • dann einen für partielle Korrektheit. • Für die Programmierung brauchen wir Teile des aktuellen KIV-Codes. • Der KIV-Code ist recht gross (300KLoC) und hat sicher noch Bugs. • Ihr müsst davon aber nur wenige Teile kennen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 254 / 318 Wiederholung: Syntax von Ausdrücken Ausdrücke e ∈ EXPR s (Σ, X ) der Sorte s ∈ S über der Signatur Σ und über den Variablen X sind rekursiv definiert durch • x aus Xs ist ein Ausdruck der Sorte s • Sind e1 , . . . , en Ausdrücke der Sorten s1 , . . . , sn und op : s1 , . . . , sn → s 0 , dann ist op(e1 , . . . , en ) ein Ausdruck der Sorte s 0 • Bem.: Schreibe c statt c() für Konstanten (n = 0) • Sind e1 , e2 Ausdrücke der Sorte s, so ist e1 = e2 eine Formel (i. e. ein Ausdruck der Sorte bool) • Ist ϕ eine Formel und x eine Variable, so sind ∀ x.ϕ und ∃ x.ϕ Formeln EXPR(Σ, X ) := S s∈S EXPR s (Σ, X ), For (Σ, X ) := EXPR bool (Σ, X ) Terme t ∈ T (Σ, X ) sind Ausdrücke ohne Quantoren und Gleichheit. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 255 / 318 Scala und KIV: Ausdrücke Expressions sind ein freier Datentyp (hier leicht vereinfacht): package types sealed abstract class Expr // Operation case class Op(val name:String, val typ:Type) extends Expr // Variable case class Xov(val name:String, val sort:Type) extends Expr // Applikation case class Ap(val fct:Expr, val termlist:List[Expr]) extends Expr //Allquantor case class All(val vl:List[Xov], val fma:Expr) extends Expr //Existenzquantor case class Ex(val vl:List[Xov], val fma:Expr) extends Expr ... 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 256 / 318 Scala und KIV: Parsen • Die “rohen” Konstuktoren All, Ap etc. machen keinen Typcheck • Konstruktoren mit Typcheck sind mkap, mkall etc. • Formeleingabe als z.B. mkall(List(x),Op(”true”,. . . )) möglich • In der Praxis nicht gemacht. Stattdessen Aufruf des Parsers ⇒ Eingabe wie in KIV • parser.scalaparse.parse expr(”∀ x. true”) (wie in KIV) parse seq(arg:String):Seq (Sequenzen), parse spec(arg:String):Spec (Spezifikationen) • Um Ausdrücke und Sequenzen korrekt zu parsen (Mixfix-Notation!), muss KIV eine Spezifikation “kennen”: Das geht mit setcurrentspecsig(sp:Spec):Unit setcurrentspeclistsig(spl:List[Spec]):Unit 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 257 / 318 Scala und KIV: Pretty-Printing • Die “rohe” Ausgabe von Formeln ist nur für Debugging relevant • Normalerweise Ausgabe mit pretty-printer: printer.prettyprint.xpp(arg:Any):String mit Sonderzeichen printer.prettyprint.pp(arg:Any):String ASCII-Ausgabe • Funktioniert für beliebiges Argument arg:Spec, arg:Expr, etc. • Für Beweisbäume (gleich) ist das Ergebnis nur ”** A TREE **”. Es wird zusätzlich ein Baumfenster (wie in KIV) geöffnet. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 258 / 318 Scala und KIV: Sequenzen und Bäume Sequenzen und Beweisbäume sind ebenfalls ein Datentyp: package types sealed abstract class Tree case class Seq(ant:List[Expr], suc:List[Expr]) extends Tree case class Vtree(concl:Seq, subtr:List[Tree]) extends Tree Regelbäume lassen sich graphisch (wie in KIV) anzeigen: Entweder per pretty-printer oder direkt mit printtree.painttree.pp painttree(t:Tree):Unit. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 259 / 318 Scala und KIV: Aussagenlogische Regeln • Es ist in KIV nicht erlaubt, beliebig Bäume zusammenzubauen • Stattdessen: Es gibt vordefinierte Regelbäume für Aussagenlogik: system.basicrules.con r ist der Regelbaum für conjunction right • Analog: dis r, equiv l, neg l, imp r, ax etc. • Allerdings: Passen nur auf die erste Formel rechts/links (der Antezedent ist eine Liste von Formeln, keine Menge) • Deshalb zusätzlich: leftrotate left, leftrotate right bzw. righttrotate left, righttrotate right zum Rotieren im ant bzw. suc. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 260 / 318 Scala und KIV: Aufbau von Bäumen Beispielregel: $Γ ` $ϕ, $∆ $Γ ` $ψ, $∆ con r $Γ ` $ϕ ∧ $ψ, $∆ • Regelbäume enthalten Metavariablen wie $ϕ, $ψ und $Γ, $∆ als Platzhalter für Formeln bzw. Formellisten. • Metavariablen kommen in normalen Beweisen nicht vor. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 261 / 318 Scala und KIV: Aufbau von Bäumen • Gegeben ein bestehender Baum (am Anfang: eine Sequenz) so lassen sich Instanzen von Regeln “anbauen”. • refine(tree:Tree,i:Int,rule:Tree):Tree wendet die Regel rule auf die i-te Prämisse P (1-basiert) des Baums tree an. • Bei der Anwendung werden in ganz R die Metavariablen so durch die konkreten Formeln aus der Regel instanziert (ergibt I(rule)), so dass die Konklusion C der Regel zu P = I(C) wird. rule I(rule) C P P tree tree G G 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 262 / 318 Scala und KIV: Failures (1) • refine wirft Error, falls der Baum nicht genug Prämissen hat, Test mit i > tree.premno. • generated.treefuns.prem(tree,i) und generated.treefuns.prems(tree) ergeben die i-te Prämisse bzw. alle Prämissen eines tree (1-basiert) des Baums tree • Eine Regel kann nicht anwendbar sein ⇒ die Regelanwendung schlägt fehl = refine wirft die Standardexception Failure. • Für con r. Wenn Sukzedent leer, oder erste Formel keine Konjunktion, schlägt refine fehl. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 263 / 318 Scala und KIV: Failures (2) • “Fehlschläge” sind ein Prinzip beim Beweisen: Regeln, Heuristiken, Simplifierregeln können alle fehlschlagen. • spezielle Unterstützung: orl(scalaexpr1,scalaexpr2) • wertet zunächst scalaexpr1 aus (z.B. ein refine). • Falls das nicht fehlschlägt ist das auch das Ergebnis. • Nur falls es fehlschlägt, wird auch scalaexpr2 ausgewertet und liefert das Ergebnis • Gewolltes Fehlschlagen durch Aufruf von fail: (i.e. def fail = throw Failure) • Bem: orl ist in scala als lazy Funktion realisiert. Erspart es überall zu Schreiben: try {scalaexpr1} catch {x:Failure => scalaexpr2} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 264 / 318 Scala und KIV: Generisches Matching • Zu refine gibt es die Verallgmeinerung: mvmatch[S,T](pattern:T, concrete:T, toinst:S):S • Stellt fest, ob die Metavariablen in pattern so instanziert werden können, dass concrete herauskommt. (ob pattern auf concrete “matcht”) • Falls das nicht fehlschlägt, werden die Metavariablen in toinst instanziert, und die Instanz ist das Ergebnis. • Variante: mvmatchp(pattern:T, concrete:T):Boolean macht einen Test, ob pattern auf concrete matcht. • Nützliche Anwendung im Praktikumsversuch: val whilepat = parse seq(”$Γ ` [while $ε do $α]$ϕ”) mvmatch(whilepat, seq, parse prog(”$α)) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 265 / 318 Programmierung eines VCG • Für’s Praktikum wollen wir einen VCG (“Verification Condition Generator”) für partielle Korrektheit programmieren • Ein VCG reduziert Korrektheitsaussagen für Programme auf prädikatenlogische Goals (automatisch, wenn Invarianten gegeben sind). • Es zeigt sich: Die Programmierung ist analog zum Aussagenlogischen Beweiser 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 266 / 318 Regeln für Hoare-Kalkül • Die DL-Regeln für den Hoare-Kalkül sind analog zu den aussagenlogischen Regeln implementiert • Sie enthalten Metavariablen für Programme $α,$β • 2 Beispiele (vollständige Listen in der Praktikumsdoku): $Γ ` $ϕ skip rule $Γ ` [skip]$ϕ $Γ, ¬$ε ` [$β] | $ϕ $Γ, $ε ` [$α]$ϕ if forward rule $Γ ` [if $ε then $α else $β]$ϕ • Es gibt kein Normalisieren wie in KIV: Die Regel compound rule muss selbst angewandt werden 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 267 / 318 Spezielle Regeln: besondere Regeln für den Versuch: • while rule(inv:Expr):Tree liefert die while-Regel mit eingefüllter konkreter Invariante INV $Γ ` Inv Inv, $ε ` [$α]Inv Inv, ¬$ε ` $ϕ (while rule Inv) $Γ ` [while $ε do $α]$ϕ • • prakt assign tactic(tree:Tree,i:Int):Tree wendet die Zuweisungsregel mit passender Substitution auf die i-te Prämisse an (x0 neue Variable). x0 = $τ, $Γ ` ($ϕ)x0 $x $Γ ` [$x := $τ ]$ϕ 8. Juli 2013 prakt assign tactic) G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 268 / 318 Temporallogik und parallele Programme 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 269 / 318 Softwaresysteme allgemein (1) Bisher: • Sequentielle Programme • Relationale Semantik: Anfangs- und Endzustand • Spezifikation: Vor- und Nachbedingung • Programm ist Algorithmus der ein Ergebnis berechnet“ ” Zweck: Spezifikation von Systemoperationen Grundannahme: Die Operationen sind atomar, i. e. nicht unterbrechbar, zeitliche Dauer ist vernachlässigbar (Meist) adäquat bei sequentiellen Programmen und für einzelne Systemoperationen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 270 / 318 Softwaresysteme allgemein (2) Die Sicht als atomare Operation ist nicht adäquat für • Abläufe von Softwaresystemen, die eine Reihe von System- operationen aufrufen (vgl. Szenarios in Use Cases) • eingebettete Systeme, die eine Umgebung haben (Benutzer, die Eingaben machen; Sensoren/Aktoren) • Programme, die nicht terminieren sollen (Betriebssysteme, Protokolle, Web-Server etc.) • Einzelne Threads, die parallel zu anderen laufen (gegenseitige Beeinflussung) Für all diese Systeme müssen Abläufe von Programmen betrachtet werden, die in einer Umgebung stattfinden. Ziel der Vorlesung: Definition einer dazu passenden Logik. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 271 / 318 Motivation - Beispielprogram semaphore semaphore ≡ while true do await S > 0; S := S − 1; while true do await S > 0; S := S − 1; (: critical section :) (: critical section :) L1 : skip; S := S + 1; L2 : skip; S := S + 1; (: noncritical section :) (: noncritical section :) skip; skip; Eigenschaften: • Sicherheit (engl. safety): Zu keinem Zeitpunkt sind beide Prozesse gleichzeitig im kritischen Bereich • Lebendigkeit/Fortschritt (engl. liveness/progress): Ein Prozess betritt irgendwann seinen kritischen Bereich 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 272 / 318 Parallele Programme: Interleaving Die Wahl der Programmiersprache trifft 3 zentrale Entscheidungen: Programme werden interleaved parallel ausgeführt und kommunizieren über gemeinsame (engl. shared) Variablen. Zuweisungen sind atomar. f Ausführung von x:= x + 1 x := x ∗ 2; x:= x ∗ 2 mit x = 0 gestartet dauert 3 Schritte und ergibt • x = 4 (linker Schritt zuerst) oder • x = 2 (erster Schritt rechts, dann links, dann rechts), oder • x = 1 (beide Schritte rechts zuerst). Alternativen: asynchron/synchron parallel (verschiedene Rechner bzw. getaktete Hardware). Kommunikation durch Synchronisation (message passing). Feinere Atomizität (z.B. Lade/Speichere Referenz in Java!). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 273 / 318 Traces (Intervalle) Ziel: Kalkül, der die Untersuchung verteilter Systeme ermöglicht 1 Abläufe definieren (Traces) 2 Formeln reden über alle Zwischenzustände eines Programms (irgendwann, immer, solange . . . bis etc.) 3 Semantik für Programme, die alle Zwischenzustände berücksichtigt Grundlegende Definition Ein Trace ist eine Zustandsfolge (z0 , . . . , zn ) mit n ∈ IN ∪ {∞} • Die Semantik von Programmen ist eine Menge möglicher Traces • Formeln sind wahr oder falsch auf einem Trace • Zustand zi im Trace = Variablenbelegung (wie bisher) • Wenn endliche Traces erlaubt sind, heißen sie auch Intervalle 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 274 / 318 Temporallogik vs. Relationale Semantik TL-Semantik von Programmen α: Einer oder mehrere Traces. Die relationale Semantik ist gröber“ und daraus herleitbar: ” Deterministische Programme: • Nur ein möglicher Trace (z0 , . . . , zn ) für einen Startzustand z0 • Wenn endlich (z0 , zn ) ∈ [[α]] • Wenn unendlich, dann kein Paar (z0 , z) in [[α]] Nichtdeterministische Programme: • Evtl. mehrere mögliche Traces (z0 , . . . , zn ) für einen Startzustand z0 • Jeder endliche liefert (z0 , zn ) ∈ [[α]] • Ein unendlicher Ablauf vorhanden gdw. z0 6∈ α ↓ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 275 / 318 Intervalle mit Umgebungsschritten Wir betrachten Programme mit einer Umgebung • Z. B. die physikalische Umgebung des Programms • Bei zwei interleaveten Programmen läuft das eine Programm in der Umgebung des anderen • Ziel (nächste Vorlesung): lokale Verifikation eines Threads (engl. thread-local reasoning) • Beachte: Die bisherigen sequentiellen Programme werden jetzt innerhalb einer Umgebung betrachtet • In einem Ablauf (z0 , z00 , z1 , z01 . . . , zn ) wechseln sich ab • Systemschritte (z0 , z00 ), (z1 , z01 ), . . . des Programms • Umgebungsschritte (z00 , z1 ) , (z01 , z2 ), . . . • Der erste Schritt eines Traces ist ein Systemschritt • Falls endlich, ist der letzte Schritt ein Umgebungsschritt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 276 / 318 Semantik temporallogischer Formeln • Temporallogische Formeln sind über einem Ablauf wahr oder falsch: A, (z0 , z00 , z1 , . . . , zn ) |= ϕ • A ist die zugrundeliegenden Algebra (Datenstruktur), die Modell der Spezifikation ist (im folgenden weggelassen). • Normale prädikatenlogische Aussagen ϕ sind temporallogische Formeln. Sie beziehen sich nur auf den Anfangszustand: (z0 , z00 , z1 , . . . , zn ) |= ϕ ⇔ z0 |= ϕ • Über zukünftige Zustände redet man mit temporallogischen Operatoren oder mit Variablen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 277 / 318 Variablen in Temporallogik • Statische Variablen haben immer denselben Wert im Ablauf. (Konvention in KIV: Mit Kleinbuchstaben) • Flexible Variablen ändern ihren Wert: X, X0 , X00 bezeichnen die Werte in z0 , z00 , z1 (Konvention in KIV: Großbuchstaben) • Konvention: Falls der Ablauf nur aus einem Zustand besteht, haben X0 und X00 auch den Wert von X in z0 . • Definition variables X : nat flexible; • Die Formeln X = X0 und X0 = X00 besagen: Der erste System- bzw. Umgebungsschritt ändert X nicht • Zuweisung X := T macht einen Systemschritt und impliziert X0 = T 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 278 / 318 Temporallogische Formeln: Always und Eventually Informelle Beschreibung: 2 ϕ d. h. ϕ gilt jetzt und in jedem künftigen Zustand (always). 3 ϕ d. h. ϕ gilt jetzt oder in einem künftigen Zustand (eventually). Formale Beschreibung (es gilt: 3 ϕ ↔ ¬ 2 ¬ ϕ): (z0 , z00 , z1 . . . , zn ) |= 2 ϕ ⇔ Für alle 0 ≤ i ≤ n gilt: (zi , . . . , zn ) |= ϕ (z0 , z00 , z1 , . . . , zn ) |= 3 ϕ ⇔ Es gibt ein 0 ≤ i ≤ n mit (zi , . . . , zn ) |= ϕ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 279 / 318 Temporallogische Formeln: Beispiele • 2 safe ≡ System verlässt nie sichere Zustände.“ ” • 2 X0 = X00 ≡ Die Umgebung modifiziert X nie.“ ” • 2 X0 ≥ X ≡ Das System erniedrigt X nie.“ ” • 2 (X = 5 ∧ X0 = 5) ≡ X ist 5 vor und nach jedem Systemschritt“ ” • 3 Result ≡ System erzielt irgendwann ein Ergebnis.“ ” • 2 3 Input ≡ System erhält immer wieder Eingaben.“ ” • 2 (Input → 3 Output) ≡ Jede (irgendwann anliegende) Eingabe ” führt auch zu einer Ausgabe.“ • 2 (X = 5 → 3 X > 5) ≡ Wann immer X den Wert 5 hat, wird es ” irgendwann später noch erhöht“ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 280 / 318 Temporallogische Formeln: Until und Unless Informelle Beschreibung: ϕ until ψ d. h. ψ gilt irgendwann, und davor gilt stets ϕ. ϕ unless ψ d. h. ϕ gilt immer, bis ψ gilt. Formale Beschreibung: (z0 , z00 , . . . , zn ) |= ϕ until ψ ⇔ Es gibt ein 0 ≤ i ≤ n mit: (zi , . . . , zn ) |= ψ ∧ ∀ 0 ≤ j < i.(zj , . . . , zn ) |= ϕ (z0 , z00 , . . . , zn ) |= ϕ unless ψ ⇔ (2 ϕ) ∨ (ϕ until ψ) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 281 / 318 Temporallogische Formeln: Beispiele • X = X0 until unlocked ≡ System verändert X nicht, bis irgendwann ” ist sicher bis irgendwann das Lock freigegeben wird“. • N = N00 + 1 until N = 0 ≡ N wird bis auf 0 heruntergezählt“ ” • Y00 = Y0 unless X0 6= X ≡ Die Umgebung ändert Y solange nicht, ” wie das System X nicht modifiziert“ • Solange sich alle vorherigen Umgebungsschritte ” an R (rely) gehalten haben, hält sich der nächste Systemschritt an G (guarantee).“ • G(X,X0 ) unless (G(X,X0 ) ∧ ¬ R(X0 ,X00 )) • ¬ (R(X0 ,X00 ) until ¬ G(X,X0 )) (unless lässt sich mit until ausdrücken und umgekehrt). 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 282 / 318 Temporallogische Formeln: Strong und Weak Next Informelle Beschreibung: ◦ ϕ d. h. es gibt einen Folgezustand in dem ϕ gilt (strong next). • ϕ d. h. wenn ein Folgezustand existiert, gilt darin ϕ (weak next). last d. h. der aktuelle Zustand ist der letzte. Formale Beschreibung: (z0 , z00 , . . . , zn ) |= ◦ ϕ ⇔ n 6= 0 ∧ (z1 , . . . , zn ) |= ϕ (z0 , z00 , . . . , zn ) |= • ϕ ⇔ n = 0 ∨ (z1 , . . . , zn ) |= ϕ (z0 , z00 , . . . , zn ) |= last ⇔ n = 0 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 283 / 318 Temporallogische Formeln: Beispiele • Eine einzelne Zuweisung impliziert ◦ last ≡ genau ein Schritt“ ” • 3 last ≡ endlicher Ablauf = Terminierung“ ” • 2 ¬ last ≡ keine Terminierung“ ” • 2 (Errorinput → 3 last) ≡ Fehlerhafte Eingabe führt zum ” Programmstop.“ • 3 (last ∧ Post) ≡ Terminierung und Nachbedingung am Ende“ ” • 2 (last → Post) ≡ Falls Terminierung dann am Ende Nachbedingung“ ” • (2 X0 = X00 ) → 3 last ≡ Wenn die Umgebung X nie modifiziert, ist Terminierung sicher.“ 8. Juli 2013 ” G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 284 / 318 Programme sind Formeln • Programme α beschreiben eine Menge möglicher Traces • Definiere (z0 , . . . , zn ) |= α als: Der Trace (z0 , . . . , zn ) ist ein möglicher Ablauf des Programms α. • Somit ist ein Programm wahr“ auf einem Trace, wenn der Trace ein ” möglicher Ablauf von α ist. • Ergebnis: Programme sind auch einfach spezielle Formeln! • Programme beschreiben nur Systemschritte in einer beliebigen Umgebung 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 285 / 318 Zuweisung als Formel • Temporallogische Zuweisungen nur für flexible Variablen • X := T impliziert X0 = T und ◦ last • Problem: Was ist mit den anderen Variablen? ⇒ Programmvariablen sollten unverändert bleiben • Deshalb: Programmvariablen (relevant für alle Zuweisungen im Programm) werden explizit durch Liste vl angegeben: [: vl | α] V 0 • Definition: unch(uvl) ≡ {X = X | X ∈ uvl} • Damit: [: vl | X := T] ↔ X0 = T ∧ unch(vl \ X ) ∧ ◦ last Beispiel: [: X, Y, Z | X := 1] ↔ X0 = 1 ∧ Y0 = Y ∧ Z0 = Z ∧ ◦ last 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 286 / 318 Typische TL Beweisziele Typisches Beweisziel: α, Pre, Env ` Prop Programm α gestartet im Zustand Pre ” hat in Umgebung Env die Eigenschaft Prop“ • α ist ein Programm (mit Variablen X ) • Pre(X) ist eine Startbedingung (Prädikatenlogik) • Env(X0 ,X00 ) ist eine Annahme an die Umgebung • Prop(X) ist eine zu zeigende Eigenschaft, z.B. • 3 last = α terminiert • 2 safe(x) = Alle erreichten Zustände sind sicher • 2 (last → post(x)) (Nachbed. für partielle Korr.) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 287 / 318 Beispiel: Beweisverpflichtung semaphore (: ParallelesProgramm :) [: S, L1 , L2 | semaphore] , (: Umgebungsannahme :) 2 (S 00 = S 0 ∧ L001 = L01 ∧ L002 = L02 ) (: Initialzustand :) S = 1, ¬ L1 , ¬ L2 ` (: Beweisverpflichtung :) 2 ¬ (L1 ∧ L2 ) Programm semaphore erlaubt es nie, dass beide Teilprogramme ” gleichzeitig im kritischen Abschnitt sind.“ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 288 / 318 Semantik Paralleler Programme Zuweisung: vl | X := t • X0 = t • Alle anderen Variablen in vl unverändert: unch(vl \ X ) • Transition nicht blockiert; terminiert nach einem Schritt No operation: vl | skip • Alle Variablen in vl unverändert: unch(vl) • Transition nicht blockiert; terminiert nach einem Schritt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 289 / 318 Semantik Paralleler Programme Sequentielle Komposition: vl | α; β • Erst Transitionen von vl | α • Wenn α terminiert, dann Transitionen von vl | β Konditional: vl | if ε then α else β • Auswertung von ε benötigt einen Schritt (if∗ ohne Schritt) • Falls ε gilt, dann Transitionen von vl | α, sonst von vl | β Schleife: vl | while ε do α • Auswertung von ε benötigt einen Schritt (while∗ ohne Schritt) • Solange ε gilt, Transitionen von vl | α, sonst Terminierung 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 290 / 318 Semantik Paralleler Programme Synchronisation: vl | await ε • Auswertung von ε dauert keinen Schritt • Sobald ε gilt, sofortige Terminierung (kein Schritt) • Typische Verwendung: await lock = free; lock := used Setzt das Lock im selben Schritt, in dem der Test gutgeht • Bis dahin: • Programm wartet, und gibt anderen parallelen Programmen Vorrang • Alle Variablen in vl unverändert: unch(vl) • Transition ist blockiert (Prädikat blocked) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 291 / 318 Semantik Paralleler Programme Interleaving: vl | α f β • Generell: nächste (nicht blockierte) Transition von α oder β • Falls beide Programme blockiert, dann Interleaving blockiert: Deadlock-Prädikat blocked ist wahr (und unch(vl)) • Beim Ausführen entstehen 2 Fälle: f • vl | α < β linke Komponente bevorzugt f • vl | α > β rechte Komponente bevorzugt • Wenn die Komponente blockiert ist, wird die andere versucht f • vl | α < b β links blockiert, deshalb doch rechts f • vl | α b > β rechts blockiert, deshalb doch links f f nicht bei α b > β (um ihn nicht doppelt zu betrachten) • Der Fall, dass beide blockiert sind, ist nur bei α < b β möglich, 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 292 / 318 Kalkül: Symbolische Ausführung in DL • Aktuelle Formel redet über ersten Zustand z0 • Ein (Programm)schritt wird ausgeführt. • Neue Formeln bezieht sich auf den nächsten Zustand z1 • Neue Variable(n) x0 für alten Zustand der zugewiesenen Variable x. • Nichtzugewiesene Variablen behalten ihren Wert (keine neue Variable) Γxx0 , x = τxx0 ` [α]ψ, ∆xx0 assign right Γ ` [x := τ ][α]ψ, ∆ Grundidee bei TL ist dieselbe: Führe Programme symbolisch aus! 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 293 / 318 Kalkül: Symbolische Ausführung in TL • Aktuelle Formel redet über Ablauf (z0 , z00 , z1 . . . , zn ) • Ein (Programm)schritt wird ausgeführt. • Restformel bezieht sich auf den restlichen Ablauf (z1 , . . . , zn ). • Für jede Variable X (auch nicht zugewiesene!) zwei neue statische Variablen x0 und x1 die die Werte alten Zustand z0 vor dem Programmschritt und z00 vor dem Umgebungsschritt merken. • Randfall: Der Ablauf ist zu Ende (n = 0) ,y0 Pre(x0 , y0 ), x1 = τXx0,Y , y1 = y0 , [: X, Y | α] ` ? Pre(X , Y ), [: X, Y | X := τ ; α] ` Env → Prop tl assign left Offene Frage: Was tun mit temporallogischen Formeln Env, Prop? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 294 / 318 Symbolische Ausführung: Randfall leerer Ablauf • Programm ist zu Ende, der Ablauf besteht nur aus z0 . • Als Formel ausgedrückt: last ist wahr. • Dann haben X, X0 , X00 alle denselben Wert. ⇒ alle durch neue statische Variable x0 ersetzen. • Temporalllogischen Formel vereinfachen sich zu PL: • • • • 2 ϕ, 3 ϕ, ψ until ϕ sind äquivalent zu ϕ last → (ψ unless ϕ ↔ ψ ∨ ϕ) last → (• ϕ ↔ true) last → (◦ ϕ ↔ false) • In jedem Fall entsteht eine prädikatenlogische Formel 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 295 / 318 Symbolische Ausführung: Nichtleerer Ablauf • Grundidee: Alle TL-Formeln können zerlegt werden in • Schritt-Formeln nur über den ersten Schritt (PL mit X , X 0 , X 00 ) • Next-Formeln = Aussagen über den Restablauf (führendes ◦ oder •) • Beispiel: 2 ϕ ↔ ϕ ∧ • 2 ϕ ϕ gilt immer gdw. ϕ gilt jetzt, und ” falls nächster Zustand ex., dann gilt ϕ ab diesem immer“ • Analog: 3 ϕ ↔ ϕ ∨ ◦ 2 ϕ ϕ until ψ ↔ ψ ∨ ϕ ∧ ◦ (ϕ until ψ) • Ein symbolischen Ausführungschritt für zerlegte Formeln • ersetzt X , X 0 , X 00 in Schritt-Formeln durch x0 , x1 , X • löscht das führende ◦ oder • in Next-Formeln 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 296 / 318 Symbolische Ausführung: Kalkülregeln • Zerlegung von TL-Formeln in Schritt- und Next-Formeln und vorwärts step geht immer, auch wenn man kein Programm hat ⇒ generische step-Regel im KIV-Kalkül • Sonst enthält der Kalkül Regeln analog zu DL: tl assign left, tl while left, tl if left, tl ipar left etc. • Die Regeln führen das Programm aus und machen (wo sinnvoll) einen step. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 297 / 318 Symbolische Ausführung: Beispiele Beispiele: • Umgebungsannahme enthält 2 X 0 = X 00 : ⇒ der erste Schritt erhält die Annahme x1 = X und der Rest des Ablaufs behält 2 X 0 = X 00 als Annahme • Zu zeigen ist: 2 X > 0 ⇒ der Anfangszustand x0 > 0 erfüllen, und für den Restablauf muss weiterhin 2 X > 0 gelten. • Es ist also wegen (Konjunktion rechts!) ein PL-Goal für den aktuellen Zustand + ein Goal für den Restablauf zu zeigen • Für 3 X > 0 hat man die Wahl: es reicht, x0 > 0 zu zeigen, man kann aber auch für den Restablauf 3 X > 0 zeigen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 298 / 318 Kalkül: VD Induktion (1) Wie bisher vorhanden: Noethersche Induktion. Jetzt zusätzlich VD Induction und apply VD Induction. • VD = Verification Diagram • Erlaubt Induktion für Beweisziele: ` 2 ϕ • Beweisidee durch Widerspruch: Wenn 2 ϕ falsch ist, gibt es einen ersten Zustand, in dem ϕ nicht gilt. • ¬ (2 ϕ) ↔ ∃ N.N = N 00 + 1 until ¬ ϕ • N wird solange heruntergezählt, bis erstmals ¬ ϕ gilt. • Jetzt geht Induktion über den Wert von N = die Zahl der Schritte • Regel VD Induction codiert dies in einen Schritt 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 299 / 318 Kalkül: VD Induktion (2) • VD induction verzögert“ die Erstellung einer Induktionshypothese: ” Es entsteht nur ein anonymes Prädikat Indhyp(N). • apply VD Induction erlaubt als Induktionshypothese jedes Beweisziel, das mit weniger als N Schritten erreicht wurde. • Dazu muss im Beweisbaum auf den Knoten, der als Induktionshypothese verwendet werden soll, geklickt werden. • Idee zur Verwendung: Sobald sich in einem Programm ein vorheriger Zustand wiederholt, Induktionshypothese anwenden • Der Zustand darf aus einem anderen Beweisast sein, er muss aber weniger steps ausgeführt haben (sonst ist er nicht noethersch kleiner) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 300 / 318 Kalkül: Induktion apply VD induction 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 301 / 318 Kalkül: Sequentialisierung • Häufig ergibt das Ausführen von interleaveten Programmen trotz • • • • • unterschiedlicher Reihenfolge zweimal dasselbe Goal f f Beispiel: x := 5; α y := 6; β ergibt 2 goals mit α β Regel insert proof lemma wendet einen Beweisknoten als Lemma in einem anderen Beweisast an. Anwendung durch Klicken auf das anzuwendende Lemma Spart die Definition eines separaten Lemmas Nur anwendbar bei Azyklizität! Regel insert proof lemma <proved in a different proof branch> V W Γ 0 ` ∆0 Γ, Γ0 → ∆0 ` ∆ Γ`∆ 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 302 / 318 Kalkül: Sequentialisierung Insert Proof Lemma 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 303 / 318 Demo (: Programm :) [: X | fwhile true do { X := 1 } { await X = 1; X := 0; }], (: Umgebung :) 2 X00 = X0 , (: Initialisierung :) X=0 (: Eigenschaft :) ` 2 X ≤ 1; 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 304 / 318 Modulare Spezifikation und Verifikation paralleler Programme mit Rely-Guarantee 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 305 / 318 Motivation • Ausführung paralleler Programme führt zu einem exponentiell großem Zustandsraum • Direkte Beweisstrategie durch explizite symbolische Ausführung aller möglichen Interleavings ineffizient. • Heuristiken zur automatischen Ausführung scheitern oftmals schon an einfachen Beispielen • Rely-Guarantee (RG) [Jones 1983]: Spezifiziere und verifiziere jeden Prozess zunächst einzeln ohne die Umgebung zu kennen. • Erst wenn mehrere Prozesse kombiniert werden, muss geprüft werden, dass sie verträglich sind. • Wenn sie verträglich sind, sollte die Korrektheit des Gesamtsystems folgen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 306 / 318 Grundidee: Rely-Guarantee (1) • Gegeben: ein Prozess/Thread mit sequentiellem Programm. • Vor- und Nachbedingung reichen nicht mehr • Umgebung des Prozesses hat maßgeblichen Einfluss auf dessen Ausführung • Um Nachbedingung zu erfüllen muss der Prozess Mindestannahmen (engl. rely, assumption) an das Verhalten seiner Umgebung treffen • Diese werden durch ein Prädikat R(S0 ,S00 ) gegeben • Die Rely R sollte reflexiv (0 Umgebungsschritte) und transitiv (mehrere Umgebungsschritte) sein. • Damit verifizierbar: Wenn Rely für alle Umgebungsschritte gilt, dann erreicht der Prozess sein Ziel (Nachbedingung). • Die Rely sollte so schwach wie möglich sein, so dass der Prozess später möglichst flexibel nutzbar ist. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 307 / 318 Grundidee: Rely-Guarantee (2) • Wenn Prozesse zu einem System kombiniert werden, hat jeder Prozess i eine Ri (S’,S”), auf die er sich verlässt. • Die anderen Prozesse müssen diese garantieren. • Deshalb von Anfang an: Jeder Prozess i definiert eine Prädikat Gi (S,S0 ) (engl. guarantee oder commitment), was er in seinen Schritten schlimmstenfalls tut. • Die Gi muss zusätzlich zur Nachbedingung gezeigt werden. • Für Prozesse, die nicht terminieren sollen, ist nur die Garantie wichtig (z.B. sicherer Zustand führt zu sicherem) • Prozess i und j sind verträglich (im wesentlichen), wenn Gi (s,s0 ) → Rj (s,s0 ) und Gj (s,s0 ) → Ri (s,s0 ) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 308 / 318 Rely-Guarantee: Spezifikation eines Prozesses • Jeder Prozess P# wird mit einem RG-Kontrakt spezifiziert: • (globale) Variablen X, die er modifiziert • Vorbedingung Pre(X) • Nachbedingung Post(X) • (reflexive, transitive) Annahme R(X0 ,X00 ) • Garantie G(X,X0 ) • Der RG-Kontrakt verallgemeint partielle Korrektheit: “Wenn der Prozess mit Pre gestartet wird, dann macht er nur G-Schritte, solange die Umgebung nur R-Schritte macht. Ausserdem gilt, wenn er terminiert Post” • In der Literatur oft {Pre, R} α {G, Post} • In KIV als Formel (analog zu DL): Pre ` [: X | R, G, true, α] Post • (statt true kann eine Invariante Inv geschrieben werden; auf den Folien in Zukunft weggelassen) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 309 / 318 Verifikation von RG-Kontrakten • Für RG-Aussagen gibt es direkte Kalküle (analog zu Hoare-Kalkül) die keine Temporallogik brauchen. • Einschränkung: mit RG lässt sich Fortschritt (Terminierung, oder Erreichen von Zwischenzielen) nicht ausdrücken • In KIV ist [: X | R, G, α] Post Abkürzung für TL-Formel. • Idee: Solange sich die bisherigen Umgebungsschritte an R ” gehalten haben, hält sich der nächste Systemschritt an G .“ ≡ ¬ (R(X0 ,X00 ) until ¬ G(X,X0 )) • Somit ist [: X | R,G,α] Post ≡ [: X | α] → ¬ (R(X0 ,X00 ) until ¬ (last ⊃ Post(X); G(X,X0 ))) • Es gelten damit auch analoge Regeln zum symbolischen Ausführen. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 310 / 318 Zuweisungsregel für RG tl assign left: ,y0 Pre(x0 , y0 ), x1 = τXx0,Y , y1 = y0 ` G(x0 ,y0 ,x1 ,y1 ) ,y0 Pre(x0 , y0 ), x1 = τXx0,Y , y1 = y0 , R(x1 ,y1 ,X,Y) ` [: X,Y| R,G,α]Post Pre(X,Y) ` [: X, Y | R,G,X := τ ;α]Post Komplizierter als im sequentiellen Fall: • Guarantee muss zusätzlich gezeigt werden (Prämisse 1) • zwischen den Schritten des Programms sind Rely-Schritte 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 311 / 318 Kombination von 2 Prozessen Gegeben 2 Prozesse mit: Pre1 ` [: X | R1 , G1 , P1 #(; X )] Post1 Pre2 ` [: X | R2 , G2 , P2 #(; X )] Post2 Zu lösen: Welche RG-Kontrakte erfüllt dann P1 # f P2 #? Schon klar: Die Kombination muss verträglich sein: G1 (s,s0 ) → R2 (s,s0 ) und G2 (s,s0 ) → R1 (s,s0 ) Welche R, G, Pre, Post fsind dann korrekt in Pre ` [: X | R, G, P1 # P2 #] Post? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 312 / 318 R + G für die Kombination von 2 Prozessen Welche Annahme ist für P1 # Was kann P1 # 8. Juli 2013 f f P2 # ok? P2 # maximal garantieren? G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 313 / 318 R + G für die Kombination von 2 Prozessen Welche Annahme ist für P1 # f P2 # ok? ⇒ Umgebung von beiden muss beide erfüllen: R → R1 ∧ R2 Was kann P1 # f P2 # maximal garantieren? ⇒ Alle Schritte sind G1 oder G2 Schritte: G1 ∨ G2 → G 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 313 / 318 Pre + Post für die Kombination von 2 Prozessen Welche Vorbedingung Pre ist ok? Kann Post := Post1 ∧ Post2 bewiesen werden? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 314 / 318 Pre + Post für die Kombination von 2 Prozessen Welche Vorbedingung Pre ist ok? • Notwendig: Pre(s) → Pre1 (s) ∧ Pre2 (s) • Reicht nicht: Pre1 (s) ∧ R1 (s,s0 ) → Pre1 (s0 ) und Pre2 (s) ∧ R2 (s,s0 ) → Pre2 (s0 ) müssen gelten (stabile Vorbedingungen) Kann Post := Post1 ∧ Post2 bewiesen werden? 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 314 / 318 Pre + Post für die Kombination von 2 Prozessen Welche Vorbedingung Pre ist ok? • Notwendig: Pre(s) → Pre1 (s) ∧ Pre2 (s) • Reicht nicht: Pre1 (s) ∧ R1 (s,s0 ) → Pre1 (s0 ) und Pre2 (s) ∧ R2 (s,s0 ) → Pre2 (s0 ) müssen gelten (stabile Vorbedingungen) Kann Post := Post1 ∧ Post2 bewiesen werden? • Ja aber wieder nur für stabile Nachbedingungen: Post1 (s) ∧ R1 (s,s0 ) → Post1 (s0 ) und Post2 (s) ∧ R2 (s,s0 ) → Post2 (s0 ) Alle 4 Stabilitätsbedingungen sind lokal für einen Prozess. Man prüft man am besten gleich bei dessen Spezifikation. 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 314 / 318 Theorem für parallele Komposition ` R1 (s, s) ` R1 (s, s0 ) ∧ R1 (s0 , s1 ) → R1 (s, s1 ) ` Pre1 (s) ∧ R1 (s, s0 ) → Pre1 (s0 ) ` Post1 (s) ∧ R1 (s, s0 ) → Post1 (s0 ) Pre1 ` [: X | R1 , G1 , P1 #(; X )] Post1 ` R2 (s, s) ` R2 (s, s0 ) ∧ R2 (s0 , s1 ) → R2 (s, s1 ) ` Pre2 (s) ∧ R2 (s, s0 ) → Pre2 (s0 ) ` Post2 (s) ∧ R2 (s, s0 ) → Post2 (s0 ) Pre2 ` [: X | R2 , G2 , P2 #(; X )] Post2 ` G1 (s, s0 ) → R2 (s, s0 ) ` G2 (s, s0 ) → R1 (s, s0 ) Pre1 ∧ Pre2 ` [: X1 | R1 ∧ R2 , G1 ∨ G2 , P1 #(; X )] (Post1 ∧ Post2 ) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 315 / 318 Beispiel: Parallele ggT-Berechnung {let Done = false, X = 0, Y = 0 in { while ¬ Done do { X := NP.1; Y := NP.2; if X > Y then NP.1 := X − Y ; f if X = Y then Done := true}}} {let Done = false, X = 0, Y = 0 in { while ¬ Done do { X := NP.2; Y := NP.1; if X > Y then NP.2 := X − Y ; if X = Y then Done := true}}} 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 316 / 318 Beispiel: gegebene Teile der Kontrakte • Eingabe ist ein Paar von Zahlen m,n, so dass NP = (m,n) • Selektion aus dem Paar mit NP.1 und NP.2 • Ausgabe ist auch NP; am Ende sollte NP.1 = NP.2 = gcd(m,n) sein. • Folgende Prädikate sind vordefiniert: • Pre1 (m,n)(NP) := NP.1 = m ∧ gcd(m,n) = gcd(NP.1, NP.2) • Pre2 (m,n)(NP) := NP.2 = n ∧ gcd(m,n) = gcd(NP.1, NP.2) • Post2 (m,n)(NP) := gcd(m,n) = NP.1 ∧ NP.1 = NP.2 • Schon definiert G1 := R2 und G2 := R1 (schwächstmöglich, so dass diese Kombination klappt) • Noch zu finden: R1 und R2 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 317 / 318 Vorgehen zum Finden der Relys • Beginne mit true als rely. • Verstärke so, dass Stabilität der Vor- und Nachbedingung gelten • Beweise alle prädikatenlogischen Beweisverpflichtungen • Erst dann beweise die beiden Beweisverpflichtungen für P1 und P2 (gehen beide gleich) 8. Juli 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 318 / 318