+ All Categories
Home > Documents > A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org...

A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org...

Date post: 30-Sep-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
269
A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨orgPf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software and Systems Engineering University of Augsburg
Transcript
Page 1: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

A Practical Course on KIV

Gidon Ernst Dominik Haneberg Jorg PfahlerWolfgang Reif Gerhard Schellhorn Kurt Stenzel

Bogdan Tofan

Institute for Software and Systems EngineeringUniversity of Augsburg

Page 2: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Contents

1 Getting Started 61.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2 Starting KIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.3 Logical Foundations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Predicate Logic Proofs in KIV 112.1 Editing and Loading Theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.1.1 Directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.1.2 Editing Theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.2 Syntax and Special Character Input . . . . . . . . . . . . . . . . . . . . . . . . . . 132.3 Proofs in KIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.4 Rule set for predicate logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2.4.1 all left . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.4.2 insert equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.4.3 insert lemma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2.5 Basic rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.5.1 Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.5.2 Propositional and equational rules . . . . . . . . . . . . . . . . . . . . . . . 202.5.3 Quantifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.5.4 Theory rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.6 Heuristics for basic rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.7 Exercise 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Simplification 283.1 General Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.2 Typical simplification steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.3 Syntactical form of simplifier rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 293.4 Input and use of simplifier rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4 Theory Proofs 324.1 Editing Theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324.2 Short Description of the Menu Commands . . . . . . . . . . . . . . . . . . . . . . . 334.3 Rules for Predicate Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

4.3.1 General Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344.3.2 Simplification Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354.3.3 Induction Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354.3.4 Quantifier Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364.3.5 Lemma Insertion Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364.3.6 Insert rewrite lemma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.4 Predefined Sets of Heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384.5 Description of the Heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394.6 Exercise 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

1

Page 3: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CONTENTS 2

4.7 Exercise 2, Part 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

5 Algebraic Specifications 475.1 Structured Algebraic Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . 475.2 The Specification Methodology in KIV . . . . . . . . . . . . . . . . . . . . . . . . . 535.3 Creating Specifications in KIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555.4 Exercise 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

6 Logische Datenstrukturen in PPL 606.1 Die Signatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606.2 Metavariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636.3 Formeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636.4 Sequenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646.5 Beweisbaume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

6.5.1 Selektoren fur Beweisbaume . . . . . . . . . . . . . . . . . . . . . . . . . . . 646.5.2 Anzeigen von Beweisbaumen . . . . . . . . . . . . . . . . . . . . . . . . . . 656.5.3 Operationen auf Beweisbaumen . . . . . . . . . . . . . . . . . . . . . . . . . 656.5.4 Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676.5.5 Beispiel fur die Verwendung von refine und infer . . . . . . . . . . . . . . . 68

7 Implementierung eines VCG 707.1 Einfuhrung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707.2 Theoretischer Unterbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

7.2.1 Wichtige Eigenschaften . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707.2.2 Einige Kalkule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717.2.3 Randbemerkungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

7.3 Technische Realisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717.4 Exercise 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

6 Hoare’s Proof Strategy 766.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766.2 The Proof Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766.3 Syntax and Semantics of Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . 776.4 The Proof Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786.5 An Example Proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816.6 Normalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836.7 Heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836.8 Exercise 5, Part 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

7 The Specifications for Hoare 86

8 Procedures and Local Variables 918.1 Syntax of Procedure Declarations and Calls . . . . . . . . . . . . . . . . . . . . . . 918.2 Syntax of Local Variable Declarations . . . . . . . . . . . . . . . . . . . . . . . . . 928.3 Semantics of Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928.4 Semantics of Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938.5 An Example Proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938.6 Functional Specification of Prodedures . . . . . . . . . . . . . . . . . . . . . . . . . 958.7 Rules for Procedures and Local Variables . . . . . . . . . . . . . . . . . . . . . . . 958.8 Heuristics for Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978.9 Exercise 6, Part 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

9 Die Beweisstrategie HASI 1029.1 Ein Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049.2 Versuch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

Page 4: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CONTENTS 3

10 Modules 11010.1 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11010.2 Module correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11210.3 The calculus for module verification . . . . . . . . . . . . . . . . . . . . . . . . . . 115

11 Module Verification with KIV 11911.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11911.2 The Project Selection Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12011.3 Modules in Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12011.4 Exercise 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

12 Module Verification: An Example 12512.1 The Nat-Bin Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12512.2 Module Verification: an Example Proof . . . . . . . . . . . . . . . . . . . . . . . . 129

13 Contracts, Abstract Data Types and Refinement 13713.1 Contracts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13713.2 Abstract Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13913.3 Example of an Abstract Data Type: Queues . . . . . . . . . . . . . . . . . . . . . . 14013.4 Semantics of Abstract Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 14013.5 Refinement of Abstract Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . 14113.6 Verifying Refinement Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14213.7 Refinements of Contracts to Programs . . . . . . . . . . . . . . . . . . . . . . . . . 14213.8 Nondeterministic Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14313.9 Rules for nondeterministic programs . . . . . . . . . . . . . . . . . . . . . . . . . . 14513.10Allocation in heaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14513.11Exercise 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

14 Abstract State Machines and ASM refinement 14814.1 Abstract State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14814.2 ASMs in KIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15014.3 ASM Refinement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15114.4 Proof obligations for ASM refinement in KIV . . . . . . . . . . . . . . . . . . . . . 15314.5 Instantiating the general refinement theory . . . . . . . . . . . . . . . . . . . . . . 15514.6 Verification of ASM refinement in KIV . . . . . . . . . . . . . . . . . . . . . . . . . 15614.7 Exercise 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

14.7.1 Formal specification of ASM 1 . . . . . . . . . . . . . . . . . . . . . . . . . 15714.7.2 ASM 2 and the First Refinement . . . . . . . . . . . . . . . . . . . . . . . . 15714.7.3 ASM 3 and the Second Refinement . . . . . . . . . . . . . . . . . . . . . . . 16014.7.4 ASM 4 and the Third Refinement . . . . . . . . . . . . . . . . . . . . . . . 16214.7.5 ASM 5 and the Fourth Refinement . . . . . . . . . . . . . . . . . . . . . . . 163

15 Java Verification in KIV 16615.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166

15.1.1 A very small tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16615.1.2 Overview over Java projects . . . . . . . . . . . . . . . . . . . . . . . . . . . 16815.1.3 The exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

15.2 Java Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16815.2.1 The State of a Java Program . . . . . . . . . . . . . . . . . . . . . . . . . . 16815.2.2 Exceptions and Jumps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16915.2.3 Loading Java Programs into KIV . . . . . . . . . . . . . . . . . . . . . . . . 17015.2.4 The Type System of Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

15.3 The rule for while loops in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17015.4 Pointer structures in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

Page 5: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CONTENTS 4

15.5 Exercise 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

8 Verification of Parallel Programs 1748.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1748.2 Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

8.2.1 Traces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1758.2.2 Static and dynamic variables . . . . . . . . . . . . . . . . . . . . . . . . . . 1758.2.3 Primed and double primed variables . . . . . . . . . . . . . . . . . . . . . . 1768.2.4 Semantics of temporal operators . . . . . . . . . . . . . . . . . . . . . . . . 1768.2.5 Semantics of parallel programs . . . . . . . . . . . . . . . . . . . . . . . . . 178

8.3 Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1788.3.1 Symbolic execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1798.3.2 Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1838.3.3 Sequencing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1838.3.4 Summary of proof method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

8.4 Exercise (TL Formulas) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1868.5 Exercise (TL Programs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1868.6 Exercise Rely-Guarantee Reasoning . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

9 Programmieren in PPL 1909.1 Befehle und Ausdrucke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1909.2 Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1919.3 Definition von Werten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1919.4 Definitionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1939.5 Typausdrucke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1949.6 Vordefinierte Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1959.7 Kontrollstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1979.8 Ein-/Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1999.9 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2019.10 Exercise 11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

A Simplifier Rules 208A.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208A.2 datastructure independent simplification rules . . . . . . . . . . . . . . . . . . . . . 209A.3 Rules generated from theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209A.4 Forward rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214A.5 Elimination rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215A.6 Cut rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

B Mixfix Notation and Overloading 217B.1 Classification of operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217B.2 Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217B.3 Generalities on Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218B.4 Usual Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218B.5 Postfix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219B.6 Prefix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219B.7 Methodfix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220B.8 Infix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220B.9 Outfix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221B.10 Outinfix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221B.11 Outprefix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222B.12 Outpostfix Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222B.13 Some examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

Page 6: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CONTENTS 5

C Syntax of Dynamic Logic 224

D Syntax of Algebraic Specifications and Modules 237

E Rules for the VCG 249E.1 Rules for the simple VCG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249E.2 Rules for the extended VCG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

F Syntax and Semantics of Higher-Order Dynamic Logic 250F.1 Syntax of Higher-Order Dynamic Logic . . . . . . . . . . . . . . . . . . . . . . . . 250F.2 Semantics of Higher-Order Dynamic Logic . . . . . . . . . . . . . . . . . . . . . . . 252F.3 Higher-Order Rules in Cosi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255F.4 Rules for Strong Diamonds and Indeterministic Choice . . . . . . . . . . . . . . . . 256

G The Module Specific Heuristic 257G.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257G.2 Using the heuristic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257G.3 Syntax of module specific entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258G.4 Rule patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260G.5 Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263G.6 Defining meta variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265

Page 7: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 1

Getting Started

1.1 Overview

This course deals with the development of provably correct programs and software systems. TheKIV system is used as a tool and development environment throughout the course. The firstexercise deals with propositional and predicate logic, proofs and their representation in KIV. Thetopic of the second exercise are proofs over data structures: theorems over specifications of listsand heaps have to be proved. In the third exercise you will create a structured specificationyourself. The fourth and fifth exercises deal with program verification “in the small” and “in thelarge”.

The exercises are solved with the KIV system. As a preparation, documentation with intro-ductory material, theoretical background, and the exercises is issued one week in advance. It isindispensible to read the documentation in advance and to prepare a solution. Otherwise it willnot be possible to solve the exercises with the system during the scheduled time. However, thecomputers are also available at other times, if the normal work is not hindered.

1.2 Starting KIV

Installation

Directories for every group have been set up. Instructions how to do the initial installation willbe given in the first course.

Starting KIV

Just type

./startkiv.sh

in a shell in your home directory.

1.3 Logical Foundations

The logic underlying the KIV system combines Higher-Oder Logic and Dynamic Logic. Higher-Order Logic extends first-order logic with functions that have functions as arguments and results.Also function variables and lambda expressions λx.e that denote anonymous functions are allowed.Dynamic-Logic is an extension of first-order logic by modal program formulae. Dynamic Logic(DL) allows the expression of properties of programs like partial and total correctness, programequivalence etc. By a suitable axiomatisation, proofs that show these properties become possible.The following chapter defines the syntax and the semantics of the first-order part of DL formally.

6

Page 8: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 1. GETTING STARTED 7

Finally a sequent calculus for DL is defined. For a survey on DL see [Har84]. [SA91] resp. [And86]are good introduction to first-order logic and to sequent calculus resp. to higher-order logic. Inthis chapter we introduce the first-order fragment of the logic.

Syntax

Signatures

A signature Σ = (S,OP,X) consists of a finite set S of sorts, a finite family OP =⋃s∈S∗,s′∈SOPs,s′

of operations (with a list of argument sorts s and target sort s′) and a family X =⋃

s∈SXs ofcountably infinite sets of variables.

We always assume that the sorts S contain at least bool and nat, and the operations containthe usual operations on bool (true, false, ∧ , ∨ , → , ↔ ,¬ ) and nat (0, succ, pred,+).

First-order expressions

For a given signature Σ, the set of expressions EXPR :=⋃

s∈SEXPRs, where EXPRs are definedto be the smallest sets with

• Xs ⊆ EXPRs for every s ∈ S

• If f∈ OPs,s and t ∈ Ts then f (t) ∈ EXPRs

• If ϕ ∈ FMA and x ∈ Xs then ∀ x.ϕ ∈ FMA.

Xs is the set of duplicate free lists of variables of sorts s.

• If ϕ ∈ FMA and x ∈ Xs then ∃ x.ϕ ∈ FMA

• If t,t’ ∈ Ts, then t = t’ ∈ FMA

• If ϕ ∈ FMA and t,t’ ∈ EXPRs, then (ϕ ⊃ t; t′) ∈ EXPRs

In the definition, FMA (formulas) abbreviates EXPRbool, the set Ts (terms of sort s) is thesubset of EXPRs, that contains neither quantifiers nor programs. BXP (boolean expressions) isTbool. We also write EXPR(Σ) and FMA(Σ) for EXPR and FMA, when we want to emphasizethat the the sets depend on Σ.

Semantics

Algebra

Given asignature Σ, an algebra A consists of a nonempty set As for every sort s and an operationfA : As → As′ for every f ∈ OPs,s′ . We assume Abool = {tt,ff}, Anat = IN and that operationson booleans and naturals have their usual semantics.

States

Given a signature and an algebra for that signature, a state z ∈ STA is a mapping z, which mapsvariables of sort s to values of As. The state z[x ← a] is the same as z, except that the variablesin x are mapped to the values a. States are sometimes also called valuations.

Semantics of Expressions

Given an Algebra A and a state z the semantics [[e]]z ∈ As of a DL expression e ∈ EXPRs isdefined as:

• [[x]]z = z(x)

• [[f(t)]]z = fA([[t]]z) for f ∈ OPs and t ∈ Ts

Page 9: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 1. GETTING STARTED 8

• [[∀ x.ϕ]]z = tt with x ∈ Xs iff [[ϕ]]z[x ← a] for all values a ∈ As

• [[∃ x.ϕ]]z = tt with x ∈ Xs iff [[ϕ]]z[x ← a] for some value a ∈ As

• [[(ϕ ⊃ e; e′)]]z is [[e]]z, if [[ϕ]]z = tt, and [[e′]]z otherwise.

Models and Validity

A formula ϕ holds over a Σ-Algebra and a valuation z, short A, z |= ϕ, iff (if and only if) [[ϕ]]z = tt.A Σ-Algebra is a model of a formula ϕ, short A |= ϕ, iff for all states z: A, z |= ϕ. A formula ϕis valid, if all Σ-algebras are a model of ϕ. A formula ϕ follows from a set of formulas Φ, short:Φ |= ϕ, if any model of all formulas from Φ is also a model of ϕ.

Sequent calculus

To define the basic axioms for KIV supports a sequent calculus, since formal reasoning with itsrules resembles informal proofs by hand quite closely. For an introduction to ’natural deduction’with sequent calculi see [Ric78] und [SA91].

In the following we will define informally the important concepts of sequent calculus. Thisshould suffice to work with the rules.

Sequents

Let ϕ1, . . . , ϕn, ψ1, . . . , ψm ∈ FMA be two lists of formulas with n,m ≥ 0. Then the scheme

ϕ1, . . . , ϕn ψ1, . . . , ψm

is called a sequent. ϕ1, . . . , ϕn is called the antecedent, ψ1, . . . , ψm the succedent of the sequent. Asequent is a simply a way to present the formula

ϕ1 ∧ . . . ∧ ϕn → ψ1 ∨ . . . ∨ ψm

The meaning of sequent therefore is: The conjunction of the antecedent formulas implies thedisjunction of the succedent formulas. Note that to determine, if a sequent has a model, it’s freevariables have to be treated, as if the whole sequent were universally quantified.

The empty conjunction is defined to be true, the empty disjunction is defined to be false. Asequent with empty succedent therefore is true, if and only if the antecedent contains a contra-diction. In the following rules, instead of using concrete formulas we will use formula schemes(e. g. ϕ, ψ). Such placeholders are called meta variables, in contrast to elements from X, whichare called object variables. We will use meta variables ϕ, ψ for formulas. We also use the capitalgreek letters Γ, Δ as meta variables for lists of formulas. As an example Γ, ϕ Δ is a scheme fora sequent. Any sequent with nonempty antecedent would be an instance of the scheme.

Rules of sequent calculus

If S1, . . . , Sn, S (n ≥ 0) are sequents (possibly containing meta variables), then the scheme

S1 S2 . . . SnS

C

is called a sequent rule. S is called the conclusion, S1, . . . , Sn die premises of the rule. sequentrules, which have an empty set of premises (n = 0) are called axioms. C is a side condition toform instances of the meta variables occuring of the rule (usually it restricts the formulas thatinstantiate the meta variables not to contain certain object variables). Often this condition istrue, and we drop it in this case.

The semantics of a rule is: the conclusion follows from the premises. It views all the sequentsas they were formulas. Sequent calculus consists of a finite set of such rules.

Page 10: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 1. GETTING STARTED 9

Derivations

Rules of sequent calculus can be combined to derivations. A derivation is a tree, whose nodes aresequents. All elementary subtrees of such a derivation must be instances of sequent rules. Exactlyas for rules the root of the tree is called ‘conclusion’, the leaves are called ‘premises’. A moreformal definition of derivation is:

• A sequent is a derivation which has itself as root and as only premise.

• A tree with conclusion K and subtrees T1 . . .Tn (n ≥ 0) is a derivation, if all subtrees T1. . .Tn are derivations, and there is a sequent rule R with Conklusion K’, condition C andpremises P1 . . .Pn, such that there is a substitution s (for the meta variables of R) such thats(K’) = K, the condition s(B) is true and s(P1) . . . s(Pn) are the conclusions of T1 . . .Tn.

The semantics of a derivation in sequent calculus is again: The conclusion follows from thepremises. A derivation with an empty set of premises is a proof, that its conclusion is valid. Thebasic rules of sequent calculus for the first-order part of DL are summarized in Sect. 2.5.

In practical work with sequent calculus one usually starts with a goal S (written as a sequent)which should be proved. Then rules are applied backwards, reducing the goal to simpler subgoals.Note that for most of the rules defined in Sect. 2.5 the premises are simpler than the conclusionin the sense that the maximal number of symbols in the formulas of the sequent decreases. Thisprocess stops when the axiom axiom of sequent calculus is reached.

Theories

Finding a proof for a sequent K over some signature Σ using the basic rules establishes, that thesequent is valid in all models of Σ. This is called logical reasoning.

But usually we want to have some meaning to be associated with the symbols. To do this wewill use a (finite) sets of axioms Ax ⊆ L(Σ,X) as preconditions. Theory reasoning allows proofswith open premises that are axioms. A pair (Σ,Ax) is called theory or a (basic) specification. Theexistance of a theory is the usual case in program verification. Usually the theory describes datatypes used in a program like naturals, lists or records. In a later chapter . theories will also beused to describe program systems

Term generatedness and induction

To describe datastructures adequatly, apart from first-order axioms we also need axioms for (struc-tural) induction. Unfortunately an induction scheme is an infinite set of axioms, that cannot bereplaced by a finite set of formulas. As a replacement we use generation clauses as axioms. Sucha clause has the form

s generated by f1, f2, . . . fn

(‘generated by’-clauses are also possible with several sorts, but since they are rare we will notdiscuss them.) In the clause s is a sort, and f1, f2, . . . fn are operation symbols with target sort s.This axiom holds in an algebra A of the signature, if all elements a ∈ As can be represented bya term t, which consists of operation symbols from f1, f2, . . . , fn only and containes no variablesof sort s. A term ‘represents’ an element a, if for a suitable state z: z(t) = a. In other words wecan say that the carrier set ∈ As can be generated by looking at the values of terms as describedabove.

If the argument sort of the function symbols f1, f2, . . . fn contain no other sort than s, then sis often called a sort generated by (the constructors) f1, f2, . . . fn. In this case every element of Ascan be represented as the value of a variable free term t.

The simplest example for a generated sort are natural numbers, which are generated by 0 : →nat and the successor function +1 : nat→ nat. If we write +1 postfix (i.e. x +1 instead of +1(x))this means that every natural number is of the form

0 +1 +1 +1 . . . +1

Page 11: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 1. GETTING STARTED 10

That is, we have the axiomnat generated by 0,+1

for natural numbers. In this special case two different terms always denote two different numbers(such a datastructure is freely generated). This is not always the case: integers can be generatedby 0 : int, the successor function and +1 : int → int and the predecessor function −1 : int → int.We have

int generated by 0,+1, –1

But here the two different terms ‘0’ and ‘0 +1 –1’ represent the same number. Typical examplesfor data structures in which the funnction symbols f1, f2, . . . fn have other argument sorts than s,are parameterized data structures like lists, arrays or (finite) sets. For the latter

set generated by ∅, insert

holds, if ∅ : → set is the empty set and function insert : elem × set → set adds an element to aset. The elements of sort elem are the parameter which can be chosen freely.

Generation clauses correspond to induction schemes, which allow induction over the structureof a term. The argument is as follows: To show a goal ϕ(x) for all elements x of some sort s,it suffices to show that for every fi ϕ(fi(x1, . . . xn)) holds, assuming that ϕ(xi) holds for all xiwhich have sort s. In those cases, where fi has no arguments of sort s (e.g. if fi is a constant),ϕ(fi(x1, . . . xn)) must be proven without any preconditions. We will not give a formal definitionof the induction rule for arbitrary generated by clauses. Instead we only show the two examplesfor natural numbers and sets, which should make the principle clear:

ϕ(0) ϕ(n) ϕ(n+ 1)

∀ n.ϕ(n)

ϕ(∅) ϕ(s) ϕ(insert(e, s)) ∀ s.ϕ(s)

Page 12: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 2

Predicate Logic Proofs in KIV

2.1 Editing and Loading Theorems

As far as it is necessary for the first exercises we will shortly describe the structure of the softwaredevelopment environment of the KIV system.

2.1.1 Directory structure

The KIV system is a system for the specification and verification of software systems. Every singlesoftware system is handled in a project. After the start of the system (the software developmentenvironment) you have the possibility to select an existing project (or install a new one) onthe project selection level. In the practical course you have to select for every exercise k thecorresponding project Exercise〈k〉. All data of a project is located in a unix directory with thesame name. Therefore the project for the first exercise is located in

〈Your project directory〉/Exercise1

By selecting a project you reach the project level. If you want back to the project selectionlevel you have to click on Edit – Go Back (Go Back is a sub menu of the menu Edit of the graphvisualization tool uDraw). Every project consists of specifications and modules. Their dependencyforms a directed acyclic graph. This graph is visualized with the graph visualization system uDraw.Rectangles correspond to specifications, rhombs to modules. Specifications are described in detailin later chapters For the moment it is enough to know that every specification and every modulecontains a logical theory (i.e. a signature and axioms, e.g. the theory of natural numbers) whereyou can prove theorems. Every specification itself is located in its own subdirectory of the project.The name of the subdirectory is specs/<name>. So you find the specification “proplogic” in thedirectory

〈Your project directory〉/Exercise1/specs/proplogic

The specification text is in the file specification in this directory. You can click on a rectangle (orrhomb) with the left mouse button to view or edit the specification. To work with a specificationyou select Work on ....

After a short time you will get another window that contains a detailed of the specification’stheorem base. The theorem base contains the axioms of the specification, and user defined theorems(properties, lemmas), and their proofs. The specification window starts with the Summary registertab that shows the names of the axioms and theorems sorted by their state (axiom, proved,unproved, partial, invalid, sig invalid). You can select an entry by clicking on it with the leftmouse button (this will highlight the entry). Then you can click the right mouse button to geta popup menu where you can View the theorem, begin a New Proof, etc. When you select theregister tab Theorem Base you get another view of the axioms and theorems that also displays

11

Page 13: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 12

their sequents (or at least part of them). Here you don’t have to select a theorem first with theleft mouse button; instead you can just click on a theorem with the right mouse button to getthe popup menu. Both tabs have the same functionality – they just present different views of thetheorem base.

The most important menu entry is File – Save that saves the theorem base back to the harddisk (KIV has no autosave feature). We recommend to save the theorem base regularly. If youleave the specification with File – Close the theorem base will be saved automatically if necessary.Note that the uDraw window the development graph is still active while the specification windowis open, i.e. you can click in the graph to view other specifications etc.

2.1.2 Editing Theorems

You can enter new theorems (sequents, not only formulas) either directly with the menu entryTheorems – Enter New, or through a file. Because theorems are often quite large and it is difficultto enter them without a fault you can use your favorite editor to edit a file. For new theorems thefile sequents in a specification directory is used. In our example you have to edit

〈Your project directory〉/Exercise1/specs/proplogic/sequents

The command Edit – Theorems starts the xemacs editor with that file loaded, and is a comfortableshortcut. After editing and saving the file, KIV has to be informed that it should load new orchanged theorem. This is done with the commands Theorems – Load New and Theorems – Load

Changed. Both of these commands can also be accessed using the corresponding buttons in theTheorem Base tab.

The syntax of the file is as follows:

1. Two or more semicolons (;;) begin a one line comment (as // in Java)

2. (: begins and :) ends a multi line comment (as /* and */ in Java). In contrast to Javathese comments can be nested.

3. Parsing stops after a line beginning with ;;; END

4. The file may not contain double quotes anywhere.

5. The file begins with an optional keyword variables that allows to declare auxiliary variablesfor theorems.

6. The keyword lemmas begins the list of theorems.

7. A theorem has the form

〈theorem name〉 : 〈sequent〉 ;The trailing semicolon is mandatory. Instead of a sequent you can also just write a formulaϕ, which is read as ϕ.

Every theorem can be written in this file. When an already defined theorem is loaded a secondtime, this definition is ignored. A theorem can be modified with the menu entry Theorems –Load Changed or the Load Changed button in the Theorem Base tab likewise in this file. Othertheorems which are not modified are ignored.

To prove a theorem you select either

• Begin to prove an unproved theorem,

• Continue to continue a partial proof,

• Load to load a complete proof, or

• Reprove to start a new proof for a completely or partially proved theorem

Page 14: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 13

in the Proof menu. You can also use the popup menu by right-clicking on a theorem and selectNew Proof (for Begin or Reprove), Continue Proof, or Load Proof.

The selection of any of these commands opens another window where proofs are done. Asbefore, all other open windows are still active. However, some commands are not possible whenyou have a current proof. E. g. Theorems – Delete will issue the message ‘You can’t use thiscommand if you have a current proof.’ You finish a proof by closing the proof window with File

– Close. If you want to keep the proof you should save the theorem base first with File – Save.(This also saves the current proof.) If you want to discard the proof (because you don’t want tooverwrite the old proof for some reason – KIV normally doesn’t keep different versions of proofs)you simply close the window and answer the following question ‘The proof is modified. Updatethe theorem first?’ with ‘No’. If you answer ‘Yes’ the current proof will be stored in the theorembase and saved the next time the theorem base is saved. (If you change your mind you can alsocancel the action.)

2.2 Syntax and Special Character Input

The syntax of predicate logic in KIV is essentially the same used e.g. in chapter 1.3. The followingoperator precedences hold:

{¬} � {∧} � {∨} � {→} � {↔} � {∀, ∃}

Quantifiers can contain one or more variables. If more than one variable exists they are separatedby commas and after the last variable (and before the quantified formula) a dot follows. Theoremsare sequents and not only formulas. The sequent sign is .

Many of the logical symbols use a special character, and KIV offers even more like ∪ or ≤,or greek letters. A full list is at the end of this section. To insert these characters in the xemacsone has to press F12 and enter the name of the special character (followed by return). The mostimportant names are

¬ ∧ ∨ → ↔ ∀ ∃ not and or implies equiv all ex follows

It is sufficient to type in a unique prefix, e.g. instead of typing implies it is enough to enterim and hit return. The available completions for a prefix are shown by hitting the tab key.

Similar support for special characters as in xemacs is also available in all editable text fields ofdialog windows. Pressing F12 in such a field will open a dialog, where all the symbols supportedby KIV are shown. You can insert a symbol by either double clicking it or entering a unique prefixand hitting ENTER. After that the dialog is closed automatically. You can cancel the dialog bypressing ESC or clicking the close button.

Note also, that you can always paste an arbitrary text selection with your mouse, or pastefrom your clipboard. Finally, since KIV originally had an ascii-syntax, the most important specialcharacters still have the following ascii-syntax (but it is not recommended that you use it).

¬ ∧ ∨ → ↔ ∀ ∃ not and or -> <-> all ex |-

When entering terms and predicates and formulas some common pitfalls should be avoided:

1. In KIV nearly arbitrary identifiers are allowed for symbols, e.g. 0, +, ++, <, list<, |’,→3, x=y, 3_’|\ etc. The disallowed characters are brackets, space, comma, semicolon,backquote, and double quotation mark. Colon, star, and the dollar sign are treated specially.Therefore:

There must be spaces around identifiers unless the previ-ous or next character is a bracket, comma, or semicolon!

Page 15: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 14

“x=y” is not the equation “x = y”, but a three character identifier!

2. Variables, function and predicate symbols can only be entered when they are already definedin the signature of the specification.

In the specification barbier the variables x and y of sort person are defined. Only these twovariables can be used to formulate the propositions.

3. Functions and predicates can be written in the usual form f(t1, . . . , tn), but there are alsoinfix, prefix, and postfix operators. E.g. + is an infix operator so you must write “m + n”instead of “+(m,n)”. +1 is a postfix operator and is placed behind its argument: “(m + n)+1”. A prefix operator precedes its single argument without brackets. An infix, prefix, orpostfix operator can’t be written in another manner, i.e. it is not possible to write “+(m,n)” or “+1(n)”.

Postfix operators have a higher precedence than prefix operators. Infix operators have lowestprecedence, so the expression “m + n +1” is equivalent to “m + (n +1)” and not to “(m+ n) +1”! Furthermore, for infix operators a precedence can be specified, e.g. ∗ is definedto have higher precedence than +. If you are not sure about precedences you should placebrackets around the expression.

Infix operators are specified in the signature definition of the specification with two dotsaround the symbol. E.g. in the specification nat

. + . : nat × nat → nat;

Postfix operations have got a dot before the symbol in the definition (the dots mark thepositions of the parameters):

. +1 : nat → nat;

4. The dot is allowed at the beginning of a symbol, but nowhere else. It is often used to definepostfix operations. The leading space before a symbol starting with a dot can be dropped.As an example in “x.first” the postfix operation “.first” is applied on x, and the expressionneeds no space in the middle. A single dot is not a symbol, but used only in quantifiers.There, no space is needed before the dot, but one space is needed after it to separate thenext symbol.

5. Special characters in Xemacs normally have the same name as the corresponding LATEXsymbol, so � is odot, ⊕ is called oplus and so on. In ascii syntax these symbols can beentered as the xemacs name with a leading backslash, e.g. \odot for �, \oplus for ⊕, etc.

A parser error occurs if the input is not correct. In the specification nat e.g. the variable x is notdefined. So the input “n + x” results in the parser error

Parser: parse error in "n + ?? x".

The parser displays two question marks before the next token that can’t be parsed. The text upto this point was parsed successfully (though perhaps not in the manner you expected). The input“n + = n” results in

Parser: parse error in "n + ?? = n".

If the beginning of the input is already faulty (e.g. the input “x” in the specification nat) you get

Parser: parse error at the beginning of "x".

If something is missing at the end (e.g. the semicolon after a sequent in the sequents file, see2.1.2) you get

Parser: parse error at the end of "lemmas lem-01 : 0 + m = m".

Page 16: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 15

name symbolfollows unequal �=not ¬and ∧or ∨implies →equivalent ↔exists ∃all ∀emptyset ∅in ∈union ∪intersection ∩times ×< 〈> 〉Delta ΔGamma ΓLambda ΛOmega ΩPhi ΦPi ΠPsi ΨSigma ΣTheta ΘXi Ξall ∀alpha α

name symboland ∧beta βbottom ⊥box �

chi χcircle ©congruent ≡delta δdiamond �

{ 〈|} |〉downarrow ↓emptyset ∅epsilon εequivalent ↔eta ηexists ∃follows forall ∀gamma γge ≥glb �greaterorequal ≥grgr �higher �implies →in ∈infinity ∞

name symbolintegral

∫intersection ∩iota ιkappa κlambda λlceil !le ≤leftarrow ←lessorequal ≤lfloor "lower #lquine !lsem [[lsls $lub %models |=mu μneq �=ni &not ¬nu νodiv 'odot �omega ωominus (oplus ⊕or ∨otimes ⊗

name symbolphi ϕpi πpsi ψrceil *revsemimp ⇐rfloor ,rho ρrquine *rsem ]]semequiv ⇔semimp ⇒sigma σsqgreater �

sqless �

subset ⊂subseteq ⊆supset ⊃supseteq ⊇tau τtheta θtimes ×top 1unequal �=union ∪uparrow ↑upsilon υxi ξzeta ζ

2.3 Proofs in KIV

The proof window (the window has the title “KIV - Specification Strategy”) is used for proofs inthe sequent calculus. In the large frame on the right you always find the currently selected premiseof the proof tree, the actual “goal” you are just now working on. On the left side all applicablerules are shown. Another window with the title “current proof” shows the current proof tree.

Selecting basic rules

In the first exercise the basic rule set of the sequent calculus is used instead of the optimized ruleset that is normally (and in later exercises) used. For your convenience this switching of rule setshas already been done (using a configuration file). Switching rule sets can also be done manually(and we will need this feature later on) by selecting the menu entry Control – Options. After thata window will appear – with a rather longish list of options. For the first exercise only the option“Use basic rules” is of interest, which is already selected. Clicking on this option will deselect itor select it again. Clicking the “Ok” button will activate your selection of options. For the firstexercise the “Use basic rules” option should be activated.

Short description of the menu commands

In the following section all menu commands of the proof level which are relevant for first orderproofs are described. Some important commands are also present in the icon bar

Page 17: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 16

• Menu File

– Save: save the theorem base and the current proof (Icon: diskette)

– Close: end the current proof (Icon: closing door)

• Menu View

– Specification: view the used specification (the specification can also be viewed underthe specification tab)

• Menu Proof

– Begin/Continue: choose a new theorem to prove

• Menu Goal

– Open Goals: display informations about open premises

– Switch Goal: continue working at an other goal (Icon: Green Arrow left/right toswitch to the previous/next goal).

– Show Tree: display the current proof tree. This command always is very useful to getinformations about the current proof. (Icon: Green Three-Node Tree).

– Prune Tree: prune a branch in the current proof tree. This makes sense if there is anerror in the proof. The position where the tree should be pruned is chosen by clickingon the node and pressing p (or choosing Operations – Prune Tree in the tree window).If the current proof tree is displayed it’s also possible to click on the node and use p orOperations – Prune Tree (without using a menu command). Note that this commanddoesn’t change the chosen heuristics. It is therefore possible that the new goal is treatedby the heuristics at once. In this case all heuristics should be deactivated before pruningthe tree by clicking “Use Heuristics” in the bottom left corner of the proof window.

• Menu Control

– Heuristics: choose heuristics (see below; Icon: Terminal with On/Off).

– Backtrack: got back to the last backtrack point. The system generates always abacktrack point if rules are applied or the systems behavior changes because of aninteraction. Nevertheless only a certain number of backtrack points are stored. (Icon:yellow, curved arrow)

– Options: To select the option Use basic rules. A window appears with a rather longishlist of options. For the first exercise only the option “Use basic rules” is of interest.Clicking on this option will mark it as selected. By clicking the “Ok” button theselection of options is ended.

Options are valid as long as you are working on a specification or doing proofs in thisspecification, i.e. the option remains in charge until you go back to the project level.

Viewing proof trees

Proof trees can be displayed graphically in the tree windows. A brief description how such a treecan be interpreted follows.

Colors

A proof tree appears in different colors which serves for an easier orientation.

• Color of branches: closed branches are displayed in green (i.e. there exist no more openpremises resp. all open premises are axioms or theorems). Red branches lead to openpremises which have to be proven.

Page 18: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 17

• Color of nodes:

– Colors of inner nodes: The color of the inner nodes marks the kind of rule that wasused.

∗ black: propositional rules not introducing case distinctions, i. e. conjunction left,negation left, disjunction right, implication right, negation right, and other “unim-portant” rules like simplifier, elimination etc.

∗ red: induction rules

∗ blue: cut formula, disjunction left, implication left, equivalence left, conjunctionright, equivalence right, case distinction, program calls

∗ brown: weakening

∗ green: quantifier instantiation

∗ violet: rules for loops and whiles

– Color for leave nodes: The color of the leave nodes sign how the corresponding branchwas closed (if at all).

∗ green: axiom or theorem of the specification.

∗ blue: axiom or theorem of a subspecification.

∗ red: open premise.

• filled vs. non-filled nodes: Premises are always drawn as non-filled nodes. Inner nodesof a tree are non-filled if the applied rule was chosen by the user. If a rule was appliedautomatically by an heuristic (see below) the node is filled.

• enumeration of premises: The open premises of a tree are enumerated. If the proof uses sometheorems as lemmas their names are displayed (lemmas are not treated as open premises).

Clicking a proof tree

Clicking on a node with the left mouse button marks1 the node and displays the correspondingsequent in a sequent window. Clicking with the middle button displays the sequent in a newsequent window2 without marking that node. Clicking a further node with the middle mousebutton opens a second, new sequent window and so on (useful if you want to see more than onesequent). Clicking a node with the right button marks it without displaying its sequent. By left-(or right-)clicking a part of the tree window where no node is displayed the marking is reset.

Operations

The menu operations contains a number of commands. But only a few of them are interesting:

Prune Tree After clicking on a node with the left or right mouse button this menu item causesthat the command Prune Tree is executed (see above). The tree is pruned at the markedpoint.

The key p is an abbreviation of this menu item.

Switch Goal After the choice of an open premise with the left mouse key the proof is continuedat this premise.

The key g is a shortcut for this item.

Quit The tree window (and all its sequent windows) are closed. (Shortcut: key q)

Note that these menu items are disabled when they’re not applicable. E.g. Switch Goal needs thatboth a node is selected in the tree and that this node is an open premise in order to be applicableand thus enabled.

1The marked node will be shown in a red rectangle.2The window will be titled Goal <nr>. For reference, in the proof tree window <nr> will be written on the right

of the node.

Page 19: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 18

Sequent Windows

The size of sequent windows is variable. The system tries to increase the size of the window untilthe whole output (generated by the pretty printer) fits. If that is not possible scrollbars are addedto the window.

Above the sequent in some cases a text is displayed. This text is extracted from the tree-comment of the (sub-)tree whose conclusion is the printed sequent. It normally contains the name(and in some case also the arguments) of the used rule. In case of open premises nothing isdisplayed. To close the sequent window press key q in the window (or click the Close button).

2.4 Rule set for predicate logic

The rule set for predicate logic can be found in the next section (2.5). Here we describe the usageof three selected rules.

2.4.1 all left

The quantifier rules all left and exists right require (or allow) an instantiation that must be enteredinteractively. We describe the rest for all left, but everything also works for exists right.

ϕτx, ∀ x.ϕ,Γ Δ∀ x.ϕ,Γ Δ

(all left)

ϕτx is the substitution of x by τ in ϕ, τ may be an arbitrary term. The rule is also applicable fora list of quantified variables ∀ x1, . . . , xn.ϕ. In this case a list of terms τ1, . . . , τn is used and aparallel substitution takes place.

You can select the rule from the rule list. If there is more than one formula with a universalquantifier in the antecedent, the first step is the selection of formula you want to apply the ruleon. Just select the formula and click ‘Okay’. Instead of selecting the rule from the rule list youcan also select the rule and the formula in one step with the mouse. Just click with the rightmouse button anywhere in the formula.

The next step is the input of the instantiation. A window appears that displays the formula,the list of variables to instantiate, a list of suggestions (or no suggestion), a text field for yourinput, and three buttons. Now you have three possibilities. You can select a substitution fromthe list of suggestions. The substitution appears in the text field. Or you can enter a substitutionyourself. For every variable to instantiate you enter one term. Several terms are separated bycomma. E.g., if the variables to substitute are [x, y], you must enter something like 3, x + y.(You can also type [3, x + y].) This means that x will be substituted by 3, and y by x + yin parallel! (I.e. the second substitution is not equivalent to 3 + y.) The third possibility is tochoose a previously typed substitution by clicking on the down arrow at the right of the text field.No matter how you selected the substitution, you can still edit it in the text field. This is veryconvenient if a suggestion is slightly wrong. Just select and edit it.

After you are satisfied with your substitution, one more decision remains: You can discard orkeep the quantified formula. Discarding it is useful if you are sure that you don’t need it anymore,because it makes the sequent smaller, easier to read, and you are not tempted to use the ruleagain with useless instances. However, the goal may become unprovable if your current instanceis not correct or you must instantiate the quantifier more than once. It’s your choice! If you wantto keep the quantified formula select the button ‘Okay (Keep)’, otherwise select ‘Okay (Discard)’.

If your substitution contains a variable that is not free in the sequent, a confirmation windowappears whether you really want to use that substitution. Normally, a new variable (not occurringfree in the sequent) indicates a typing error, because such a substitution is normally useless.However, there are cases (that occur in the exercises!) where the substitution is really irrelevant.Confirm the window this ‘Yes’ or ‘No’, and the rule is applied.

Page 20: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 19

2.4.2 insert equation

Equations can be inserted with the rule insert equation

σ = τ,Γτσ Δτσ

σ = τ,Γ Δ(insert equation)

In this rule σ = τ is an arbitrary equation of the antecedent. The system displays all possibleequations together with their symmetric counterpart τ = σ. Since predicates in the antecedentcan be read as predicate = true (and predicates in the succedent as predicate = false) they arealso listed. Beware: every equation and predicate is offered for insert equation even if there is nouseful usage for the equation!

Now you can select one equation to insert. There are two buttons: the left is labeled Okay(keep), the right Okay (discard). ‘keep’ means that the equation remains in the new goal (asshown above), ‘discard’ means that the equation will be discarded after insertion (with weakening).Beware: it is your decision! If you discard the equation the goal may become unprovable. (Thishappens if the equation is false, e.g. 0 = 1, or if the right hand side contains variables that stilloccur in the sequent after insert equation.)

After selecting the equation to insert (and whether to keep or to discard it) the positions wherethe equation can be inserted are displayed (marked with ##. . . ). It is possible to substitute alloccurrences of σ by τ (the normal case) or just one (or several occurrences). You will not get thisquestion if no or only one possibility exists.

The rule can also be applied in a context sensitive manner. If you click with the right mousebutton anywhere on the left hand side of an equation, a window with the text insert equation (leftto right) appears. This will insert the equation left to right everywhere, i.e. all occurrences of theright side are substituted by the left side, and the equation is discarded. If you click on the righthand side the left side is replaced by the right side, again everywhere, and again the equation isdiscarded. If you want to keep the equation you have to use the rule from the rule list.

2.4.3 insert lemma

To use axioms or theorems the following rule exists:

Γ′ Δ′ Γ Θ(Γ′),Δ Θ(Δ′),Γ Δ

Γ Δ(insert lemma)

• Γ′ Δ′ is the lemma (theorem)

• Θ is a parallel substitution for the free variables of the lemma

In order to apply a theorem Γ′ Δ′ it is necessary to enter a substitution Θ for the free variables ofthe theorem to obtain the instances for the actual goal. The system shows the free variables of thesequent and you have to enter a list of terms term1, term2, . . . termn for every variable separatedby comma. The list of terms may be optionally enclosed in square brackets. The selection of thesubstitution is identical to the quantifier instantiation all left. However, there is only one ‘Okay’button because you can’t ‘keep’ the lemma. If you need it more than once you have to use therule several times.

The rule adds three new premises to the proof tree. The first one is the theorem itself. Thispremise stays open and is managed by the correctness management which takes care that nocyclical proof dependencies occur. (For example you prove the theorem A with the lemma B andthe lemma B with the theorem A). For the second premise you have to show that the (instances ofthe) precondition for the lemma holds. This is the conjunction of the formulas of the antecedentof the lemma, written as ΘΓ′. If the lemma has no conditions then ΘΓ′ is true and the statementis an axiom. In the last premise the results (i.e. the disjunction of the formulas of the succedent,often only one formula) are added to the previous goal.

Page 21: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 20

A similar rule is insert axiom. An axiom or theorem (with all quantifiers added) is added tothe antecedent of the goal. If you instantiate the quantifiers with all left, discard the formula, andmake a case distinction (provided the axiom is ϕ → ψ), you obtain the same premises as withinsert lemma.

2.5 Basic rules

The following notation is used for the rules: ϕ, ψ denote arbitrary formulas, Γ,Δ stand for arbitrarylists of formulas. σ, τ denote terms. The rules are written in a little bit simplified notation.Even though we write ϕ ∧ ψ,Γ Δ the rule conjunction left is applicable on any conjunction inthe antecedent, not only on the first formula of the antecedent. The correct notation would beΓ1, ϕ ∧ ψ,Γ2 Δ.

2.5.1 Axioms

ϕ,Γ ϕ,Δ (axiom)false,Γ Δ

(false left)

Γ τ = τ,Δ(reflexivity right)

Γ true,Δ(true right)

2.5.2 Propositional and equational rules

Γ ϕ,Δ¬ ϕ,Γ Δ

(negation left)ψ,Γ ΔΓ ¬ ψ,Δ (negation right)

ϕ, ψ,Γ Δϕ ∧ ψ,Γ Δ

(conjunction left)Γ ϕ,Δ Γ ψ,Δ

Γ ϕ ∧ ψ,Δ (conjunction right)

ϕ,Γ Δ ψ,Γ Δϕ ∨ ψ,Γ Δ

(disjunction left)Γ ϕ, ψ,ΔΓ ϕ ∨ ψ,Δ (disjunction right)

Γ ϕ,Δ ψ,Γ Δϕ→ ψ,Γ Δ

(implication left)ϕ,Γ ψ,Δ

Γ ϕ→ ψ,Δ(implication right)

Γ ϕ, ψ,Δ ϕ, ψ,Γ Δϕ ↔ ψ,Γ Δ

(equivalence left)ϕ,Γ ψ,Δ ψ,Γ ϕ,Δ

Γ ϕ ↔ ψ,Δ(equivalence right)

Γ′ Δ′

Γ Δ(weakening, Γ′ ⊆ Γ,Δ′ ⊆ Δ)

Γ ϕ,Δ ϕ,Γ ΔΓ Δ

(cut formula)

σ = τ,Γτσ Δτσ

σ = τ,Γ Δ(insert equation)

2.5.3 Quantifiers

Note: ϕτx is the substitution of x by τ in ϕ.

• ϕτx, ∀ x.ϕ,Γ Δ∀ x.ϕ,Γ Δ

(all left)Γ ϕτx, ∃ x.ϕ,ΔΓ ∃ x.ϕ,Δ (exists right)

τ may be an arbitrary term.

The rule is also applicable for a list of quantified variables ∀ x1, . . . , xn.ϕ. In this case a listof terms τ1, . . . , τn is used and a parallel substitution takes place.

The quantified formula can optionally be discarded.

Page 22: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 21

• ϕyx,Γ Δ∃ x.ϕ,Γ Δ

(exists left)Γ ϕyx,Δ

Γ ∀ x.ϕ,Δ (all right)

y is a new variable, i.e. one that does not occur in the free variables of ϕ,Γ,Δ.

The rule is also applicable for a list of quantified variables ∀ x1, . . . , xn.ϕ. In this case a listof new variables y1, . . . , yn is used and a parallel substitution takes place.

2.5.4 Theory rules

• ϕ(c) ϕ(x) ϕ(f(x))Γ Δ

(structural induction)

ϕ = ∀ x′.Γ → Δ with x′ = Free(Γ→ Δ) \ xThe specification contains a generation principle sort(x) generated by c, f

• ∀ x.ϕ ∀ x.ϕ,Γ ΔΓ Δ

(insert axiom/insert spec-axiom)

ϕ is an axiom, x the free variables of ϕ.

insert axiom applies a lemma from the current specification, insert spec-axiom from a sub-specification.

• Γ′ Δ′ Γ Θ(Γ′),Δ Θ(Δ′),Γ ΔΓ Δ

(insert lemma/insert spec-lemma)

Γ′ Δ′ is the lemma (theorem)

Θ is a parallel substitution for the free variables of the lemma.

insert lemma applies a lemma from the current specification, insert spec-lemma from asubspecification.

• ϕ → σ = τ Γ Θ(ϕ),Δ Θ(ϕ),ΓΘ(τ)Θ(σ) Δ

Θ(τ)Θ(σ)

Γ Δ(insert rewrite lemma)

ϕ → σ = τ is the rewrite theorem.

Θ is a parallel substitution for the free variables of the theorem. (Computed automatically.)

2.6 Heuristics for basic rules

If you have worked for a while with the basic rules of the sequent calculus you will see that alot of steps always repeat. For example, you will always apply rules for propositional connectivesthat do not introduce case distinctions. Such regular patterns of the proof can be detected by thesystem and it can apply the corresponding rules automatically. Heuristics take the decision fromthe user what has to be done next. But the user has to decide which heuristics to use and whichto omit. They can be switched on/off at any position in the proof. If a heuristic is not applicableon the actual sequent the system tries to apply the next heuristic. If there are no more applicableheuristics the system stops the automatic proof attempt and asks the user for an interaction. Thesystem displays all rules that are applicable on the current goal.

The heuristics are chosen by the menu entry Control – Heuristics. If you are working withthe basic rules of the sequent calculus a two column window appears where the left column containsall heuristics for basic rules, and the right column the currently selected, active heuristics. Youcan add heuristics by clicking on them in the left window. The order of the application of theheuristics corresponds to the order of their selection. By clicking on the OK button the heuristicsare applied on the current goal. You can turn the heuristics on or off by clicking ‘Use Heuristics’in the lower left bottom of the proof window. If no heuristics are selected, and ‘Use Heuristics’ isdeselected, clicking on the field is a shortcut to the menu entry Control – Heuristics.

Page 23: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 22

Heuristics are only heuristics: They may do the wrong thing, or something useless. And theorder of the heuristics can have considerable impact on the size of the proof. (E.g. if you do casedistinctions too early.) The following heuristics are for the basic rules:

• axiom: This heuristic searches for a possibility to apply the axiom rules axiom, false left,true right, and reflexivity right.

This heuristic closes the goal, i.e. it can’t do anything wrong or useless, and should be alwaysused as the first heuristic.

• prop simplification: applies the propositional rules with one premise negation left, negationright, conjunction left, disjunction right, and implication right.

Can’t do something wrong or useless.

• prop split: applies the propositional rules with two premises disjunction left, conjunctionright, implication left, equivalence left, and equivalence right.

Can’t do something wrong, but may do case distinctions too early.

• smart basic case distinction: tries to apply propositional rules with two premises whereone premise can be immediately closed, so that no ‘real’ case distinction is introduced.

Can’t do something wrong or useless.

• insert equation: inserts equation with the rule insert equation without discarding theequation.

May be useless, but not wrong.

• Quantifier closing: applies the rules all left and exists right if it can find an instantiationthat will close the goal.

Can’t do something wrong or useless.

• discard quantifier: applies the rules exists left and all right.

Can’t do something wrong or useless.

• Quantifier: applies the rules all left and exists right if it finds (or rather guesses) an instan-tiation that may be useful for the proof. This guessing is not perfect at all (and can not bedue to the undecidability of predicate logic), and therefore this heuristic is “dangerous” inmultiple regard: It can happen that this heuristic tries unnecessary instances for a quantifier,thereby producing a large proof tree. It can also happen that this heuristic does not findthe correct instance and you have to insert it yourself (maybe several times if unnecessaryinstances arose). In the worst case this heuristic tries again and again an incorrect instancean the system does not stop at all. In this case press the Stop button. This will enforcea stop. But for all that this heuristic often finds the correct instance and is therefore veryuseful.

• batch mode: This ‘heuristic’ just switches to the next goal. It should be only used as thelast heuristic. Its effect is that all branches of the proof are treated by the heuristics as muchas possible.

Page 24: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 23

2.7 Exercise 1

For every exercise (except the last one) the basic rules have to be used, i.e. the option Use basicrules (by selecting the menu command Control – Options) must be switched on. This should bethe case by default.

Exercise 1.1 Propositional logicWork on the specification proplogic and switch on the option to use basic rules (with the menu

command Control – Options). Then prove without heuristics the three propositional axioms ofthe Hilbert calculus:Hilbert-1: ϕ → (ψ → ϕ)Hilbert-2: (ϕ → ψ) → (¬ ψ → ¬ ϕ)Hilbert-3: ((ϕ → ψ) → (ϕ → χ)) → (ϕ → (ψ → χ))

Exercise 1.2 (Example) Propositional logicConsider the following logical puzzle:

The oracle says:

The left and the right path lead to Delphi if the middle path leads somewhere else.

If at most one of the left and middle path lead to the oracle, then the right path iswrong.

However, if the right or left path leads to Delphi, the middle path definitely does notlead there.

Which of the three paths leads to Delphi?

To solve this puzzle we can use three propositional constants left, right, and middle. Theirintuitive meaning is: If the constant is true the path leads to Delphi, otherwise not. For example,if left is true the left path leads to Delphi. We can now formalize the three sentences (or knownfacts):

¬ middle → left ∧ right

¬ (left ∧ middle) → ¬ right

left ∨ right → ¬ middle

Together we have

〈facts〉 = (¬ middle → left ∧ right)= ∧ (¬ (left ∧ middle) → ¬ right)= ∧ (left ∨ right → ¬ middle)

(Note the brackets!) Now we have to find a solution. Here it is important to read exactly whatis requested. Let’s assume we found out (by hard thinking) that the middle path leads to Delphi.This means a possible solution is middle. On the other hand, we may have found out that themiddle path leads to Delphi and the other two paths do not. This means another (more complete)solution is middle ∧ ¬ left ∧ ¬ right. Now we can prove two things:

1. The solution fulfills the facts, i.e. the solution is indeed a solution. (This also proves thatthe facts are not contradictory!)

Prove 〈 solution〉 〈 facts〉 :middle ∧ ¬ left ∧ ¬ right (¬ middle → left ∧ right)∧ (¬ (left ∧ middle) → ¬ right)∧ (left ∨ right → ¬ middle)

Page 25: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 24

(Note the brackets because of the priorities of ¬ , ∧ , → !) This only works for completesolutions, i.e. if a value is given to all constants.

If we want to check a partial solution, we can prove

¬ 〈 partial solution〉 ¬ 〈 facts〉 :¬ middle ¬ ( (¬ middle → left ∧ right)

∧ (¬ (left ∧ middle) → ¬ right)∧ (left ∨ right → ¬ middle))

2. The solution follows from the facts. (This means the solution is unique.)

Prove 〈 facts〉 〈 solution〉 :¬ middle → left ∧ right,¬ (left ∧ middle) → ¬ right,left ∨ right → ¬ middle

middle ∧ ¬ left ∧ ¬ right

It is somewhat unsatisfactory that we have to know the solution before we can prove anything.However, we can also use the system to find a solution. We begin ‘proving’ with only the facts,i.e. 〈 facts〉 〈 empty succedent〉 :

¬ middle → left ∧ right, ¬ (left ∧ middle) → ¬ right, left ∨ right → ¬middle

Using the heuristics we get a proof tree that contains one open premise:

middle right, left, right

And this is the solution! middlemust be true and left and right must be false. The open premisealso shows that the facts are not contradictory. However, the result may be more complicated tointerpret:

• We must use only equivalence rules, i.e. rules that are true in both directions (i.e. theconclusion is equivalent to the conjunction of the premises). This means that e.g. the ruleweakening formulas may not be used.

• One constant may be missing. If the result is just right, left, then we don’t knowanything about the middle path (it may or may not lead to Delphi). It depends on theproblem whether this is a correct solution.

• Often the resulting proof tree has more than one open premise. Then every premise yields apossible solution that fulfills the facts. However, this does not mean that the solution followsfrom the facts (i.e. is unique). The solution is unique if all premises yield the same solution(and this solution contains all constants).

If we have the two premises

middle left, and right

we have two solutions, middle ∧ ¬ left (and we don’t know anything about right), anda second solution ¬ right (and we don’t know anything about middle and left). This iscertainly not a correct solution!

If the premises are middle left, and middle right, the solution is not unique.middle must be true, but we don’t know anything about left or right. (This may be acorrect solution.)

• The resulting proof tree is closed. This means that the facts are contradictory. (Which maybe a correct solution.)

Page 26: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 25

Your task: Work on the specification proplogic, use basic rules, and any heuristics you like (agood selection is all heuristics – how does their order influence the proofs?). Prove the threetheorems delphi-try, delphi-solution, delphi-fulfills, and compare the proof trees. (Ofcourse, delphi-try is not provable.)

Exercise 1.3 Propositional logicWork on the specification proplogic, use basic rules, and any heuristics you like. Formalize

and prove the following puzzle using propositional logic. Use the propositional constants a, b, c.What is their intuitive meaning?

Mr. McGregor, a London shopkeeper, phoned Scotland Yard that his shop had beenrobbed. Three suspects A, B, C were rounded up for questioning. The following factswere established:

1. Each of the men A, B, C had been in the shop on the day of the robbery, and noone else had been in the shop that day.

2. If A was guilty, then he had exactly one accomplice.

3. If B is innocent, so is C.

4. If exactly two are guilty, then A is one of them.

5. If C is innocent, so is B.

Whom did Inspector Craig indict?

Add the formalization as a theorem in the file sequents (see section 2.1.2). Note that you shouldenter a sequent, not a formula, and that you can only use the symbols defined in the specification.

Exercise 1.4 Propositional logicWork on the specification proplogic, use basic rules, and any heuristics you like. Formalize

and prove the following puzzle using propositional logic. Use the propositional constants af, bf,ad, bd. (What is their intuitive meaning? a = ‘amplifier’, b = ‘bycicle’, f = ‘flux generator’, d =‘dragon trap’)

Engineer Trurl wants to construct two machines (a probabilistic flux generator and auniversal dragon trap) from a heap of scrap metal. The most valuable components athis hands are a chance amplifier and a bicycle. His colleague Klapauzius asks, ‘Is ittrue that if you need the bicycle for the probabilistic flux generator, and the chanceamplifier for the dragon trap if and only if you also need the bicyle for it, you then don’thave to install the amplifier in the flux generator?’ Trurl ponders ‘If this statementis true, then I need the bicycle for exactly one machine, and the same holds for thechance amplifier. On the other hand, if I need the bicycle at all then the statementmust be false. But in each case I do not need both components for both machines.’

Now, Which component is needed for which machine?

Show that a unique solution exists. What is it?

Exercise 1.5 Predicate logicWork on the specification predlogic, use basic rules or not (you can change it with the menu

Control – Options and Use Basic Rules), and any heuristics you like. Prove the following theorems:

Page 27: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 26

1. Allneg : (∀ x. ¬ p(x)) ↔ ¬ ∃ x. p(x);

2. Exneg : (∃ x. ¬ p(x)) ↔ ¬ ∀ x. p(x);

3. Allimpleft : ((∀ x. p(x)) → q(y)) ↔ ∃ x. p(x) → q(y);

4. Allimpright : (p(x) → ∀ y. q(y)) ↔ ∀ y. p(x) → q(y);

5. Eximpleft : ((∃ x. p(x)) → q(y)) ↔ ∀ x. p(x) → q(y);

6. Eximpright : (p(x) → ∃ y. q(y)) ↔ ∃ y. p(x) → q(y);

7. Exor : (∃ x. p(x) ∨ q(x)) ↔ ((∃ x. p(x)) ∨ (∃ x. q(x)));

8. Exands : (∃ x. p(x) ∧ q(y)) ↔ (∃ x. p(x)) ∧ q(y);

9. Exors : (∃ x. p(x) ∨ q(y)) ↔ (∃ x. p(x)) ∨ q(y);

10. Alland : (∀ x. p(x) ∧ q(x)) ↔ ((∀ x. p(x)) ∧ (∀ x. q(x)));

11. Allands : (∀ x. p(x) ∧ q(y)) ↔ (∀ x. p(x)) ∧ q(y);

12. Allors : (∀ x. p(x) ∨ q(y)) ↔ (∀ x. p(x)) ∨ q(y);

Note that these rules allow to shift quantifiers in a formula (possibly with renaming of boundedvariables). Specifically, all quantifiers can be shifted to the beginning of a formula so that the bodyis quantifier free (the only problem being equivalences, which must be first split into a conjunctionof two implications). The resulting normal form is not unique. It is called a prenex form.

Exercise 1.6 Predicate logicIn this exercise you have to invent formulas yourself. Note that you cannot use arbitrary

variables, but only those that are declared in the specification! (Try the menu command View –Specification or click in daVinci on the node and select ‘View’.)

Work on the specification predlogic, use basic rules or not, and any heuristics you like. Solvethe following tasks

1. prove exall-allex : (∃ x. ∀ y. pr(x,y)) → ∀ y. ∃ x. pr(x,y) ;

2. prove allex-exex : (∀ x. ∃ y. pr(x,y)) → ∃ x. ∃ y. pr(x,y) ;

3. prove not-exall : pr(a, a), pr(b, b), ¬ pr(a, b), ¬ pr(b, a), ∀ x. x = a ∨ x = b ¬ ((∀ y. ∃ x. pr(x,y)) → ∃ x. ∀ y. pr(x,y));

4. Show that the following quantifier shift is not valid by adding a suitable precondition so thatthe sequent becomes provable (similar to the previous task).

not-exand : 〈 add precondition here〉 ¬ ((∃ x. p(x) ∧ q(x)) ↔ ((∃ x. p(x)) ∧ (∃ x.q(x))));

5. Show that the following quantifier shift is not valid.

not-allor : 〈 add precondition here〉 ¬ ((∀ x. p(x) ∨ q(x)) ↔ ((∀ x. p(x)) ∨ (∀ x.q(x))));

6. Transform the following formulas into a prenex form and prove that the original form isequivalent to the prenex formula.

prenex1 : ((∀ x. p(x) → pr(x,y)) → ((∃ y. p(y)) → (∃ z. pr(y,z))))↔ 〈 add prenex form here〉 ;

7. prove pelletier19 : ∃ x. ∀ y. ∀ z. (p(y) → q(z)) → (p(x) → q(x)) ;

This exercise shows a weakness of the sequent calculus because it is not possible to applyrules inside a formula. The first rule to apply must be exists right, but it is unclear whatinstance to use.

Page 28: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 2. PREDICATE LOGIC PROOFS IN KIV 27

The formula is in prenex form. Untransform the formula on a piece of paper using theshift rules of the previous exercise to obtain a formula where the quantifiers are inside thepropositional junctors. Solve this goal (again on paper). Inspect which quantifiers areinstantiated with which variables (and why). Then solve the original goal.

Exercise 1.7 Predicate logicWork on the specification predlogic, use basic rules or not, and any heuristics you like. For-

malize and prove the following statements:

1. A barber is a man who shaves precisely those men who do not shave themselves.

It follows that no barber exists.

(use barber(x) and shaves(x,y))

2. Everybody loves my baby, but my baby loves nobody but me.

This means that ‘me’ and ‘baby’ are identical.

(use loves(x,y), baby, and me)

3. If everyone loves somebody and no one loves everybody, then someone loves some and doesn’tlove others.

(use loves)

Remember that you can only use the symbols of the specification. This is also true for variables.The specification contains the variables x, y, z, etc., that you have to use.

Exercise 1.8 Natural numbersIn the specification nat, the natural numbers are specified. This specification contains the

constant 0, the successor function succ, and an (infix) addition function +. The axioms, whichdescribe the natural numbers are

distinctiveness : 0 �= succ(n);injectivity : succ(m) = succ(n) ↔ m = n;add-zero : n + 0 = n;add-succ : m + succ(n) = succ(m + n)

plus the induction principle expressed through the generated by clause as described in chapter 1.3.(Note: you can view the specification with the command View – Specification.)

Prove with the basic rules and without heuristics the correctness of the following theorems:

lem-01 : 0 + n = nlem-02 : succ(m) + n = succ(m + n)com : m + n = n + m

Hint: The first two theorems are propositions which should help to prove com. Therefore provethe theorems in the above order without the use of com. All proofs need induction.

Exercise 1.9 RewritingThis exercise shows that it must not be tedious to prove the theorem from the exercise above.

The convenient proof technique is called “term rewriting”. This proof method uses equationsσ = τ in the following way as “rewrite rules”: If there is an instance of the term σ in the goalit will always be substituted through the corresponding instance of τ . (This requires that allvariables of τ also appear in σ.) Therefore τ should be ‘easier’ than σ. The substitution of termsthrough easier ones can happen recursively as long as possible. Term rewriting is (beneath otherthings) done by the simplifier rule from the normal calculus.

Switch off the basic rules by using the menu command Control – Options, and unmark theoption Use Basic Rules. Now try the proofs for lem-01, lem-02, and com again (with ProofReprove). If a theorem was successfully proved, it will used as a simplifier rule in the followingproofs. You can also use heuristics for the proof if you want. Therefore select PL Heuristics +Struct. Ind..

Page 29: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 3

Simplification

3.1 General Comments

Deduction on algebraic specifications in KIV is mainly based on the idea that most proof stepsof predicate logic proofs (especially the steps that can be done automatically) are simplificationsteps. We use “simplification” in an intuitive way, so it may depend on the ideas of the user. Acomplete proof for a formula ϕ is in this point of view a special case where ϕ is simplified to the(“simplest”) formula true.

KIV is told about the exact nature of simplification steps by giving simplifier rules. Simpli-fier rules are sequents whose syntactical form describes what simplification step should be done.Simplification steps must obviously be correct, but they are also required to be invertible: the ap-plication of an inverted (“complicating”) step must also correct. This implies that it is impossiblethat a provable goal becomes unprovable by simplification. We treat here only two forms, the restis described in appendix A.

Important: One of the main obstacles to using KIV effectively, is to understandwhat exactly the effects of a simplifier rule are. Adding simplifier rules blindly (justbecause this is offered) is a very bad idea. In particular it may lead to infinite loopsin the simplifier.

3.2 Typical simplification steps

Typically one can distinguish between two sorts of simplification steps:

• formula substitution steps: In this case a formula is substituted by a simpler one. Typicalexamples are the substitution of formulas of the form ϕ ∧ ϕ by ϕ, and the substitution of¬ σ < succ(τ) by τ < σ. The first rule is independent of concrete data types, the secondone depends on the data type (it is only valid for natural numbers).

• term rewriting steps: In this step a term is rewritten to another, simpler one. A typicalexample is the simplification of a term (σ + τ) − τ to σ. Term substitution steps alwaysdepend on the data type.

Application of data type independent simplification steps is built into the KIV rule ’simplifier’.All propositional simplifications are done. In particular all propositional rules of sequent calculuswith one or no premise are applied. Also, e.g. a formula of the form ϕ → ϕ ∧ ψ is simplifiedto ϕ → ψ. The quantifier rules ’all left’ and ’exists right’ that drop quantifiers in favor of newvariables are applied too. Quantifiers of the form ∃ x.x = τ ∧ ϕ are simplified to ϕτx. Equation ofthe form x = τ are inserted and the equation is dropped afterwards.

Data type dependent simplification steps may often be used only if certain preconditions arefulfilled. An example is (n −m) + n = n which may only be applied if m ≤ n (otherwise n −m

28

Page 30: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 3. SIMPLIFICATION 29

yield an unspecified number, and the equation may be false). The validity of preconditions canbe shown in KIV in two ways:

• recursive call of the simplifier: This strategy attempts to simplify the precondition to true.This is the common strategy in most systems (there are also many automated provers whichcombine this strategy with the search for simplification rules according to certain strategies).But there is one disadvantage in this strategy: It is very inefficient because it invests a largeamount of time in the attempts to prove these rules (especially if the attempt fails). Fur-thermore, using this strategy makes it very obscure what happens during the simplification.Therefore KIV usually does not call the simplifier recursively to prove the preconditions ofa rule but uses the following strategy:

• search for preconditions: With this strategy the system tries to find the precondition in thesequent. This corresponds to the first strategy, but instead of proving the precondition withthe full simplifier it is only tested on “is axiom”. This strategy is obviousely weaker than thefirst one and leads often to the fact that variants of preconditions are needed. In the aboveexample a variant with the stronger precondition m < n (instead of m ≤ n is often needed.

The user can decide which variant to use by placing a precondition in the antecedent (firststrategy) or before an implication (second strategy). We have found that the first strategy isusually too inefficient, even if it does some more small proofs can be found automatically. Thereforewe typically use the second strategy.

An exception are preconditions that should always be fulfilled in ‘reasonable’ sequents. In ourexample (m − n) + n the precondition should always be true in any reasonable goal. If it is notpossible to prove n ≤ m this is usually a hint that the goal is not provable and should lead to theabortion of the whole proof. Therefore one should always try to prove n ≤ m with the simplifierto verify the precondition for the simplification of (m − n) + n to m. The correct form for thisrewrite rule therefore is

m ≤ n (n - m) + m = n

An example, where the precondition is typically not true is x �= [] → (x + y).f irst = x.first(from the list exercise at the end of the next chapter). This rule says that the first element of thelist x + y (which appends lists x and y) is the same as the first element of x, provided x is notthe empty list. Replacing (x+ y).f irst with x.first obviously makes the formula simpler, but thecurrent goal may not specify whether x is empty or not (maybe the proof requires a case split).The correct form for this simplifier rule therefore is

x �= [] → (x + y).first = x.first

It remains to explain the general form of the simplification rules for the simplification stepsshown above.

3.3 Syntactical form of simplifier rules

• term rewriting steps: term rewriting rules have the following form

Γ ϕ → τ = σ (1)

where τ is the term to be simplified, σ the result of the simplification. Γ contains thepreconditions which should be validated by a recursive call of the simplifier, ϕ are thepreconditions to be searched for. The rule has to be read as a scheme, i.e. it can be used forevery substitution of the variables by terms. There are the following restrictions for rules:

Page 31: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 3. SIMPLIFICATION 30

1. all variables contained in the sequent must already be contained in τ (i.e. if in a sequentan instance of τ is found the instantiation of the whole rule is fixed.)

2. τ must not be a variable.

3. ϕ must be a conjunction of literals (i.e. predicates and equations or their negations).ϕ may be omitted so that the succedent of the sequent is simply the equation τ = σ.

4. Γ contains no quantifiers.

• formula substitution steps: formula substitution rules have the form

Γ ϕ → (ψ ↔ χ) (2)

where ψ is the formula to be simplified, χ the result of the simplification. Γ contains (as inthe previous case) the preconditions to be proven by a recursive call of the simplifier, ϕ arethe preconditions to be searched for. The rule has to be read as a scheme as well and thereare again some restrictions:

1. all variables contained in the sequent must already be contained in ϕ and/or in ψ. Thisrestriction is weaker than above: if in a sequent an instance of ϕ and ψ is found theinstantiation of the whole rule is fixed.

2. ψ must be a literal or a negated literal.

3. ϕ must be a conjunction of literals. ϕ may be omitted so that the succedent of thesequent is simply the equivalence (ψ ↔ χ)

4. Γ contains no quantifiers.

The effect of the rule depends on the number of negations in front of ψ. If ψ = ¬ ψ1,instances of ψ1 in the succedent are simplified to χ. If ψ = ¬ ¬ ψ1 then instances of ψ1 inthe antecedent are simplified to χ. If ψ is an atomic formula (i.e. an equation or a predicateand not a negated formula) ψ is simplified to χ in the antecedent and in the succedent. Thelast case is the common one because in most cases both simplifications should be applied.

In the last case (where ψ is an atomic formula) the rule has a modified effect if χ is adisjunction or a conjunction of literals (this effect can obviously be avoided if χ is substitutedby ¬ ¬ χ). An example for this effect is the following rule:

ar = ar[n, d] ↔ ¬ n < #ar ∨ d = ar[n] (3)

Normally ar = ar[n, d] should be substituted in the succedent by ¬ n < #ar ∨ d = ar[n]since this simply leads to two formulas. Substituting it in the antecedent simply leads toa disjunction which is more difficult to read than the original formula and which can onlybe removed by an explicit case distinction. Therefore the formula is substituted in theantecedent only if one of the elements of the disjunction is already present in the succedent.This gives the following three rules:

Γ, n < #ar d = ar[n],ΔΓ ar = ar[n, d],Δ

Γ n < #ar, d = ar[n],ΔΓ, ar = ar[n, d] Δ, d = ar[n]

Γ, n < #ar, d = ar[n] ΔΓ, ar = ar[n, d], n < #ar Δ

Page 32: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 3. SIMPLIFICATION 31

3.4 Input and use of simplifier rules

Simplifier rules are added in KIV with the command Theorems - Load New as theorems. Thesequent is defined in the sequents file. In this file theorems may be marked as simplifier rules byusing the keywords used for : together with the key ‘s’ for a global simplifier rule or the key ‘ls’for a local simplifier rule (see below). An example:

lemmas

simp-rule : n < # ar → ar[n, d][n] = d ; used for : s, ls;

Another possibility is to add or delete a theorem or an axiom as a simplifier rule using a menucommand. Theorems may be used as local simplifier rules (used only in the specification they aredefined in) or as global simplifier rules in all higher specifications (or as both). Therefore thereare two commands to add (Simplifier - Add Local Simplifier Rules and Simplifier -

Add Simplifier Rules) or to delete simplifier rules (Simplifier - Delete Local Simplifier

Rules and Simplifier - Delete Simplifier Rules; the theorem itself is not deleted), in theview menu there are two commands as well. Global simplifier rules are here structured, that isthey are sorted by the subspecification they are defined in.

Application of local simplifier rules is guarded by the correctness management, i.e. the systemprevents applications which would lead to a cycle in the proof dependencies of the theorems. Localsimplifier rules are shown in the proof tree like normal lemmas as premisses. Changes in localsimplifier rules have direct effect on the proofs in which they are used. If a theorem used in aproof as local simplifier rule is deleted the proof gets invalid at once.

In contrast, global simplifier rules need not be checked by the correctness management becausethey can not lead to cyclical dependencies in proofs. The deletion of a simplifier rule or even thedeletion of the whole theorem does not make proofs in higher specifications invalid. The check ifall used simplifier rules are still marked as simplifier rules or do still exist can explicitely be doneby Specification - Check Simplifier Rules and Specification - Check Spec Theorems.It may also be delayed until the specification enters the proved state (Proof - Enter Proved

State). The advantage is that deleting a simplifier rule by accident or doing an incorrect changedoes not make all proofs invalid.

It often happens that during working on a proof a new simplifier rule is needed. This newsimplifier rule in a subspecification of the current specification should be added in the followingway:

1. Load the subspecification with File - Load or – in case it is already loaded – with File -

Specification 〈name〉 .

2. Add the theorem in the subspecification. Now you can choose between two possibilities:Either you prove the theorem at once and do not risk to use an incorrect theorem or youcan postpone the proof if you do not want to loose concentration for the main proof.

3. Add the theorem as a simplifier rule.

4. Save the subspecification with File - Save.

5. Switch back to the main specification with File - Specification 〈name〉 .

6. Continue the proof. (If the last step has been the use of the simplifier it should be pruned.Then the heuristics apply the simplifier again using the new rule.)

Page 33: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 4

Theory Proofs

In this exercise you will prove theorems over two data structures: lists and heaps. As you will seethese proofs differ from the proofs of the previous chapter. In theory proofs over lists it is veryimportant to find a suitable induction scheme and to apply the correct lemmas. For proofs aboutheaps the extensionality axiom is important.

4.1 Editing Theorems

The Specification level is used to work on a single specification. Besides viewing and printing aspecification (or parts of it) it is possible to enter and change theorems and to start and continuethe proof a theorem.

All theorems entered at this level are stored in a file called theorem base. When a specificationis selected the theorem base is loaded. So two copies of the theorem base exist while working ona specification, the “internal” version in KIV and the “external” version on disk. It is possiblethat several people work on the same unit in parallel. Therefore a locking mechanism exists whichprevents that inconsistent changes are made to the theorem base.

If you want to add a new theorem or change an existing one there are always two possibilities:The first one is to enter the theorem directly with the commands Theorems - New Theorem resp.Theorems - Edit Theorem. The system prompts for all information needed. How special symbolscan be entered in a dialog window or in a file is described in section 2.2.

The second possibility is to use the file sequents to add or change theorems. This file containsa template starting with a short description of the syntax. If the comment around (: variables

; :) is removed new variables can be defined using the same syntax as in specifications. Thetheorems can be entered between the keyword lemmas and the quotation mark according to thefollowing syntax:

<name> : <sequent> ;

used for : <some_flags> ;

comment : <some_comment> ;

where ’used for’ and ’comment’ are optional. <some comment>may be any text not containinga ’;’, <some flags> is a comma separated list with information that the lemma should be used asa simplifier rule. Since you can add or delete simplifier rules etc. by menu commands, you canalways omit ’used for’ if you want. Possible flags are:

32

Page 34: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 33

simplifier rule: simp, s, S, simplifier rule, simplifier, simplificationlocal simplifier rule: localsimp, ls, LS, local simplifier rule, locsimp,

local simplifier, local simplificationelimination: elim, e, E, eliminationforward: forward, f, Flocal forward: localforward, lf, LF, local forwardcut: cut, c, Clocal cut: localcut, lc, LC, local cut

A description of these simplifier commands can be found in chapter 3 and in appendix A.All text that is written behind the exit command is ignored by the system.

4.2 Short Description of the Menu Commands

Here all menus and the important commands are described:

• Menu File: The following commands are available:

– Save: Save all changes in the theorem base (as proofs, new theorems, . . . ). A lockingmechanism prevents two people saving the theorem base at the same time.

– Load: Load additional units to work on (units are specifications or modules). You canswitch between these units with the command Specification <name>. The commandhas a similar effect as Work on . . . on the project selection level.

– Specification <name>: Switch between different units already loaded.

– Unlock Theorem: Unlock theorems. A theorem is locked while somebody is working onit to prevent two people storing the same proof in parallel. If the system crashes orchanges are not saved a theorem may be locked when you start working on a unit. Inthis case it should be unlocked with this command.

– Unlock Proofdir: Unlock the proof directory. This is only needed if KIV was aborted.

– Go Back: Go back to the project level. All changes should be saved using File – Savefirst.

– Exit All: Go back to the project selection level. All changes should be saved using File– Save first.

• Menu Edit: Edit some files using Emacs.

• Menu Print: Print some information.

• Menu Latex: Generate LATEX files containing information about theorems, poofs, statistics,used properties and specifications. These files are stored in the directory doc.

• Menu View: View some information.

• Menu Specification: Change parts of the specification.

• Menu Simplifier: Perform changes in the simplifier. For details see chapter 3 and appendixA.

• Menu Theorems:

– Load New: Load new theorems from the sequents file.

– Enter New: Enter new theorems directely.

– Load Changed: Load changed theorems from the sequents file. Changing theorems ispossible only if you are the only one working on the unit.

– Enter Changed: Enter changed theorems directly.

Page 35: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 34

– Change Comment: Change the comment of a theorem.

– Rename: Rename theorems.

– Delete: Delete theorems. Deleting theorems is possible only if you are the only oneworking on the unit.

– View: View theorems.

• Menu Control: Change some options.

• Menu Proof:

– Begin: Begin a new proof. A locking mechanism prevents two people proving the sametheorem in parallel.

– Continue: Continue to prove a partially proven theorem.

– Load: Load the proof of a theorem and modify it.

– Reprove: Prove a theorem again starting with an empty proof.

– Begin Some: Begin new proofs for several theorems.

– Reprove Some: Prove some theorems again.

– Replay Proofs: Replay an existing proof. This command is used if some proofs areinvalid because theorems have changed.

– Discard: Should not be used.

– Delete Some: Delete some proofs. It is also possible to delete only invalid or partialproofs.

– Add Extern: Should not be used.

– Enter/Leave Proved State: Enter/Leave proved state (see project level).

4.3 Rules for Predicate Logic

The rules for predicate logic as used in KIV is similar to the set of basic rules, but in some respectsoptimized. For example, the propositional rules with two premises are combined in one rule casedistinction that can be applied context sensitively by clicking anywhere in the formula. Thepropositional rules with one premise are combined in prop simplification, which itself is subsumedby simplifier. insert spec-lemma applies a lemma as insert lemma, but from a subspecification etc.

4.3.1 General Rules

weakening

Γ′ Δ′Γ Δ

• Γ′ ⊆ Γ,Δ′ ⊆ Δ

• The formulas to discard can be selected.

cut formulaϕ,Γ Δ Γ ϕ,Δ

Γ Δ

• ϕ is the cut formula. It can be given by typing it in or by loading it from the file formulas(where it must be inclosed in %". . .").

Page 36: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 35

case distinctionψ1,Γ Δ ψ2,Γ Δ ψn,Γ Δ

ψ1 ∨ ψ2 ∨ . . . ∨ ψn,Γ Δ

ϕ, ψ,Γ Δ ¬ϕ, χ,Γ Δ

(ϕ ⊃ ψ;χ),Γ Δ

ϕ,Γ ψ,Δ ¬ϕ,Γχ, Δ

Γ (ϕ ⊃ ψ;χ),Δ• the rule is also applicable for →, ↔ and for formulas in the succedent with ∧, ↔ (yieldingan appropiate premise, of course).

insert equation

σ = τ,Γτσ Δτσ

σ = τ,Γ Δ

• The rule presents all equations σ = τ of the sequent (with both orientations). Selecting aequation replaces the left side by the right.

• The positions where σ can be replaced by τ are indicated by markers (##. . . ). You canselect some of them or “All positions”.

• The equation may be discarded in the premise.

4.3.2 Simplification Rules

simplifier

Γ′ Δ′Γ Δ

• Γ and Δ are simplified to Γ′ and Δ′ (see chapter A).

prop simplification

ϕ, ψ,Γ Δ

ϕ ∧ ψ,Γ Δ

• The rule combines the propositional logic rules with one premise, i.e. negation left/right,conjunction left, disjunction right, implication right.

• The rule is rarely needed because the simplifier rule also applies these rules. However, thesimplifier also applies rewrite rules et.al., which is sometimes undesireable.

4.3.3 Induction Rules

inductionΓ Θ(ϕ),Δ Γ,Θ(ψ) Δ ϕ, Ind-Hyp ψ

Γ Δ

• Ind-Hyp = ∀ x, u′.(u′ $ u→ (ϕ→ ψ)u′u )

• x = free(ϕ→ ψ) \{u}

• u is the induction variable

• The variant term induction allows to induct over a term τ . This is equivalent to adding anequation x = τ with new variable x to the sequent and induction on x.

• Θ is a parallel substitution for u, x

• $ is a well founded ordering

Page 37: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 36

apply induction

Γ Θ(u′)$ u,Δ Γ Θ(ϕ),Δ Θ(ψ),Γ, Ind-Hyp Δ

Γ, Ind-Hyp Δ

• Ind-Hyp = ∀ x, u′.(u′ $ u→ (ϕ→ ψ))

• Θ is a parallel substitution for x

structural induction (example)

ϕ(c) ∀ x′.ϕ(x) ϕ(f(x))Γ Δ

• ϕ =∧Γ→

∨Δ

• x′ = free(ϕ) \ x

• sort(x) generated by c, f

4.3.4 Quantifier Rules

all left/exists right

ϕτx, ∀ x.ϕ,Γ Δ

∀ x.ϕ,Γ Δ

Γ ϕτx, ∃ x.ϕ,ΔΓ ∃ x.ϕ,Δ

• An instance τ of x must be given as τ1, . . . , τn manually or chosen from some precomputedsubstitutions.

• The quantified formula may be discarded in the premise

exists left/all right

ϕx′x ,Γ Δ

∃ x.ϕ,Γ Δ

Γ ϕx′x ,Δ

Γ ∀ x.ϕ,Δ

• x′ are new variables (automatically computed)

4.3.5 Lemma Insertion Rules

insert lemma/insert spec-lemma

Γ′ Δ′ Γ Γ′τx,Δ Δ′τx,Γ Δ

Γ Δ

• Γ′ Δ′ is the theorem with free variables x.

• An instance τ of x must be given as τ1, . . . , τn manually or chosen from some precomputedsubstitutions.

Page 38: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 37

insert elim lemmaΓ′ Δ′, σ(ϕ) ∧

∧σ(Γ) σ(ψ),Θ(Γ′) Θ(Δ′)

Γ′ Δ′

• Γ ϕ→ (x1 = t1 ∧ . . . xn = tn ↔ ∃y.v = t ∧ ψ) is the elimination rule

• σ is a substitution for the free variables of the elimination rule

• Θ is the substitution σ(t1), . . . , σ(tn)← σ(x1), . . . , σ(xn)[σ(v)← σ(t)]

• For details see appendix A

insert rewrite lemma

ϕ→ σ = τ Γ Θ(ϕ),Δ ϕΘ(τ)Θ(σ),Γ

Θ(τ)Θ(σ) Δ

Θ(τ)Θ(σ)

Γ Δ

ϕ→ ψ ↔ χ Γ Θ(ϕ),Δ ϕΘ(τ)Θ(σ),Γ

Θ(χ)Θ(ψ) Δ

Θ(χ)Θ(ψ)

Γ Δ

• ϕ→ σ = τ is the rewrite theorem

• An instance Θ(σ) resp. Θ(ψ) must be contained in the sequent.

• The system offers all applicable instances. Select one of these.

4.3.6 Insert rewrite lemma

Some extra remarks about a very useful new rule: insert rewrite lemma.

ϕ → σ = τ Γ Θ(ϕ),Δ ϕΘ(τ)Θ(σ),Γ

Θ(τ)Θ(σ) Δ

Θ(τ)Θ(σ)

Γ Δ

ϕ → (ψ ↔ χ) Γ Θ(ϕ),Δ ϕΘ(τ)Θ(σ),Γ

Θ(χ)Θ(ψ) Δ

Θ(χ)Θ(ψ)

Γ Δ

Suppose you have a theorem n �= 0 → succ(pred(n)) = n, your goal contains somewhere thesubterm succ(pred(m + m0)), and you want to rewrite succ(pred(m + m0)) to m + m0. Youcan cut formula with m + m0 = 0, insert lemma the theorem, add a substitution, apply casedistinction, and insert equation. It works, but is quite tedious. Instead, you can use the ruleinsert rewrite lemma, select the theorem, and get the same result without any more interaction.You can also apply the rule context sensitive by clicking on the succ symbol in succ(pred(m + m0))(with the right mouse button). You will get a popup menu that contains only those rewrite rulesthat are applicable on the selected term. This means you don’t have to know that this rewriterules exists (and where it is stored), but can try it out.

If you select the rule from the rule list, the system displays a list with the specification, allsubspecifications, and how many potentially applicable rewrite rules they contain. Then you haveto select a specification. The system know computes those rewrite rules that are indeed applicableto the current goal. It may be that no rule remains. (The reason for this approach is that theremay be a lot of subspecifications with lots of rewrite rules – checking their applicability maybe to inefficient.) Otherwise the applicable rules are displayed. If you want to apply the rulecontext sensitive you have to click on a function (or predicate) symbol. The system will displayall rewrite rules that have this function symbol as their top- (or outer-)most function symbol,and are applicable at the current position in the goal. Be warned: this can be confusing if theoutermost symbol is an infix or postfix operation! If you click somewhere else or no rewrite ruleis applicable, nothing happens. (But context sensitive insert equation or quantifier instantiation

Page 39: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 38

works as described.) Otherwise the system will display the applicable rules with their nameand the sequent. For some rewrite rules it is not possible to automatically compute a completesubstitution. In these cases you have to select or enter a substitution as in insert lemma. Finally,the rule is applied.

There are quite a lot of theorems that can be used with this rule, but not all:

• Γ ϕ → σ = τ rewrites either σ by τ or τ by σ (comparable to insert equation where youcan also replace the left side by the right or vice versa). Γ may be empty, and ϕ → may bemissing. Γ and ϕ may be arbitrary formulas (compare this to the restricted form of rewriterules the simplifier uses).

• Γ ϕ → (ψ1 ↔ ψ2) rewrites ψ1 by ψ2 or vice versa. Again Γ and ϕ → may be missing.However, there are restrictions on the formula to rewrite: To rewrite ψ1 by ψ2, ψ1 must bea literal.

• Γ ϕ → ψ where ψ is a predicate or a negated predicate.Read this as Γ ϕ → (ψ ↔ true/false).

And finally one word of warning about the simplifier: You can’t do serious proofs without thesimplifier (as you will probably notice very fast). But it may do things you didn’t intended it todo. For example, if you insert a lemma that is also a simplifier rule the simplifier will probably‘remove’ the lemma from your goal by rewriting it (with the lemma) to true. This particularlyhappens if you use the simplifier heuristic, which you should do. In such a case you must

1. turn the heuristics off (by clicking on ‘Use Heuristics’ in the lower left corner of the proofwindow),

2. prune the last proof step in the proof window,

3. use the lemma as you intended it (e.g. with insert equation),

4. and turn the heuristics on again.

insert rewrite lemma avoids this phenomenon. So use this rule whenever possible!

4.4 Predefined Sets of Heuristics

Heuristics are used to decrease the number of user interactions. In the best case they find proofsautomatically. Even if a proof is not found completely automatically heuristics can help the user byapplying often used, mechanical rules automatically. But there is also a risk when using heuristics:They may apply steps which are unnecessary or even unwanted.

During a proof heuristics can be enabled and disabled at any time (using the command Control

– Heuristics). Therefore heuristics can be used for a single branch of the proof or for the wholeproof. An important property of heuristics is that there is an arbitrary hierarchical ordering: Ifa heuristic can’t be applied the next heuristic according to the hierarchical ordering is tested.Furthermore a heuristic can determine which other heuristics should be applied next. Thereforeheuristics are a very flexible concept.

To choose a good set of heuristics some experience is needed. To simplifiy matters KIV of-fers three predefined sets of heuristics which are usually sufficient. Therefore after selecting thecommand Control – Heuristics a window is displayed where a set of heuristics can be chosen:

Let the system choose the heuristics

PL Heuristics + Induction

PL Heuristics + Case Splitting

PL Heuristics

No heuristics at all

Select your own heuristics

Read from file ’default heuristics’

Page 40: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 39

Let the system choose the heuristics : If this option is selected KIV chooses one of the setsof heuristics described below. The criterion is a very basic estimation of the complexity ofthe sequent to be proven (i.e. number and kind of formulas and their combinations). Thisis an experimental feature and is not recommended.

PL Heuristics + Induction : This set of heuristics is best fitting for simple goals. The proofidea should be induction, and it shouldn’t be necessary to avoid case distinctions. This setof heuristics finds proofs often fully automatically. The following heuristics are contained:

simplifier, elimination, module specific, Quantifier closing, cut, if-then-else split,pl case distinction, structural induction

PL Heuristics + Case Splitting : This set of heuristics is used for more complex goals. It isused e.g. for uncommon inductions or if some lemmas have to be applied first. In contrastto the heurisics for simple goals the induction heuristicand some heuristics that introducecase distinctions are missing. This set contains the following heuristics:

simplifier, elimination, module specific, Quantifier closing, weak cut, if-then-elsesplit

PL Heuristics : This set of heuristics is used for very complex goals where case distinctions mustbe avoided. It contains the following heuristics:

simplifier, elimination, module specific, Quantifier closing

No heuristics at all : All heuristics are disabled.

Select your own heuristics : You can choose yourself which heuristics you want to use, oryou can modify the current selection. A description of the heuristics is given in the nextsection.

After selecting this command a window opens containing two columns: on the left side allavailable heuristics are displayed, on the right side the currently selected heuristics are shownin order of selection. To select a heuristic click on this heuristic on the left side. It appearson the right side at the position of the black bar. To delete a heuristic currently selectedclick again on the heuristic in the left column. After leaving the window by clicking on theOK–Button the selected heuristics are applied according to their order.

Read from file ’default heuristics’ : The file ’default-heuristics’ should contain a PPL listof heuristics: (list "..." "..." ...). This option is for experts only.

When you begin (or continue) a proof all heuristics are disabled (but still selected).

4.5 Description of the Heuristics

Induction

induction

This heuristic applies the rule induction if a suitable induction variable and an ordering is found.Induction orderings are found in the heuristic info where size functions (as the length of a list orthe number of elements of a set) are listed. If a data-specification is installed size functions andorder predicates are automatically inserted into the heuristic info. Additional size functions canbe added using the command Add Heuristic Info.

The induction rule is applied only once in each branch of a proof.

Page 41: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 40

structural induction

This heuristic applies the rule structural induction on first order goals trying to find an inductionvariable. This heuristic applies the structural induction only once in each branch.

apply ind once

This heuristic applies the induction hypothesis (i.e. the rule apply induction) if a suitable instanceis found. The same mechanism is used to find instances as is used to search for substitutionproposals if the rule is used in an interactive way.

This heuristic does not apply the induction hypothesis if it was applied already in this branchby any heuristic or by the user. Therefore it cannot lead to infinite loops.

apply ind

This heuristic applies the induction hypothesis always if an instance is found. Therefore it canlead to infinite loops (not recommended).

apply ind closing

This heuristic applies the induction hypothesis if this closes the goal at once. It can’t lead towasted applications of rules or infinite loops but is used rather seldom.

Simplification

simplifier

This heuristic decides when the simplifier (i.e. the rule pl simplifier) should be applied on a goal.The simplifier is called only if the goal has changed or the number of predicate logic formulas isincreased. This heuristic should be used always.

pl case distinction

This heuristic resolves propositional logical combinations into case distinctions.

Other Heuristics

module specific

This heuristic is controlled by the information provided in the file module-specific. It is used forspecific treatment of different modules or specifications (see appendix G).

batch mode

This heuristic changes the goal to be proven. If this heuristic is added after all other heuristics itis only applied if no other heuristic can be applied. The program works as long as possible withouthuman interactions. It stops if a goal is reached again that was treated before.

elimination

This heuristic applies the rule insert elim lemma (see appendix 4.3.1 and A.5).

var elimination

This heuristic applies the rule insert elim lemma (see appendix 4.3.1 and A.5) only if the term tobe eliminated is a variable.

Page 42: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 41

Quantifier closing

This heuristic tries to find instances for quantified variables which close the goal at once. It appliesin these cases the rules all left and exists right resp.

Quantifier

This heuristic instantiates quantifiers if a sensible instance is found even if the goal is not closed atonce (here unification and a heuristical measure for “suitable” of instances is used). This heuristiccan lead to wasted instantiations.

weak cut

This heuristic applies cut rules on a sequent (see appendix A.6).

cut

This heuristic applies cut rules on a sequent as weak cut but applies a cut with ϕ if ϕ is an atomand ϕ ∨ ψ is contained in the antecedent of a goal (or ϕ ∧ ψ in the succedent).

if-then-else split

This heuristic applies case distinction on if-then-else’s.

4.6 Exercise 2

Select the project Exercise2. It contains several specifications. nat-basic1, nat-basic2, and natcontain the natural numbers, and are of no further interest.

The specification list-basic defines lists of natural numbers. It specifies various list operations,and has several unproved theorems. Your task is to prove these theorems. You can use the basicrules (to get a feeling for the proofs) or the normal set of rules (described in appendix 4.3.1). Noteespecially the rule insert elim-lemma which is very helpful. You can also use any heuristics youlike (see appendix 4.5). You can also invent new theorems (provided you prove them), but it is notnecessary. Note that the option ‘Use only proved locals’ is active. Its effect is that the simplifierwill only use theorems for simplification that are already proved (including all used theorems inthe proof). The advantage is that a simple theorem is not proved unintentionally with a complexone. (This can lead to problems if the proof of the complex theorem requires the simple theorem.)On the other hand, the order in which the theorems are proved has a significant impact on thesimplicity of the proofs. To make things easier, we provide a suitable order for you.

Exercise 2.1 (list-basic)The specification list-basic defines lists and elements. The elements have a total irreflexive

order < (note that < is also the symbol for less on the natural numbers). This is later needed tosort lists. [ ] is the empty list, + is used to add an element to the front of the list. + is also usedto append two lists (and it also denotes addition of natural numbers). The postfix operators .firstand .rest select the first element and the rest of a nonempty list. # is the length of the list, ∈tests if an element occurs in a list.

list-basic =enrich nat with

sorts elem, list;constants [ ] : list;functions

Page 43: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 42

. + . : elem × list → list prio 9;

. + . : list × list → list prio 9;

. .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 [ ], +;

axioms

irreflexivity : ¬ a < a; used for : s,ls;transitivity : a < b ∧ b < c → a < c; used for : f,lf;totality : a < b ∨ a = b ∨ b < a; used for : s,ls;constructors : [ ] �= a + x; used for : s,ls;first : (a + x).first = a; used for : s,ls;rest : (a + x).rest = x; used for : s,ls;append-base : [ ] + x = x; used for : s,ls;append-rec : (a + x) + y = a + x + y; used for : s,ls;size-base : #([ ]) = 0; used for : s,ls;size-rec : #(a + x) = #(x) + 1; used for : s,ls;In : a ∈ x ↔ (∃ y, z. x = y + a + z);

end enrich

The following theorems are already proven. All except the last theorem deal with the simpli-fication of the total order < on elements. The last theorem is a very elementary property of lists,but it requires a little trick to prove.

lel: a < b ∧ b = c → a < c; used for : f, lf ;lel-01: a < b ∧ a = c → c < b; used for : f, lf ;loc: ¬ a < b ↔ ¬ ¬ (a = b ∨ b < a); used for : ls ;nen: ¬ b < a ∧ b = c → ¬ c < a; used for : f, lf ;nen-01: ¬ b < a ∧ a = c → ¬ b < c; used for : f, lf ;nll: ¬ b < a ∧ b < c → a < c; used for : f, lf ;nnn: ¬ c < b ∧ ¬ a < c → ¬ a < b; used for : f, lf ;seq: ¬ b < a → (¬ a < b ↔ a = b); used for : s, ls ;sls: a �= b → (¬ a < b ↔ b < a); used for : s, ls ;injectivity: a + x = b + y ↔ ¬ ¬ (a = b ∧ x = y); used for : s, ls ;

These operations are the most basic list operations. Many more can be defined with them.However, as you will see, they allow to formulate quite complicated theorems.

Task: Prove the following theorems in specification list-basic:

elim-list-c: x �= [ ] a = x.first ∧ y = x.rest ↔ x = a + y;case: x = [ ] ∨ x = x.first + x.rest;exrew: x �= [ ] ↔ ∃ a, y. x = a + y;ex: x �= [ ] ∃ a, y. x = a + y;append: x + [ ] = x;append-01: x + y = x + z ↔ y = z;append-02: x + y = [ ] ↔ x = [ ] ∧ y = [ ];append-04: x = x + y ↔ y = [ ];

Page 44: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 43

associativity: (x + y) + z = x + y + z;first-append x �= [ ] → (x + y).first = x.first;rest-append x �= [ ] → (x + y).rest = x.first + y;first-split: y �= [ ] a + x = y + z ↔ a = y.first ∧ x = y.rest + z;first-split-01: y �= [ ] y + z = a + x ↔ a = y.first ∧ x = y.rest + z;length: #(x + y) = #(x) + #(y);zero-length: #(x) = 0 ↔ x = [ ];append-05: x = y + x ↔ y = [ ]; Hint: no struct. ind., use theorem lengthappend-03: x + y = z + y ↔ x = z;append-06: x + a + y = z + y ↔ x + a + [ ] = z;

Hint: no struct. ind., use append-03append-07: x + a + y = z + b + y ↔ x = z ∧ a = b;in-empty: ¬ a ∈ [ ]; Hint: no struct. ind., use axiom Inin-cons: a ∈ b + x ↔ ¬ ¬ (a = b ∨ a ∈ x); Hint: no struct. ind., use axiom Inin-append: a ∈ x + y ↔ ¬ ¬ (a ∈ x ∨ a ∈ y);lastdiv: x �= [ ] ↔ (∃ y, a. x = y + a + [ ]);lastoc: a ∈ x ↔ (∃ y, z. x = y + a + z ∧ ¬ a ∈ z);split-first: n ≤ #(x) ∃ y, z. x = y + z ∧ #(y) = n;firstoc: a ∈ x ↔ (∃ y, z. x = y + a + z ∧ ¬ a ∈ y);len-01: #(x) = #(z) → (x + y = z + y0 ↔ x = z ∧ y = y0);split-rest: n ≤ #(x) ∃ y, z. x = y + z ∧ #(z) = n;

Hint: no struct. ind., use split-first

Some comments: All theorems without a hint can be proved by simple structural induction.However, you have to find the correct variable for structural induction. (And correct instances forquantifiers, and the right lemmas to use, etc.) append – zero-length are some simple propertiesthat are needed in lots of other proofs. They are all simplifier rules. append-05 – append-07 arealso very useful simplifier rules, but more tricky to prove. in-empty and in-cons could be usedas axioms instead of the declarative axiom In. With these two simplifier rules it is possible toprove other properties about ∈ with structural induction. lastdiv is also a useful theorem. lastocand split-first are needed for the remaining theorems. They are more or less tricky to prove, butindependent from each other.

Exercise 2.2 (list-last)Specification list-last defines two new functions .last and .butlast. Both are written postfix

(like .first and .rest). x.last selects and x.butlast removes the last element of a non-empty list.They are specifiied with the axiom

Last: x �= [] → x.butlast + x.last = x

Task: Prove the following theorems in specification list-last:

one-attach: a + [] = x + a0 + [] ↔ a = a0 ∧ x = []last-elim: x �= [] a = x.last ∧ y = x.butlast ↔ x = y + a + []b: (a + []).butlast = []b-02: (a + x).butlast = [] ↔ x = []butlast-def: (x + a + []).butlast = xl: (a + []).last = al-05: (a + b + x).last = (b + x).lastlast-def: (x + a + []).last = a

Page 45: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 44

Hint: None of the proofs needs induction. last-elim is an elimination rule (see appendix A.5for a detailed description) that can be used to get rid of the .last and .butlast function.

Page 46: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 45

null.nxt

c

r

ba.nxt .nxt

Figure 4.1: representation of list [a,b,c] in a heap

4.7 Exercise 2, Part 2

Exercise 2.3 (heap)Specification Ref defines a sort Ref of references to be used as addresses in a heap (with typical

variable r : Ref). Nothing is known about references except that there is a null pointer null : Ref.Specification heap defines heaps. A heap H can allocate any finite number of adresses (we

ignore running out of memory). There is a predicate r ∈ H that checks, whether a reference isallocated. A memory cell, that an allocated reference points to, stores a value of type cell. We donot fix what memory cells contain (they could store any object), but we require that the objecthas at least a .nxt-reference (i.e. a field in object-oriented terms). As an instance, in a low-levelrepresentation of lists, a cell would store both a value (in some .val field) and a next-pointer: itwould be a pair of the two fields. A heap H that stores a list with elements a,b,c at reference rcould look like in Fig. 2.3.

To access a cell stored at some reference, a function

. [ . ] : Heap × Ref → cell;

is defined, which is written similar to array access. When r is allocated (if r ∈ H), thenH [r] gives the cell stored at reference r. Otherwise, the function is unspecified, i.e. it gives somearbitrary value.

To construct heaps, two constructors are defined. The empty store, written ∅, which has noallocated reference, as stated by the axiom

In-empty: ¬ r ∈ ∅

The second constructor

. [ . , . ] : Heap × Ref × cell → Heap;

stores a cell under some reference (the KIV specification has only one dot between the brackets.The convention is that the first arguments is before the brackets, all the rest are between them).H [r, ce] is a modified heap, that stores ce at r. In programs we will later on write an assignmentH [r] := ce to create such a modified heap. If r was not already allocated in H , it is added to theallocated references. We therefore have the axiom

In-insert: r ∈ H[r0,ce] ↔ r ∈ H ∨ r = r0

If the reference r was already allocated in H , then the cell at r is overwritten with the new contentce. Accessing a modified heap is therefore specified with the axioms

At-same: H[r, ce][r] = ce;At-other: r �= r0 → H[r0, ce][r] = H[r];

Page 47: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 4. THEORY PROOFS 46

Finally we have a function

new: Heap → Ref

that gives a new element not yet allocated in H (axiom ¬ new(H) ∈ H). The new reference isnot the null pointer (axiom new(H) �= null). The theorems we prove do not use this function.

Heaps satisfy a structural induction principle with two cases for the constructors ∅ and . [ . , . ](similar to the one for lists with constructors [] and +). But this induction principle is more difficultto use since putting an element at an address may overwrite: the heap before modification mayallocate the same number of elements, so it may not be smaller (we may even have H = H [r, ce]).This was simpler for lists: given a + x, x is always smaller. It turns out, that a specification thatspecifies exactly heaps and no other data type (a so-called monomorphic specification) needs anadditional axiom, called the extensionality axiom.

Extensionality: H1 = H2 ↔ (∀ r. (r ∈ H1 ↔ r ∈ H2) ∧ (r ∈ H1 → H1[r] = H2[r]);

The axiom specificies, that two heaps H1 and H2 are equal, if and only if they have the sameallocated references, and if acessing any allocated references gives the same content. This axiomis always needed, when we want to prove that two heaps are equal (or different).

Task: Prove the following theorems in specification heap:

insin: r ∈ H[r, ce]in-neq: r1 �= r2 → (r1 ∈ H[r2, ce] ↔ r1 ∈ H)neq: H[r, ce] �= ∅At-in-out: r ∈ H ∧ ¬ r0 ∈ H → H[r0, ce][r] = H[r]rew: r1 �= r2 → H[r1, ce1][r2, ce2] = H[r2, ce2][r1, ce1]insins: H[r, ce0][r, ce] = H[r, ce]put-neq: ce �= ce0 → H[r, ce] �= H0[r, ce0]inj-put: ¬ r ∈ H ∧ ¬ r ∈ H0 → (H[r, ce] = H0[r, ce] ↔ H = H0)ins-same-01: r ∈ H → H[r, H[r]] = Hins-same: H[r, H[r]] = H ↔ r ∈ Hdel-exists: r ∈ H ∃ H0. ¬ r ∈ H0 ∧ H = H0[r, H[r]]exin: r ∈ H ↔ (∃ ce, H0. H = H0[r, ce] ∧ ¬ r ∈ H0)exnotempty: H = ∅ ↔ ¬ ∃ r, ce, H0. H = H0[r, ce] ∧ ¬ r ∈ H0

Hints: Many proofs require extensionality to prove that two heaps are equal. No induction isused except for del-exists, which is the most complex proof. It shows, that for any heap withallocated reference r there is a smaller heap H0, which did not have r allocated. H can be createdfrom H0 by allocating r and writing H [r]. In the inductive case of this proof, where the heap Hhas the form H1[r0, ce0], the cases r ∈ H1 and r = r0 must be considered separately. Lemma rewis useful. The last two lemmas make use of del-exists.

Page 48: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 5

Algebraic Specifications

The KIV system is based on structured algebraic specifications. In this chapter we describe thesyntax of structured algebraic specifications and a methodology for their development. A formaldescription of the syntax of structured algebraic specifications is given in appendix D, a grammarof dynamic logic is given in appendix C. A more detailed description of the simplifier (with someadditional features) can be found in appendix A.

5.1 Structured Algebraic Specifications

Basic Specifications

A basic specification consists of three parts: a description of the signature, the axioms and theprinciples of induction. A basic specification begins with the keyword specification and thedeclarations of sorts, constants, functions, predicates and variables. After the keyword induction

follow the principles of induction consisting of ‘generated by’-clauses (separated by ‘;’). Next arethe axioms (after the keyword axioms, separated by ‘;’). The specification ends with the keywordend specification. Here is as an example a specification of the integers:

specificationsorts int;constants 0,1 : int;functions . +1 : int → int;

. –1 : int → int;

. + . : int × int → int;

. * . : int × int → int prio 10;# . : int → int;

predicates . < . : int × int;variables x,y,z : int;induction

int generated by 0, +1, –1;axioms

x +1 –1 = x; x –1 +1 = x; 1 = 0 +1;¬ x < x; x < y ∧ y < z → x < z;x < x +1; x +1 < y +1 ↔ x < y;x + 0 = x; x + y +1 = (x + y) +1;x ∗ 0 = 0; x ∗ y +1 = x ∗ y + x;¬ x < 0 → # x = x; x < 0 → # x + x = 0;

end specification

In the example, infix, prefix, and postfix declarations are used. Normal function applicationbinds more tightly than postfix application, postfix binds more tightly than prefix, infix operations

47

Page 49: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 48

have the lowest priority. Infix operations have a priority given with ‘prio n’ with (6 ≤ n ≤ 15).If it is omitted it defaults to 9. The additional keyword left indicates that the function is leftassociative (otherwise it binds to the right). Functions and predicates with higher priorities bindmore tightly than those with a lower one. Some examples:

x + y + z ≡ x + (y + z)

x ∗ y + x ≡ (x ∗ y) + x

x + y +1 ≡ x + (y +1)

# x +1 ≡ #(x +1)

#x + x ≡ (#x) + x

A detailed explanation of all mixfix notations and all possibilities for overloading can be found inappendix B.

The following propositional logical operations are predefined: ¬ , ∧ , ∨ , → , ↔ , ⊃ (inorder of binding: ¬ binds more tightly than ∧ , ∧ binds more tightly than ∨ , . . . ). (ϕ ⊃ ψ;χ)is an if-then-else operation meaning if ϕ then ψ else χ. For first order logic the Quantors ∀ and ∃are predefined. They have always the largest possible scope. Some examples:

¬ x ∧ y ≡ (¬ x) ∧ y

(x → y ⊃ ¬ z; y ↔ z) ≡ ((x → y) ⊃ (¬ z); (y ↔ z))

∀ x. f(x) ∧ g(x) ≡ ∀ x. (f(x) ∧ g(x)) but (∀ x. f(x)) ∧ g(x)

It is also possible to enter the name of the operation as not, and, or, . . . .

Generic Specifications

In contrast to basic specifications, generic specifications have a parameter. Typical examples forgeneric specifications are sets or lists where the elements form the parameter or arrays and storeswith the data stored in them as parameter. In most cases the parameter is a basic specificationwhich only defines the name of the parameter sort and a few properties (e.g. that there is anordering on the elements or that a ‘default’ constant exists). A parameter specification maynot be generic itself. Usually it contains no ‘generated by’ clauses (because this restricts thepossible elements too much). Their sorts and operations are called parameter sorts and parameteroperations respectively. All other sorts and operations of a generic specification are called targetsorts and target operations. The syntax of generic specifications begins with the keywords genericspecification and parameter followed by the name of the parameter specification. The optionalkeyword using starts a list of additionally used specifications (separated by comma). Frequentlythe specification of natural numbers is used as an index sort, e.g. in the specification of arrays.Used specifications may be generic. Their parameters are added to the parameter of the wholespecification. After the keyword target the description of sorts, constants, functions, predicates,generated by clauses and axioms is given in the same syntax as in a basic specification. Thespecification is terminated by the keyword end generic specification. The parameter of ageneric specification may be instantiated by an actualization (see below). An example for ageneric specification is the following specification of arrays.

generic specificationparameter elem-specusing nat-spectargetsorts array;functions mkarray : nat → array;

. [ . ] : array × nat → elem;

. [ . ] : array × nat × elem → array;# . : array → nat;

Page 50: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 49

variables ar, ar0, ar1, ar2 : array;induction

array generated by mkarray, [ ] :: (array × nat × elem → array);axiomsExtension : ar1 = ar2 ↔ # ar1 = # ar2 ∧ ∀ n. n < # ar1 → ar1[n] = ar2[n]; used for : ls;Size-mkarray : # mkarray(n) = n; used for : s,ls;Size-put : # ar[n, a] = # ar; used for : s,ls;Put-same : m < # ar → ar[m, a][m] = a; used for : s,ls;Put-other : m �= n → ar[n, a][m] = ar[m]; used for : s,ls;

end generic specification

This specification is also used in chapter 5.2 as an example for the specification methodology inKIV. The parameter specification elem-spec declares only the sort elem and the variables a, b, c(KIV requires to declare at least one variable for every sort). The specification introduces furtherpossibilities. . [ . ] is used to declare a mixfix notation so that array access can be written asusual. Updating an array is written as ar[m, a] (the array ar is updated at index m with valuea). Because [] is overloaded we have add the types of the operation in the induction principle ( ::(array × nat × elem → array)). The axioms have names and hints for the simplifier (used for: s,ls;).

Union Specifications

One possibility to combine several specifications is to unite them into one specification. Thesyntax of a union specification begins with the keyword union specification followed by thespecifications (separated by ‘+’) und the keyword end union specification. Signature, axioms,and parameters of a union specification are as expected the unions of the signatures, axioms andparameters of the subspecifications.

Enrichments

Another possibility to create larger specifications from smaller ones is the enrichment by new sortsand operations. These are added to the specification. The parameter of the enriched specificationis the parameter of the subspecification. (A specification cannot be enriched by parameter opera-tions. New parameter operations are needed very rarely, and the corresponding enrichment can besimulated by an actualization.) The syntax of an enriched specification starts with the keywordenrich and the name of the specification to be enriched. It is possible to give several specificationsseparated by comma. Then the union of these specifications is enriched. After the keyword with

the new signature, induction principles, and axioms are added. The enriched specification endswith the keyword end enrich.

Actualizations

Instances of generic specifications like sets of numbers, lists of booleans, or arrays of lists of elements(the instance may again be generic!) are created by actualization. An actualization consists ofthree parts: First, a parameter specification to be instantiated. This is in the most simple case ageneric specification, but may also be every other specification containing a parameter. Second,the parameter is instantiated by one or more actual specifications. The actual specification maybe parameterized.

The third part is a mapping called morphism between the parameterized and the actual spec-ification. It must fulfill several requirements that are demonstrated with the following example,the actualization of the elements of the generic arrays with booleans:

Parameter In most cases, each parameter sort and operation of the parameterized specificationis mapped to sorts and operations of the actual specification. In our example the parameter sort

Page 51: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 50

‘elem’ is mapped to the sort ‘bool’. The variables a, b, c must also be mapped to boolean variables.Their names can be new (i.e. not existing in the bool specification).

Parameter sorts and operations of the parameterized specification which are not mapped tosomething are not actualized. They form – together with the parameter of the actual specification– the parameter of the instance. In the example below there are no such sorts. An example is theacualization of only one of two parameters (e.g. of pairs).

It’s obvious that in an actualization of a parameter sort by a sort of the actual specificationall operation symbols of the parameter containing this sort as argument or target sort must alsobe mapped to an operation symbol and vice versa. Furthermore it’s possible to actualize severalparameter sorts by the same sort.

Target The target sorts and operations of the parameterized specification can – but need notbe – renamed during the actualization. A renaming must be injective, the results of a renamingmay not be contained in the actual specification.

The syntax of on actualization starts with the keyword actualize followed by the parameter-ized specification. After the keyword with, a list of actual specifications (separated by comma),and the keyword by morphism, a list (separated by ‘;’) of renamings of sorts and operations inarbitrary order follows. A renaming consists of the symbol to be renamed, the implication symbol‘→’ (or ‘->’), and the renamed symbol. Usually infix, prefix, and postfix declarations, and priori-ties are inherited by the renamed symbol. The default can be changed by adding dots in front ofor behind the symbol and by a priority declaration. A ‘prio 0’ declaration creates an ‘ordinary’(non-infix, non-prefix, non-postfix) symbol.

In this example arrays are actualized by booleans:

actualize array-specwith bool-specby morphism

(: parameter :)elem → bool; ; a → boolvar; b → boolvar0; c → boolvar1;(: No target renamings in this actualization :)

end actualize

The sort mapping automatically changes the types of the array operations, e.g. . [ . ] : array× nat → elem is changed to. [ . ] : array × nat → bool.

Renamings

The sorts and operations of a specification may be renamed by an injective morphism. A renamingspecification starts with the keyword rename and the specification whose sorts or operations shouldbe renamed. After by morphism a list of renamings follows as described in the case of actualization.The specification ends with end rename.

Data Type Specifications

Often the constructors of a sort have the property that two different constructors always yield twodifferent objects, and that each application of a constructor yields a new object. Data type speci-fications provide a convenient way to specify such sorts and their constructors. More specifically,they are useful if:

• All syntactically different terms built up from the constructors denote different values (Theconstructors are the constants and functions contained in the generated by clause. If a termcontains parameter variables it is sufficient that there exists an arbitrary variable assignmentwhere the terms are different). Such data types are called ‘freely generated’. An example offreely generated datatypes are lists with the two constructors nil (empty list) and cons (addan element at the beginning of a list) for lists.

Page 52: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 51

• There exists for each constructor and each of its arguments a function selecting the corre-sponding argument (in case of lists these are the functions car and cdr selecting the firstelement or the rest of a list respectively).

Data types fulfilling these requirements can be described in KIV by data type specifications.Data type specifications may also be generic. A data type specification starts with the keyworddata specification or generic data specification. In the second case a parameter specifi-cation follows after the keyword parameter. An optional list of used specifications may be given(starting with the using keyword, separated by ‘,’). The parameter of the whole specification isthe union of the parameters of all subspecifications which is in the second case enriched by the ex-plicitely defined parameter (this means that a specification may be generic even without an explicitparameter). Now some data type declarations follow. They define some mutually recursive definedsorts (in most cases only one sort is declared so that there is only one data type declaration). Eachdata type declaration consists of the name of one sort. After the equals sign some constructordeclarations (separated by ‘|’) follow, which end with a ‘;’. Each constructor declaration startswith the constructor. If the constructor is not a constant a list of selector declarations separatedby ‘;’ follows in parentheses. Each selector declaration is of the form ‘selector name : argumentsort’. A constructor declaration declares a constructor whose target sort is the sort of the datatype declaration and whose argument sorts correspond to the sorts of the selector declaration.The selectors select the corresponding arguments. Each constructor declaration may be followedby the keyword with and a predicate to test if a data was generated by this constructor.

The data type declaration is followed by a declaration of variables as in other types of speci-fications. Furthermore there are two (optional) abbreviated definitions. The first begins with thekeyword size functions. Size functions may only be declared if the systems own specificationof naturals is (directly or indirectly) contained in the using list. A size function must be unary,the argument sort must be declared in a data type declaration, and the target sort must be ‘nat’.For such a function axioms are created that count the number of constructors of the data. Con-structors that are constants are not counted (so the size function returns the usual length in caseof lists).

The second abbreviated declaration order predicates contains binary predicates describingthe ‘is subterm of’ relation. The corresponding axioms are generated automatically. These predi-cates are always noetherian and may therefore be used for induction. In case of lists the order ‘isan endpiece of’ is generated. Together with an ‘emptyp’ predicate testing if a list is empty resultsthe following specification of lists which is based on the specifications ‘elem-spec’ for the elementsand ‘nat-spec’ for the naturals:

generic data specificationparameter elem-specusing nat

list = [] with emptyp| . + . (. .first : elem; . .rest : list);

variables x, y, z : list;size functions # . : list → nat;order predicates . < . : list × list;end generic data specification

Note the infix declaration of + (overloaded with addition on natural numbers) and the postfixdeclarations of the selectors .first and .rest.

The axioms generated can be divided in the following groups (as shown for the example oflists):

• ‘Generated by’ clause: This clause declares that the sorts contained in the data type speci-fications are generated by all of its constructors: list generated by [], +

Page 53: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 52

• Injectivity of constructors: a + x = b + y ↔ a = b ∧ x = y

• Uniqueness (or distinctiveness) of constructors: a + x �= []

• Selector axioms: (a + x).first = a, (a + x).rest = x

• Test predicates: emptyp([]), ¬ emptyp(a + x)

• Size functions: # [] = 0, # (a + x) = # x +1

• Order predicates: ¬ x < x, x < y ∧ y < z → x < z, x < a + y ↔ x = y ∨ x < y, ¬x < nil

Actually, some more useful theorems are generated.Basic and generic data specifications are a very common type of specification. Here are a few

examples for other data types which can be described by data specifications:

• enumeration types like booleans, or days of the weeks:

data specificationday = Mon | Tue | Wed | Thu | Fri | Sat | Sun;variables da : day;end data specification

• tupels (or synonym records) like pairs:

generic data specificationparameter elem12-specpair = . × . ( . .1 : elem1; . .2 : elem2 );variables p : pair;end data specification

• variant records:

data specificationusing name-specliterature = mkbook ( author : name; title : name )

| mkarticle (author : name; title : name; booktitle : name);variables l : literature;end data specification

• natural numbers. This specification is the most basic recursive data type specification andis predefined in KIV:

data specificationnat = 0 | . +1 ( . –1 : nat);variables m, n : nat;order predicates . < . : nat,nat;end data specification

Page 54: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 53

5.2 The Specification Methodology in KIV

This section provides some hints about the methodology that is used to specify single data typesor small groups of data types in KIV. It does not describe how to divide a large specification inits components and should be considered only as a quick starter.

We assume that an informal description of a data type is given. In most cases it is useful toproceed as follows:

1. Determine all sorts, functions, and predicates.

2. Determine the constructors which generate the elements of the data types. The result iswritten in the ‘generated by’ clauses and determines in most cases how the specificationhierarchy should be built. Sorts having no constructors should be entered in a parameterspecification (no computer is able to generate data elements without constructors). In realsystems typical parameters are e.g. names (if you don’t want to decide at an early time thatthey are strings, numbers, . . . ).

3. The next step is to decide in which case two terms generated by the constructors are equal.If they are only equal if the terms are identical it’s the simple case of a data specification(which may be enriched by some functions). Otherwise it is in most cases possible to writedown an axiom of extensionality of the form d1 = d2 ↔ ϕ describing when two datas d1 andd2 are equal. The operations contained in ϕ are normally selectors which form together withthe constructors the core of a specification. All other things should be added by enrichments.

4. The selectors should be defined recursively by the constructors. Here you often need casedistinctions which should be complete (every case is treated) and sound (if cases are containedtwice the definitions should be equal).

5. At the end all other operations needed should be defined. It is recommended to use separateenrichments for operations not directly depending on each other (especially if the data typeis complex). There are several possibilities recommended to define new operations:

• nonrecursive definition: In this case a new predicate p or function symbol f is definedby a form p(x) ↔ ϕ or f(x) = t respectively where p or f are not contained in ϕ ort. Case distinctions are possible. If case distinctions are sound (see above) they do notlead to inconsistencies.

• recursive definition by constructors: The principle of definition remains the same asabove and there is a complete case distinction containing all constructors of x. That is,each occurrence of x is replaced by c(x1, ..xn) for each constructor c. The restriction‘p or f are not contained in’ is replaced by ‘p or f is only applied to x1, . . . , xn’.

• definition of modification functions by selector operations: In this method the effect ofmodification operations is defined by their effect on the selectors used in the axiom ofextensionality.

As an example of how to use this methodology we describe the developement of the specificationof arrays:

1. Three sorts are involved in the specification of arrays: the arrays itself, the index sort, andthe sort of the elements. It is obvious that the element sort is a parameter sort and the arraysort is a target sort. In case of the index sort there are two possibilities: If natural numbersare to be used as an index sort (easier) it must be a target sort. If other enumerationstypes should also be allowed to be the index, it has to be chosen as a parameter sort.Nevertheless, a first element and a successor function is needed (to iterate over the array) sothat the specification will roughly describe natural numbers. We choose the first solution.

Page 55: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 54

2. As constructors a function ‘mkarray : nat → array’ is needed to create an array of sizen. To create an array with an arbitrary content we need a modification operation ‘. [ . ] :array × nat × elem → array’. ar[n,a] changes the content of the array ar at the positionn into a if n is smaller than the size of the array. Therefore the generation clause is ‘arraygenerated by mkarray, [ ]’.

3. Do two different terms built only by mkarray and put always differ? The answer is nobecause the arrays ar[n,a] and ar[n,a][n,a] (read as (ar[n,a])[n,a]) are equal. According to themethodology you should try to write down an axiom of extensionality. To do this a selector‘. [ . ] : array × nat → elem’ (lookup) is needed. Furthermore arrays of different size haveto be distinguished and so a length function ‘# . : array → nat’ has to be defined. Nowit is possible to formulate the axiom of extensionality as

ar1 = ar2 ↔ # ar1 = # ar2 ∧ ∀ n. n < # ar1 → ar1[n] = ar2[n].

4. The selectors ‘lookup’ and ‘length’ should be defined recursively for the constructors of anarray. For the function ‘#’ it is easy: ‘# mkarray(n) = n, # ar[n,a] = # ar’. (But note thatwe need the axiom that updating an array does not change the length of the array by somequeer side effect.) In the case of ‘lookup’ there are two possibilities to handle the problem of‘violation of array bounds’. These possibilities exist in each case where it is not clear whichresult a function returns on a certain input value (in programming languages these problemlead to overflows, . . . ):

• underspecification: In this case you simply do not specify the result value. That meansthat the function may return on a critical input value any result. Because nothingcan be induced from this fact, it’s impossible to prove the correctness of a programcontaining such a function call. (Well, at least for normal programs.) This method ischosen in data type specifications if selectors are applied on ‘wrong’ constructors (e.g.selecting the first element of an empty list).

• error and default elements: This possibility is chosen if it makes sense that programs(or functions) using this data type are calculating with “error” results. Typical ex-amples are specifications of algorithms for searching, pattern matching, or unificationwhere failures are possible. In this case the concerned sort has to be enriched by anerror constant which also generates an element of the data type (and must thereforebe contained in the generation principle). Adding a new error constant often causesproblems because all other operations must be able to deal with it.

For example in the case of lists the constant ‘errlist’ may added to the list sort to specify‘[].rest = errlist’. In this case it’s necessary to specify a + errlist and errlist.rest (aserrlist), too. Furthermore the axiom (a + x).rest = x is only valid for x �= errlist . . . .Therefore it is often easier to use existing constants as ‘default’ and specify [].rest =rest.

In case of parameter sorts it may be useful to define a default constant ‘noelem: elem’. Theadvantage of this solution is that arrays need not be initialized explicitely. Instead, for everyactualization of the elements by concrete datas (e.g. nat) a default constant has to be givenwhich is used to initialize arrays. An even more flexible solution is to add a further argumentof the sort elem to the operation mkarray which is used to initialize the array.

However, the two possibilities to define ‘lookup’ on an index value beyond the length of thearray remain.

5. Additional functions for arrays are e.g. copying parts of one array into another, selecting asubarray, filling part of an array with a given element, comparing parts of two arrays etc.These functions are typically specified in one (or more) enrichments.

Page 56: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 55

5.3 Creating Specifications in KIV

When a project is selected the system switches to the project level which is displayed by the graphvisualisation tool uDraw. All KIV commands are contained in the menu Edit. (uDraw allows toconfigure only this menu for applications).

Each project consists of specifications (and modules which contain the implementations of thesoftware system) whose dependencies form an acyclic graph displayed by daVinci. Rectanglescorrespond to specifications, rhombs correspond to modules.

Each specification is located in its own subdirectory specs/〈name〉 in the project directory.The specification text itself is contained in the file specification. A specification is created withthe command Edit – Specification – Create. Then you have to choose the type of the specification.In case of generic, enriched, union, actualized, or renamed specifications the used subspecificationshave to be selected (a first selection is made with the left mouse button, further selections aredone by holding the shift key and klicking with the left mouse button). Finish the selection withEdit – OK (or cancel the creation with Edit – Selections – Cancel). The system actualizes thespecification graph.

A created specification containing no text is displayed in white in the developement graph.The specification text has to be typed in using XEmacs. To load the file into XEmacs, click thecorresponding node in the developement graph with the left mouse button. You get a menu whereyou select Edit Specification. This will load the file ’specification’ into an XEmacs buffer. Itcontains already a template of the specification text (given in %". . . ") with some commands toload the used subspecifications.

When the text of the specification is completed it can be installed. That means that thespecification is loaded, its syntactical correctness is checked and an internal data structure isgenerated. To install a specification use the Install command which you get by clicking on thecorresponding node. If there are some errors in the specification a window is displayed showingthe errors. Note that in case of parser errors the two question marks are displayed immediatelyin front of the token that cannot be parsed. Frequent errors are missing spaces between tokens(‘a=b’ is one token, not an equation!), signature conflicts within the project, and type checkingerrors (multiple defined symbols, invalid or incomplete morphisms, . . . ). When an error occursyou can leave the error window open, continue editing the file, and try to install it once moreby selecting Yes in the error window. If a specification is successfully installed the node in thedevelopement graph changes its color to blue.

Note that you can change the type of the specification or the used specifications simply byediting the file (e.g. by replacing basic specification with enrich). You do not have to deleteand re-create the specification.

Finally you can work on the specification using the work on ... command. If a specificationhas to be changed the Reload command in the menu of the specification is used. The systemreloads the specification and tries to keep theorems already proven valid. If the specification issubspecification of other specifications the system tries to use the changed subspecification insteadof the old one. If this is not possible (because a symbol is deleted in the subspecification, an addedsymbol is missing in a morphism, . . . ) the system tries to reload these specifications, too. If that isnot possible the user is asked whether he wants to correct these specifications, to abort the wholeaction, or to leave the specifications that are currently not loadable invalid. Invalid specificationshave a red color.

When all theorems of a specification are proven the specification can be set into Proved State.Specifications which are in proved state are shown as green nodes. When a specification entersthe proved state all dependencies between the proofs in this specifications and used lemmas fromsubspecifications are checked. In particular it is checked that all simplifier rules used in the proofsdo still exist in the subspecifications (see below).

Page 57: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 56

Short description of the menu commands

The following operations can be performed on a specification by either clicking on the specificationand choosing the corresponding menu item or by choosing Edit – Specification – . . . :

• Install: Install a specification. The text of the specification is loaded. The color of thecorresponding rectangle changes to blue.

• Uninstall: Uninstall a specificaton. The color of the corresponding rectangle changes towhite.

This is a dangerous operation because it delete all theorems and proofs!

• Reload: Reload a specification if the specification text has changed.

• Edit: Edit the text of the specification using emacs. (It is possible to use another editor,too.) The syntax of specifications is described in chapter 5.

• View: View the text of a specification.

• Work on . . . : Work on a specification. This command is used to change to the specificationlevel.

• Rename: Rename a specification. The name is changed in all other specifications referringto the specification to be renamed, too.

• Delete: Delete the specification.

• Delete edges: Delete edges in the development graph. The corresponding files are alsochanged.

• Print: Print the text of a specification as a LATEX document.

• Enter Proved State: Enter into the proved state. The system checks if all dependencies arefulfilled and if there are no cyclic proofs. If a specification is in the proved state it is notpossible to make any changes to it.

• Leave Proved State: Leave the proved state.

If a command is not contained in the popup menu it is not applicable on the specification. E.g.you can only delete specifications that are uninstalled, and you can only uninstall a specificationif all its super specifications are already uninstalled.

To leave the project level use the command Edit – Go Back.

5.4 Exercise 3

All specifications for this exercise should be developed in advance with pencil and paper. Theproject for this exercise contains only some specifications of natural number from the KIV libraryof data types (with orange color).

Exercise 3.1 Gauss summation formulaEnrich the specification of natural numbers with division nat-div by a specification gauss.

Define the sum (0 + ) 1 + . . . + n as a recursive function Σ : nat → nat (KIV symbol capital“Sigma”, alternatively use the word “sum”) by structural recursion, i.e., find right-hand sides forthe axioms

axiomssum-zero: Σ(0) = . . .sum-succ: Σ(n + 1) = . . .

Page 58: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 57

and add them as simplifier rules.

Then create and prove the theorem

gauss: Σ(n) = (n ∗ (n + 1)) / 2

Which proof principle do you use?

Hint The lemmadiv-two-add: m / 2 + n = (m + 2 ∗ n) / 2

from specification nat-div will be useful. It can be applied by right clicking on some + symbol insome proof step.

Exercise 3.2 Specification of anonymous elementsCreate a basic specification elem that contains the sorts of elements elem together with a

variable of that sort.This specification will serve as a placeholder in the following definitions (trees, sets) that can

be actualized later. For example, trees of natural numbers can be derived from the definitions inthe next exercises by actualizing this element sort to the sort nat.

Exercise 3.3 Data type specification of binary treesDefine a data type binary trees in a generic data type specification. Binary trees consist of

internal nodes with an element, a left and a right subtree, and leaves that have no elements. Thedata type should have the the above elements as parameter in its nodes.

Define an order predicate < for binary trees.

Exercise 3.4 Complete binary treesEnrich your specifcation of binary trees with a specification containing a predicate that states

that the tree is complete: every leaf in the tree has the same depth.Use your specification of binary trees and the given specifcation nat-pot (natural numbers with

addition, multiplication and exponentiation operators) as foundation for your enrichment.Hints:

• You will need to specify some other functions on natural numbers and/or on trees. Thesefunctions should be defined recursively over the structure of binary trees, i.e. there arealways two cases 1) for leaves and 2) for internal nodes. This should also give you a hint forthe proof strategy in the next exercise.

• Use those functions to specify the predicate for complete binary trees.

• The depth of a leaf is 0.

Exercise 3.5 Properties of complete binary trees

1. Prove that the number of leaves in a complete binary tree bt is 2depth(bt).

2. Prove that the number of nodes (including leaves) in a complete binary tree bt is2(depth(bt)+1) − 1.

Hints:

• Of course you have to specify functions for counting nodes and leaves first.

• Turn off the elimination heuristics: right click on the heuristics button, configure, select yourown, and remove elimination.

Page 59: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 58

Exercise 3.6 Trees containing elementsEnrich the specification of binary trees with a predicate . ∈ . : elem × bintree that specifies

whether an element is contained within some node of the tree. The predicate should be definedby structural recursion.

Then, specify a predicate contains-only : tree × elem that states that a tree contains only agiven element (possibly many times). For example, the tree

node(leaf, a, node(leaf, a, leaf))

should satisfy this predicate for the element a, but not

node(leaf, a, node(leaf, b, leaf)).

Again, define it by structural recursion on the tree. Prove the equivalence to a non-recursivecharacterization

contains-only(bt, a) ↔ (∀ b. b ∈ bt → a = b)

Use this lemma to prove the simplifier rule

contains-only(bt, a) ∧ bt �= leaf → (b ∈ bt ↔ a = b)

and (automatically) the lemma

contains-only(bt, a) ∧ bt �= leaf → a ∈ bt

Exercise 3.7 Generic specification of setsSpecify finite sets with arbitrary parameter elements. (Note that the element specification

must be created first.) Define a constant for the empty set, an operation to insert an element intoa set, and a predicate to test if an element is contained in a set. Do not specify other operations.

Prove that an element is a member of a set with only one element if and only if the two elementsare equal. The theorem should be formulated in such a manner that it can be used as a simplifierrule.

Exercise 3.8 Actualization of sets by treesSpecify sets of binary trees (including the union operation on sets) by actualizing the union

specification with the specification of binary trees.

Exercise 3.9 Enrichment of sets of binary trees by a subtree operationSpecify a function subtrees that return the set of all subtrees of a given tree (including the tree

itself).

Exercise 3.10 Enrichment by a union, remove and difference operationEnrich the specification of sets by a function . ∪ . that unites two sets, a function . -- . that

removes one element from a set and a function . \ . that returns the difference of two sets. Defineall functions recursively. For each of them prove a theorem that characterizes the elements in theresulting set and the theorem

(s0 \ s1) \ s2 = s0 \ (s1 ∪ s2)

Exercise 3.11 Well-founded recursion/inductionEnrich the specification nat-mult with the modulo and division (without remainder) functions

. % . and . / . on natural numbers and the predicate even. even(n) should hold if the naturalnumber n is even. Define them recursively and prove the theorems

1. even(n)↔ n % 2 = 0

2. m �= 0→ (n/m) ∗m+ n % m = n

You have to add ”prio 11” to the declaration of the modulo and division functions.

Page 60: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 5. ALGEBRAIC SPECIFICATIONS 59

Sometimes it is very easy to write inconsistent specifications that allow to ‘prove’ everything. Thefollowing example demonstrates this.

Exercise 3.12 Inconsistent specifications (1)Enrich the subtrees specification from the last exercise with the following specification:

functions min : set → bintree;

axioms

min-def : min(s) = t ↔ t ∈ s ∧ ∀ t0. t0 ∈ s → t < t0 ∨ t = t0;

The idea is to specify a function min that selects the smallest element of a set of binary trees.(Here we assume that your sorts are named set and bintree, and that s is a variable for sets andt and t0 variables for trees, and that < is the order predicate for the binary trees. You have tomodify the names to fit your specifications.)

Show that this specification is inconsistent by proving false. (You can ignore the warningabout a sub signature when adding this theorem.)

The remaining exercises of this section are not mandatory. You should, however, try to solvethem.

Exercise 3.13 Prove the injectivity of subtreesProve that subtrees is injective, i.e. two trees are equal if and only if they have the same

subtrees. A little hint: You should formulate a lemma that connects the order predicate forbinary trees with subtrees.

Exercise 3.14 Inconsistent specifications (2)Another try: Enrich the subtrees specification a second time with the specification

functions min : set → bintree;

axioms

min-in : s �= ∅ → min(s) ∈ s;

min-min : t ∈ s → t = min(s) ∨ min(s) < t;

Show that this specification is also inconsistent by proving false.

Page 61: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 6

Logische Datenstrukturen in PPL

Alle Konstrukte der Logik wie Expressions, Formeln, Programme und Sequenzen werden in PPLdurch Datenstrukturen realisiert. Genau wie in anderen Programmiersprachen Konstruktorenund Selektoren z. B. fur Arrays, Listen, Records etc. realisiert sind, gibt es in PPL Konstruk-toren und Selektoren fur Formeln, Expressions etc.. Z. B. bildet (mkneg x) aus der Formel x dienegierte Formel, und der Selektor expr selektiert die Ausgangsformel wieder aus dem Ergebnis.Allerdings wird besonders bei komplizierten, verschachtelten Ausdrucken diese LISP-ahnliche Syn-tax unubersichtlich, und wir werden sie im Praktikum deshalb auch nicht verwenden. Stattdessengibt es im KIV-System fur Ausdrucke, die zu logischen Datenstrukturen wie Expressions, Formeln,Sequenzen und (Objekt-)Programmen gehoren, eine vereinfachte Schreibweise. Diese Syntax wirdvon Doppelhochkommata eingeschlossen und beginnt mit einem Prozentzeichen:

Beispiel:

PPL 1> %"not true"

steht fur

PPL 1> (mkneg (mktrue))

Die innerhalb von %"..." erlaubte Syntax wird als konkrete Syntax bezeichnet (die andere Syn-tax als abstrakte. Rein technische gesehen wird die konkrete Syntax von einem Parser eingelesen,also geparst. Tritt dabei ein Fehler auf, so wird eine Fehlermeldung ausgegeben, z. B.:

PPL 1> %"not tru"

Error:

Parser: parse error in "not ?? tru".

Die Stelle direkt vor dem Symbol, das nicht mehr geparst werden kann, wird dabei mit zweiFragezeichen markiert. (In diesem Beispiel fehlt das e bei ”‘true”’.) Im Folgenden wollen wir dieDatenstrukturen einzeln betrachten:

6.1 Die Signatur

Jede Logik, wie z. B. die Aussagenlogik oder Pradikatenlogik besitzt zunachst einmal eine Syntax,die den Aufbau von Expressions, atomaren Formeln und Formeln uber einer Signatur beschreibt.Beispielsweise die Konjunktion von Formeln P und Q zu einer neuen Formel P ∧ Q. Im Folgendenwird die Syntax der im KIV-System verwendete Logik, sowie die Eingabe von Expressions undFormeln in dieser Logik in PPL beschrieben.

Die Logik des KIV-Systems ist eine Erweiterung der mehrsortigen Pradikatenlogik. Bevor wirExpressions konstruieren konnen, mussen wir die Signatur, also Sorten, Variablen und Funktion-ssymbole deklarieren und fur Formeln auch noch die Sorten der Pradikatsymbole.

60

Page 62: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 61

Jedes dieser Symbole wird zusammen mit den Angaben uber die Art des Symbols und seinerSorte in der sogenannten Signatur abgelegt. Dort bleibt es, bis das KIV-System verlassen wird.Wenn versucht wird, ein Symbol anders zu verwenden, als es in der Signatur steht, oder einundefiniertes Symbol zu verwenden, wird ein Fehler gemeldet, da sonst Inkonsistenzen auftretenkonnen.

Signaturen werden innerhalb von Spezifikationen definiert. Es gibt aber auch die Moglichkeit,Signatursymbole einzeln zu definieren. Hierbei gilt: Ein einmal definiertes Symbol kann nichtohne weiteres redefiniert werden. Eine Definition bleibt gultig, bis die komplette Signatur mitdem Kommando (resetsig) wieder geloscht wird. Ein paar Beispiele:

Sorten werden durch den Befehl

%"sorts sortname;"

definiert.

PPL 1> %"sorts nat;"

[nat]

PPL 1> %"sorts nat,tree;"

[nat, tree]

Konstanten const werden definiert durch:1

%"constants const : sort;"

Ein Beispiel:

PPL 1> %"constants 1 : nat;"

Eine Objektvariable wird so definiert:

PPL 1> %"variables n1 : s1; ...nm : sm;"

wobei die ni Namen von Objektvariablen und si die entsprechenden Sorten sind. Es ist auchmoglich, mehrere Variablen derselben Sorte durch Komma getrennt, wie folgt einzugeben:

PPL 1> %"variables n, n0 : nat;"

[n, n0]

Eine solche Definition ist nur dann moglich, wenn die Sorte bereits definiert wurde. Versucht man,eine undefinierte Sorte zu verwenden, erhalt man eine Fehlermeldung:

PPL 1> %"variables x : int;"

Error:

Parser: parse error in "variables x : ?? int;".

Die beiden Fragezeichen for dem ”‘int”’ zeigen an, dass der Bezeichner ”‘int”’ nicht geparst werdenkann, was in diesem Fall daran liegt, dass die Sorte ”‘int”’ nicht definiert wurde.

Das Funktionssymbol fun mit den Argumentsorten s1, s2, . . . , sn und der Ergebnissorte s wirdwie folgt deklariert:

PPL 1> %"functions fun (s1,s2,...,sn) : s;"

Wieder ein Beispiel:

PPL 1> %"functions plus (nat,nat) : nat; "

[plus]

PPL 1> %"plus(n,n0)"

1Die Leerzeichen um den Doppelpunkt herum sind notwendig.

Page 63: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 62

Es besteht auch die Moglichkeit, Funktionen als Infix (nur bei zweistelligen Funktionen) oder Prafix(nur bei einstelligen Funktionen) oder Postfix (nur bei einstelligen Funktionen) zu deklarieren.Dies geschieht durch Punkte um das Funktionssymbol herum, die die Position der Argumentesymbolisieren:

PPL 1> %"functions . + . (nat,nat) : nat;"

[+]

PPL 1> %"functions . +1 (nat) : nat;"

[+1]

PPL 1> %"n +1 + n0"

Fur Pradikate pred sieht es ahnlich aus:

PPL 1> %"predicates pred (s1,s2,...,sn);"

Zum Beispiel die kleiner-Relation auf naturlichen Zahlen

PPL 1> %"predicates less (nat,nat); . < . (nat,nat);"

[less, <]PPL 1> %"n < m"

Es gibt den Befehl show-entry, der Eintrage in der Signatur anzeigt. Das Symbol muss indoppelte Hochkommata eingeschlossen sein.

PPL 1> (show-entry "n")

>>> N type: xov, entry: [nat], tmp, current

PPL 1> (show-entry "+")

>>> +

type: sigid, entry: [(natbot -> (natbot -> natbot)), prio 7:left], tmp

type: fct, entry: [[nat, nat], nat, 5], tmp, current

Die einzelnen Slots haben folgende Bedeutung:

type zeigt den Typ an.

sort ⇒ Sortexov ⇒ Variableconst ⇒ Konstantensymbolfct ⇒ Funktionssymbolprd ⇒ Pradikatensymbol

entry enthalt als Eintrag

• nil fur Sorten

• Angabe der Sorte fur Konstanten

• Angabe der Sortierung fur Funktionen inklusive Prioritat (hangt mit Infix zusammen)

• Angabe der Sortierung bei Pradikaten inklusive Prioritat (hangt mit Infix zusammen)

Wie man sieht, kann ein Symbol mehrere Signatureintrage besitzen. Es kann aber immernur maximal einen aktuellen Eintrag geben. Dieser ist als current markiert.

Page 64: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 63

6.2 Metavariablen

Metavariablen sind Platzhalter fur viele PPL-Objekte (Formellisten, Formeln, Expressions, Ob-jektvariablen usw.).

Jeder Teil einer Formel oder Abschnitt einer Formelliste lasst sich durch Metavariablen er-setzen. Sie werden syntaktisch durch einen Bezeichner dargestellt, dem ein Dollarzeichen $ vor-angestellt ist.

Metavariablen mussen extra definiert werden. Es gibt vordefinierte Metavariablen, wie z. B.$phi, $psi und $chi fur Formeln, $Gamma, $Delta fur Formellisten, $alpha fur Objektprogramme,$sigma fur Expressions usw.

Mit den oben definierten Funktions-, Pradikatsymbolen lasst sich durch

PPL 1> (deftermmv (mksym "$n") %"nat")

eine Metavariable $n fur einen Term der Sorte nat definieren, oder durch

PPL 1> (defexprmv (mksym "$phi1") bool-sort)

eine neue Metavariable $phi1 fur Formeln.

6.3 Formeln

Pradikatenlogische Formeln und ihre Syntax sind bereits bekannt. Will man nun Aussagen uberProgramme ermoglichen, muss man die Pradikatenlogik um weitere Konstrukte erganzen. Manerhalt die Dynamische Logik. Sei α ein Programm und ϕ eine Formel der dynamischen Logik.Dann bedeutet

[α] ϕ: Wenn α terminiert, dann gilt nach Ausfuhrung von α die Nachbedingung ϕ. (Box)

〈α〉 ϕ: α terminiert und es gilt nach Ausfuhrung von α die Nachbedingung ϕ. (Diamond)

Boxen werden mit eckigen Klammern [ und ] eingegeben, Diamonds entweder mit Kleiner undGroßer (< und >, wobei vor und nach den Zeichen Leerzeichen folgen mussen), oder durch dieSonderzeichen 〈 und 〉 , die man im xemacs durch F12-< und F12-> erhalt.

Das Programm α kann folgende Form haben:

skip die leere Anweisung; es gilt 〈skip〉 ϕ ↔ ϕ

abort die niemals terminierende Anweisung; es gilt [abort] ϕ

x := τ Zuweisungen (Assignments)

if ε then α1 else α2 Konditionale (Conditionals)

if ε then α1 Konditional (der else-Zweig ist skip)

{ α1; . . . ;αn } Zusammengesetzte Anweisungen (Compounds)

while ε do α While-Schleifen

In den Tests muss ε ein boole’scher Ausdruck sein, d. h. eine pradikatenlogische Formel ohneQuantoren. Noch eine Anmerkung zur Bindungsstarke: Box- und Diamond-Operator bindenstarker als Konjunktionen, d. h. [α] ϕ1 → ϕ2 ist nicht gleich [α] (ϕ1 → ϕ2) sondern gleich([α] ϕ1) → ϕ2

Page 65: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 64

6.4 Sequenzen

Eine Sequenz besteht im wesentlichen aus zwei Listen von Formeln. Da wir aber zum bequemenHinschreiben von Regeln auch Platzhalter fur Listen von Formeln benotigen, fuhren wir hier einenspeziellen Typ fur Formellisten, Fmal, ein:

Fmal ::= ε| MV| Fmalist| MV, Fmalist| Fmalist, MV| Fmalist, MV, Fmalist

Fmalist ::= ε| Fma| Fma , Fmalist

wobei MV eine Metavariable fur Formellisten ist.Eine Sequenz besteht aus zwei Formellisten, genannt Antezedent und Sukzedent. Die konkrete

Syntax fur Sequenzen lautet:

Sequent::= Fmal |- Fmal

Die Bedeutung einer Sequenz ist : ”‘Die Konjunktion der Formeln im Antezedent impliziert dieDisjunktion der Formeln im Sukzedent”’. Die leere Konjunktion (bei leerem Antezedent) wird alstrue, die leere Disjunktion als false interpretiert. Der Sequenzenpfeil (das Sonderzeichen ist imxemacs mit F12-follows erhaltlich) wird also nicht als Ableitungsoperator (wie im Hilbertkalkul),sondern als Implikation gedeutet. Ableitungen macht man mit Hilfe der im Folgenden beschriebe-nen Beweisbaume.

6.5 Beweisbaume

Beweisbaume besitzen eine Conclusio, die Sequenz, die bewiesen wird, und Pramissen, also dieSequenzen, die vorausgesetzt werden. Ein Beweisbaum stellt also eine Ableitung dar. In 6.5.1werden die Moglichkeiten beschrieben, Teile von Beweisbaumen zu selektieren. Wie Baume aus-gegeben werden, wird in Abschnitt 6.5.2 beschrieben. 6.5.3 befasst sich mit den Operationenauf Beweisbaumen. Diese ermoglichen es, Beweise durch Regelanwendung zu fuhren, und auchRegeln selbst zu definieren. Es gibt bereits eine ganze Reihe vordefinierter Baume (die eigentlichenBasisregeln des Kalkuls), die im Folgenden als Beispiele dienen.

6.5.1 Selektoren fur Beweisbaume

Die einzelnen Komponenten lassen sich durch die Selektoren prem, prems, concl und subtr gewin-nen. Wir wollen ihre Wirkung an der vordefinierten Regel con r demonstrieren.

Γ ϕ,Δ Γ ψ,ΔΓ ϕ ∧ ψ,Δ (con r)

Wenn man sich fur die Conclusio interessiert kann man folgendes eintippen:

PPL 1> (concl con r)

$GAMMA |- $phi and $psi, $DELTA

Man kann sich auch eine Liste der Pramissen anzeigen lassen:

PPL 1> (prems con r)

[$GAMMA |- $phi, $DELTA, $GAMMA |- $psi, $DELTA]

Page 66: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 65

oder gezielt eine einzelne Pramisse anschauen, z. B. die zweite Pramisse der Regel:

PPL 1> (prem con r 2)

$GAMMA |- $psi, $DELTA

Eine Liste der Unterbaume (in diesem Fall nur Sequenzen) erhalt man durch

PPL 1> (subtr con r)

[$GAMMA |- $phi, $DELTA, $GAMMA |- $psi, $DELTA]

6.5.2 Anzeigen von Beweisbaumen

Ein Baum wird ausgegeben, wenn man ihn mit mkttree, mkftree, refine oder infer erzeugt.Einen mit diesen 4 Operationen erzeugten Baum kann man auch in einer Variablen abspeichern.Wenn man diese Variable evaluiert (Variablennamen eingeben und Return drucken), wird derdarin gespeicherte Baum ebenfalls ausgegeben. Die graphische Anzeige von Beweisbaumen wurdebereits in Kapitel 2 erklart.

6.5.3 Operationen auf Beweisbaumen

PPL arbeitet hauptsachlich auf Beweisbaumen (anstatt Listen wie bei LISP). Die wichtigsten PPL-Funktionen sind somit die, die Beweisbaume manipulieren: makettree, mkftree bauen aus einerKonklusion und Unterbaumen einen neuen Baum zusammen, refine und infer erweitern Beweisedurch Regelanwendung.

Durch makettree und mkftree ist es moglich, neue Regeln, d. h. Baume zu definieren. Umjedoch stets die Korrektheit dieser neuen Regeln sicherzustellen, ist man gezwungen, eine Vali-dierung, d. h. einen Beweis fur die Richtigkeit dieser Regel anzugeben. Eine Validierung ware indiesem Fall ein Baum, der durch infer und refine (siehe unten) aus den Basisregeln des Systemsgewonnen wurde, und dessen Blatter und Wurzel gerade gleich den Pramissen und der Konklu-sion des zu konstruierenden Baums sind. Auf diese Weise bleibt die Korrektheit der verwendetenRegeln bei spateren Verifikationsbeweisen stets erhalten und man kann das Regelsystem von KIVstandig erweitern und verbessern. Es gibt somit zwei Arten von Baumen:

einen ttree, der als Validierung einen Baum hat und mit makettree gebildet wird, und

einen ftree, der als Validierung eine Funktion besitzt und mit makeftree gebildet wird.

makettree

(makettree seq list of trees validationtree comment) konstruiert einen Baum mit der Konklusionseq. validationtree ist ein Baum, comment ist ein Text, der bei der Baumausgabe zu sehen ist.Der validationtree muss ein Beweisbaum fur die Konklusion seq des Baums sein, der als Pramissen(hochstens) die Konklusionen der Unterbaume list of trees hat. ”‘Passt”’ der Baum nicht, gibt eseinen Fehler (ein fail, siehe Abschnitt 9.7). Ein Beispiel dazu folgt am Ende dieses Abschnitts.

mkftree

(mkftree seq list of trees validationfct comment) konstruiert einen Baum mit der Konklusionseq. validationfct ist eine Funktion, die, wenn sie mit der Konklusion seq und den Unterbaumenlist of trees aufgerufen wird, einen ”‘passenden”’Baum als Validierung liefern sollte. (Dies wirdnicht kontrolliert, damit man auch schematische Regeln erzeugen kann, deren Validierungsbaumvon der jeweiligen Instanz der Regeln abhangt. Die Kontrolle der Korrektheit kann so fur jedeInstanz separat zu einem beliebigen Zeitpunkt erfolgen. Dazu gibt es spezielle Validierungspro-gramme, die diesen Test durchfuhren, die wir hier aber nicht diskutieren wollen). comment ist einText, der bei der Baumausgabe zu sehen ist.

Page 67: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 66

refine

Angenommen, wir wollen die i-te offene Pramisse p eines Beweisbaumes b auf einfachere Pramissenzuruckfuhren. Wir mussen uns dann einen Beweisbaum r suchen, der eine Conclusio hat, die aufdie Pramisse p passt (”‘matcht”’), d. h. die Metavariablen der Conclusio lassen sich so ersetzen,dass man daraus p erhalt. Dabei muss dieselbe Metavariable immer durch dieselbe Instanz ersetztwerden. Die Funktion refine fuhrt die Ersetzung der Metavariablen auf jeder Sequenz von rdurch und ersetzt dann die Pramisse p durch den so erhaltenen Beweisbaum. refine erhalt alsodrei Argumente: Den Beweisbaum b, der erweitert werden soll, die Pramissennummer i von b, ander der neue Baum angesetzt werden soll und den neuen Baum r.

PPL 1> (def (st %"|- odd(n) and not odd(n0) -> not n = n0"))

PPL 1> st

|- odd(n) and not odd(n0) -> not n = n0

PPL 1> (refine st 1 imp r)

Die Regel imp r liefert einen Baum mit Pramisse ϕ,Γ ψ,Δ und Conclusio Γ ϕ → ψ,Δ. Wen-det man diese Regel auf die Sequenz st an, erhalt man also einen Baum mit Pramisse

odd(n) ∧ ¬ odd(n0) n �= n0

und Conclusio

odd(n) ∧ ¬ odd(n0) → n �= n0

infer

infer arbeitet ahnlich wie refine. Auch hier werden durch Matchen von Sequenzen Baume neuaufgebaut. Der Aufruf lautet

PPL 1> (infer tree integerliste treeliste)

wobei integerliste eine Liste mit disjunkten naturlichen Zahlen ist, deren großte Zahl nicht großerals die Anzahl der Pramissen von tree sein darf, und treelist eine Liste mit Baumen ist. Die Anzahlder Zahlen in integerlist und der Baume in treelist muss gleich sein.

So bedeutet

PPL 1> (infer tree1 (list 5 2) (list tree2 tree3))

dass an die Pramisse 5 des Baumes tree1 der Baum tree2 und an Pramisse 2 gleichzeitig derBaum tree3 angefugt werden soll:

PPL 1> (def (str %"odd(n) and not odd(n0) |- not n = n0"))

PPL 1> (infer imp r (list 1) (list str))

ergibt einen Baum mit Pramisse

odd(n) ∧ ¬ odd(n0) n �= n0

und Conclusio

odd(n) ∧ ¬ odd(n0) → n �= n0

Man erhalt also das gleiche Ergebnis wie bei dem Aufruf (refine st 1 imp r)

Der Unterschied liegt in der Art, wie eine Metavariable einen Wert erhalt (instantiiert wird).Bei refine wird eine konkrete Formel stets nach oben gegeben und instantiiert dort die Metavari-ablen, wahrend bei infer eine konkrete Formel nach unten gegeben wird.

Ein Beispiel: imp r ist ein Baum, der nur Metavariablen enthalt. st und str sind Baumeohne Metavariable, also nur mit konkret gegebenen Formeln. Der Befehl (refine st 1 imp r)

instantiiert alle Metavariablen in imp r durch konkrete Formeln aus st. Der erzeugte Baum

Page 68: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 67

⇑⇓

����P

����G

��������

��������

T

������

����

C

R

���

���I(R)

����P

����G

��������

��������

T

����G

��������

��������

T

����C

��������

R

��������I(R)

����G

��������

��������

T

refine infer

Figure 6.1: Graphische Darstellung der Wirkung von refine und infer

wird von unten nach oben entwickelt. Bei (infer imp r (list 1) (list str)) werden alleMetavariablen in imp r von oben durch konkrete Formeln instantiiert. Der Baum wird von obennach unten entwickelt.

Das Vorgehen bei refine entspricht dem Entwickeln eines Beweises aus der zu beweisendenBehauptung (der Conclusio des Baums) durch Anwendung von Vereinfachungsregeln, wahrendman bei infer schon die Pramissen des Baumes kennt und daraus (und mit Hilfe der Axiome)wiederum durch Anwendung von Regeln die Behauptung (Conclusio) gewinnt, also analog zuHilbert-Typ-Kalkulen.

Der Sequenzenkalkul ist aber gerade auf das erste Verfahren hin entwickelt worden, und wirwerden dieses auch in den meisten Beweisen verwenden. Wir werden also von einer Behauptung G(dem Beweisziel, auch goal genannt) ausgehen, und refine-Schritte anwenden. Dabei erhalten wirneue Beweisziele (subgoals), die (hoffentlich) einfacher sind als das ursprungliche (wir reduzierendas Goal auf Subgoals). Das Verfahren wird solange fortgesetzt, bis alle Pramissen mit Axiomendes Sequenzenkalkuls geschlossen werden konnen. Abbildung 6.1 zeigt noch einmal graphisch dieWirkung von refine und infer. s(R) ist der Baum R mit instantiierten Metavariablen.

6.5.4 Matching

Bei refine und infer spielt derMatcher eine wichtige Rolle, der Einsetzungen fur die vorkommendenMetavariablen finden muss. Das matchen ist auch an anderen Stellen von Interesse, daher gibt eszwei Funktionen, die es erlauben, zwei Objekte miteinander zu matchen. Allerdings konnen nicht

Page 69: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 68

beliebige PPL-Objekte miteinander gematcht werden, sondern nur die logischen Datenstrukturen,wie Sequenzen, Formeln, Programme oder Expressions.

matchp ist ein Testpradikat, das uberpruft, ob die Metavariablen des zweiten Arguments soinstanziiert werden konnen, dass das erste Argument heraus kommt. Der Aufruf lautet also(matchp object pattern).

match erhalt drei Argumente: (object1 pattern object2). Wie bei matchp wird zuerst patternmit object1 gematcht, dann aber die gefundenen Instanziierungen in object2 eingesetzt. Fallskein Matcher gefunden werden kann, gibt es einen Fehler (ein fail, siehe Abschnitt 9.7).

Ein paar Beispiele zu match und matchp:

PPL 1> (matchp %"n = m" %"$phi")

T

PPL 1> (matchp %"n = m" %"not $phi")

F

PPL 1> (matchp %"(n = m), (m = n) |- "

%"$phi,$psi,$gamma |- $delta")

T

PPL 1> (matchp %"$phi and $psi" %"$phi")

T

PPL 1> (match %"n = m" %"$phi" (list %"not $phi"))

[NOT n = m]

PPL 1> (match %"n = m" %"not $phi" (list %"$phi"))

Error:

operation MATCH failed

PPL 1>

6.5.5 Beispiel fur die Verwendung von refine und infer

Das folgende Beispiel erlautert den Aufbau von Beweisbaumen mit refine und infer, und derenVerwendung als Validierung neuer Regeln und Axiome.

Gesucht ist ein Beweis der Aussage

ϕ ∧ ψ ↔ ψ ∧ ϕ

Der Beweisbaum lasst sich graphisch sehr schon veranschaulichen. Man entwickelt ihn ambesten von der Wurzel ausgehend zu den Blattern. Eine Aussage ist allgemeingultig, wenn alleBlatter leer sind, d. h. nur noch Axiome enthalten. Die Regeln ax, false l und true r sindbeispielsweise solche Axiome. Zur Verdeutlichung wurde im unten stehenden Beweisbaum jedemTransformationsschritt die angewendete Regel aus den Basisregeln beigefugt.

ψ,ϕ � ψax

ϕ,ψ � ψleftexchange left

ϕ, ψ � ϕax

ϕ,ψ � ψ ∧ ϕcon r

ϕ ∧ ψ � ψ ∧ ϕcon l

ϕ,ψ � ϕax

ψ,ϕ � ϕleftexchange left

ψ,ϕ � ψax

ψ,ϕ � ϕ ∧ ψcon r

ψ ∧ ϕ � ϕ ∧ ψcon l

� ϕ ∧ ψ ↔ ψ ∧ ϕequiv r

Alle Blatter (= die Pramissen) sind leer und damit ist die zu beweisende Aussage allgemeingultig.Wie lasst sich nun dieser Beweisbaum in PPL aufbauen? Man verwendet dazu den Befehl

refine, baut den Baum schrittweise auf und speichert Zwischenergebnisse in Hilfsvariablen.Hier das Ergebnis:

Page 70: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. LOGISCHE DATENSTRUKTUREN IN PPL 69

(def (seq %"|- ($phi and $psi <-> $psi and $phi)"))

(def (t1 (refine seq 1 equiv r)))

(def (t2 (refine t1 2 con l)))

(def (t3 (refine t2 2 con r)))

(def (t4 (refine t3 3 ax)))

(def (t5 (refine t4 2 leftexchange left)))

(def (t6 (refine t5 2 ax)))

(def (t7 (refine t6 1 con l)))

(def (t8 (refine t7 1 con r)))

(def (t9 (refine t8 2 ax)))

(def (t10 (refine t9 1 leftexchange left)))

(def (t11 (refine t10 1 ax)))

Die Variable t11 enthalt schließlich den gesamten Beweis der Aussage.Will man nun diese allgemeingultige Aussage als neue Regel (mit Namen new rule) verwenden,

schreibt man sich zunachst wieder die Regel in Form eines Baumes hin. Die Pramisse ist dabeileer und die Conclusio enthalt die Sequenz:

ϕ ∧ ψ ↔ ψ ∧ ϕ new rule

Anschließend wird durch den Befehl mkttree diese neue Regel definiert.

(def (new rule (mkttree seq (list) t11 (mktext "new rule"))))

Das erste Argument ist die Sequenz seq, das zweite Argument eine Liste von Baumen (die hierleer ist, da die neue Regel keine Pramissen enthalt) und das dritte Element ist die Validierungder neuen Regel, d. h. ein Beweisbaum fur die Korrektheit der Regel. Durch die Notwendigkeitder Angabe einer Validierung wird sichergestellt, dass nur korrekt abgeleitete Regeln im Systemverwendet werden. Das letzte Argument ist schließlich der Kommentar.

Page 71: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 7

Implementierung eines VCG

7.1 Einfuhrung

VCG ist, wie unschwer zu erraten, eine Abkurzung. Sie steht fur Verification Condition Generatorund bezeichnet damit eine ganze Klasse von Programmen, die im wesentlichen nach dem gleichenGrundschema versuchen, Korrektheitsaussagen uber Programme zu beweisen.

Ziel eines VCG ist es, hinreichende pradikatenlogische Bedingungen fur die Korrektheit einesProgramms bezuglich einer gegebenen Spezifikation zu errechnen.

Die Philosophie, die dem VCG zugrunde liegt, basiert auf der Idee, den Beweisprozess in zweiPhasen aufzuspalten:

• in der ersten Phase wird das Programm zusammen mit seiner Spezifikation in einen VCGgesteckt, der daraus eine endliche Menge pradikatenlogischer Formeln macht, und

• dieser Output wird im zweiten Schritt in einen Beweiser fur Pradikatenlogik eingefuttert,der die Formeln dann alle beweist.

Eine der fundamentalen (aber falschen) Annahmen dabei ist insbesondere, dass pradikatenlogischeDeduktionsprobleme einfacher zu losen sind als solche, die Programme enthalten, und das entsprechendleistungsfahige (pradikatenlogische) Beweiser verfugbar sind (oder gebaut werden konnen).

Historisch gesehen waren VCGs gewissermaßen die erste Antwort auf die Frage, wie manKalkule fur die Korrektheit von Programmen (wie z. B. den Hoare-Kalkul) in einem Rechnerimplementieren kann. Eines der beruhmtesten Exemplare ist der Stanford Verifier, ein VCG fureine Pascal-artige Sprache.

7.2 Theoretischer Unterbau

Grundlage fur einen VCG ist eine in Form eines Kalkuls gegebene Theorie der Korrektheit vonProgrammen. Die Leistungsfahigkeit dieses Kalkuls ist der wesentliche Faktor, der die theoretischeLeistungsfahigkeit eines VCG bestimmt.

7.2.1 Wichtige Eigenschaften

Die beiden interessantesten Eigenschaften sind, wie im Bereich formaler Systeme ublich, Vollstandigkeitund Korrektheit. Die Korrektheit ist aus naheliegenden Grunden eine unverzichtbare Eigenschaft.Sie ist allerdings fur zahlreiche in wissenschaftlichen Papieren veroffentlichte Kalkule nicht gegeben(irren ist menschlich).

Fur die Vollstandigkeit ist wesentlich, welche “Features” die Programmiersprache bietet. Durchgeschickte Kombination von eingebauten Kontroll- und Datenstrukturen kann man die Suche nach

70

Page 72: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. IMPLEMENTIERUNG EINES VCG 71

einem entsprechenden Kalkul praktisch beliebig erschweren. Das geht sogar soweit, dass fur gewisseKombinationen beweisbar kein “guter” Hoare-ahnlicher Kalkul existieren kann.

Es zeigt sich allerdings in der Praxis, dass Vollstandigkeit nicht mit Leistungsfahigkeit gle-ichzusetzen ist. Praktisch bedeutender ist ein angemessener Trade-off zwischen Ausdrucksstarkeund “Deduktionstauglichkeit” (man denke z. B. an die Pradikatenlogik erster Stufe, fur die jabekanntlich ein vollstandiger Kalkul existiert, und diverse Einschrankungen wie z. B. Horn-Logik(Prolog!)).

Eine weitere essentielle Eigenschaft ist die der Kompositionalitat, d. h. der Beweis einerKorrektheitsaussage uber eine zusammengesetzte Anweisung darf nur von der Gultigkeit geeigneterKorrektheitsaussagen uber die zusammengesetzen Teile abhangen, nicht jedoch von der konkretenImplementierung der Teile. Dies bereitet allerdings bei sequentiellen Programmen keine großenProbleme. Interessant wird diese Forderung erst bei der Modulverifikation oder nebenlaufigenProzessen.

7.2.2 Einige Kalkule

Fur den Bau eines VCGs fur sequentielle, imperative Programmiersprachen (Algol, Pascal, etc.)kann man zwischen einer Vielzahl von Kalkulen wahlen, einige seien hier erwahnt:

• Hoare-Kalkul (klassisch)

• Hoare-Kalkul mit Terminierung

• Subgoal-Induction

• wp-Kalkul (Dijkstra)

• intermittant-assertion-methode (Burstall)

Dabei gilt: Je einfacher (primitiver) ein Kalkul ist, desto einfacher kann man ihn in die compilerar-tige Struktur eines VCG gießen. Die meisten VCGs sind daher direkte Abkommlinge irgendeinerVariante des Hoare-Kalkuls.

7.2.3 Randbemerkungen

• Kalkule fur Pascal-artige Sprachen kann man im wesentlichen in zwei Klassen einteilen: Dieeinen sind vollstandig nur, wenn uber einer hinreichend ausdrucksstarken Datenstruktur(Arithmetik!) gerechnet wird (“relative” bzw. “arithmetische” Vollstandigkeit), und dieanderen verwenden infinitare Regeln (Regeln mit unendlich vielen Pramissen), um vollstandigzu werden.

• Uber die Axiomatisierung von Programmiersprachen existiert eine umfangreiche Literatur.

• Es gibt nicht nur wissenschaftliche Papiere uber Kalkule fur Programmiersprachen, sondernauch uber die Fehler in solchen Papieren.

7.3 Technische Realisierung

Schon bei der einfachsten Variante, einem auf dem Hoare-Kalkul basierenden VCG, ergeben sicheinige kleinere Unannehmlichkeiten: Die reine Spezifikation in Form von Vor- und Nachbedingun-gen reicht fur die Erzeugung von Verifikationsbedingungen nicht aus. Fur einen Hoare-Kalkul z.B. benotigt man zusatzlich noch die beruchtigten Schleifeninvarianten.

Dies hat dazu gefuhrt, dass in den meisten VCGs als Eingabesprache eine Erweiterung dereigentlichen Programmiersprache verwendet wird, die die Formulierung von Zusicherungen, Schleifen-invarianten etc. innerhalb des Programmtextes erlaubt.

Page 73: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. IMPLEMENTIERUNG EINES VCG 72

In der einfachsten Variante eines VCG wird dann “lediglich” Backward-Chaining mit dementsprechenden Kalkul durchgefuhrt. Das ist unter theoretischen Aspekten hinreichend. Praktischgesehen ist es nicht sehr befriedigend, wie man gleich merken wird.

Das grundsatzliche Vorgehen soll nun in einem Beispiel erlautert werden. Dabei verwendetman, wie auch in den Aufgaben, keine Syntax mit eingebauten Assertions oder Invarianten. AlsBasis fur das Ausrechnen der Verifikationsbedingungen verwendet man einen einfachen Hoare-Kalkul, der im Anhang E angegeben ist.

In “Reinform” wurde man das Programm “von hinten’ aufrollen, und insbesondere fur dieConditionals die Regel PRAKT IF BACKWARD RULE verwenden (sie ist in dieser Form fur dieseUnterlagen erfunden, existiert nicht im System und kann Fehler enthalten). Zwei Abweichungensollen jetzt bereits erlaubt sein: Man arbeitet von vorne nach hinten, und man produzieret furConditionals zwei neue Ziele. Das muss zwar nicht sein, macht die Formeln aber etwas lesbarer.

Das Programm, mit dem der Prozess illustriert wird, ist folgendes:

beginif ¬ g then rm := 0 r else rm := 1 r;i := 0;

while i < n dobegin

if ¬ g then rm := rm + r get(ar, i)

else rm := rm $*$ r get(ar, i);

i := i +1

end;if ¬ g then rm := div r(rm, int to real(n))

else rm := root r(int to real(n), rm)

endDabei seien die Variablen n und i von der Sorte nat, g habe die Sorte bool und ar die Sorte

array. Vorbedingung ist n �= 0, Nachbedingung ist

ψ ≡ (¬ g → rm = am(ar, n)) ∧ (g → rm = gm(ar, n)).

Dabei sei am(ar, n) das arithmetische Mittel und gm das geometrischeMittel (root r(n,m) berechnedie n-te Wurzel von m). Die Schleifeninvariante ist

Inv ≡ i ≤ n∧ (¬ g → rm = am(ar, i) ∗r i)∧ (g → rm = pow r(gm(ar, i), i))

Auf die ursprungliche Aussage n �= 0 → [α]ψ liefert die IF FORWARD RULE gleich zwei neuePramissen. Man beschrankt sich hier auf den Fall ¬ g, dann lautet das Unterziel

n �= 0 ∧ ¬ g → [rm := 0r; . . .]ψ

Die Assignmentregel PRAKT ASSIGN TACTIC fuhrt zu

n �= 0 ∧ ¬ g ∧ i = 0 ∧ rm = 0r → [while . . . ] ψ

Nun kommt die WHILE RULE mit ihren drei Pramissen, diese sind

n �= 0 ∧ ¬ g ∧ i = 0 ∧ rm = 0r → Inv

Inv ∧ i ≤ n → [if ¬ g then rm := rm+r get(ar, i) . . . ] Inv

undInv ∧ ¬ i ≤ n → [if ¬ g then rm := divr(rm, int to real(n)) . . . ] ψ

Page 74: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. IMPLEMENTIERUNG EINES VCG 73

Das erste Unterziel ist rein pradikatenlogisch, und damit fur einen VCG eine der ausgegebenenFormeln. Das zweite und dritte Unterziel werden analog zum ersten Conditional im gesamtenProgramm behandelt, worauf aus Platzgrunden hier verzichtet wird.

Die Programmierung eines VCG, der diesen Prozess durchfuhrt, wird die erste Aufgabe sein.Im KIV-System ist es dabei am einfachsten, wenn man, statt nur eine Menge von Formeln zuberechnen, gleich den gesamten Beweisbaum aufbaut. Die Schleifeninvariante sollte dabei inter-aktiv eingegeben werden.

Die Formelmenge, die bei diesem Prozess entsteht, ist relativ unansehnlich. Dies liegt daran,dass die pradikatenlogischen Formeln, die durch Conditionals und Zuweisungen entstehen, ein-fach aufgesammelt werden, und insbesondere nicht versucht wird, die Tests von Conditionals zuentscheiden.

Die Sache wird etwas besser, wenn man nach der Fallunterscheidung zu Beginn des Programmsdie beiden Zweige mit unterschiedlichen Invarianten behandelt, in die jeweils g bzw. ¬ g mitaufgenommen wird. Damit kann man die beiden Invarianten zu

i ≤ n ∧ ¬ g ∧ rm = am(ar, i) ∗r i)

undi ≤ n ∧ g ∧ rm = powr(gm(ar, i), i))

vereinfachen. Dies erspart einem auch pro Zweig eine weitere Fallunterscheidung nach der Schleife.Der resultierende Beweis ist wesentlich einfacher und auch lesbarer. Der Preis dafur ist, dass

man sich vom “compilerhaften” Vorgehen trennen muss, dass man eine Scheife bei verschiedenenGelegenheiten mit verschiedenen Invarianten behandelt und dass man einen Beweiser bereits beimGenerieren der Verifikationsbedingungen verwenden muss, und nicht erst hinterher. Außerdemmussen die potentiellen Vereinfachungen auch im Regelsatz Niederschlag finden, man kann jetztz. B. vorteilhaft Regeln fur Conditionals mit beweisbar wahren oder falschen Tests verwenden.

Diese Modifikation des VCG wird Gegenstand der zweiten Aufgabe sein.

7.4 Exercise 4

Exercise 4.1 Fibonacci numbersImplement a function fibo that takes a natural number n as argument and computes the nth

Fibonacci number:

• n = 0 : fibo(n) = 1

• n = 1 : fibo(n) = 1

• n ≥ 2 : fibo(n) = fibo(n− 1) + fibo(n− 2)

Give a slow and an efficient implementation for fibo, and compare the run time for some inputs(e.g. 10, 20, 50, 100, 1000).

Exercise 4.2 Towers of HanoiThe following description is stolen somewhere:

The puzzle: Start with N rings, decreasing in sizes from bottom to top, stacked arounda post. There are two other posts. Your mission, should you choose to accept it, is toshift the pile, stacked in its original order, to another post.

The challenge is to do it in the fewest possible moves. Each move shifts one ring to adifferent post. But there’s a rule; you can only stack a ring on top of a larger one.

The simplest nontrivial version of this puzzle is N = 3. Solution time rises as 2N , andprograms to solve it have long been considered classic introductory exercises in the useof recursion.

Page 75: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. IMPLEMENTIERUNG EINES VCG 74

The puzzle is called ‘Towers of Hanoi’ because an early popular presentation wove afanciful legend around it. According to this myth (uttered long before the VietnamWar), there is a Buddhist monastery at Hanoi which contains a large room with threetime-worn posts in it surrounded by 21 golden discs. Monks, acting out the commandof an ancient prophecy, have been moving these disks, in accordance with the rules ofthe puzzle, once every day since the monastery was founded over a thousand years ago.They are said believe that when the last move of the puzzle is completed, the world willend in a clap of thunder. Fortunately, they are nowhere even close to being done . . .

Implement the “Towers of Hanoi”. Write a PPL function that takes the number N of rings asinput and return the list of moves. A move is a pair of the numbers of source and destinationpost. For example, (hanoi 3) returns

[[1 | 2], [1 | 3], [2 | 3], [1 | 2], [3 | 1], [3 | 2], [1 | 2]]

Exercise 4.3 ProplogicImplement a prover for propositional logic. To simplify the task, several auxiliary functions

are already defined (see appendix ??).

1. Take a look at the function applyrule (defined in file Exercise4/proplogic in your direc-tory). What does the function do?

2. Load the file in PPL (i.e. at a PPL prompt in a running system) and call the function withsome example trees like

%" |- $phi, $phi -> $psi"

as the first argument and 1 as the second argument.

3. Implement a function leftmost until failure that takes as input a tree tree and thenumber i of a premise of the tree, and reduces all premises of the tree with number ≥ i asmuch as possible. Use applyrule for single rule applications.

Hint: The body of the function has three lines.

4. Implement a function my-proplogic that applies the propositional rules on a tree and testit with the examples listed in the file proplogic.

Exercise 4.4 A simple VCGImplement a (forward working) simple VCG that reduces all program statements to predicate

logic formulas. Then simplify these goals with your propositional prover my-proplogic.The invariants for while loops should be entered by hand by the user when a loop is encoun-

tered. It makes sense to test first if the current statement is a while loop (and to fail otherwise),then to display the goal, ask for the invariant, and call the WHILE RULE with the invariant asargument. The test can be programmed using

(if (matchp (prem pt n)

%"$Gamma |- [while $epsilon do $alpha] $phi")

(while_rule (read-expr "Invariante?"))

(fail))

(see section 9.8 for read-fma). The goal can be displayed using before.The assignment rule PRAKT ASSIGN TACTIC is applied on the nth premise of a tree tree

by

(refine tree n (prakt assign tactic tree n))

Tip: Copy (and rename) your program leftmost-until-failure for the propositional proverand replace applyrule with a function that applies the rules of Hoare’s calculus instead of propo-sitional rules.

Several can be found in Exercise4/vcg-program. The example program from the previoussection is defined as alpha, the goal to prove as seq, and inv is the complete invariant.

Page 76: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. IMPLEMENTIERUNG EINES VCG 75

Exercise 4.5 Improved VCGImprove your VCG by trying to decide the tests of conditionals (thereby reducing the size of

the proof). You can do this with your program my-proplogic. Call the prover with an appropri-ate goal, and check (with premno) if the proof is closed. If this is the case, apply IF POS RULEor IF NEG RULE instead of IF FORWARD RULE and use the closed proof to close the corre-sponding subgoal in the rule.

You can test your program with seq, but use the two separat invariants inv2 and inv1 insteadof inv.

Page 77: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 6

Hoare’s Proof Strategy

6.1 Introduction

The Hoare logic ([Hoa69], [LS80]) is a well known approach to verifying “small” programs. Itwas developed during the late sixties and allows to formulate properties for the partial correctnessof while programs. These properties can then be verified using the Hoare calculus. Originally itwas not possible to express and verify termination properties. This drawback has been mendedin different enhancements later on (e.g. [LS80]). In this chapter we will use a small imperativeprogramming language with while loops. The next chapter will extend the programming languagewith local variables and recursive procedures.

The next section gives an overview on the proof method of Hoare. The syntax and semanticsof programs is defined formally in Section 6.3. This section also defines Dynamic Logic, whichextends predicate logic formulas with two new formulas that contain programs. The new formulascan be used to express Hoare triples in the sequent calculus of KIV as described in Section 6.4.This section also gives the original Hoare rules, and the rules used in KIV. Section 6.5 gives anexample proof. Section 6.6 describes the strategy used in KIV to normalize goals (all predicatelogic is moved to the end of the antecedent). Finally, Section 6.7 describes the heuristics forsymbolic execution, that can be used to automate proofs.

6.2 The Proof Strategy

A Hoare formula has three parts:

precondition: ϕ (formula in predicate logic)

program: α

postcondition: ψ (formula in predicate logic)

notation:

{ϕ}α{ψ}Its interpretation is as follows: if precondition ϕ holds and program α terminates, then postcon-dition ψ holds after α has been executed.

In order to prove, that a specification SPEC implies a Hoare formula

{ϕ}α{ψ},

i.e.SPEC |= {ϕ}α{ψ}

76

Page 78: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 77

holds, proof rules are used. For each program construct exactly one proof rule exists. These rulesmake up the core of the Hoare calculus. They combine logical and algebraic properties of useddata with properties of the program structure. The rules do not depend on an interpretation ofthe data type, but are valid in general.

The proof strategy is as follows: Proof rules are used to reduce the program of a given Hoareformula {ϕ}α{ψ} to simpler programs, until formulas in pure predicate logic result. Proving thesepredicate logical sub goals then is sufficient for the correctness of the overall Hoare formula relativeto the chosen interpretation. Because of this strategy, the Hoare calculus is also called a VCG(Verification Condition Generator) approach in program verification.

In the following, programs are defined as relations between initial and final state. The notationfor Hoare formulas is slightly different in the Dynamic Logic of KIV. A Hoare formula {ϕ}α{ψ}will be written as ϕ [α] ψ.

6.3 Syntax and Semantics of Programs

Syntax

The set of programs PROG is defined as being the smallest possible set for which the followingholds:

• skip ∈ PROG (empty program)

• abort ∈ PROG (never terminating programm)

• x := t ∈ PROG (parallel/random assignment), where xi ∈ Xsi and ti ∈ Tsi ∪ {?}

• if ε then α else β ∈ PROG (conditional), where α, β ∈ PROG, ε ∈ BXP

• { α; β } ∈ PROG (composition), where α, β ∈ PROG

• while ε do α ∈ PROG (loop), where α ∈ PROG and ε ∈ BXP

Remarks:

1. Superfluous { . . .} blocks are omitted.

2. if ε then α else skip is abbreviated as if ε then α

3. skip is equivalent to x := x

4. abort is equivalent to while true do skip

Semantics

Given an algebra A and states z and z′ the semantics of a program z[[α]]z′ is defined as follows.1

• z[[skip]]z′, iff (if and only if) z = z′

• [[abort]] is false for every pair of states (empty relation)

• z[[x := t]]z′, iff z′ = z[x ← [[t]]z], where [[?]]z represents an arbitrary value

• z[[{ α; β }]]z′, iff there is a z′′ such that z[[α]]z′′ and z′′[[β]]z′

• z[[if ε then α else β]]z′, iff [[ε]]z = tt and z[[α]]z′, or [[ε]]z �= tt and z[[β]]z′

• z[[while ε do α]]z′, iff there is a finite sequence of states z0, . . . , zn (n ≥ 0) such that

1z[[α]]z′ is a relation on states in infix notation. It depends on the algebra A, so we write z[[α]]Az′, if we wantto emphasize the dependency.

Page 79: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 78

– z = z0, z′ = zn,

– [[ε]]z0 = tt = . . . = [[ε]]zn−1= tt, [[ε]]zn = ff , and

– zi[[α]]zi+1 for each i with 0 ≤ i < n

(zi is the state after the ith repetition of the loop)

Semantics of Formulas in Dynamic Logic

The semantics of formulas in Dynamic Logic is similar to the semantics of formulas in predicatelogic with the following additional two constructs.

• [[[α] ϕ]]z = tt, iff for all states z′, z[[α]]z′ implies [[ϕ]]′z = tt gilt. (The different z′ represent

the reachable final states of program α.)

• [[〈α〉 ϕ]]z = tt, iff there is a state z′ for which z[[α]]z′ and [[ϕ]]′z = tt hold. (This implies, thatprogram α terminates, i.e. there is a reachable final state z′.)

Program Equivalence

Two programs α, β are equivalent, short α ≡ β, iff their semantics are the same in all models, i.e.for all A ∈ Alg(Σ) [[α]]A = [[β]]A holds.

Remarks on Dynamic Logic

• The semantics of Dynamic Logic does not evaluate program formulas “statically”, using afixed variable setting, but “dynamically”, depending on the location within other dynamiclogic formulas. The inital states may result from the execution of other programs. Thereforethe term “Dynamic Logic” is used.

• [[[α] ϕ]]z = tt is always true, if α does not terminate. Thus [α] ϕ models partial correctness.Contrary to this 〈α〉 ϕ is always false, if α does not terminate.

• Formula 〈α〉 ϕ ↔ ¬ [α] ¬ ϕ is valid. Therefore diamonds can be defined using boxes andvice versa.

• If α ≡ β, then for all ϕ, 〈α〉 ϕ ↔ 〈β〉 ϕ is valid.

• If x1, . . . , xn are the variables of α and/or β, and y1, . . . , yn are different varables, then thevalidity of 〈α〉 (x1 = y1 ∧ . . . ∧ xn = yn) ↔ 〈β〉 (x1 = y1 ∧ . . . ∧ xn = yn) implies α ≡ β

• The last two remarks show, that program equivalence can be expressed in Dynamic Logic.

6.4 The Proof Rules

In the following, the rules of Hoare calculus are explained. First a general translation of Hoarenotation into Dynamic Logic is given. Afterwards all Hoare rules—written as sequent calculusrules—which are currently available in KIV are listed. In general more than one calculus rule fora program construct exists. The additional rules allow to partly overcome the disadvantages of apure VCG: trivial subgoals are omitted.

Page 80: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 79

Hoare Formulas in KIV

Hoare formulas can be expressed in Dynamic Logic as follows:

Hoare formula{ϕ}α{ψ}

sequentϕ [α] ψ

In Dynamic Logic ψ may also contain programs.

Hoare Rules in KIV

Assignment

assign (Hoare){ϕτx}x := τ{ϕ}

If a formula ϕ holds for (free instances of) variables x being substituted with term τ , thenϕ holds after the assignment has been executed.

assign right (DL)

Γ ϕτx,ΔΓ [x := τ ]ϕ,Δ

Γx′x , x = τx

′x ϕ,Δx′

x

Γ [x := τ ]ϕ,Δ

These rules are not axioms as with Hoare, because the consequence rule of Hoare has beenintegrated. The first variant of the rule is used if it is possible to substitute x with τ in ϕ(e.g. if ϕ is a predicate logic formula). Otherwise the second variant is used, where x′ is anew variable.

The name of the rule is extended with right because this rule is applicable, if an assignmentoccurs in the succedent of a sequent.

Conditionals

if-then-else (Hoare){ϕ ∧ ε}α{ψ} {ϕ ∧ ¬ ε}β{ψ}{ϕ}if ε then α else β{ψ}

• If ε holds α is executed.

• If ¬ ε holds β is executed.

if right (DL)Γ, ε [α]ϕ,Δ Γ,¬ ε [β]ϕ,Δ

Γ [if ε then α else β]ϕ,Δ

if positive right (DL)Γ ε Γ [α]ϕ,Δ

Γ [if ε then α else β]ϕ,Δ

Applying this rule only makes sense if Γ → ε is provable.

if negative right (DL)Γ ¬ ε Γ [β]ϕ,Δ

Γ [if ε then α else β]ϕ,Δ

Applying this rule only makes sense if Γ → ¬ ε is provable.

Page 81: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 80

Loops

while (Hoare){Inv ∧ ε}α{Inv}

{Inv}while ε do α{Inv ∧ ¬ ε}

• Inv is called loop invariant.

• If ε holds, the body of the loop is executed and Inv must hold afterwards.

• If ¬ ε holds, the body of the loop is not executed and Inv ∧ ¬ ε is trivially true, becauseInv is a precondition.

invariant right (DL)

Γ Inv,Δ Inv, ε [α]Inv Inv,¬ ε ϕΓ [while ε do α]ϕ,Δ

• Inv is called loop invariant.

• The consequence rule has been integrated into this rule.

while right (DL)Γ, ε [α][while ε do α]ϕ,Δ Γ,¬ ε ϕ,Δ

Γ [while ε do α]ϕ,Δ

This rule can be used if an invariant is not needed, e.g. if the loop is executed exactlythree times. The next two rules are special cases of this rule (comparable to if vs. ifpositive/negative).

while unwind right (DL)

Γ ε Γ [α][while ε do α]ϕ,Δ

Γ [while ε do α]ϕ,Δ

This rule is applicable if the rule test ε is provable before executing the loop. In this specialcase the body of the loop can be executed once instead of giving an invariant.

while exit right (DL)Γ ¬ ε Γ ϕ,ΔΓ [while ε do α]ϕ,Δ

If the rule test ε does not hold the loop is exited.

Remark: The rules while right, while unwind right and while exit right are special cases of theinvariant rule invariant right. It is possible to only use invariant right, but with the additionalrules proofs may become shorter.

Composition

composition (Hoare){ϕ}α{χ} {χ}β{ψ}{ϕ}α;β{ψ}

For this rule an intermediate assertion χ has to be guessed. In order to avoid this, programformulas are normalized in the sequent calculus of KIV.

normalize (DL)Γ [α][β]ϕ,Δ

Γ [α; β]ϕ,Δ

This rule is automatically applied after each rule application. Therefore it is not a calculusrule on its own.

Page 82: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 81

Rule normalize offers two possibilities to approach program verification:

forward: A sequent of program constructs is executed from left to right, i.e. a rule applicationsimplifies the first construct of a program.

backward: A sequent of program constructs is executed from right to left, i.e. a rule applicationsimplifies the last construct of a program.

Here, the forward direction is preferred, because it follows the intuition of symbolically executingprograms. As a disadvantage of this strategy a slightly more complicated assignment rule is neededwhich is capable of substituting variables in programs (see above).

Consequence

consequence (Hoare)ϕ→ ψ {ψ}α{χ} χ→ δ

{ϕ}α{δ}In KIV a consequence rule is not explicitly provided, since the predicate logic rules areavailable already (with simplifier, case distinction etc.).

Additional Rules

In DL we additionally use the skip program that does nothing, and occasionally the abortprogram that never terminates.

skip right (DL)Γ ϕ,Δ

Γ [skip]ϕ,Δ

abort right (DL)

〈abort〉ϕ,Γ Δ

6.5 An Example Proof

We will try to prove the partial correctness of a program that implements the function square onnatural numbers by repeated addition.

{0 ≤ n ∧ m = 0}

{k := 0;

while k < n do{

k := k + 1;

m := m + n;

}}{m = n ∗ n}

This Hoare formula is expressed in Dynamic Logic as follows:

0 ≤ n ∧ m = 0

[{k := 0;

while k < n do{

Page 83: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 82

k := k + 1;

m := m + n

}} ] m = n ∗ n

This formula can be found in project Exercise5 as the theorem 1-example in the specifica-tion hoare. (This specification is just an empty enrichment, and used only to store our theo-rems/exercises.) In order to trace all subgoals of rule applications, choose Control/Options andselect option “No automatic predtest”. This option prevents simple predicate logical subgoalsfrom disappearing.

We begin with the normalised sequent

0 ≤ n, m = 0

[k := 0;]

[while k < n do{

k := k + 1;

m := m + n

} ] m = n ∗ n

The first program statement is an assignment. Applying rule assign right results in the followingsequent:

0 ≤ n, m = 0, k = 0

[while k < n do

{k := k + 1;

m := m + n

} ] m = n ∗ n

Next, rule invariant right is applied. This rule requires an invariant. The appropriate invariantis m = k ∗n ∧ k ≤ n. It can be entered in concrete syntax as m = k * n and k \le n. You maywonder why we need the condition k ≤ n – we will see later.

Applying invariant right yields three subgoals:

1. 0 ≤ n, m = 0, k = 0, m �= k ∗ n ∨ ¬ k ≤ n

2. k < n, m = k ∗ n, k ≤ n [ k := k + 1] [ m := m + n] (m = k ∗ n ∧ k ≤ n)

3. ¬ k < n, m = k ∗ n, k ≤ n, m �= n ∗ n

Remark: Goal 1 and goal 3 differ from the first and the third premise of the invariant rule in thatall formulas appear in the antecedent of the sequent. This is due to the ‘normalization’ that keepsall predicate logic formulas in the antecedent for program proofs.

The intention of the three goals of rule invariant right is as follows: Partial correctness of awhile loop is guaranteed if the loop invariant

• holds at the beginning of a loop (goal 1),

• holds after each execution of the loop’s body (goal 2), and

• implies the postcondition after the while loop has terminated (goal 3).

We are now trying to prove goal 1. The sequent of this goal no longer contains programconstructs because the application of rules of the Hoare calculus resulted in a predicate logicsubgoal. In order to prove this goal, rule simplifier is applied. This rule automatically closesgoal 1.

Goal 2 still contains two assignments which can be eliminated by applying rule assign righttwice. The first application leads to

Page 84: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 83

k < n, m = k ∗ n, k ≤ n [ m := m + n] (m = (k + 1) ∗ n ∧ k + 1 ≤ n)

the second application results in

k < n, m = k ∗ n, k ≤ n, m + n �= (k + 1) ∗ n ∨ ¬ k + 1 ≤ n

Now also goal 2 can be closed by applying rule simplifier.Similar to goal 1, goal 3 only contains formulas in predicate logic. Applying rule simplifier

also closes this last goal. However, here the condition k ≤ n is essential, because we need to knowthat k = n. The negated loop condition only gives the information n < k. The information thatk is incremented only by 1 so that afterwards k = n must be explicitly stated in the invariant byk ≤ n.

Remark: If option ‘No automatic predtest’ is not selected, subgoals in pure predicate logicwhich can be automatically closed with the help of the simplifier are not generated at all. Thesimplifier is internally applied. In this example, rule invariant right produces only goal 2.

6.6 Normalization

When proving properties of programs the predicate logic formulas form the context of the currentgoal. Experience shows that a user ignores them most of the time and concentrates on the programformulas. In order to help this concentration, sequents containing program formulas are orderedin a special manner.

1. The first part of the antecedent contains only program formulas.

2. An optional induction hypothesis follows.

3. The rest of the antecedent contains all(!) predicate logic formulas of the sequent.

4. The succedent contains only program formulas.

Predicate logic formulas are kept in the antecedent even if this means that negations are notresolved. The rule case distinction is applicable also on negated conjunctions etc. For programformulas, negations are resolved in the usual manner. This ordering is introduced automaticallywhen beginning a new proof (this may lead to a first proof step called normalize that can neverappear anywhere else in a proof), and kept intact automatically during a proof (without visibleproof steps).

The normalization also deals with compounds. (It may have been noted that no proof rulefor compounds exists.) A formula 〈α;β〉 ϕ is equvialent to 〈α〉 〈β〉 ϕ. Using this equivalence,compounds are eliminated.

6.7 Heuristics

When proving properties using the Hoare strategy, the following choice of heuristics are of interest:

• symbolic execution:

The following noncritical rules are automatically applied on the first program construct inthe succedent:

– assign right

– if positive right

– if negative right

– skip right

• loop exit:

If it can be automatically shown, that the loop test is false, rule while exit right is applied.

Page 85: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 84

• unwind:

If a loop test evaluates to true, the body of the loop is executed once (rule while unwindright).

• simplifier:

This heuristic decides, if rule simplifier should be applied, e.g. if predicate logical formulashave changed.

• conditional right split:

This heuristic tries to apply rule if right on the first formula in the succedent.

Heuristics are selected by choosing Control/Heuristics. An additional window is displayed whichallows to

• select a predefined set of heuristics (all heuristics above are included in the set of heuristicscalled DL Heuristics + Case Splitting),

• deactivate all heuristics, or

• arrange an individual set of heuristics.

In the last case, a window with two columns is displayed, listing all available heuristics on the leftand all selected heuristics on the right. A heuristic is selected by clicking on its name. The orderof selection determines the application order of heuristics. By pressing ‘OK’, the heuristics areactivated and are automatically applied on the current goal.

6.8 Exercise 5, Part 1

Task: Prove the Hoare formulas listed below with KIV. They are formulated as theorems inspecification hoare in the project “Exercise5”. For each exercise a corresponding theorem exists.

Exercise 5.1 exampleRedo the example described above.

Exercise 5.2 sumThe following program calculates z =

∑x≤nx=0 x. Prove the following theorem:

z = 0 ∧ m = 0

[ while m ≤ n do

{z := z + m;

m := m + 1

} ]z = (n * (n + 1)) / 2

Exercise 5.3 moduloThe following program calculates the remainder of a division of natural numbers n mod m.

The original input to the program is stored in variables n0 and m0. The result of the calculationis contained in n.

n = n0 ∧ m = m0

[ while m ≤ n don := n - m ]

(∃ k. k ∗ m0 + n = n0 ∧ n < m0)

Page 86: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 6. HOARE’S PROOF STRATEGY 85

Additionally try to prove 3-modul-termination. The theorem is the same as for modulo, butnow with diamonds instead of boxes (meaning you have to prove termination now). When usingthe ‘invariant right’ rule, you will now additionally have to give a decreasing term.

If your proof attempt fails think about the reason and change the theorem accordingly. Thenprove the corrected theorem.

Exercise 5.4 binary searchGiven is an array ar of some totally ordered elements with values stored between the two

indices mi (minimum) and ma (maximum). The values in the array are sorted in ascending order.Additionally an element searched is given, which is contained in the array between the two givenindices. The program computes the index of the element searched by applying a binary searchstrategy. The correctness of the program is to be verified with the help of the standard set ofheuristics.

mi ≤ ma ∧ sor<(ar,mi,ma) ∧ ∃ n. ar[n] = searched ∧ mi ≤ n ∧ n ≤ ma

[ lower := mi;

upper := ma;

while lower �= upper do{middle := (lower + upper) / 2;

if ar[middle] < searched

then lower := middle + 1

else upper := middle;

} ](ar[lower] = searched ∧ mi ≤ lower ∧ lower ≤ ma)

ar[n] selects the element stored in array ar with index n. sor<(ar,mi,ma) is a predicate whichis true if and only if the elements between the indicesmi andma of array ar are sorted in ascendingorder (relative to an order predicate <). Predicate sor< is defined in specification oarray. Note:Properties, i.e. theorems, of this specification must be used (by insert rewrite lemma or insertspec-lemma.

Page 87: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 7

The Specifications for HoaredaVinci

V2.

1

nat−prime natlist

natlista

intnat

int−div

int−mult

int−abs

int−basic2

int−basic1

olist−sort

olist

olista

list−perm

list−set

list−del

list−last

list−dup

list

list−data

hoare

oarray

oarraya

gelem

oelem

array

nat−pot

elem

nat−div

nat−mult

nat

nat−basic2

nat−basic1

86

Page 88: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. THE SPECIFICATIONS FOR HOARE 87

hoare = nat-pot + nat-prime + natlist + oarray

oarray =enrich oarraya with

predicates <sor : array × nat × nat;variables m0: nat;

axioms

<sor(ar, m, n) ↔ n < # ar ∧ (∀ m0, n0. m ≤ m0 ∧ m0 < n0 ∧ n0 ≤ n → ar[m0] <ar[n0]);

end enrich

oarraya =actualize array with gelem by morphism

end actualize

array =generic specification

parameter elem using nat targetsorts array;functions

mkarray : nat → array ;. [ . ] : array × nat → elem prio 2;. [ . ] : array × nat × elem → array ;# . : array → nat ;pos : array × elem → nat ;

variables ar, ar0, ar1, ar2: array;

axioms

array generated by mkarray, ];Extension : ar1 = ar2 ↔ # ar1 = # ar2 ∧ (∀ n. n < # ar1 → ar1[n] = ar2[n]);

Size-mkarray : # mkarray(n) = n;

Size-put : # ar[n, a] = # ar;

Put-same : m < # ar → ar[m, a][m] = a;

Put-other : m �= n → ar[n, a][m] = ar[m];

Pos-found :(∃ n. n < # ar ∧ ar[n] = a)

→ pos(ar, a) < # ar ∧ ar[pos(ar, a)] = a ∧ (∀ m. m < pos(ar, a) → ar[m] �= a);

Pos-notfound : (∀ n. n < # ar → ar[n] �= a) → pos(ar, a) = # ar;

end generic specification

natlist =enrich natlista with

functionsΣ . : natlist → nat ;Π . : natlist → nat ;

Page 89: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. THE SPECIFICATIONS FOR HOARE 88

axioms

sum-empty : Σ @ = 0;

sum-rec : Σ(n ’ + nats) = n + Σ nats;

prod-empty : Π @ = 1;

prod-rec : Π(n ’ + nats) = n ∗ Π nats;

end enrich

natlista =actualize olist-sort with intnat by morphism

elem → nat; list → natlist; -1l → -pos; a → m0; a0 → m1; b → m2; c → m3;x → nats; x0 → nats0; y → nats1; z → nats2; y0 → nats3; z0 → nats4; x1 →nats5; y1 → nats6; z1 → nats7; x2 → nats8; y2 → nats9; z2 → nats10

end actualize

olist =enrich olista with

functionsins : elem × list → list ;merge : list × list → list ;

predicates≤ordered : list;<ordered : list;

axioms

le-e : ≤ordered(@);

le-o : ≤ordered(a ’);

le-r : ≤ordered(a ’ + b ’ + x) ↔ ¬ b < a ∧ ≤ordered(b + x);

ls-e : <ordered(@);

ls-o : <ordered(a ’);

ls-r : <ordered(a ’ + b ’ + x) ↔ a < b ∧ <ordered(b + x);

ins-e : ins(a, @) = a ’;

ins-y : ¬ b < a → ins(a, b ’ + x) = a + b + x;

ins-n : b < a → ins(a, b ’ + x) = b + ins(a, x);

end enrich

list =enrich list-data with

functions. ’ : elem → list ;. + . : list × list → list prio 9;. + . : list × elem → list prio 9;. + . : elem × elem → list prio 9;

predicates . ∈ . : elem × list;

axioms

Page 90: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. THE SPECIFICATIONS FOR HOARE 89

Nil : @ + x = x;

Cons : (a + x) + y = a + x + y;

One : a ’ = a + @;

Last : x + a = x + a ’;

Two : a + b = a ’ + b ’;

in : a ∈ x ↔ (∃ y, z. x = y + a + z);

end enrich

list-data =generic data specification

parameter elem using natlist = @

| . + . prio 9 (. .first : elem ; . .rest : list ;) prio 9;

variables x, y, z, x0, y0, z0, x1, y1, z1, x2, y2, z2: list;size functions # . : list → nat ;order predicates . < . : list × list;

end generic data specification

gelem =generic specification

parameter oelem targetend generic specification

oelem =enrich elem with

predicates . < . : elem × elem;

axioms

irreflexivity : ¬ a < a;

transitivity : a < b ∧ b < c → a < c;

totality : a < b ∨ a = b ∨ b < a;

end enrich

elem =specification

sorts elem;variables a, b, c: elem;

end specification

Page 91: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 7. THE SPECIFICATIONS FOR HOARE 90

nat-prime =enrich nat-div with

functions gcd : nat × nat → nat ;predicates

prime : nat;. | . : nat × nat;

axioms

Prime : prime(n) ↔ 1 < n ∧ (∀ m. m | n → m = 1 ∨ m = n);

Divides : m | n ↔ (∃ n0. m ∗ n0 = n);

gcd-zero : gcd(0, n) = n;

gcd-c : gcd(m, n) = gcd(n, m);

gcd-rec1 : n ≤ m → gcd(m, n) = gcd(m - n, n);

end enrich

nat-pot =enrich nat-div with

functions. ˆ . : nat × nat → nat prio 12;log : nat × nat → nat ;2ˆ . : nat → nat ;log2 . : nat → nat ;

axioms

Pot-zero : n ˆ 0 = 1;

Pot-succ : n ˆ m +1 = n ˆ m ∗ n;Logdef : m ˆ n0 ≤ n ∧ n < m ˆ n0 +1 → log(m, n) = n0;

Pot2-zero : 2ˆ 0 = 1;

Pot2-succ : 2ˆ n +1 = 2 ∗ 2ˆ n;

Log2def : 2ˆ m ≤ n ∧ n < 2ˆ m +1 → log2 n = m;

end enrich

nat-div =enrich nat-mult with

functions. / . : nat × nat → nat prio 11;. % . : nat × nat → nat prio 11;

axioms

Divdef : n �= 0 → m / n ∗ n ≤ m ∧ m < (m / n)+1 ∗ n;Moddef : n �= 0 → m = m / n ∗ n + m % n;

end enrich

Page 92: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 8

Procedures and Local Variables

In this chapter we extend Dynamic Logic with procedures and local variables. Their syntax andsemantics are given is defined in the first four sections. Section 8.5 gives an example proof . Thelast two subsections give new symbolic executions rules and describe new heuristics for unfoldingcalls.

8.1 Syntax of Procedure Declarations and Calls

Besides the program statements that were used in the first Hoare exercise (like while and if) itis also possible to use procedures and local variables. Procedures have to be declared globally inspecifications:

predicates . . .procedures p1 s1,1, s1,2, . . . , s1,n1 : s

′1,1, s

′12, . . . , s

′1,m1

;p2 s2,1, s2,2, . . . , s2,n2 : s

′2,1, s

′2,2, . . . , s

′2,m2

;...pk sk,1, sk,2, . . . , sk,nk

: s′k,1, s′k,2, . . . , s

′k,mk

;variables . . ....axioms . . .declaration

p1 (x1,1, x1,2, . . . , x1,n1 ; y1,1, y1,2, . . . , y1,m1) { α1 }p2 (x2,1, x2,2, . . . , x2,n2 ; y2,1, y2,2, . . . , y2,m2) { α2 }

...pk (xk,1, xk,2, . . . , xk,nk

; yk,1, yk,2, . . . , yk,mk) { αk }

The procedures part defines procedure symbols as an additional part of the signature. Thedeclaration part gives procedure declarations for each of the procedures p1, . . . , pk (which maybe mutual recursive). p1 has the value parameters x1,1, x1,2, . . . , x1,n1 of sorts s1,1, s1,2, . . . , s1,n1

and the reference parameters y1,1, y1,2, . . . , y1,m1 of sorts s′1,1, s′1,2, . . . , s

′1,m1

. All these parametersmust be different variables. The semantics of value and reference parameters is input and outputparameters. The reference parameters can be used as input/output parameters by adding thekeyword nonfunctional at the end of the signature definition. Otherwise any procedure body,which does not write the reference parameters, or reads some parameter before writing it, willbe rejected. Similarly, the signature definition must contain the keyword indetermistic at theend, if you want a nondeterministic procedure (the information on a procedure being functionalor determistics helps KIV to have more efficient symbolic execution rules for procedures). There

91

Page 93: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 92

are no nested procedure declarations. A procedure call of p1 has the form

p1(σ1,1, σ1,2, . . . , σ1,n1 ; z1,1, z1,2, . . . , z1,m1)

σ1,1, . . . , σ1,n1 are arbitrary terms (or variables), z1,1, . . . , z1,m1 must be pairwise different variables.Typically for every procedure defined in the procedures section a declaration is given. But thisis not necessary. It is also possible to leave away the declaration and to just write axioms aboutprocedure calls (indeed, a procedure declaration can be translated to axioms that specify theprocedure semantics unambigously).

8.2 Syntax of Local Variable Declarations

Local variable declarations have the form

let x1 = t1, . . . , xn = tn in { α }The local variables x1, . . . , xn are defined with α as its scope. It is not necessary to give a type(as in Java) because they must have a signature entry already which fixes their type (it is notpossible to use a local variable with different types in different places). Initial values t1, . . . , tnare mandatory to avoid undefined values. The initial values are evaluated in parallel, i.e. xj usedinside of σi references the global value of xj , not tj .

8.3 Semantics of Procedures

To define the semantics of procedures we add a new component to signatures: Σ = (S,OP, P )where P =

⋃s∈S∗,s′∈S∗Ps,s′ is the of procedure names with value parameters of sorts s and

reference parameters of sorts s′ (procedure names are used in programs). A Σ-Algebra nowcontains for every p ∈ Ps,s′ a relation pA on As,s′ and As′ . The idea is that (a, b, c) ∈ pA iff theprocedure started in a state z where value parameters have values a and reference parameters havevalues b will give a final state where reference parameters have values c. If the procedure does notterminate in state z with, then there will be no c in the relation. For a functional procedure (theusual case), the result does not depend on b. For a deterministic procedure (the usual case again),there is at most one value c for every (a and b. The semanctics of a procedure call therefore is:

z[[p(t, u)]]z′ iff z(t), z(u), z′(u) ∈ [[p]] and z(y) = z′(y) for all y �∈ u.

A procedure declaration p(x; y){α} roughly1 states, that the semantics of a procedure call isequivalent to the semantics of the body

z[[p(x; y)]]z′ iff z[[α]]z′

Dynamic Logic can express this semantic equivalence as program equivalence:

〈p(x; y)〉 y = z ↔ 〈α〉 y = z

This equivalence is used in the call rule for procedures.

1for recursive procedure declarations this definition is too weak, and the semantics must be given as the leastfixpoint of procedure calls with bounded depth. We irgnore this problem here

Page 94: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 93

8.4 Semantics of Local Variables

The semantics of a local variable declaration let x = t in α is simpler. Given an initial state zthe definition first evaluates terms t in the current state to give the initial values a for the localvariables. Then it overwrites the values of x in z with a and runs α in the resulting state. If αterminates and gives a final state z′′, the local variables must finally be deallocated. To do this,they are replaced with the initial values z(x) of the global variables to give the final state z′ of thewhole program. Formally

z[[let x = t in α]]z′ iff z[x ← a][[α]]z′′ and z′ = z′′[x ← [[x]]z(x)] where ai = [[ti]]z.

8.5 An Example Proof

This section gives an example for a proof involving a recursive procedure. The proof can befound in specification hoare-proc of the specifications for this exercise. The procedure checks themembership of a natural number in a list of natural numbers. The procedure is defined in KIV asfollows:

member#(n, nats; var boolvar)

if nats = []

then boolvar := false

else if n = nats .first

then boolvar := true

else member#(n, nats .rest; boolvar);

The signature of the procedure consists of three parameters, two input parameters and one outputparameter. The input parameters are n and nats, where n is a natural number and nats is a listof natural numbers. The output parameter is named boolvar and is of type bool. When theprocedure is called, it is first determined, whether the list of natural numbers is empty. If thisis so, the result is set to false, as no number is element in the empty list. If the list of naturalnumbers is non-empty, the number n is checked against the first member of the list. If n and thefirst member of the list are equal, the MEMBER# function terminates with the result value true,otherwise, MEMBER# is called recursively.

We expect boolvar to be true after termination, iff the list nats contains the number n. Wewant to prove this property in KIV. To do so, we formulate a lemma in KIV with the followingform:

〈MEMBER#(n, nats; boolvar)〉 boolvar ↔ n ∈ nats;

To verify this lemma, induction is required, since the procedure is recursive. We choose structuralinduction for the list nats, since the recursive call has an argument, which is one constructorsmaller than the original argument (if in general, the recursive argument is smaller in some well-founded order, then induction insterad of structural induction must be used). The basis ofthis induction is rather simple. As nats is the empty list, it can be evaluated, that n ∈ nats isfalse. Therefore, the proof obligation is simply to verify, that MEMBER# evaluates to false forthe empty list:

〈MEMBER#(n, []; boolvar)〉 ¬ boolvar

With the application of the rule call left, the MEMBER# function call is replaced by theprocedure body:

Page 95: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 94

〈if [] = []

then boolvar0 := false

else if n = [] .first

then boolvar0 := true

else member#(n, [] .rest; boolvar0)〉 boolvar0

The conditional can be decided using the if positive rule. This leaves the assignment on theantecedent of the sequent:

〈boolvar0 := false〉 ¬ boolvar0

Using the assign rule, this goal can be closed. For the inductive case, the following goal resultsafter simplification:

∀ n. 〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n ∈ nats0)

〈MEMBER#(n, m ’ + nats0; boolvar)〉 (boolvar ↔ n = m ∨ n ∈ nats0);

Note that the KIV library of lists has simplifier rules, that normalize m+ nats0 (where + :: nat× natlist→ natlist) to m′+nats0, where + appends lists and the quote (’) operator creates a oneelement list from an element (this allows to use associativity of append more often).

The idea for a proof is to apply rules, such that the procedure call in the induction hypothesis(with argument nats) can be matched to the procedure call in the sequent. Since the currentcall with m′ + nats0 has a recursive call in its body with arguments nats0, this can be done bysymbolically executing the procedure MEMBER#.

The first step to do this is to apply the call right rule, which again replaces the call withthe body. The first test m′ + nats0 = [] is false, so if negative right can be applied and gives

∀ n. 〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n ∈ nats0)

〈if n = m then boolvar0 := true

else MEMBER#(n, nats0; boolvar0)〉(boolvar ↔ n = m ∨ n ∈ nats0)

Applying if right gives two goals. The first, where m = n can be closed with assign right.The second goal is

∀ n. 〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n ∈ nats0),

n �= m

〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n = m ∨ n ∈ nats0)

The formula on the right now is almost the induction hypothesis. Instantiating the quantifierwith n and discarding it (since we only need this one instance) gives:

〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n ∈ nats0)

〈MEMBER#(n, nats0; boolvar)〉 (boolvar ↔ n = m ∨ n ∈ nats0)

Now symbolic execution of the two formulas does not help (it will only lead deeper into therecursion). We need a method to reduce a goal of the form

Γ, 〈α〉 ϕ 〈α〉 ψ, Δ

Page 96: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 95

to a goal that ϕ implies ψ. The execute call rule does this reduction. If both sides areprocedure calls, then this rule allows different output parameters in the calls in the antecedentand succedent (they can be renamed to be equal). The rule gives a slightly stronger premise thanjust the impliciation:

Γ, 〈α〉 (x = y), ϕyx ψ

yx, Δ

It says that the implication must be proved only for values y, which are possible results ofexecuting α. The first formula of the antecedent says that y are such values: x are the variablesthat are modified by α (if α is a call, then these are just the ouput parameters of the call). yare new variables, which store the resulting values. Note that KIV automatically applies executecall as soon as heuristics for DL goals are used.

Applying execute call closes the proof, since the resulting predicate logic goal can be closedby the simplifier.

8.6 Functional Specification of Prodedures

Instead of giving an implementation for a procedure, KIV also allows a functional specificationof what the call does, leaving the implementation open. An example for such a specification isNEXTTOKEN#:

nextok-spec:

nats = nats0

〈NEXTTOKEN#(;nats,tok)〉( (tok = error → nats = nats0)

∧ (tok �= error → tostring(tok) �= [] ∧ tostring(tok) + nats = nats0))

The idea of NEXTTOKEN# is to do lexical analysis in a parser: given a string (for simplicitywe represent the string as a list of ASCII codes, i.e. natural numbers). NEXTTOKEN# searchesfor an occurence of some token at the start of the string (if the string is a Java program read froma file, example tokens are key words like ”‘try”’ or ”‘if”’). The specification of tokens abstractsfrom the exact nature of tokens (in a real parser token would be numbered), it just defines a sortof tokens and a function tostring which a string representation, and that there is a special tokenerror (a constant). The error token is used as the result of NEXTTOKEN#, when the inputstring does not start with a token. In this case the first clause of the postcondition says, that thestring nats should be returned unchanged (nats is used as input and output, tok is used as outputonly; nats0 is used to save the initial value of nats). Otherwise the second clause says, that thetoken should have a nonempty string representation, and the string should have been shortenedby the string representation of the token2.

Since the implementation of NEXTTOKEN# is left open, symbolic execution of this function isnot possible. Instead it is necessary to insert the lemma nextok-spec, whenever NEXTTOKEN#is used in a sequent, and use rules execute call (see the example proof above) or contract call.The latter rule is similar to execute call, but it assumes that both calls are in the antecedent.

8.7 Rules for Procedures and Local Variables

This section document the rules for procedures and local variables. The name given to each ruleis the name used in KIV . The actual implementation of a rule might differ in some details fromits representation. Especially we try to introduce as less new variables and equations as possible.Those simplifications, however, should allow the user to choose a rule — it is the purpose of thesystem to handle these technical details.

2this is a simplification: in reality, the string would also be shortened by additional spaces, so the equality wouldbe modulo spacing

Page 97: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 96

Almost all rules are also applicable for box formulas instead of diamond formulas.Almost all rules are applicable not only on the first formula in the antecedent or succedent but

on a formula at an arbitrary position.

call right

y = σ,Γ 〈αxz 〉ϕ,ΔΓ 〈f(σ, x)〉ϕ,Δ

for bounded procedure blocks:

Γ 〈αxz times κ〉ϕ,ΔΓ 〈f(σ, x) times κ+ 1〉ϕ,Δ

Γ 〈abort〉ϕ,Δy = σ,Γ 〈f(σ, x) times 0〉ϕ,Δ

• The specification contains a declaration f(y, z).α

• Variables y,z of the declaration are not free in the sequent (otherwise they are renamed)

• The counter κ specifies the number of calls allowed at most.

• Rule applicable on boxes too

call left

y = σ, 〈αxz 〉ϕ,Γ Δ

〈f(σ, x)〉ϕ,Γ Δ

for bounded procedure blocks:

y = σ, 〈αxz times κ〉ϕ,Γ Δ

〈f(σ, x) times κ+ 1〉ϕ,Γ Δ

〈abort〉ϕ,Γ Δ

〈f(σ, x) times 0〉ϕ,Γ Δ

• The specification contains a declaration f(y, z).α

• Variables y,z of the declaration are not free in the sequent (otherwise they are renamed)

• The counter κ specifies the number of calls allowed at most.

• Rule applicable on boxes too

execute call

Γ σ = τ 〈f(σ;x)〉(x = y), ϕyx,Γ ψ

yz

〈f(σ;x)〉ϕ,Γ 〈f(τ ; z)〉ψ• y are new variables

• the procedure f is functional

• the rule is also applicable for non-functional procedures with the additional condition Γ x = z

contract call left

Γ σ = τ 〈f(σ, z)〉(z = x′), ϕx′x , ψ

x′y ,Γ Δ

〈f(σ, x)〉ϕ, 〈f(τ , y)〉ψ,Γ Δ

• z, x′ are new variables

• the procedure f is functional

• the rule is also applicable for non-functional procedures with the additional condition Γ x = y

Page 98: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 97

contract call right

Γ σ = τ [f(σ, z)](z = x′),Γ ϕx′x , ψ

x′y ,Δ

Γ [f(σ, x)]ϕ, 〈f(τ , y)〉ψ,Δ

• z, x′ are new variables

• the procedure f is functional

• the rule is also applicable for non-functional procedures with the additional condition Γ x = y

vardecls right

x′ = τ,Γ 〈αx′x 〉ϕ

Γ 〈let x = τ in α〉ϕΓ ∃x′.〈αx′

x 〉ϕΓ 〈let x =? in α〉ϕ

• x =? is a random variable declaration

• both rules are integrated into one

• for boxes replace the ∃ by a ∀

vardecls left

〈αx′x 〉ϕ, x′ = τ,Γ Δ

〈let x = τ in α〉ϕ,Γ Δ

∃x′.〈αx′x 〉ϕ,Γ Δ

〈let x =? in α〉ϕ,Γ Δ

• x =? is a random variable declaration

• both rules are integrated into one

• Rule applicable on boxes too

split left/split right

〈α〉x = x′, ϕx′x ,Γ Δ

〈α〉ϕ,Γ Δ

Γ 〈α〉true 〈α〉x = x′,Γ ϕx′x ,Δ

Γ 〈α〉ϕ,Δ

• x = asgvars(α)

• x′ are new variables

8.8 Heuristics for Procedures

Predefined Sets of Heuristics

Heuristics are used to decrease the number of user interactions. In the best case they find proofsautomatically. Even if a proof is not found completely automatically heuristics can help the userby applying often used, mechanical rules automatically. Ideally, they find a proof completely auto-matic. But there is also a risk when using heuristics: They may apply steps which are unnecessaryor unwanted or may even lead to infinite loops. When selecting heuristics, the following (partlyantagonistic) issues have to be considered.

1. Efficiency

Since the prover works interactively, the heuristics cannot take too much time, especially incases where they can’t do anything at all. When large goals appear, usefulness vs. efficiencyof a heuristic is a real issue.

Page 99: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 98

2. Probability of wrong decisions

A wrong decision (e.g. making a case distinction when none is necessary, or instantiatingand dropping a quantifier) can lead to unprovable goals or unnecessary work for the user.Or it can make the proofs harder. A wrong decision normally means that the heuristic isdeselected and the proof tree pruned.

The more complicated the proof is, the higher the probability of wrong decisions becomes.This means, that fewer heuristics should be selected.

Unfortunately (or luckily?) the universal problem solving heuristic hasn’t been published yet.Therefore KIV offers quite a large number of heuristics (ranging from general but “dumb” tovery special but “intelligent”, and from established and useful to experimental and doubtful). Anexpert user can combine the heuristics in a manner that is most useful for the given problem.

During a proof heuristics can be enabled and disabled at any time (using the command Control

– Heuristics). Therefore heuristics can be used for a single branch of the proof or for the wholeproof. An important property of heuristics is that there is an arbitrary hierarchical ordering: Ifa heuristic can’t be applied the next heuristic according to the hierarchical ordering is tested.Furthermore a heuristic can determine which other heuristics should be applied next. Thereforeheuristics are a very flexible concept.

For example, there is a heuristic that just tests if there is an assignment, a conditional or avariable declaration. If this is the case, the corresponding rule is applied. Another heuristic onlyexecutes procedure calls and leaves the other work (the symbolic execution of procedure bodies)for other heuristics. There is also a global induction heuristic that only calls other heuristics —depending on the progress of the proof.

To choose a good set of heuristics some experience is needed. To simplifiy matters KIV of-fers three predefined sets of heuristics which are usually sufficient. Therefore after selecting thecommand Control – Heuristics a window is displayed where a set of heuristics can be chosen:

Let the system choose the heuristics

DL Heuristics + Induction

DL Heuristics + Case Splitting

DL Heuristics

No heuristics at all

Select your own heuristics

Let the system choose the heuristics : KIV chooses one of the predefined sets of heuristicsdescribed below. It uses a very simple heuristic to determine the complexity of the goal basedon the number and type of program formulas and their connection. The lower the complexity,the more heuristics are chosen. The idea is that the goal complexity has some connection tothe difficulty of the proof. The implementation of the programs is not considered (therebylimiting the usefulness of this option).

DL Heuristics + Induction : This set is useful for simple goals that can be proven by simpleinduction and symbolic execution of programs, and where case distinctions must not beavoided at any cost. This heuristic set often finds proofs automatically for simple recursiveprograms. The set consists of the following heuristics (in the listed order):

symbolic execution, conditional right split, conditional left split, contract andexecute, split, simplifier, elimination, module specific, weak unfold, Quantifierclosing, loop exit, execute loop, omega, unwind, weak cut, dl case distinction,unfold, induction, apply ind once, batch mode

DL Heuristics + Case Splitting : This set is useful for more complex goals, where nonstan-dard induction (or no induction at all) is used, or some lemmas are introduced before theinduction step, or some procedures shouldn’t be unfolded. Compared to the previous set,the induction heuristics (induction, apply ind once) and the strong heuristic for unfolding

Page 100: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 99

procedures (leading to the symbolic execution of the procedure bodies) is missing. Theremaining heuristics are

symbolic execution, conditional right split, conditional left split, contract andexecute, split, simplifier, elimination, module specific, weak unfold, Quantifierclosing, dl case distinction, omega, unwind, loop exit, execute loop

DL Heuristics : This set is for very complex goals where case distinctions (by splitting condi-tionals in programs or propositional connectives) have to be avoided at all costs. It uses theheuristics

symbolic execution, contract and execute, module specific, split, simplifier, elimi-nation, conditional

No heuristics at all : Deselect all heuristics.

Select your own heuristics : This allows to select a different set of heuristics or to modify anexisting set. It is possible to select a predefined set of heuristics and this option together.

After selecting this command a window opens containing two columns: on the left side allavailable heuristics are displayed, on the right side the currently selected heuristics are shownin order of selection. To select a heuristic click on this heuristic on the left side. It appearson the right side at the position of the black bar. To delete a heuristic currently selectedclick again on the heuristic in the left column. After leaving the window by clicking on theOK–Button the selected heuristics are applied according to their order.

Read from file ’default heuristics’ : The file ’default-heuristics’ should contain a PPL listof heuristics: (list "...""..."...). This option is for experts only.

When you begin (or continue) a proof all heuristics are disabled (but still selected). This isindicated in the status bar (by heuristics off). They can be enabled by clicking on the buttonHeuristics On/Off in the lower left corner of the window.

Description of the Heuristics

This section describes only heuristics dealing with programs.

Procedure calls

weak unfold This heuristic unfolds procedure call with the rules call left or call right. Aprocedure call can be safely unfolded if the procedure

1. is not recursive, or

2. it is recursive, but the induction hypothesis will be applied for the recursive call, or

3. it is recursive, but the context is such that the execution path is not leading to a recursivecall (i.e. the tests of if’s can be decided).

Unconditionally unfolding a procedure call and executing the body of a recursive procedure usuallydoes not terminate, and has to be avoided. Additionally, the order in which procedures areunfolded and executed (or whether to unfold them at all) can have a significant impact on thesize of the proof. If a procedure body does not contain any conditionals, or all conditionals can bedecided in a given context, then the execution of the body does not introduce any case distinctions.Furthermore, if the execution path does not lead to a recursive call, it is safe (and normally useful)to unfold the call.

The heuristic weak unfold deals with such procedures. It is called “weak” because it unfoldsfewer procedure calls than the following two heuristics.

Page 101: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 100

unfold This heuristic unfolds the same calls as weak unfold and some more. It also unfolds callsthat lead to case distinctions if one execution path contains a recursive call where the inductionhypothesis can be applied. Usually these procedures have to be unfolded to finish the proof. Theheuristic keeps track of the procedures and will unfold each call only once. It tries to find the bestcall to unfold that will minimize the size of the proof. This depends on the statical call hierarchy(one procedure calls another) and the dynamical information flow (the result of one procedure callis the input for another). The heuristic also unfolds nonrecursive procedures.

strong unfold This heuristic may unfold recursive procedures several times under certain cir-cumstances. It may also unfold procedures that do not appear in the induction hypothesis. Thisheuristic should be used with care.

calls concrete This heuristic unfolds a call if all actual parameters are concrete, i.e. do notcontain variables, unless they are variables of a parameter sort. It uses the assumption that alltests in conditionals can be decided. If this is not the case (e.g. due to missing simplifier rules)the heuristic may lead to non-termination for recursive procedures. Normally, weak unfold is abetter choice, so this heuristic should be used only in special circumstances.

calls nonrecursive This heuristic unfolds procedures that are not recursive.

bounded calls Experimental – don’t use it.

Symbolic execution

symbolic execution This heuristic is normally the first in the list of chosen heuristics. Itexecutes those program statements that are uncritical. “Uncritical” means that application of theappropriate rule does not introduce case distinctions and will not lead to non-termination. Thismeans it does not deal with calls, loops, and if’s with an undecidable test. It will only look atthe first formula in the antecedent and the succedent. (The idea is to execute a program until it isfinished or a critical statement is reached. This means that assigments etc. normally only appearin the first formula.) The following rules will be applied if possible:

abort right, abort left, skip right, skip left, assign right, assign left, vardecls right,vardecls left, if positive right, if negative right, if positive left, if negative left

split This heuristic tries to apply the rule split left anywhere in the antecedent. This is anuncritical heuristic and can be always used.

conditional This heuristic tries to apply the rules if positive right, if negative right, if positiveleft, and if negative left anywhere in a sequent. In most proofs, conditionals only appear at the firstposition in the antecedent or succedent where the heuristic symbolic execution deals with them.However, they may appear anywhere if the heuristics conditional left/right split are not used.

This heuristic may need some time if a goal contains several conditionals.

conditional right split This heuristic applies the rule if right on every formula in the succedentif possible.

conditional left split This heuristic applies the rule if left on every formula in the succedentif possible.

contract and execute This heuristic applies the rules execute call, contract call left, and con-tract call right if the actual parameters of the calls are identical, and no termination goal isintroduced.

Page 102: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. PROCEDURES AND LOCAL VARIABLES 101

Case distinctions

pl case distinction This heuristic will do nothing for goals containing programs. This meansthat case distinctions for predicate logic formulas have to be done by hand.

dl case distinction This heuristic resolves propositional connectives between program formulasby introducing case distinctions.

8.9 Exercise 6, Part 2

Exercise 6.1 differenceProgram a function DIFFERENCE# (in the declaration section of specification hoare-proc,

which takes two lists as arguments and returns a list, which contains all elements of the first listthat are not in the second list. Use a recursive procedure, not a while loop. Do not use predicate ∈in the programm, but call MEMBER# (see the example proof). Verify that your implementationof difference follows this specification (using predicate ∈ on lists). In particular, it should alwaysterminate.

Exercise 6.2 quicksortVerify the termination of QUICKSORT#.Hint: Use well-founded induction on list length, and a suitable correctness lemma for DI-

VIDE#.

Exercise 6.3 parsingA function PARSE# is implemented in specification hoare-proc, which repeatedly calls NEXT-

TOKEN# and finally returns a list of tokens, and a rest of the initial input, that could not beparsed. Verify the termination and functional correctness of the parse-function PARSE#. Func-tional correctness for PARSE# means, that the string representations of the resulting tokens canbe appended with the restlist such that the original list is restored.

Hint: An additional recursive function tostring is needed, which turns a list of tokens into astring.

Page 103: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 9

Die Beweisstrategie HASI

Wir werden in diesem Teil des Praktikums eine weitere Verifikationsmethode kennenlernen, die”‘symbolische Programmausfuhrung und Induktion”’ (SI), die in informeller Weise von Burstallbeschrieben wurde.

Diese Methode eignet sich besonders gut zur Verifikation von Programmen, die Funktionen,welche inharent rekursiv sind, mittels Schleifen implementieren. Im Gegensatz zum Hoare-Kalkulwerden Aussagen uber Schleifen nicht mit Invarianten, sondern durch Induktion uber die Daten-struktur, auf der gerechnet wird, bewiesen.

Dadurch erreicht man eine großere Flexibilitat bei der Beweisfuhrung, denn man muss beiSchleifen nicht mehr unbedingt eine Invariante angeben, also eine Formel, die bei jedem Schleifendurch-lauf gultig bleibt. Es ist jetzt moglich, eine Vorbedingung und eine Nachbedingung anzugeben,die erst nach einer geeigneten Anzahl i von Schleifendurchlaufen gultig wird. Liegt ein Programmvor, das die iterative Version eines rekursiven Programms ist, so wahlt man die Vor- und Nachbe-dingung am besten meist so, dass sie die Vor- und Nachbedingung eines rekursiven Aufrufs sind.Die Zahl i ist dann die Zahl der Schleifendurchlaufe, die notwendig ist, um einen rekursiven Aufrufiterativ zu simulieren.

Eingabe ist ein einfacher Beweisbaum mit einer Sequenz der Form Γ 〈γ〉 Ψ. Man beachte diespitzen Klammern, die besagen, dass hier im Gegensatz zur Methode von Hoare die Terminierunggleich mitbewiesen wird. Ist γ eine Hintereinanderausfuhrung α;β, so eliminiert die Strategie dannα und berechnet ein neues Ziel der Form Γ′ 〈β〉 Ψ, wobei Γ′ die Veranderungen widerspiegelt,die die Ausfuhrung von α in Γ bewirkt hat. Das Vorgehen der Strategie wird von der Form von αbestimmt.

Γ 〈skip;β〉 Ψ wird reduziert zu Γ 〈β〉 ΨΓ 〈skip〉 Ψ wird reduziert zu Γ ΨΓ 〈abort;β〉 Ψ wird reduziert zu Γ falseΓ 〈x := τ ;β〉 Ψ wird reduziert zu Γy

x, x = τyx 〈β〉 Ψ ,

wobei y eine neue Variable ist, die den alten Wert von x enthalt.Wenn die erste Anweisung ein Konditional ist, also α = if ε then γ1 else γ2 fi, werden drei

Falle unterschieden, je nachdem, ob die Bedingung ε vom Simplifizierer bewiesen oder widerlegtwerden konnte:

• Wenn Γ ε gezeigt werden kann, wirdΓ 〈if ε then γ1 else γ2 fi; β〉 Ψ reduziert zu Γ 〈γ1;β〉 Ψ.

• Wenn Γ ¬ ε gezeigt werden kann, wirdΓ 〈if ε then γ1 else γ2 fi; β〉 Ψ reduziert zu Γ 〈γ2;β〉 Ψ.

• Andernfalls mussen sowohl Γ, ε 〈γ1; β〉 Ψ als auch Γ,¬ ε 〈γ2; β〉 Ψ gezeigt werden.

102

Page 104: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 103

Die while-Schleife

Γ 〈while ε do α2 od; β〉 Ψ

wird anhand der Omega-Regel (siehe Regelanhang) reduziert zu

Γ ∃ κ.〈loop if ε then α2 times κ〉 (¬ ε ∧ 〈β〉 Ψ).

loop α times κ ist dabei ein nur fur die Verifikation benotigtes Konstrukt, das informell‘κ-malige Ausfuhrung von α’ besagt. Die while-Schleife wird also reduziert zur (aquivalenten) Be-hauptung, dass ein κ existiert, so dass die Schleifenbedingung ε nicht erfullt ist und der Schleifen-rumpf α2 nicht mehr ausgefuhrt wird. Wenn so ein κ existiert, wird die Schleife hochstens κ maldurchlaufen (zu großes κ macht wegen des vorgeschalteten if’s im Rumpf der loop nichts aus).

Um nun die totale Korrektheit der Schleife zu beweisen, wird Induktion uber die von derSchleife bearbeitete Datenstruktur benotigt. Dazu muss eine Induktionshypothese der Bauart

ϕ(u) → ∃ κ.〈 loop if ε then α2 times κ〉 Ψ1(u)uberlegt werden, die in der Induktionsregel (siehe Anhang) verwendet wird. Typischerweise

enthalt die Induktionshypothese eine Behauptung uber die Schleifendurchlaufe die (ein beliebiges)u bearbeiten. Durch die Anwendung der Induktionsregel erhalt man folgende drei Pramissen:

(1) Γ Θ(ϕ),

(2) Γ,Θ(∃ κ.〈loop if ε then α2 times κ〉 Ψ1(u)) ∃ κ 〈loop if ε then α2 times κ〉 (¬ ε ∧ 〈β〉 Ψ)

(3) ϕ(u), IND(u) ∃ κ 〈loop if ε then α2 times κ〉 Ψ1(u),

wobei IND(u) die Induktionshypothese ist:

IND(u)≡ ∀ u’,x (u’$ u → (ϕ(u’) → ∃ κ〈loop if ε then α2 times κ〉 Ψ1(u’)))Dabei ist x der Vektor der von u verschiedenen Variablen, die in ϕ,Ψ1, ε und α2 vorkommen.

Θ ist eine Substitution fur die in Ψ1(u) und ϕ(u) vorkommenden Variablen.Bei der Anwendung dieser Regel kann der Benutzer zwischen Induktion ohne Verallgemeinerung

(“Standardinduktion”) und allgemeiner Induktion wahlen. Bei Induktion ohne Verallgemeinerungwird die Behauptung selbst (als Formel gelesen) als Induktionshypothese verwendet (Θ ist dann dieleere Substitution), und nur die Induktionsvariable muss ausgewahlt werden. Bei Induktion mitVerallgemeinerung (Knopf “induction”) mussen die Vorbedingung ϕ, die Nachbedingung Ψ und dieInduktionsvariable u eingegeben werden (die Induktionsordnung schließt das System selbstandigaus der Sorte der Induktionsvariable). Bei den hier zu zeigenden Aussagen uber while-Schleifenmuss (im Gegensatz zu den in spateren Versuchen betrachteten rekursiven Prozeduren) haufig eineVerallgemeinerung der Ausgangsbehauptung als Induktionshypothese gewahlt werden.

Die Induktionsregel hat 3 Pramissen, die noch etwas naher erklart werden sollen: Die erstenbeiden Pramissen zeigen, dass die Ausgangsbehauptung ein Spezialfall der gewahlte Verallge-meinerung ist. Die Spezialisierung muss durch eine Substitution Θ angegeben werden. Pramisse(1) zeigt, dass aus der Vorbedingung des Originalziels die Spezialisierung der Vorbedingung derInduktionsbehauptung, Θ(ϕ) folgt. Ist die Induktionsbehauptung richtig, (Pramisse 3), so darf inPramisse (2) deren mit Θ instantiierte Nachbedingung

Θ(∃ κ 〈loop if ε then α2 times κ〉 Ψ1(u)) zu den Voraussetzungen dazugenommen werden.Die wesentliche Beweisarbeit steckt in der Behandlung der offenen Pramisse (3). Diese reprasentiert

einen Schritt des Induktionsbeweises, der zeigt, dass fur jedes u, fur das ϕ(u) gilt, nach einergeeigneten Zahl κ von Schleifendurchlaufen die Nachbedingung Ψ(u) erfullt wird. Die grundsatzlicheIdee des Induktionsbeweises ist nun, die Schleifendurchlaufe, die u bearbeiten und in Teildaten-strukturen zerlegen, symbolisch auszufuhren, und fur die anderen, die sich mit Teildatenstrukturenvon u befassen, die Induktionshypothese anzuwenden. Bei Binarbaumen sind also 2 Anwendun-gen der Induktionshypothese (auf den rechten und linken Teilbaum) notwendig. SymbolischesAusfuhren von loop’s geschieht mit den folgenden Regeln

Page 105: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 104

loop unwind:Diese Regel trennt den Schleifenkorper einmal von der Schleife ab. Anschließend kann die Schleifeeinmal symbolisch ausgefuhrt werden. Die Regel nimmt an, dass noch mindestens ein Schleifendurch-lauf notwendig ist, um die Nachbedingung zu erreichen.

loop exitDie Schleife wird verlassen, und die Gultigkeit der Nachbedingung ist nachzuweisen.

loop right:Diese Regel fuhrt eine Fallunterscheidung bezuglich des Schleifentests ε und der Zahl der Schleifendurchlaufeκ durch. Ist der Test nicht erfullt, so fuhrt Abarbeiten der Schleife (wie bei loop unwind) zu nichts,also muss direkt ϕ gelten (2. Pramisse). Ist der Schleifentest erfullt, kann entweder die Schleife ein-mal ausgefuhrt werden (wie bei loop unwind), oder die Zahl der notwendigen Schleifendurchlaufe,um die Nachbedingung ist 0 (wie bei loop exit), dann muss sofort ϕ gelten.

execute loop:Diese Regel wird immer nach Anwendung der Induktionshypothese sowie auf die Pramisse (2)der Induktionsregel angewandt, um Information im Antezedent uber die Wirkung von der erstenκ Schleifendurchlaufe auf den Sukzedent zu propagieren. Die ersten κ Schleifendurchlaufe imSukzedent werden quasi ‘ubersprungen’.

9.1 Ein Beispiel

Wir wollen ein Programm untersuchen, das die Anzahl der Blatter eines Baumes zahlt. Wirmussen die Funktionen und Pradikate auf der Datenstruktur der Baume definieren. Der Datentyp’data’ ist dabei ein generischer Datentyp (kann spater instantiiert werden), der die Werte in denKnoten des Baumes reprasentiert. In der zugrundegelegten Spezifikation werden die folgendenFunktionen definiert:

mknode : data → bintreemacht aus einem Datum einen Baum, der nur aus einem Wurzel-knoten besteht

mktree: bintree × data × bintree → bintreeder Baum mit zwei Argumenten als direkte Unterbaume undeinem Datum als Knoteneintrag

el: bintree → dataliefert den Wert des aktuellen Knotens im Baum.

left: bintree → bintreeder linke Unterbaum

right: bintree → bintreeder rechte Unterbaum

subtreep ⊆ bintree × bintreeeine Ordnungsrelation auf Baumen, die wir fur die In-duktion benotigen. Also muss subtreep(left(t), t) undsubtreep(right(t), t) gelten, wenn t kein Knoten ist. Mankann sich unter subtreep etwa ein Pradikat vorstellen, das genaudann zutrifft, wenn die Hohe des ersten Arguments kleiner als diedes zweiten ist.

nodep ⊆ bintreedieses Pradikat ist genau dann erfullt, falls der Baum keine Un-terbaume besitzt.

tips: bintree → natliefert zu einem Baum die Anzahl seiner Blatter, also die Funktiondie durch unser Programm implementiert wird.

Da wir eine boolesche Hilfsvariable und einen Keller benotigen, definieren wir auch noch:

Page 106: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 105

ff: → booldie Konstante ”‘falsch”’.

neg: bool → boolliefert das Negat des Arguments.

sempty: → stackder leere Keller

push: stack × tree → stacklegt einen Baum auf den Keller

top: stack → bintreeliefert das oberste Element

pop: stack → stackentfernt das oberste Element

Die Spezifikation unseres Programms lautet:

tree = t0 < ∗tip count > n = tips(t0)

tips lasst sich leicht als rekursive Prozedur implementieren:

PROCEDURE tips(tree, var n);

VAR n1 = 0, n2 = 0;

BEGIN

IF nodep(tree) THEN

n := 0 +1

ELSE

BEGIN

tips(left(tree), n1);

tips(right(tree), n2);

n := n1 + n2;

END;

END;

Die iterative Version davon sieht dann wie folgt aus:

begin

stack := sempty; n := 0;

ready := ff;

while ready=ff do

if nodep(tree) then begin

n := n +1;

if stack = sempty then

ready := tt

else begin

tree := right(top(stack));

stack := pop(stack)

end

end

else begin

stack := push( tree,stack);

tree := left(tree)

end

end

Zunachst starten wir das System, und arbeiten in Versuch5 auf dem Modul tipcount. In Aufgabe-5-1 steht die zu beweisende Sequenz.

Nach einem kleinen Moment klappt dasKIV-Strategy Fenster auf, das aus fruheren Sitzungenschon hinreichend bekannt sein durfte. Zur Arbeitserleichterung wahlen wir unter dem Menupunkt

Page 107: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 106

Control die Heuristics an und hier wiederum den Punkt Select your own heuristics. Jetztklicken wir nacheinander die Heuristiken symbolic execution, simplifier, omega, loop exit,execute loop und endlich split dl-simplifier an und bestatigen mit OK. Das System ver-sucht nun, sooft es moglich ist, eine dieser Regeln anzuwenden.

Ein Blick auf das rechte untere Fenster verrat uns, dass die Zuweisungen abgearbeitet unddie omega-Regel angewendet wurde. Nun sind wir in der Lage die Induktionsbehauptung zuformulieren und wahlen deshalb die induction-Regel im linken Fenster an. Die Anfangsbelegungder Programmvariablen zeigt uns, dass eine Abarbeitung des Programmsmit dieser Belegung nichtalle Programmteile erfassen wurde.

Wir konnen deshalb keine Standardinduktion uber eine der vorgeschlagenenVariablen durchfuhren,so dass wir gezwungen sind eine starkere Aussage zu formulieren (wir verallgemeinern Vor- undNachbedingung; siehe Theorieteil). Dazu dient der Punkt induction, der hiermit zu drucken ist(das abschließende OK versteht sich von selbst).

Daraufhin erscheint ein Fenster, das uns fragt, ob die Vorbedingung von einem File namenssequents zu laden ist. Dieses File, in dem die verallgemeinerte Vor- und Nachbedingung stehen, istim Verzeichnis∼kivprakt/prakt<i>/Versuch5/modules/tipcount zu finden. Da ein Editieren desselben notwendigist, ist es ratsam das File in einen Emacs zu laden. Das geht entweder von Hand oder durchAuswahl des Knopfes Edit File Sequents. Bei dieser Moglichkeit wird die Sequentsdatei im Emacsgeladen, und das System wartet, bis das Editieren mit C-x # beendet wird, um dann die Datei zuladen (wenn man die Datei nochmal editieren will, kann man sie mit C-x b (oder dem Menupunkt“Buffers” im Menu des Emacs) zurucholen.

Ganz am Ende der sequents-Datei stehen phi (=Vorbedinung) und psi (=Nachbedinung). Dazunachst die Vorbedingung einzulesen ist, kommentieren wir die Nachbedinung mit einem ”’;”’ aus,drucken Yeah! und verfahren umgekehrt genauso (das Sichern der Anderungen und das Definierenneuer Variablen nicht vergessen!). Nun werden wir aufgefordert die Induktionsvariable, hier t2,in konkreter Syntax einzugeben. Anschließend verlangt das System nach der Substitution Θ derinduction-Regel (siehe Regelanhang). und macht gleichzeitig mehrere Vorschlage. Man solltesich auf die Korrektheit der Vorschlage nicht verlassen, hier ist es so, dass die erste Moglichkeitdie richtige ist (auch die anderen waren, trotzdem sie verschieden sind, korrekt; uberlege warum!). Wir nehmen also den ersten Vorschlag an und drucken OK.

Die Verallgemeinerung der Originalbehauptung zur Induktionsbehauptung wurde dabei so er-halten: Unsere Behauptung soll so sein, dass sie etwas uber die Beaerbeitung eines allgemeinenTeilbaums t2 der Originaleingabe aussagt (die Spezialisierung der Induktionsbehauptung zumOriginalziel wird dann fur t2 t wahlen, bei die Induktionsvoraussetzung wird mit left(t2) undright(t2) verwendet). Wenn die Schleife an einem Punkt angelangt ist, an dem die Blatter einesbeliebigen Teilbaums gezahlt werden sollen, sind bereits irgendeine Anzahl n2 Blatter gezahlt.Der Anfangswert n = 0 aus der Originalbehauptung ist also zu speziell. Wenn vor Beginn derSchleifendurchlaufe die Vaiable n den Wert n2 speichert, so wird sie nach Abarbeitung des Baumsden Wert n2 + tips(t2) haben. Dieselbe Argumentation wie fur n gilt auch fur den Stack: wennwir die Bearbeitung eines beliebigen Teilbaums betrachten, so hat der Stack am Anfang den be-liebigen Wert s2. Nun gibt es hier ein zusatzliches Problem: Je nachdem, ob wir den ganzenBaum t oder nur einen echten Teilbaum betrachten, wird im letzten Schleifen- durchlauf (der dasletzte Blatt zahlt, unterschiedliches passieren). Nun gibt es zwei Moglichkeiten: Entweder wirbescreiben die beiden Falle im Detail (wer Interesse hat, kann den Beweis auch mal so versuchen),oder (einfacher) wir lassen den letzten Schleifendurchlauf einfach weg, betrachten also in der In-duktionsbehauptung alle Schleifendurchlaufe in denen t2 bearbeitet wird, bis auf den letzten, indem das letzte (rechteste) Blatt des Baums gezahlt wird. Dann hat der Algorithmus dieses letzteBlatt noch nicht gezahlt (Nachbed. n = n2 + tips(t2) -1, aber wir wissen, dass der Stack s

wieder der Originalstack s2 ist, und das ready-bit wahrenddessen immer ff war, und die Variabletr zum Schluss einen Knoten enthalt (also nodep gilt).

Durch die Anwendung der Induktionsregel erhalten wir zwei offene Pramissen. Die im Theo-rieteil mit (1) bezeichnete Pramisse hat das System bereits geschlossen. Es verbleiben also noch(2) und (3), wobei das System die Zuweisungen, die aus der Substitution entstanden sind, und die

Page 108: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 107

execute loop-Regel in Pramisse (3) automatisch angewandt hat. Dadurch steht in der Vorbe-dingung jetzt ein Zustand, in dem (laut Induktionshypothese!) alle Blatter des Baums t bis aufdas letzte gezahlt sind. Das letzte Blatt wird nun durch Ausfuhren des Schleifenrumpfs gezahlt,was wir durch einen Doppelklick auf die loop unwind-Regel bewirken. Nach mehrmaliger selb-ststandiger Anwendung der if-Regel verlasst das System die Schleife, da es erkennt, dass diesesZiel geschlossen werden kann, da die Nachbedingung erreicht ist.

Jetzt ist nur noch die Pramisse mit der Induktionshypothese zu beweisen. Dazu mussen wirzunachst die Schleife einmal abarbeiten. Dies geschieht hier mit der loop right-Regel, damitsichergestellt werden kann, dass not nodep(tree) gilt (falls der Baum gleich zu Anfang ein Knotenist, muss die Schleife nicht abgearbeitet werden, und wir sind sofort fertig).

Betrachtet man sich nach der symbolischen Ausfuhrung des Schleifenrumpfs die Gleichun-gen im Antezedenten, so sieht man, dass zur Bearbeitung durch das Programm jetzt den linkenTeilbaum left(t2) ansteht. Daher wird nun die Induktionshypothese auf den linken Teilbaumangewandt. Dieses geschieht durch die Anwendung der apply induction-Regel. Auch in diesemwie im letzten Falle ist die erste vorgeschlagene Substitution korrekt. Das System wendet dannautomatisch ein execute loop an, und wir erreichen einen Zustand (die Beschreibung steht wiederim Antezedent), in dem der linke Teilbaum bis auf sein letztes Blatt gezahlt ist. Nun arbeitenwir die Schleife abermals ab, um das letzte Blatt des linken Teilbaums zu zahlen, und den rechtenTeilbaum right(t2) zur Bearbeitung zu holen (Bem.: Das System benennt die Variable, auf der dasProgramm arbeitet, mehrmals um. Man sollte also bei der Analyse des momentanen Program-mzustands, der im Antezedent steht, auch immer auf die im loop-Konstrukt stehenden Variablenachten). Dafur genugt loop unwind, da wir schon wissen, dass unser Baum kein Knoten ist (i.e.die Schleife mindestens einmal ausgefuhrt werden muss. Nun konnen wir wie vorher die Induktion-shypothese anwenden, und erreichen mit Hilfe der automatisch angewandten execute loop-Regelden Zustand vor dem letzten Schleifendurchlauf. Mit einem letzten loop unwind fuhren wir auchdiesen noch aus. Sollte das System dann den Schleifenausstieg nicht automatisch erkennen, mussenwir zum Abschluss die loop exit-Regel manuell betatigen, um den Beweis zu vollenden.

9.2 Versuch

Exercise 7.1 RechnerubungWie gewohnt, soll in der ersten Aufgabe das Beispiel aus den Unterlagen ’durchgerechnet’

werden. Die Behauptung steht im Modul tipcount-module.

Exercise 7.2 RechnerubungDas folgende Programm bestimmt das am weitesten links stehende Blatt eines Baumes und

gibt seinen Wert in der Variablen leaf zuruck.

begin

while not nodep(tree) do

tree:=left(tree);

leaf := el(tree)

end

Die fur den Beweis notwendige Spezifikation ist leftmost. Die fur die Formulierung der Nachbe-dingung notwendige Funktion leftmosttip ist dort definiert. Sie erhalt als Argument einen Baumund liefert als Ergebnis das am weitesten links stehende Blatt. Sie reprasentiert also genau dieAnforderung an das Programm. Die Korrektheitsbehauptung fur das Programm steht im Modulleftmost-module

Exercise 7.3 RechnerubungDurch das nachste Programm soll die Hohe eines Binarbaumes berechnet werden. Das geschieht,

indem der Baum in depth-first-search Manier durchlaufen wird, wobei auf einem Array (unvisited)ein Keller simuliert wird. Die Variable depth gibt immer die Tiefe des gerade besuchten Knotens

Page 109: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 108

an. Sie ist gleichzeitig der Index des obersten Elements im Keller. Ihr maximaler Wert wahrenddes Programmlaufes ist um eins großer als die zu bestimmende Hohe.

Zunachst die verwendeten Funktionen und Pradikate:Naturliche Zahlen:0: → nat Konstante der Sorte nat, stellt die Null dar.

+1: nat → nat Nachfolgerfunktion-1: nat → nat Vorgangerfunktion+: nat × nat → nat Addition

max: nat × nat → nat Das Maximum zweier Zahlen< ∈ nat × nat → echt kleiner≤ ∈ nat × nat kleiner oder gleichArrays:

tget: arrayofbintree × nat → bintreeliefert den Eintrag zueinem gegebenen Index.

tput: arrayofbintree × nat × bintree → arrayofbintreetragt einen Baum untereinem bestimmten Indexin das Array ein.

Es geltetget(tput(a1,i,t),i) = t;tget(tput(a1,i,t),j) = tget(a,j), falls i �=j

Die Hohe:height: tree → natmitheight(mknode(a)) = 0;height(mktree(t1,a,t2)) = max(height(t1), height(t2)) +1

Zur Formulierung der Induktionsbehauptung empfiehlt es sich folgendes Pradikat zu verwen-den:

boundedeq ∈ arrayofbintree × arrayofbintree × natgilt genau dann, wenn die Eintrage zweier Arrays biszum angegebenen Index ubereinstimmen.

Also:

boundedeq(a1, a2, i) ↔ ∀j. j≤i → tget(a1, j) = tget(a2, j)

Das Programm

BEGIN

depth := 0 +1;

maxdepth := depth;

unvisited := tput(mktarray, depth, dummynode);

WHILE depth <> 0 DO

IF nodep(tr) THEN

IF nodep(tget(unvisited, depth)) THEN

depth := depth -1

ELSE

BEGIN

tr := tget(unvisited, depth);

unvisited := tput(unvisited, depth, dummynode)

END

ELSE

BEGIN

depth := depth +1;

Page 110: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. DIE BEWEISSTRATEGIE HASI 109

maxdepth := max(maxdepth,depth);

unvisited := tput(unvisited, depth, right(tr));

tr := left(tr)

END;

maxdepth := maxdepth -1

END

und die Korrektheitsbehauptung sind zu finden im height-module. dummynode ist eine Kon-stante vom Typbintree, um das konstante Feld mktarray mit diesem Wert zu belegen. mktarray wird furdie Initialisierung des Feldes unvisited benotigt. Hier erfolgt die Initialisierung zufallig eben-falls mit dummynode. Damit ist ein Zugriff auf jedes Feldelement gewahrleistet, denn es isttget(mktarray,i) = dummynode fur alle i. Außerdem gilt nodep(dummynode).Die Korrektheitsbehauptung muss mit Hilfe der Definition von der Funktion height in der Spezi-fikation gleichen Namens bewiesen werden.

Page 111: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 10

Modules

10.1 Modules

A module in our context is used to implement one abstract data type, i.e. a specification, on thebasis of another. The idea is that a “complex” data type is implemented by procedures that use“simpler” data types until eventually the basic data types of the target programming language(or target processor) are used. A module consists of

• an export interface, i.e. the specification to implement,

• an import interface, i.e. the specification of the used data types,

• a mapping that defines the correspondence between the export interface and the importinterface and the module implementation. The mapping contains the description whichexport sort is implemented by which import sort (e.g. when implementing sets by lists),and which export operations is implemented by which procedure. Sometimes an element ofthe export data type can be represented by several elements of an import data type (e.g.when implementing sets by duplicate free, but unordered, lists). In this case it is necessaryto define an “identification” procedure that tests if two import elements represent the sameexport element.

• the implementation consisting of procedure declarations that implement the export oper-ations.

We consider an example module, that implements natural numbers (nat) by binary words (bin).The export interface is the following specification of natural numbers:

nat =specification

sorts nat;constants 0 : nat;functions

. +1 : nat → nat ;

. -1 : nat → nat ;

. + . : nat × nat → nat ;

. - . : nat × nat → nat prio 8;

. * . : nat × nat → nat prio 10;

. div . : nat × nat → nat prio 7;

. mod . : nat × nat → nat prio 7;predicates

. < . : nat × nat;

. | . : nat × nat;

110

Page 112: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 111

variables n, m, k: nat;induction nat generated by 0, +1;

axioms

0 �= n +1;0 -1 = 0;n +1 -1 = n;m + 0 = m;m + n +1 = (m + n)+1;m - 0 = m;m - n +1 = (m - n)-1;m * 0 = 0;m * n +1 = m * n + m;¬ n < n;k < m ∧ m < n → k < n;¬ n < 0;0 < n +1;n +1 < m +1 ↔ n < m;n div 0 = 0;m < n → m div n = 0;n �= 0 ∧ ¬ m < n → m div n = (m - n div n)+1;m mod n = m - (m div n) * n;n | m ↔ (∃ k.k * n = m)

end specification

We implement this specification by binary words. Binary words are built from the bits 0 and1 by adding new bits at the end with the operations .0 and .1. top selects the last bit, pop dropsthe last bit. The specification is an enriched data specification:

bin =data specification

bin = 0| 1| . .0 (. pop : bin)| . .1 (. pop : bin);

variables z, y, x: bin;order predicates . $ . : bin × bin;

end data specification

enrbin =enrich bin with

functions . top : bin → bin ;

axioms

x.0 top = 0,x.1 top = 1,0 top = 0,1 top = 1

end enrich

The implementation contains for every export operation a procedure that performs the oper-ation on binary words. In our example, natural numbers are represented by their corresponding

Page 113: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 112

binary representation, i.e. 6 is represented by ’110’, 9 by ’1001’. The representation should beunique. This means that binary words with leading zeros like ’0010’ do not represent a naturalnumber. The procedure declarations (and the complete module) can be found in appendix 12.1.Note that all implementing procedures must be functional, and that the signature entries for pro-cedure symbols must not be given explicitly: they are generated automatically from the mapping,wich is

refinementrepresentation of sorts

bin implements nat;representation of operations

zero# implements 0;succ# implements +1;pred# implements -1;add# implements +;sub# implements -;mult# implements *;div# implements div;mod# implements mod;ls# implements <;divisor# implements |;

The export operation 0 is implemented by the procedure zero#, + by add#, etc. (There is noneed to choose procedure names ending with #; it is just a convention.) Since the representationof natural numbers is unique, an identification procedure is not necessary. Otherwise the mappingwould contain the line

equality eq# : nat;

10.2 Module correctness

In general, four different types of requirements must be met to ensure a correct module:

I) termination

The procedures must terminate for all binary words without leading zeros. Furthermore, theresults of the procedures must be again binary words without leading zeros. This guaranteesthat we really do not use binary words with leading zeros for natural numbers.

II) congruence

The identification procedure (if present) must work like a congruence relation, i.e. it mustbe reflexive, symmetrical, transitive, and compatible with all operations.

III) export axioms

The procedures must work like the export operations they implement. This means theymust fulfill the export axioms if the operations are replaced by the procedures.

IV) generatedness

Natural numbers are generated by 0 and +1. Correspondingly, it must be possible to get allbinary words that represent naturals (i.e. all binary words without leading zeros) by callingthe procedures zero# and succ# several times.

The notion of binary words without leading zeros plays an important role in our example.Therefore we need a predicate that checks this property. One possibility is to add this predicateto the specification of the binary words (with appropriate axioms). Another possibility is to use aprocedure that terminates if and only if the input has no leading zeros. This restriction procedurer# looks like

Page 114: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 113

declaration

r#(x) {if x = 0 then skip else rh#(x) }rh#(x){

if x = 0 then abort elseif x = 1 then skip else rh#(x pop)

}(Recall that abort is the never-terminating program.) Now the formula

〈r#(x)〉 true

is true if and only if x has no leading zeros. The restriction procedure reflects this design decisionthat was made when implementing the module, and is used only for verification purposes. It willnever be part of the code that actually runs.

Termination

Using the restriction formula, we can formulate requirement I) by a number of proof obligations.For every procedure we get one sequent in dynamic logic. If these proof obligations are proved,requirement I) is met. (We list only four of them.)

Term zero 〈zero#(; x)〉 〈r#(x)〉 true

The procedure zero# terminates with a result without leading zeros.

Export constants are implemented by procedures that have no input parameters.

Term succ 〈r#(x)〉 true 〈succ#(x; y)〉 〈 r#(y)〉 true

If the input x for succ# has no leading zeros, then succ# terminates, and the result y againhas no leading zeros.

Term add 〈r#(x)〉 true, 〈r#(y)〉 true 〈 add#(x, y; s)〉 〈r#(s)〉 true

If both inputs for add# have no leading zeros, then the procedure terminates, and the resulthas no leading zeros.

Term ls 〈r#(x)〉 true, 〈r#(y)〉 true 〈ls#(x, y; e)〉 true

If the inputs for ls# have no leading zeros, then the procedure terminates.

The result of ls# is a boolean value, because ls# implements the predicate <. Obviously itmakes no sense to talk about leading zeros of a boolean value. So the only requirement forprocedures implementing predicates is their termination.

Congruence

The identification procedure has two inputs and returns a boolean value that is true if and only ifthe two input values represent the same export element. The procedure implements an equalitytest for export elements. In our example we could use the trivial implementation

eq#(x, y; var e) {if x = y then e := true else e := false }We obtain the following proof obligations:

Term eq 〈r#(x)〉 true, 〈r#(y)〉 true 〈eq#(x, y; e)〉 true

The identification procedure terminates for binary words withou leading zeros.

Refl eq 〈r#(x)〉 true 〈eq#(x, x; e)〉 e = true

Reflexivity

Page 115: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 114

Sym eq 〈r#(x)〉 true, 〈r#(y)〉 true, 〈eq#(x, y; e)〉 e = true 〈eq#(y, x; e)〉 e = true

Symmetry

Trans eq 〈r#(x0)〉 true,〈r#(x)〉 true,〈r#(y)〉 true,〈eq#(x, x0; e)〉 e = true,〈eq#(x0, y; e)〉 e = true 〈eq#(x, y; e)〉 e = true

Transitivity

Cong succ 〈r#(x)〉 true,〈r#(x0)〉 true,〈eq#(x, x0; e)〉 e = true 〈succ#(x; y)〉 〈succ#(x0; y0)〉 〈eq#(y, y0; e)〉 e = true

Compatibility with succ#: If x and x0 represent the same natural number, then their suc-cessors also represent the same number.

Cong add 〈r#(x)〉 true,〈r#(y)〉 true,〈r#(x0)〉 true,〈r#(y0)〉 true,〈eq#(x, x0; e)〉 e = true,〈eq#(y, y0; e)〉 e = true 〈add#(x, y; s)〉 〈add#(x0, y0; s0)〉 〈eq#(s, s0; e)〉 e = true

Compatibility with add#: If both inputs represent the same number the result values alsorepresent the same number.

Cong ls 〈r#(x)〉 true,〈r#(y)〉 true,〈r#(x0)〉 true,〈r#(y0)〉 true,〈eq#(x, x0; e)〉 e,〈eq#(y, y0; e)〉 e 〈ls#(x, y; e)〉 〈ls#(x0, y0; e0)〉 e = e0

Compatibility with ls#: if x and x0 represent the same number, and y and y0 represent thesame number, then the result of calling ls# with inputs x and y is the same as the result ofcalling ls# with the inputs x0 and y0.

Export axioms

The procedures must work on the binary words like the export operations on natural numbers.We obtain one proof obligation for each export axiom by a translation process, where exportoperations are replaced by their implementing procedures. Consider the axiom n +1 -1 = n. Afirst try is

〈succ#(x; y0)〉 〈 pred#(y0; y1)〉 y1 = x

“If the successor of x is y0, and the predecessor of y0 is y1, then x must equal y1.”

If we have multiple representations for one export element the values need not be equal, but mustonly represent the same export element:

〈succ#(x; y0)〉 〈pred#(y0; y1)〉 〈eq#(y1, x; e)〉 e

Page 116: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 115

Unfortunately, both statements are wrong. succ# computes for ’01’ and ’1’ a result ’10’. However,we only have to deal with binary words without leading zeros. Therefore, the proof obligation hasto hold only for those inputs. We obtain the following sequents (besides others):

Exp-01 〈r#(x)〉 true ¬ 〈zero#(; x0)〉 〈succ#(x; y0)〉 x0 = y0

Exp-02 〈zero#(; x0)〉 〈pred#(x0; y0)〉 〈zero#(; x1)〉 y0 = x1

Exp-03 〈r#(y)〉 true 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

Exp-19 〈r#(x)〉 true,〈r#(y)〉 true 〈divisor#(x, y; e)〉 e ↔ (∃ u.〈r#(u)〉 true ∧ 〈mult#(u, x; p0)〉 p0 = y)

Generatedness

A last proof obligation guarantees that the natural numbers are indeed generated by 0 and +1.This means for the implementation that all binary words without leading zeros can be generatedwith the procedures zero# and succ# (by calling them for a number of times). This propertycan be expressed with the help of an automatically generated procedure uniform r#. We get thefollowing proof obligation:

G bin r#(x)〉 true 〈uniform r#(x)〉 trueIf the input x has no leading zeros the procedure uniform r# terminates with input x.uniform r# terminates if and only if after one call of procedure zero# followed by a finitenumber of calls of procedure succ# returns x as result. (With multiple representations theresult must only represent the same export element as x.)

Procedure uniform r# works as follows: In a first step zero# is called. If the result perchance isx, the procedure terminates. Otherwise a binary word y is guessed such that succ# with input yreturns x. However, this input y must again be generated by zero# and succ#, i.e. uniform r#must terminate with input y. The declaration is

uniform r#(x){

let x2 = x inzero#(; x2);if x2 = x then skip elselet x1 = ?, x0 = x in{

uniform r#(x1);succ#(x1; x0);if x0 = x then skip else abort

}}

An indeterministic variable initialization let x1 = ? does the “guessing”. x1 is initializedwith the “correct” (not a random!) value if it exists. This means the indeterministic variableinitialization is equivalent to an existential quantifier over x1, and defined by the following axiom:

〈let x = ? in α〉 ϕ ↔ ∃ x. 〈α〉 ϕ x �∈ Var(ϕ)

10.3 The calculus for module verification

Symbolic execution of programs is an important part of the calculus (cf. the Hoare rules). Newrules are needed for the new program statements (procedure calls and local variables), and for

Page 117: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 116

programs in the antecedent of a sequent. (In the Hoare calculus we had only one program inthe succedent.) Furthermore, (structural or noetherian) induction plays an important role forrecursive procedures. The complete set of rules is given in appendix 8.7. The new proof rules andthe proof idea for recursive procedures is explained in the following example proof (Exp-03). Thegoal to prove is

〈r#(y)〉 true 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y (1)

If succ# is called with an input y without leading zeros the procedure terminates. If itsresult y0 is used as input for pred#, then pred# also terminates and the result y1 isequal to the original input y.

This goal can be proved by standard induction for y. “Standard” induction means that the goalitself is used as the induction hypothesis. We use noetherian induction with the order predicate$for binary words. The proof idea is to unfold, i.e. expand, the procedure calls, and to use symbolicexecution on the programs until recursive calls are reached. Then the induction hypothesis canbe implied because the arguments of the recursive call pop(y) is smaller than y (y pop $ y, if y�= 0 and y �= 1). The induction hypothesis is

Ind-Hyp =∀ y2. y2 $ y →〈r#(y2)〉 true

→ 〈succ#(y2; y0)〉 〈pred#(y0; y1)〉 y1 = y2

We get the goal

〈r#(y)〉 true, Ind-Hyp 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y (2)

Since procedure r# itself is not recursive, we can unfold the call (unfolding a recursive procedurecan lead to nontermination if it is done again and again, unfolding a nonrecursive procedurecan’t) Unfolding is done with the rule call left. The procedure call is replaced by the body ofthe procedure declaration, where the formal parameters are substituted by the actual values. Theresult is

〈if y = 0 then skip else rh#(y)〉 true, Ind-Hyp 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

(3)

Symbolic execution of the if-statement and application of rule skip left leads in the first case to

Ind-Hyp 〈succ#( 0; y0)〉 〈pred#(y0; y1)〉 y1 = 0 (4)

and in the second case to

〈rh#(y)〉 true, Ind-Hyp, y �= 0 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y (5)

The first case is finished by symbolic execution. Unfolding succ# gives

Ind-Hyp 〈pred#( 1; y1)〉 y1 = 0 (6)

and symbolic execution of pred#

Ind-Hyp 0 = 0 (7)

We turn to the second case. All remaining procedure calls are for recursive procedures. We unfoldsucc# (once) and symbolically execute its body. This results in three cases (the case y = 0 can’t

Page 118: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 117

occur). The first two cases become axioms after the symbolic execution of pred#. The third caseleads to a recursive call:

〈rh#(y)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

(8)

The argument of succ# is now y pop. The input of rh# is y. Symbolic execution of rh# will leadto a recursive call with the same argument y pop of succ#:

〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

(9)

Now is the right time to apply the induction hypothesis with rule apply induction. The correctinstance for y2 is y pop. We obtain two goals. (The goal that y pop is indeed less than y is provedautomatically.) The first goal states that the precondition 〈r#(y)〉 true is true for y pop, i.e. that〈r#(y pop)〉 true holds:

〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈r#(y pop)〉 true, 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

(10)

This is the first time that the succedent contains two program formulas. However, we can ignorethe second formula. Basically we have to prove

〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈r#(y pop)〉 true (11)

This is done again by symbolic execution of r#(y pop) which leads to the axiom

〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈rh#(y pop)〉 true (12)

In the second case the induction hypothesis is added to the antecedent:

〈succ#(y pop; y0)〉 〈pred#(y0; y1)〉 y1 = y pop,〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

(13)

Now we have the same procedure call succ# with the same input y pop in the antecedent and thesuccedent. succ#(y pop; y0) in the antecedent computes some value (say y3). Obviously, succ#(ypop; y1) in the succedent must compute the same value, i.e. y1 must be equal to y3. The ruleexecute call follows these considerations: It introduces a new variable y3 as the result of succ#(ypop; y0) in the antecedent, discards succ#(y pop; y1) in the succedent, and substitutes y1 by y3in the rest of both formulas:

〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3,〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈y3 := y3.0〉 〈pred#(y3; y2)〉 y2 = y

(14)

The formula in the antecedent is splitted into two formulas that are related by y3. This intro-duction of intermediate values is also done by the rule split left. assign right gives

〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3,〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1 〈pred#(y3.0; y2)〉 y2 = y

(15)

Now we have one call of pred# with argument y3, and one call with argument y3.0. If botharguments were equal we could again discard the call in the succedent. How do we make botharguments equal? By symbolically executing pred#(y3.0; y2) because the recursive call will havethe argument y3.0 pop = y3. We obtain

〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3,〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y3 �= 1, y �= 0, y �= 1 〈pred#(y3; y0)〉 〈y0 := y0.1〉 y0 = y

(16)

Page 119: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 10. MODULES 118

Applying execute call once more leads to

〈pred#(y3; y1)〉 y1 = y4, 〈succ#(y pop; y0)〉 y0 = y3,〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y3 �= 1, y �= 0, y �= 1, y4 = y pop 〈y4 := y4.1〉 y4 = y

(17)

which is true after executing the assignment.We note that proofs involving recursive procedures is based on induction and symbolic exe-

cution until recursive calls are reached. After the application of the induction hypothesis we tryto apply the rule execute call. However, this requires the same arguments in both calls. If theyare not equal we try make them equal by symbolic execution of the appropriate procedure. Itis important to have the implementation of the procedures in mind in order to determine whichcall to unfold when. The treatment of the restriction procedure was somewhat arbitrary in thisexample. It doesn’t really matter when r#(y) is unfolded.

The proof is found automatically by the system. The proof protocol in appendix 12.2 listsfor each proof step which heuristic applied the rule. The heuristic selection was “Let the systemchoose the heuristics”. What heuristics exist for module verification and how modules are used inKIV is the topic of the next chapter.

Page 120: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 11

Module Verification with KIV

11.1 Introduction

The proof strategy for module verification is part of the software development environment of KIV.A project can contain not only specifications, but also modules. Each module has its theorembase with proof obligations and user defined theorems (lemmas etc.). The user interface is similarto that for specifications, except that some menu commands differ. The interface for provingis also very similiar, but, of course, proof rules and heuristics dealing with programs are new.The hierarchy from projects to specifications and modules and finally to single proofs introducesdifferent levels. When working with KIV, the user is always working on one of these levels. Thetitle of the main window indicates the current level (see Fig. 11.1).

• Selecting or creating projects: KIV

• in a project, selecting or creating specifications and modules: daVinci

• in a specification, adding or selecting theorems for proving: Specification

in a module, adding or selecting theorems for proving: Module

• proving in a specification: Specification Strategy

proving in a module: Module Strategy

This structure is mapped onto the file system. The top directory (named with ?, which is ashortcut, and usually stands for projects) contains a file projects with a list of all known

start

����������

�����

����

�KIV

project1

����������

�����

����

�. . . projectk daVinci

spec1 . . . modulem

����������

�����

����

�Specification/Module

proof1 . . . proofn Specification/Module Strategy

Figure 11.1: Hierarchical structure of the software development environment

119

Page 121: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 11. MODULE VERIFICATION WITH KIV 120

projects and their directories. Each project is located in its own directory which is usually foundin the projects directory. Each project directory contains two subdirectories specs and mods,which in turn contain directories for every specification and module of the project. Finally, everyspecification or module directory contains a subdirectory proofs with the theorem base and theproofs.

11.2 The Project Selection Level

The software development environment is started by entering

PPL 1> (start)

at the PPL prompt. The KIV window appears and the user is working on the highest level. Hereonly one menu Projects with the commands Select, Create and Exit exists:

Select an existing project to work with. The level changes from the project selection level to theproject level. The windows changes to daVinci.

Create a new project. The user has to provide a name and a directory for the project.

1. What is the name for the project?

The name must be new (i.e. different from all existing projects) and suitable as adirectory name. This means beside others that it should not contain spaces or slashes.

2. In which directory is the project located?

KIV suggests the project name as the directory name, but it is also possible to enteran arbitrary directory. If the directory does not exist it is created.

After creating a new project it can be selected with Projects – Select. The system doesnot change to the new project automatically.

Exit the software development environment.

11.3 Modules in Projects

It has already been mentioned that every module has its own directory (with the same name asthe module) inside a subdirectory

〈Project name〉/mods/

The module directory contains six files and two subdirectories that are created when the moduleis created (with Module – Create).

• module

This file will contain the text for the module (mapping and implementation). Initially, itcontains a frame that has to be filled in by the user. Once created, the file is never overwrittenby the system.

• restriction

This file will contain the text for the restriction. Initially, it contains an empty restriction.If no restriction is needed (i.e. true is a valid restriction), the user can ignore this file.Otherwise it should be filled in before the module is installed.

Both the module and the restriction files are loaded when the module is installed, andmust be properly filled in.

Page 122: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 11. MODULE VERIFICATION WITH KIV 121

• sequents

This file is used to enter or modify theorems. It is loaded by the commands Theorem – Load

New and Theorem – Load Changed. It is overwritten by the command Print – Theorems

Readably. KIV will never overwrite this file by itself.

• module-specific

This file contains the patterns for the module specific heuristic which is explained in detailin section 8.8 and appendix G. Initially this file contains no patterns.

• formulas

This file is used to enter complex formulas for some rules. The rule cut formula (andothers) has an option to read the cut formula from this file. It is intended as a temporarybuffer.

• declarations

This file is used to enter auxiliary declarations to the theorem base.

• proofs/

The proofs/ directory contains the theorem base and all proofs. This directory should neverbe touched by the user!

• doc/

The doc/ directory stores documentation (proof protocols, Latex – Proof Protocol, aLATEX version of the theorem base, Latex – Theorems, etc.), that is generated by selectingthe appropriate commands. Existing files will be overwritten.

11.4 Exercise 8

Exercise 8.1 The task is to implement and verify a module that implements sets by duplicate-freelists.

The specifications and part of the implementation are already predefined. They can be foundin the project Exercise8. The specification of sets (called set) is

set =generic specification

parameter elem targetsorts set;constants ∅ : set;functions

. ++ . : set × elem → set prio 9 left;

. – . : set × elem → set prio 9 left;predicates

. ∈ . : elem × set;

. ⊆ . : set × set;variables s’, s: set;induction set generated by ∅, ++;

axiomss = s’ ↔ (∀ a. a ∈ s ↔ a ∈ s’),¬ a ∈ ∅,a ∈ s ++ b ↔ a = b ∨ a ∈ s,a ∈ s – b ↔ a �= b ∧ a ∈ s,s ⊆ s’ ↔ (∀ a. a ∈ s → a ∈ s’),end generic specification

Page 123: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 11. MODULE VERIFICATION WITH KIV 122

The specification of lists contains only the elementary operations.

list-data =generic data specification

parameter elem using natlist = []

| . + . prio 9 (. .first : elem ; . .rest : list ;) prio 9;

variables x, y, z, x0, y0, z0, x1, y1, z1, x2, y2, z2: list;size functions # . : list → nat ;order predicates . < . : list × list;

end generic data specification

As already mentioned, sets should be implemented by duplicate free lists (other possibilitiesare arbitrary lists, or ordered lists if an ordering is added to the parameter). This means that arestriction procedure is needed that checks if a list has no duplicates. Furthermore, an identificationprocedure is needed that tests if two lists represent the same set, i.e. if one list is permutation ofthe other. The restriction is already implemented in the module (see below).

set-list =module

export setrefinement

representation of sortslist implements set;

representation of operationsempty# implements ∅;insert# implements ++;delete# implements –;member# implements ∈;subset# implements ⊆;

equality eq# : set;restriction r# : set;uniform restriction uniform r# : set;implementationimport listvariables e, e0 : bool;

declaration

r#(x){

if x = [] then skip elselet e = true in

{member#(x.first, x.rest; e);if e then abortelse r#(x.rest)

};};

member#(a, x; var e){

if x = [] then e := false

Page 124: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 11. MODULE VERIFICATION WITH KIV 123

else if a = x.first then e := trueelse member#(a, x.rest; e);

}

empty#(var x){

*your task*};

insert#(x, a; var y){

*your task*};

subset#(x, y; var e){

*your task*};

eq#(x, y; var e){

*your task*};

delete#(x, a; var y){

*your task*};

Here are some recommendations to make the verification as easy as possible.

1. Use recursive procedures, not while loops.

2. Don’t use always ‘DL Heuristics + Induction’. This set can prove some simple goals auto-matically, but will lead to very nasty sequents for more complex goals. On the other handyou can always use ‘DL Heuristics + Case Splitting’. You can use either structural inductionor (noetherian) induction for the proofs.

3. It is very important to invent useful theorems! Even if it takes some time to type them in –in the end they simplify the verification more than you think. Some additional tips on howto formulate theorems:

• Use as few propositional connectives as possible. They have to be simplified (withadditional proof steps) when you use the theorem as a lemma, and when you prove thetheorem.

• Don’t formulate a theorem as an equivalence ϕ ↔ ψ. Formulate two theorems foreach direction (ϕ ψ and ψ ϕ).

Page 125: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 11. MODULE VERIFICATION WITH KIV 124

• Formulate the theorem only with the really indispensible preconditions. Otherwise youhave to prove that they hold every time you use the theorem. This applies especiallyto the precondition that a list is duplicate free. If the theorem holds without thisprecondition (e.g. member# always terminates), you should formulate this theoremeven though a proof obligation with the precondition already exists.

• Theorems for sets (e.g. ¬ a ∈ s → ¬ a ∈ s − b) are usually useful theorems for theimplementation (of course the theorem has to be formulated for the procedures workingon the duplicate free lists).

Bonus Exercise: Add a union operation to the specification of sets. Implement your operationin your module using a procedure union#. Reload the set specification and the module and proofthe additional proof obligations for union. The specification of union for sets should be:

a ∈ s ∪ s’ ↔ a ∈ s ∨ a ∈ s’

In the same manner add specifications to the set specification for the predicate disjP, which istrue, iff two lists do not share common elements and the function \, which implements differenceon sets. Implement these operations in the module and verify the additional proof obligations.

Page 126: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 12

Module Verification: An Example

12.1 The Nat-Bin Module

nat-bin =module

export natrefinement

representation of sortsbin implements nat;

representation of operationszero# implements 0;succ# implements +1;pred# implements -1;add# implements +;sub# implements -;mult# implements *;div# implements div;mod# implements mod;ls# implements <;divisor# implements | ;

implementation

import enrbin

proceduresbitadd# (bin, bin, bin) : (bin, bin);bitsub# (bin, bin, bin) : (bin, bin);addc# (bin, bin, bin) : bin;subb# (bin, bin, bin) : (bin, bool);divisorh# (bin, bin) : bin;divmod# (bin, bin) : (bin, bin);

variables u, r, q, p, x1, y1, s, z, ca, c, bo, b, a: bin; e0, e: bool;

declaration

zero#(var x) { x := 0 };succ#(x; var y)

125

Page 127: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 126

{if x = 0 then y := 1 elseif x = 1 then y := 1.0 elseif x top = 0 then y := x pop.1 else { succ#(x pop; y); y := y.0 }

};pred#(x; var y){if x = 0 ∨ x = 1 then y := 0 elseif x = 1.0 then y := 1 elseif x top = 1 then y := x pop.0 else { pred#(x pop; y); y := y.1 }

};add#(x, y; var s) { addc#(x, y, 0; s) };addc#(x, y, c; var s){

if x = 0 then if c = 0 then s := y else succ#(y; s) elseif y = 0 then if c = 0 then s := x else succ#(x; s) elseif x = 1 thenif c = 0 then succ#(y; s) elseif y = 1 then s := 1.1 else{ succ#(y pop; s); if y top = 0 then s := s.0 else s := s.1 }

elseif y = 1 thenif c = 0 then succ#(x; s) else{ succ#(x pop; s); if x top = 0 then s := s.0 else s := s.1 }

elselet z = 0 in{

bitadd#(x top, y top, c; z, c);addc#(x pop, y pop, c; s);if z = 0 then s := s.0 else s := s.1

}};bitadd#(a, b, c; var z, ca){if a = 0 thenif b = 0 then { ca := 0; z := c }elseif c = 0 then { ca := 0; z := 1 }else{ ca := 1; z := 0 }

elseif b = 0 thenif c = 0 then { ca := 0; z := 1 }else{ ca := 1; z := 0 }

else{ ca := 1; z := c }

};sub#(x, y; var s) {let e = true insubb#(x, y, 0; s, e) };subb#(x, y, b; var s, e)

Page 128: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 127

{if x = 0 then{ s := 0; if y = 0 ∧ b = 0 then e := true else e := false }

elseif y = 0 thenif b = 0 then { s := x; e := false }elseif x = 0 then { s := 0; e := false }else{ pred#(x; s); e := true }

elseif x = 1 then{ s := 0; if y = 1 ∧ b = 0 then e := true else e := false }

elseif y = 1 then{

e := true;if b = 0 then pred#(x; s) else{ pred#(x pop; s); if x top = 0 then s := s.0 else s := s.1 }

}elselet b = 0, z = 0 in{

bitsub#(x top, y top, b; z, b);subb#(x pop, y pop, b; s, e);if e thenif s = 0 then s := z else if z = 0 then s := s.0 else s := s.1

}};bitsub#(x, y, b; var z, c){if x = 0 thenif y = 0 then { z := b; c := b }elseif b = 0 then { z := 1; c := 1 }else{ z := 0; c := 1 }

elseif y = 0 thenif b = 0 then { z := 1; c := 0 }else{ z := 0; c := 0 }

else{ z := b; c := b }

};mult#(x, y; var p){

if x = 0 then p := 0 elseif x = 1 then p := y else{ mult#(x pop, y; p); p := p.0;if y top = 1 then add#(p, y; p) }

};ls#(x, y; var e) {let s = 0 insubb#(x, y, 0; s, e) };div#(a, b; var q)

Page 129: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 128

{let x = 0 inif b = 0 then q := 0 else divmod#(a, b; q, x)

};mod#(a, b; var x){

let q = 0 inif b = 0 then x := a else divmod#(a, b; q, x)

};divmod#(a, b; var q, r){let e = true inls#(a, b; e);if e then { q := 0; r := a }elseif a = 1 then { q := 1; r := 0 }else{

divmod#(a pop, b; q, r);if q = 0 then { q := 1; sub#(a, b; r) }else{

if r = 0 then r := a top else if a top = 0 then r := r.0 else r := r.1;ls#(r, b; e);if ¬ e then { sub#(r, b; r); q := q.1 }elseq := q.0

}}

};divisor#(x, y; var e){let z = 0 inif y = 0 then e := true elseif x = 0 then e := false else{

ls#(y, x; e);if ¬ e then{ divisorh#(x, y; z); if y = z then e := true else e := false }

}};divisorh#(u, y; var z){let e = true, x = 0 inls#(y, u.0; e);if ¬ ethen{

divisorh#(u.0, y; z);add#(z, u; x);ls#(y, x; e);if ¬ e then z := x

}elsez := u

}

Page 130: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 129

12.2 Module Verification: an Example Proof

�1

�2

�3��� ���

�4

�5

�6

�7

�8

�9

�10

�11

�12

�13

�14��� ���

�15

�16

�17

�18

�19

�20

�21��� ��

�22

�23

�24

�25

�26

�27

�28

�29

�30

�31

�32�����33

�34

�35

�36

�37

�38

�39

�40�����41

�42

�43

�44

�45

�46

�47

�48

�49

�50

�51

�52

�53

�54

�55

�56

�57

Page 131: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 130

iii-03

〈r#(y)〉 true 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

• proofsteps: 57

• interactions: 0

• automation: 100.0 %

• used lemmas: -

• used simplifier rules:

x pop.1 = x ↔ ¬ (x = 0 ∨ x = 1 ∨ x top = 0)

x.0 pop = x

x.0 top = 0

x.0 = x0.0 ↔ x = x0

1 �= x.0

0 �= x.0

true → (x pop = 0 → ¬ ¬ (x = 0 ∨ x = 1 ∨ x = 0.0 ∨ x = 0.1))

x pop $ x ↔ ¬ (x = 0 ∨ x = 1)

x top �= 0 ↔ x top = 1

x pop.0 = x ↔ ¬ (x = 0 ∨ x = 1 ∨ x top = 1)

x.1 pop = x

0 �= 1

x.1 top = 1

x top �= 1 ↔ x top = 0

x.0 �= x0.1

1 �= x.1

0 �= x.1

1) induction: induction for y〈r#(y)〉 true 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

2) unfold: call left 1〈r#(y)〉 true, Ind-Hyp 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

3) conditional left split: if left 1〈 if y = 0 then skip else rh#(y)〉 true, Ind-Hyp 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

4) symbolic execution: skip left〈skip〉 true, Ind-Hyp, y = 0 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

5) pl simplifier: pl simplifier

Page 132: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 131

Ind-Hyp, y = 0, true 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

6) weak unfold: call right 1Ind-Hyp 〈succ#( 0; y0)〉 〈pred#(y0; y1)〉 y1 = 0

7) symbolic execution: if positive right 1Ind-Hyp

〈if 0 = 0 then y := 1 elseif 0 = 1 then y := 1.0 elseif 0 top = 0 then y := 0 pop.1 else{succ#( 0 pop; y);y := y.0

} 〉 〈pred#(y; y1)〉 y1 = 0

8) symbolic execution: assign rightInd-Hyp 〈y := 1〉 〈pred#(y; y1)〉 y1 = 0

9) weak unfold: call right 1Ind-Hyp 〈pred#( 1; y1)〉 y1 = 0

10) symbolic execution: if positive right 1Ind-Hyp 〈if 1 = 0 ∨ 1 = 1 then y := 0 else

if 1 = 1.0 then y := 1 elseif 1 top = 1 then y := 1 pop.0 else{pred#( 1 pop; y);y := y.1

} 〉 y = 0

11) symbolic execution: assign rightInd-Hyp 〈y := 0〉 y = 0

12) (from 3) induction: call right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0 〈succ#(y; y0)〉 〈pred#(y0; y1)〉 y1 = y

13) symbolic execution: if negative right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0

〈if y = 0 then y1 := 1 elseif y = 1 then y1 := 1.0 elseif y top = 0 then y1 := y pop.1 else{succ#(y pop; y1);y1 := y1.0

} 〉 〈pred#(y1; y2)〉 y2 = y

14) conditional right split: if right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0

〈if y = 1 then y1 := 1.0 elseif y top = 0 then y1 := y pop.1 else{succ#(y pop; y1);y1 := y1.0

Page 133: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 132

} 〉 〈pred#(y1; y2)〉 y2 = y

15) symbolic execution: assign right〈rh#(y)〉 true, Ind-Hyp, y �= 0, y = 1 〈y1 := 1.0〉 〈pred#(y1; y2)〉 y2 = y

16) pl simplifier: pl simplifier〈rh#(y)〉 true, Ind-Hyp, y �= 0, y = 1 〈pred#( 1.0; y2)〉 y2 = y

17) weak unfold: call right 1〈rh#( 1)〉 true, Ind-Hyp 〈pred#( 1.0; y2)〉 y2 = 1

18) symbolic execution: if negative right 1〈rh#( 1)〉 true, Ind-Hyp

〈if 1.0 = 0 ∨ 1.0 = 1 then y := 0 elseif 1.0 = 1.0 then y := 1 elseif 1.0 top = 1 then y := 1.0 pop.0 else{pred#( 1.0 pop; y);y := y.1

} 〉 y = 1

19) symbolic execution: if positive right 1〈rh#( 1)〉 true, Ind-Hyp

〈if 1.0 = 1.0 then y := 1 elseif 1.0 top = 1 then y := 1.0 pop.0 else{pred#( 1.0 pop; y);y := y.1

} 〉 y = 1

20) symbolic execution: assign right〈rh#( 1)〉 true, Ind-Hyp 〈y := 1〉 y = 1

21) (from 14) conditional right split: if right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1

〈if y top = 0 then y1 := y pop.1 else{succ#(y pop; y1);y1 := y1.0

} 〉 〈pred#(y1; y2)〉 y2 = y

22) symbolic execution: assign right〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0 〈y1 := y pop.1〉 〈pred#(y1; y2)〉 y2 = y

23) weak unfold: call right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0 〈pred#(y pop.1; y2)〉 y2 = y

24) symbolic execution: if negative right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0

〈if y pop.1 = 0 ∨ y pop.1 = 1 then y0 := 0 elseif y pop.1 = 1.0 then y0 := 1 elseif y pop.1 top = 1 then y0 := y pop.1 pop.0 else{pred#(y pop.1 pop; y0);

Page 134: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 133

y0 := y0.1} 〉 y0 = y

25) symbolic execution: if negative right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0

〈if y pop.1 = 1.0 then y0 := 1 elseif y pop.1 top = 1 then y0 := y pop.1 pop.0 else{pred#(y pop.1 pop; y0);y0 := y0.1

} 〉 y0 = y

26) symbolic execution: if positive right 1〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0

〈if y pop.1 top = 1 then y0 := y pop.1 pop.0 else{

pred#(y pop.1 pop; y0);y0 := y0.1

} 〉 y0 = y

27) symbolic execution: assign right〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top = 0 〈y0 := y pop.1 pop.0〉 y0 = y

28) (from 21) pl simplifier: pl simplifier〈rh#(y)〉 true, Ind-Hyp, y �= 0, y �= 1, y top �= 0

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

29) unfold: call left 1〈rh#(y)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

30) symbolic execution: if negative left 1〈 if y = 0 then abort else if y = 1 then skip else rh#(y pop)〉 true, Ind-Hyp, y top = 1,y �= 0, y �= 1

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

31) symbolic execution: if negative left 1〈 if y = 1 then skip else rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

32) apply ind once: apply induction with y2 ← y pop〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

33) weak unfold: call right 1〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1

〈r#(y pop)〉 true, 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

34) conditional right split: if right 1〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1

〈 if y pop = 0 then skip else rh#(y pop)〉 true,〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

35) symbolic execution: skip right

Page 135: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 134

〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1, y pop = 0 〈skip〉 true, 〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

36) (from 32) contract and execute: execute call (1,1)〈succ#(y pop; y0)〉 〈pred#(y0; y1)〉 y1 = y pop, 〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y

�= 0,y �= 1

〈succ#(y pop; y1)〉 〈y1 := y1.0〉 〈pred#(y1; y2)〉 y2 = y

37) symbolic execution: assign right〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1

〈y3 := y3.0〉 〈pred#(y3; y2)〉 y2 = y

38) weak unfold: call right 1〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1

〈pred#(y3.0; y2)〉 y2 = y

39) symbolic execution: if negative right 1〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1

〈if y3.0 = 0 ∨ y3.0 = 1 then y0 := 0 elseif y3.0 = 1.0 then y0 := 1 elseif y3.0 top = 1 then y0 := y3.0 pop.0 else{pred#(y3.0 pop; y0);y0 := y0.1

} 〉 y0 = y

40) conditional right split: if right 1〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1

〈if y3.0 = 1.0 then y0 := 1 elseif y3.0 top = 1 then y0 := y3.0 pop.0 else{pred#(y3.0 pop; y0);y0 := y0.1

} 〉 y0 = y

41) symbolic execution: assign right〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1, y3.0 = 1.0

〈y0 := 1〉 y0 = y

42) pl simplifier: pl simplifier〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1, y3.0 = 1.0, 1 �= y

Page 136: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 135

43) weak unfold: call left 1〈pred#( 1; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = 1, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1, 1 �= y

44) symbolic execution: if positive left 1〈if 1 = 0 ∨ 1 = 1 then y0 := 0 else

if 1 = 1.0 then y0 := 1 elseif 1 top = 1 then y0 := 1 pop.0 else{pred#( 1 pop; y0);y0 := y0.1

} 〉 y0 = y pop,〈succ#(y pop; y0)〉 y0 = 1, 〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1, 1 �= y

45) symbolic execution: assign left〈y0 := 0〉 y0 = y pop, 〈succ#(y pop; y0)〉 y0 = 1, 〈rh#(y pop)〉 true, Ind-Hyp, y top =

1, y �= 0,y �= 1, 1 �= y

46) pl simplifier: pl simplifier〈succ#(y pop; y0)〉 y0 = 1, 〈rh#(y pop)〉 true, Ind-Hyp, y top = 1, y �= 0, y �= 1, 1 �= y,0 = y pop

47) weak unfold: call left 1〈succ#( 0; y0)〉 y0 = 1, 〈rh#( 0)〉 true, Ind-Hyp

48) symbolic execution: if positive left 1〈if 0 = 0 then y := 1 else

if 0 = 1 then y := 1.0 elseif 0 top = 0 then y := 0 pop.1 else{succ#( 0 pop; y);y := y.0

} 〉 y = 1,〈rh#( 0)〉 true, Ind-Hyp

49) symbolic execution: assign left〈y := 1〉 y = 1, 〈rh#( 0)〉 true, Ind-Hyp

50) pl simplifier: pl simplifier〈rh#( 0)〉 true, Ind-Hyp, 1 = 1

51) weak unfold: call left 1〈rh#( 0)〉 true, Ind-Hyp

52) symbolic execution: if positive left 1

Page 137: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 12. MODULE VERIFICATION: AN EXAMPLE 136

〈 if 0 = 0 then abort else if 0 = 1 then skip else rh#( 0 pop)〉 true, Ind-Hyp

53) symbolic execution: abort left〈abort〉 true, Ind-Hyp

54) (from 40) symbolic execution: if negative right 1〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1, y3.0 �= 1.0

〈if y3.0 top = 1 then y0 := y3.0 pop.0 else{pred#(y3.0 pop; y0);y0 := y0.1

} 〉 y0 = y

55) pl simplifier: pl simplifier〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y �= 0, y �= 1, y3.0 �= 1.0

〈pred#(y3.0 pop; y0)〉 〈y0 := y0.1〉 y0 = y

56) contract and execute: execute call (1,1)〈pred#(y3; y1)〉 y1 = y pop, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y

top = 1,y3 �= 1, y �= 0, y �= 1

〈pred#(y3; y0)〉 〈y0 := y0.1〉 y0 = y

57) symbolic execution: assign right〈pred#(y3; y1)〉 y1 = y4, 〈succ#(y pop; y0)〉 y0 = y3, 〈rh#(y pop)〉 true, Ind-Hyp, y top =

1,y3 �= 1, y �= 0, y �= 1, y4 = y pop

〈y4 := y4.1〉 y4 = y

Page 138: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 13

Contracts, Abstract Data Typesand Refinement

In this exercise we will have a look at the problem, how to get from an abstract specification toexecutable code. This is a general problem of Software Engineering, independent of whether formalmethods are used or not. There are many proposals, what to use for informal specifications (e.g.the various diagrams of UML) and how to proceed (e.g. Unified Process). Almost all methodsbased on abstract models propose to construct more concrete models incrementally.

When formal methods are used, one step from a more abstract to a more concrete specificationis called a refinement step. The main question for such a step is: Is the concrete model guaranteedto meet the requirements given in the abstract specification, is the refinement correct? Correctnessof a refinement should imply, that certain properties that were true for the abstract specificationare also true for the concrete specification. What the properties that should be preserved are(functional properties, safety properties, security properties, termination etc.) often depends onthe application and the specification language. Therefore there are many formal definitions ofrefinement.

We will look at one, that assumes that an abstract data type is specified as a number of contractsfor procedures (or methods), and that we want the implementation to preserve inputs and outputsthat were specified in these contracts. The next section defines contracts. Based on these abstractdata types and their semantics are defined.

13.1 Contracts

A contract for a procedure consists of

• A name

• A definition of the input and output variables of a procedure (these may overlap)

• A precondition ϕ

• A postcondition ψ

• Some informal text specifying the purpose of the procedure

A procedure satisfies a contract, if the procedure terminates on any input that satisfies ϕand yields output that satisfies ψ (total correctness). In our formal specification language, thespecification of a contract requires specifications of data types to be used as the type of variables,and predicate logic formulas ϕ and ψ. A simple example is the contract for a reverse function:

• Name: reverse#

• Input: x of type list

137

Page 139: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 138

• Output: x

• Precondition: x = y

• Postcondition: x = reverse(y)

This definition assumes a data type of lists and that a function reverse on it has been given.The name reverse# follows the usual KIV convention to have procedure names that end with #.The pre- and postcondition use the program variable x and the auxiliary variable y which is notused in the implementation. Such a variable is often called a logical variable.

Another example is the following contract for a dequeue operation:

• Name: dequeue#

• Input: q of type queue

• Output: the modified queue q and an element o

• Precondition: q = q0 ∧ q0 �= empty

• Postcondition: q = deq(q) ∧ o = hd(q)

A specification of queues is assumed, where deq(q) removes the first queue element hd(q) andwhere empty is the empty queue.

For formal specification of contracts it is often convenient to merge the pre- and postconditioninto a single formula, that describes a relation between initial and final state. This is usuallydone using a convention that distinguishes between the value of a variable in the state beforethe procedure is called and in the state at the end. We use the convention of the specificationlanguage Z [Spi92]: x refers to the value of x in the initial state, and x′ refers to the value at theend. Other conventions are pre(x) and x in VDM [Jon87], or \old(x) and x in JML [LBR06], aspecification language for Java programs. With our convention the contract above can be specifiedby the predicate

REV(x,x′) ↔ ∃ y. x = y ∧ x′ = reverse(y)

Note that this definition was systematically constructed: the quantified variables are all logi-cal variables, and the formula below the quantifier is the conjunction of the precondition and amodified postcondition, that primes all program variables. The definition can be simplified to

REV(x,x′) ↔ x′ = reverse(x)

The logical variables always disappear, when the precondition has equations x = y. At first glance,a contract adds little new information to the algebraic specification of the reverse function. Butnote, that the contract states which variables will be affected: for the contract above, variable xwill be overwritten by the procedure. A contract

REV(x,z′) ↔ z′ = reverse(x)

would require that x is unchanged and z overwritten. The contract

REV(x,x′, z′) ↔ z′ = reverse(x)

allows x to change arbitrarily.For the queue example above the relational contract becomes

DEQ(q,q′,o′) ↔ q �= empty ∧ q′ = deq(q) ∧ o′ = hd(q)

Page 140: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 139

For a contract OP(s,s′) in relational form the precondition can be recomputed as

pre(OP)(s) := ∃ s′. OP(s,s′)

For the dequeue example above, this gives

pre(DEQ)(q) := q �= empty

13.2 Abstract Data Types

A standard view of a software system is the black box view: the system is defined as the interfaceit offers to a user, which consists of a number of (system) operations specified by contracts. Thisdefinition of a software system encompasses systems of any size: it can be a big system consistingof many components, packages and classes. It can also be a package or a class. Even an objectand the methods for a single object in Java would be acceptable as a system.

The system operations all modify a common (system) state, and have inputs and outputs.The system is used in an environment which calls the operations with suitable inputs and receivestheir outputs. The system state is not directly accessible (information hiding), but only using theoperations.

In formal specification, the black box view of a software system is commonly called an abstractdata type (which should not be confused with algebraic data types, although algebraic data typesare often called abstract data types too).

Definition 1 An abstract data type DT = (S, I, {OPi}i=1...n) consists of

• A set of states S.

• A set of initial states I ⊆ S.

• A definition of a number of contracts OPi (i = 1 . . . n) for the methods (= operations) ofthe data type. Each contract is specified as a relation over some inputs Ii, the initial andfinal state of type S, and some outputs Oi:

OPi : Ii × S × S × Oi

In KIV abstract data types are specified using an algebraic data type that defines the set ofstates. To formally specify an abstract data type in KIV one therefore has to do the following:

• Algebraically specify a data type with sort S. Its values are the possible states. Typicallythe sort S is specified as a tuple type. Each element of a tuple will become the value of oneprogram variable in an implementation.

• Specify a predicate I on sort S, which describes the initial states.

• Specify the types Ii and Oi to be used as inputs and outputs

• Define the signature of the contracts as predicates:

predicates OP1 : I1 × S × S × O1

OP2 : I2 × S × S × O2

• Specify the contracts with axioms:

OP1(i,s,s’,o) ↔ <some formula>

Page 141: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 140

13.3 Example of an Abstract Data Type: Queues

In this section we specify an abstract data type of queues, that will be used in the exercise. Thestate of a queue consists of a value of type queue. In the exercise, the algebraic type of queuesis specified by renaming lists: the empty list is the empty queue, enqueuing an element adds itto the end of the list, dequeuing removes the first element of the list. The three operations onqueues are EMP (setting a queue to the empty queue), ENQ and DEQ (enqueuing/ dequeuing anelement). Their contracts are:

EMP(q,q’) ↔ q’ = empty

DEQ(q,q’,an) ↔ (q �= null ⊃ q’ = deq(q) ∧ an = mk(hd(q)); q’ = q ∧ an = none)

ENQ(i,q,q’) ↔ q’ = enq(q,i)

In contrast to the previous section, the dequeue operation is defined for all queues includingthe empty queue. Its output is of type elemornone, which is a free data type specified as:

data specificationelemornone = mk(. .elem : elem) | none;

variables an : elemornone;end data specification

For an empty queue the operation returns none and does not change the queue, for a nonemptyqueue the output is mk(hd(q)).

13.4 Semantics of Abstract Data Types

An abstract data type is used by starting in an initial state and randomly invoking operations.Starting from an initial state s0 ∈ I, calling one of the operations, e.g. OPk1 with input i1 (ofsuitable type) may change the state to s1 and gives an output o1, if OPk1(i1,s0,s1,o1) holds. Asecond operation may result in OPk2(i2,s1,s2,o2) and so on.

To define a semantics it is assumed, that all a user can observe when calling an operation isthe inputs he chooses and the output he gets. All changes to the state are invisible for the user(information hiding). A first idea for a formal definition therefore is to define the semantics as allsequences

(i1,k1,o1), (i2,k2,o2), . . . (im,km,om)

that result from calling operations as describe above. This has a small problem: Assume the firstoperation is invoked with a state and an input that violates its precondition. Then according tothe specification, the effect is unspecified, and all following operations are allowed to do anything.Therefore the formal definition must leave open what happens after an operation (say OPkp forsome p ≤ m) is invoked outside its precondition:

Definition 2 (Semantics of Abstract Data Types)The semantics SEM(DT) of a data type is the set of all finite sequences

[(i1,k1,o1) (i2,k2,o2), . . . (im,km,om)]

such that

• All OPkj (1 ≤ j ≤ n) are operations, i.e. kj ≤ n. The inputs and outputs ij and oj havesuitable types for OPkj .

Page 142: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 141

• There are suitable intermediate states s0, s1, . . . sm and s0 is an initial state.

• There is a 1 ≤ p ≤ m such that all operations before step p are invoked within theirprecondition, and therefore give a result (state and output) that satisfies the contract:

OPkj (ij , sj−1, sj , oj) holds for j < p.

• If p �= m (otherwise all steps are ok), then step p is invoked with an input outside itsprecondition:

¬ ∃ s, o. OPkp(ip, sp−1, s, o)

The result state sp and output op are arbitrary, as well as all states sj , inputs ij and outputsoj for later steps with j > p.

13.5 Refinement of Abstract Data Types

The idea of refinement of data types is that a user works with an abstract specification ADT =(AS, AI, {AOPi}i=1...n) like the example queue above. He will invoke operations of the data typeand can check, whether the outputs he gets when giving some inputs conform to the abstractcontracts. The implementation will be a concrete data type CDT = (CS, CI, {COPi}i=1...n),which has the same operations, inputs and outputs, but which works with an implementation ofthe abstract state AS by a concrete state CS. In our exercise below, the concrete state will consistof a heap of cons cells. The concrete state represents the queue as (the values in) a chain of heapcells.

A refinement of ADT by CDT is correct, if the user cannot note the difference. Substitutingeach call to the abstract operation by a call to the concrete operation gives the same result(this is called the principle of substitutivity). Formally, each sequence [(i1,k1,o1) (i2,k2,o2), . . . ofobservations a user can make with CDT (i.e. that is in the semantics of CDT) must also bepossible when using ADT.

Definition 3 (Refinement of Abstract Data Types)A refinement of one data type ADT = (AS, AI, {AOPi}i=1...n) to another data type CDT =

(CS, CI, {COPi}i=1...n) is correct, if

• Both data types have the same number n of operations with the same input and outputtypes.

• SEM(CDT) ⊆ SEM(ADT)

It is not necessary that all observations the user can make with ADT are also observations withCDT. This happens in two cases: first, when the abstract operation was unspecified for some inputi and state s (so calling it results in any result state s′ and any output o) the concrete operationis free to return one single well-defined result (s′ and o). Second, when the abstract specificationcan return one of several results, the implementation is free to choose one specific result.

As an example consider an abstract specification of sets (the state is of type set) with anoperation that chooses an (arbitrary) element from the set. A contract for this operation wouldbe:

GET(s,s’,a) ↔ s’ = s ∧ (s �= ∅ → a ∈ s)An implementation could e.g. represent sets by lists (or some more elaborate data structure likea hash table or a balanced tree) and choose some element from the representation, e.g. the firstelement of the list. The implementation is free to always return the same element (e.g. theminimum if the list is sorted). Its answer may also depend on the internal order, that resultedfrom inserting the elements (e.g. the implementation could always return the element that wasinserted last), even though the abstract set does not have such an internal order.

Page 143: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 142

13.6 Verifying Refinement Correctness

The definition of refinement correctness talks about arbitrary sequences of operations. This is notpractical for verification. Instead one would like to verify proof obligations for single operations.To define such proof obligations the usual approach is to define an abstraction relation ABS(as, cs)(also called a simulation or a coupling invariant) between abstract states as and concrete statescs. ABS is typically a partial function from concrete to abstract states. Its domain are thelegal representations (for a queue e.g. the non-cyclical linear pointer structures). Its result is theabstract data structure that it represents. With such an abstraction function it can be shown thatthe following three conditions are sufficient to verify data refinement.

• initialization:CI(cs) → ∃ as. ABS(as,cs) ∧ AI(as)

• applicability:ABS(as,cs) ∧ pre(AOPk)(i,as) → pre(COPk)(i,cs)

• correctnesspre(AOPk)(i,as) ∧ ABS(as,cs) ∧ COPk(i,cs,cs’,o) → ∃ as’. ABS(as’,cs’) ∧ AOPk(i,as,as’,o)

The initialization condition guarantees that each concrete initial state represents some abstractstate. The applicability condition guarantees that as long as the precondition of the abstractoperations is not violated, the precondition of the concrete operation must hold too. Finally,the correctness condition guarantees, that invoking the concrete operation (with the abstractprecondition satisfied) gives an output that the abstract operation can give too. The resultingstate cs′ of the concrete operation should be a state that represents the abstract state as′ again.The correctness condition propagates the abstraction relation forwards through operations. If arelation satisfies the conditions it is therefore called a forward simulation (some authors preferthe term downward simulation). A forward simulation enables an inductive argument over thenumber of operations applied that formally proves refinement correctness.

Theorem 1 If the conditions initialization, applicability and correctness can be proved (the lattertwo for all operations) then the refinement from ADT to CDT is correct.

A simpler form of this theorem was first proved by Hoare and He [HHS86], the theorem hereis from [WD96]. These papers also prove that there are cases where forward simulations alone arenot sufficient to prove every data refinement: in rare cases one also needs backward simulations.We do not discuss these here, since we will not need them for the exercise.

13.7 Refinements of Contracts to Programs

Data refinement considers the case where a number of operations is implemented by operations on alower level data structure. In general there are many other types of refinement, e.g. implementingone operation by a sequence of lower level instructions (non-atomic refinement) or refinementswhere the lower level operations may be interleaved (e.g. when considering several threads onmulti-processors). In this section we will consider the case, where the abstract contracts areimplemented by programs working on a lower level data structure. This case can be viewed as ainstance of data refinement, by viewing a program as specific form of defining a contract. This ispossible by allowing dynamic logic formulas as pre- and postconditions. To see this, assume wehave specified a contract AOP(i,as,as’,o) and that we have a procedure

procedures COP#(i; cs,o) nonfunctional;

The procedure has input i, modifies a concrete state cs (therefore it must get the keywordnonfunctional in its signature definition) and returns output o. Such a procedure trivially satisfiesthe following contract:

Page 144: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 143

COP(i,cs,cs’,o’) ↔ 〈COP#(i;cs,o’)〉 (cs = cs’ ∧ o = o’) (1)

The precondition of this contract is just termination of the procedure.

pre(COP)(i,cs)↔ ∃ cs’,o’. 〈COP#(i;cs,o’)〉 (cs = cs’ ∧ o = o’) ↔ 〈COP#(i;cs,o’)〉 true

This contract can be substituted into the applicability and correctness condition for datarefinement. The resulting two conditions can be simplified into one proof obligation which is

ABS(as,cs) ∧ pre(AOP)(i,as)→ 〈COP#(i;cs,o)〉 (∃ as’. AOP(i,as,as’,o) ∧ ABS(as,cs’))

(2)

In words: If two states with ABS(cs, as) are given, and the contract of the abstract operationguarantees a well-defined result for some input i (i.e. pre(AOP )(i, as) holds), then the concreteoperation must terminate and give a state cs and an output o after its termination, such that itsimulates a possible execution of the abstract operation with the same output o: Some result stateas′ of the abstract operation must exists, that is the abstraction of the final state cs.

13.8 Nondeterministic Programs

In the exercise below we will use nondeterministic programs to choose new references in theheap (see below). Nondeterminism is necessary, as soon as parallel programs are considered (onetypically wants to abstract from scheduling strategies), but it is useful for specification too, e.g.to choose some element of a set, when we do not want to fix a concrete representation of sets onthe computer yet. KIV has two constructs for nondeterminism. The first is

α or β

which randomly chooses between executing α and β. The second construct is

choose x with ϕ in α ifnone β

It binds local variables x to arbitrary values that satisfy ϕ (ϕ may depend on x as well as on othervariables) and then executes the program α, which may now use the local variables in assignments.If no values that satisfies ϕ exists, β is executed. The ifnone can be dropped, and the defaultbehavior then is nontermination (i.e. ifnone abort). choose is more general than or: or can besimulated by choosing a boolean variable b:

choose b with true in if b then α else β

It is strictly more powerful than or, which cannot be used to implement a choice betweeninfinitely many values (e.g. to choose an arbitrary natural number). The relational semantics ofor is the union of both semantics

z[[α or β]]z′ iff z[[α]]z′ or z[[β]]z′

The semantics of choose is somewhat more complex:

Page 145: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 144

z[[choose x with ϕ in α ifnone β]]z′ iffeither there exists a with [[ϕ]]z[x ← a] = tt and z[x ← a][[α]]z′′ andz′ = z′′[x ← [[x]]z]or z[[β]]z′ and there does not exist a with [[ϕ]]z[x ← a] = tt

The relational semantics of nondeterministic programs is sufficient to answer the question:what are the possible final states of the program when started in a state z? It is no longersufficient to answer the question: Is the program guaranteed to terminate, when started in a statez? This can be seen when comparing the semantics of skip with the semantics of skip or abort:both programs have the same relational semantics (since the semantics of abort is empty)! This isdifferent from deterministic programs where possible and guaranteed nontermination are the same.Therefore in addition to defining a relational semantics, a formal semantics for nondeterministicprograms α must in addition specify a set of states where α is guaranteed to terminate. We writeα ↓ z = tt iff α is guaranteed to terminate, when started in z. A full formal definition for all casesis left to the reader, some cases of the definition are

• abort ↓ z = ff

• skip ↓ z = tt

• x := e ↓ z = tt

• α ∨ β ↓ z iff α ↓ z and β ↓ z

• α;β ↓ z = tt iff α ↓ z = tt and β ↓ z′ = tt for all states z′ that α can reach, when startedin z. These are the states with z[[α]]z′.

• choose x with ϕ in α ifnone β ↓ z iff either there is an a with A, vax |= ϕ, and all such asatisfy α ↓ vax = tt or there is no such a and β ↓ z holds.

With this additional semantic definition we can distinguish between skip or abort and skip,since skip or abort ↓ z = ff (this program is not guaranteed to terminate in any state), whileskip ↓ z = tt. For deterministic programs only we have

α ↓ z = tt iff there is a state z′ with z[[α]]z′

The diamond operator is no longer sufficient to show guaranteed termination for nondeterministicprograms. It shows only, that the program has a terminating run. This is an interesting property,but for total correctness one usually wants that all runs of a program terminate (and satisfy somepostcondition ϕ). Therefore we define a new operator 〈|α|〉 ϕ, which makes this assertion. Itssemantics is

[[〈|α|〉 ϕ]]z = tt iff α ↓ z = tt and all z′ with z[[α]]z′ satisfy [[ϕ]]z′ = tt.

The “strong diamond” operator 〈|α|〉 ϕ of KIV is usually written wp(α,ϕ) (from weakest pre-condition) in the literature. It was first defined in Dijkstra’s book [Dij76]. Note that “〈|α|〉 true”states, that α is guaranteed to terminate.

Guaranteed termination must be added to the definition of the contract for an implementedprocedure given in formula 1 of Section 13.7, when the procedure is nondeterministic. It mustchange to

COP(i,cs,cs’,o’) ↔ (〈|COP#(i;cs,o’)|〉 true) ∧ 〈COP#(i;cs,o’)〉 (cs = cs’ ∧ o = o’) (3)

Page 146: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 145

The proof obligation 2 also changes slightly. It now uses the strong diamond:

ABS(as,cs) ∧ pre(AOP)(i,as)→ 〈|COP#(i;cs,o)|〉 (∃ as’. AOP(i,as,as’,o) ∧ ABS(as’,cs))

(4)

This is the proof obligation we will use for the implementations of the procedures in the exercise.

13.9 Rules for nondeterministic programs

Since the exercise uses a nondeterministic choose for allocation in heaps (see below), the proofobligations for the exercises below will use the strong diamond. For the deterministic programswe have seen so far, the calculus rules for the strong diamond are exactly the same as the onesfor the diamond, so there is nothing new to learn for these. The strong diamond rules for the twonondeterministic program constructs in the succedent are given below. Note that for these therules are similar to their box rules, since all results have to satisfy the postcondition. In particular,for α or β, the strong diamond requires to prove that both α and β terminate and ψ holds at theend.

or right

Γ 〈α〉 ψ, 〈β〉 ψ,ΔΓ 〈α ∨ β〉 ψ,Δ

Γ [α] ψ,Δ Γ [β] ψ,Δ

Γ [α ∨ β] ψ,Δ

Γ 〈|α|〉 ψ,Δ Γ 〈|β|〉 ψ,ΔΓ 〈|α ∨ β|〉 ψ,Δ

choose right

Γ ∃ y.ϕyx ∧ 〈α

yx〉 ψ, (∀ x.¬ ϕ) ∧ 〈β〉 ψ,Δ

Γ 〈choose x with ϕ in α ifnone β〉 ψ,Δ

ϕyx,Γ [α

yx] ψ,Δ ∀ x.¬ ϕ,Γ [β] ψ,Δ

Γ [choose x with ϕ in α ifnone β] ψ,Δ

ϕyx,Γ 〈|α

yx|〉 ψ,Δ ∀ x.¬ ϕ,Γ 〈|β|〉 ψ,Δ

Γ 〈|choose x with ϕ in α ifnone β|〉 ψ,ΔThe variables y are new. The rules or left and choose left for the antecedent are similar.

13.10 Allocation in heaps

Allocation in heaps can be done via a new function

new : heap → Ref;

that is specified with the axiom

¬ new(H) ∈ H ∧ new(H) �= null

Page 147: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 146

It is somewhat more elegant and gives simpler proofs, to use nondeterminism in the programsthat have to allocate a new address. It is also slightly more realistic, since choose may choose adifferent value every time it is invoked, while for a fixed heap H , the reference new(H) is alwaysthe same (new is a function!). The standard code for allocation is:

choose r with ¬ r ∈ H ∧ r �= null in H[r] := . . .

Note that choosing the r itself does not allocate the reference. Only the assignment H [r] := . . .does.

13.11 Exercise 9

Select the project Exercise9. It contains a specification enqueue of queues, based on a specificationof lists from the library. This specification is used as the abstract specification of a refinement.The specification cons-heap of heaps is based the one of Exercise 2. It specifies the contents of aheap cell as a pair of an elem selected with .val and a reference to a next cell, selected with .nxt.Your task is to do two implementations of queues by sequences of cons-cells.

Exercise 9.1 (implementation of queues by sequences with tail pointer)In this exercise, you should implement heap based queues that have an additional pointer r1 to

the last cell (tail-pointer), besides a pointer to the first cell, r0. Specification queueimpl containsprocedure skeletons for enq#, deq# and emq#. Your task is to provide an implementation forthese procedures. You might need special code for the cases r0 = null or r0 = r1.

In specification queue-refinement, complete the definition of the abstraction relation abs(r0, r1, H, q).Then, prove correctness of the refinement.

Hints:

• The recursive definition of abs has three cases. One for the empty queue, one for a one-element queue, and one for a queue with more elements. The axioms should be usable asoften as possible as a simplifier rule.

• The implementation is quite simple. It has no recursion and no while loops.

• A useful lemma (and simplifier rule) may start with: abs(null, r1, H, q) ↔ . . ..

• You will also need a lemma such as abs(r,r,H,a + q) → q = []. This lemma is hard to prove,a direct inductive proof will fail since the induction hypothesis is not applicable. The trickis to find and prove a generalization. Intuitively, this lemma says that there are no cycles.

Exercise 9.2 implementation of queses by sequences without a tail pointerThis exercise is very similar to the previous one. The difference is that you should drop the

tailpointer, so the queue is defined by one reference r and the heap H only:

• The procedures enq#, deq# and emq# have a different signature (without r1)

• The abstraction abs(r,H, q) relation can be defined with two cases only (empty vs. nonemptyqueue, see lecture slides #8)

• enq# now needs to traverse the queue until the last cell is found. You will either need awhile-loop or recursion.

• deq# and emq# are almost identical to the previous exercise

Page 148: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 13. CONTRACTS, ABSTRACT DATA TYPES AND REFINEMENT 147

Create a specification queue-notail as an enrichment of cons-heap, elemornone and enqueue.Declare and implement the three procedures. Then, define abs and the proof obligations (again,see lecture slides) directly in this specification. Remember to also include the axiom infmem.

The proofs for emq# and deq# are similar to their tailpointer counterparts. The proof forenq# is more difficult, as this procedure is either recursive or contains a loop. Here are somehints:

• For recursion: an information you may need is: Given the heaps H and H ′ before and afterenq#, and any allocated reference r (r ∈ H, r �= null) with H [r].nxt �= null before theoperation. Then this reference will not change: r ∈ H ′ ∧ H [r] = H ′[r] holds.

• For recursion: It might be a good idea to define a helper procedure enqh# that performs theactual recursion but allocate the new reference in enq#. Otherwise, you may need a lemmathat specifies when the pointer to the head cell is not changed.

• For a while loop: Invariants may not help. An alternative is to use induction over queuesand while right to unwind a loop. execute while has the same purpose for while loops asexecute call has for calls.

• Again, a lemma (and simplifier rule) abs(null,H, q) ↔ . . . will be useful.

Page 149: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 14

Abstract State Machines andASM refinement

Abstract State Machines (ASMs) are a formalism to model algorithms in a simple, but formallydefined way.

ASMs originally were the result of theoretical research into the foundations of computation:The idea was to sharpen the thesis by Church and Turing, which says that all definitions of“algorithm” are equivalent (and equivalent to the computations of a Turing machine). This leadGurevich to the thesis that every algorithm (which satisfies some simple principles) can be naturallyexpressed as the computation of an ASM.

Recently, ASMs have been used in a large number of projects in software engineering. (for anoverview see either [BS03] or have a look at http://www.eecs.umich.edu/gasm/). In this sectionwe give a short overview over ASMs, the support for ASMs in KIV, ASM refinement and the proofobligations generated by KIV for ASM refinement.

14.1 Abstract State Machines

Basically, ASMs are like automata: they have initial and final states, and a transition relationto get from one state to the next. Since the idea of ASMs is that states should be as general aspossible, the state of an ASM is an algebra over some fixed signature (since what is more generalthan an arbitrary algebra?). The transition relation is defined by a rule which modifies algebras.Formally, an ASM = (S,I,F,R) consists of a set of states (a class of algebras over some fixedsignature), two sets of algebras I and F (the initial and the final states) and an ASM rule R.

ASM rules resemble the programs of KIV we saw earlier, but are more general: first, since thestate not only consists of variables like in KIV programs, ASMs may modify functions. Thereforethe simplest ASM rule R0 is an assignment of the form:

R0 ≡ f(t) := t′

where t and t′ are terms without variables. Such an assigment is called a function update.Executed in state A it computes a new algebra B, which is equal to A, except that function fAhas been modified, such that fB now computes [[t′]]A at position [[t]]A. A function f that is modifiedis called a dynamic function. “Dynamic constants” which are updated in assigments c := t areno longer constant, and we call them program variables. Functions which are not dynamic arecalled static and used to describe fixed datastructures like lists, natural numbers (just as we didin algebraic specifications).

Second, ASMs are more general than the programs we saw until now, since they may benondeterministic. For example the ASM rule

148

Page 150: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 149

choose x with ϕ(x) in R(x)

binds a local variable x to an arbitrary value that satisfies ϕ(x) then executes the ASM ruleR, which may now contain the local variable in the terms of assignments. If no suitable value xexists, the rule does not terminate by default. The variant

choose x with ϕ(x) in R(x) ifnone R1

allows to overwrite this default behaviour: the ifnone clause specifies explicitly, that R1 shouldbe applied in the case where no suitable value x exists.

Third, ASMs are more general than the programs we saw until now, since they may executerules in parallel. There are two constructs for parallel execution: One combines two rules R1 andR2 by just writing one on top of the other:

R1R2

It executes both rules in parallel. The second construct is

forall x with ϕ(x) do R(x)

It executes the rule R(x) in parallel for all values of x that satisfy ϕ(x). For example

forall n with true do f(n) := n+ 1

will modify f to become the successor function. Parallel updates come with a problem: Whathappens when executing

R1 ≡ f(3) := 4f(3) := 5

or

R2 ≡ forall n with true do f(2) := n

The solution is to have a slightly different semantics for ASM rules than we had for KIVprograms: ASM rules (nondeterministically) compute a set of updates, where one update is written(f, a) ← b. It consists of a function symbol f, an number of some argument values a (a pair (f, a)is also called a location) and a new value b. The idea is that it describes the modification of f ata to b. For the three examples above these sets are

[[R0]]A ≡ {(f, tA) ← t′A}

[[R1]]A ≡ {(f, 3) ← 4, (f, 3) ← 5}and

[[R2]]A ≡ {(f, 2) ← 0, (f, 2) ← 1, (f, 2) ← 2, . . .}If the set contains two updates for the same location (but with different values), as for R1 and

R2, then the update set is called inconsistent and the rule will do nothing. Otherwise all updatesare applied like described above to compute the successor state B from A.

Apart from the new constructs above, an ASM may also contain conditionals, sequential exe-cution and local variables, written

let x = t in R(x)

While loops are usually avoided (but can be defined), since the whole idea of an ASM is to bea loop itself that execute its rule until a final state is reached. Recursive procedures can be defined

Page 151: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 150

too, but since the idea of an ASM is to compute on a global state, usually only abbreviatons(called macros) are used for parts of a rule which appear several times. These are usually notrecursive.

Runs of an ASM (also called computations or traces) are sequences of states, that start in aninitial state (to be precise: an initial algebra) and apply the rule of the ASM either until a finalstate is reached (finite runs) or forever (infinite runs).

14.2 ASMs in KIV

KIV supports (a specific variant with some restrictions of) ASMs. The variant supported byKIV uses its many-sorted type system of higher-order logic (the original definition uses untypedfirst-order logic). Also, KIV replaces first-order algebras equivalently with valuations of higher-order functions: Instead of modifying a dynamic function, in KIV a function variable is modified.Program variables are ordinary first-order variables again. The function assignment

R = f(t) := t′

is available in KIV, and modifies a function variable f , specified as

variables f : s1 × . . .× sn → s;

The assignment now is just an abbreviation for

R = f := f(t; t′)

where the right hand side is a built-in mixfix operator that allows function modification on thealgebraic level. The mixfix operator can be viewed as a shortcut for:

f(t; t′) = λx.(x = t ⊃ t′; f(x))The KIV simplifier automatically rewrites f(t; t′)(t′′) to (t = t′′ ⊃ t′; f(t′′)).In general, dynamic functions are specified as functions variables, while static functions are

specified as functions just as in earlier exercises.Parallel composition is available only in the form of the parallel assignment1 we saw earlier.

Parallel composition of arbitrary rules as well as forall are currently not supported (since theproblem of detecting inconsistent updates would prevent the use of the intuitive principle ofproofs by symbolic execution). On the other hand, nondeterminism with the choose constructis available in KIV and comes with an additional problem: for a nondeterministic program α theformula 〈α〉 ϕ only says that there is one terminating run such that ϕ holds at the end. But oftenwe are also interested in the fact, that all runs terminate and ϕ holds at the end. We express thisfact with a new operator as 〈|α |〉 ϕ (read: strong diamond alpha phi). Like for boxes vs. diamondswhere all rules were the same except for program constructs which may not terminate, the rulesfor diamonds and strong diamonds are the same except for choose. The rules for choose aregiven in the appendix F on KIV rules.

To specify ASMs, KIV has a special type of ASM specifications. These have the form:

asm specification ASM#using < SPEC1 >, . . .< SPECn >variables < a list of variable definitions as usual>;input variables <a list of variables separated with comma>;state variables <a list of variables separated with comma>;initial state <some predicate on state and input variables>final state <some predicate on state and input variables>asm rule ASMRULE#

1In KIV parallel assignments are separated by commas.

Page 152: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 151

declaration<some procedure declarations without parameters>end asm specification

ASM# is the name of the ASM (a procedure name). <SPEC1> . . . , <SPECn> are the namesof specifications that define algebraic data types (the static functions used in the ASM). variablesdeclares new variables used in the ASM, typically those that represent dynamic functions andauxiliary variables as used in let or choose. state variables is the list of variables that representsthe dynamic functions. input variables represent static functions which have no specificationsand which may vary in initial states (such functions are specified as variables in KIV too, whichact as input to the algorithm). initial state and final state give a predicate over state and inputvariables, that describe (the dynamic part of) initial and final states.

ASMRULE# defines the name of the ASM rule (also a procedure name). From this name, thename of the ASM and the final predicate, KIV generates the following procedure declaration, thatdescribes the algorithm executed by the ASM (starting from initial states):

ASM#(<input variables>; var <state variables>) {while ¬ <final predicate> do ASMRULE#(. . . )}

Parameters of ASMRULE# are generated as necessary (see below). The content of an ASMrule is specified in the declaration section. This section is similar to procedure declarations wesaw earlier in the module exercise (recursive declarations are allowed). The only difference is thatwe neither need formal parameters for the declarations nor actual parameters in calls.

Since the idea of an ASM is to compute on the global state given by input and state variables,KIV can compute these parameters itself. In particular, the actual parameters of procedure callsare always the same as the formal parameters of the declaration, and the formal parameters ofthe procedure ASMRULE# are always a subset of input and state variables. KIV computes theminimal sets of reference parameters from the variables that are assigned in the declarations, andadds value parameters for those variables that are read, but not modified in a declaration (thecomputation must of course take recursive calls into account). After entering a specification andinstalling it, the command View specification will show the generated formal paramters as wellas the procedure definitions for the signature together with the procedure modes (these are alsogenerated automatically).

14.3 ASM Refinement

Refinement is a concept to prove that a “concrete” ASM CM = (CS,CI,CF,CRULE#) (consistingof concrete initial and final states CI, CF, and a concrete rule CRULE#) refines an “abstract”ASM AM = (AS,AI,AF,ARULE#). Typically more details are added to the concrete ASM andthe steps become more fine-grained and more deterministic (often towards a standard sequentialalgorithm).

ASM refinement is very general, since it is used for many purposes. An important exampleis compiler verification: The abstract ASM is an interpreter of source code: The initial statestores a program to execute (the input of the ASM) together with an initial execution state of theinterpreter (with e.g. a program counter pointing to the start of the program). The ASM rule doesa case analysis of the next step of the program to execute (pointed to by the program counter)and changes the execution state according to the next instruction. Many programming languageshave been specified as an ASM: Java, Prolog and C for example. The refinement replaces thesource code of the initial state with compiled code (byte code for Java or assembler code). Theinterpreter now is either JVM or a processor. Of course the compiled code should behave “thesame” as the source code. This has been verified formally in KIV for Prolog. The Java book[SSB01] contains a similar development (on paper) for Java. Having a formal specification of a

Page 153: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 152

processor, one can also refine pure sequential execution of assembler instructions, by introducingthe pipelining strategies of modern processors (this has been done for the DLX processor).

Other examples where ASM refinement is used are specifications of operating systems (an ab-stract specification of its basic operations is refined by implementations of the operations and ascheduling strategy), embedded systems (abstract requirements on the behaviour must be imple-mented by algorithms), communication and security protocols (which refine abstract specificationof communication transactions).

All these examples have in common that the abstract and the concrete level must behave “thesame”. If both levels use different data representations (similar to what we saw in the set-listmodule) then “the same” is too strict and must be weakened to “similarly”. The formal definitionof ASM refinement is given looking at the runs of the two ASMs:

An abstract ASM refines an concrete ASM iff for every concrete run there exists asimilar abstract run.

We say that the concrete run refines the abstract one in this case. Similarity of runs is definedbased on similarity relations on states:

A concrete run is similar to an abstract run if both start with a similar initial state.If the concrete run ends in a final state then the abstract must be finite too, and endin a similar final state. If the concrete run is infinite (which happens for the runs ofoperating systems, or when an interpreter executes some source code that contains aninfinite loop), then the abstract run should be infinite too and both runs should gothrough infinitely many similar intermediate states, indicating that during the runssimilar input and output happens.

����� ����� ����� ����� ����� ����� ����OR

��

��

��IR

�� �� �� ��⇑

�� �� ��

Figure 14.1: For every finite run from cs0 to csn there is a finite run from as0 to asm such thatIR(as0, cs0) and OR(asm, csn)

���� �����

IO ��

��

� ����� ���� �����

IO ��

��

� ����� ����� . . .

IO

��IR

�� �� ��

⇑�� �� �� . . .

Figure 14.2: For every infinite run starting with cs0 there is an infinite run from as0 such thatIR(as0, cs0) and infinitely often IO(asik , csjk)

Similarity between initial, intermediate and final states must be formally defined using relationsIR, IO and OR. Figure 14.1 shows two similar finite runs and Figure 14.2 two similar infinite runs.Solid lines indicate the concrete run that is assumed, dashed lines indicate what has to be shown.For the formal definition of refinement we write as and cs for typical abstract and concrete states.Thereby IR (and similarly IO and OR) becomes a formula IR(as, cs).

Definition 4 (Refinement Correctness) A refinement of AM to CM is correct with respect to(IR, IO,OR), if

• for every finite run (cs0, cs1, . . . , csn) of CM a finite run (as0, . . . asm) of AM exists, such thatIR(as0, cs0) and OR(asm, csn).

Page 154: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 153

• for every infinite run (cs0, cs1, . . .) of CM an infinite run (as0, as1, . . .) of AM exists, such thatIR(as0, cs0). There must also exist states (csi0 , csi1 , . . .) with 0 = i0 < i1 < . . . and (asj0 , asj1 , . . .)with 0 = j0 < j1 < . . . in the concrete and abstract trace, such that IO(csik , asjk) holds for ev-ery k.

Note that the definition of ASM refinement does not enforce that one rule application of theabstract machine corresponds to one rule application of the concrete machine. In general, several(say: m) rule applications of the abstract machine (that achieve a certain task) are refined byseveral (say: n) rule applications of the concrete machine (that achieve the same task), and wespeak of an “m:n diagram”. In compiler verification a common case is to compile one source codeinstruction to a sequence of n assembler instructions, resulting in a “1:n” diagram.

�� �� �� �� �� �� �� ��OR

�����

����

��

��IR

�� �� �� ���

�� �� ��

�� ����

INV���

����

���� ��

�����

����

�� �� ��

��

INV�� ����

�����

����

�� ��INV

�����

����

�� �� �� INV

��

����

INV

�����

����

��

���

INV

�� ���

���

���

�� ���

��

Figure 14.3: Decomposition of a full diagram (above) into subdiagrams (below) using a couplinginvariant

14.4 Proof obligations for ASM refinement in KIV

To prove refinement correctness a coupling invariant INV (also called a simulation) between ab-stract and concrete states is used. Commuting diagrams decompose the whole runs into subdia-grams, as shown in Figure 14.3. The basic assumption, underlying a modularization of this kind is,that the correspondence between two computation of the ASMs can be reduced to the correspon-dence of suitable “subcomputations” (i.e. finite sequences of rule applications), that both ASMsdo in the same order. Corresponding similar states are characterized by the coupling invariant.To prove this, it must be shown that INV can be propagated through runs by adding commutingdiagrams: For any two states related by INV it must be possible to add another commuting dia-gram which again establishes INV in the end, except if we have two final states already. Of courseinitial states must be related by INV, i.e. IR must imply INV to get this process started, and fortwo final states at the end INV must imply OR. In order to hold at least as often as IO does, INVmust imply IO.

Since ASM refinement pushes the coupling invariant forwards through traces, and since itgeneralizes forward simulations of other refinement definitions, the coupling invariants of ASMrefinement are also called generalized forward simulations.

ASM refinement diagrams may have any shape, (“m:n diagrams”, where m abstract transitionmatch n concrete transitions).

Even triangular shapes are allowed, but the case of an infinite consecutive sequence of 0:ndiagrams as shown in Fig. 14.4 must be prevented. Therefore some size #0n must decrease in everysuch triangle (a size function #0n that decreases over natural numbers is practically sufficient;a general wellfounded order could also be used). Otherwise a finite run (of zero steps) could berefined to an infinite run. Similarly, infinite sequences of m:0 diagrams as shown in Fig. 14.5 mustalso be ruled out using some size #m0.

Formally, we get the following proof obligations for a commuting diagram:(VC) ≡INV(ain, as, cin, cs), as = as0, cs = cs0,¬ (final(ain, as) ∧ final(cin, cs))

Page 155: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 154

��INV

�������

�����

����

INV

�� ����

����������� ��

����

. . .�����������

. . .

Figure 14.4: Infinite sequence of 0:n diagrams

����

INV����

������

������

� ����

�����

����

����

����

. . .����������� . . .

�� INV

������������

Figure 14.5: Infinite sequence of m:0 diagrams

(: m:0 diagram :)¬ final(ain, as) ∧ ∃ m. 〈loop if ¬ final(ain, as) then ARULE#(ain; as) times m+ 1〉

(INV(ain, as, cin, cs) ∧ #m0(ain, as, cin, cs) < #m0(ain, as0, cin, cs)),(:0:n diagram :)¬ final(cin, cs) ∧ ∃ n. 〈|loop if ¬ final(cin, cs) then CRULE#(cin; cs) times n+ 1|〉

(INV(ain, as, cin, cs) ∧ #0n(ain, as, cin, cs) < #0n(ain, as, cin, cs0)),(: m:n diagram :)

¬ final(cin, cs) ∧ ¬ final(ain, as)∧ ∃ n. 〈|loop if ¬ final(cin, cs) then CRULE#(cin; cs) times n+ 1|〉

∃ m. 〈loop if ¬ final(ain, as) then ARULE#(ain; as) times m+ 1〉 INV(ain, as, cin, cs)

The proof obligation contains calls of the ASM rules CRULE#(cin; cs) and ARULE#(cin; cs) ofthe concrete and abstract level. cin is the input and cs is the state modified by CRULE# (usuallythese variables are the same as the ones given by input and state variables). There is also anew construct which allows iterated execution of rules:

loop α times i

executes the body α i times, so it is kind of a simple for loop. Rules for symbolic execution ofloops, that should be self-explanatory are given in the appendix F on KIV rules.

Intuitively, the proof condition says: if states ain, as and cin, cs are related by INV, then wemust be able to prove one of four cases, corresponding to the four formulas in the succedent. Thefirst case is that both states are final, otherwise it must be possible to add a commuting diagram,such that INV holds at the end. The diagram may either be a m:0 diagram consisting of abstractsteps only. In this case the steps may be suitably chosen (the diamond around the loop indicatesthat it is sufficient to find some execution of abstract steps). In this case a size function #m0 mustdecrease. Note that the loop is executed a positive (m + 1) number of times. The diagram mayalso be a 0:n diagram consisting of concrete steps only. In this case every execution must lead toa commuting diagram, hence the strong diamond. The final formula in the succedent describesm:n diagrams.

Given the main verification condition of ASM refinement, and the other verification conditions,described informally above, we can show the main theorem of ASM refinement:

Theorem 2 (Generalized forward simulation) A refinement from AM to CM is correct forIR, IO,OR, provided the following proof obligations can be proved for some generalized forwardsimulation INV and suitable size functions #m0 and #0n:

• cinit(cin, cs) → ∃ ain, as.ainit(ain, as) ∧ IR(ain, as, cin, cs) (“initialize”)

• IR(ain, as, cin, cs) → INV(ain, as, cin, cs) (“establish invariant”)

Page 156: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 155

• verification condition (VC) holds (“keep invariant”)

• afinal(ain, as) ∧ cfinal(cin, cs) ∧ INV(ain, as, cin, cs) → OR(ain, as, cin, cs) (“finalize”)

The “initialize” condition guarantees that every initial state cin, cs (consisting of the inputcin to and the state cs modified by the concrete rule) has a corresponding initial state ain, aswith IR(ain, as, cin, cs). “establish invariant” guarantees that INV holds for them. The “finalize”condition establishes OR for final states.

14.5 Instantiating the general refinement theory

The general refinement theory, and a generic proof of the theorem above are contained in thespecification loopDLforward-is-DLforward (and subspecifications) which are imported from a li-brary (the library also contains a number of even more general refinement theorems, which areonly relevant for rules which have non-terminating cases).

The generic refinement theory talks about sorts cinput,cstate ,ainput, astate of concrete input,concrete state, abstract input and abstract state, corresponding variables cin, cs, ain, as and twoprocedures ARULE#(ain;as) and CRULE#(cin;cs). In the generic theory, these procedures haveno implementation, since the refinement theory must be correct for any rule.

When two concrete ASMs of a refinement are given, the variables cin, cs, ain, as (and theirsorts) must be instantiated by the tuples of variables which actually form the states used in therefinement. These are exactly the value and reference parameters of the procedures for the twoASM rules of the concrete and abstract level. The anonymous procedures of the refinement theorymust become the concrete ASM rules of the refinement given.

To do this instantiation, KIV offers a specification type of instantiated specifications. Thesespecifications are similar to the actualized specifications we saw earlier. They are more general inthree respects: first, in contrast to the morphisms we used earlier, the mappings of instantiatedspecifications allow to map a sort to a tuple of sorts2 and a variable to a suitable tuple of variables.This feature is essential to map an abstract ASM rule ARULE#(ain;as) to a real ASM rule whichtypically has many parameters. Second, instantiated specifications do not instantiate a parameter,that is inherited from a generic specificiation. Instead the paramter is given explicitly, and maybe any subspecification. Third, instantiated specifications do not require that the instantiatedparameter axioms must be present in the actual specification. Instead, these instantiated axiomsare now set up as proof obligations. In the case of ASM refinement, these instantiated axioms arejust the proof obligations for ASM refinement correctness of the theorem above, instantiated bysuitables tuples of arguments for ain, as, cin, cs.

The Syntax of instantiated specificiations is:

instantiate parameter PSPEC1, . . . PSPECn < GSPECwith ASPEC1, . . . , ASPECm by mapping: s → s1, . . . , sn;v → v1, . . . , vn;f → f1, . . . , fk;...

end instantiate

Note that a “:” is required in front of mappings for sorts. The specifications PSPEC1,. . . PSPECn must be proper subspecifications of GSPEC: no intermediate renamings or actu-alizations are allowed. They form the parameter, and their instantiated axioms become proofobligations. The section “parameter PSPEC1, . . . PSPECn <” may be left off. In this case theparameter specification is the full specification GSPEC.

2It is also possible to add a restriction and equality here, so instantiated specifications also generalize modules,but we do not consider this case here

Page 157: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 156

14.6 Verification of ASM refinement in KIV

Given a refinement, we usually have several differently shaped diagrams, depending on the currentabstract and concrete state. Typically the proof obligation then is proved by explicitly splittingthe different cases with the cut rule of sequent calculus. For a case, where a 0:n diagram has to beproved the formulas for m:n and m:0 diagrams are then immediately thrown away by weakening(and similar for the other two cases). Then if the diagram is for example a 2:0 diagram the ruleloop unwind right rule is applied twice and in between the ASM rule is symbolically executed.After that, the rule loop exit right is executed to finish the two executions. Note that it isnot necessary to instantiate the quantifiers in front of the loop explicitly (this is possible too, butrequires more effort and is not suported by heuristics which often can determine automatically,when the loop should be left), the two loop rules for unwinding and exiting the loop are alreadyapplicable with the quantifier present.

It should also be noted, that in an m:n diagram the m concrete rule applications often resultin case splits, while for the n abstract rule steps only one suitable branch of the rule needs tobe executed (often using suitable instances for the existential quantifiers that result from chooseoperations. If during the execution of an abstract rule the simplifier cannot decide a conditional,it is often wise not to blindly continue symbolic execution (i.e. not to use heuristics with casesplitting which will do that), but to carefully check, whether the condition of an if can be shown tobe provable using first-order reasoning. To do this, turn off the heuristics, use the rule conditionalright split, and weaken the program formula of the then (or else) branch, if you want to show thatthe conditional is always negative (positive).

Symbolically executing the loops finally leads to a pure first-order condition (without pro-grams) of approximately the form INV(cin, cs, ain, as) INV(cin, cs′, ain, as′) (some additional pre-conditions are usually present, and an additional postcondition about #0n or #m0), where cs′

and as′ are the states as changed by the rule applications. Usually, the predicate INV is alreadyunfolded using its definition.

14.7 Exercise 9

The exercise is inspired by the marking algorithm of Schorr and Waite. It is also inspired by thesystematic development of the algorithm in Abrial’s paper [Abr03], which develops the algorithmusing refinement of the specification language “Event B”, which is very similar to ASMs.

Given a graph and a starting node in it, the marking algorithm computes all reachables nodes.Marking algorithms are part of every modern programming languages like Java which supportsautomatic garbage collection of allocated objects.

Instead of proving a large monolithic algorithm, we develop it incrementally by means of aseries of progressively more and more refined “sketches” starting with the formal specification andending with the final program:

• The first ASM computes the solution in one step, using the transitive closure of the relationdefining the graph. The transitive closure operator is used.

• The second ASM uses an nondeterministic loop algorithm.

• The third ASM uses depth-first search and makes use of a backtracking structure to collectthe reachable nodes.

• The fourth ASM restricts the graph to be binary (every node has at most two successors).

• The fifth ASM stores the backtracking structure within the graph by pointer reversal, therebyintroducing the main idea of the Schorr-Waite algorithm.

In the exercise you will verify the first three refinements from ASM1 to ASM4 (the relationsIO, INV etc. will already be given). The three refinements are described in the following three

Page 158: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 157

no1 no2

no3 no4 no5

no6

no0no0 no1 no2

no6

no3 no4 no5

Figure 14.6: On the left side a graph g and on the right side its transitive closure c(g)

subsections. The last refinement from ASM4 to ASM5 are contained in the project and are alreadyproven completely.

14.7.1 Formal specification of ASM 1

In the first ASM, the marking algorithm is specified to compute the image of the starting nodeunder the transitive closure of the graph.

A graph g is defined as a set of edges e. An edge is a pair of nodes. Function c takes theargument g and returns the transitive closure of g. Figure 14.6 shows the edges of a graph g withsolid lines, that is formally represented as the set

g := ∅ ++ (no0×no3) ++ (no1×no3) ++ (no1×no5) ++ (no2×no5) ++ (no3×no4) ++ (no3×no6)

This set can be viewed as a binary relation on nodes. The dashed lines are edges added by thetransitive closure operator c, we have

c(g) := g ++ (no0 × no0) ++ (no0 × no1) ++ (no0 × no4) ++ (no0 × no5)++ (no0 × no6) ++ (no1 × no1) ++ (no1 × no4) ++ (no1 × no6)++ (no2 × no2) ++ (no3 × no1) ++ (no3 × no3) ++ (no3 × no5)++ (no4 × no3) ++ (no4 × no4) ++ (no4 × no5) ++ (no4 × no6)++ (no5 × no5) ++ (no6 × no6)

The specification closure-image in figure 14.7.1 defines the necessary axioms for the transitiveclosure of a binary relation and the image of nodes.

Given the transitive closure of g, the reachable nodes from t are the image of {t} under therelation c(g). In general the image of a set s under a relation g is written g[s] and defined by theaxiom image-def in specification closure-image.

In our example we define the node b as our starting node t. The result is

c(g)[t] := {no1, no3, no4, no5, no6}

Figure 14.7 shows the marking performed in one shot.An ASM computing c(g)[{t}] in one step is shown in specifiation 14.9. The ASM starts in an

initial state where final = false. It has one step MARK1# which computes the result in r andsets final = true to indicate that it has reached is final state after one step.

14.7.2 ASM 2 and the First Refinement

In this refinement, we introduce a new variable b (for “black”), which is a set of nodes, and twonew procedures called ASM2# and PRG1 2# (for progress a single step of ASM 2). The imageof the set {t} is now computed gradually. In the initialisation b is set to {t}. As long as there are

Page 159: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 158

t

Figure 14.7: Marking in one shot of ASM 1

closure-image =enrich graph, nodes with

functionsc : graph → graph;. [ . ] : graph × nodes → nodes;

axioms;; Properties of closure cclosure-subset: s ⊆ c(g)[s];closure-transitive: x × y ∈ g ∧ x ∈ c(g)[s] → y ∈ c(g)[s];closure-bounded: g[s] ⊆ s → c(g)[s] ⊆ s;

;; g[N]: Image of set (of nodes) under graph (binary relation) gimage-def: no2 ∈ g[s] ↔ (∃ no1. no1 ∈ s ∧ no1 × no2 ∈ g);

end enrich

Figure 14.8: Specification closure-image

some successor nodes reachable from within b (i.e. in the image g[b]), which are not already inb (i.e. g[b] �⊆ b), we can choose such a node y nondeterministically and add it to the set b. Afterseveral steps we have collected all nodes reachable from t, and reach a final state where g[b] ⊆ bholds (MARK 2#). Figure 14.11 shows the specification of ASM 2, figure 14.10 shows, how thealgorithm adds one black node in each step.

Because our second ASM needs several steps whereas ASM 1 only needs one step, we have0:1 diagrams for all steps of ASM2, except for the last (which forms a 1:1 diagram with the onlystep of ASM1). To avoid the problem of infinitely many 0:1 diagrams, we have to find a functionexpressing that the amount of (ASM 2) steps decreases while ASM1 is performing zero steps,similar to the termination function in the Hoare exercise. This has already been done and verifiedin specification CORR12 and is named #0n.

#0n → (λ g, t, final, r, g0, b, final0, r0. #(c(g0)[{t}] \ b));The parameter of the function are the abstract state consisting of g, t, f inal, r and the concrete

state consisting of g0, b, final0, r0 (the variables of the concrete state have been suitably renamedto be disjoint from the abstract state).

The function #(S) returns the cardinality of set S. While we are adding new nodes to b thenumber of elements in the set c(g0)[{t}] \ b is decreasing.

The next important part is the invariant between ASM 1 and ASM 2. The predicate has tobe true while ASM 1 and ASM 2 are performing steps. It can be found in specification INV12:

INV12-def :INV12(g, t, final, r, g0, b, final0, r0)

↔ g = g0

Page 160: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 159

ASM1 =asm specification ASM1

using closure-imagevariables final: bool;input variables g, t;state variables final, r;initial state final ↔ falsefinal state final ↔ trueasm rule MARK 1#declarationMARK 1# {

r := c(g)[{t}], final := true};

end asm specification

Figure 14.9: Specification of ASM1

1 2 3

4 5

Figure 14.10: A non-deterministic marking algorithm

∧ (final ↔ final0)∧ t ∈ b∧ (final ⊃ r = r0 ∧ r = c(g)[{t}] ; b ⊆ c(g)[{t}]);

The predicate states that

1. both ASMs reach their final states at the same time

2. at any time, the set of black nodes b is a subset of the transitive closure

3. in final states the result sets r and r0 have the same value, namely the value c(g)[{t}]) wewanted to compute. In non-final states the set b collects some part of this set.

Last but not least, we have to connect corresponding initial and final states of ASM 1 withstates of ASM 2. In the beginning, the set b is initialised with our starting node t, so b = {t}holds. In final states, the same result must have been computed, and both states must indeed befinal, as indicated by final and final0.

Page 161: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 160

ASM2 =asm specification ASM2

using closure-imagevariables final: bool;input variables g, t;state variables b, final, r;initial state b = {t} ∧ final ↔ falsefinal state final ↔ trueasm rule ASM2#declarationASM2# {

if g[b] ⊆ b thenMARK 2#

elsePRG1 2#

};PRG1 2# {

choose y with y ∈ g[b] \ b inb := b ∪ {y}

};MARK 2# {

r := b, final := true};

end asm specification

Figure 14.11: Specification of ASM2

IR → (λ g, t, final, r, g0, b, final0, r0. b = {t} ∧ g = g0 ∧ (final ↔ false) ∧ (final0 ↔ false));

OR → (λ g, t, final, r, g0, b, final0, r0. r = r0 ∧ (final ↔ true) ∧ (final0 ↔ true));

14.7.3 ASM 3 and the Second Refinement

The idea of the second refinement is to reduce the nondeterminism contained in the arbitrarychoice of the next node y that is added to b by a systematic procedure which does depth-firstsearch and backtracking. To do depth first search ASM3 shown in figure 14.13 needs a stack ofnodes, which is implemented by the list nl, that indicates the current search path. This list isinitialized to contain t alone. When searching forward (PROG1 3#) the first node is selected viathe ‘head’ operator hd(nl). We choose one successor node that has not been visited (i.e. is not inb) to push it onto the stack (add it as a first element to the list). The choice of a suitable successoris still done randomly. In this way the nodelist nl grows and always contains a path starting fromt into the graph, stored in reverse order (t is always the last element of the list, i.e. the bottomelement of the stack.). When all successors of hd(nl) have been visited, then backtracking startsby popping this node from the stack. This is done by PRG1 2#, which deletes the first element ofthe list by using the ‘rest’ operator tl(nl). Finally, if we get hd(nl) = t by backtracking again andall successors of t are already marked, then we have finished the search and the result is stored inb. This last step again corresponds to the last step of the previous algorithm (1:1 diagram). Stepssearching forward correspond 1:1 to steps of the previous algorithm. They just choose a morespecific node to add to the set b. Backtracking steps have no correspondent abstract steps, theyjust organize the search (0:1 diagram). Obviously the number of possible successive backtrackingsteps is bounded by the length of nl, therefore we have:

Page 162: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 161

������������

������������

����������

����������

����������

����������

1 2 3

����������

����������

���������������

���������������

����������

����������

4 5 6

������������

������������

����������

����������

������������

������������

7 8 9

Figure 14.12: A depth-first marking with backtracking structure. The patterned node is hd(nl)of the backtracking structure

#0n → (λ g, b, final, r, g0, t, b0, final0, nl, r0. # nl);

The relations for similar initial and final states should be obvious:

IR → (λ g, b, final, r, g0, t, b0, final0, nl, r0. b = {t} ∧ nl = t’ ∧ b = b0 ∧ g = g0 ∧ (final ↔false) ∧ (final0 ↔ false));

OR → (λ g, b, final, r, g0, t, b0, final0, nl, r0. r = r0 ∧ (final ↔ true) ∧ (final0 ↔ true));

The main difficulty to verify the refinement is to find a suitable coupling invariant. We have:

INV23-def :INV23(g, b, final, r, g0, t, b0, final0, nl, r0)

↔ g = g0∧ (final ↔ final0)∧ nl ⊆ b0 ∧ b = b0∧ g[b0 \ nl] ⊆ b0∧ nl �= [] ∧ last(nl) = t ∧ ¬ dups(nl)∧ (final → r = r0);

The invariant states:

1. Both algorithms reach final states at the same time

2. The backtracking stack contains visited nodes, and these visited nodes are the same for bothalgorithms

3. for all visited nodes, which are not in the current backtracking stack, all successors havebeen visited (these nodes are the old nodes, which have been completely searched)

4. The backtrack stack is never empty, has no duplicates and its last element is always t

Page 163: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 162

ASM3 =asm specification ASM3

using bingraph-closure-image, revpathp-subsetvariables final: bool;input variables g, t;state variables b, final, nl, r;initial state b = {t} ∧ nl = t ’ ∧ final ↔ falsefinal state final ↔ trueasm rule ASM3#declarationASM3# {

if g[{hd(nl)}] ⊆ b thenif hd(nl) = t then

MARK 3#else

PRG2 3#else

PRG1 3#};PRG1 3# {

choose y with y ∈ g[{hd(nl)}] \ b inb := b ∪ {y}, nl := y + nl

};PRG2 3# {

nl := tl(nl)};MARK 3# {

r := b, final := true};

end asm specification

Figure 14.13: Specification of ASM3

5. For final states the same result has been computed.

Fig. 14.12 shows step by step how the algorithm works.

14.7.4 ASM 4 and the Third Refinement

ASM4 restricts the graphs considered to binary graphs, where each node has at most two succes-sors. Since it is possible that only one of the successor nodes exists, a function selecting one of thesuccessors can only be partially defined. Such functions are typically specified using hashtables.One hashtable represents the left successor nodes of all nodes in the graph, a second hashtablerepresents all right successor nodes of all nodes in the graph. If the node n can be found as a keyin the first hashtable, it has a left successor and using n as the selection key for this hashtablegives as a result the left successor node. One initial assumption for the refinement therefore is,that the graph g stored in the initial state of ASM3 is equal to the data structure represented bythe hashtables of ASM4. With a binary graph we can replace the nondeterministic computationof successors by first visiting the left, and then the right successor. The hashtables are specifiedusing the generic data type of a store from the library. Stores map a finite set of keys to values.

Formally, stores are a nonfree data type generated by the empty store and an update functionst[k, d] which stores data value d under key k. The operation allocates key k if necessary. If k wasalready allocated, the old entry is overwritten. To check, whether a key is allocated k ∈ st must be

Page 164: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 163

tested. To access the data value stored under an allocated under key k, use st[k]. For simplicity, itis assumed that accessing st[k] for a key, that is not allocated, gives an arbitrary, but fixed dummyvalue, that is always the same. The extensionality axiom for stores therefore is:

st1 = st2 ↔ ∀ a.(a ∈ st1 ↔ a ∈ st2) ∧ st1[a] = st2[a]

Stores also come with several auxiliary functions (which we will not need): the number ofallocated keys is counted with #st, (k, d) ∈ st checks if the pair (k, d) is in the store. Finallyst−−k deallocates key k, and st1 ⊆ st2 if every key k, that is allocated in st1 is allocated in st2with the same data value.

ASM4 is given in Fig. 14.14. If the left successor is present and has not yet been visited, it isvisited first. If it is not present or has already been processed, the right succcessor is visited.. Tocheck whether a node n, does not have an unvisited (i.e. not in b) left successor is now

n ∈ st → lt[n] ∈ b

If a left resp. right successor exists, the deterministic code of PRG114 resp. PRG124 is executed,which corresponds to the nondeterministic code of PRG13.

To verify the refinement, we need to formalize the assumption, that the graph g is representedby the hashtable data-structure. This is done with the formula g = lt ∪ rt using the union opera-tion defined in specification bingraph. Apart from the equality g = lt ∪ rt, the simulation relaton(as well as IR,OR, IO) are identity:

INV34(g, t, b, final, nl, lt, rt, t0, b0, final0, nl0)↔ g = lt ∪ rt ∧ t = t0 ∧ b = b0 ∧ (final ↔ final0) ∧ nl = nl0 ∧ (final → r = r0)

As this refinement only removes nondeterminism and leaves the execution paths otherwiseuntouched, all diagrams are 1:1 diagrams.

14.7.5 ASM 5 and the Fourth Refinement

ASM 5 introduces pointer reversal as used by the final algorithm. Instead of keeping an explicitstack nl it stores the stack by reversing the corresponding pointers in lt and rt. To distinguishthe modified graph from the original, lt and rt renamed to ult and urt (“updated left and right”).The algorithm starts with ult = lt and urt = rt. For intermediate states the values of ult and urthave pointers reversed, but in final states we prove that ult = lt and urt = rt holds again, so thealgorithm changes the graph only temproarily.

The stack nl = [no1, . . . , non] of ASM4 is a path, stored in reverse order: each noi, noi+1 (i < n)is a pointer in the original graph (either lt[noi = noi+1] or rt[noi = noi+1]). In a corresponding stateof ASM5, these pointers are reversed in ult and urt: for i > 0 noi points to its father noi−1 (theroot is unchanged). Additionally no1 and no2 are always stored in p and q. Reversing pointersmeans that backtracking becomes easier: Instead of managing a separate list nl backtracking cannow be done by floowing a reversed pointer: p becomes q and q becomes the pointer to which qpoints in ult or urt. To decide which of two must be used, two auxiliary sets of nodes lft and rhtof nodes are used. They still store the elements of nl (except the root node): lft stores those noi+1

where noi, noi+1 is in lt, rht stores all others. Together, lft and rht together are the same nodes asthose of nl of ASM4, except that the root node is not stored (in another refinement, the two setswould be replaced by using marks on the nodes, that say whether they were reached from the leftor the right).

The new algorithm is shown in Fig. 14.15. The critical properties for verification are

ptrrev(ult, nl, lft) = lt ∧ ptrrev(urt, nl, rht) = rt∧ isptrrev(tl(nl), lft, ult) ∧ isptrrev(tl(nl), rht, urt) ∧ disjoint∪(lft, rht, nl)

ptrrev, isptrrev and disjoint∪are specified in specification ptr − rev: ptrrev(ult, nl, lft) = lt means:when those pointers in nl which are also in lt are reversed in ult the result is lt. isptrrev(tl(nl), lft, ult)means: all pointers in ult that are also in tl(nl) point in the reverse direction of the stack nl. Finally,disjoint∪(lft, rht, nl) expresses that the disjoint union of lft and rht is nl.

The refinement is unfortunately too complex to be verified in this exercise, but you can havea look at the already complete proofs.

Page 165: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 164

ASM4 =asm specification ASM4

using revpathp-subset, bingraph-closure-imagevariables final: bool;input variables lt, rt, t;state variables b, final, nl, r;initial state b = {t} ∧ nl = t ’ ∧ final ↔ falsefinal state final ↔ trueasm rule ASM4#declarationASM4# {

if hd(nl) ∈ lt → lt[hd(nl)] ∈ b thenif hd(nl) ∈ rt → rt[hd(nl)] ∈ b then

if hd(nl) = t thenMARK 4#

elsePRG2 4#

elsePRG12 4#

elsePRG11 4#

};PRG11 4# {

b := b ++ lt[hd(nl)], nl := lt[hd(nl)] + nl};PRG12 4# {

b := b ++ rt[hd(nl)], nl := rt[hd(nl)] + nl};PRG2 4# {

nl := tl(nl)};MARK 4# {

r := b, final := true};

end asm specification

Figure 14.14: Specification of ASM4

Page 166: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 14. ABSTRACT STATE MACHINES AND ASM REFINEMENT 165

ASM5 =asm specification ASM5

using revpathp-subset, store-node-nodevariables

final: bool;ult, urt: store-node-node;lft, rht: nodes;p, q: node;

input variables ult, urt, t;state variables b, final, lft, r, rht, ult, urt, p, q;initial state b = {t} ∧ lft = ∅ ∧ rht = ∅ ∧ p = t ∧ final ↔ falsefinal state final ↔ trueasm rule ASM5#declarationASM5# {

if p ∈ ult → ult[p] ∈ b thenif p ∈ urt → urt[p] ∈ b then

if p = t thenMARK 5#

elseif q ∈ lft then

PRG21 5#else

PRG22 5#else

PRG12 5#else

PRG11 5#};PRG11 5# {

b := b ++ ult[p], p := ult[p], q := p, lft := lft ++ p, ult := ult[p, q]};PRG12 5# {

b := b ++ urt[p], p := urt[p], q := p, rht := rht ++ p, urt := urt[p, q]};PRG21 5# {

lft := lft – q, ult := ult[q, p], p := q, q := ult[q]};PRG22 5# {

rht := rht – q, urt := urt[q, p], p := q, q := urt[q]};MARK 5# {

r := b, final := true};

end asm specification

Figure 14.15: Specification of ASM5

Page 167: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 15

Java Verification in KIV

Warning: You should be familiar with (the problems of) Java verification before trying thisexercise.

15.1 Introduction

15.1.1 A very small tutorial

1. Start the KIV system

2. Select Projects - Select

3. Select normal and click Okay

4. Select Exercise 9 and click Okay. You should get a project with a lot of orange specifications(these are libraries) and two blue ovals.

5. Left-click on the blue oval named ArrayMax, select Work on ... from the popup menu andclick Okay.

This specification contains a Java class ArrayMax with two implementations to compute the max-imum of an array of integers, one using a while loop, one with a for loop.

package swt;

public class ArrayMax {

public static int maxWhile(int[] a) {

if ( a.length == 0 ) return 0;

int max = a[0], i = 1;

while ( i < a.length ) {

if ( a[i] > max ) max = a[i];

++i;

}

return max;

}

public static int maxFor(int[] a) {

if ( a.length == 0 ) return 0;

int max = a[0];

for(int i = 1; i < a.length; i++ ) {

if ( a[i] > max ) max = a[i];

166

Page 168: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 167

}

return max;

}

}

You can see the code by right-clicking on the entry ArrayMax-class and left-clicking on View inthe context menu. The actual code was loaded from the file in

java/Exercise9/specs/ArrayMax/swt/ArrayMax.java

The specification contains two theorems, one for the maxWhile method that is already proven,and an unproved one for maxFor. The theorem named arrayMaxWhile states that the methodindeed computes the maximum of an array and looks like this:

st[ mode] = noval, okarray(a, int type, st), init(st) 〈st; private (int i, int[] a)

i = swt.ArrayMax.maxWhile(a); 〉 i = max(getintarray(a, st))

The first line contains some preconditions (see below for more background information). st[ mode] =noval means that the current execution mode is normal, i.e. no exception has occurred.okarray(a, int type, st) says that the reference a points to an integer array. init(st) means thatall classes have been initialized successfully.

The second and third line contain a Dynamic Logic formula. The second line declares thevariables for the following line (after the private keyword). The third line contains Java: amethod call to maxWhile with argument a. Finally, the postcondition i = max(getintarray(a, st))states that i is the maximum of the array a. Both operations, max and getintarray are part ofKIV’s library. getintarray maps the pointer structure representing the integer array into analgebraic data structure, and max specifies their maximum. Using algebraic operations makes thetheorem much more readable than specifying the maximum with quantifiers and indices.

Now you can re-prove the theorem arrayMaxWhile:

1. Right-click on arrayMaxWhile and select New Proof from the context menu. You will getthree windows, the big main window with the current proof goal, the already existing prooftree, and a window the new proof that contains only two nodes.

2. Double left-click on jcall in the left list of the main window. This will expand the methodcall and then the heuristics will continue until the while loop is reached.

3. Double left-click on jwhile-invariant in the left list of the main window. This selects theinvariant proof rule for while loops (including termination). The actual invariant is storedin a file named java/Exercise9/specs/ArrayMax/formulas.

4. Select arrayMaxWhile-inv in the popup menu and click Okay. That’s it.

The invariant is

0 < i1 ∧ i1 ≤ st[a0 – length] .intval∧ st[ mode] = noval ∧ a0 �= jvmref ∧ okarray(a0, int type, st) ∧ init(st) ∧ a = a0∧ int max0 = max(getintarray(a0, 0, i1, st))

with termination order

i→n(st[a0 – length] .intval - i1)

The main line is int max0 = max(getintarray(a0, 0, i1, st)) which states that int max0 is themaximum of the subarray denoted by getintarray(a0, 0, i1, st). Unfortunately the KIV systemoften renames variables so you have to look at the actual proof goal to see how it all fits together.The termination order is a.length− i (with some renaming) mapped to the natural numbers withi → n to have a wellfounded order.

Now you can prove the second theorem. Guess what the invariant is ...

Page 169: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 168

15.1.2 Overview over Java projects

To get an overview about Java proofs in KIV you should have a look at the following projects andspecifications that contain already many proofs:

• In project java the specification jlsprogs contains simple tests of different features of theJava language. You can find the Java source code in the directory

kiv/projects/java/java/specs/jlsprogs/javafiles

• In project java the specification loopexamples contains simple while loops and their in-variants. The source files can be found in

kiv/projects/java/java/specs/loopexamples/javafiles

• Project javacard contains Java Card examples. The specification javacarddefs containselementary definitions from the Java Card API (e.g. Util.arrayCopy), the source is in

kiv/projects/java/javacard/specs/javacarddefs/src

The specifications decimalImpl, Unsigned, shorttests, and decimal2Impl have somefun with short arithmetic.

The other specifications contain many programs but no proofs.

• Project java-context contains in specification Autoboxing and Generics examples forsome of these Java language features, and Collection, POArrayList and POLinkedListthe list interface and two implementations.

15.1.3 The exercise

In this exercise we will do a partial correctness proof for a Java program.The first subsection will give the necessary information to enable us doing a simple proof for

a Java program. In the second subsection, we will introduce the invariant rule for while loops inJava, which is slightly different from the rule in DL. Additionally we will introduce some detailsabout pointer structures in Java.

We will not give the theoretical foundations like semantics, nor will we give a precise definitionof the calculus. These can be found in [?]), our exercise merely intends to give an impression whatadditional complexity one has to face if one wants to verify Java programs.

15.2 Java Programs

Basically the calculus for Java programs is based on the same principles than the one for theabstract programs, we used until now. But Java programs have several additional properties thatmake verification (and the rules that have to be used) a lot more complex. We will not give thedetails here (they can be found in [Ste01]), for our exercise some rough idea of what the problemsare should be sufficient. In the following we list the main problems and how they are dealt within the KIV calculus:

15.2.1 The State of a Java Program

In our abstract programs, the state of a program just consisted of the values of ordinary first-ordervariables. In Java we have to manage a graph of interconnected objects (where the fields of objectscontain pointers to other objects). Therefore, we need a state st, which stores those values. Wedefine an algebraic datatype which describes the state of the memory of Java (the “store”) andtwo functions to access and update a store.

Page 170: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 169

functions

(: access function :)

. [ . ] : store x refkey -> javavalue;

(: update function :)

. [ . , . ] : store x refkey x javavalue -> store;

variables

st : store;

References in Java can be either to a field o.fieldname or to an element of an array a[i]. Thetype refkey (reference keys) is used in KIV to describe them. A reference key consists of anobject or array reference (type reference describes the address of o or the base address of a) anda storekey, which is either a field description (type fieldspec uniquely identifies a field by itsclass, static type, and name), or an index into an array. Formally, reference keys are specified as:

fieldspec = mkfs(. .class:classname ; . .type:javatype ; . .field:fieldname)

storekey = . ’ (. .fs : fieldspec) with is_fskey

| . ’ (. .index : int) with is_indexkey

refkey = . -- . (. .ref : reference; . .key : storekey) prio 9 left;

As an abbreviation for mkfs(class,ty,fieldname) we can write simply .fieldname in KIV. Inorder to access a field fs of object o in a store st, we write st[ o -- fs ’]. For accessingelement i of array a, we write st[ a -- i ’]. The result is not a value of an arbitrary datatype(as in our abstract programs), but a value that can be stored in Java. Such values are integers,references (to arrays or objects), and some others, like bytes, shorts etc. which we will not needin our exercise. The type javavalue is defined:

javavalue = intval (. .intval : int) with is_integervalue

| refval (. .refval : reference) with is_referencevalue

| noval with is_novalue

| ....

noval is the undefined value. We can also update the store at some location with an updatefunction: e.g. the effect of updating an array a at index i with an integer j (the effect of anassignment a[i] := j on the store) would result in the store st[ a -- i ’, intval(j)].

15.2.2 Exceptions and Jumps

Java has exception handling: if an exception occurs, normal execution is stopped and a handlerfor the exception is searched. When one is found, computation continues with the handling clause(otherwise the program is stopped with an error message).

We model the search for an exception as a special execution mode of the program which skips allstatements until an appropriate exception handler is found. Otherwise we are in normal executionmode.

Information about the current execution mode is stored using a special reference key mode

(note the underscore). A value of noval is interpreted as normal execution mode. This meansthat

st[ mode] = noval

says, that we are currently executing a program regularly.Jumps caused by break, continue and return are handled by special values of the mode

too. They skip execution of statements, until the end of the loop or method (that must be left) isreached.

Page 171: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 170

15.2.3 Loading Java Programs into KIV

KIV is able to read files containing Java programs directly. (This has been done already in theexercise below.) To add the code of such files to a specification MySpec, add a file named javafiles

to the directory of MySpec, which contains one or more lines similar to the following:

java file: myclasses = specs/MySpec/src/myPackage/SomeCode.java

The path is relative to the project directory, i.e. in this case the directory of MySpec shouldcontain the subdirectory src with src/myPackage/SomeCode.java. You can now work on MySpec

and select File - Load Java File. This will add an axiom named myclasses to the specificationwhich makes the method definitions, class structure etc. as given in SomeCode.java. It is stronglyrecommended to let KIV read only Java Code, that has been successfully compiled. Although KIVwill check the code to be compilable.

Finally it should be noted that there are restrictions on what code KIV can read: The codecan only be of the JavaCard language, so it cannot contain threads, and strings are not reallysupported. It is also unavoidable, that all libraries used must be explicitly included (by addingcorresponding lines in javafiles), since the semantics of a program using a library depends onit.

15.2.4 The Type System of Java

Another difference between the abstract programs and the Java programs is that they have verydifferent type systems. While the abstract programs use the simple type system of many-sortedlogic, Java has a complex type system involving inheritance and dynamic binding. Therefore wemust specify types and the fact, that a javavalue has a certain type explicitly. This is done bygiving a datatype

javatype =

boolean_type | int_type | short_type | byte_type

| long_type | float_type | double_type | char_type

| mkclasstype(. .class : classname) with is_classtype

| mkarraytype(. .type : javatype) with is_arraytype

| void_type with is_void_type

predicates . ≤ . : javatype × javatype;≤ defines subtyping (based on subclassing). A lot more predicates are provided by the library

specifications.

15.3 The rule for while loops in Java

Lets remember the invariant rule for while loops in DL programs:

Γ Inv,Δ Inv, ε [α]Inv,Δ Inv,¬ ε ϕ,ΔΓ [while ε do α]ϕ,Δ

For Java Programs, such a rule must look different. First of all, in a Java Program, the test forthe loop can be any Java expression with boolean return value itself, e.g. while(!s.equals(x)

&& z != w){...}. In DL programs, the test is a formula, so we can add this formula to theantecedent or to the succedent in our sequents. Java programs cannot be part of a formula outsidea box or a diamond, so we cannot extract ε out of the boxes here.

The solution is to introduce a new Java variable x (which is in contrast also a logical variablein KIV) of boolean type and assign the result value of the test expression ε to this variable. Thenwe can use the variable x outside the boxes.

Page 172: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 171

Another difference is the following: In DL programs, a loop is exited only when the loop test isfalse. In Java, we additionally have exceptions and the occurence of an uncaught exception insidethe loop will also exit the loop. So, here the loop rule must consider both of these possibilities.

Together we have the rule (where ψ is the invariant):

Γ ψ, Δψ [st; x = ε] [st; if (x) { α }] ( (x ∧ st[ mode] = noval → ψ)

∧ (¬ (x ∧ st[ mode] = noval) → ϕ))Γ [ st; while ε { α } ] ϕ,Δ

In the first premise, we show that our invariant is valid at the beginning of the loop, exactlylike in DL. The second premise now handles the two other cases of the DL invariant rule. Letstake a closer look at this premise:

The variable st in the boxes defines the store, in whose context the program after the semicolonis executed. First of all, we do the assignment of the test expression ε to a new variable x. If thisassignment terminates, one execution of the loop body is done by the if-then-else statement. Thetruth value of x decides, whether the loop body is entered or not.

If we execute the body (denoted by x in the premise of the first implication after the boxes),and additionally our loop exits without any exception (st[ mode] = noval), the invariant ψ musthold again. That means, if the invariant was true before any execution of the loop, it will be trueafterwards. Otherwise, if we did not enter the loop or if an exception occured (Note: the exceptioncould have occured either in the test ε or in the loop body α), then the postcondition ϕ of thewhole loop must be true.

15.4 Pointer structures in Java

Since Java is an object oriented programming language, the store contains pointer structures. Forthe exercise we will need a specification of valid and acyclic pointer structures. This is providedby the predicates:

predicatesvalidrefnotnull : string × reference × type × store;cyclic : string × reference × store;

Both predicates are parametrized with a string that is the current specification name. Thisis necessary since it is possible to define new Java classes in specifications above the current one.Because of that references can be valid on higher levels (where the class declaration exists) andbe invalid on lower specification levels (where the class does not exist).

validrefnotnull(str, r, ty, st) checks that a reference value and its fields have the cor-rect type and values and the same holds transitively for the values of the fields. It includes e.g.checks for the following properties:

1. r �= null

2. The reference r is contained in the store.

3. The type field of the reference r is present and contains a type value.

4. Fields of r of reference type ty contain a reference value that is of type ty or a subclass typeor null.

5. Fields of r of primitive type contain a compatible primitive value.

cyclic(str, r, st) checks whether a pointer structure beginning at r contains a cycle. Thisis done by checking whether a list of valid references exists that is reachable from r (when followingthe values of the fields) which contains duplicates.

Page 173: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 172

If we have an acyclic pointer structure and an operation that iterates over this structue, wecan make induction over the maximum length of a valid path of references that is reachable froma certain reference. To compute the maximum path length there exists the function:

functionsmaxpath : string × reference × store → nat;

As an example, consider linked lists:

public class LinkedList {

public LinkedList next;

public int value;

private LinkedList(int value, LinkedList next){

this.value = value;

this.next = next;}

public boolean contains(int value ){

return this.value == value || (next != null && next.contains(value));}

public boolean isOrdered(){

if(next == null) return true;

return this.value <= next.value && next.isOrdered();}

...

}

The operation contains checks whether a given integer value is contained in the linked list. Sincecontains is recursive we have to use induction when proving something about it. For example, whenproving a property like Γ 〈st/boolvar = r.contains(i);〉 ϕ; we use induction formaxpath(specname,r, st).

15.5 Exercise 9

Exercise 9.3 Give a proof sketch (on paper), why the invariant rule for while-loops would notbe correct, if we would replace the boxes by diamonds.

Exercise 9.4 Linked ListsGiven is the implementation of linked lists in Java as descibed above.Work on the specification LinkedList in Project java-exercise. This specification contains the

source code of the linked lists and a function that transforms the a linked list pointer structure ina store into an algebraic list of integers:

Page 174: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 15. JAVA VERIFICATION IN KIV 173

LinkedList =enrich contains with

functions getList : store × reference → intlist ;

axioms

getList-null : getList(st, jvmref) = [];

getList-rec :r �= jvmref∧ ¬ cyclic(“LinkedList”, r, st)∧ validref(“LinkedList”, r, LinkedList, st)

→ getList(st, r) = st[r – .value].intval + getList(st, st[r – .next].refval);

getList-cyclic :r �= jvmref∧ ( cyclic(“LinkedList”, r, st)∨ ¬ validref(“LinkedList”, r, LinkedList, st))

→ getList(st, r) = [];

end enrich

A reference with a null value corresponds to the empty list (getList-null). A non-null referenceof type LinkedList corresponds to its integer value concatenated to the list represented by its nextpointer (getList-rec). Since for cyclic lists our function would be inconsistent (think about thereason !), we have to add the axiom getList-cyclic which returns the empty list for cyclic or invalidpointer structures.

Now prove the two unproved theorems about contains and isOrdered :

contains-ok:init(st),st[ mode] = noval,validrefnotnull(“LinkedList”, r, LinkedList, st),¬ cyclic(“LinkedList”, r, st) 〈st/boolvar = r.contains(i);〉 (boolvar ↔ i ∈ getList(st, r))

isordered-ordered:init(st),st[ mode] = noval,validrefnotnull(“LinkedList”, r, LinkedList, st),¬ cyclic(“LinkedList”, r, st) 〈st/boolvar = r.isOrdered();〉 (boolvar ↔ ordered≤(getList(st, r)))

contains-ok states that the contains method finds every value in the linked list. isordered-ordered states that the isOrdered method returns true if and only if the values in the linked listare sorted according to ≤.

Hint: Both proofs have to be done with induction for the length of maxpath(‘LinkedList’,r,st).You will need an additional theorem for each proof that provides a useful invariant for the store forboth methods. Furthermore the specification LinkedList already contains some proven theoremswhich are either useful simplifier rules for this exercise or should be used via insert lemma duringyour proofs.

Page 175: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 8

Verification of Parallel Programs

The goal of this chapter is to learn how to verify temporal properties of simple parallel programswith KIV. Temporal logic is defined and a simple programming language for parallel programsis introduced. Furthermore, the basics of the KIV proof method to verify temporal properties ofparallel programs are epxlained.

8.1 Introduction

Example Consider the following program semaphore which contains two processes running inparallel.

semaphore ≡while true doawait S > 0; S := S − 1;(: critical section :)

L1: skip;S := S + 1;(: noncritical section :)

skip;

while true doawait S > 0; S := S − 1;(: critical section :)

L2: skip;S := S + 1;(: noncritical section :)

skip;

The two processes consist of while loops which never terminate. The processes make use of aso called semaphore S to synchronise the execution of a critical program fragment. The criticalfragment is here abstracted to a no operation statement skip which is labelled L1 for the firstprocess and L2 for the second. Before entering the critical section, the processes wait for thesemaphore S to be greater than 0. If this is the case, the semaphore is immediately decremented toprevent the other process from also entering its critical section. After the execution of the criticalstatements, semaphore S is restored to its original value 1.

As a requirement, the two processes must never execute their critical program fragments at thesame time.

The requirements we consider here are formalised in temporal logic which can be used to restrictthe behaviour of a program during execution. In contrast to Hoare Logic, we need to consider notonly the initial and final states of program execution, but all of the intermediate states as well.

Parallel processes communicate with each other using shared variables. It is also possible forthe processes to communicate with an abstract environment. In this case, the parallel programdefines a reactive system which reacts on input from the outside world.

A temporal proof obligation in KIV most often is of the following form

[: . . . α] ,� ψ, ϕPL χ

where α is the parallel program to examine, ψ is a so called environment assumption and ϕPL

describes the precondition. Formula χ is the temporal formula to verify.

174

Page 176: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 175

Example The following temporal proof obligation for program semaphore gives an impressionof the task which is to solve within this chapter.

(: parallel program :)

[: . . . semaphore] ,(: environment assumption :)

� (S′′ = S′ ∧ L′′1 = L′1 ∧ L′′2 = L′2)(: initial values :)

S = 1,¬ L1,¬ L2

(: property to prove :)

� ¬ (L1 ∧ L2)

If the parallel program semaphore is executed in an environment that never modifies neithersemaphore S nor labels Li, then the property � ¬ (L1 ∧ L2) (read “always during execution notboth labels L1 and L2 are satisfied at the same time”) holds. Initially, semaphore S is 1 and bothlabels are false.

The semantics of temporal formulas and the simple programming language for parallel pro-grams are explained in Section 8.2. An introduction to the KIV proof method is given in Sec-tion 8.3. It is your task to verify the property above in Section 8.5

8.2 Semantics

8.2.1 Traces

In predicate logic, a so called state z maps variables to values. The value of a variable x in statez is z(x). In temporal logic, (linear) sequences of states (z0, z1, z2, z3, . . . ) are considered.

z0 z1 z3z2

A sequence of states represents all of the intermediate variable assignments of a program execution.The sequences can be finite or infinite, in the case of a nonterminating program. In the following,we will also refer to sequences of state as traces. We write down traces as (z0, . . . , zn) with variablen ∈ N ∪ {∞}: the length n of the trace is either finite (∈ N) or infinite (=∞).

Example Programwhile true do N := N + 1

never terminates and increments variable N in each step. If the program is executed, differentsequences of states result depending on the initial value of N . If N is initially 5, then the followingsequence is generated.

z0 z1 z2 z3 . . .

N 5 6 7 8

8.2.2 Static and dynamic variables

In KIV, we distinguish between static and dynamic variables. Static variables can be compared toconstants and dynamic variables to program variables of a programming language. Throughoutthe execution of a program, static variables do not change their initial value, whereas dynamicvariables usually have different values at different times of an execution. Dynamic variables arealso called flexible. Variables in KIV are static by default. In order to define a dynamic variable,a keyword flexible is used in the variable slot of a specification.

Example Statementvariables N,N1, N2 : nat flexible;

Page 177: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 176

defines N , N1, and N2 to be dynamic variables of type nat.

As a convention, names of dynamic variables always start with an uppercase letter, while staticvariables are denoted by names starting with a lowercase letter.

8.2.3 Primed and double primed variables

A primed variable X ′ can be used to refer to the value of a variable X after a transition. Thisnotation is useful to formalise properties of a program transition. A formula in predicate logic,which refers to unprimed and primed dynamic variables X and X ′ defines a program transition.The unprimed variables X are interpreted as program input, the primed variables X ′ as output.

Example Formula N ′ > N states that the program transition modifies N such that the outputvalue N ′ is strictly larger than the input value of N .

Reactive systems communicate with an environment (cf, e.g., [?]). In order to model thebehaviour of the environment, double primed variables X ′′ are used. A formula in predicate logic,which refers to primed and double primed dynamic variables X ′ and X ′′ defines an environmenttransition. The primed variablesX ′ are interpreted as input for the enviroment, the double primedvariables X ′′ as output.

Example Formula N ′′ = N ′ states that the environment does not change the value of N .

Program and environment transitions alternate. A state transition between states zi and zi+1

starts with a program transition which is followed by an environment transition. This can bedepicted as follows.

= environment transition

= program transition

= state transition

X X ′ X ′′

X X ′′X ′′X ′X

X ′

z0 z1 z2

In state z0, the program transition takes the initial, unprimed value of X as input and returnsvalue X ′ which is the input to the environment transition. The environment returns the doubleprimed value X ′′. Important: The double primed value X ′′ is equal to the unprimed value X inthe next state z1. In other words: the output of the environment X ′′ in state z0 is the input Xto the program in state z1.

8.2.4 Semantics of temporal operators

Temporal logic (cf, e.g., [?]) is an extension of standard first order logic. It is based on expressionse which are variable or function symbols. Interpretation of static variables and unprimed variablesis done by evaluating the state function z0 of an interval I = (z0, z1, . . . ). Evaluation of primedand double primed variables can be done by evaluating z′0 and z1 respectively. Function symbols fare recursively interpreted on an Algebra A as fA((e1)I , . . . , (en)I) in the standard way. Similarlya predicate formula p is interpreted as pA((e1)I , . . . , (en)I). All other predicate logic formulas areinterpreted as usual.

Page 178: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 177

(z0, . . . , zn) |= � ϕ iff (zi, . . . , zn) |= ϕ forall 0 ≤ i ≤ n(z0, . . . , zn) |= � ϕ iff there exists 0 ≤ i ≤ n with (zi, . . . , zn) |= ϕ

(z0, . . . , zn) |= ϕ until ψ iff there exists 0 ≤ i ≤ nwith (zi, . . . , zn) |= ψ

and (zj , . . . , zn) |= ϕ forall 0 ≤ j < i

(z0, . . . , zn) |= ϕ unless ψ iff � ϕ or ϕ until ψ

(z0, . . . , zn) |= ◦ ϕ iff n �= 0 and (z1, . . . , zn) |= ϕ

(z0, . . . , zn) |= • ϕ iff n = 0 or (z1, . . . , zn) |= ϕ

(z0, . . . , zn) |= last iff n = 0

(z0, . . . , zn) |= blocked iff n �= 0 and z0(Blk) is true

Table 8.1: Formal semantics of temporal operators

z0 z1 z2 zn

ϕ

ϕ

ϕ

ϕ

z0 z1 z2 zn

ϕ

ϕ

ψ

Figure 8.1: Illustrations for � ϕ on the left and ϕ until ψ on the right

In order to formalise properties of a sequence of states, a number of different temporal operatorsis provided. The operators used here, are informally defined as follows.

� ϕ ϕ holds now and always in the future� ϕ ϕ holds now or eventually in the futureϕ until ψ ψ eventually holds and ϕ holds until ψ holdsϕ unless ψ � ϕ or ϕ until ψ◦ ϕ there is a next step which satisfies ϕ (strong next)• ϕ if there is a next step, it satisfies ϕ (weak next)last the current state is the lastblocked execution is blocked

While the informal definitions sketch the basic idea of the operators, the formal definitionsof Table 8.1 clarify the semantics of the operators in detail. A trace (z0, . . . , zn) satisfies � ϕ,if and only if for every postfix (zi, . . . , zn) formula ϕ is satisfied. This is depicted on the left ofFigure 8.1. The trace satisfies ϕ until ψ, if and only if for some i, postfix (zi, . . . , zn) satisfies ψ(in other words: ψ eventually holds), and for all j < i, postfix (zj , . . . , zn) satisfies ϕ (in otherwords: ϕ always holds before ψ holds). This is depicted on the right of Figure 8.1. The notion ofblocking is relevant for the interleaving of two programs.

Example Consider the following temporal formulas with their informal interpretations.

1. Formula � N = 3 states that eventually the value of N is equal to 3.

2. Formula N ′ = N +1 until N > 10 states that a program increments N until the value of Nis greater than 10.

Page 179: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 178

3. Formula � N ′′ = N ′ states that the environment always leaves N unchanged.

8.2.5 Semantics of parallel programs

A parallel program can be interpreted as a transition system. In each step zi, the program takesthe unprimed values X as input and executes a certain transition to calculate the output valuesX ′.

A program only modifies certain variables and leaves other variables unchanged. A variablelist vl in front of a program denotes which variables remain unchanged, if they are not assignedby a current transition of the program. We use a special formula τvl to express that all variablesX from vl remain unchanged by a program.

τvl ≡∧{x1 = x0 | X ∈ vl}

where x0 denotes the value of X before a program transition and x1 is the value of X after thistransition. In order to describe a transition, we need to know,

• which variables are modified and which variables are unchanged,

• whether a transition is blocked, and

• how execution is continued after the first transition.

In Table 8.2, we informally describe the transition system which is defined by the different programstatements. Statements X := t and skip define single transitions. Sequential composition, condi-tionals and while loops, combine transition systems α and β to form a larger transition system.An await statement is used to synchronise parallel processes: execution of a process is blockeduntil a certain condition holds. Finally, the interleaving operator combines two parallel processes.Either a nonblocked transition of process α or of process β is executed. If both processes areblocked, then the interleaving is also blocked.

In KIV, programs α are written in square brackets [: V1, . . . , Vn | α] to receive a temporalformula.

Example The first example explains the semantics of the variable list in front of a program.

[: X,Y, Z | X := 1]

The program sets X ′ to 1 and leaves variables Y and Z unchanged. As an example for a temporalproof obligation, consider

[: N | while true do N := N + 1],� N ′′ = N ′, N = 1 � N = 3

The program is a nonterminating loop which increments N in every step of the loop body. Theprogram transitions are never blocked. The environment does not modify N . Initially, the valueof N is 1. Our task is to verify that eventually the value of N is greater than 3.

8.3 Calculus

The proof method for the verification of parallel programs in KIV is symbolic execution withinduction. Different from verifying sequential programs in Hoare Logic or Dynamic Logic, thetemporal property must be considered during execution already. Therefore, program and propertyare “executed” simultaneously. Executing two interleaved parallel processes gives many differentcases, i.e., proof branches: in each step either a transition of the first or the second process isexecuted. To counter the exponential growth of the proof size, a simple sequencing strategy isexploited in KIV. The three principles

Page 180: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 179

vl | X := t an assignment changes X ′ to the value of t and leaves all othervariables in variable list vl unchanged; it is never blocked; it ter-minates after the first transition.

vl | skip the no operation statement leaves all variables in vl unchanged; itis never blocked; it terminates after the first transition.

vl | α; β sequential composition is to execute the transitions of program αfirst and then to execute β.

vl | if ε then α else β a conditional requires one step (skip) to evaluate its condition ε;it executes the transitions of α, if the condition is true, otherwiseβ is executed.

vl | while ε do α a while loop requires one step (skip) to evaluate its condition ε;it executes α as long as ε is true, otherwise it terminates.

vl | await ε an await statement takes no step to evaluate its condition ε; it ter-minates as soon as ε is true; until then all variables are unchangedand the program is blocked.

vl | α�β interleaving two programs is to either execute the first transition

of program α or β, but only if the transition is not blocked andthen continuing by interleaving the rest of the programs; the in-terleaving is blocked, if the first transitions of both programs areblocked.

Table 8.2: Informal semantics of parallel programs

1. symbolic execution (see Sect. 8.3.1),

2. induction (see Sect. 8.3.2), and

3. sequencing (see Sect. 8.3.3)

are explained next.

8.3.1 Symbolic execution

For symbolic execution of simple temporal proof obligations, a single proof rule

L(Γ) L(Δ) S(Γ) S(Δ)

Γ Δstep

is sufficient. Rule step generates two premises, the first assuming that execution terminates,the second executing all of the possible first steps. The rule considers every parallel programand temporal formula occuring in the sequent simultaneously! Function L(ϕ) returns a formuladescribing the conditions under which execution terminates. Function S(ϕ) calculates a formulawhich describes the first transition. The two functions are explained next.

Executing PL formulas

The basic idea of executing a PL formula is to substitute the values of the dynamic variables X inthe first state z0 with fresh static variables xi. If the first transition is executed, then the valuesof the unprimed and primed dynamic variables X and X ′ are stored in distinct static variables x0and x1. Moreover, variables X ′′ are replaced with the corresponding unprimed variables X .

S(ϕPL) :≡ ϕPL

x0,x1,XX,X′,X′′

Page 181: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 180

ϕ L(ϕ) S(ϕ)� ϕ L(ϕ) S(ϕ) ∧ � ϕ� ϕ L(ϕ) S(ϕ) ∨ � ϕϕ until ψ L(ψ) S(ψ) ∨ S(ϕ) ∧ ϕ until ψϕ unless ψ L(ϕ) ∨ L(ψ) S(ψ) ∨ S(ϕ) ∧ ϕ unless ψ• ϕ true ϕ◦ ϕ false ϕlast true falseblocked false blk0

Table 8.3: Definition of L(ϕ) and S(ϕ) for temporal formulas

If execution terminates, then all unprimed, primed and double primed dynamic variables X , X ′,and X ′′ are substituted with a single static variable x0 which represents the final value of thedynamic variable X .

L(ϕPL) :≡ ϕPLx0,x0,x0

X,X′,X′′

Static variables in ϕPL are not affected by functions S and L!Example Executing the first transition of formula N ′ = N + 1 ∧ N ′′ = N leads to

S(N ′ = N + 1 ∧ N ′′ = N ′) ≡ n1 = n0 + 1 ∧ N = n1 .

After the first transition, the new initial value of N is the old value n0 incremented by one. Ifexecution terminates, then we receive the condition

L(N ′ = N + 1 ∧ N ′′ = N ′) ≡ n0 = n0 + 1 ∧ n0 = n0 .

(In this case, the condition is contradictory. Execution cannot terminate while variable N is stillincremented.)

Executing TL formulas

The definitions of functions L(ϕ) and S(ϕ) for a temporal formula ϕ are given in Table 8.3. Foroperator � ϕ if execution terminates, then formula L(ϕ) must hold in the final state. Otherwise,if execution takes a step, then formula S(ϕ) holds now and after executing the first transition,� ϕ again holds. For operator ϕ until ψ if execution terminates, then formula L(ψ) must hold.If execution takes a step, then either S(ψ) holds in the current state, or formula S(ϕ) holds andafter the execution of the first transition, ϕ until ψ again holds.

For combinations of temporal formulas with conjunction ϕ ∧ ψ, disjunction ϕ ∨ ψ, etc., func-tions S and L simply recurse. For example, S(ϕ ∧ ψ) ≡ S(ϕ) ∧ S(ψ).Example Executing the first transition for formula N ′ = N + 1 until N > 10 leads to

S(N ′ = N + 1 until N > 10)

≡ S(N > 10) ∨ S(N ′ = N + 1) ∧ (N ′ = N + 1 until N > 10)

≡ n0 > 10 ∨ n1 = n0 + 1 ∧ (N ′ = N + 1 until N > 10) .

Either the old value n0 is greater than 10 (in this case, the final condition of operator until issatisfied), or n0 is incremented to receive n1 and the until condition again holds in the next state.If execution terminates, then we receive the condition

L(N ′ = N + 1 until N > 10)

≡ L(N > 10)

≡ n0 > 10 .

The final value n0 of variable N must be greater than 10.

Page 182: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 181

α L(α) T (α)

vl | X := t false {(x1 = S(t)∧ τvl \ X ,F,E)}vl | skip false {(τvl,F,E)}

vl | α; β L(vl | α) ∧ L(vl | β) {(L(vl | α) ∧ ϕ, b, vl | β′) | (ϕ, b, vl | β′) ∈ T (vl | β)}∪ {(ϕ, b, vl | α′; β) | (ϕ, b, vl | α′) ∈ T (vl | α)}

vl | if ε then α else β false {(S(ε) ∧ τvl,F, vl | α), (S(¬ ε) ∧ τvl,F, vl | β)}vl | while ε do α false {(S(ε) ∧ τvl,F, vl | α;while ε do α), (S(¬ ε) ∧ τvl,F,E)}vl | await ε L(ε) {(¬ S(ε) ∧ τvl,T, vl | await ε)}

vl | α�β L(vl | α) ∧ L(vl | β) {(ϕ,F, vl | α′ �

β) | (ϕ,F, vl | α′) ∈ T (vl | α)}∪ {(ϕ,F, vl | α

�β′) | (ϕ,F, vl | β′) ∈ T (vl | β)}

∪ {(ϕ ∧ ψ,T, vl | α′ �β′) | (ϕ,T, vl | α′) ∈ T (vl | α),

(ψ,T, vl | β′) ∈ T (vl | β)}

Table 8.4: Definition of L(α) and T (α) for parallel programs with variable list vl

Executing parallel programs

For executing parallel programs, we define a special function

T : VLPROG → {(FMA× {F,T} × (VLPROG ∪ {E}))}

which returns the set of first program transitions. A transition is a triple containing

• FMA: the PL formula defining the relation between unprimed and primed variables,

• {F,T}: a flag which is T, if the transition is blocked, and

• (VLPROG ∪ {E}): the remaining program to execute in the next step. If no programremains, E is returned.

Table 8.4 contains the definition of function T (α) for all program statements in additionto the definition of function L(α) returning a formula which is the condition under which theprogram terminates. For assignments, a set containing a single transition is returned, whichdefines variable x1 to be equal to S(t) and leaves all other variables from the variable list varlistunchanged (τvl \ X). The transition is not blocked (flag F) and the remaining program for thenext state is empty (program E). A while loop always takes a step to evaluate its condition ε. Itis consequently never blocked. If ε is satisfied, execution continues with the loop body α togetherwith the repeated while loop. Otherwise, the loop terminates after one step. Evaluating thecondition of an if-construct also consumes one step. The transition is not blocked. If ε holds inthe current state, the remaining program is α, otherwise β. The first transitions of an interleavingα

�β of two processes α and β are given by the union of all unblocked first transitions of α and

unblocked first transitions of β. Furthermore, if for both processes there are transitions which areblocked, then there is also the possibility for the interleaving to be blocked.

Example The transitions of program N | while true do N := N + 1 are calculated as follows.First, the condition of the while loop is evaluated.

T (N | while true do N := N + 1)

≡ {(n1 = n0,F, N | N := N + 1; while true do N := N + 1), (false,F,E)}

The first transition of the loop evaluates the loop condition, which in this case is trivially true.This transition does not change N and is not blocked (F). In the first tuple, execution continueswith the loop body N := N + 1, followed by the entire loop. The second tuple describes the case inwhich the while loop is exited (false) and no program is left (E).

Page 183: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 182

Calculating T for the remaining program yields the following set of transitions.

T (N | N := N + 1; while true do N := N + 1)

≡ {(false ∧ ϕ, b,N | β′) | (ϕ, b,N | β′) ∈ T (N | while true do N := N + 1)}∪ {(ϕ, b,N | α′;while true do N := N + 1 | (ϕ, b,N | α′) ∈ T (N | N := N + 1)}

where T (N | N := N + 1)≡ {(n1 = n0 + 1,F,E)}

≡ {(n1 = n0 + 1,F, N | E;while true do N := N + 1)}≡ {(n1 = n0 + 1,F, N | while true do N := N + 1)}

The result is a single transition where N is incremented by one. The transition is not blocked andthe program continues with again executing the while loop.

The transitions of a temporal formula [: vl | α] containing a parallel program are executed bycalculating the set of transitions of vl | α with function T (.) and by transforming the resultingprogram transitions into a temporal formula:

S([: vl | α]) :≡∨{ϕ ∧ ¬ blk0 ∧ [: vl | α′] | (ϕ,F, vl | α′) ∈ T (vl | α)}

∨∨{ϕ ∧ blk0 ∧ [: vl | α′] | (ϕ,T, vl | α′) ∈ T (vl | α)}

For the unblocked transitions the boolean variable blk0 is false, for the blocked transitions it istrue.

Executing temporal proof obligations

Example Consider again the following proof obligation

[: N | while true do N := N + 1],� N ′′ = N ′, N = 1 � N = 3

Applying rule step leads to

L([: N | while true do N := N + 1]),L(� N ′′ = N ′),L(N = 1) L(� N = 3)S([: N | while true do N := N + 1]),S(� N ′′ = N ′),S(N = 1) S(� N = 3)

[: N | while true do N := N + 1],� N ′′ = N ′, N = 1 � N = 3step

After evaluating functions L(.), the first premise finally reads:

¬ true, n0 = n0, n0 = 1 n0 = 3 .

Rule simplifier uses the contradiction ¬ true in the antecedent to close the goal. After evaluatingfunctions S(.) in the second premise, we receive

n1 = n0 ∧ ¬ blk0 ∧ [: N | N := N + 1;while true do N := N + 1],N = n1 ∧ � N ′′ = N ′,n0 = 1 n0 = 3 ∨ � N = 3 .

Simplifying the goal leads to

[: N | N := N + 1;while true do N := N + 1],� N ′′ = N ′, N = 1 � N = 3 .

Thus, symbolic execution of the proof obligation gives rise to a single next premise, where the newinitial value of N is still 1. The target property N = 3 has not yet been satisfied and we need tocontinue symbolically executing the premise by again applying rule step.

Page 184: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 183

8.3.2 Induction

For proving properties of programs with loops, we basically do well-founded induction over thevalue of an arbitrary induction term t of type nat with rule

Γ, n = t, IndHyp Δ

Γ Δwhere IndHyp :≡ � t < n → (

∧Γ →

∨Δ)

The initial value of the induction term t is stored in a fresh static variable n. If – after the executionof a number of steps – the value of the term has decreased (t < n), the induction hypothesis canbe applied.

Normally, induction requires an invariant which again holds after the loop has been executed.The generalization can be obtained using the rules “cut formula” and “weakening”. (Sometimesit is necessary to shut off the heuristics to avoid unintented simplification.)

Example For the proof obligation

[: N | while true do N := N + 1],� N ′′ = N ′, N = 1 � N ≥ 1

we generalise N = 1 with N ≥ 1 to receive

[: N | while true do N := N + 1],� N ′′ = N ′, N ≥ 1 � N ≥ 1

If an always formula � ϕ occurs in the succedent, formula � ϕ can be used to get an inductionterm. The formula is converted into an equivalent formula

∃ N0. N0 = N ′′0 + 1 until ¬ ϕ

in the antecedent and variable N0 is used as an induction term.

[: N | while true do N := N+1],� N ′′ = N ′, N ≥ 1, N0 = N ′′0 +1 until (¬ 1 ≤ N), IndHyp � N ≥ 1

After executing the first two transitions with rule step, we receive a single premise

[: N | while true do N := N + 1],� N ′′ = N ′, N = n+ 1, n ≥ 1, IndHyp � N ≥ 1.

In this premise, the body of the while loop has been completed, and the remaining program isidentical to the program of the penultimate premise. Furthermore, the constraint N ≥ 1 is fullfiled.Induction can be applied to close the goal.

Induction can only be applied, if the remaining program is identical to the program in theinduction hypothesis. For parallel programs it is not sufficient to use induction once. Instead,induction must be used every time one of the parallel processes is in front of a while loop. Inorder to avoid the necessity of an induction rule every time a process loops, KIV implementsa special induction strategy called VD induction which is initiated only once. Afterwards, if apremise contains a program which already occured earlier in the proof, induction can be appliedusing apply VD induction . The rule requires the selection of a node in the proof tree which containsthe identical parallel program. We apply the rule by highlighting the desired node in the prooftree and by selecting apply VD induction from the proof menu (see Figure 8.2). Important: It iseven possible to refer to proof nodes which are on a different proof branch as long as the conditionthat the induction term has decreased can be established!

8.3.3 Sequencing

While executing two interleaved processes many different cases must be considered. In each step,either a transition of the first or the second process is executed. After executing several steps, in

Page 185: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 184

Figure 8.2: Rule apply VD induction in KIV

Figure 8.3: Rule insert proof lemma in KIV

some cases the same transitions have been executed, but in a different order. These cases can becontracted with rule insert proof lemma

<proved in a different proof branch>

Γ0 Δ0 Γ,∧

Γ0 →∨

Δ0 Δ

Γ Δinsert proof lemma

If you arrive with a premise, where the parallel program is the same as in a different premise,highlight the premise and chose insert proof lemma from the context menu (see Fig. 8.3).

Example Consider the temporal proof obligation

[: vl | { N := 1; . . . }�{ M := 2; . . . }],� (N ′′ = N ′ ∧M ′′ =M ′) . . . .

After executing the first step, the following premises result

N = 1, [: vl | { . . . }�{ M := 2; . . . }],� (N ′′ = N ′ ∧M ′′ =M ′) . . .

andM = 2, [: vl | { N := 1; . . . }

�{ . . . }],� (N ′′ = N ′ ∧M ′′ =M ′) . . . .

Page 186: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 185

In the first premise, assignment N := 1 of the first process, in the second premise, assignmentM := 2 of the second process have been executed. Executing a step for both premises gives fourpremises, and two of the four premises read

N = 1,M = 2, [: vl | { . . . }�{ . . . }],� (N ′′ = N ′ ∧M ′′ =M ′) . . . .

In one premise, a transition of the first process was followed by a transition of the second and viceversa. These two premises can be contracted with rule insert proof lemma.

8.3.4 Summary of proof method

If you want to execute a concurrent program manually, it is best to do the steps breadth first,i.e., execute a step for every open premise of the proof tree, before you continue with symbolicexecution. This corresponds to the following recipee.

1. Use heuristics TL Heuristics.

2. If necessary, use rule generalise to introduce an invariant.

3. If required, define an induction hypothesis using rule VD induction .

4. For every open premise do:

(a) If the remaining program is identical to a program occuring earlier in the proof, try toclose the premise with rule apply VD induction .

(b) Otherwise, execute a step with rule step.

(c) Simplify the resulting premises.

5. Try to contract premises with rule insert proof lemma.

6. Continue with 4.

Instead of using rule step, you can also use the rules for individual program statements. Theset of KIV heuristics TL Heuristics + Breadth First Exec automates steps 1 - 6 above, whichare typically rather hard to perform manually.

Page 187: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 186

8.4 Exercise (TL Formulas)

Exercise 10.1 This exercise helps you to become familiar with central temporal operators and thecalculus (the step rule and VD induction). Formalize and prove the following tautologies in KIVspecification “TL-Formulas”, using adequate temporal operators on flexible variables ϕi : bool.

1. ”What will always be, will be”

2. ”If ϕ1 will always imply ϕ2, then if ϕ1 will always be the case, so will ϕ2”

3. ”If it will be the case that ϕ, it will be, that it will be that ϕ”

4. Only use the eventually operator � to formalize this statement:”If it will never be that ϕ, then it will be that it will never be that ϕ”

Exercise 10.2 Prove the remaining lemmas from specification “TL-Formulas” in any order. Ad-ditional remarks:

• The “unless” operator is also known as the “weak until” operator of temporal logic.

• The proof of Lemma fin-progress is optional: the lemma states that in a finite concurrentsystem of up to ”n” processes, infinite progress of some process m ≤ n is equivalent tothe infinite progress of one individual process m0 ≤ n. The proof of the sufficient directionrequires structural induction over ”n” first. To apply the induction hypothesis (A ...), simplyuse rule “all left”.

8.5 Exercise (TL Programs)

Exercise 10.3 Prove lemma inc-3 from KIV specification “TL-Progs”

[: N | while true do N := N + 1],� N ′′ = N ′, N = 1 � N = 3

Either use the step rule or rules for the individual program statements. As the standard heuristicsset choose TL Heuristics.

Exercise 10.4 Prove lemma while-ilv

[: N | while true do N := N + 1 || N := 1],� N ′′ = N ′, N = 1 � N ≥ 1

from specification TL-Progs in KIV. Generalise the initial condition N = 1 appropriately. Userules VD induction , step and insert proof lemma. Either use the step rule or rules for the indi-vidual program statements. As the standard heuristics set choose TL Heuristics.

Exercise 10.5 Prove lemma counter-seq from specification TL-Progs, using heuristics TLHeuristics:

[: X,N | while true do {N := X ;N := N + 1;X := N ;}],� (X ′′ = X ′ ∧N ′′ = N ′), N = 0 � � X ′ > X

Variable N can be seen as a local variable. The sequential counter program repeatedly takes acopy N of variable X . After locally incrementing N , it updates X to the new value of N . It isyour task to prove that X will always be eventually incremented.

Page 188: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 187

Exercise 10.6 Lemma counter-ilv from specification TL-Progs regards two simple counterprograms which are executed concurrently.

[: X,N1, N2 |N1 := X ;N1 := N1 + 1;X := N1;

N2 := X ;N2 := N2 + 1;X := N2;

],� (N ′′1 = N ′1 ∧N ′′2 = N ′2 ∧X ′′ = X ′), X = 0 � (last ∧X = 2)

Each program increments the value of the shared counter variable X by one. Starting withX = 0, execution of the interleaved program terminates and the value of X is expected to beequal two. Can you prove this property for the interleaved system? If yes, give a proof in KIVusing heuristics TL Heuristics + Exec. Otherwise, use the await-construct and a semaphoreS (similar to program semaphore above) to construct a symmetric concurrent system, whichterminates with postcondition X = 2. Use heuristics TL Heuristics + Breadth First Exec toprove termination and correctness of your extended system.

Exercise 10.7 Prove lemma mutex

[: L1, L2, S | semaphore ],� (S′′ = S′ ∧ L′′1 = L′1 ∧ L′′2 = L′2),¬ L1,¬ L2, S = 1 � ¬ (L1 ∧ L2)

from specification TL-Progs in KIV. Either manually apply the recipee from 8.3.4 or use the setof heuristics TL Heuristics + Breadth First Exec to automate the proof. It is recommendedto try a manual proof first.

Exercise 10.8 (Peterson2) Prove lemma “peterson2-safe” from specification TL-Progs. Itensures correctness of a simple version of Peterson’s [?] mutual exclusion lock for two processes.Again, instead of an interactive proof, you may use the set of heuristics TL Heuristics +Breadth First Exec to automate the proof. You must first manually apply VD Inductionthough. Similarly, prove lemma “peterson2-live-await”.

Remark: The automatic verification of an algorithm gives little intuition why a property holds.The interactive verification using symbolic execution is similar to the stepwise debugging of theinterleaved program and thus, it gives better insight on how the algorithm works and why it iscorrect. Of course, the latter method is much more time consuming.

8.6 Exercise Rely-Guarantee Reasoning

Direct symbolic execution of interleaved programs typically fails even for small programs. Rely-Guarantee (RG) reasoning is a wide-spread decomposition technique that avoids verification ofparallel programs by directly computing their interleaved executions. Instead, proof obligations forindividual components of an interleaved system are defined that can be composed to yield an overallproperty. This exercise introduces the basic ideas of rely-guarantee reasoning, by verifying thecorrectness of a simple concurrent program that calculates the greatest common divisor in parallel.The parallelization in this example does not really improve performance of the computation, butserves for illustration purposes only.

The algorithm concurrent-gcd computes the greatest common divisor gcd(m,n) of two ar-bitrary input naturals m and n, using two processes. The shared memory location NP holds theinput values initially, i.e., NP = m×n . Process P1 repeatedly checks whether the first slot NP .1stores a number that is greater than NP .2. In this case, it sets NP .1 to (NP .1 – NP .2). However,if both slots NP .1 and NP .2 contain the same value, it terminates. Process P2 is symmetric.

Page 189: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 188

concurrent-gcd ≡P1 : 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 ;if X = Y then Done := true}}

P2 : 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}}

Rely-guarantee (RG) decomposition theorems decompose global properties of a concurrentsystem to local proof obligations for the system’s components. This section introduces a simplerely-guarantee decomposition technique for two interleaved processes. It will be your task to provethe resulting RG assertions for the individual processes P1 and P2 of the concurrent gcd algorithm.

The central task of RG proofs is to verify an RG assertion for each individual process. RGassertions in KIV have the following syntax

Prei(S) [Ri(S′, S′′),Gi (S, S

′), Inv(S),Pi(S)] Posti(S) (1)

where variable S : state represents the overall state of the concurrent system. Semantically, theformula says that when running procedure Pi from an initial state that satisfies preconditionPrei , it maintains the guarantee Gi and the invariant Inv in its own steps, as long as previoustransitions of its environment satisfy Ri and maintain Inv respectively; upon termination, theprogram establishes the postcondition Posti .

The invariant predicate is irrelevant in our example. More important is the fact that RG-assertions are safety formulas, i.e., they can be verified by well-founded induction over the lengthof an arbitrary interval prefix: Use rules extract liveness and VD Induction on the resultingboolean variable Boolvar that characterizes the length of the prefix.

Having verified an RG assertion (1) for each individual process i = 1, 2, we can derive thefollowing RG assertion for their interleaving.

Pre1 ∧ Pre2 [R1 ∧ R2,G1 ∨ G2, Inv(S),P1(S)�P2(S)] Post1 ∧ Post2 (2)

Some additional predicate logic restrictions RGrestr on the used predicates must also be satisfiedto prove (2).

RGrestr(Ri ,Gi ,Prei ,Posti) ≡(Gi (S , S

′) → R3−i(S , S ′))∧ (Prei(S

′) ∧ Ri(S′, S ′′) → Prei(S

′′))∧ (Post i(S

′) ∧ Ri(S′, S ′′) → Post i(S

′′))∧ transitive(Ri)

They ensure that (1) the guarantee of a process implies the rely of the other process (2) bothpreconditions and postconditions must be stable over rely conditions, i.e., they must be main-tained by rely transitions and (3) rely predicates must be transitive. The stability of pre- andpostconditions over rely steps is required, since before a process starts its execution, respectivelyafter termination of a process, arbitrary many steps of the other process are possible. (Steps ofthe overall environment are ignored here.)

Exercise 10.9 (RG Proof of concurrent-gcd) Verify the correctness of the concurrent gcdprogram using RG reasoning. The main task is to find suitable rely properties for each individualprocess such that you can prove the corresponding RG assertion. (The rely predicates of bothprocesses will be of course symmetric.) The right instances for the guarantee, as well as thepreconditions and the postconditions are already defined in specification “Concurrent-GCD-RG”.First of all, you should have a close look at these definitions and try to understand their meaning.Then proceed as follows.

Page 190: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 8. VERIFICATION OF PARALLEL PROGRAMS 189

Start by trying to prove all predicate logic lemmas of the specification “Concurrent-GCD-RG”first. These correspond to the predicate logic restrictions RGrestr from above. The four lemmasabout stability (“post-stable-r1” etc.) are not provable right away, since the initial rely conditions“true” are too weak. Think of reasonable environment restrictions and encode them into thecorresponding rely predicates such that all predicate logic lemmas can be proved. (Do not forgetto reload the specification.)

Once you have found rely properties such that all predicate logic lemmas can be proved, try toprove the RG assertions “Proc1-sat-rg” and “Proc2-sat-rg”, respectively. (This shows that yourassumptions are met by the algorithms indeed.) The proofs of these two lemmas are symmetric andslightly more challenging. When you are at the beginning of the while loop, you need to generalizethe current state (use rule “generalise”) and to apply “extract-liveness” and “VD induction” onthe RG assertion to enable an inductive proof. Then the proof consists of mainly stepping throughthe code and applying induction if the program loop is reiterated. For the instruction that modifiesthe shared variable NP , you will have to prove the guarantee and in the last state of the program,the post condition must be shown. Use heuristics TL Heuristics + Exec if you like to havemost rules of symbolic execution applied automatically.

Exercise 10.10 (Peterson2 Revisited) This exercise is optional:Give a RG proof of mutual exclusion of Peterson’s lock implementation for two processes (similarto concurrent-gcd).

Page 191: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Chapter 9

Programmieren in PPL

Bisher wurden alle Versuche in der Entwicklungsumgebung, die mit (start) aufgerufen wird,durchgefuhrt. Diese Entwicklungsumgebung ist ein Programm der Programmiersprache PPL.Im folgenden Versuch soll man nun selbst PPL Programme schreiben, die Beweise konstruieren.Deshalb folgt in diesem Kapitel zunachst eine allgemeine Einfuhrung in das Programmieren in PPL(PPL steht fur proof programming language). Das nachste Kapitel behandelt dann die Realisierungder logischen Datenstrukturen (Expressions, Formeln, Beweisbaume).

PPL ist eine rein funktionale Programmiersprache mit statischer Bindung. Das außere Erschei-nungsbild ist ahnlich wie in LISP (viele Klammern!), außerdem heißen einige Befehle genauso wiein LISP. Eine weitere Ahnlichkeit besteht in der interaktiven Programmierumgebung: Eingabenwerden an dem PPL 1>-Prompt gemacht.

9.1 Befehle und Ausdrucke

Die Eingaben an das KIV-System sind entweder Befehle oder Ausdrucke. Syntaktisch sehen Be-fehle und Ausdrucke gleich aus. Der Unterschied liegt darin, dass Ausdrucke ein Ergebnis (eineDatenstruktur) zuruckliefern, wahrend Befehle dies nicht tun, sondern einen Seiteneffekt bewirken.

Im einfachsten Fall, bei Konstanten oder PPL-Variablen (beides sind Ausdrucke) gibt mandiese direkt ein:

PPL 1> Konstante-oder-Variable

Beispiele sind

PPL 1> 3

oder

PPL 1> x

Der erste Ausdruck ergibt naturlich 3 als Ergebnis, der zweite den Wert der Variable x (odereine Fehlermeldung, wenn die Variable noch keinen Wert hat). Wenn der Befehl Parameter ver-langt oder der Ausdruck die Anwendung einer Funktion auf Parameter (die Anzahl der Parameterkann auch 0 sein) ist, wird wie in Lisp der Befehl bzw. die Funktion gefolgt von den Parameternin runde Klammern eingeschlossen:

PPL 1> (Befehl-oder-Funktion Param1 Param2 ... Paramn)

Die Parameter sind selbst wieder Ausdrucke. Sie konnen keine Befehle sein. In den folgendenAbschnitten werden zunachst Funktionen und ihre Anwendung erklart (Abschnitt 9.2) und dieBefehle zur Definition von Variablen (Abschnitt 9.3) behandelt. Abschnitt 9.6 gibt dann einenUberblick uber vordefinierte Funktionen fur Arithmetik, Listen etc.. Die Datenstrukturen in PPL

190

Page 192: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 191

sind, anders als die in LISP, typisiert. Das in Abschnitt 9.5 erklarte Typsystem ist ’polymorph’, d.h. Funktionen wie die Langenfunktion auf Listen konnen unabhangig vom Typ der Listenelementedefiniert werden. Abschnitt 9.7 behandelt dann die Kontrollstrukturen von PPL. Abschnitt 9.8erklart die Ein- und Ausgabebefehle von PPL. Im letzten Abschnitt 9.9 werden die Moglichkeitenerklart, die PPL bereits stellt, um Fehler zu suchen.

9.2 Funktionen

In PPL gibt es drei Arten von Funktionen. Erstens die vordefinierten Funktionen wie +, equaloder zerop, hierzu findet ihr eine Ubersicht in Abschnitt 9.6. Weiter gibt es die vom Benutzerselbst definierten Funktionen (Abschnitt 9.3) und die Lambda-Ausdrucke (Abschnitt 9.3).

Funktionsanwendungen

Am wichtigsten beim Programmieren in PPL sind Funktionsanwendungen. Eine Funktionsanwen-dung besteht aus einem Funktionsnamen fun und den Argumenten fur die Funktion arg1, . . . , argn.Die Funktionsanwendung hat dann die Form

(fun arg1 . . . argn)

Nach Klammer-auf folgt also der Funktionsname, dann (mindestens ein) Leerzeichen oder Return,dann die Argumente fur die Funktion, ebenfalls durch (mindestens ein) Leerzeichen oder Returngetrennt, dann Klammer-zu.

Ein Beispiel ist die (vordefinierte) Funktion +, die zwei Zahlen addiert: (+ 3 5). An einemPPL 1>-Prompt geschrieben, ergibt sich:

PPL 1> (+ 3 5)

8

PPL 1>

Das System liest den Ausdruck (+ 3 5) ein, wertet ihn aus und gibt das Ergebnis 8 aus. Danacherscheint wieder der PPL 1>-Prompt fur die nachste Eingabe.

Man kann Funktionsanwendungen beliebig schachteln: Die Argumente konnen ihrerseits wiederFunktionsanwendungen sein:

PPL 1> (+ (+ 4 (+ 1 6)) 10)

21

PPL 1>

Bei Funktionsanwendungen werden zunachst die Argumente ausgewertet, dann die Funktion aufdie Argumente angewendet. In obigem Beispiel wird daher zuerst (+ 1 6) berechnet, was 7 ergibt,dann 4 + 7, und schließlich 11 + 10.

9.3 Definition von Werten

Mit def konnen an Variablen beliebige PPL-Objekte gebunden werden:

(def (var1 expr1)(var2 expr2)...

(varn exprn))

Page 193: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 192

PPL 1> (def (x 3)

(y (list 4 5))

(z (concl ax))

)

PPL 1> x

3

PPL 1> y

[4, 5]

PPL 1> z

$phi, $GAMMA |- $phi, $DELTA

PPL 1>

def darf nicht innerhalb anderer PPL-Ausdrucke auftreten! Die Ausdrucke expr1 . . . exprn werdenparallel ausgewertet. Dies wird an folgendem Beispiel deutlich:

PPL 1> (def (x 0))

PPL 1> x

0

PPL 1> (def (x 3)

(y (+ 1 x))

)

PPL 1> y

1

PPL 1> x

3

PPL 1>

Zuerst wird mit (def (x 0)) x der Wert 0 zugewiesen. Dann werden in dem zweiten def x undy parallel definiert. In dem Ausdruck (+ 1 x) hat x daher den Wert 0. Erst nach Beendigungder Definition hat x dann den Wert 3.

Man kann auf diese Weise auch einen Effekt der statischen Bindung demonstrieren:

PPL 1> (def (x 0))

PPL 1> (def (y (+ x 1)))

PPL 1> y

1

PPL 1> (def (x 5))

PPL 1> y

1

PPL 1>

Bei der Definition von y wird der aktuelle Wert von x verwendet. Andert man dann den Wert vonx, so hat dies keine Auswirkungen auf den Wert von y, also auf Definitionen, in denen x verwendetwurde.

Lambda-Ausdrucke

Funktionen werden mit lambda definiert:

(lambda (var1 . . . varn) expr)

var1 . . . varn sind die Parameter der Funktion, expr ist der Rumpf der Funktion:

PPL 1> ((lambda (x y z) (+ x (- y z))) 3 4 5)

2

PPL 1>

Page 194: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 193

9.4 Definitionen

Um Funktionen oder Werte an einen Bezeichner zu binden benutzt man def:

PPL 1> (def (fun (lambda (x) (+ x x))))

PPL 1> (fun 3)

6

Jetzt benotigt man nur noch eine Moglichkeit, rekursive Funktionen zu definieren, und man kannin PPL schon richtig programmieren. Rekursive Funktionen werden mit defrec definiert. DieSyntax von defrec ist identisch zu der Syntax von def.

PPL 1> (defrec (fac (lambda (x)

(if (zerop x) 1 (* x (fac (- x 1)))

)

)))

PPL 1> (fac 4)

24

PPL 1>

berechnet die Fakultat. Auch (fac 1000) lasst sich so recht schnell berechnen. Man kann hiernicht def verwenden, da bei dem rekursiven Aufruf (fac (- x 1)) ansonsten eine bereits ex-istierende Definition fur fac gesucht bzw. verwendet wurde. Mit defrec wird die gerade entste-hende Definition fur fac verwendet. Nicht rekursive Funktionen kann man mit def definieren,aber auch mit defrec — da es keinen rekursiven Aufruf gibt, ist keine Unterscheidung notwendig,ob die aktuelle oder eine bereits existierende Definition herangezogen wird.

Man kann mit defrec auch andere Definitionen ausfuhren:

PPL 1> (def (x 0))

PPL 1> (defrec (x 3)

(y (+ 1 x))

)

PPL 1> y

4

PPL 1>

Hier wird bei der Auswertung von (+ 1 x) der Wert von x in der aktuellen Definition verwendet,der 3 ist. Es empfiehlt sich aber (guter PPL-Programmierstil!), defrec nur bei der Definition von(gegenseitig) rekursiven Funktionen zu verwenden.

Noch zwei Beispiele fur Funktionen. Die Funktion reverse soll eine Liste invertieren. Esgibt generell zwei Moglichkeiten, diese Funktion zu programmieren. Die erste Variante ist rechtineffizient (warum?), und verwendet eine Funktion attach, die ein Element an das Ende einerListe anfugt.

PPL 1> (def (attach (lambda (elem a-list) (append a-list (list elem)))))

PPL 1> (defrec (myreverse (lambda (a-list)

(cond ((emptyp a-list) (list))

(t (attach (car a-list) (myreverse (cdr a-list))))

)

)))

PPL 1> (reverse (list 1 2 3 4 5 6 7))

[7, 6, 5, 4, 3, 2, 1]

PPL 1>

Die zweite Variante arbeitet mit tail recursion.

Page 195: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 194

PPL 1> (defrec (myreverse-h (lambda (a-list result-list)

(if (emptyp a-list) result-list

(myreverse-h (cdr a-list)

(cons (car a-list) result-list))

)

)))

PPL 1> (def (myreverse (lambda (a-list) (myreverse-h a-list (list)))))

PPL 1> (myreverse (list 1 2 3 4 5 6 7))

[7, 6, 5, 4, 3, 2, 1]

PPL 1>

Man beachte, dass myreverse-h vor myreverse definiert werden muss!Man kann auch Funktionen als Argumente ubergeben. Die Funktion every-el erhalt als

Eingabe eine Funktion und eine Liste und testet, ob die Funktion, wenn sie der Reihe nach aufjedes Element der Liste angewandt wird, jedesmal T ergibt:

PPL 1> (defrec (every-el (lambda (test-fun a-list)

(cond ((emptyp a-list) t)

((test-fun (car a-list)) (every-el test-fun (cdr a-list)))

(t f)

))))

PPL 1> (every-el (lambda (x) (positivep x)) (list 1 2 3 4))

T

PPL 1> (every-el (lambda (x) (positivep x)) (list 1 2 0 3 4))

F

PPL 1>

9.5 Typausdrucke

In PPL erhalt jeder Ausdruck einen Typ. Dadurch werden Typfehler in Funktionsdefinitionenschon bei der Definition erkannt.

Typausdrucke sind folgendermaßen definiert:

<typeexpr> := <typevar> | (<typeconstructor><typeexpr 1>

...

<typeexpr n>)

<typevar> := *t*,*t1*,*t2*,...

Sie sind also entweder eine Typvariable die mit einem * beginnt, oder ein n-stelliger Typkonstruktorder dann wiederum n Typausdrucke enthalt. Die Typkonstruktoren sind:

bool, string, int, tree,... (0-stellig)list (1-stellig) (alle Elemente vom selben Typ)mkpair (2-stellig)fun (n-stellig)

Damit sind nun alle anderen Typen frei definierbar.Ein paar Beispiele:

Ausdruck Typ

3 (int)

"ab" (string)

(mkpair 3 t) (pair (int) (bool))

(lambda (x y) (+ x y)) (fun (int)(int)(int))

(list 3) (list (int))

Page 196: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 195

nil (list *t*)

(lambda (x) x) (fun *t* *t*)

(lambda (x) (cons x nil)) (fun *t* (list *t*))

Dass nil den Typ (list *t*) hat, bedeutet dass nil je nach Verwendung sowohl als Liste vonnat’s, bool’s etc. angesehen werden darf. Bei der Funktion (lambda (x) x) ist es ebenso.Sie darf auf jedes Argument mit beliebigem Typ *t* angewandt werden und liefert genau diesenTyp zuruck. Man sagt die Funktion ist ”‘polymorph”’.

Bei Typfehlermeldungen des Compilers sehen diese Typen allerdings etwas anders aus, weil dortKlammern oft weggelassen werden und Listen und Funktionen in einer anderen Form ausgegebenwerden:

(int) => int

(list (int)) => int*

(fun (int)(int)) => int -> int

(pair (int) (int)) => [ int | int ]

9.6 Vordefinierte Funktionen

Es gibt in PPL eine große Anzahl vordefinierter Funktionen. An dieser Stelle soll nur auf solcheFunktionen eingegangen werden, die nichts mit der Logik zu tun haben, sondern mit Zahlen, Listenusw. arbeiten.

Zahlen

In PPL gibt es nur ganze Zahlen, diese konnen aber beliebig groß sein. Es gibt die vier Grun-drechenarten Addition, Subtraktion, Multiplikation und Ganzzahldivision, die jeweils zwei Zahlenals Argumente nehmen.

+ Addition- Subtraktion* Multiplikationdiv Ganzzahldivision

Um zwei Zahlen zu vergleichen, gibt es folgende Funktionen (man spricht auch von (Test-)Pradikaten):

< kleiner> großer= gleich

Und schließlich gibt es noch fur eine Zahl:

zerop Ist die Zahl gleich 0?positivep Ist die Zahl positiv?

Ergebnis der Testpradikate ist ein Wahrheitswert t (fur wahr) oder f (fur falsch).

Listen

Listen sind ein Grunddatentyp von LISP und ebenso von PPL. Aber anders als in LISP mussenin PPL alle Elemente einer Liste denselben Typ haben. Eine Liste wird konstruiert mit

(list arg1 ... argn)

Statt (list) kann man auch nil schreiben. list ist keine normale Funktion, da sie beliebig vieleArgumente als Eingabe erhalten kann:

Page 197: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 196

PPL 1> (list)

[]

PPL 1> nil

[]

PPL 1> (list 1)

[1]

PPL 1> (list 1 2 3 4 5 6 7 8)

[1, 2, 3, 4, 5, 6, 7, 8]

PPL 1> (list (list 1) (list 1 2 3) nil)

[[1], [1, 2, 3], []]

Es gibt einige Funktionen fur Listen: car selektiert das erste Element einer Liste, cdr schneidetdas erste Element einer Liste ab, und hat als Ergebnis den Rest der Liste, cons fugt ein Elementin eine Liste ein. length berechnet die Lange einer Liste. get selektiert das n-te Element einerListe, set andert das n-te Element. Ein paar Beispiele:

PPL 1> (car (list 1 2 3))

1

PPL 1> (cdr (list 1 2 3))

[2, 3]

PPL 1> (cons 1 (list 2 3))

[1, 2, 3]

PPL 1> (length (list 1 2 3))

3

PPL 1> (get 3 (list 2 4 6))

6

Dabei muss beachtet werden, dass das Zahlen der Elemente einer Liste mit 1 beginnt.

PPl 1> (set 1 8 (list 2 4 6))

[8, 4, 6]

PPL 1>

emptyp testet, ob eine Liste leer ist. Des weiteren gibt es noch member (ist ein Element in einerListe enthalten?), append (Aneinanderhangen zweier Listen), union (Vereinigung zweier Listen,wenn man sie als Mengen ansieht), intersection (Schnitt) und difference (Differenz).

Paare

Will man in PPL unterschiedliche Elemente zusammenfugen, so steht dafur die Funktion mkpair

zur Verfugung:

PPL 1> (mkpair 3 (list 3))

[3 | [3]]

PPL 1> (mkpair (list 1 2 3) (mkpair 4 5))

[[1, 2, 3] | [4 | 5]]

PPL 1>

Fur Paare gibt es zwei Funktionen: fst liefert das erste Element eines Paares, snd das zweiteElement. Beispiele:

PPL 1> (fst (mkpair 3 (mkpair 4 5)))

3

PPl 1> (snd (mkpair 3 (list 3)))

[3]

PPL 1>

Page 198: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 197

Wahrheitswerte

Es gibt in PPL die Wahrheitswerte t (wahr) und f (falsch). Jedes Testpradikat hat als Ergebnisimmer einen Wahrheitswert. (not expr) negiert expr (ein Wahrheitswert), (and expr1,...,exprn) bildet die Konjunktion, (or expr1,..., exprn) die Disjunktion von n Wahrheitswerten.and und or werten immer zuerst das erste Argument aus und die weiteren nur, wenn der Ausdrucknicht bereits berechnet werden kann (d. h. die folgenden Argumente von and werden nur dannausgewertet, wenn das erste zu t ausgewertet wird, bei or zu f):

PPL 1> (and t t)

T

PPL 1> (not f)

T

PPL 1> (or t f)

T

PPL 1>

Die Funktion equal vergleicht zwei PPL-Objekte. Das Ergebnis ist t, falls die Objekte gleich sind,f andernfalls. Die PPL-Objekte durfen allerdings keine Beweisbaume oder Funktionen enthalten.

Strings

Strings werden einfach durch doppelte Anfuhrungsstriche eingerahmt:

PPL 1> "dies ist ein String"

dies ist ein String

PPL 1> (mkpair 3 "dies ist ein String")

[3 | dies ist ein String]

PPL 1> (list "dies" "ist" "ein" "String")

[dies, ist, ein, String]

PPL 1>

Bei der Ausgabe von Strings werden die Anfuhrungsstriche weggelassen.

9.7 Kontrollstrukturen

In PPL gibt es außer Funktionsanwendungen naturlich auch Kontrollstrukturen, allerdings wesentlichweniger, als etwa in LISP. Es gibt Fallunterscheidungen und die Definition lokaler Variablen.

Fallunterscheidungen

Fallunterscheidungen werden mit cond oder if durchgefuhrt. Ein cond gleicht dem cond in Lisp:Man hat einige Testklauseln und Anweisungen, was zu tun ist, wenn ein Test wahr ist. Ein if

gleicht einer if -Anweisung in Lisp. Es hat die Form

(if test thenexpr elseexpr)

Ein cond hat die Form

(cond (test1 expr1)(test2 expr2)...

(t exprn))

cond ist keine Funktion! Eine solche Anweisung wird so behandelt:

Page 199: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 198

Werte zuerst test1 aus. Falls test1 den Wahrheitswert t ergibt, werte expr1 aus. DasErgebnis des gesamten cond ist dann das Ergebnis von expr1. Andernfalls fahre mittest2 fort. Falls test2 t ergibt, werte expr2 aus usw. Da der letzte Test t lautet, wird,falls alle anderen Testklauseln falsch waren, exprn ausgewertet, und das Ergebnis descond ist dann das Ergebnis von exprn.

PPL 1> (cond ((emptyp (list)) 0)

(t 1)

)

0

PPL 1> (cond ((emptyp (list 3 4 5)) 0)

(t 1)

)

1

PPL 1> (cond (t 3)

(t 5)

)

3

PPL 1> (if t (+ 2 3) 1)

5

PPL 1>

Lokale Variablen

Lokale Variablen werden mit let* eingefuhrt. Die Syntax ist

(let* ((var1 expr1)(var2 expr2)...

(varn exprn))

expr)

Zuerst wird expr1 ausgewertet, und das Ergebnis an die Variable var1 gebunden, dann expr2,wobei var1 benutzt werden kann, usw. bis varn. Das Ergebnis des let* ist dann das Ergebnisvon expr. Die Variablen var1 . . . varn existieren nur innerhalb des let*.

PPL 1> (let* ((x (+ 2 5))

(y (* x x))

)

(* y y))

2401

PPL 1>

Es gibt auch ein let mit gleicher Syntax, wobei aber expr1 . . . exprn parallel ausgewertet werden.Insbesondere darf in expr2 nicht var1 verwendet werden.

Backtracking

In PPL kann man sehr bequem Backtracking programmieren. Backtracking wird entweder durchdas PPL-Kommando (fail) ausgelost, oder durch einige andere vordefinierte Funktionen. Dazugehoren makettree, mkftree, refine, infer, match (siehe Kapitel 6). Falls ein refine-Schrittnicht durchgefuhrt werden kann, da keine geeignete Instanziierung der Meta-Variablen gefundenwerden konnte, wird das Backtracking ausgelost.

Naturlich muss noch bekannt sein, an welcher Stelle des Programms weiter gearbeitet werdensoll. Hierzu verwendet man orL. Ein Ausdruck (orL expr1 expr2) wird so ausgewertet: Zuerst

Page 200: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 199

wird expr1 ausgewertet. Wird dabei ein backtracking ausgelost, wird expr2 ausgewertet. Dies istdann auch das Ergebnis des gesamten Ausdrucks. Andernfalls wird expr2 nicht ausgewertet, unddas Ergebnis des gesamten Ausdrucks ist das Ergebnis von expr1.

Falls es keine solche Rucksprungstelle gibt, aber trotzdem ein backtracking ausgelost wird,gibt es die Meldung Error: operation operation failed, und das laufende Programm wirdabgebrochen.

fail ist kein Wert, daher kann diese Anweisung auch an Stellen auftreten, wo etwa eine Zahlerwartet wird.

PPL 1> (orL 3 4)

3

PPL 1> (orL (+ 3 (fail)) 4)

4

PPL 1> (equal 5 (fail))

Error:

operation FAIL failed

PPL 1> (equal (fail) (fail))

Error:

operation FAIL failed

PPL 1> (def

(example-tree

(lambda (tree)

(orL (refine tree 1 weakening_left)

(refine tree 2 weakening_left)))))

PPL 1> (def (res-tree (example-tree cut)))

PPL 1>

9.8 Ein-/Ausgabe

Laden von Dateien

Großere PPL-Programme kann man nicht mehr direkt am PPL-Prompt eingeben, da man beieinem Fehler die gesamte Definition erneut eintippen musste. Daher kann man diese Definitionen ineine Datei schreiben und diese dann laden. Dies geschieht mit load oder require. Der Unterschiedzwischen diesen beiden Ladebefehlen besteht darin, dass load die Datei immer ladt, require nurdann, wenn sie nicht bereits schon geladen wurde.

load und require erhalten den Dateinamen, in doppelte Anfuhrungsstriche eingeschlossen,als Argument:

PPL 1> (load "~kivprakt/prakt3/Versuch3/vcg-program")

;;; loading vcg-program

;;; loaded vcg-program

Alles, was in der zu ladenden Datei steht, wird genauso behandelt, als hatte man es direkt amPPL-Prompt eingetippt. Es gibt nur eine Ausnahme: steht in der Datei ein exit, so verlasst mandamit nicht das KIV-System, sondern das Laden der Datei wird an dieser Stelle beendet.

Im allgemeinen stehen in einer Datei weitere require-Befehle. Man verwendet dort meistensden require-Befehl, da bei einem zweiten Laden der Datei (nach einer Fehlerkorrektur o. a.) dieanderen Dateien nicht noch einmal geladen werden mussen.

require und load durfen nicht innerhalb anderer PPL-Ausdrucke auftreten.

Speichern und Laden von PPL-Objekten

Es gibt außerdem noch die Moglichkeit, PPL-Objekte in einer Datei abzuspeichern und wiederzu laden. Man kann alle PPL-Objekte außer Funktionen abspeichern. Eine Ausnahme wird bei

Page 201: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 200

Baumen gemacht, die ja Funktionen als Validierung enthalten konnen. Baume konnen abgespe-ichert werden, beim Wiederladen mussen die Validierungsfunktionen aber bereits definiert sein.

Das Abspeichern erfolgt mit save-obj, und erhalt als Eingabe das abzuspeichernde Objekt,den Dateinamen, in dem das Objekt gespeichert wird und den Objekttyp: (save-obj obj (typ)dateiname). Das Objekt wird mit load-obj wieder geladen. load-obj erwartet ein Flag, denObjekttyp und den Dateinamen als Argument: (load-obj t (typ) dateiname) (das t gibt an,dass die Signatur des Objekts als aktuelle Signatur eingetragen werden soll.

Schnittstelle zum Dateisystem

Die Dateinamen bei require, load, save-obj und load-obj sind relativ zum aktuellen Ar-beitsverzeichnis, sofern sie nicht mit / beginnen. Das aktuelle Arbeitsverzeichnis erhalt man mitder nullstelligen Funktion pwd, mit cd (Argument: neues Verzeichnis als string) kann es gewechseltwerden, und list-directory (Argument: Verzeichnis als string) gibt den Inhalt eines Verzeichnisseszuruck. Beispiel:

PPL 1> (pwd)

/home/kiv/doc/praktss99/

PPL 1> (cd "~kivprakt/prakt1")

T

PPL 1> (pwd)

/home/kivprakt/prakt1/

PPL 1> (list-directory "Versuch2")

[devgraph, modules, projectinfo.ppl, specifications, version]

PPL 1> (list-directory "./")

[projects, Versuch1, Versuch2, Versuch3, Versuch4]

PPL 1>

Textuelle Ausgabe

Es gibt nur eine einzige Moglichkeit, von einem Programm aus Meldungen auszugeben, ohnedie graphische Fensteroberflache zu verwenden. Dies geschieht mit before. before erhalt zweiArgumente, wertet das erste aus, und gibt das Ergebnis auf dem Bildschirm aus. Dann wird daszweite Argument ausgewertet. Dies ist dann das Ergebnis des gesamten Ausdrucks.

PPL 1> (def (x (before "Jetzt wird x definiert." 3)))

Jetzt wird x definiert.

PPL 1> x

3

PPL 1> (def (y (before (+ x 7) (+ x 1))))

10

PPL 1> y

4

PPL 1>

Eingabe

Ein PPL-Programm kann mit Hilfe von read Eingaben vom Benutzer verlangen. (Wiederum wirdnur die Eingabe ohne Verwendung der graphischen Fensteroberflache beschrieben.) Ein read istfolgendermaßen definiert:

(read x (<typ_1> expr_1)

...

(<typ_n> expr_n))

Page 202: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 201

Ausgewertet wird es so, dass zuerst x eingelesen wird. Wenn x vom Typ typ 1 ist, (typ 1 istein Typausdruck, siehe Abschnitt 2), wird expr 1 ausgewertet, wenn x vom Typ typ 2 ist wirdexpr 2 ausgewertet usw. Dabei mussen expr 1, expr 2, . . . alle denselben Typ haben. Will mansichergehen, dass read in jedem Fall ein definiertes Ergebnis ergibt, muss man fur typ n denAusdruck *t* schreiben, der einen beliebigen Typ beschreibt.

Nach dem Aufruf eines read erscheint dann ein PPL 2>-Prompt, wo nun wiederum beliebigeEingaben gemacht werden konnen wie am PPL 1>-Prompt. Man beendet die Eingabe mit exit.Das Ergebnis von read ist dann der Wert des letzten PPL-Ausdrucks. Gibt es keinen solchenWert (z. B. wenn man sofort exit tippt oder der Typ nicht passt), wird die Fehlermeldung

Error: you cannot exit without a result

ausgegeben, und man befindet sich weiter am PPL 2>-Prompt. Man muss also immer einen Wertangeben.

PPL 1> (def (y (read x ((INT) (* x x)))))

PPL 2> 4

4

PPL 2> exit

PPL 1> y

16

PPL 1> (defrec (read-expr (lambda (text)

(before text

(read x ((expr) x)

((bool) (fail))

(*t* (read-expr text)))))))

PPL 1> (read-expr "geben sie eine Formel ein")

geben sie eine Formel ein

PPL 2> %"true"

true

PPL 2> exit

true

PPL 1>

Die Funktion read-expr liest eine Formel ein, nachdem sie den Text ausgegeben hat. Wennder Benutzer eine Formel (expr) eingibt, wird diese zuruckgegeben, gibt er t oder f ein, wirdBacktracking ausgelost (siehe Abschnitt 9.7). Andernfalls wird die Funktion rekursiv aufgerufenund verlangt erneut die Eingabe einer Formel.

9.9 Debugging

Fehler

Es gibt drei Arten von Fehlern: Fehler beim Einlesen von Eingaben, Compilerfehler und Laufzeit-fehler.

• Fehler beim Einlesen

Ein solcher Fehler tritt z. B. dann auf, wenn man am PPL-Prompt einen Punkt tippt:

PPL 1> .

Error:

Tokens cannot contain only dots..

PPL 1>

In diesen Fallen konnte die Eingabe uberhaupt nicht eingelesen werden. Der typischsteFehler dieser Art sind fehlende schließende Klammern in einer Datei. In diesem Fall erhalt

Page 203: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 202

man die Meldung Error: end of file reading in a list.. Andere Meldungen dieserArt sind

– end of file reading in a list.

– Tokens cannot contain only dots.

– READ encountered #

– A comma appears outside the scope of a backquote (or there are too many commas).

– Symbol token cannot end immediately after a colon.

– ignoring an unmatched right parenthesis.

Bei Verwendung von konkreter Syntax (also innerhalb von %" bis zum schließenden ", nichtzu verwechseln mit Strings), sieht die Fehlermeldung in etwa so aus:

PPL 1> %"($phi)$gamma |- "

Error: Parser: parse error in "($phi) ?? $gamma |-".

PPL 1>

• Compilerfehler

treten auf, wenn die Eingabe syntaktisch falsch ist, oder ein Bezeichner nicht definiert ist.

PPL 1> ein-nicht-definierter-Bezeichner

Error:

The identifier EIN-NICHT-DEFINIERTER-BEZEICHNER has no definition

PPL 1> (def x 3)

Error:

X is not a correct variable binding clause in a def,defrec,let or let*

PPL 1> (+ 5 (def (x 3)))

Error:

(DEF (X 3)) is a command. It cannot be used as an expression

PPL 1> (def (x (+ 5 t)))

Error:

types of arguments

int x bool

do not match type of built in function

(int x int -> int)

in

(+ 5 T)

PPL 1> (car 3)

Error:

types of arguments

int

do not match type of built in function

(t1* -> t1)

in

(CAR 3)

PPL 1> (def (x 5))

PPL 1> (x)

Error:

Types

of arguments do not match type

int

of user defined function in

(X)

Page 204: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 203

PPL 1>

Die dritte Meldung folgt aus der Tatsache, dass def nicht innerhalb anderer PPL-Ausdruckeverwendet werden darf, die vierte und funfte sind Typfehler. Im letzten Beispiel ist (x) eineFunktionsanwendung ohne Argument, aber x ist keine Funktion, sondern vom Typ int.

• Laufzeitfehler haben meistens die Form type error in ... oder selector error in ...

PPL 1> (def (get-3 (lambda (li) (get 3 li))))

PPL 1> (get-3 (list 1))

Error:

length of list is not sufficient

dynamic type error in operation GET in function GET-3

PPL 1> (def (get-1 (lambda (li) (car li))))

PPL 1> (get-1 nil)

Error:

selector CAR applied on object of type NIL in function GET-1

PPL 1> (def (get-valttree (lambda (tr) (valttree tr))))

PPL 1> (get-valttree %" $gamma |- $delta")

Error:

selector VALTTREE applied on object of type SEQ in function GET-VALTTREE

Es gibt noch eine Reihe weiterer Fehlermeldungen, auf die hier aber nicht naher eingegangenwerden soll.

Der Debugger

Ist ein Laufzeitfehler aufgetreten, so kann man mit Hilfe des Debuggers naheren Aufschluss uberden Fehler erhalten. Im Normalfall liefert der Debugger aber nur sehr wenig Informationen. Umseine volle Funktionalitat auszunutzen, mus zunachst der development mode eingeschaltet werden.Dies erfolgt mit

PPL 1> (debug)

invoking debugger

PPL

debug> :on

debug> :exit

PPL 1>

Nach Auftreten eines Fehlers tippt man wiederum (debug). Man erhalt dann die aktuelle Aufrufhier-archie der PPL-Funktionen und den Prompt debug>, an dem man jetzt spezielle Kommandoseingeben kann. :? gibt eine Liste aller Kommandos. Das wichtigste ist :s, mit dem man dieArgumente gezeigt bekommt, die zu dem Fehler fuhrten.

PPL 1> (defrec (func (lambda (x)

(cond ((zerop x) (car (cdr (list x))))

(t (func (- x 1)))))))

PPL 1> (func 10)

Error:

selector car applied on object of type NIL in function FUNC

PPL 1> (debug)

invoking debugger

FUNC (11) <- PPL

debug> :s

0

Page 205: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 204

debug> :exit

PPL 1>

Man sieht, dass von dem PPL-Prompt aus die Funktion func aufgerufen wurde. Sie hat sichdann zehnmal selbst rekursiv aufgerufen. Das falsche Argument war 0, d. h. es wurde (car NIL)aufgerufen.

Der Debugger kann nur bei Laufzeitfehlern eingesetzt werden.

Der Tracer

Der Tracer verfolgt die Anwendung von Funktionen und gibt beim Aufruf einer Funktion dieArgumente aus, mit denen sie aufgerufen wird, und beim Verlassen der Funktion das Ergebnis.Der Aufruf erfolgt mit (trace fun1 ... funn), wenn fun1 . . . funn getraced werden sollen.(trace) gibt alle gerade getraceden Funktionen aus, (untrace fun1 ... funn) beendet dastracen, (untrace) fur alle Funktionen.

PPL 1> (trace reverse-h)

(reverse-h)

PPL 1> (reverse (list 1 2))

+++ REVERSE-H ++++++++++++++++++++++++++++++++++

first argument:

[1, 2]

second argument:

[]

++++++ REVERSE-H +++++++++++++++++++++++++++++++

first argument:

[2]

second argument:

[1]

+++++++++ REVERSE-H ++++++++++++++++++++++++++++

first argument:

[]

second argument:

[2, 1]

--------- REVERSE-H ----------------------------

[2, 1]

------ REVERSE-H -------------------------------

[2, 1]

--- REVERSE-H ----------------------------------

[2, 1]

Page 206: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 205

[2, 1]

PPL 1>

Statt eines Funktionsnamens kann man auch (fun i1 . . . ik) schreiben. Der Tracer gibt dann nurdas i1-te,. . . ,ik-te Argument aus (nutzlich bei großen Argumenten). Das Resultat der Funktionwird dabei als Argument 0 betrachtet, d. h. (trace (fun 0 3)) gibt das Resultat und das dritteArgument aus.

Der Tracer ist mit Vorsicht zu genießen, da die Ausgaben unter Umstanden sehr lang undumfangreich werden konnen.

Page 207: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 206

9.10 Exercise 11

Exercise 11.1 Fibonacci numbersImplement a function fibo that takes a natural number n as argument and computes the nth

Fibonacci number:

• n = 0 : fibo(n) = 1

• n = 1 : fibo(n) = 1

• n ≥ 2 : fibo(n) = fibo(n− 1) + fibo(n− 2)

Give a slow and an efficient implementation for fibo, and compare the run time for some inputs(e.g. 10, 20, 50, 100, 1000).

Exercise 11.2 Towers of HanoiThe following description is stolen somewhere:

The puzzle: Start with N rings, decreasing in sizes from bottom to top, stacked arounda post. There are two other posts. Your mission, should you choose to accept it, is toshift the pile, stacked in its original order, to another post.

The challenge is to do it in the fewest possible moves. Each move shifts one ring to adifferent post. But there’s a rule; you can only stack a ring on top of a larger one.

The simplest nontrivial version of this puzzle is N = 3. Solution time rises as 2N , andprograms to solve it have long been considered classic introductory exercises in the useof recursion.

The puzzle is called ‘Towers of Hanoi’ because an early popular presentation wove afanciful legend around it. According to this myth (uttered long before the VietnamWar), there is a Buddhist monastery at Hanoi which contains a large room with threetime-worn posts in it surrounded by 21 golden discs. Monks, acting out the commandof an ancient prophecy, have been moving these disks, in accordance with the rules ofthe puzzle, once every day since the monastery was founded over a thousand years ago.They are said believe that when the last move of the puzzle is completed, the world willend in a clap of thunder. Fortunately, they are nowhere even close to being done . . .

Implement the “Towers of Hanoi”. Write a PPL function that takes the number N of rings asinput and return the list of moves. A move is a pair of the numbers of source and destinationpost. For example, (hanoi 3) returns

[[1 | 2], [1 | 3], [2 | 3], [1 | 2], [3 | 1], [3 | 2], [1 | 2]]

Exercise 11.3 ProplogicImplement a prover for propositional logic. To simplify the task, several auxiliary functions

are already defined (see appendix ??).

1. Take a look at the function applyrule (defined in file Exercise11/proplogic in your di-rectory). What does the function do?

2. Load the file in PPL (i.e. at a PPL prompt in a running system) and call the function withsome example trees like

%" |- $phi, $phi -> $psi"

as the first argument and 1 as the second argument.

3. Implement a function leftmost until failure that takes as input a tree tree and thenumber i of a premise of the tree, and reduces all premises of the tree with number ≥ i asmuch as possible. Use applyrule for single rule applications.

Hint: The body of the function has three lines.

Page 208: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

CHAPTER 9. PROGRAMMIEREN IN PPL 207

4. Implement a function my-proplogic that applies the propositional rules on a tree and testit with the examples listed in the file proplogic.

Page 209: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix A

Simplifier Rules

A.1 Introduction

While verifying formulas of dynamic logic, the cosi strategy must often deal with predicate logicformulas. There are four main reasons, why simplification of such formulas is important:

1. Simplification leads to better readability.

2. Simplification of predicate logic formulas is important to eliminate superfluous variables inprogram formulas.

3. Goals which are true regardless of all program formulas (including those where all programformulas have been eliminated by the cosi strategy) can be closed

4. The tests of conditionals and while loops can be decided, which means a reduction of searchspace.

Simplification is done by rules of the sequent calculus. The rules are (as usual in a sequent calculus)applied backwards, until no one is applicable. Although, the KIV-System stores the antecedentand succedent of a sequent as lists of formulas, the rules, described in the following sections matchwithout considering the order of the formulas, so you can view a sequent as consisting of two setsof formulas. Simplification is done automatically when trying to decide conditional tests, it canbe called manually by clicking on “simplifier” and there is a heuristic, also called “simplifier”, todo it.

Since simplification is dependent on the datastructure used in sequents to prove, the informa-tion, how to simplify, is kept with the specifications of datastructures.

Simplifier rules are split into four types: First, there are built-in rules, described in sectionA.2, that are used independent of the datastructure (concerned mostly with propositional logic).

The next class of simplifier rules is datastructure dependent, and given explicitly by the user,while working on a specification. The first class is given by marking some theorems of the specifi-cation with the command “Simplifier – Add Simplifier Rules” or “Simplifier – Add Local SimplifierRules”.

Theorems which are local simplifier rules are used when proving (other) theorems over thesame specification, in which the theorem is defined. Theorems which are declared as simplfierrulesare used when proving in superspecifications of the specification, in which they are defined.This distinction is useful to use axioms like extensionality only locally in proofs of other theorems,which are then used (globally) as simplifier rules.

Theorems which can be declared to be simplfier rules must have one of several special forms,so that the system is able to generate rules of the sequent calculus from them. The generation ofrules is done uniformly, so if you have verified the theorem, there is a uniform validation for thegenerated rule (which again uses the theorem). The admissible forms for the theorems, and whichrules are actually generated is described in section A.3.

208

Page 210: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 209

The third class of simplifier rules deal are associativity and commutativity axioms (AC). Theyare not used directly, but allow all other simplifier rules to be used modulo AC. AC rules are alsoused by several heuristics and tactics to do matching modulo AC (e.g. when computing proposalsfor instances of quantifiers, when using cut rules (see below), when replacing left hand sides ofequations by right hand sides etc.).

The last class of simplifier rules is called “forward rules”. It is used to add information to asequent, so it is datastructure dependent too. The rules are described in section A.4.

In addition to the simplifier there is an elimination heuristic, which tries to eliminate “bad”function symbols, by trading them for “good” ones. The heuristic and also the “insert elim lemma”is based on “elimination rules”. These are described in the Sect. A.5. Elimination rules are usedlocally and globally (so there are no special local elimination rules).

Finally there are the two heuristics weak cut and cut, which apply the cut rule on goals. Theseare based on cut rules, which are explained in the last section. Cut rules may be local or global.

The following conventions apply to the sections below:

• Γ, Δ, Γ1, . . . are (possibly empty) sets of formulas,

• ϕ,ψ, χ are formulas

• σ, τ , ρ are terms

A.2 datastructure independent simplification rules

The following datastructure independent simplifier rules are used:

• the usual axiom of the sequent calculus

• all basic rules of the sequent calculus, that eliminate junctors

• rules that eliminate the constants ‘true’ and ‘false’.

• rules, that eliminate reflexive equations.

• two rules for eliminating all-quantifiers in the sucedent and existential quantifiers in theantecedent by inserting new variables

• rules, that try to eliminate equations x = τ (or τ = x) in the antecedent. For every suchequation, where x does not occur in the variables of τ , the rule tries to eliminate the equationby substituting τ for x in the rest of the sequent. Since substitution is not possible on allprogram formulas, the rule is not always applicable.

• rules, that minimize the scope of quantifiers, such as (x �∈ Free(ψ))

∀ x.(ϕ(x) → ψ) (∃ x.ϕ(x)) → ψ

• rules, that eliminate redundant quantifiers, such as (x �∈ Vars(τ))

∃ x.(x = τ ∧ ϕ) ϕ[x ← τ ]

A.3 Rules generated from theorems

Theorems which may be used to generate simplifier rules have the following general form

Γ ψ1 ∧ . . . ∧ ψn → ϕ

n must be ≥ 0, for n = 0 the implication is omitted. Depending on the form of ϕ, the rule isin one of four classes:

Page 211: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 210

• If ϕ is an equation, then the rule is a rewrite rule.

• If ϕ is an atomic formula, but no equation, then the rule is an axiom rule.

• If ϕ is an equivalence then the rule is an equivalence rule

• If ϕ is an implication, then the rule is a implication rule

To avoid conflicts in the last case, n is not allowed to be 0 there. Instead, we allow in the casen = 1 ψ1 to be true. All rules come with applicability conditions, which are the formulas in Γ andψ1, . . . , ψn. Those in Γ must be proved, the others must be present in the sequent. Applicabilityconditions should be put in the antecedent, if goals often contain stronger conditions which implythe condition (e.g. instead of a condition x �= y we often have the stronger conditions x < y or y< x in the sequent). Otherwise they should only be put in the preconditions (this is likely to bethe case for e.g. li �= nil).

The four classes of rules are described in the following subsections. We will use the followingnotations:

• an atomic formula is either a predicate or an equation

• a literal is either ϕ or ¬ ϕ for a atomic formula ϕ

• An atomic formula is in a sequent, if it is in the succedent of the sequent

• A negated atomic formula ¬ ϕ is in a sequent, if ϕ is in the antedent of the sequent

• For an atomic formula ∼ ϕ is ¬ ϕ, for a literal ¬ ϕ, ∼ ϕ is ϕ

Rewrite Rules

Rewrite rules are of the form:

Γ ψ1 ∧ . . . ∧ ψn → σ = τ

where σ must not be a variable or a constant. ψ1, . . . , ψn must be literals. The variables ofthe theorem must be a subset of x = Vars(ψ1, . . . , ψn, σ).

The variables of τ must be a subset of those in σ (remark: this restriction may be dropped inthe future). The rule rewrites instances of the term σ by instances of the term τ . Formally, therule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ] with domain x as abovesuch that

• σ[x ← ρ] is a term of the sequent contained in some formula ϕ

• ψ1[x ← ρ], . . . , ψn[x ← ρ] are contained in the sequent

• Γ′ Δ, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ without ϕ.

If the rule is applicable, it replaces all occurences of σ[x ← ρ] in ϕ by τ [x ← ρ]Example: pop(push(a,x)) = x

Example: ¬ x = 0 x -1 +1 = xExample: ¬ li = nil → length(cdr(li)) = pred(length(li))Pragmatics: These rules are mainly used to do term rewriting. τ should be ‘simpler’ than σ.Most rewrite rules are either used to eliminate applications of selectors and defined functions toconstructor terms (first two examples), or to move such selectors and defined functions “inwards”(last example)

Page 212: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 211

Axiom Rules

Γ ψ1 ∧ . . . ∧ ψn → ϕ

where ϕ is a literal, but not an equation. ψ1, . . . , ψn must be literals. The variables of thetheorem must be a subset of x = Vars(ψ1, . . . , ψn, ϕ). The rule closes sequents containing ϕ andeliminates ∼ ϕ from sequents containing it.

Formally the the rule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ]with domain x as above such that

• ϕ[x ← ρ] or ∼ ϕ[x ← ρ] is contained in the sequent

• ψ1[x ← ρ], . . . , ψn[x ← ρ] are contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ withoutϕ[x ← ρ]

If the rule is applicable, it removes all occurences of ∼ ϕ[x ← ρ] from the sequent, resp. closesthe goal, if ϕ[x ← ρ] is contained in it.

Example: ¬ 0 = x +1Example: ¬ x = x +1Example: ¬ member(x,delete(x,set))Example: 0 ≤ xExample: x ≤ xExample: ¬ x +1 ≤ xPragmatics: These rules are mainly used to separate different constructor terms (first two exam-ples) or two specify when a predicate is true or false.

Equivalence Rules

Equivalence rules have one of the four forms, which will be described in the following subsections

Succedent Equivalence Rules

A succedent equivalence rule has the form

Γ ψ1 ∧ . . . ∧ ψn → (¬ ϕ ↔ χ)

where ϕ is an atomic formula. ψ1, . . . , ψn must be literals. The variables of the theorem mustbe a subset of x = Vars(ψ1, . . . , ψn, ϕ). The rule replaces instances of ϕ in the succedent by χ.

Example: x �= y → ¬ y < x ↔ x < yExample: ¬ x = true ↔ x = falseExample: ¬ x = false ↔ x = true

Pragmatics: Used in cases, where we do not want the full equivalence rule (with ϕ ↔ ∼ χinstead of ¬ ϕ ↔ χ) Such cases occur, if the idea of a rule is to prefer some non-negated literalto an (under the sideconditions) equivalent negated literal. An obvious example is the first, wherethe nonnegated form allows to remove the sidecondition x �= y and the full equivalence rule wouldlead to an infinite loop. The second and third example produces only positive boolean equationsin the antecedent. If we woud use the equivalence rule x = false ↔ ¬ x = true instead, we wouldget ¬ x = true in the antecedent instead of x = false.

Antecedent Equivalence Rules

An antecedent equivalence rule has the form

Γ ψ1 ∧ . . . ∧ ψn → (¬ ¬ ϕ ↔ χ)

Page 213: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 212

where ϕ is an atomic formula. ψ1, . . . , ψn must be literals. The variables of the theorem mustbe a subset of x = Vars(ψ1, . . . , ψn, ϕ). The rule replaces instances of ϕ in the antecedent by χ.

Pragmatics: Same as in the previous case, but we prefer the negated literal to the positive(rarely used).

Conjunctive Equivalence Rules

A conjunctive equivalence rule has the form

Γ ψ1 ∧ . . . ∧ ψn → (ϕ ↔ χ1 ∧ . . . ∧ χm)

where ϕ is an atomic formula. ψ1, . . . , ψn must be literals. The variables of the theorem mustbe a subset of x = Vars(ψ1, . . . , ψn, ϕ). The rule does two things: First, it removes occurences of(instances of) ∼ ϕ an adds instead χ1, . . . , χn to the antecedent. Second if for some i, (instances of)the formulas ψ1, . . . , ψn, ϕ,∼ χ1, . . . ,∼ χi−1,∼ χi+1, . . . ,∼ χm are all contained in the sequent,then ϕ is replaced by χi

Formally the the rule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ]with domain x as above such that either

• ∼ ϕ[x ← ρ] is contained in the sequent

• ψ1[x ← ρ], . . . , ψn[x ← ρ] are contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ without∼ ϕ[x ← ρ]

or there is an 1 ≤ i ≤ m, such that

• χ1, . . . , χi−1, χi+1, . . . , χm are literals

• ϕ[x ← ρ] is contained in the sequent

• ψ1[x ← ρ], . . . , ψn[x ← ρ] are contained in the sequent

• ∼ χ1[x ← ρ], . . . , ∼ χi−1[x ← ρ], ∼ χi+1[x ← ρ], . . . , ∼ χm[x ← ρ] are contained inthe sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ withoutϕ[x ← ρ]

In the first case ∼ ϕ[x ← ρ] is removed and χ1[x ← ρ], . . . , χn[x ← ρ] are added to theantecedent. In the second case ϕ[x ← ρ] is replaced by χi[x ← ρ]

Example: x -1 +1 = x ↔ ¬ x = 0Example: primefactorlist(x) = primefactorlist(y) ↔ x = yExample: x ≤ y → (y ≤ x ↔ x = y)Example: p(x) = y ↔ x = s(y) (where ‘s’ and ‘p’ are successor and predecessor on integers)Example: ¬ x = 0 ∧ ¬ y = 0 → (pred(x) = pred(y) ↔ x = y)Example: zerop(x) ↔ x = 0Example member(x,delete(y,set)) ↔ ¬ x = y ∧ member(x,set)Pragmatics:

These rules are used in all cases, where a formula ϕ is equivalent to a simpler formula χ (undersome conditions). Sometimes χ is a conjunction as in the last example. Consider the last one:Here we want to replace member(x,delete(y,set)) in the antecedent by the two simpler formulas ¬x=y and member(x,set). But normally we do not want the same thing in the succedent to happen(since we would get a conjunction in the succedent which leads to a case distinction). Instead wewant to replace member(x,delete(y,set)) in the succedent by x=y if we have member(x,set) in thesuccedent too (since under the condition ¬ member(x,set) member(x,delete(y,set)) is equivalent

Page 214: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 213

to the x = y). Similarly we want member(x,delete(y,set)) in the succedent to be replaced bymember(x,set) if we have x = y in the succedent. These three cases are covered by the rule. Ifyou really want to introduce the conjunction use

member(x,delete(y,set)) ↔ ¬ ¬ (¬ x = y ∧ member(x,set))

Disjunctive Equivalence Rules

A disjunctive equivalence rule has the form

Γ ψ1 ∧ . . . ∧ ψn → (ϕ ↔ χ1 ∨ . . . ∨ χm)

where ϕ is an atomic formula. ψ1, . . . , ψn must be literals. The variables of the theorem mustbe a subset of x = Vars(ψ1, . . . , ψn, ϕ).

The rule does two things: First, it removes occurences of (instances of) ϕ an adds insteadχ1, . . . , χn to the sucecedent. Second if for some i, (instances of) the formulas ∼ ψ1, . . . ,∼ ψn,∼ϕ, χ1, . . . , χi−1, χi+1, . . . , χm are all contained in the sequent, then ∼ ϕ is replaced by ∼ χi

Formally the the rule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ]with domain x as above such that either

• ϕ[x ← ρ] is contained in the sequent

• ∼ ψ1[x ← ρ], . . . , ∼ ψn[x ← ρ] are contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ withoutϕ[x ← ρ]

or there is an 1 ≤ i ≤ m, such that

• ∼ χ1, . . . ,∼ χi−1,∼ χi+1, . . . ,∼ χm are literals

• ∼ ϕ[x ← ρ] is contained in the sequent

• ∼ ψ1[x ← ρ], . . . , simψn[x ← ρ] are contained in the sequent

• χ1[x ← ρ], . . . , χi−1[x ← ρ], χi+1[x ← ρ], . . . , χm[x ← ρ] are contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ without∼ ϕ[x ← ρ]

In the first case ϕ[x ← ρ] is removed and ∼ χ1[x ← ρ], . . . , ∼ χn[x ← ρ] are added to theantecedent. In the second case ∼ ϕ[x ← ρ] is replaced by ∼ χi[x ← ρ]

Example: member(x,insert(y,set)) ↔ x=y ∨ member(x,set))

Pragmatics:

Same as for Conjunvctive Case. Here ϕ is equivalent to a disjunction instead of a conjunction(or equivalently ¬ ϕ is equivalent to a conjunction).

Implication Rules

Implication rules rules have the form

Γ ψ1 ∧ . . . ∧ ψn → (ϕ → χ)

where ϕ is a literal. ψ1, . . . , ψn must be literals. The variables of the theorem must be a subsetof x = Vars(ψ1, . . . , ψn, ϕ). The rule removes occurences of (instances of) ∼ ϕ in the sequent andadds χ instead.

Formally the rule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ] withdomain x as above such that either

Page 215: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 214

• ∼ ϕ[x ← ρ] is contained in the sequent

• ψ1[x ← ρ], . . . , ψn[x ← ρ] are contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ without∼ ϕ[x ← ρ]

Then the rule removes ∼ ϕ[x ← ρ] from the sequent and adds χ[x ← ρ] to the antecedentExample: ¬ pred(x)=x → ¬ x = 0

Example: subtree(t,right(t)) → t=emptytreeExample: regexp-less(r,alt1(r)) → ¬ altp(r) (from the LEX-Example, regexp-less is the term-order on regular expressions, altp tests r for being a regexp with two alternatives, alt1 selects thefirst)Pragmatics: These rules are mainly used in two cases. In the first, ϕ is equivalent to ϕ, but weonly want to replace ϕ in the antecedent by ψ. The other case is, when ϕ is “nearly equivalent”to ψ, i.e. if ϕ implies ψ, and the reverse implication would hold, if an additional axiom foran underspecified function or predicate would be added. Typical such “additional axioms” areaxioms for selector applications on the wrong summand in data specifications (like 0 -1 = 0 orleft(emptytree) = emptytree as in the first two examples). The cases, where ϕ is not equivalentto χ are dangerous to use, since simplifier rules like x + y < z → y < z (e.g. to prove that x+ y < z, ¬ y < z is valid), are not invertible (i.e. the conclusion does not imply the premise).Non invertible rules lose information, that may be necessary in other cases (e.g. in (0 +1) + y <z, y +1 = z applying the simplifier rule above would yield y < z, y +1 = z , which is nolonger provable). Therefore they should be avoided.

A.4 Forward rules

Forward rules are used to add information to sequents. They have the form:

Γ ϕ → ψ

where ϕ is a conjunction of literals and ψ is an arbitrary first order formula. All free variablesx of the sequent must be contained in the free variables of ϕ. The rule adds instances of ψ to thesequent, if ϕ and Γ can be proved.

Formally the rule is applicable to a sequent Γ′ Δ′ if there is a substitution [x ← ρ] withdomain x as above such that

• ϕ[x ← ρ] is contained in the sequent

• Γ′′ Δ′′, ∧ Γ[x ← ρ] is provable by the simplifier, where Γ′′ Δ′′ is Γ′ Δ′ withoutϕ[x ← ρ]

Then the rule adds ψ[x ← ρ] to the sequent, if it has not already been added in the currentbranch of the proof.Pragmatics: The rule is typically used to compute the closure of transitive relationsExample: x < y ∧ y < z → x < zExample: x ≤ y ∧ y < z → x < zand to derive weaker formulas from stronger ones (e.g. to establish preconditions for rewrite rules).Example: succ(x) < y → x < yOne should be careful not to use the same rule as a forward rule and as an axiom rule. Otherwisethe added formula will immediately be removed by the axiom rule.

Page 216: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 215

A.5 Elimination rules

Elimination rules try to eliminate “bad” function symbols such as ‘-1’,‘-’,‘car’ and ‘cdr’,‘delete’for “good” ones (in the examples the good function symbols are ‘+1’,‘+’,‘cons’,‘insert’). This isdone by replacing a term like ‘x -1’ or ‘x - y’ by a new variable z and replacing ‘x’ by ‘z +1’ resp.‘z + y’. The rule produces appropriate side conditions, while the heuristic tries to prove (or find)these conditions to be applicable. The heuristic and the rule are based on elimination rules of thefollowing form:

Γ ϕ → (x1 = t1 ∧ . . . ∧ xn = tn ↔ ∃ y.v = t ∧ ψ)where ϕ is a conjunction of literals and ψ is an arbitrary first order formula. For every i, the

variables of the sequent are contained in the two disjoint sets Vars(ti) and {x1, . . . , xn}. v, x1,. . . , xn are pairwise different variables. The variables y are not free in the sequent. v does notoccur in ψ or t (but in every ti). x1, . . . , xn do not occur in ϕ or Γ. The precondition ϕ and thesideformula ψ are optional.Example: x �= 0 → ( x = y -1 ↔ y = x +1 )Example: ¬ x < y → z = x - y ↔ x = z + y)Example: x �= nil ( a = car(x) ∧ y = cdr(x) ↔ x = cons(a,y))Example: x �= nil ( y = cdr(x) ↔ ∃ a. x = cons(a,y) ∧ a = car(x)) (eliminates only cdr,not car)Example: b �= 0 ( k = x div b ∧ r = x mod b ↔ x = k * b + r ∧ r < b)Example: x ∈ set → ( set’ = delete(x,set) ↔ set = insert(x,set’) ∧ ¬ x ∈ set’)Example: prodp(x) → ( x1 = sel1(x) ∧ . . . ∧ xn = seln(x) ↔ x = mkprod(x1,. . . ,xn))where mkprod and prodp are constructor and predicate of a product type, sel1, . . . , seln are theselectors of its factorsExample: set �= ∅ → set’=butmin(set) ↔ ∃ x. set=insert(x,set’) ∧ ∀ y. y ∈ set’ → x< yExample: n = m mod2ˆ d ↔ ∃ k. m = k * 2ˆ d + r ∧ r < d

The elimination rule tries to find a substitution σ, such that σ(ti) is in the sequent, σ(v) is avariable, and all variables in ti are instantiated to terms with disjoint variables (we do not considerterms like ‘x div x’, ‘(y - z) div x’ or ‘x div (x - y)’ in the sequent, but we do consider ‘x div y +z’)). If such a substitution can be found, there is also a variant, which renames x1, . . . , xn andy (these are exactly all other variables in the rule) to new variables relative to the sequent underconsideration. Then it creates a sidegoal, in which Γ and ϕ must be proved (the heuristic mustfind the literals of ϕ in the sequent and must prove Γ). The main goal of the rule is then createdby first replacing every σ(ti) by σ(xi), then substituting σ(t) for σ(v) and finally adding σ(ψ). So,if the substitution is empty, the proof tree created looks like:

Γ′ Δ′, ϕ ∧ ∧ Γ ψ,Γ′[t ← x][v ← t] Δ′[t ← x][v ← t]

Γ′ Δ′

Examples (sidegoals are trivial, hence omitted)

b �= 0, r < b ϕ(k ∗ b + r, b, r, k)

b �= 0 ϕ(a, b, amodb, adivb)

cons(a, y) �= nil ϕ(a, y, cons(a, y))x �= nil ϕ(car(x), cdr(x), x)

¬ z + y < y ϕ(z, z + y, y)

¬ x < y ϕ(x− y, x, y)

x ∈ insert(x, set′),¬ x ∈ set′ ϕ(insert(x, set′), set′)x ∈ set ϕ(set, del(x, set))

Page 217: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX A. SIMPLIFIER RULES 216

insert(x, set′) �= ∅, ∀ y.y ∈ set′ → x < y ϕ(insert(x, set′), set′)set �= ∅ ϕ(set, butmin(set))

r < 2ˆn ϕ(k ∗ 2ˆn + r, r)

ϕ(m,mmod2ˆn)

Several examples show, that elimination may produce redundant formulas. The redundantformulas are always some of the instances of preconditions in ϕ or Γ. We could have formulatedelimination rules, such that these redundant formulas would be eliminated (by moving them tothe right side of the equivalence), but then we would not have had the choice if side conditionsshould be found by matching or by proof. In the first (third) example, a (x) must be a variable,while b (y) may be an arbitrary term.

A.6 Cut rules

The weak cut and the cut heuristic apply the cut rule with a literal ϕ, which is computed by usingthe information present in cut rules. Cut rules must have one of the four forms

•ϕ ∧ ϕ1 ∧ . . . ϕn → σ = τ

where ϕ is a literal with free variables contained in the variables of σ.

•ϕ ∧ ϕ1 ∧ . . . ϕn → ψ

where ψ must be a literal. The free variables of ϕ must be a subset of free(ψ)

•ϕ ∧ ϕ1 ∧ . . . ϕn → ψ ↔ χ

where ψ must be a literal. The free variables of ϕ must be a subset of free(ψ)

•ψ ↔ ϕ ∧ ϕ1 ∧ . . . ϕn

where ψ is a literal, and free(ϕ) ⊆ free(ψ)

All forms cause a cut with an instance Θ(ϕ) of ϕ. For the first form the cut is done, if Θ(σ) isa free term (i.e. none of it’s variables are bound) of the sequent. For the other forms a cut is done,if Θ(ψ) is a free literal that occurs in the sequent. In the second case the cut is done regardless ofwhether the literal is in the antecedent or in the succedent.

The weak cut heuristic computes the set of all possible cut formulas according to the cut rules.Reflexive equations, literals already present on the toplevel of the current goal and all literals withwhich a cut has already been done are excluded from this set. One of the most often computedformulas from this set is then chosen for the aplication of the cut tactic. The cut heuristic computesthe same set of potential cut formulas, but additionally adds all literals, which are present in thesequent, but not on top-level (e.g. a literal ϕ1 in an antecedent formula ϕ1 ∨ ϕ2 is added). Againthe most often computed formula is chosen.

Page 218: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix B

Mixfix Notation and Overloading

In this section we will use the symbols c for a constant with sort s,f for a function with argumentsorts s1, . . . sn and target sort s’, and p for a predicate with argument sorts s1, . . . sn (the targetsort is bool).

B.1 Classification of operations

KIV allows the following classes of operations:

• usual operations

• postfix operations

• prefix operations

• infix operations

• methodfix operations

• outfix operations

• outinfix operations

• outprefix operations

• outpostix operations

A symbol is of one of the last four classes, if and only if it starts with one of the “closingbracket” characters ,, *, }, ], ]] or �. It is then called an outfix symbol. For each closing bracketcharacter, there is the corresponding “opening bracket”: ", !, {, [, [[ and �. Closing bracketcharacters cannot be used otherwise in symbols (opening bracket characters cannot be used insymbols at all). Note that the symbol ] alone is reserved for program formulas.

So “×a” can only be an operation of one of the first four classes, while “}abc” alwas belongsto one of the last four classes.

Infix operations have one of the priorities “1 left”, “1 right”, “2 left”, . . . , “15 left”,“15 right”.

B.2 Overloading

Operations from each of the eight classes can be overloaded only with operations of the same class.Two infix operations can be overloaded only if they have the same priority. When an operation isoverloaded and used in a place, where its type cannot be inferred, it is always possible to clarifywhich type is intended by writing “c :: s”, “f :: (s1×. . .×sn → s′)”, or “p :: (s1×. . .×sn → bool)”instead.

217

Page 219: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 218

B.3 Generalities on Usage

Operations are used in five places:

• declaration in the signature

• usage of functions and predicates in formulas

• on the right hand side of a renaming in morphisms

• in a generated by-clause

• on both sides of a renaming of an operation

The following sections will define the syntax for each class of operations and each of the firstthree places. In generated-by-clauses and on the left hand side of equations, outfix symbols arealways paired with their opening bracket (with a space in the middle). Otherwise just the symbolis written. As an example

set generated by { }, ∪

is a correct generated by clause (where the outfix symbol “}” has been paired with the openingbracked “{”).

Some other general remarks:

• In declarations it is always possible to use a comma instead of “×”as the separator betweensorts.

• Usually the right hand side of a renaming gets the same type (and priority) as the left handside. When the left hand side is an outfix symbol, but the right hand side is not, then as adefault the right hand side is a usual operation.

• ∧ , ∨ , → , ↔ are infix operations with prio 4 right,3 right,2 right and 1 right.

• ¬ is a prefix predicate, equality is an infix operation of priority 5 right.

• The strength of binding is (form strong to weak): usual application, postfix function, prefixfunction, infix operation with priority 15 (associative to the left or right),14, . . . , infixoperation with priority 5, equality, postfix predicate, prefix predicate, infix operation withpriority 4, . . . , infix operation with priority 1.

• Note that quantifiers (and lambda expressions) do not care about binding strength. Theyalways bind to the farthest right as possible.

B.4 Usual Operations

Usual operations can be constants or functions or predicates (with any number of arguments).

Declaration

constants c : s;functions f : s1 × . . .× sn → s’;predicates p : s1 × . . .× sn;

Usage Usual applications are written f(t) and p(t).

Page 220: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 219

Renaming If the left hand side of a renaming is a postfix, prefix, methodfix or infix operation,but the right hand side should be a usual operation, then at the right hand side a “prio 0” mustbe added. For example

∪ → union prio 0;

is a correct renaming of the infix operation “ ∪ ” to the usual operation “union”.

B.5 Postfix Operations

A postfix operation can only be a function or a predicate with one argument. Often postfixoperations start with a dot.

Declaration Postfix declarations are written with a dot before the operation symbol

functions . f : s1 → s′;functions . .sel : s1 → s′;predicates . p : s1;

Usage Postfix application is written t f, t.sel and t p.

Renaming If the left hand side of a renaming is not a postfix operation, but has one argument,and the renamed symbol should be postfix, then at the right hand side a dot must be added beforethe symbol. For example

succ → . +1;

is a correct renaming of the usual operation “succ” to the postfix operation “+1”.

B.6 Prefix Operations

A prefix operation can only be a function or a predicate with one argument. The symbol # isoften used as a prefix size function.

Declaration Prefix declarations are written with a dot after the operation symbol

functions f . : s1 → s′; # . : s → nat; predicates p . : s1;

Usage Prefix application is written f t, # t and p t.

Renaming If the left hand side of a renaming is not a prefix symbol, but has one argument, andthe renamed symbol should be prefix, then at the right hand side a dot has to be added behindthe symbol. For example

size → # .

is a correct renaming of the usual operation “size” to the prefix operation “#”.

Page 221: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 220

B.7 Methodfix Operations

Methodfix operations are used to imitate object oriented method calls, where the first argumentis before the function, and the other arguments are written behind the function in brackets. InOO languages, a dot is used to separate the first argument and the function. The separating dotis unnecessary here, but usually the function name starts with a dot (note that a space must beused between the first argument and the function symbol, if the function does not start with adot).

Declaration Methodfix declarations are written with a dot after the operation symbol

functions . .f ( . ) : s1 × s2 × s3 → s′; predicates . .p ( . ) : s1;

Usage Methodfix application is written e1.f(e2,e3) and e1.p().

Renaming If the left hand side of a renaming is not a methodfix symbol, and the renamedsymbol should be methodfix, then the right hand side has a dot before the symbol, and a dot inbrackets behind it. For example

f → . .f ( . );

is a correct renaming of the usual operation “f” to the methodfix operation “.f”.

B.8 Infix Operations

A infix operation can only be a function or a predicate with two arguments. An infix operationhas a priority from“1 left”, “1 right”, “2 left”, . . . , “15 left”,“15 right”. The number determinesthe binding strength (the higher the stronger is the binding). “right” signals a right-associativeoperation like conjunction (x ∧ y ∧ z is the same as x ∧ (y ∧ z)), a negative a left-associativeoperation (like subtraction “−”in the library).

Declaration Infix declarations are written with a dot before and after the operation symboland a prio n left or prio n right at the end of the declaration. The default priority is “9 right”.The “right” at the end can be omitted.

functions . f . : s1 × s2 → s′ prio n left; predicates . p . : s1 × s2 prio n;

Usage Infix application is written t1 f t2 and t1 p t2. Note that a space is needed between thearguments and the function symbol (except when the arguments are in brackets).

Renaming If the left hand side of a renaming is not an infix symbol, but has two arguments,and the renamed symbol should be infix, then at the right hand side a dot has to be added beforeand after the symbol and a priority may be given (like in a declaration) For example

sub → . − . prio 9 left; add → . + . ;

are correct renamings.

Page 222: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 221

B.9 Outfix Operations

An outfix operations has one argument.

Declaration Outfix operations are declarated by giving the opening bracket, then a dot andthen the operation symbol:

functions { . }s : s1 → s′; predicates { . }p : s1 (: a predicate testing theargument to be a one-element set :) ;

Usage Application of an outfix symbol is written opening bracket, argument, operation symbollike in “{a}s”. Note that in a formula you do not need to add space before or after the openingbracket or before the operation symbol. Space is only needed behind the operation symbol.

Renaming If the left hand side of a renaming has one argument, and should be renamed to anoutfix operation write opening bracket, dot, operation symbol on the right hand side.

For example

elemtoset → { . }

is a correct renaming.

B.10 Outinfix Operations

An outinfix operation always has two arguments. Outinfix operations are often used as construc-tors for pairs.

Declaration Outinfix operations are declarated by giving the opening bracket, then a dot, acomma, another dot and then the operation symbol:

functions " . , . ,x : s1 × s2 → s′;

Usage Application of an outinfix symbol is written opening bracket, first argument, operationsymbol like in “" a, b, x”. Note that in a formula you do not need to add space before or afterthe opening bracket or before the operation symbol. Space is only needed behind the operationsymbol.

Renaming If the left hand side of a renaming has one argument, and should be renamed to anoutinfix operation write opening bracket, dot, comma, dot, operation symbol on the right handside:

For example

mkpair → [ . , . ]p

is a correct renaming.

Page 223: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 222

B.11 Outprefix Operations

An outprefix operation has at least two arguments. Outinfix operations are often used to apply afunction to arguments, as array selectors or as array modifiers.

Declaration Outprefix operations are declared by giving a dot, the opening bracket, then a dot,and finally the operation symbol:

functions . [ . ]s : s1 × s2 × . . . sn → s′;

Note that only one dot is used between the brackets, regardless how many arguments theoutprefix operation has.

Usage Application of an outprefix symbol is written first arguments, opening bracket, remainingarguments separated with comma, and finally operation symbol like in “f " a, b,x”. Note that in aformula you do not need to add space before or after the opening bracket or before the operationsymbol. Space is only needed behind the operation symbol.

There is a special rule for using outprefix symbols in assignments:Instead of writing f := f" t1, t2, . . . tn, tn + 1,x it is possible to write f" t1, t2, . . . tn,x :=

tn + 1, if the operation “,x is overloaded to have type s1 × s2 × . . . sn → sn+1 → s1 and types1 × s2 × . . . sn → sn+1. Usually s1 will be an array sort (or a dynamic function), the overloadedfunction of the first type is an array modifier (or a modification operation for dynamic functions),the second an array selector (or application of a dynamic function).

Renaming If the left hand side of a renaming has one argument, and should be renamed toan outprefix operation write dot, opening bracket, dot operation symbol on the right hand side(again only one dot between the brackets, regardless how many arguments the function has).

For example

update-array → . [ . ]p

is a correct renaming.

B.12 Outpostfix Operations

An outpostfix operations has two or more arguments. The second and all other arguments arewritten (separated by commas) in between the brackets.

Declaration Outpostfix operations are declarated by giving a dot, the opening bracket, anotherdot and then the operation symbol:

functions [[ . ]] s : s1 × s2 → s′; predicates { . }p . : s1 × s2;

Only one dot between the brackets is used, even if the operation has more than two arguments.

Usage Application of an outpostfix symbol is written opening bracket, first argument, operationsymbol, second argument like in “[[ a]] s v”. Note that in a formula you do not need to add spacebefore or after the opening bracket or before the operation symbol. Space is only needed behindthe operation symbol. The program formulas of Dynamic Logic are like outpostfix operations.

Page 224: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX B. MIXFIX NOTATION AND OVERLOADING 223

Renaming If the left hand side of a renaming has two arguments, and should be renamed toan outpostfix operation write dot, opening bracket, dot, operation symbol on the right hand side.

For example

eval → . [[ . ]]

is a correct renaming.

B.13 Some examples

The following examples of expressions give the expressions without brackets, and with full brack-eting. They use infix operations ‘+’ and ‘*’ of priorities ‘9 right’ and ‘10 right’, a postfix function‘+1’, a prefix function ‘#’, and a postfix predicate ‘evenp’. Also the predefined operations = (infixwith prio 5 right), ∧ (infix with prio 4 right), ∨ (infix with prio 3 right), → (infix with prio2 right), ↔ (infix with prio 1 right), ¬ (prefix predicate) are used.

# n +1 ≡ #(n +1)# m + n ≡ (# m) + n# n +1 ≡ #(n +1)# m + n ≡ (# m) + nf(n) +1 ≡ (f(n)) +1m + n evenp ≡ (m + n) evenpm ∧ k evenp ≡ m ∧ (k evenp)# m evenp ≡ (# m) evenpx + y + z ≡ x + (y + z)x * y + x ≡ (x * y) + xx + y +1 ≡ x + (y +1)# x +1 ≡ #(x +1)# x + x ≡ (# x) + x¬ x ∧ y ≡ (¬ x) ∧ y(x → y ⊃ ¬ z; y ↔ z) ≡ ((x → y) ⊃ (¬ z); (y ↔ z))∀ x. f(x) ∧ g(x) ≡ ∀ x. (f(x) ∧ g(x)) but (∀ x. f(x)) ∧ g(x)

Page 225: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix C

Syntax of Dynamic Logic

This grammar of the PPL parser uses the following assumptions described:

1. The start symbol is ‘start’.

2. Terminals are written in bold.

3. Pseudoterminals are written in italics. There are three kinds: PPL-Variables (which startwith a backquote), meta variables (which start with a $) and other symbols. In the lasttwo cases the lexical analysis returns a token, depending on the entry of the symbol in thecurrent signature. If the symbol has no entry the pseudoterminal returned is sym. Otherwiseit may be sort, xov, fct, proc, praefixfct, praefixprd, postfixfct, postfixprd or infixfct{l‖r}i.

4. In priorities “right” may be omitted.

5. [ . . . ] means: is optional.

6. {. . .}∗ means: repeated any times (even 0 times)

7. {. . .}+ means: repeated at least one time.

8. {. . . //sep}∗ means: repeated any times, separated by sep.

9. {. . . //sep}+ means: repeated any times, separated by sep.

10. {. . . | . . .}+ means: alternative.

11. Superscript index i is always in {0 . . . 4, 6 . . . 15}

term : term1 [ite term ; term ];

start : expr| prog 2| sorts {sym // , }+ ;| constants defconstlist aux| functions {deffct }+| predicates {defprd }+| defvarlist| defproclist| procdeclmv| vlmv| vdlmv| flmv

224

Page 226: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 225

| sort| fct| proc

| [ ]| [ {proc // , }+ ]| [ {fct // , }+ ]| [ {expr nonppl // , }+ ]| [ expr nonppl | expr nonppl ]| . vl .;

crosscomma : ×| ,;

symorplusorstern : sym| +| ∗;

sym : symbol| specialsymbol;

extsymorplusorstern : extsym| +| ∗;

extsym : extsymbol| specialsymbol;

specialsymbol : →| <

| >

| ×| in;

pplvarassym : symbol| in;

string1 : symbol1| ×| in| ∀| ∃| <

| >

| →;

string : sort| string1;

symbol : sort| symbol1;

extsymbol : sort| extsymbol1

Page 227: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 226

;symbol1 : regsymbol

| outsymbol;

extsymbol1 : regsymbol| extoutsymbol;

regsymbol : infixfctri

| infixfctli

| const| xov| fct| postfixfct| praefixfct| postfixprd| praefixprd| infixfctl10| infixfctl11| infixfctl12| infixfctl13| infixfctl14| infixfctl15| proc| sym;

outsymbol : rceiloutfct| rceiloutinfct| rceiloutprefct| rceilsym| rflooroutfct| rflooroutinfct| rflooroutprefct| rfloorsym| rsemoutfct| rsemoutinfct| rsemoutprefct| rsemsym| rquineoutfct| rquineoutinfct| rquineoutprefct| rquinesym| rgeschwoutfct| rgeschwoutinfct| rgeschwoutprefct| rgeschwsym| rceiloutpostfct| rflooroutpostfct| rquineoutpostfct| rgeschwoutpostfct| rsemoutpostfct| reckigzuoutpostfct| reckigzusym

| ]

Page 228: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 227

;extoutsymbol : ! rceiloutfct

| ! rceiloutinfct| ! rceiloutprefct| ! rceilsym| " rflooroutfct| " rflooroutinfct| " rflooroutprefct| " rfloorsym| [[ rsemoutfct| [[ rsemoutinfct| [[ rsemoutprefct| [[ rsemsym| � rquineoutfct| � rquineoutinfct| � rquineoutprefct| � rquinesym| { rgeschwoutfct| { rgeschwoutinfct| { rgeschwoutprefct| { rgeschwsym| ! rceiloutpostfct| " rflooroutpostfct| � rquineoutpostfct| { rgeschwoutpostfct| [[ rsemoutpostfct

| [ reckigzuoutpostfct| [ reckigzusym| [ ];

infixfct : infixfctl1| infixfctl2| infixfctl3| infixfctl4| infixfctl5orgreater| =

| infixfctl6| infixfctl7| infixfctl8| infixfctl9| infixfctl10| infixfctl11| infixfctl12| infixfctl13| infixfctl14| infixfctl15| infixfctr1| infixfctr2| infixfctr3| infixfctr4| infixfctr5| infixfctr6| infixfctr7

Page 229: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 228

| infixfctr8| infixfctr9| infixfctr10| infixfctr11| infixfctr12| infixfctr13| infixfctr14| infixfctr15;

fctnonpraefix : fct| infixfct| postfixfct| postfixprd;

fct : fctnonpraefix| praefixfct| praefixprd| ∗;

extfct : fctnonpraefix| praefixfct| praefixprd| ∗| ! rceiloutfct| ! rceiloutinfct| ! rceiloutprefct| ! rceilsym| " rflooroutfct| " rflooroutinfct| " rflooroutprefct| " rfloorsym| [[ rsemoutfct| [[ rsemoutinfct| [[ rsemoutprefct| [[ rsemsym| � rquineoutfct| � rquineoutinfct| � rquineoutprefct| � rquinesym| { rgeschwoutfct| { rgeschwoutinfct| { rgeschwoutprefct| { rgeschwsym| ! rceiloutpostfct| " rflooroutpostfct| � rquineoutpostfct| { rgeschwoutpostfct| [[ rsemoutpostfct

| [ reckigzuoutpostfct| [ reckigzusym| [ ];

rceilsym : rceiloutfct

Page 230: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 229

| rceiloutinfct| rceiloutprefct| rceiloutpostfct| rceilsym;

rfloorsym : rflooroutfct| rflooroutinfct| rflooroutprefct| rflooroutpostfct| rfloorsym;

rsemsym : rsemoutfct| rsemoutinfct| rsemoutprefct| rsemoutpostfct| rsemsym;

rquinesym : rquineoutfct| rquineoutinfct| rquineoutprefct| rquineoutpostfct| rquinesym;

rgeschwsym : rgeschwoutfct| rgeschwoutinfct| rgeschwoutprefct| rgeschwoutpostfct| rgeschwsym;

reckigzusym : reckigzuoutpostfct| reckigzusym

| ];

var : ppl variable| var nonppl;

var nonppl : xov| const| xmv;

vl : [ppl variable ]| [var , ] vlmv [, {var // , }+ ]| var nonppl| var , {var // , }+ [, vlmv [, {var // , }+ ] ];

expr : ppl variable| expr nonppl;

expr nonppl : expr nonppl1| expn2 ite expr ; expr;

expr5 : expr5a| praefixprd expr5

Page 231: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 230

| boxdiaexpr;

expr nonppl5 : expr5a nonppl| praefixprd expr5| boxdiaexpr;

expr5a : expr5b| expn5a postfixprd;

expr5a nonppl : expr5b nonppl| expn5a postfixprd;

expr5b : expr6| lexpr5| rexpr5;

expr5b nonppl : expr nonppl6| lexpr5| rexpr5;

lexpr5 : lexpn5 infixfctl5orgreater expr6| expn6 infixfctl5orgreater expr6| lexpn5 = expr6| expn6 = expr6| lexpn5 �= expr6| expn6 �= expr6;

infixfctl5orgreater : infixfctl5| >

;infixfctl5 : infixfctl5

| <

;infixfctr2 : infixfctr2

| →;

rexpr5 : expn6 infixfctr5 rexpr5| expn6 infixfctr5 expr6;

infixfctr9 : infixfctr9| +| ×;

infixfctr10orstern : infixfctr10| ∗;

term5 : term5a| praefixprd term5| boxdiaterm;

term5a : term5b| term5a postfixprd;

term5b : expn6

Page 232: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 231

| lterm5| rexpn5;

lterm5 : lterm5 infixfctl5 expn6| expn6 infixfctl5 expn6| lterm5 = expn6| expn6 = expn6;

expn5 : expn5a| praefixprd expn5| boxdiaexpn;

expn5a : expn5b| expn5a postfixprd;

expn5b : expn6| lexpn5| rexpn5;

lexpn5 : lexpn5 infixfctl5orgreater expn6| expn6 infixfctl5orgreater expn6| lexpn5 = expn6| expn6 = expn6| lexpn5 �= expn6| expn6 �= expn6;

rexpn5 : expn6 infixfctr5 rexpn5| expn6 infixfctr5 expn6;

expri : {expri+1 // infixfctli }+| {expri+1 // infixfctri }+;

expni : {expni+1 // infixfctli }+| {expni+1 // infixfctri }+;

termi : {termi+1 // infixfctli }+| {termi+1 // infixfctri }+;

expr nonppli : {expr nonppli+1 // infixfctli }+| {expr nonppli+1 // infixfctri }+;

expr16 : praefixexpr| outpraefixexpr| expr17;

expr nonppl16 : praefixexpr| outpraefixexpr| expr nonppl17;

expn16 : praefixexpn| outpraefixexpn| expn17;

Page 233: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 232

praefixexpr : praefixfct expr16| ∗ expr16| ampersand expr16;

praefixexpn : praefixfct expn16| ∗ expn16| ampersand expn16;

outpraefixexpr : ! expr rceiloutprefct expr16| [[ expr rsemoutprefct expr16| " expr rflooroutprefct expr16| � expr rquineoutprefct expr16| { expr rgeschwoutprefct expr16;

outpraefixexpn : ! expr rceiloutprefct expn16| [[ expr rsemoutprefct expn16| " expr rflooroutprefct expn16| � expr rquineoutprefct expn16| { expr rgeschwoutprefct expn16;

expr17 : expn17 postfixfct| expr18;

expr nonppl17 : expn17 postfixfct| expr nonppl18;

expn17 : expn17 postfixfct| expn18;

expr18 : expn18| allex;

expr nonppl18 : expn nonppl18| allex;

boxdiaexpr : [ progseq nonparasg ] expr5| < progseq nonparasg > expr5;

boxdiaexpn : [ progseq nonparasg ] expn5| < progseq nonparasg > expn5;

boxdiaterm : [ progseq nonparasg ] term5| < progseq nonparasg > term5;

allex : ∃ vl . expr| ∀ vl . expr;

expn18 : ppl variable| expn nonppl18;

expn nonppl18 : exprmv| termmv| xmv

Page 234: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 233

| const| xov| fctnonpraefix ( {expr // , }+ )| expn nonppl18 ! expr rceiloutpostfct| expn nonppl18 [ expr reckigzuoutpostfct| expn nonppl18 [ expr ]| expn nonppl18 " expr rflooroutpostfct| expn nonppl18 [[ expr rsemoutpostfct| expn nonppl18 � expr rquineoutpostfct| expn nonppl18 { expr rgeschwoutpostfct| ( expr )| outfixexpr;

outfixexpr : ! expr rceiloutfct| ! expr , expr rceiloutinfct| " expr rflooroutfct| " expr , expr rflooroutinfct| [[ expr rsemoutfct| [[ expr , expr rsemoutinfct| � expr rquineoutfct| � expr , expr rquineoutinfct| { expr rgeschwoutfct| { expr , expr rgeschwoutinfct;

fl : [{expr // , }+ , ] flmv [, {expr // , }+ ]| {expr // , }∗;

prog : parasg| ppl variable| prog 2;

prog 2 : progmv| asg| proc ( apl )| while expr do prog| if expr then prog [else prog ]| skip| abort| { {prog // ; }+ }| { {prog // ; }+ }| bwhile expr do {prog // ; }+ times term| loop {prog // ; }+ times term| let vdl in prog| choose vl with expr in prog| choose vl with expr in prog ifnone prog;

parasg : [{asg // | }+ | ] parasgmv [| {asg // | }+ ]

| {asg // | }+ | asg;

asg : var {({expr // , }+)}∗ := term| var := [?];

progseq nonparasg : prog 2 [; {prog // ; }+ ]

Page 235: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 234

| ppl variable;

vdl : [{vardecl // , }+ , ] vdlmv [, {vardecl // , }+ ]| {vardecl // , }∗;

vardecl : var = expr| var = [?]| ppl variable;

pdl : [{procdecl // ; }+ , ] pdlmv [, {procdecl // ; }+ ]| ppl variable| {procdecl // ; }∗;

procdecl : proc ( param ) { {prog // ; }+ }| proc ( param ) { {prog // ; }+ }| procdeclmv;

param : {var // , }+ [; {var // , }+]]| var {var // , }+| ε;

apl : {expr // , }∗ ; {var // , }+;

spec0 : ppl variable| pplvarassym;

symren : sort → sym| const → sym| proc → sym| xov → sym;

renoutsymbol : ! . rceiloutfct| ! . rceilsym [. ]| " . rflooroutfct| " . rfloorsym [. ]| [[ . rsemoutfct| [[ . rsemsym [. ]| � . rquineoutfct| � . rquinesym [. ]| { . rgeschwoutfct| { . rgeschwsym [. ]| ! . rceiloutprefct .| " . rflooroutprefct .| � . rquineoutprefct .| { . rgeschwoutprefct .| [[ . rsemoutprefct .| . ! . rceiloutpostfct| . ! . rceilsym| . " . rflooroutpostfct| . " . rfloorsym| . [[ . rsemoutpostfct| . [[ . rsemsym| . � . rquineoutpostfct| . � . rquinesym

Page 236: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 235

| . { . rgeschwoutinfct| . { . rgeschwsym

| . [ . reckigzuoutpostfct

| . [ . reckigzusym

| . [ . ]| ! . , . rceiloutpostfct| ! . , . rceilsym| " . , . rflooroutpostfct| " . , . rfloorsym| [[ . , . rsemoutpostfct| [[ . , . rsemsym| � . , . rquineoutpostfct| � . , . rquinesym| { . , . rgeschwoutinfct| { . , . rgeschwsym

| [ . , . reckigzuoutpostfct

| [ . , . reckigzusym

| [ . , . ];

prdandprio : sym [. ]| . sym;

defconstlist aux : [defconstlist aux ] sym : sort ;| [defconstlist aux ] sym , {sym // , }+ : sym ;;

deffct : sym : {sort // crosscomma }+ → sort ;| . symorplusorstern . : sort crosscomma sort → sort ;| sym . : sort → sort ;| . sym : sort → sort ;| ! . rceilsym : sort → sort ;| " . rfloorsym : sort → sort ;| [[ . rsemsym : sort → sort ;| � . rquinesym : sort → sort ;| { . rgeschwsym : sort → sort ;| ! . , . rceilsym : sort crosscomma sort → sort ;| " . , . rfloorsym : sort crosscomma sort → sort ;| [[ . , . rsemsym : sort crosscomma sort → sort ;| � . , . rquinesym : sort crosscomma sort → sort ;| { . , . rgeschwsym : sort crosscomma sort → sort ;| ! . rceilsym . : sort crosscomma sort → sort ;| " . rfloorsym . : sort crosscomma sort → sort ;| [[ . rsemsym . : sort crosscomma sort → sort ;| � . rquinesym . : sort crosscomma sort → sort ;| { . rgeschwsym . : sort crosscomma sort → sort ;| . ! . rceilsym : sort crosscomma sort → sort ;

| . [ . reckigzusym : sort crosscomma sort → sort ;| . " . rfloorsym : sort crosscomma sort → sort ;| . [[ . rsemsym : sort crosscomma sort → sort ;| . � . rquinesym : sort crosscomma sort → sort ;| . { . rgeschwsym : sort crosscomma sort → sort ;;

defprd : sym ;| sym : {sort // crosscomma }+ ;

Page 237: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX C. SYNTAX OF DYNAMIC LOGIC 236

| . symorplusorstern . : sort crosscomma sort ;| sym . : sort ;| . sym : sort ;| ! . rceilsym : sort ;| " . rfloorsym : sort ;| [[ . rsemsym : sort ;| � . rquinesym : sort ;| { . rgeschwsym : sort ;| ! . , . rceilsym : sort crosscomma sort ;| " . , . rfloorsym : sort crosscomma sort ;| [[ . , . rsemsym : sort crosscomma sort ;| � . , . rquinesym : sort crosscomma sort ;| { . , . rgeschwsym : sort crosscomma sort ;| ! . rceilsym . : sort crosscomma sort ;| " . rfloorsym . : sort crosscomma sort ;| [[ . rsemsym . : sort crosscomma sort ;| � . rquinesym . : sort crosscomma sort ;| { . rgeschwsym . : sort crosscomma sort ;| . ! . rceilsym : sort crosscomma sort ;

| . [ . reckigzusym : sort crosscomma sort ;| . " . rfloorsym : sort crosscomma sort ;| . [[ . rsemsym : sort crosscomma sort ;| . � . rquinesym : sort crosscomma sort ;| . { . rgeschwsym : sort crosscomma sort ;;

defproclist : procedures {defproc }+;

defproc : sym mode ;;

mode : ( {sort // , }∗ ) [: sortlist nonempty or sort [: ( {mode // , }+ ) ] ];

sortlist nonempty or sort : ( {sort // , }+ )| sort;

defvarlist : variables defvarlist aux;

defvarlist aux : [defvarlist aux ] sym : sort ;| [defvarlist aux ] sym , {sym // , }+ : sort ;;

Page 238: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix D

Syntax of Algebraic Specificationsand Modules

This grammar uses the same assumptions as described in the syntax of dynamic logic in appendixC.

1. The start symbol is ‘start’.

2. Terminals are written in bold.

3. Pseudoterminals are written in italics.

4. In priorities “right” may be omitted.

5. [ . . . ] means: is optional.

6. {. . .}∗ means: repeated any times (even 0 times)

7. {. . .}+ means: repeated at least one time.

8. {. . . //sep}∗ means: repeated any times, separated by sep.

9. {. . . //sep}+ means: repeated any times, separated by sep.

10. {. . . | . . .}+ means: alternative.

11. Attached number j is always from {1 . . . 9}.

start : expr| sequent| module specific {pattern forbidden rule applyrule }∗| {gen }+| implementation| lemmas {string : sequent ; optionals }∗| sort| fct| proc| module| spec nonppl

| [ ]| [ {proc // , }+ ]| [ {fct // , }+ ]

237

Page 239: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 238

| morphism| signature signature end signature;

optionals : [usedfor [{string // , }+ ] ; ] [remark ]| [usedfor {string // , }∗ ; ] comment [remark ];

pattern : pattern {expr // , }∗ {expr // , }∗ ;;

forbidden : [forbidden [{expr // , }+ ] [{expr // , }+ ] ; ];

rule : rule rule1 ;;

rule1 : insert lemma string substitution| execute call| contract call left| callleft| callright| assignleft| assignright| loopunwindright| loopunwindleft| loopexitleft| loopexitright| splitleft| splitright| weakening {exprposarg // , }+| cut formula expr| allleft| existsright| insert speclemma namessubsarg| insert neg rewritelemma negrewritearg| insert pos rewritelemma posrewritearg| ifleft| ifright| case distinction exprposarg;

substitution : with [ {expr // , }∗ ] → [ {expr // , }∗ ]| with ppl variable| ε;

exprposarg : right j| left j;

callleft : call left j| call left;

callright : call right j| call right;

assignleft : assign left j| assign left;

assignright : assign right j

Page 240: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 239

| assign right;

loopunwindleft : loopunwind left j| loopunwind left;

loopunwindright : loopunwind right j| loopunwind right;

loopexitleft : loopexit left j| loopexit left;

loopexitright : loopexit right j| loopexit right;

splitleft : split left j| split left;

splitright : split right j| split right;

allleft : all left j with [ {expr // , }+ ] discard| all left with [ {expr // , }+ ] discard;

existsright : exists right j with [ {expr // , }+ ] discard| exists right with [ {expr // , }+ ] discard;

ifleft : if left j| if left;

ifright : if right j| if right;

discard : and discard| ε;

namessubsarg : string from specification string [ string ] substitution| string from specification string substitution;

negrewritearg : [string from specification ] string substitution

| string from specification string [ string ] substitution;

posrewritearg : [string from specification ] string substitution

| string from specification string [ string ] substitution;

applyrule : [applyrule 1 ; ]| applyrule 11 ;| applyrule once ;| applyrule unique ;| applyrule always ;;

crosscomma : ×| ,;

Page 241: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 240

symorplusorstern : sym| +| ∗;

sym : see grammar for DL;

extsymorplusorstern : extsym| +| ∗;

extsym : extsymbol| specialsymbol;

specialsymbol : →| <

| >

| ×| in;

pplvarassym : symbol| in;

string1 : symbol1| ×| in| ∀| ∃| <

| >

| →;

string : sort| string1;

symbol : sort| symbol1;

extsymbol : sort| extsymbol1;

symbol1 : regsymbol| outsymbol;

extsymbol1 : regsymbol| extoutsymbol;

regsymbol : infixfctri

| infixfctli

| const| xov| fct| postfixfct| praefixfct

Page 242: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 241

| postfixprd| praefixprd| proc| sym;

outsymbol : rceiloutfct| rceiloutinfct| rceiloutprefct| rceilsym| rflooroutfct| rflooroutinfct| rflooroutprefct| rfloorsym| rsemoutfct| rsemoutinfct| rsemoutprefct| rsemsym| rquineoutfct| rquineoutinfct| rquineoutprefct| rquinesym| rgeschwoutfct| rgeschwoutinfct| rgeschwoutprefct| rgeschwsym| rceiloutpostfct| rflooroutpostfct| rquineoutpostfct| rgeschwoutpostfct| rsemoutpostfct| reckigzuoutpostfct| reckigzusym

| ];

extoutsymbol : ! rceiloutfct| ! rceiloutinfct| ! rceiloutprefct| ! rceilsym| " rflooroutfct| " rflooroutinfct| " rflooroutprefct| " rfloorsym| [[ rsemoutfct| [[ rsemoutinfct| [[ rsemoutprefct| [[ rsemsym| � rquineoutfct| � rquineoutinfct| � rquineoutprefct| � rquinesym| { rgeschwoutfct| { rgeschwoutinfct| { rgeschwoutprefct

Page 243: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 242

| { rgeschwsym| ! rceiloutpostfct| " rflooroutpostfct| � rquineoutpostfct| { rgeschwoutpostfct| [[ rsemoutpostfct

| [ reckigzuoutpostfct| [ reckigzusym| [ ];

fct : see grammar for DL;

extfct : praefixfct| praefixprd| ∗| ! rceiloutfct| ! rceiloutinfct| ! rceiloutprefct| ! rceilsym| " rflooroutfct| " rflooroutinfct| " rflooroutprefct| " rfloorsym| [[ rsemoutfct| [[ rsemoutinfct| [[ rsemoutprefct| [[ rsemsym| � rquineoutfct| � rquineoutinfct| � rquineoutprefct| � rquinesym| { rgeschwoutfct| { rgeschwoutinfct| { rgeschwoutprefct| { rgeschwsym| ! rceiloutpostfct| " rflooroutpostfct| � rquineoutpostfct| { rgeschwoutpostfct| [[ rsemoutpostfct

| [ reckigzuoutpostfct| [ reckigzusym| [ ];

rceilsym : rceiloutfct| rceiloutinfct| rceiloutprefct| rceiloutpostfct| rceilsym;

rfloorsym : rflooroutfct| rflooroutinfct| rflooroutprefct

Page 244: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 243

| rflooroutpostfct| rfloorsym;

rsemsym : rsemoutfct| rsemoutinfct| rsemoutprefct| rsemoutpostfct| rsemsym;

rquinesym : rquineoutfct| rquineoutinfct| rquineoutprefct| rquineoutpostfct| rquinesym;

rgeschwsym : rgeschwoutfct| rgeschwoutinfct| rgeschwoutprefct| rgeschwoutpostfct| rgeschwsym;

reckigzusym : reckigzuoutpostfct| reckigzusym

| ];

expr : see grammar for DL;

sequent : see grammar for DL;

pdl : see grammar for DL;

spec : unionspec0| spec0;

spec0 : ppl variable| pplvarassym| spec1;

spec nonppl : spec1 [+ {spec0 // + }+ ];

spec1 : basicspec| unionspec| genericspec| enrichedspec| actualizedspec| renamedspec| asmspec| basicdataspec| gendataspec;

unionspec : union specification unionspec0 end union specification;

unionspec0 : spec0 + {spec0 // + }+

Page 245: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 244

;basicspec : specification signature [axioms genlistandaxioms ] end specification

;genlistandaxioms : [[{gen }+ ] {[string1 : ] expr // , }+ [, ] ] {declaration [string : ] pdl }∗

| {gen }+ {declaration [string : ] pdl }∗;

gen : {sort // , }+ generated by {extsymorplusorstern // , }+ ;| {sort // , }+ freely generated by {extsymorplusorstern // , }+ ;;

signature : [sorts {sym // , }+ ; ][constants constdeflist aux ][functions {fctdef }+ ][predicates {prddef }+ ][procedures {procdef }+ ][variables vardeflist aux ]

;enrichedspec : enrich {spec // , }+ enrichedpart

;enrichedpart : with signature end enrich

| with signature axioms genlistandaxioms end enrich;

genericspec : generic specificationparameter spec [using {spec // , }+ ]genericpart

;genericpart : target signature end generic specification

| target signature axioms genlistandaxioms end generic specification;

actualizedspec : actualize specwith {spec // , }+by morphism [{symren // , }+ [, ] ]

end actualize;

renamedspec : rename specby morphism [{symren // , }+ [, ] ]

end rename;

morphism : morphism [{symren // , }+ [, ] ] end morphism;

symren : sort → sym| const → sym| fctren| procren| xov → sym;

procren : proc → sym;

fctren : extfct → symorplusorstern| extfct → . sym| extfct → sym .| extfct → . symorplusorstern . [prioleftright ]| extfct → sym prio 0| extfct → renoutsymbol;

Page 246: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 245

renoutsymbol : ! . rceiloutfct| ! . rceilsym [. ]| " . rflooroutfct| " . rfloorsym [. ]| [[ . rsemoutfct| [[ . rsemsym [. ]| � . rquineoutfct| � . rquinesym [. ]| { . rgeschwoutfct| { . rgeschwsym [. ]| ! . rceiloutprefct .| " . rflooroutprefct .| � . rquineoutprefct .| { . rgeschwoutprefct .| [[ . rsemoutprefct .| . ! . rceiloutpostfct| . ! . rceilsym| . " . rflooroutpostfct| . " . rfloorsym| . [[ . rsemoutpostfct| . [[ . rsemsym| . � . rquineoutpostfct| . � . rquinesym| . { . rgeschwoutinfct| . { . rgeschwsym

| . [ . reckigzuoutpostfct

| . [ . reckigzusym

| . [ . ]| ! . , . rceiloutpostfct| ! . , . rceilsym| " . , . rflooroutpostfct| " . , . rfloorsym| [[ . , . rsemoutpostfct| [[ . , . rsemsym| � . , . rquineoutpostfct| � . , . rquinesym| { . , . rgeschwoutinfct| { . , . rgeschwsym

| [ . , . reckigzuoutpostfct

| [ . , . reckigzusym

| [ . , . ];

asmspec : asm specification procsym[using {spec // , }+ ]signature[input variables {var // , }+ ]state variables {var }+initial state exprasm rule procsymdeclaration prepdl

end asm specification;

Page 247: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 246

prepdl : see pdl in grammar for DL, but parameterlistsin the declaration (param) or in calls (apl) are optionalIf left off, they are computed from the variables occurring in the bodies

basicdataspec : data specification[using {spec // , }+ ]

{sym = {constructordef // | }+ ; }+[variables vardeflist aux ][size functions {fctdef }+ ][order predicates {prddef }+ ]

end data specification;

gendataspec : generic data specificationparameter spec[using {spec // , }+ ]

{sym = {constructordef // | }+ ; }+[variables vardeflist aux ][size functions {fctdef }+ ][order predicates {prddef }+ ]

end generic data specification;

constructordef : sym [( {selector // , }+ ) [with prdandprio ] ]| sym with prdandprio| . symorplusorstern . ( selector , selector ) [prioleftright ] [with prdandprio ]| . sym ( selector ) [with prdandprio ]| sym . ( selector ) [with prdandprio ]| ! . rceilsym ( selector ) [with prdandprio ]| � . rquinesym ( selector ) [with prdandprio ]| [. ] [[ . rsemsym ( selector ) [with prdandprio ]| " . rfloorsym ( selector ) [with prdandprio ]| { . rgeschwsym ( selector ) [with prdandprio ]| ! . , . rceilsym ( selector , selector ) [with prdandprio ]| � . , . rquinesym ( selector , selector ) [with prdandprio ]| [[ . , . rsemsym ( selector , selector ) [with prdandprio ]| " . , . rfloorsym ( selector , selector ) [with prdandprio ]| { . , . rgeschwsym ( selector , selector ) [with prdandprio ]| ! . rceilsym . ( selector , selector ) [with prdandprio ]| � . rquinesym . ( selector , selector ) [with prdandprio ]| [[ . rsemsym . ( selector ) [with prdandprio ]| " . rfloorsym . ( selector )| " . rfloorsym . ( selector , selector ) with prdandprio| { . rgeschwsym . ( selector , selector ) [with prdandprio ]| . ! . rceilsym ( selector , selector ) [with prdandprio ]| . � . rquinesym ( selector , selector ) [with prdandprio ]| . " . rfloorsym ( selector , selector ) [with prdandprio ]| . { . rgeschwsym ( selector , selector ) [with prdandprio ]

| . [ . reckigzusym ( selector , selector ) [with prdandprio ];

selector : [. ] sym : sym| sym . : sym;

prdandprio : sym [. ]| . sym;

Page 248: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 247

prioleftright : prio {1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 } {left | right | ε};

constdeflist aux : [constdeflist aux ] sym : sym ;| [constdeflist aux ] sym , {sym // , }+ : sym ;;

fctdef : sym : {sym // crosscomma }+ → sym ;| . symorplusorstern . : sym crosscomma sym → sym [prioleftright ] ;| sym . : sym → sym ;| . sym : sym → sym ;| ! . rceilsym : sym → sym ;| " . rfloorsym : sym → sym ;| [[ . rsemsym : sym → sym ;| � . rquinesym : sym → sym ;| { . rgeschwsym : sym → sym ;| ! . , . rceilsym : sym crosscomma sym → sym ;| " . , . rfloorsym : sym crosscomma sym → sym ;| [[ . , . rsemsym : sym crosscomma sym → sym ;| � . , . rquinesym : sym crosscomma sym → sym ;| { . , . rgeschwsym : sym crosscomma sym → sym ;| ! . rceilsym . : sym crosscomma sym → sym ;| " . rfloorsym . : sym crosscomma sym → sym ;| [[ . rsemsym . : sym crosscomma sym → sym ;| � . rquinesym . : sym crosscomma sym → sym ;| { . rgeschwsym . : sym crosscomma sym → sym ;| . ! . rceilsym : sym crosscomma sym → sym ;

| . [ . reckigzusym : sym crosscomma sym → sym ;| . " . rfloorsym : sym crosscomma sym → sym ;| . [[ . rsemsym : sym crosscomma sym → sym ;| . � . rquinesym : sym crosscomma sym → sym ;| . { . rgeschwsym : sym crosscomma sym → sym ;;

prddef : [sym . : ] sym ;| sym : {sym // crosscomma }+ ;| . symorplusorstern . : sym crosscomma sym [prioleftright ] ;| . sym : sym ;| ! . rceilsym : sym ;| " . rfloorsym : sym ;| [[ . rsemsym : sym ;| � . rquinesym : sym ;| { . rgeschwsym : sym ;| ! . , . rceilsym : sym crosscomma sym ;| " . , . rfloorsym : sym crosscomma sym ;| [[ . , . rsemsym : sym crosscomma sym ;| � . , . rquinesym : sym crosscomma sym ;| { . , . rgeschwsym : sym crosscomma sym ;| ! . rceilsym . : sym crosscomma sym ;| " . rfloorsym . : sym crosscomma sym ;| [[ . rsemsym . : sym crosscomma sym ;| � . rquinesym . : sym crosscomma sym ;| { . rgeschwsym . : sym crosscomma sym ;| . ! . rceilsym : sym crosscomma sym ;

| . [ . reckigzusym : sym crosscomma sym ;| . " . rfloorsym : sym crosscomma sym ;

Page 249: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX D. SYNTAX OF ALGEBRAIC SPECIFICATIONS AND MODULES 248

| . [[ . rsemsym : sym crosscomma sym ;| . � . rquinesym : sym crosscomma sym ;| . { . rgeschwsym : sym crosscomma sym ;;

procdef : sym premode ;;

premode : ( {sym // , }∗ ) [: symlist nonempty or sym [: ( {premode // , }+ ) ] ];

symlist nonempty or sym : ( {sym // , }+ )| sym;

sortlist nonempty or sort : ( {sort // , }+ )| sort;

vardeflist aux : [vardeflist aux ] sym : sym ;| [vardeflist aux ] sym , {sym // , }+ : sym ;;

module : moduleexport specrefinementmodimpl end module

;modimpl : implementation

import spec[procedures {procdef }+ ][variables vardeflist aux ]declaration pdl

| implementation ppl variable;

implementation : implementationimport spec[procedures {procdef }+ ][variables vardeflist aux ]declaration pdl

| implementation ppl variable;

refinement : refinement[representation of sorts {sym implements sort ; }+ ][representation of operations {progclause }+ ][equality {sym : sort ; }+ ]

;progclause : sym implements const ;

| sym implements fct ;;

Page 250: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix E

Rules for the VCG

E.1 Rules for the simple VCG

Γ ϕΓ [skip]ϕ

SKIP RULE

Γ [abort]ϕABORT AXIOM

Γ [α][β]ϕ

Γ [α;β]ϕCOMPOUND RULE

Γ,¬ε [β]ϕ Γ, ε [α]ϕ

Γ [if ε then α else β]ϕIF FORWARD RULE

Γ [α0]((ε→ ϕ1) ∧ (¬ε→ ϕ2)) ϕ1 [α]ϕ ϕ2 [β]ϕ

Γ [α0; if ε then α else β]ϕPRAKT IF BACKWARD RULE

(not implemented in KIV)

Γ Inv Inv, ε [α]Inv Inv,¬ε ϕΓ [while ε do α]ϕ

(WHILE RULE Inv)

x′ = τ,Γ ϕx′x

Γ [x := τ ]ϕ(PRAKT ASSIGN TACTIC proof-tree prem-no)

(x′ is a new variable)

E.2 Rules for the extended VCG

Γ [α]ϕ Γ εΓ [if ε then α else β]ϕ

IF POS RULE

Γ [β]ϕ Γ ¬εΓ [if ε then α else β]ϕ

IF NEG RULE

249

Page 251: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix F

Syntax and Semantics ofHigher-Order Dynamic Logic

The Basic Logic of KIV is a Higher-Order variant of Dynamic Logic. Operations and procedureswith higher-order types can be defined in the functions, predicates, procedures and variablesparts of specifications. Just use a function type (in parenthesis) in those places, where a first-orderdefinition would require to use a sort. For example,

functions map : (int → int) × intlist → intlist;

is a correct function definition. Functions are not curried, so the definition

functions map2 : (int → int) → intlist → intlist;

defines a unary function, while map is a function with 2 arguments. As usual, the functionarrow binds to the right (but weaker than ×), so an additional parenthesis around “intlist →intlist” in the definition of map2 is possible, but unnecessary. Typical higher-order expressionswith these function symbols are

map(λ x. x + x, nil), map2(f)(nil)

Lambda expressions can have several arguments (just like quantifiers), and can be writteneither using the special greek symbol λ or just ascii lambda. Variable f has been declared with

variables f : int → int;

If a function has a higher-order argument or result type, KIV requires that you define a variableof this type too (which is used in the rule “expand right” of Sect. F.3). So, both definitions of mapand map2 require the definition of f. The simplifier of KIV automates β-reduction, i.e. it rewritesall occurrences of (λ x. e) (e) to e

ex. Other rules used in cosi are given in Sect. F.3.

F.1 Syntax of Higher-Order Dynamic Logic

Definition 5 Sorts and TypesGiven a set SO of base sorts, the set of sorts (also called types) S is defined to be the least set,which includes the base sorts in SO, and which includes for every vector of argument sorts s ∈ S+

and each target sort s′ ∈ S also the function sort s⇒ s′.

Definition 6 SignaturesA (many-sorted) signature SIG = (SO,OP,X, P ) consists of a finite set of base sorts SO, a familyOP =

⋃s∈SOPs of operations (for a base sort an operation in OPs is a constant, otherwise a

250

Page 252: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 251

function) a family X =⋃

s∈SXs of countably many variables for each sort, and a family P =⋃s∈S∗,s′∈S∗Ps,s′ of procedure names with value parameters of sorts s and reference parameters

of sorts s′ (procedure names are used in programs).It is assumed, that SO contains at least the base sorts bool and nat, and that OP contains the

usual operations on these sorts (true, false, ∧ , ∨ , → , ↔ , ¬ , 0, +1, −1, +). A function withtarget sort bool is called a predicate.

Definition 7 DL ExpressionsFor a many-sorted signature SIG, the set DLEXPR =

⋃s∈SDLEXPRs of expressions, and the

set PROG of programs are defined to be the smallest sets with

• Xs ⊆ DLEXPRs for every s ∈ S

• OP s ⊆ DLEXPRs for every s ∈ S

• If e ∈ DLEXPRs⇒ s′ and t ∈ DLEXPRs then e(t) ∈ DLEXPRs′

• If e ∈ DLEXPRs and x ∈ Xs then λx.e ∈ DLEXPRs⇒ s

• If ϕ ∈ FMA and x ∈ Xs then ∀ x.ϕ ∈ FMA

• If ϕ ∈ FMA and x ∈ Xs then ∃ x.ϕ ∈ FMA

• If t, t′ ∈ DLEXPRs, then t = t′ ∈ FMA

• If ϕ ∈ FMA and t, t′ ∈ DLEXPRs, then (ϕ ⊃ t; t′) ∈ DLEXPRs

• If x ∈ Xs and t ∈ Us, where Us = Ts ∪ {?}, then x := t ∈ PROG

• If α ∈ PROG, x ∈ Xs and t ∈ Us, where Us = Ts ∪ {?}, then var x = t in α ∈ PROG

• If α ∈ PROG, x ∈ Xs and ϕ ∈ FMA var x with ϕ in α ∈ PROG

• skip, abort ∈ PROG

• If α, β ∈ PROG, then α ∨ β ∈ PROG

• If α, β ∈ PROG, then α;β ∈ PROG

• If α, β ∈ PROG and ε ∈ BXP, then if ε then α else β ∈ PROG

• If α ∈ PROG and ε ∈ BXP then while ε do α ∈ PROG

• If α ∈ PROG and κ ∈ Tnat then loop α times κ ∈ PROG

• If p ∈ Ps,s′ , t ∈ Ts, x ∈ Xs′ then p(t;x) ∈ PROG.

• If p ∈ Ps,s′ , t ∈ Ts, x ∈ Xs′ and κ ∈ Tnat then procbound κ in p(t;x) ∈ PROG.This program is a call to p with maximal recursion depth bounded by κ.

• If α ∈ PROG and ϕ ∈ FMA then 〈α〉 ϕ ∈ FMA (there is a terminating run with ϕ)

• If α ∈ PROG and ϕ ∈ FMA then [α] ϕ ∈ FMA (for all terminating runs ϕ)

• If α ∈ PROG and ϕ ∈ FMA then 〈|α|〉 ϕ ∈ FMA (all runs terminate and ϕ)

The definition uses FMA (formulas) to abbreviate DLEXPRbool. The set Ts (Terms of sort s)is the subset of DLEXPRs, that does neither contain quantifiers nor programs. BXP (booleanexpressions) is Tbool. First-order expressions must contain no lambda-expressions, no operationsother than constants or functions with base sorts as argument and target sorts. Used variablesmust all be of base sorts. Also in applications the function expression must be an operation, andthe arguments must be terms. In equations, the arguments must be terms too.

Page 253: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 252

Remark 1 Like in Pascal we use begin . . . end as brackets around programs. if ε then α isused as an abbreviation for if ε then α else skip.

Remark 2 The tests of while loops and conditionals must be boolean expressions in the definitionabove (ε ∈ BXP). This is necessary for application programs. For proof obligations and in proofsit is sometimes convenient to use arbitrary formulas. This extension does not pose any problems,everything that follows holds for arbitrary ε ∈ FMA too.

Definition 8 Assigned VariablesThe set asgv(α) of assigned variables in a programs α is defined by:

• asgv(skip) = asgv(abort) = ∅

• asgv(α;β) = asgv(α) ∪ asgv(β)

• asgv(α ∨ β) = asgv(α) ∪ asgv(β)

• asgv(if ε then α else β) = asgv(α) ∪ asgv(β)

• asgv(while ε do α) = asgv(α)

• asgv(loop α times κ) = asgv(α)

• asgv(var x with ϕ in α) = asgv(α) \ x

• asgv(var x = t in α) = asgv(α) \ x

• asgv(p(t;x)) = x

• asgv(procbound p(t;x) times κ) = x

Definition 9 Procedure DeclarationsThe setPD of procedure declarations is the set of all p(x;var y).α with p ∈ Ps,s′ x, y ∈ Xs,s′ ,α ∈ PROG and asgv(α) ⊆ x ∪ y. α must not contain procedure calls with bounded recursiondepth. p is the procedure defined with the procedure declaration, α is the body of the procedure.

F.2 Semantics of Higher-Order Dynamic Logic

Definition 10 AlgebraAn Algebra A over a signature SIG consists of a nonempty carrier set As for every base sort s.Carriers of functions sorts s⇒ s are inductively constructed to be the sets of functions from Asto As′ . For an operation f ∈ OPs its semantics fA is an element of As. For every procedure p∈ Ps,s′ and every n ∈ IN the algebra A contains a relation [[p]]A,n between As,s′ and As′ ∪ ⊥(which is the semantics of p when the maximal recursion depth is bounded by n). [[p]]A,0 mustbe the relation, which relates every initial state with ⊥ only (a program with allowed recursiondepth 0 behaves just like abort). [[p]]A denotes the semantics of the procedure and is definedas the union of all [[p]]A,n. The semantics defines a relation between the initial values of valueand reference parameters and the result values of the reference parameters. The special value ⊥expresses (possible) nontermination for a certain input.

It is assumed that Abool = {tt,ff }, Anat = IN, and that the operationen on booleans and naturalnumbers have their usual semantics.

Definition 11 States/ValuationsFor a signature SIG and an algebra A over this signature a state (or synonymously, a valuation)z ∈ STA is defined as a function, that maps the variables of sort s to values in As. The statez[x ← a] is the state, which results from z by modifying the values at variables x with a.

Page 254: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 253

Definition 12 Semantics of ExpressionsFor an algebra A and a valuation z the semantics [[ e]]z of a DL expression e ∈ DLEXPRs is avalue in As. The semantics of programs is a relation z[[α]]z′ (written infix), where z and z′ areeither states or a bottom element ⊥, which indicates nontermination. If z = ⊥ , then z[[α]]z′ iffz′ = ⊥ too. For z �= ⊥ the semantics of programs and the semantics of programs are definedby:

• [[x]]z = z(x)

• [[f ]]z = fA

• [[e(t)]]z = [[e]]z([[t]]z) for e ∈ DLEXPRs⇒ s′ and t ∈ Ts

• [[λx.e]]z with x ∈ Xs is the function, which maps each vector a ∈ As to [[e]]z[x ← a].

• [[∀ x.e]]z = tt with x ∈ Xs iff [[e]]z[x ← a] = tt for all values a ∈ As

• [[∃ x.e]]z = tt with x ∈ Xs iff [[e]]z[x ← a] = tt for some values a ∈ As

• [[(ε ⊃ e; e′)]]z is [[e]]z, if [[ε]]z = tt, and [[e′]]z otherwise.

• z[[skip]]z′ iff z = z′

• z[[α]]z′ iff z′ = ⊥ .

• z[[x:=t]]z′ iff z′ = z[x ← [[t]]z], where each [[?]]z is some arbitrary value.

• z[[α;β]]z′ iff there is a z′′ with z[[α]]z′′ and z′′[[β]]z′

• z[[α ∨ β]]z′ iff z[[α]]z′ or z[[β]]z′

• z[[if ε then α else β ]]z′ iffeither [[ε]]z = tt and z[[α]]z′ or [[ε]]z = ff and z[[β]]z′

• z[[loop α times κ]]z′ iffthere are states z0 := z, z1, . . . , zn := z′ with n := [[κ]]z such thatzi−1[[α]]zi for every 1 ≤ i ≤ n

• z[[while ε do α]]z′ iffthere are states z0 := z, z1, . . . , zn := z′ with zi−1[[α]]zi for 1 ≤ i ≤ n,[[ε]]zi = tt for 1 ≤ i < n and [[ε]]z′ = ff (terminating loop).Also z[[while ε do α]] ⊥ iff there is a sequence z0 := z, z1, . . . , zn, . . . such that for all n[[ε]]zi = tt and zi[[α]]zi+1 (diverging loop).

• z[[var x = t in α]]z′ iff z[x ← a][[α]]z′′ and either z′ = z′′ = ⊥ or z′ = z′′[x ← [[x]]z] whereai = [[ti]]z for ti �=? and otherwise ai is arbitrary.

• z[[var x with ϕ in α]]z′ iff z[x ← a][[α]]z′′ and z′ = z′′[x ← [[x]]z] where a is such that[[ϕ]]z[x ← a] = tt. If an a with [[ϕ]]z[x ← a] = tt does not exist, then z[[var x with ϕ in α]] ⊥

• z[[p(t, x)]]z′ with z′ �= ⊥ iff z(t), z(x), z′(x) ∈ [[p]] and z(y) = z′(y) for all y �∈ x. z[[p(t, x)]] ⊥iff z(t), z(x), ⊥ ∈ [[p]].

• z[[procbound κ in p(t, x)]]z′ with z′ �= ⊥ iff z(t), z(x), z′(x) ∈ [[p]]n, where n = [[κ]]z, andz(y) = z′(y) for all y �∈ x. z[[procbound κ in p(t, x)]] ⊥ iff z(t), z(x), ⊥ ∈ [[p]]n

• [[〈α〉 ϕ]]z = tt iff there is a z′ �= ⊥ with z[[α]]z′ and [[ϕ]]z′ = tt

• [[[α] ϕ]]z = tt iff for all z′ �= ⊥ with z[[α]]z′: [[ϕ]]z′ = tt

Page 255: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 254

• [[〈|α|〉 ϕ]]z = tt iff all z′ with z[[α]]z′: z′ �= ⊥ and [[ϕ]]z′ = tt

Remark 3 The semantics of expressions and programs is defined unambiguously, since each casereduces the number of elementary statements in the expression/program considered.

Definition 13 Semantics of Procedure DeclarationsA |= p(x; y).α, iff for every κ = 0+1 . . .+1 (representing a number n ≥ 0) the following propertyholds:

[[procbound κ+ 1 in p(x; y)]] = [[procbound κ in α]]

In the definition procbound κ in α is the program, that results from replacing each procedurecall q(σ; z) in α by procbound κ in q(σ; z) (for every procedure name q).

Remark 4 For a list of procedure declarations, such that the called procedures in their bodies area subset of the set of all defined procedures, the semantics of each defined procedure is unambigu-ously fixed. The proof is by induction on n, that [[p]]A,n is fixed for each defined procedure p. Itis also easy to show, that the [[p]]A,n are monotone increasing relations for the defined procedures.

Definition 14 models operator

• A, z |= ϕ holds (or is valid) for a formula ϕ iff [[ϕ]]z = tt

• A |= ϕ holds iff for all states z: A, z |= ϕ

• |= ϕ holds off for every algebra A : A |= ϕ

• Φ |= ψ holds iff for every algebra A: from A |= ϕ for every ϕ ∈ Φ follows A |= ψ.

Remark 5 The following properties are valid, if i does neither occur in α nor in ε. The first twoproperties characterize while loops (they allow induction over the number of iterations). The thirdproperty allows to avoid loops with a counter occurring in α.

• |= 〈while ε do α〉 ϕ ↔ ∃ i.〈loop if ε then α times i〉 (ϕ ∧ ¬ ε)

• |= 〈loop α times κ+ 1〉 ϕ ↔ 〈α; loop α times κ〉 ϕ

• |= 〈loop α times κ〉 ϕ ↔ (∀ i.i = κ → 〈loop α times i〉 ϕ)

Remark 6 Let A be an algebra with A |= p(x;var y) for a procedure declaration. Then thefollowing three formulas characterize the recursive procedure (i.e. their validity is equivalent tothe procedure declaration). Procedure declarations therefore can be viewed as abbreviations foraxioms. The formulas allow to induce over the recursion depth and unfolding of procedures. Thefirst formulas holds in every algebra. In the third formula x0 and y0 have to be new variables ofthe same sorts as x and y. procbound κ in α again is the program, that is derived from α byreplacing all procedure calls q(σ; z) with procbound κ in q(σ; z).

• |= 〈p(t; z)〉 ϕ ↔ ∃ κ.〈procbound κ in p(t; z)〉 ϕ

• A |= 〈procbound κ+ 1 in p(t; z)〉 ϕ ↔〈x0, y0, x, y := x, y, t, z;procbound κ in α;x, y, y0 := x0, y0, y; z := y0〉 ϕ

• A |= 〈p(t; z)〉 ϕ↔ 〈x0, y0, x, y := x, y, t, z;α;x, y, y0 := x0, y0, y; z := y0〉 ϕ

Page 256: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 255

Definition 15 (Basic) SpecificationsA basic specification SPEC = (SIG,Ax,GAx,PAx) consists of

• a signature SIG = (SO,OP,P,X).

• a set of axioms Ax (formulas over SIG).

• a set GAx of generation clauses of the form: s1, . . . sn generated by f1, . . . fm (n,m > 0).

It is required that s1, . . . sn ∈ SO+and all fj have a target sort in s1, . . . sn.

• a set PAx of procedure declarations over SIG.

Definition 16 Semantics of SpecificationsAn algebra A is a model of SPEC (written as A |= SPEC, if it is an algebra over the signature ofthe specification with

• A |= ϕ for every ϕ ∈ Ax

• For every generation clause s1, . . . , sn generated by f1, . . . , fm ∈ GAx and every i = 1 . . . n,every element a ∈ Asi can be got as the semantics a = [[t]]z of some term t under some valuesfor z. The term must not contain variables of the sorts s1, . . . , sn and all contained operationsymbols must be in {f1, . . . , fm}.

• A |= δ for every procedure declaration δ ∈ PAx

Remark 7 For every model of a specification (SIG,Ax,GAx,∅) with no procedure names in itssignature, there is exactly one extension to a model (SIG ∪ P,Ax,GAx, PAx ), where P is theset of defined procedures in PAx.

Remark 8 We write SPEC |= ϕ, iff in every model A of SPEC A |= ϕ holds.

F.3 Higher-Order Rules in Cosi

expand left/expand right

f(τ) = g(τ ), f = g,Γ Δ

f = g,Γ Δ

Γ f(x′) = g(x′),ΔΓ f = g,Δ

• f, g are arbitrary expressions of function type with argument sorts of types s

• expand left/expand right work like all left/all right on ∀ x. f(x) = g(x), so just like for allleft, it is possible to discard f = g in the premise of expand left.

• An instance τ of terms of sort s must be given as τ1, . . . , τn manually or chosen from someprecomputed substitutions.

• x′ are new variables of sorts s (automatically computed)

choice left/choice right

∀ x.ϕf(x)y ,Γ Δ

∀ x.∃ y.ϕ,Γ Δ

Γ ∃ x.ϕf(x)y ,Δ

Γ ∃ x.∀ y.ϕ,Δ

• When the sorts of x are s′ and those of y are s1, . . . , sn, then f is a vector of new functionvariables of types s′ → si.

Page 257: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX F. SYNTAX AND SEMANTICS OF HIGHER-ORDER DYNAMIC LOGIC 256

• The variables defined in the specification must contain at least one function variable for eachtype s′ → si (the order of the types in s′ may be permuted).

• The choice left rule also works if the formula has the form ∀ x.ψ → ∃ y.χ and free(ψ) ∩ y= ∅, since then the formula is equivalent to ∀ x.∃ y.ψ → χ.

F.4 Rules for Strong Diamonds and Indeterministic Choice

The rules for strong diamonds 〈|α|〉 ϕ are the same as for ordinary diamonds, except for inde-terministic constructs: program or, random assignment, and choosing variables. Also the rulesexecute call, omega right,split right, split left differ.

choose left/choose right

ψyx, 〈α

yx〉 ϕ,Γ Δ

〈var x with ψ in α〉 ϕ,Γ Δ

Γ ∃ y.ψyx ∧ 〈αyx〉 ϕ,Δ

Γ 〈var x with ψ in α〉 ϕ,Δ

∀ y.ψyx → [αyx] ϕ,Γ Δ

[var x with ψ in α] ϕ,Γ Δ

ψyx,Γ [α

yx] ϕ,Δ

Γ [var x with ψ in α] ϕ,Δ

ψyx, ∀ y.ψ

yx → 〈|α

yx|〉 ϕ,Γ Δ

〈|var x with ψ in α|〉 ϕ,Γ Δ

Γ ∃ y.ψyx,Δ ψyx,Γ 〈|α

yx|〉 ϕ,Δ

Γ 〈|var x with ψ in α|〉 ϕ,Δ

• y is x, with those variables that conflict with free(ϕ,Γ Δ) renamed to new variables

or left/or right

〈α〉 ϕ ∨ 〈β〉 ϕ,Γ Δ

〈α ∨ β〉 ϕ,Γ Δ

Γ 〈α〉 ϕ, 〈β〉 ϕ,ΔΓ 〈α ∨ β〉 ϕ,Δ

[α] ϕ, [β] ϕ,Γ Δ

[α ∨ β] ϕ,Γ Δ

Γ [α] ϕ ∧ [β] ϕ,Δ

Γ [α ∨ β] ϕ,Δ〈|α|〉 ϕ, 〈|β|〉 ϕ,Γ Δ

〈|α ∨ β|〉 ϕ,Γ Δ

Γ 〈|α|〉 ϕ ∧ 〈|β|〉 ϕ,ΔΓ 〈|α ∨ β|〉 ϕ,Δ

Page 258: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Appendix G

The Module Specific Heuristic

G.1 Introduction

While proving the verification conditions of a module, the user is often confronted with the fol-lowing phenomen: In many proofs, the next rule to apply on the current goal depends only a fewrelevant formulas, which are common to all these goals. Typical examples are:

• procedure calls (on recursive procedures), for which the current input will lead to no furtherrecursive calls when executing the procedure like in (only relevant formulas are shown!)

〈add#(x, 0; y)〉 y = y0

(in a module implementing natural numbers by binary words) or

〈union#(l1, nil; l2)〉 l2 = l3

(in a module implementing sets by lists).

• two procedure calls, for which executing the first will lead to a call of the second (with thecorrect arguments for the second) like in (only relevant formulas are shown!)

〈member#(x, l; b)〉 b 〈member#(x, cdr(l); b)〉 b

(in a module implementing sets by lists).

• situations, in which insert lemma with a simple often used theorem closes the goal. Anexample is the theorem

〈r#(x)〉 true 〈r#(cdr(x))〉 truewhere r# terminates, iff its argument is an ordered list (in a module implementing sets byordered lists).

These regularities can be automated in the cosi strategy using the ‘module-specific’ heuristic.

G.2 Using the heuristic

The module-specific heuristic allows the user to specify sequent patterns and rule patterns. To-gether they form a module specific entry, which is one entry in the list of all entries.

Sequent patterns are schemata, describing a class of goals (i.e. sequents). The heuristic triesto match the current goal against the sequent patterns of all module specific entries (in the orderin which they are in the list). Matching a goal against a sequent pattern may be successful orunsuccessful. If it is unsuccessful for all patterns, the heuristic does nothing. If the heuristic finds

257

Page 259: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 258

a first pattern that matches the goal (i.e. for which the match is successful), the success yields asubstitution. The substitution is applied on the corresponding rule pattern, giving a rule and itsarguments. Then this rule is applied on the goal. If the rule is not applicable, there will be anerror message, and the heuristic will do nothing.

It is possible to specify that a module specific entry should only be applied once in a proofbranch, or that it should be applied only once with the same substitution.

The module specific entries are defined in the file

<projectdir>/modules/<module-name>/module-specific

for each module. This file is loaded when beginning to work on a module. It can be reloaded atany time using the command Reload Module Specific. The heuristic itself does not read the file,so you have to reload the file yourself if you modify it.

Normally, the file will contain some declarations of meta variables at the beginning (see below).The list of module specific entries is enclosed between

%"module specific

and

"

Nothing should follow afterwards.The following sections give detailed informations on the syntax of an module specific entry,

the action of matching sequents to sequent patterns and its substitution result, and the syntax ofrule patterns.

G.3 Syntax of module specific entries

A module specific entry is given by

• A first sequent pattern (that must be present in the goal)

• Optional, a second sequent pattern (that must not be present)

• A rule pattern

• Optional, how often the rule should be applied

The concrete syntax of a module specific entry is

pattern: sequent;

[forbidden: sequent;]

rule: name [rulearg];

[apply rule: (1 | 11 | once | unique | always);]

If there is no forbidden sequent you can omit the whole line. If you omit apply rule it defaultsto apply rule: always. name in the rule pattern is the rule that should be applied. For moreinformations about the rule pattern and apply rule see the corresponding sections below.

Formulas in the sequents are formula patterns (that match only the formula itself). Formulaschemes may include meta variables, that act as placeholders for formulas, boolean expressions(bxp‘s), programs, procedure declaration lists (pdl‘s), variable declaration lists (vdl‘s), variablelists (vl‘s), terms and variables. Matching instantiates them with concrete formulas, booleanexpressions etc.. All meta variables are symbols beginning with a $-sign and must be declaredbefore they can be used. The appropriate declarations have to be placed at the beginning of thefile.

Since a lot of meta variables are already predefined, most of the time only meta variables forterms and variables have to be defined. For a more detailed information of defining meta variables,see the last section. The following table lists the predifined meta variables.

Page 260: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 259

meta variables for variableFormulas $phi, $phi0, $phi1, $phi2

$psi, $psi0, $psi1, $psi2$chi, $chi0, $chi1, $chi2

Programs $alpha, $betaBoolean Expressions $epsilonVariable List $vl, $vl1, $vl2Variable Declaration List $vdl, $vdl1, $vdl2

Now you see some examples which explain when and how you could use the module specificheuristics, and how meta variables work.

1. consider a procedure call to a procedure add#, adding two integers, where the second argu-ment is zero. If every such procedure call in the succedent should be executed, the followingentry (note that nil is the empty list) should be added:

pattern: |- < add#(x,zero;xvar) > $phi;

rule: call right;

in the file module-specific.

2. consider two related procedure calls, like in

〈member#(x1, l1; b1)〉 b1 〈member#(x2, l2; b2)〉 b2

(in a module, implementing sets of elems by lists of elems). If the left procedure should beexecuted, whenever x1 = x2 and l2 = cdr(l1), and the result of both procedures is true, addthe following entry in the file module-specific:

pattern: < member#(x,l;bvar) > bvar = true |-

< member#(x,cdr(l);bvar0) > bvar0 = true ;

rule: call left;

3. In nearly every module, a lot of goals show up that relate the restriction procedure (orits subprocedures) for different arguments. These relations are often proved by separatetheorems. A typical example is the theorem r-rcdr

〈r#(l)〉 true, l �= nil 〈r#(cdr(l))〉 true

in the module implementing sets by ordered lists. To insert this theorem when the formulasof the antecedent and succedent of the theorem appear in the antecedent resp. succedent ofthe goal, the following module specific entry is used:

pattern: < r#(l) > true |- < r#(cdr(l)) > true;

rule: insert lemma r-rcdr with [l] -> [l];

apply rule: unique;

Two things have to be noticed:

(a) The theorem will be applied only once with the same substitution. Since the rule isagain applicable after the insertion of the theorem, applying the rule always might leadto a loop.

(b) The condition l �= nil of the theorem does not appear in the sequent pattern. Appli-cation of the theorem makes sense only if the condition holds. However, this may verywell be the case but the condition cannot be found literally in the goal. If we assumethat a term cdr(l) only shows up when the list l is not empty we can apply the theoremand hope that the condition can be proved.

Page 261: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 260

4. In many modules, the verification conditions VC T (i.e. i-1, i-2, . . . ) are used as theoremsin other proofs. Sometimes, it is useful to insert a theorem i-2:

〈r#(x)〉 true 〈f#(x; y)〉 〈r#(y)〉 true

whenever the formulas 〈r#(x)〉 true and 〈f#(x; y)〉 y = y0 appear in the sequent to get theadditional information 〈r#(y0)〉 true. This can be done by the following module specificentry (and some declarations):

pattern: < r#(x) > true, < f#(x;yvar) > yvar = y |- ;

forbidden: < r#(y) > true |- ;

rule: insert lemma i-2 with [x] -> [x];

apply rule: unique;

Note, that the formula 〈r#(y)〉 true that will be added in the antecedent by inserting thetheorem (and following contract call left) is explicitly prohibited to be already in the an-tecedent of the sequent. Otherwise the module specific heuristic would insert the theoremeven though it does not add really new information. Using the declaration to apply a ruleonly once with the same substitution is different from the declaration to apply the rule onlyonce, and is different from using forbidden formula patterns, because formulas may be elim-inated (by weakening left, call left, etc.) and variables may be renamed, which leads to thedanger of infinite loops.

G.4 Rule patterns

A rule pattern consists of two parts,

1. a name of a rule

Examples are

call left

call right

insert lemma

2. a pattern for a rule argument. This pattern is instantiated by applying Θ on it. The ruleargument should be admissible for the rule.

Actually, most of the existing rules of the proof strategy are never used for the module specificheuristic, either because they are always applied by other heuristics (like the rules for symbolicexecution) or because it is much to complicated to define a pattern when to apply the rule. Sothe following list of rules and their arguments is not complete but should cover all normal uses.

insert lemma

The insert lemma rule needs two informations: The name of the theorem to be inserted, given byand a substitution for the free variables of the theorem. So the rule pattern is given by

rule: insert lemma 〈theorem name〉 with 〈free variables〉 -> 〈term patterns〉

The 〈free variables〉 must be the list of the free variables of the theorem in any order, written e.g.as [x,y,z]. Note that this is the same list as shown in the pop-up window, when applying therule interactively, except that the order of the variables doesn’t matter. 〈term patterns〉 must bea list of term patterns of the same length. The i-th free variable of the first list is instantiated bythe i-th term of the second list. Since the pattern will be instantiated with the substitution Θ,you can use the meta variables of the sequent pattern.

Page 262: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 261

call left/right, split left/right

Used interactively, you have to select the formulas to discard. Used as a module specific entry,you have to do the same. However, you can only select a formula that is matched by a formulapattern. A formula position is given by an indicator for the antecedent (call/split left) or thesuccedent (call/split right) and an index i. The index refers to the position of the formulapattern in the list of patterns. The first formula that matches an indicated formula pattern willbe selected. If the sequent pattern is of the form

pattern: < f#(x;vary) > $phi,

< g#(x;vary) > $phi |- ;

the sequent is

〈g#(x;x0)〉 true, 〈f#(x;x0)〉 true, 〈g#(y; y0)〉 true, 〈f#(y; y0)〉 true

and the rule is

rule: call left

the rule will be applied on 〈f#(x;x0)〉 true. If the rule is

rule: call left 2

the rule will be applied on 〈g#(x;x0)〉 true. The same holds for the rules split left/right.

weakening

Used interactively, you have to select the formulas to discard. Used as a module specific entry, youselect a formula as described for the call left/right. Since it is possible to discard several formulas,the formula positions must be listed as

〈formula positions〉, 〈formula positions〉, ...

Example: If the sequent pattern is of the form

pattern: < f#(x;vary) > $phi,

< g#(x;vary) > $phi |- ;

the sequent is

〈g#(x;x0)〉 true, 〈f#(x;x0)〉 true, 〈g#(y; y0)〉 true, 〈f#(y; y0)〉 true

and the rule is

rule: weakening left 2

the formula 〈g#(x;x0)〉 true will be discarded.

cut formula

The rule cut formula requires a formula as its argument. This has to be entered as

rule: cut formula 〈formula〉;

The formula may contain meta variables from the sequent pattern.

Page 263: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 262

all left/exists right

The rules all left and exists right need the position of the quantified formula (again a formulaposition) and the substitution for the quantified variables (or a program). The formula position isignored and computed by the module specific heuristic in the same manner as for call left/right.For example the this must be entered as

rule: all left 1 with 〈list of terms〉;

The list of terms and the program may contain meta variables of the sequent pattern.

insert spec-lemma

The rule insert spec-lemma needs the theorem to apply and a substitution. The theorem isspecified by its name. However, since the theorem stems from another specification that wasperhaps actualized several times, the unique name of the theorem consists of three parts: Thespecification name, the instance name, and the theorem name. The three names are the same asdisplayed when viewing the theorem with the command View Spec Theorems. If the specificationwas not actualized you can leave out the instance name. The substitution is entered in the samemanner as for insert lemma, the complete rule has the form

rule: insert spec-lemma 〈theorem name〉 from specification

〈specification name〉 [〈instance name〉]with 〈free variables〉 -> 〈instantiations 〉;

or, if no instance name is needed,

rule: insert spec-lemma 〈theorem name〉 from specification

〈specification name〉 with 〈free variables〉 -> 〈instantiations 〉;

Apply Rule

As you saw in the section for the concrete syntax of an module specific entry, you can say howoften a rule should be applied. The given parameter are 1, 11, once, unique, always.

If you want that the rule should be applied everytime the sequent pattern matches, you haveto write

apply rule: always

If it should be applied only once, writeapply rule: once

orapply rule: 1

if the rule should be applied once with the same substitution, writeapply rule: unique

orapply rule: 11

If you omit the line apply rule:. . . , this has the same meaning as to write apply rule: always

Summary

The following list gives an overview over the rules and its corresponding arguments.

Page 264: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 263

rule argumentinsert lemma 〈theorem name〉 with 〈free variables〉 -> 〈term patterns〉call left ( |1|2|..|9)

call right ( |1|2|..|9)

split left ( |1|2|..|9)

split right ( |1|2|..|9)

weakening ((left|right) (1|2|3|..|9))+

cut formula 〈formula〉all left (1|2|3|..|9) with 〈list of terms〉exists right (1|2|3|..|9) with 〈list of terms〉insert spec-lemma 〈theorem name〉 from specification 〈specification name〉

[〈instance name〉] with 〈free variables〉 -> 〈instantiations〉;insert spec-lemma 〈theorem name〉 from specification 〈specification name〉

with 〈free variables〉 -> 〈instantiations 〉;

G.5 Matching

Matching a sequent against a sequent pattern is based on the notion of matching data structuresagainst patterns. A data structure obj matches a pattern pat, if there is a substitution for themeta variables of pat by concrete data structures of the appropriate type, such that applying thesubstitution on pat yields obj. The data structures that allow matching are formulas, programs,terms and lists and pairs built of the former. The following two subsections give examples forsuccessful matches, show some common errors, and explain how matching of sequents to sequentpatterns is reduced to ordinary matching of data structures to patterns.

Examples

1. %"x = y and y = z" matches %"$phi and $psi"

by the substitution {$phi ← x = y, $psi ← y = z}

2. %"x = z" matches %"$epsilon"

by the substitution {$epsilon ← x = z}

3. %"< skip > true" matches %"< $alpha > true"

by the substitution {$alpha ← skip}

4. %"x" matches %"$x"

by the substitution {$x ← x}, if the sort of x is int.

5. %"x := add(y,z)" matches %"<$xvar := $x"

by the substitution {$xvar ← x, $x ← add(y,z)}, if the sort of x is int.

6. %"all x. x = x" matches %"all \$vl. \$phi"

by the substitution {$vl ← (x), $phi ← x = x}

7. matches %"all $xvar,$vl. true"

by the substitution {$vl ← (), $xvar ← x}, if the sort of x is int,

but not %"all $xvar,$vl,$yvar. true"

8. (list %"skip" %"abort") matches (list %"$alpha" %"$beta")

by the substitution {$alpha ← skip, $beta ← abort},but not (list %"$alpha" %"$alpha")

Page 265: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 264

9. %"[x, add(x,y)]" matches %"[$x, $y]"

by the substitution {$x ← x, $y ← add(x,y)},

10. (mkpair (list %"true" %"x = y") (list %"x = y"))

matches

(mkpair (list %"$phi" %"$psi") (list %"$psi"))

by the substitution {$phi ← true, $psi ← x = y}

Common Errors

1. %"all x. x = z" does not match %"$epsilon", since all x. x = z is not a boolean expression

2. (list) does not match (list %"$phi"), since the lists have different length.

3. (mkpair %"true" %"false" does not match (mkpair %"$phi" %"$phi"), since the samemetavariable cannot be instantiated by different data structures simultaneously. So usedifferent metavariables for different datastructures.

4. %"add(y,z)" does not match %"$xvar", since the xmv $xvar matches only variables, notgeneral terms.

5. %"f#($xvar; $yvar)" does not match %"f#(add(x,y); z)" since the xmv $xvar matchesonly variables, not general terms. Therefore, do not use xmv’s as mv’s for value-parameters.Use termmvs instead.

6. Diamond formulas in cosi sequents always have a procedure declaration list (pdl) in front oftheir programs, that is hidden by the pretty-printer. So a formula printed

< f#(add(y,z); x) > true"

must be written (e. g. in the sequents file) as

%"< procedure ‘module-decls in begin f#(add(y,z); x) end > true"

Therefore the prodedure above matches

%"< procedure $pdl in begin f#($x; $xvar) end > true"

but not

%"< f#($x; $xvar) > true"

7. Note that there are hidden pdl‘s not only in front of procedure calls, but also in front ofother programs, even if there are no procedure calls in the program. So a formula printed

< skip > true

is a shortcut for

< procedure ‘module-decls in begin skip end > true

8. There are several pdl’s in the formulas, that appear while verifying a module: The mod-ule declaration, containing the implementation of the module (written module-decls in thesequents-file), the restriction declaration (written rest-decls in the sequents-file) and for allmodules for which VC A (i.e the vc’s iiii-1, iiii-2, . . . ) the declaration of the uniform restric-tion (written uniform-decls in the sequents-file). Since different pdl‘s cannot be matched bythe same $pdl, use different mv‘s for different pdl‘s.

Page 266: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 265

Matching Sequents on Sequent Patterns

A given sequent matches a sequent pattern, where the first list of formula schemes l1 has lengthm, and the second list l2 has length n, iff

1. there are m different formulas ϕ1, . . . , ϕm in the antecedent of the sequent (in arbitrary order)and n different formulas ψ1, . . . , ψn in the succedent, such that (mkpair (list ϕ1, . . . , ϕm) (listψ1, . . . , ψn)) matches (mkpair l1 l2) with substitution Θ.

2. Applying Θ on the third and fourth list of the sequent pattern yields two lists of formulas(not only formula patterns!) l3 and l4, such that none of the formulas in l3 appear in theantecedent of the sequent, and none of the formulas in l4 appear in the succedent of thesequent.

G.6 Defining meta variables

Meta variables for formulas: fmamv

• predefined meta variables: $phi, $psi, $chi

• naming convention: additional meta variables should be named $phi1, $psi3, $chi0 etc.

• declaration: (defexprmv (mksym "$phi1") %"bool")

• examples of use:

%"$phi and $psi"

%"< skip > $phi"

%"not [ abort ]($phi -> $psi)"

Meta variables for boolean expressions: bxpmv

• predefined meta variables: $epsilon

• naming convention: additional meta variables should be named $epsilon0, $epsilon1, etc.

• declaration: (defbxpmv (mksym "$epsilon1"))

• examples of use:

%"< if $epsilon then skip > true"

%"$epsilon and $psi"

%"< if $epsilon then skip > all x. $epsilon and $phi"

Meta variables for programs: progmv

• predefined meta variables: $alpha, $beta

• naming convention: additional meta variables should be named $beta3, $alpha0 etc.

• declaration: (defprogmv (mksym "$alpha0"))

• examples of use:

%"< $alpha > $phi"

%"[ begin $alpha; $beta end ] true"

%"not < if $epsilon then $alpha else $beta > true"

Page 267: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 266

Meta variables for procedure declaration lists: pdlmv

• predefined meta variables: $pdl, $pdl1, $pdl2

• naming convention: additional meta variables should be named $pdl0, $pdl3 etc.

• declaration: (defpdlmv (mksym "$pdl0"))

• examples of use:

%"< procedure $pdl in begin $alpha end > $phi"

Meta variables for variable declaration lists: vdlmv

• predefined meta variables: $vdl, $vdl1, $vdl2

• naming convention: additional meta variables should be named $vdl0, $vdl3 etc.

• declaration: (defpdlmv (mksym "$vdl0"))

• examples of use:

%"< var $vdl in begin $alpha end > $phi"

• remark: rarely used

Meta variables for variable lists: vlmv

• predefined meta variables: $vl, $vl1, $vl2

• naming convention: additional meta variables should be named $vl0, $vl3 etc.

• declaration: (defpdlmv (mksym "$vl0"))

• examples of use:

%"all $vl. $phi"

%"all x,$vl,y. $phi"

%"all x,$vl. $phi"

%"all $vl,x. $phi"

• remark: only one vlmv is allowed in the list of quantified variables

%"all \$vl1,x,\$vl2. \$phi" is illegal. x,$vl,y can be instantiated to any concrete listof variables beginning with x and ending with y. x,$vl,x can not be instantiated to the listcontaining only x.

Meta variables for terms: termmv

• predefined meta variables: none

• naming convention: additional meta variables should be named as corresponding variables(but beginning with $)

• declaration: (termmvs (list "var1" . . . "varn"))

var1 . . . varn must be existing variables. Then the meta variables $var1 . . . $varn are defined,e. g.

(termmvs (list "x" "y" "z"))

Page 268: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

APPENDIX G. THE MODULE SPECIFIC HEURISTIC 267

• examples of use:

%"< x := $x > $phi"

%"x = $x"

%"< procedure $pdl in begin r#($x) end > $phi

• remark: you can define new variables in the file in the same manner as in the sequents file:%"variables x, y, z: nat;"

• remark: Always use meta variables for terms if possible instead of meta variables for vari-ables, because meta variables for variables will not match a term. Use them only in situationswhere terms are not allowed (see below).

Meta variables for variables: xmv

• predefined meta variables: none

• naming convention: additional meta variables should be named $〈prefix〉 var where prefix isthe name of a corresponding variable

• declaration: (varmvs (list "var1" . . . "varn"))

var1 . . . varn must be existing variables. Then the meta variables $var1 . . . $varn are defined,e. g.

(varmvs (list "xvar" "yvar" "zvar"))

• examples of use:

%"< $xvar := $x > $phi"

%"$xvar = $x"

%"< procedure $pdl in begin f#($x;$xvar) end > $phi"

%"ex $xvar, $yvar, $zvar. $phi"

%"all $xvar,$vl,$yvar. $phi"

• remark: you can define new variables in the file in the same manner as in the sequents file:%"variables x, y, z: nat;"

• remark: Note that meta variables for variables are acceptable as left sides of assignmentsand variable declarations, as var parameters in procedure calls and as quantified variables,but not termmvs!! In the above examples you had to use meta variables for variables. Ifpossible you should use meta variables for terms.

Page 269: A Practical Course on KIV · A Practical Course on KIV Gidon Ernst Dominik Haneberg J¨org Pf¨ahler Wolfgang Reif Gerhard Schellhorn Kurt Stenzel Bogdan Tofan Institute for Software

Bibliography

[Abr03] Jean-Raymond Abrial. Event based sequential program development: Application toconstructing a pointer program. In FME, pages 51–74, 2003.

[And86] Peter B. Andrews. An Introduction to Mathematical Logic and Type Theory: To TruthThrough Proof. Academic Press, 1986.

[BS03] E. Borger and R. F. Stark. Abstract State Machines—A Method for High-Level SystemDesign and Analysis. Springer-Verlag, 2003.

[Dij76] E. W. Dijkstra. A Discipline of Programming, chapter 14. Prentice-Hall, EnglewoodCliffs, N. J., 1976.

[Har84] David Harel. Dynamic logic. In D. Gabbay and F. Guenther, editors, Handbook ofPhilosophical Logic, volume 2, pages 496–604. Reidel, 1984.

[HHS86] H. Jifeng, C. A. R. Hoare, and J. W. Sanders. Data refinement refined. In B. Robinet andR. Wilhelm, editors, Proc. ESOP 86, volume 213 of Lecture Notes in Computer Science,pages 187–196. Springer-Verlag, 1986.

[Hoa69] C.A.R. Hoare. An axiomatic basis for computer programming. COMM ACM, pages576–580, 1969.

[Jon87] C. B. Jones. Program Specification and Verification in VDM, Logic of Programming andCalculi of Discrete Design. Springer, 1987.

[LBR06] Gary T. Leavens, Albert L. Baker, and Clyde Ruby. Preliminary design of JML: A be-havioral interface specification language for Java. ACM SIGSOFT Software EngineeringNotes, 31(3):1–38, March 2006.

[LS80] J. Loeckx and K. Sieber. The Foundations of Program Verification. Wiley and Sons,1980.

[Ric78] M. Richter. Logikkalkule. Teubner, Stuttgart, 1978.

[SA91] Volker Sperschneider and Gigorios Antoniou. Logic: A Foundation for Computer Science.Addison Wesley, 1991.

[Spi92] J. Michael Spivey. The Z Notation: A Reference Manual. Prentice Hall InternationalSeries in Computer Science, 2nd edition, 1992.

[SSB01] R.F. Stark, J. Schmid, and E. Borger. Java and the Java Virtual Machine: Definition,Verification, Validation. Springer, 2001.

[Ste01] K. Stenzel. Verification of JavaCard Programs. Technical report 2001-5, Institut fur Infor-matik, Universitat Augsburg, Germany, 2001. Available at http://www.Informatik.Uni-Augsburg.DE/swt/fmg/papers/.

[WD96] J. C. P. Woodcock and J. Davies. Using Z: Specification, Proof and Refinement. PrenticeHall International Series in Computer Science, 1996.

268


Recommended