├── 2022 ├── LICENSE ├── README.md ├── chapter01-basics │ └── exercises │ │ ├── DirectionsLibrary.dfy │ │ ├── LunchLibrary.dfy │ │ ├── UtilitiesLibrary.dfy │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ ├── exercise03.dfy │ │ ├── exercise04.dfy │ │ ├── exercise05.dfy │ │ ├── exercise06.dfy │ │ ├── exercise07.dfy │ │ ├── exercise08.dfy │ │ ├── exercise09.dfy │ │ ├── exercise10.dfy │ │ ├── exercise11.dfy │ │ ├── exercise12.dfy │ │ ├── exercise13.dfy │ │ ├── exercise14.dfy │ │ ├── exercise15.dfy │ │ ├── exercise16.dfy │ │ ├── exercise17.dfy │ │ ├── exercise18.dfy │ │ ├── exercise19.dfy │ │ ├── exercise20.dfy │ │ ├── exercise21.dfy │ │ └── exercise22.dfy ├── chapter02-specification │ └── exercises │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ ├── exercise03.dfy │ │ ├── exercise03a.dfy │ │ └── exercise03b.dfy ├── chapter03-state-machines │ └── exercises │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter04-invariants │ └── exercises │ │ ├── exercise01.dfy │ │ └── exercise02.dfy ├── chapter05-distributed-state-machines │ └── exercises │ │ ├── CommitTypes.dfy │ │ ├── UtilitiesLibrary.dfy │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter06-refinement │ └── exercises │ │ ├── CommitTypes.dfy │ │ ├── UtilitiesLibrary.dfy │ │ ├── ch06exercise01.dfy │ │ ├── ch06exercise02.dfy │ │ ├── ch06exercise03.dfy │ │ ├── ch06exercise04.dfy │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter07-async-clients │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ └── exercise01.dfy ├── chapter08-application-correspondence │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ └── exercise01.dfy ├── index.html ├── lectures │ ├── lecture1-2.png │ ├── lecture1.pdf │ ├── lecture1.pptx │ ├── lecture10-2.png │ ├── lecture10.pdf │ ├── lecture10.pptx │ ├── lecture11-2.png │ ├── lecture11.pdf │ ├── lecture11.pptx │ ├── lecture12-2.png │ ├── lecture12.pdf │ ├── lecture12.pptx │ ├── lecture13-2.png │ ├── lecture13.pdf │ ├── lecture13.pptx │ ├── lecture14-2.png │ ├── lecture14.pdf │ ├── lecture14.pptx │ ├── lecture15-2.png │ ├── lecture15.pdf │ ├── lecture15.pptx │ ├── lecture16-2.png │ ├── lecture16.pdf │ ├── lecture16.pptx │ ├── lecture2-2.png │ ├── lecture2.pdf │ ├── lecture2.pptx │ ├── lecture3-2.png │ ├── lecture3.pdf │ ├── lecture3.pptx │ ├── lecture4-2.png │ ├── lecture4.pdf │ ├── lecture4.pptx │ ├── lecture5-2.png │ ├── lecture5.pdf │ ├── lecture5.pptx │ ├── lecture6-2.png │ ├── lecture6.pdf │ ├── lecture6.pptx │ ├── lecture7-2.png │ ├── lecture7.pdf │ ├── lecture7.pptx │ ├── lecture8-2.png │ ├── lecture8.pdf │ ├── lecture8.pptx │ ├── lecture9-2.png │ ├── lecture9.pdf │ └── lecture9.pptx ├── main.css ├── project01-distributed-lock-server │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ ├── distributed_system.t.dfy │ │ ├── exercise01.dfy │ │ ├── host.v.dfy │ │ └── network.t.dfy └── project02-sharded-kv-store │ └── exercises │ ├── AsyncKVSpec.t.dfy │ ├── AtomicKV.t.dfy │ ├── AtomicKVSpec.t.dfy │ ├── DistributedSystem.t.dfy │ ├── EventSequenceRecorder.t.dfy │ ├── Host.v.dfy │ ├── IMapHelpers.t.dfy │ ├── MessageType.v.dfy │ ├── Network.t.dfy │ ├── RefinementObligation.t.dfy │ ├── RefinementProof.v.dfy │ ├── Types.t.dfy │ └── UtilitiesLibrary.t.dfy ├── README.md ├── fall2024 ├── chapter01-basics │ └── exercises │ │ ├── DirectionsLibrary.dfy │ │ ├── LunchLibrary.dfy │ │ ├── UtilitiesLibrary.dfy │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ ├── exercise03.dfy │ │ ├── exercise04.dfy │ │ ├── exercise05.dfy │ │ ├── exercise06.dfy │ │ ├── exercise07.dfy │ │ ├── exercise08.dfy │ │ ├── exercise09.dfy │ │ ├── exercise10.dfy │ │ ├── exercise11.dfy │ │ ├── exercise12.dfy │ │ ├── exercise13.dfy │ │ ├── exercise14.dfy │ │ ├── exercise15.dfy │ │ ├── exercise16.dfy │ │ ├── exercise17.dfy │ │ ├── exercise18.dfy │ │ ├── exercise19.dfy │ │ ├── exercise20.dfy │ │ ├── exercise21.dfy │ │ └── exercise22.dfy ├── chapter02-specification │ └── exercises │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter03-state-machines │ └── exercises │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter04-invariants │ └── exercises │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter05-distributed-state-machines │ └── exercises │ │ ├── CommitTypes.dfy │ │ ├── UtilitiesLibrary.dfy │ │ ├── exercise01.dfy │ │ ├── exercise02.dfy │ │ └── exercise03.dfy ├── chapter06-refinement │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ └── exercise01.dfy ├── chapter07-async-clients │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ └── exercise01.dfy ├── chapter08-application-correspondence │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ └── exercise01.dfy ├── index.html ├── lectures │ ├── lecture1-2.png │ ├── lecture1-9.png │ ├── lecture1.pdf │ ├── lecture1.pptx │ ├── lecture10-2.png │ ├── lecture10-6.png │ ├── lecture10.pdf │ ├── lecture10.pptx │ ├── lecture11-2.png │ ├── lecture11.pdf │ ├── lecture11.pptx │ ├── lecture12-2.png │ ├── lecture12.pdf │ ├── lecture12.pptx │ ├── lecture13-2.png │ ├── lecture13-7.png │ ├── lecture13.pdf │ ├── lecture13.pptx │ ├── lecture14-2.png │ ├── lecture14.pdf │ ├── lecture14.pptx │ ├── lecture15-2.png │ ├── lecture15.pdf │ ├── lecture15.pptx │ ├── lecture16-2.png │ ├── lecture16-6.png │ ├── lecture16.pdf │ ├── lecture16.pptx │ ├── lecture17-2.png │ ├── lecture17-5.png │ ├── lecture17.pdf │ ├── lecture17.pptx │ ├── lecture18-2.png │ ├── lecture18-3.png │ ├── lecture18.pdf │ ├── lecture18.pptx │ ├── lecture19-2.png │ ├── lecture19-5.png │ ├── lecture19.pdf │ ├── lecture19.pptx │ ├── lecture2-2.png │ ├── lecture2-4.png │ ├── lecture2.pdf │ ├── lecture2.pptx │ ├── lecture20-2.png │ ├── lecture20-6.png │ ├── lecture20.pdf │ ├── lecture20.pptx │ ├── lecture3-2.png │ ├── lecture3.pdf │ ├── lecture3.pptx │ ├── lecture4-2.png │ ├── lecture4.pdf │ ├── lecture4.pptx │ ├── lecture5-2.png │ ├── lecture5-4.png │ ├── lecture5.pdf │ ├── lecture5.pptx │ ├── lecture6-2.png │ ├── lecture6.pdf │ ├── lecture6.pptx │ ├── lecture7-2.png │ ├── lecture7-4.png │ ├── lecture7.pdf │ ├── lecture7.pptx │ ├── lecture8-2.png │ ├── lecture8-4.png │ ├── lecture8.pdf │ ├── lecture8.pptx │ ├── lecture9-2.png │ ├── lecture9-6.png │ ├── lecture9.pdf │ └── lecture9.pptx ├── main.css ├── project01-distributed-lock-server │ └── exercises │ │ ├── UtilitiesLibrary.dfy │ │ ├── distributed_system.t.dfy │ │ ├── exercise01.dfy │ │ ├── host.v.dfy │ │ └── network.t.dfy └── project02-sharded-kv-store │ └── exercises │ ├── AtomicKVSpec.t.dfy │ ├── DistributedSystem.t.dfy │ ├── Host.v.dfy │ ├── IMapHelpers.t.dfy │ ├── MessageType.v.dfy │ ├── Network.t.dfy │ ├── RefinementObligation.t.dfy │ ├── RefinementProof.v.dfy │ ├── Types.t.dfy │ └── UtilitiesLibrary.t.dfy └── index.html /2022/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GLaDOS@Michigan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /2022/README.md: -------------------------------------------------------------------------------- 1 | # verification-class 2 | Material for the class on verification of distributed and asynchronous systems, developed by Jon Howell and Manos Kapritsos 3 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/DirectionsLibrary.dfy: -------------------------------------------------------------------------------- 1 | //#desc Library for exercises 12 & 14 2 | 3 | // This is tagged union, a "sum" datatype. 4 | datatype Direction = North() | East() | South() | West() 5 | 6 | function TurnRight(direction:Direction) : Direction 7 | { 8 | // This function introduces two new bits of syntax. 9 | // First, the if-else expression: if then T else T 10 | // Second, the element.Ctor? built-in predicate, which tests whether 11 | // the datatype `element` was built by `Ctor`. 12 | if direction.North? 13 | then East 14 | else if direction.East? 15 | then South 16 | else if direction.South? 17 | then West 18 | else // By elimination, West! 19 | North 20 | } 21 | 22 | lemma Rotation() 23 | { 24 | assert TurnRight(North) == East; 25 | } 26 | 27 | function TurnLeft(direction:Direction) : Direction 28 | { 29 | // Another nice way to take apart a datatype element is with match-case 30 | // construct. Each case argument is a constructor; each body must be of the 31 | // same type, which is the type of the entire `match` expression. 32 | match direction { 33 | case North => West 34 | case West => South 35 | case South => East // Try changing "East" to 7. 36 | case East => North 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/LunchLibrary.dfy: -------------------------------------------------------------------------------- 1 | //#desc Library for exercises 13 & 14 2 | 3 | // This whole product-sum idea gets clearer when we use both powers 4 | // (struct/product, union/sum) at the same time. 5 | 6 | datatype Meat = Salami | Ham 7 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 8 | datatype Veggie = Olive | Onion | Pepper 9 | datatype Order = 10 | Sandwich(meat:Meat, cheese:Cheese) 11 | | Pizza(meat:Meat, veggie:Veggie) 12 | | Appetizer(cheese:Cheese) 13 | 14 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 15 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 16 | // Thus there are 8+6+4 = 18 Orders. 17 | // This is why they're called "algebraic" datatypes. 18 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Lemmas and assertions 2 | 3 | lemma IntegerOrdering() 4 | { 5 | // An assertion is a **static** check of a boolean expression -- a mathematical truth. 6 | // This boolean expression is about (mathematical) literal integers. 7 | // Run dafny on this file. See where it fails. Fix it. 8 | assert /*{*/ 5 < 3 /*}*/; 9 | } 10 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Boolean logic 2 | 3 | lemma BooleanLogic() 4 | { 5 | // An assertion is a static check of a boolean expression. 6 | // This boolean expression is about a boolean implication. 7 | // Run dafny on this file. See where it fails. Fix it. 8 | assert true ==> /*{*/ false /*}*/; 9 | } 10 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Functions 2 | 3 | // A `function` is a mathematical function. 4 | // This one has a domain of the integers and the range is (within) the 5 | // integers. Again, `int` is the entire set of mathematical integers. 6 | 7 | // Run dafny on this file. See where it fails. Fix it. 8 | 9 | ghost function Double(val:int) : int 10 | { 11 | // The body of a function is an expression context. No semicolon 12 | // at the end. 13 | 2 * val 14 | } 15 | 16 | // A lemma is like a C++ method or C function (hence the statement context). 17 | // The proof it contains is like a program: a sequence of statements. 18 | // As in C, statements terminate with semicolons and can be grouped into blocks 19 | // with braces. 20 | lemma DoubleIsLikePlus() 21 | { 22 | assert Double(6) == 6 + 6; 23 | { 24 | assert Double(-2) == /*{*/4/*}*/; 25 | } 26 | } 27 | 28 | // A lemma can take arguments. This is one way to prove a statement about 29 | // *any* value, not just a particular literal. 30 | lemma foo4(val:int) 31 | { 32 | assert Double(val) == val + /*{*/val + val/*}*/; 33 | } 34 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise04.dfy: -------------------------------------------------------------------------------- 1 | //#title Predicates 2 | 3 | // A common thing you'll want is a function with a boolean result. 4 | ghost function AtLeastTwiceAsBigFunction(a:int, b:int) : bool 5 | { 6 | a >= 2*b 7 | } 8 | 9 | // It's so fantastically common that there's a shorthand for it: `predicate`. 10 | ghost predicate AtLeastTwiceAsBigPredicate(a:int, b:int) 11 | { 12 | a >= 2*b 13 | } 14 | 15 | ghost function Double(a:int) : int 16 | { 17 | 2 * a 18 | } 19 | 20 | lemma TheseTwoPredicatesAreEquivalent(x:int, y:int) 21 | { 22 | assert AtLeastTwiceAsBigFunction(x, y) == AtLeastTwiceAsBigPredicate(x, y); 23 | } 24 | 25 | // Add a 'requires' precondition to make this lemma verify. 26 | // Keep it as simple as possible (e.g. avoid named predicates). 27 | lemma FourTimesIsPrettyBig(x:int) 28 | /*{*/ 29 | /*}*/ 30 | { 31 | assert AtLeastTwiceAsBigPredicate(Double(Double(x)), x); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise05.dfy: -------------------------------------------------------------------------------- 1 | //#title Sets 2 | 3 | // This predicate takes a set of integers as an argument. 4 | // set is a built-in templated type. 5 | ghost predicate HasSevenAndNotNine(intset:set) 6 | { 7 | 7 in intset && 9 !in intset 8 | } 9 | 10 | lemma TryOutSomeSetLiterals() 11 | { 12 | assert {1,3,8} == {8,1,3}; 13 | 14 | assert HasSevenAndNotNine({7}); 15 | 16 | // None of these asserions are correct. Try them. 17 | // Then delete these first two... 18 | /*{*/ 19 | assert HasSevenAndNotNine({7,9}); 20 | assert HasSevenAndNotNine({1,3,5,7,8,9,10}); 21 | /*}*/ 22 | // ...and replace the argument of this assert with a set that does satisfy 23 | // the predicate. 24 | assert HasSevenAndNotNine({/*{*//*}*/}); 25 | } 26 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise06.dfy: -------------------------------------------------------------------------------- 1 | //#title More set tools 2 | 3 | // <= on sets is subset. 4 | ghost predicate HasFourFiveSix(intset:set) 5 | { 6 | {6,5,4} <= intset // I can because they're sets! 7 | } 8 | 9 | lemma SomeAssertionsAboutSets() 10 | { 11 | assert !HasFourFiveSix({1,2,4,6,7}); 12 | 13 | // This is just a mathematical "let" statement. 14 | // It's safe to substitute the value wherever "happySet" appears. 15 | var happySet := {1,2,4,6,7,5}; 16 | assert HasFourFiveSix(happySet); 17 | 18 | // - on sets is difference. 19 | assert happySet - {4,5,6} == {7,2,1}; 20 | 21 | // + on sets is union. 22 | assert HasFourFiveSix({4,6} + {5}); 23 | 24 | // |x| on a set is cardinality. 25 | // (set is always finite; there is another type iset for 26 | // possibly-infinite sets.) 27 | assert |happySet| == /*{*/7/*}*/; 28 | } 29 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise07.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: Literals, indexing 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | // [x,y,z] is a literal sequence; this one is a seq. 6 | var fibo := [1,1,2,3,5,8,13,21,34]; 7 | // Index into a sequence. 8 | assert fibo[4] == 5; 9 | 10 | // Sequences have cardinality (and hence are always finite length). 11 | assert |fibo| == 9; 12 | assert fibo[0] == 1; 13 | assert fibo[8] == 34; 14 | assert fibo[/*{*/9/*}*/] == 21; 15 | } 16 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise08.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: Slices 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | var fibo := [1,1,2,3,5,8,13,21,34]; 6 | 7 | // A slice of a sequence is a sequence. 8 | // The left argument is inclusive, the right exclusive. 9 | assert fibo[2..4] == [2,3]; 10 | 11 | // You can omit either endpoint to refer to the beginning or end of the 12 | // sequence. 13 | assert fibo[..3] == [1,1,2]; 14 | assert fibo[7..] == [21,34]; 15 | 16 | assert fibo[5..6] == /*{*/8/*}*/; 17 | } 18 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise09.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: types, cardinality 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | var fibo := [1,1,2,3,5,8,13,21,34]; 6 | 7 | // The type of fibo is seq. 8 | // Here, we explicitly declare the type of `copy`. In previous examples, the 9 | // type has always been inferred by the compiler. I just wanted you to see 10 | // what it was inferring. 11 | var copy:seq := fibo; 12 | 13 | // You can, of course, have a seq of other stuff. 14 | var seqOfSets:seq> := [{0}, {0,1}, {0,1,2}]; 15 | 16 | var whatsMyProblem := [0, /*{*/1, false/*}*/]; 17 | 18 | // |expr| below is sequence-length 19 | assert |seqOfSets| == 3; 20 | // Type checking means the |expr| below is a set-cardinality operator. 21 | assert |seqOfSets[1]| == /*{*/3/*}*/; 22 | } 23 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise10.dfy: -------------------------------------------------------------------------------- 1 | //#title Type synonyms 2 | 3 | // So by now you see me composing types and you're itching to 4 | // construct some of your own. 5 | 6 | // First, type renaming: 7 | type SeqOfSets = seq> 8 | 9 | lemma TryATypeSynonym() 10 | { 11 | var seqOfSets:SeqOfSets := [{0}, {0,1}, {0,1,2}]; 12 | assert 1 in /*{*/seqOfSets[0]/*}*/; 13 | } 14 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise11.dfy: -------------------------------------------------------------------------------- 1 | //#title Struct (product) datatypes. 2 | 3 | // Okay, but I know you won't settle for merely renaming some fancy type 4 | // expression. You actually want to define something new. 5 | 6 | // Dafny has "algebraic" datatypes which capture both "struct" 7 | // and (tagged) "union". 8 | // First, structs: 9 | datatype Point = PointCtor(x:int, y:int) 10 | 11 | // You could alternatively write this as: 12 | // datatype Point = Point(x:int, y:int) 13 | // The first "Point" is the type name, the second is the constructor name. When 14 | // the type has only one constructor, it's conventional to give them the same 15 | // name since the language can distinguish the two uses from context. 16 | 17 | /*{*/ 18 | ghost function subtractPoints(tip:Point, tail:Point) : Point 19 | { 20 | PointCtor(tip.x - tail.x, tip.y - tail.x) 21 | } 22 | /*}*/ 23 | 24 | lemma PointArithmetic() 25 | { 26 | var a := PointCtor(1,13); 27 | var b := PointCtor(2,7); 28 | 29 | // NB Points (and every other `datatype`) are mathematical, immutable 30 | // objects, so the one we get back from the function must be equal 31 | // (identical) to the one we construct manually. There's no implicit 32 | // user-overridable Equals() method; these are platonic mathematical objects. 33 | 34 | // This exercise is a little harder than the previous ones; take a moment 35 | // to investigate it carefully! 36 | assert subtractPoints(a, b) == PointCtor(-1, 6); 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise12.dfy: -------------------------------------------------------------------------------- 1 | //#title include directive and Union (sum) datatypes 2 | 3 | // You can include code from another file. includes must all appear at the 4 | // beginning of a file, before any other definitions. 5 | // Open and read DirectionsLibrary.dfy 6 | include "DirectionsLibrary.dfy" 7 | 8 | lemma TwoWrongsDontMakeARight(dir:Direction) 9 | { 10 | assert TurnLeft(/*{*/TurnLeft(TurnLeft(dir))/*}*/) == TurnRight(TurnRight(dir)); 11 | } 12 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise13.dfy: -------------------------------------------------------------------------------- 1 | //#title More with algebraic datatypes. 2 | 3 | // Begin by reading LunchLibrary.dfy. We extracted it 4 | // to a separate file because we'll use it again later. 5 | include "LunchLibrary.dfy" 6 | 7 | lemma AlgebraicLunch() 8 | { 9 | var meal:set := { 10 | Pizza(Ham, Olive), 11 | Sandwich(Ham, Provolone), 12 | Pizza(Ham, Olive) 13 | }; 14 | // Fix this assertion. Hint: The two pizzas are the same element of the datatype. 15 | assert |meal| == /*{*/3/*}*/; 16 | } 17 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise14.dfy: -------------------------------------------------------------------------------- 1 | //#title Quantifiers 2 | include "LunchLibrary.dfy" 3 | include "DirectionsLibrary.dfy" 4 | 5 | // Most of what we'll be working with in proof are quantified 6 | // statements: for all inputs, my program produces the right output! 7 | lemma Forall() 8 | { 9 | assert forall x:int :: x+x == 2*x; 10 | } 11 | 12 | // Remember this critter from exercise12? We can rewrite it in a forall. 13 | lemma AnotherForall() 14 | { 15 | // "Two wrongs don't make a right, but ..." 16 | assert forall dir :: TurnLeft(/*{*/TurnLeft(TurnLeft(dir))/*}*/) == TurnRight(TurnRight(dir)); 17 | } 18 | 19 | // Here's there-exists, forall's evil twin. 20 | // exists x :: P(x) == !forall x :: !P(x) 21 | lemma TryThatCheeseOnASandwich() 22 | { 23 | // Hey, neat. Dafny has a hard time proving exists. It needs 24 | // a "witness". 25 | // To proceed, replace 'false' with 'true', and move on to the 26 | // next lemma to read about how to solve it. 27 | // If the '?' syntax is surprising, go re-read DirectionsLibrary.dfy. 28 | assert (forall o1:Order :: 29 | o1.Appetizer? 30 | ==> exists o2:Order :: o2.Sandwich? && o1.cheese == o2.cheese) 31 | || /*{*/ false /*}*/; 32 | } 33 | 34 | lemma CheeseTakeTwo() 35 | { 36 | // So here's the "statement" version of a forall expression. 37 | // With nothing in the body, it's exactly equivalent to the assertion 38 | // above. 39 | forall o1:Order 40 | // The assumptions follow a '|' ("such that") 41 | | o1.Appetizer? 42 | // The conclusions follow a "requires" keyword. 43 | ensures exists o2:Order :: o2.Sandwich? && o1.cheese == o2.cheese 44 | { 45 | // The body of the forall statement is a proof context for the 46 | // statement's conclusion. Inside here, o1 is defined, and we 47 | // can use it to complete the proof. 48 | 49 | // But how? What's missing is that Dafny needs a "witness" to the 50 | // there-exists. We need to show an expression that satisfies the 51 | // body of the exists. Try uncommenting these lines: 52 | /*{*////*}*/ var o3 := Sandwich(Ham, o1.cheese); 53 | /*{*////*}*/ assert o3.Sandwich? && o1.cheese == o3.cheese; 54 | // Simply *mentioning* an Order that satisfies the predicate 55 | // on o2 above is enough for Dafny to see the proof; once we mention 56 | // it, Dafny will try plugging it into the expression. Try removing 57 | // the assertion above this comment; notice that the proof still goes 58 | // through. 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise15.dfy: -------------------------------------------------------------------------------- 1 | //#title Maps. Set, Map and Sequence comprehensions. 2 | 3 | ghost predicate IsEven(x:int) 4 | { 5 | x/2*2==x 6 | } 7 | 8 | lemma SetComprehension() 9 | { 10 | // Here's how you define a "big" (perhaps unknown size, but finite) set: 11 | // Read it as "the set of values x such that (|) x is between 0 and 10 and is even." 12 | // (In general, it's "the set of value x such that predicate P(x) is true".) 13 | var modestEvens := set x | 0 <= x < 10 && IsEven(x); 14 | assert modestEvens == {/*{*/0,2,4,8/*}*/}; 15 | } 16 | 17 | lemma Maps() 18 | { 19 | // Map generic type, map literal syntax 20 | var doubleMap:map := map[1:=2, 2:=4, 3:=6, 4:=8]; 21 | 22 | assert doubleMap[3] == 6; 23 | 24 | var replaceMap := doubleMap[3 := 7]; 25 | assert replaceMap[1] == 2; 26 | assert replaceMap[2] == 4; 27 | assert replaceMap[3] == /*{*/6/*}*/; 28 | } 29 | 30 | lemma MapComprehension() 31 | { 32 | // Here's how you define a "big" (but finite-domain) map. Read it as 33 | // "The map with domain x such that 0<=x<5" (that is, domain is defined just like a set comprehension) 34 | // ..."and for which the value at [x] is 2*x" (the thing after :: is an expression of the value type). 35 | // This map is type-inferred to be map. 36 | var doublyMap := map x | 0<=x<5 :: 2*x; 37 | assert doublyMap[1] == 2; 38 | assert doublyMap[4] == /*{*/4/*}*/; 39 | } 40 | 41 | lemma SeqComprehension() 42 | { 43 | // The sequence comprehension syntax is, unfortunately, kinda hideous compared 44 | // to the set & map comprehensions. seq(N, f) is a function. 45 | // 46 | // N is the size of the output sequence (that is, |eventsInOrder| == 5). 47 | // 48 | // f is a function -- in this case an anonymous lambda -- that gives the value 49 | // at each index. The "i" before the "=>" is the parameter list of the lambda; 50 | // "i*2" is the expression body of the lambda function. The "requires 0<=i<5" 51 | // is a way to pass into the lambda the knowledge that seq() will only call 52 | // it with those particular values. It's not actually needed here (since the 53 | // expression i*2 works on all integers), but it's quite often necessary. 54 | var evensInOrder := seq(5, i requires 0<=i<5 => i*2); 55 | assert evensInOrder[2] == 4; 56 | assert evensInOrder == [/*{*/8,6,4,2,0/*}*/]; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise16.dfy: -------------------------------------------------------------------------------- 1 | //#title IsEven 2 | //#desc Hoare logic 3 | 4 | // So far, we have introduced function and datatype definitions; 5 | // the definition of each is entirely visible to its users. 6 | // We have also discussed lemmas. The body of a lemma is invisible 7 | // to its callers -- but we haven't ever called a lemma! 8 | // Calling lemmas is how we can compose proofs to prove larger concepts. 9 | 10 | ghost predicate IsEven(x:int) 11 | { 12 | x/2*2==x 13 | } 14 | 15 | // A lemma is like a C function; it can return values. Let's return a value 16 | // and then ensure a property of it. 17 | lemma ExplainEvenNumbers(x:int) returns (twocount:int) 18 | // This lemma doesn't work unless we know x is even. 19 | // This requires clause is a fact we get to assume inside the lemma. 20 | requires IsEven(x) 21 | // To export knowledge from a lemma, we declare it in an `ensures` clause. 22 | ensures twocount*2 == x 23 | { 24 | // return twocount by assigning it. 25 | twocount := x / /*{*/3/*}*/; 26 | } 27 | 28 | ghost predicate AlternateEven(x:int) 29 | { 30 | exists twocount :: twocount * 2 == x 31 | } 32 | 33 | // Instead of hiding the thing we prove inside the body as an assert, 34 | // let's export it. 35 | lemma EvenDefinitionsAreEquivalent(x:int) 36 | ensures IsEven(x) == AlternateEven(x) 37 | { 38 | // Wow, that proved without us providing a witness! 39 | } 40 | 41 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise17.dfy: -------------------------------------------------------------------------------- 1 | //#title Fibo 2 | //#desc Recursion challenge. 3 | 4 | ghost function fibo(val:nat) : nat 5 | { 6 | /*{*/ 7 | 0 8 | /*}*/ 9 | } 10 | 11 | lemma Check() 12 | ensures fibo(0) == 0 13 | ensures fibo(20) == 6765 14 | { 15 | } 16 | 17 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise18.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Search 2 | //#desc Method implementation; writing a Hoare spec. 3 | 4 | ghost predicate IsSorted(seqint:seq) { 5 | forall i:nat,j:nat | i= to the needle. 10 | // If the needle is present, this should be the index of the needle. 11 | // If needle is bigger than every element, return the length of the 12 | // sequence: It's not a valid index in the sequence, but it's bigger 13 | // than the indices of all the elements that have smaller values. 14 | 15 | lemma BinarySearch(haystack:seq, needle:int) returns (index:nat) 16 | requires IsSorted(haystack) 17 | /*{*/ 18 | /*}*/ 19 | { 20 | /*{*/ 21 | return 0; // Replace me with an implementation. 22 | /*}*/ 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise19.dfy: -------------------------------------------------------------------------------- 1 | //#title IsSeqSorted 2 | //#desc Build an entire imperative loop method implementation with loop 3 | //#desc invariants. 4 | 5 | predicate IsSorted(intseq:seq) { 6 | forall i:nat,j:nat | i) returns (issorted:bool) 10 | ensures issorted <==> IsSorted(intSeq[..]) 11 | { 12 | /*{*/ 13 | return true; 14 | /*}*/ 15 | } 16 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise20.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Search 2 | //#desc Method implementation; writing a Hoare spec. 3 | 4 | predicate IsSorted(seqint:seq) { 5 | forall i:nat,j:nat | i= to the needle. 10 | // If the needle is present, this should be the index of the needle. 11 | // If needle is bigger than every element, return the length of the 12 | // sequence: It's not a valid index in the sequence, but it's bigger 13 | // than the indices of all the elements that have smaller values. 14 | 15 | method BinarySearch(haystack:seq, needle:int) returns (index:nat) 16 | requires IsSorted(haystack) 17 | /*{*/ 18 | ensures false // real spec should go here 19 | ensures false // real spec should go here 20 | ensures false // real spec should go here 21 | /*}*/ 22 | { 23 | /*{*/ 24 | return 0; // Replace me with an implementation. 25 | /*}*/ 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise21.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Tree Is Sorted 2 | //#desc Prove an implementation meets its spec. 3 | //#desc Practice with proof diagnosis. 4 | 5 | include "UtilitiesLibrary.dfy" 6 | import opened UtilitiesLibrary 7 | 8 | // Define a Binary Tree and write a method to check if it is sorted 9 | 10 | // A binary tree is a tree data structure in which each (internal) node has a value and at 11 | // most two children, which are referred to as the left child and the right child. 12 | 13 | /*{*/ 14 | // you should define your Tree datatype here. 15 | datatype Tree = Tree 16 | /*}*/ 17 | 18 | // This lemma is here to guide you in defining the tree in a way 19 | // that will help with the rest of the exercise. 20 | lemma DatatypeCheck() 21 | { 22 | var emptyTree := Nil; 23 | var littleTree := Node(9, Nil, Nil); 24 | var biggerTree := Node(10, littleTree, littleTree); // Note: not sorted 25 | } 26 | 27 | // You will find the following function method useful. It is meant to express 28 | // the given tree as a sequence. 29 | // 30 | // New syntax: a function method is just like any other function, except it 31 | // can be used in an "imperative" context (i.e., inside a method) 32 | 33 | function method TreeAsSequence(tree:Tree) : seq 34 | { 35 | /*{*/ 36 | [] // Replace me 37 | /*}*/ 38 | } 39 | 40 | // If this predicate is true about sorted sequences, then everything 41 | // in seq1 is <= everything in seq2. 42 | predicate SequencesOrderedAtInterface(seq1:seq, seq2:seq) 43 | { 44 | if |seq1|==0 || |seq2|==0 45 | then true 46 | else Last(seq1) <= seq2[0] 47 | } 48 | 49 | predicate IsSortedTree(tree:Tree) { 50 | /*{*/ 51 | true // Replace me 52 | /*}*/ 53 | } 54 | 55 | // You may find it useful to relate your recursive definition of IsSortedTree to 56 | // a sequential representation of the tree structure 57 | 58 | datatype TreeSortedness = Unsorted | Empty | Bounded(low: int, high: int) 59 | 60 | // Write a recursive implementation that checks if a tree 61 | // is sorted by checking the children, then using TreeAsSequence 62 | // on the children to confirm that both children stay on their 63 | // respective sides of the pivot. 64 | method CheckIfSortedTree(tree:Tree) returns (out: TreeSortedness) 65 | ensures IsSortedTree(tree) <==> !out.Unsorted? 66 | /*{*/ 67 | /*}*/ 68 | { 69 | /*{*/ 70 | return Unsorted; 71 | // Implement this method. Feel free to make this a recursive method. 72 | /*}*/ 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /2022/chapter01-basics/exercises/exercise22.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Tree Search 2 | //#desc Implement search in a binary tree and prove it works. 3 | //#desc Practice with proof diagnosis. 4 | 5 | include "exercise21.dfy" 6 | //#extract exercise21.template solution exercise21.dfy 7 | 8 | // This exercise builds on exercise21 (so make sure you have completed 9 | // that one, too). If in doubt about your solution to exercise21, contact 10 | // an instructor during office hours to make sure you're on the right path. 11 | 12 | predicate SequenceIsSorted(intseq:seq) { 13 | forall i:nat,j:nat | i needle in TreeAsSequence(tree) 25 | { 26 | /*{*/ 27 | /*}*/ 28 | } 29 | -------------------------------------------------------------------------------- /2022/chapter02-specification/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title IsPrimeSpec I 2 | //#desc Basic specification. 3 | // Implement a predicate that tells whether a natural number is prime. 4 | 5 | /*{*/ 6 | /*}*/ 7 | ghost predicate IsPrimeSpec(candidate:nat) 8 | { 9 | /*{*/ 10 | false // Replace me 11 | /*}*/ 12 | } 13 | 14 | // illustrate IsPrimeSpec on a few examples (note that the verifier is able to 15 | // check these only with some help to find divisors for non-prime numbers) 16 | lemma ConstantObligations() 17 | ensures !IsPrimeSpec(0) 18 | ensures !IsPrimeSpec(1) 19 | ensures IsPrimeSpec(2) 20 | ensures IsPrimeSpec(3) 21 | ensures !IsPrimeSpec(4) 22 | ensures !IsPrimeSpec(6) 23 | ensures IsPrimeSpec(7) 24 | ensures !IsPrimeSpec(9) 25 | { 26 | /*{*/ 27 | /*}*/ 28 | } 29 | 30 | lemma CompositeIsntPrime(p: nat) 31 | requires 1 < p 32 | ensures !IsPrimeSpec(p*66) 33 | { 34 | /*{*/ 35 | /*}*/ 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /2022/chapter02-specification/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title IsPrime II 2 | //#desc Working with an implementation proof 3 | 4 | // Let's try "implementing" (with a recursive function) a check for 5 | // primeness. 6 | 7 | // The definition of IsPrime will be included from exercise01.dfy. Make sure 8 | // that definition is correct before you start implementing it. 9 | include "exercise01.dfy" 10 | //#extract exercise01.template solution exercise01.dfy 11 | 12 | // A recursive implementation of IsPrime. The function HasDivisorBelow should 13 | // check if n is divisible by something between 1 and limit (including limit, 14 | // not including 1). 15 | function 16 | HasDivisorBelow(n:nat, limit:nat): bool 17 | requires limit >= 1 18 | { 19 | if limit == 1 then false else 20 | /*{*/ 21 | true // replace this with an appropriate definition 22 | /*}*/ 23 | } 24 | 25 | function 26 | IsPrime(n: nat): bool { 27 | if n <= 1 then false else 28 | !HasDivisorBelow(n, n-1) 29 | } 30 | 31 | // You'll now prove IsPrime(n) == IsPrimeSpec(n). This will require a helper 32 | // lemma to deal with the recursion. 33 | 34 | // An intermediate spec for what HasDivisorBelow returns. The solution is expressed using an 35 | // exists; you may find it more natural to write a forall. 36 | lemma HasDivisorBelow_ok(n: nat, limit: nat) 37 | requires 1 <= limit 38 | /*{*/ 39 | ensures true // replace this with an appropriate postcondition 40 | /*}*/ 41 | { 42 | /*{*/ 43 | /*}*/ 44 | } 45 | 46 | lemma IsPrime_ok(n: nat) 47 | ensures IsPrime(n) == IsPrimeSpec(n) 48 | { 49 | /*{*/ 50 | // This proof should work if your postcondition for HasDivisorBelow_ok is 51 | // correct, but you can change it if needed. 52 | if n <= 2 { 53 | return; 54 | } 55 | HasDivisorBelow_ok(n, n-1); 56 | /*}*/ 57 | } 58 | -------------------------------------------------------------------------------- /2022/chapter02-specification/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary search 2 | //#desc More specification practice 3 | 4 | datatype Option = Some(v: T) | None 5 | 6 | predicate sorted(s: seq) { 7 | forall i, j | 0 <= i < j < |s| :: s[i] < s[j] 8 | } 9 | 10 | function BinarySearch(s: seq, x: int): Option { 11 | /*{*/ 12 | if |s| == 0 then None 13 | else (var mid := |s|/2; 14 | None // replace this with the recursive implementation 15 | ) 16 | /*}*/ 17 | } 18 | 19 | predicate SearchSpec(s: seq, x: int, res: Option) { 20 | res.Some? ==> 21 | && res.v < |s| 22 | && s[res.v] == x 23 | } 24 | 25 | // Here's a specification and proof 26 | lemma BinarySearch_ok(s: seq, x: int) 27 | requires sorted(s) 28 | ensures SearchSpec(s, x, BinarySearch(s, x)) 29 | { 30 | } 31 | 32 | /*{*/ 33 | // We will talk about this specification and proof in class 34 | /*}*/ -------------------------------------------------------------------------------- /2022/chapter02-specification/exercises/exercise03a.dfy: -------------------------------------------------------------------------------- 1 | //#title Merge Sort (a) 2 | //#desc More specification practice. 3 | 4 | // Implement a merge sort that guarantees the result is sorted. 5 | // merge() should merge its two sorted inputs into a sorted output. 6 | // merge_sort picks a pivot, recursively merge_sort()s the subsequences, 7 | // and then uses merge() to put them back together. We've provided 8 | // signatures for merge and merge_sort to get you started. 9 | 10 | predicate IsSorted(seqint:seq) 11 | { 12 | forall idx :: 0 <= idx < |seqint|-1 ==> seqint[idx] <= seqint[idx+1] 13 | } 14 | 15 | /*{*//*}*/ 16 | method merge_sort(input:seq) returns (output:seq) 17 | /*{*/ 18 | ensures true // Replace me 19 | /*}*/ 20 | { 21 | /*{*/ 22 | // Supply the body. 23 | /*}*/ 24 | } 25 | 26 | method merge(seqa:seq, seqb:seq) returns (output:seq) 27 | requires IsSorted(seqa) 28 | requires IsSorted(seqb) 29 | /*{*/ 30 | ensures true // Replace me 31 | /*}*/ 32 | { 33 | /*{*/ 34 | // Supply the body. 35 | /*}*/ 36 | } 37 | 38 | -------------------------------------------------------------------------------- /2022/chapter02-specification/exercises/exercise03b.dfy: -------------------------------------------------------------------------------- 1 | //#title Merge Sort (b) 2 | //#desc More specification practice. 3 | 4 | // Implement a merge sort that guarantees the result is sorted. 5 | // merge() should merge its two sorted inputs into a sorted output. 6 | // merge_sort picks a pivot, recursively merge_sort()s the subsequences, 7 | // and then uses merge() to put them back together. We've provided 8 | // signatures for merge and merge_sort to get you started. 9 | 10 | predicate IsSorted(seqint:seq) 11 | { 12 | forall idx :: 0 <= idx < |seqint|-1 ==> seqint[idx] <= seqint[idx+1] 13 | } 14 | 15 | /*{*//*}*/ 16 | method merge_sort(input:seq) returns (output:seq) 17 | /*{*/ 18 | ensures true // Replace me 19 | /*}*/ 20 | { 21 | /*{*/ 22 | // Supply the body. 23 | /*}*/ 24 | } 25 | 26 | method merge(seqa:seq, seqb:seq) returns (output:seq) 27 | requires IsSorted(seqa) 28 | requires IsSorted(seqb) 29 | /*{*/ 30 | ensures true // Replace me 31 | /*}*/ 32 | { 33 | /*{*/ 34 | // Supply the body. 35 | /*}*/ 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /2022/chapter03-state-machines/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Coke Machine 2 | //#desc The first state machine specification exercise: fill in actions. 3 | 4 | // You are asked to define the state machine for a coke vending machine. 5 | // The machine starts empty and has a maximum capacity of 7 cokes. 6 | // The machine should support the following actions: 7 | // Purchase: dispense one coke from the machine 8 | // Restock: add a number of cokes to the machine 9 | 10 | datatype Constants = Constants(capacity:int) 11 | datatype Variables = Variables(numCokes:int) 12 | 13 | ghost predicate Init(c:Constants, v:Variables) { 14 | /*{*/ 15 | true // Replace me 16 | /*}*/ 17 | } 18 | 19 | ghost predicate Purchase(c:Constants, v:Variables, v':Variables) { 20 | /*{*/ 21 | true // Replace me 22 | /*}*/ 23 | } 24 | 25 | ghost predicate Restock(c:Constants, v:Variables, v':Variables, numRestock:int) 26 | { 27 | /*{*/ 28 | true // Replace me 29 | /*}*/ 30 | } 31 | 32 | // Jay-Normal-Form: pack all the nondeterminism into a single object 33 | datatype Step = 34 | | PurchaseStep 35 | | RestockStep(num: int) 36 | 37 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 38 | match step 39 | case PurchaseStep => Purchase(c, v, v') 40 | case RestockStep(num) => Restock(c, v, v', num) 41 | } 42 | 43 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 44 | exists step :: NextStep(c, v, v', step) 45 | } 46 | 47 | //========================== 48 | // Everything below this line is not part of the specification. It allows 49 | // you to use the verifier to confirm that your state machine has a number 50 | // of desirable properties. 51 | 52 | ghost predicate Inv(c:Constants, v:Variables) { 53 | 0 <= v.numCokes <= c.capacity 54 | } 55 | 56 | lemma SafetyProof() 57 | ensures forall c, v | Init(c, v) :: Inv(c, v) 58 | ensures forall c, v, v' | Inv(c, v) && Next(c, v, v') :: Inv(c, v') 59 | { 60 | forall c, v, v' | Inv(c, v) && Next(c, v, v') 61 | ensures Inv(c, v') 62 | { 63 | if(Purchase(c, v, v')) { 64 | assert Inv(c, v'); 65 | } else { 66 | var num :| Restock(c, v, v', num); 67 | assert Inv(c, v'); 68 | } 69 | } 70 | } 71 | 72 | lemma NonTrivialPurchase() 73 | ensures exists c, v, v' :: Inv(c, v) && Next(c, v, v') && v'.numCokes + 1 == v.numCokes 74 | { 75 | var c := Constants(7); 76 | var v := Variables(1); 77 | var v' := Variables(0); 78 | assert NextStep(c, v, v', PurchaseStep); 79 | assert Inv(c, v) && Next(c, v, v') && v'.numCokes + 1 == v.numCokes; 80 | } 81 | 82 | lemma NonTrivialRestock() 83 | ensures exists c, v, v' :: Inv(c, v) && Next(c, v, v') && v.numCokes < v'.numCokes 84 | { 85 | var c := Constants(7); 86 | var v := Variables(4); 87 | var v' := Variables(7); 88 | assert NextStep(c, v, v', RestockStep(3)); 89 | assert Inv(c, v) && Next(c, v, v') && v.numCokes < v'.numCokes; 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /2022/chapter03-state-machines/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Dining Philosophers 2 | //#desc A more challenging state machine: define the state datatype. 3 | 4 | // Define the state machine for the Dining Philosophers. 5 | // There are N philosophers sitting around a round table. 6 | // Between every pair of philosophers lies a chopstick. 7 | // Every philosopher has three possible actions: 8 | // * Acquire the chopstick to their left. 9 | // * Acquire the chopstick to their right. 10 | // * Release both chopsticks (in a single step). 11 | // 12 | // (Nota bene: The dining philosophers problem is used to illustrate deadlocks 13 | // and deadlock-freedom. We're not doing any of that here, just using the 14 | // example to teach you to set up a state machine model.) 15 | 16 | datatype Constants = Constants(tableSize:nat) 17 | { 18 | // An initial predicate to define well-formed constants. 19 | ghost predicate WellFormed() { 20 | && 0 < tableSize 21 | } 22 | } 23 | 24 | 25 | /*{*/ 26 | /*}*/ 27 | // Define all the relevant state in this datatype. 28 | /*{*/ 29 | datatype Variables = Variables() 30 | { 31 | ghost predicate WellFormed(c: Constants) { 32 | && c.WellFormed() 33 | } 34 | } 35 | /*}*/ 36 | 37 | ghost predicate Init(c:Constants, v:Variables) { 38 | /*{*/ 39 | true // Replace me 40 | /*}*/ 41 | } 42 | 43 | /*{*/ 44 | /*}*/ 45 | 46 | // Philosopher with index philosopherIndex acquires left chopstick 47 | ghost predicate AcquireLeft(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 48 | /*{*/ 49 | true // Replace me 50 | /*}*/ 51 | } 52 | 53 | // Philosopher with index philosopherIndex acquires right chopstick 54 | ghost predicate AcquireRight(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 55 | /*{*/ 56 | true // Replace me 57 | /*}*/ 58 | } 59 | 60 | // Philosopher with index philosopherIndex releases both chopsticks 61 | ghost predicate ReleaseBoth(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 62 | /*{*/ 63 | true // Replace me 64 | /*}*/ 65 | } 66 | 67 | datatype Step = 68 | /*{*/ 69 | Step() // Replace me 70 | /*}*/ 71 | 72 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 73 | match step 74 | /*{*/ 75 | case Step => false // Replace me 76 | /*}*/ 77 | } 78 | 79 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 80 | exists step :: NextStep(c, v, v', step) 81 | } 82 | 83 | // This predicate should be true if and only if no philosopher holds a 84 | // chopstick. 85 | // Since you defined the Variables state, you must define this predicate in 86 | // those terms. 87 | ghost predicate NoSticksAcquired(c:Constants, v: Variables) 88 | requires v.WellFormed(c) 89 | { 90 | /*{*/ 91 | true 92 | /*}*/ 93 | } 94 | 95 | // Change this predicate to be true if and only if philosopher 96 | // `philosopherIndex` holds both of their chopsticks. 97 | // Since you defined the Variables state, you must define this predicate in 98 | // those terms. 99 | ghost predicate BothSticksAcquired(c:Constants, v: Variables, philosopherIndex: nat) 100 | requires philosopherIndex < c.tableSize 101 | requires v.WellFormed(c) 102 | { 103 | /*{*/ 104 | true 105 | /*}*/ 106 | } 107 | 108 | // Show that, in the Init state, no philosopher has chopsticks. 109 | lemma InitProperty(c:Constants, v: Variables, philosopherIndex:nat) 110 | requires Init(c, v) 111 | ensures NoSticksAcquired(c, v) 112 | { 113 | /*{*/ 114 | /*}*/ 115 | } 116 | 117 | 118 | // Show a behavior that evolves from the init state to one where a philosopher 119 | // has completed acquiring both chopsticks. 120 | lemma PseudoLiveness(c:Constants, philosopherIndex:nat) returns (behavior:seq) 121 | requires c.tableSize == 3 122 | requires philosopherIndex == 1 123 | ensures 0 < |behavior| // precondition for index operators below 124 | ensures forall i | 0 <= i < |behavior|-1 :: Next(c, behavior[i], behavior[i+1]) // Behavior satisfies your state machine 125 | ensures behavior[0].WellFormed(c) // precondition for calling NoSticksAcquired 126 | ensures Init(c, behavior[0]) 127 | ensures behavior[|behavior|-1].WellFormed(c) // precondition for calling BothSticksAcquired 128 | ensures BothSticksAcquired(c, behavior[|behavior|-1], philosopherIndex) // Behavior ultimately achieves acquisition for philosopherIndex 129 | { 130 | /*{*/ 131 | /*}*/ 132 | } 133 | -------------------------------------------------------------------------------- /2022/chapter03-state-machines/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Single-Server Lock Service Model 2 | //#desc A complex state machine 3 | //#desc including a Safety predicate on the state type. 4 | 5 | // Model a lock service that consists of a single server and an 6 | // arbitrary number of clients. 7 | // 8 | // The state of the system includes the server's state (whether the server 9 | // knows that some client holds the lock, and if so which one) 10 | // and the clients' states (for each client, whether that client knows 11 | // it holds the lock). 12 | // 13 | // The system should begin with the server holding the lock. 14 | // An acquire step atomically transfers the lock from the server to some client. 15 | // (Note that we're not modeling the network yet -- the lock disappears from 16 | // the server and appears at a client in a single atomic transition.) 17 | // A release step atomically transfers the lock from the client back to the server. 18 | // 19 | // The safety property is that no two clients ever hold the lock 20 | // simultaneously. 21 | 22 | datatype Constants = Constants( 23 | /*{*/ // You define this ... 24 | /*}*/ 25 | ) { 26 | ghost predicate WellFormed() { true } 27 | /*{*/ 28 | /*}*/ 29 | } 30 | 31 | /*{*/ 32 | /*}*/ 33 | 34 | datatype Variables = Variables( 35 | /*{*/ // You define this ... 36 | /*}*/ 37 | ) { 38 | ghost predicate WellFormed(c: Constants) { 39 | /*{*/ 40 | true 41 | /*}*/ 42 | } 43 | } 44 | 45 | ghost predicate Init(c:Constants, v:Variables) { 46 | && v.WellFormed(c) 47 | /*{*/ 48 | && true // Replace me 49 | /*}*/ 50 | } 51 | 52 | /*{*/ 53 | /*}*/ 54 | // Jay-Normal-Form: pack all the nondeterminism into a single object 55 | // that gets there-exist-ed once. 56 | datatype Step = 57 | /*{*/ 58 | | SomeStep(somearg: int) // Replace me 59 | /*}*/ 60 | 61 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 62 | match step 63 | /*{*/ 64 | case SomeStep(somearg) => false // Replace me 65 | /*}*/ 66 | } 67 | 68 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 69 | exists step :: NextStep(c, v, v', step) 70 | } 71 | 72 | // A good definition of safety for the lock server is that no two clients 73 | // may hold the lock simultaneously. This predicate should capture that 74 | // idea in terms of the Variables you have defined. 75 | ghost predicate Safety(c:Constants, v:Variables) { 76 | /*{*/ 77 | false // Replace me 78 | /*}*/ 79 | } 80 | 81 | 82 | // This predicate should be true if and only if the client with index `clientIndex` 83 | // has the lock acquired. 84 | // Since you defined the Variables state, you must define this predicate in 85 | // those terms. 86 | ghost predicate ClientHoldsLock(c: Constants, v: Variables, clientIndex: nat) 87 | requires v.WellFormed(c) 88 | { 89 | /*{*/ 90 | false // Replace me 91 | /*}*/ 92 | } 93 | 94 | // Show a behavior that the system can release a lock from clientA and deliver 95 | // it to clientB. 96 | lemma PseudoLiveness(clientA:nat, clientB:nat) returns (c: Constants, behavior:seq) 97 | requires clientA == 2 98 | requires clientB == 0 99 | ensures 0 < |behavior| // precondition for index operators below 100 | ensures forall i | 0 <= i < |behavior|-1 :: Next(c, behavior[i], behavior[i+1]) // Behavior satisfies your state machine 101 | ensures forall i | 0 <= i < |behavior| :: Safety(c, behavior[i]) // Behavior always satisfies the Safety predicate 102 | ensures behavior[0].WellFormed(c) // precondition for calling ClientHoldsLock 103 | ensures ClientHoldsLock(c, behavior[0], clientA) 104 | ensures behavior[|behavior|-1].WellFormed(c) // precondition for calling ClientHoldsLock 105 | ensures ClientHoldsLock(c, behavior[|behavior|-1], clientB) 106 | { 107 | /*{*/ 108 | /*}*/ 109 | } 110 | 111 | -------------------------------------------------------------------------------- /2022/chapter04-invariants/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Crawler 2 | //#desc Introduction to inductive invariants 3 | //#desc -- implement the visualization from the lecture. 4 | 5 | module Crawler { 6 | //datatype Constants = Constants() 7 | datatype Variables = Variables(x:int, y:int) 8 | 9 | ghost predicate Init(v:Variables) { 10 | && v.x == 0 11 | && v.y == 5 12 | } 13 | 14 | ghost predicate MoveNorth(v:Variables, v':Variables) { 15 | && v'.x == v.x 16 | && v'.y == v.y + 1 17 | } 18 | 19 | ghost predicate MoveSouthEast(v:Variables, v':Variables) { 20 | && v'.x == v.x + 1 21 | && v'.y == v.y - 1 22 | } 23 | 24 | ghost predicate Next(v:Variables, v':Variables) { 25 | || MoveNorth(v, v') 26 | || MoveSouthEast(v, v') 27 | } 28 | 29 | ghost predicate InManhole(v:Variables) { 30 | v.x*v.x + v.y*v.y <= 3*3 31 | } 32 | 33 | ghost predicate Safety(v:Variables) { 34 | !InManhole(v) 35 | } 36 | 37 | ghost predicate Inv(v:Variables) { 38 | /*{*/ 39 | true // probably not strong enough. :v) 40 | /*}*/ 41 | } 42 | 43 | // Here's your proof obligation that Safety predicate holds in every behavior 44 | // allowed by the state machine. 45 | // With the correct invariant, this proof goes through without a body. 46 | lemma SafetyTheorem(v:Variables, v':Variables) 47 | ensures Init(v) ==> Inv(v) 48 | ensures Inv(v) && Next(v, v') ==> Inv(v') 49 | ensures Inv(v) ==> Safety(v) 50 | { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /2022/chapter04-invariants/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Single-Server Lock Service Proof 2 | //#desc A more realistic invariant proof of the previous chapter's lock 3 | //#desc service. 4 | 5 | // We provide a correct spec for the lock server here, but leave you 6 | // to define the Safety property to be proven. 7 | // You are welcome to prove correct your own model from chapter03, 8 | // but note that may be too hard or too easy if your spec is broken. 9 | 10 | // Copy your solution for chapter03/exercise03 into the current directory with 11 | // this name: 12 | include "chapter03-exercise03.dfy" 13 | //#extract ../../chapter03-state-machines/exercises/exercise03.template solution chapter03-exercise03.dfy 14 | 15 | 16 | /*{*/ 17 | /*}*/ 18 | ghost predicate Inv(c:Constants, v:Variables) { 19 | /*{*/ 20 | true // Replace me: probably not strong enough. :v) 21 | /*}*/ 22 | } 23 | 24 | // Here's your obligation. Probably easiest to break this up into three 25 | // lemmas, each P==>Q becomes requires P ensures Q. 26 | lemma SafetyTheorem(c:Constants, v:Variables, v':Variables) 27 | ensures Init(c, v) ==> Inv(c, v) 28 | ensures Inv(c, v) && Next(c, v, v') ==> Inv(c, v') 29 | ensures Inv(c, v) ==> Safety(c, v) 30 | { 31 | /*{*/ 32 | /*}*/ 33 | } 34 | -------------------------------------------------------------------------------- /2022/chapter05-distributed-state-machines/exercises/CommitTypes.dfy: -------------------------------------------------------------------------------- 1 | 2 | module CommitTypes { 3 | // How a particular participant feels. 4 | datatype Vote = Yes | No 5 | // What decision has been reached by the protocol. 6 | datatype Decision = Commit | Abort 7 | } 8 | 9 | -------------------------------------------------------------------------------- /2022/chapter05-distributed-state-machines/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Two Phase Commit Safety Specification Predicate 2 | //#desc Express the English Atomic Commit safety properties as predicates 3 | //#desc over the compound state machine model from exercise01. 4 | 5 | // 2PC should satisfy the Atomic Commit specification. English design doc: 6 | // 7 | // AC-1: All processes that reach a decision reach the same one. 8 | // AC-3: The Commit decision can only be reached if all processes prefer Yes. 9 | // AC-4: If all processes prefer Yes, then the decision must be Commit. 10 | // 11 | // Note that the full Atomic Commit spec includes these additional properties, 12 | // but you should ignore them for this exercise: 13 | // AC-2: (stability) A process cannot reverse its decision after it has reached one. 14 | // (best modeled with refinement) 15 | // AC-5: (liveness) All processes eventually decide. 16 | 17 | // Note that we include the model of exercise01, so you should write your 18 | // spec accordingly. Of course, that also means double-checking that your 19 | // model performs all actions as described. 20 | include "exercise01.dfy" 21 | //#extract exercise01.template solution exercise01.dfy 22 | 23 | module Obligations { 24 | import opened CommitTypes 25 | import opened Types 26 | import opened UtilitiesLibrary 27 | import opened DistributedSystem 28 | 29 | /*{*/ 30 | /*}*/ 31 | 32 | // AC-1: All processes that reach a decision reach the same one. 33 | ghost predicate SafetyAC1(c: Constants, v: Variables) 34 | requires v.WF(c) 35 | { 36 | // All hosts that reach a decision reach the same one 37 | /*{*/ 38 | true // Replace me 39 | /*}*/ 40 | } 41 | 42 | // AC2 is sort of a history predicate; we're going to ignore it. 43 | 44 | // AC-3: The Commit decision can only be reached if all processes prefer Yes. 45 | ghost predicate SafetyAC3(c: Constants, v: Variables) 46 | requires v.WF(c) 47 | { 48 | /*{*/ 49 | true // Replace me 50 | /*}*/ 51 | } 52 | 53 | // AC-4: If all processes prefer Yes, then the decision must be Commit. 54 | ghost predicate SafetyAC4(c: Constants, v: Variables) 55 | requires v.WF(c) 56 | { 57 | /*{*/ 58 | true // Replace me 59 | /*}*/ 60 | } 61 | 62 | // AC5 is a liveness proprety, we're definitely going to ignore it. 63 | 64 | ghost predicate Safety(c: Constants, v: Variables) 65 | requires v.WF(c) 66 | { 67 | && SafetyAC1(c, v) 68 | && SafetyAC3(c, v) 69 | && SafetyAC4(c, v) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /2022/chapter05-distributed-state-machines/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Two Phase Commit Safety Proof 2 | //#desc Prove that the 2PC distributed system (from exercise01) accomplishes the Safety spec (from exercise02) 3 | 4 | include "exercise02.dfy" 5 | //#extract exercise02.template solution exercise02.dfy 6 | 7 | module TwoPCInvariantProof { 8 | import opened CommitTypes 9 | import opened Types 10 | import opened UtilitiesLibrary 11 | import opened DistributedSystem 12 | import opened Obligations 13 | 14 | /*{*/ 15 | /*}*/ 16 | // This is a conjunct of the inductive invariant, indicating that the messages carrying 17 | // decisions should reflect the votes of the participants as relayed to the coordinator 18 | ghost predicate DecisionMsgsAgreeWithDecision(c: Constants, v: Variables) 19 | requires v.WF(c) 20 | { 21 | /*{*/ 22 | true // Replace me 23 | /*}*/ 24 | } 25 | 26 | ghost predicate Inv(c: Constants, v: Variables) 27 | { 28 | && v.WF(c) 29 | /*{*/ 30 | /*}*/ 31 | // We give you the blueprint for one invariant to get you started... 32 | && DecisionMsgsAgreeWithDecision(c, v) 33 | // ...but you'll need more. 34 | && Safety(c, v) 35 | } 36 | 37 | lemma InitImpliesInv(c: Constants, v: Variables) 38 | requires Init(c, v) 39 | ensures Inv(c, v) 40 | { 41 | /*{*/ 42 | /*}*/ 43 | } 44 | 45 | lemma InvInductive(c: Constants, v: Variables, v': Variables) 46 | requires Inv(c, v) 47 | requires Next(c, v, v') 48 | ensures Inv(c, v') 49 | { 50 | /*{*/ 51 | /*}*/ 52 | } 53 | 54 | lemma InvImpliesSafety(c: Constants, v: Variables) 55 | requires Inv(c, v) 56 | ensures Safety(c, v) 57 | { // Trivial, as usual, since safety is a conjunct in Inv. 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /2022/chapter06-refinement/exercises/CommitTypes.dfy: -------------------------------------------------------------------------------- 1 | 2 | module CommitTypes { 3 | // How a particular participant feels. 4 | datatype Vote = Yes | No 5 | 6 | // What decision has been reached by the protocol. 7 | datatype Decision = Commit | Abort 8 | 9 | // Define events for this state machine (and the ch6 spec state machine it 10 | // refines). 11 | datatype Event = ParticipantLearnsEvent(idx: nat) | CoordinatorLearnsEvent() | NoOpEvent() 12 | } 13 | -------------------------------------------------------------------------------- /2022/chapter06-refinement/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /2022/chapter06-refinement/exercises/ch06exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Property Lemmas for Atomic Commit 2 | //#desc The state machine model captures AC2 nicely, 3 | //#desc but let's make it very clear that the model also obeys 4 | //#desc AC1, AC3 and AC4. 5 | 6 | // To increase our confidence that our state machine spec from 7 | // exercise02 accurately defines our goal, 8 | // we can state and prove some properties about it. 9 | // 10 | // AC1: All processes that reach a decision reach the same one. 11 | // AC3: The Commit decision can only be reached if all processes prefer Yes. 12 | // AC4: If all processes prefer Yes, then the decision must be Commit. 13 | // 14 | // We'll not bother with AC2 because it can't be stated as a safety 15 | // property, however it should be abundantly clear from the Next 16 | // action of the state machine model. 17 | // AC2: (stability) A process cannot reverse its decision after it has reached one. 18 | // 19 | // We'll not bother with AC5 because it's a liveness property, which 20 | // is outside the scope of this course. 21 | // AC5: (liveness) All processes eventually decide. 22 | // 23 | // If you wrote a broken spec, it will be difficult to prove these properties 24 | // on it. 25 | 26 | include "ch06exercise01.dfy" 27 | //#extract ch06exercise01.template solution ch06exercise01.dfy 28 | 29 | module AtomicCommitProperties { 30 | import opened CommitTypes 31 | import opened AtomicCommit 32 | 33 | // Make this predicate true if every host (coordinator or one of the participants) that 34 | // has learned a decision has recorded `decision`. (Hosts that haven't yet learned a 35 | // decision shouldn't affect the value of this predicate.) 36 | // 37 | // Defining this predicate makes the definitions of the AC properties 38 | // much easier to read (and in fact easier for Dafny to automate). 39 | ghost predicate AllWithDecisionAgreeWithThisOne(c: Constants, v: Variables, decision: Decision) 40 | requires c.WF() 41 | requires v.WF(c) 42 | { 43 | /*{*/ 44 | true // Replace me 45 | /*}*/ 46 | } 47 | 48 | ghost predicate SafetyAC1(c: Constants, v: Variables) 49 | requires c.WF() 50 | requires v.WF(c) 51 | { 52 | /*{*/ 53 | false // Replace me 54 | /*}*/ 55 | } 56 | 57 | // AC2 can't be stated about a single state; the "code reviewer" 58 | // should be able to confirm it by reading the state machine spec 59 | // from exercise02. 60 | 61 | ghost predicate SafetyAC3(c: Constants, v: Variables) 62 | requires c.WF() 63 | requires v.WF(c) 64 | { 65 | /*{*/ 66 | false // Replace me 67 | /*}*/ 68 | } 69 | 70 | ghost predicate SafetyAC4(c: Constants, v: Variables) 71 | requires c.WF() 72 | requires v.WF(c) 73 | { 74 | /*{*/ 75 | false // Replace me 76 | /*}*/ 77 | } 78 | 79 | // AC5 is a liveness proprety, we're definitely going to ignore it. 80 | 81 | //#instructor Player 1 82 | ghost predicate Safety(c: Constants, v: Variables) 83 | { 84 | && c.WF() 85 | && v.WF(c) 86 | && SafetyAC1(c, v) 87 | && SafetyAC3(c, v) 88 | && SafetyAC4(c, v) 89 | } 90 | 91 | lemma SafetyInit(c: Constants, v: Variables) 92 | requires Init(c, v) 93 | ensures Safety(c, v) 94 | { 95 | } 96 | 97 | lemma SafetyNext(c: Constants, v: Variables, v': Variables, event: Event) 98 | requires Safety(c, v) 99 | requires Next(c, v, v', event) 100 | ensures Safety(c, v') 101 | { 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /2022/chapter07-async-clients/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /2022/lectures/lecture1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture1-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture1.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture1.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture1.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture10-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture10-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture10.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture10.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture10.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture11-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture11-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture11.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture11.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture11.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture12-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture12-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture12.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture12.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture12.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture13-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture13-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture13.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture13.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture13.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture13.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture14-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture14-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture14.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture14.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture14.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture14.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture15-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture15-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture15.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture15.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture15.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture15.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture16-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture16-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture16.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture16.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture16.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture16.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture2-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture2.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture2.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture3-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture3.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture3.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture3.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture4-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture4-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture4.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture4.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture4.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture5-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture5-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture5.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture5.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture5.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture6-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture6-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture6.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture6.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture6.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture7-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture7-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture7.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture7.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture7.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture8-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture8-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture8.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture8.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture8.pptx -------------------------------------------------------------------------------- /2022/lectures/lecture9-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture9-2.png -------------------------------------------------------------------------------- /2022/lectures/lecture9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture9.pdf -------------------------------------------------------------------------------- /2022/lectures/lecture9.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/2022/lectures/lecture9.pptx -------------------------------------------------------------------------------- /2022/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Open Sans, Arial; 3 | color: #454545; 4 | font-size: 16px; 5 | margin: 2em auto; 6 | max-width: 800px; 7 | padding: 1em; 8 | line-height: 1.4; 9 | text-align: justify; 10 | } 11 | 12 | h1, 13 | h2, 14 | h3 { 15 | text-align: left; 16 | } 17 | 18 | .lec-preview { 19 | display: inline-block; 20 | border: 2px solid black; 21 | width: 300px; 22 | height: 180px; 23 | margin: auto; 24 | } 25 | 26 | .li-none { 27 | list-style-type: none; 28 | } 29 | -------------------------------------------------------------------------------- /2022/project01-distributed-lock-server/exercises/distributed_system.t.dfy: -------------------------------------------------------------------------------- 1 | //#title DistributedSystem 2 | //#desc This file isn't editable because it's a trusted file that specifies how 3 | //#desc hosts interact with one another over the network. 4 | 5 | include "host.v.dfy" 6 | //#extract host.v.template solution host.v.dfy 7 | 8 | // Before we get here, caller must define a type Message that we'll 9 | // use to instantiate network.s.dfy. 10 | 11 | module DistributedSystem { 12 | import opened HostIdentifiers 13 | import Host 14 | import Network 15 | 16 | datatype Constants = Constants( 17 | hosts:seq, 18 | network:Network.Constants) { 19 | ghost predicate WF() { 20 | // Network numHosts and each host's numHosts agree with the size of our 21 | // own host list 22 | && network.Configure(|hosts|) 23 | && (forall id | ValidHostId(id) :: hosts[id].Configure(|hosts|, id)) // every host knows its id (and ids are unique) 24 | } 25 | 26 | ghost predicate ValidHostId(hostid: HostId) { 27 | HostIdentifiers.ValidHostId(|hosts|, hostid) 28 | } 29 | } 30 | 31 | datatype Variables = Variables( 32 | hosts:seq, 33 | network:Network.Variables) { 34 | ghost predicate WF(c: Constants) { 35 | && c.WF() 36 | && |hosts| == |c.hosts| 37 | } 38 | } 39 | 40 | ghost predicate Init(c:Constants, v:Variables) { 41 | && v.WF(c) 42 | && (forall id | c.ValidHostId(id) :: Host.Init(c.hosts[id], v.hosts[id])) 43 | && Network.Init(c.network, v.network) 44 | } 45 | 46 | // JayNF 47 | datatype Step = Step(id:HostId, msgOps: Network.MessageOps) 48 | 49 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 50 | && v.WF(c) 51 | && v'.WF(c) 52 | && c.ValidHostId(step.id) 53 | && Host.Next(c.hosts[step.id], v.hosts[step.id], v'.hosts[step.id], step.msgOps) 54 | && (forall other | c.ValidHostId(other) && other != step.id :: v'.hosts[other] == v.hosts[other]) 55 | && Network.Next(c.network, v.network, v'.network, step.msgOps) 56 | } 57 | 58 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 59 | exists step :: NextStep(c, v, v', step) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /2022/project01-distributed-lock-server/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Midterm Project 2 | //#desc Build a distributed lock server. Define how a host implements your 3 | //#desc protocol in host.v.dfy; write your safety spec and proof here. 4 | 5 | // This challenge differs from LockServer (from chapters 03 and 04) in two 6 | // ways. First, there is no central server that coordinates the activity. 7 | // Second, the hosts can communicate only via asynchronous messages; a single 8 | // state machine transition cannot simultaneously read or update the state of 9 | // two hosts. 10 | // 11 | // To guard against duplicate messages, the nodes associate a monotonically 12 | // increasing epoch number with the lock. Initially, node 0 holds the lock and 13 | // its epoch number is 1, while all other nodes with an epoch of 0 (and not 14 | // holding the lock). A node that holds the lock can “grant” it to another 15 | // node by sending them a “Grant” message which has an epoch number that is 16 | // greater than the node's epoch number. A node that receives such a message 17 | // will become the new holder and will set its epoch number to the message’s 18 | // epoch number. 19 | 20 | // You'll first need to modify 'host.v.dfy' to define the protocol message 21 | // format and the host behavior. 22 | // Then come back here to define the safety condition and prove that the 23 | // distributed system made from that protocol maintains it. 24 | 25 | include "distributed_system.t.dfy" 26 | //#extract distributed_system.t.template solution distributed_system.t.dfy 27 | 28 | module SafetySpec { 29 | import opened HostIdentifiers 30 | import DistributedSystem 31 | 32 | // Define this predicate to be true if idx is a valid host ID and that host's 33 | // Variables indicates that it holds the lock. 34 | ghost predicate HostHoldsLock(c:DistributedSystem.Constants, v:DistributedSystem.Variables, idx: int) { 35 | && v.WF(c) 36 | /*{*/ 37 | && false 38 | /*}*/ 39 | } 40 | 41 | // No two hosts think they hold the lock simultaneously. 42 | ghost predicate Safety(c:DistributedSystem.Constants, v:DistributedSystem.Variables) { 43 | /*{*/ 44 | true // Replace this placeholder with an appropriate safety condition 45 | /*}*/ 46 | } 47 | } 48 | 49 | module Proof { 50 | import opened HostIdentifiers 51 | import Host 52 | import opened DistributedSystem 53 | import opened SafetySpec 54 | 55 | // Here's a predicate that will be very useful in constructing inviariant conjuncts. 56 | ghost predicate InFlight(c:Constants, v:Variables, message:Host.Message) { 57 | && v.WF(c) 58 | && message in v.network.sentMsgs 59 | /*{*/ 60 | && false // ...and then add a check that the message's epoch is still valid. 61 | /*}*/ 62 | } 63 | 64 | /*{*/ 65 | /*}*/ 66 | 67 | ghost predicate Inv(c: Constants, v:Variables) { 68 | /*{*/ 69 | false // Replace this placeholder with an invariant that's inductive and supports Safety. 70 | /*}*/ 71 | } 72 | 73 | lemma SafetyProof(c: Constants, v:Variables, v':Variables) 74 | ensures Init(c, v) ==> Inv(c, v) 75 | ensures Inv(c, v) && Next(c, v, v') ==> Inv(c, v') 76 | ensures Inv(c, v) ==> Safety(c, v) 77 | { 78 | // Develop any necessary proof here. 79 | /*{*/ 80 | /*}*/ 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /2022/project01-distributed-lock-server/exercises/host.v.dfy: -------------------------------------------------------------------------------- 1 | //#title Host protocol 2 | //#desc Define the host state machine here: message type, state machine for executing one 3 | //#desc host's part of the protocol. 4 | 5 | // See exercise01.dfy for an English design of the protocol. 6 | 7 | include "network.t.dfy" 8 | //#extract network.t.template solution network.t.dfy 9 | 10 | module Host { 11 | import opened UtilitiesLibrary 12 | import opened HostIdentifiers 13 | import Network 14 | 15 | // Define your Message datatype here. 16 | datatype Message = 17 | /*{*/ 18 | Message() // Populate this datatype. 19 | /*}*/ 20 | 21 | // Define your Host protocol state machine here. 22 | datatype Constants = Constants(numHosts: nat, myId:HostId) { 23 | // host constants coupled to DistributedSystem Constants: 24 | // DistributedSystem tells us our id so we can recognize inbound messages. 25 | ghost predicate Configure(numHosts: nat, id:HostId) { 26 | && this.numHosts == numHosts 27 | && this.myId == id 28 | } 29 | } 30 | 31 | datatype Variables = Variables( 32 | /*{*/ 33 | // Fill me in. 34 | /*}*/ 35 | ) 36 | 37 | ghost predicate Init(c:Constants, v:Variables) { 38 | /*{*/ 39 | true // Replace me 40 | /*}*/ 41 | } 42 | 43 | /*{*/ 44 | /*}*/ 45 | // JayNF 46 | datatype Step = 47 | /*{*/ 48 | | SomeStep // Replace me 49 | /*}*/ 50 | 51 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, msgOps:Network.MessageOps, step: Step) { 52 | match step 53 | /*{*/ 54 | case SomeStep => true 55 | /*}*/ 56 | } 57 | 58 | ghost predicate Next(c:Constants, v:Variables, v':Variables, msgOps:Network.MessageOps) { 59 | exists step :: NextStep(c, v, v', msgOps, step) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /2022/project01-distributed-lock-server/exercises/network.t.dfy: -------------------------------------------------------------------------------- 1 | //#title Network 2 | //#desc This file isn't editable because it's a trusted file that specifies how 3 | //#desc the network delivers packets, allowing reorder and duplicate delivery. 4 | 5 | include "UtilitiesLibrary.dfy" 6 | 7 | module HostIdentifiers { 8 | type HostId = int // Pretty type synonym (a la C typedef) 9 | 10 | ghost predicate ValidHostId(numHosts: nat, hostid: HostId) { 11 | 0 <= hostid < numHosts 12 | } 13 | 14 | // The set of all host identities. 15 | ghost function AllHosts(numHosts: nat) : set { 16 | set hostid:HostId | 17 | && 0 <= hostid < numHosts // This line is entirely redundant, but it satisfies Dafny's finite-set heuristic; see chapter01 exercise15 18 | && ValidHostId(numHosts, hostid) 19 | } 20 | } 21 | 22 | // This version of Network uses a template parameter to avoid having to declare 23 | // the Message type before the Network module. (Contrast with ch05/ex02.) 24 | module Network { 25 | import opened UtilitiesLibrary 26 | 27 | // A MessageOps is a "binding variable" used to connect a Host's Next step 28 | // (what message got received, what got sent?) with the Network (only allow 29 | // receipt of messages sent prior; record newly-sent messages). 30 | // Note that both fields are Option. A step predicate can say recv.None? 31 | // to indicate that it doesn't need to receive a message to occur. 32 | // It can say send.None? to indicate that it doesn't want to transmit a message. 33 | datatype MessageOps = MessageOps(recv:Option, send:Option) 34 | 35 | datatype Constants = Constants(numHosts: nat) 36 | { 37 | ghost predicate Configure(numHosts: nat) { 38 | this.numHosts == numHosts 39 | } 40 | } 41 | 42 | // Network state is the set of messages ever sent. Once sent, we'll 43 | // allow it to be delivered over and over. 44 | // (We don't have packet headers, so duplication, besides being realistic, 45 | // also doubles as how multiple parties can hear the message.) 46 | datatype Variables = Variables(sentMsgs:set) 47 | 48 | ghost predicate Init(c: Constants, v: Variables) 49 | { 50 | && v.sentMsgs == {} 51 | } 52 | 53 | ghost predicate Next(c: Constants, v: Variables, v': Variables, msgOps: MessageOps) 54 | { 55 | // Only allow receipt of a message if we've seen it has been sent. 56 | && (msgOps.recv.Some? ==> msgOps.recv.value in v.sentMsgs) 57 | // Record the sent message, if there was one. 58 | && v'.sentMsgs == 59 | v.sentMsgs + if msgOps.send.None? then {} else { msgOps.send.value } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/AsyncKVSpec.t.dfy: -------------------------------------------------------------------------------- 1 | include "AtomicKV.t.dfy" 2 | //#extract AtomicKV.t.template inherit AtomicKV.t.dfy 3 | include "EventSequenceRecorder.t.dfy" 4 | //#extract EventSequenceRecorder.t.template inherit EventSequenceRecorder.t.dfy 5 | 6 | 7 | // Identical to chapter08 AsyncWarehouseSpec, except that we're 8 | // asynchronizing AtomicKV instead of AtomicWarehouse. 9 | module AsyncKVSpec { 10 | import opened Types 11 | import AtomicKV 12 | import EventSequenceRecorder 13 | 14 | /*{*/ 15 | // Model this after the AsyncWarehouseSpec in chapter08. 16 | datatype Constants = Constants() // define me 17 | datatype Variables = Variables() // define me 18 | 19 | predicate Init(c: Constants, v: Variables) { 20 | && true // define me 21 | } 22 | 23 | predicate Next(c: Constants, v: Variables, v': Variables, event: Event) { 24 | && true // define me 25 | } 26 | /*}*/ 27 | } 28 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/AtomicKV.t.dfy: -------------------------------------------------------------------------------- 1 | include "IMapHelpers.t.dfy" 2 | include "Types.t.dfy" 3 | //#extract Types.t.template inherit Types.t.dfy 4 | 5 | // The application spec for this system is a key-value store 6 | // that maintains a map of int keys to int values. 7 | // The type of the state in this state machine is simply a total imap: one in 8 | // which every possible key is in the domain. 9 | // The user-visible actions are Get and Put operations. 10 | // Get accepts a key and returns a value. 11 | // Put accepts a key and a value and returns nothing (acknowledging completion). 12 | // 13 | // As in chapter08, we define the spec behavior as an atomic state machine -- 14 | // one that consumes an input and delivers an output in a single transition. 15 | // In DistributedSystem you'll use the EventSequenceRecorder to extend this 16 | // atomic definition to an asynchronous one where requests arrive some time 17 | // before execution, and responses are delivered some time after execution. 18 | 19 | module AtomicKV { 20 | import opened IMapHelpers 21 | import opened Types 22 | 23 | datatype Constants = Constants() 24 | 25 | datatype Variables = Variables(table: imap) 26 | 27 | // The initial map should assign the value zero to every key. 28 | predicate Init(c: Constants, v: Variables) { 29 | /*{*/ 30 | true // define me 31 | /*}*/ 32 | } 33 | 34 | // Model the state machine transition on the AtomicWarehouse module in chapter08. 35 | /*{*/ 36 | /*}*/ 37 | 38 | predicate Next(c: Constants, v: Variables, v': Variables, internalOp: InternalOp) { 39 | /*{*/ 40 | true // define me 41 | /*}*/ 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/AtomicKVSpec.t.dfy: -------------------------------------------------------------------------------- 1 | include "IMapHelpers.t.dfy" 2 | include "Types.t.dfy" 3 | 4 | // The application spec for this system is a key-value store 5 | // that maintains a map of int keys to int values. 6 | // The type of the state in this state machine is simply a total imap: one in 7 | // which every possible key is in the domain. 8 | // The user-visible actions are Get and Put operations. 9 | // Get accepts a key and returns a value. 10 | // Put accepts a key and a value and returns nothing (acknowledging completion). 11 | // 12 | // As in chapter08, we define the spec behavior as an atomic state machine -- 13 | // one that consumes an input and delivers an output in a single transition. 14 | // TODO correct: In DistributedSystem you'll use the EventSequenceRecorder to extend this 15 | // atomic definition to an asynchronous one where requests arrive some time 16 | // before execution, and responses are delivered some time after execution. 17 | 18 | // TODO correct docs: Identical to chapter08 AsyncWarehouseSpec, except that we're 19 | // asynchronizing AtomicKV instead of AtomicWarehouse. 20 | module AtomicKVSpec { 21 | import opened IMapHelpers 22 | import opened Types 23 | 24 | // Model this after the AsyncWarehouseSpec in chapter08. 25 | datatype Constants = Constants() // don't need any here 26 | datatype Variables = Variables( 27 | /*{*/ 28 | // define me 29 | /*}*/ 30 | ) 31 | 32 | // The initial map should assign the value zero to every key. 33 | // Be sure to check out IMapHelpers.t.dfy. It's helpful. 34 | ghost predicate Init(c: Constants, v: Variables) { 35 | /*{*/ 36 | && true // define me 37 | /*}*/ 38 | } 39 | 40 | // TODO replace docs: Model the state machine transition on the AtomicWarehouse module in chapter08. 41 | /*{*/ 42 | /*}*/ 43 | 44 | ghost predicate Next(c: Constants, v: Variables, v': Variables, event: Event) { 45 | // All the nondeterminism is encoded in `event`! No `exists` required. 46 | NextStep(c, v, v', event) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/DistributedSystem.t.dfy: -------------------------------------------------------------------------------- 1 | include "Network.t.dfy" 2 | //#extract Network.t.template inherit Network.t.dfy 3 | include "Host.v.dfy" 4 | //#extract Host.v.template inherit Host.v.dfy 5 | 6 | module DistributedSystem { 7 | import opened UtilitiesLibrary 8 | import opened Types 9 | import Network 10 | import Host 11 | 12 | type HostId = Network.HostId 13 | 14 | /*{*/ 15 | // TODO correct hint: Model this module after DistributedSystem in chapter08. 16 | datatype Constants = Constants() 17 | { 18 | ghost predicate WF() { 19 | && true 20 | } 21 | } 22 | datatype Variables = Variables() 23 | { 24 | ghost predicate WF(c: Constants) { 25 | && true 26 | } 27 | } 28 | 29 | ghost predicate Init(c: Constants, v: Variables) 30 | { 31 | && true // define me 32 | } 33 | 34 | ghost predicate Next(c: Constants, v: Variables, v': Variables, event: Event) 35 | { 36 | && true // define me 37 | } 38 | /*}*/ 39 | } 40 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/EventSequenceRecorder.t.dfy: -------------------------------------------------------------------------------- 1 | include "UtilitiesLibrary.t.dfy" 2 | include "Types.t.dfy" 3 | //#extract Types.t.template inherit Types.t.dfy 4 | 5 | module EventSequenceRecorder { 6 | import opened UtilitiesLibrary 7 | import opened Types 8 | 9 | datatype Constants = Constants() // No constants 10 | datatype Variables = Variables(requests:set, replies:set) 11 | 12 | predicate Init(c: Constants, v: Variables) 13 | { 14 | // Initialize Variables correctly. Hint: see chapter08 15 | /*{*/ 16 | && true 17 | /*}*/ 18 | } 19 | 20 | // Allow the Host to consume a request and produce a reply. 21 | // 22 | // internalOp is a binding variable: protocol says what it'd do if it got that 23 | // request, and this module gets to say whether a request is available right 24 | // now, or record the fact that the protocol returned a given result. 25 | // 26 | // The Host protocol can consume any request it wants, and introduce any reply 27 | // it wants; that won't affect meaning, since it ultimately has to get the 28 | // incoming requests and outgoing replies to match what the spec allows. 29 | predicate Execute(c: Constants, v: Variables, v': Variables, internalOp: InternalOp) 30 | /*{*/ 31 | requires true // Fix me. Hint: see chapter08 32 | /*}*/ 33 | { 34 | // Record that a request has been transformed into a reply. 35 | // Same idea as in the previous chapter. 36 | /*{*/ 37 | && true // Define me. Hint: see chapter08 38 | /*}*/ 39 | } 40 | 41 | predicate Internal(c: Constants, v: Variables, v': Variables) 42 | { 43 | && v' == v 44 | } 45 | 46 | // Record the claim that a client actually made this request. 47 | // This corresponds to a trusted handler attesting that the client wanted the 48 | // request, it wasn't just invented by the protocol. 49 | predicate AcceptRequest(c: Constants, v: Variables, v': Variables, request: Input) 50 | { 51 | // Record that a client has introduced a new request into the system. 52 | // Same idea as in the previous chapter. 53 | /*{*/ 54 | && true // Define me. Hint: see chapter08 55 | /*}*/ 56 | } 57 | 58 | // Ensure there's a reply to deliver to a client, and record the fact that 59 | // it's been delivered so we can't deliver a duplicate later. 60 | // This corresponds to a trusted handler attesting that this reply was 61 | // exposed to the client -- so the spec must justify the exposed value. 62 | predicate DeliverReply(c: Constants, v: Variables, v': Variables, reply: Output) 63 | { 64 | // Record that a reply has been delivered to a client. 65 | // Same idea as in the previous chapter. 66 | /*{*/ 67 | && true // Define me. Hint: see chapter08 68 | /*}*/ 69 | } 70 | 71 | predicate Next(c: Constants, v: Variables, v': Variables, event: Event) 72 | { 73 | /*{*/ 74 | && true // Define me. Hint: see chapter08 75 | /*}*/ 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/Host.v.dfy: -------------------------------------------------------------------------------- 1 | include "UtilitiesLibrary.t.dfy" 2 | include "IMapHelpers.t.dfy" 3 | include "Types.t.dfy" 4 | //#extract Types.t.template inherit Types.t.dfy 5 | include "MessageType.v.dfy" 6 | //#extract MessageType.v.template inherit MessageType.v.dfy 7 | include "Network.t.dfy" 8 | //#extract Network.t.template inherit Network.t.dfy 9 | 10 | // 11 | // Your protocol should capture the idea that keys "live" on different hosts 12 | // *and can move around* from host to host. So, in addition to implementing 13 | // client-visible actions as described in AtomicKV, each host should have a way 14 | // to send part of its state to another host, and to receive the corresponding 15 | // message from another sender. (The messages can move a batch of key-value 16 | // pairs, or a single pair at a time; neither is particularly harder than the 17 | // other.) 18 | // 19 | // Obviously, the hosts must be aware of which fraction of the keyspace they 20 | // own at any given time, so that a host doesn't try to service a Get or Put 21 | // request when the "real state" is off at some other host right now. 22 | // 23 | 24 | module Host { 25 | import opened UtilitiesLibrary 26 | import opened IMapHelpers 27 | import opened Types 28 | import opened MessageType 29 | import Network 30 | 31 | type HostId = Network.HostId 32 | 33 | /*{*/ 34 | // Model your Host on the chapter08 Host module. 35 | datatype Constants = Constants() 36 | datatype Variables = Variables() 37 | /*}*/ 38 | } 39 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/IMapHelpers.t.dfy: -------------------------------------------------------------------------------- 1 | module IMapHelpers { 2 | ghost predicate IsKey(k: int) { true } // a useless symbol for dafny to trigger on 3 | 4 | ghost function ZeroMap() : imap 5 | { 6 | imap i | IsKey(i) :: 0 7 | } 8 | 9 | ghost function EmptyMap() : imap 10 | { 11 | imap i | !IsKey(i) :: 0 12 | } 13 | 14 | ghost function MapUnionPreferLeft(a:map, b:map) : map 15 | { 16 | map key | key in a.Keys + b.Keys :: if key in a then a[key] else b[key] 17 | } 18 | 19 | ghost function IMapUnionPreferLeft(a:imap, b:imap) : imap 20 | { 21 | imap key | key in a || key in b :: if key in a then a[key] else b[key] 22 | } 23 | 24 | ghost function MapRemove(table:imap, removeKeys:iset) : imap 25 | requires removeKeys <= table.Keys 26 | { 27 | imap key | key in table && key !in removeKeys :: table[key] 28 | } 29 | 30 | ghost predicate IsFull(m:imap) { 31 | forall i :: i in m 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/MessageType.v.dfy: -------------------------------------------------------------------------------- 1 | module MessageType { 2 | datatype Message = 3 | /*{*/ 4 | | SomeMessage() // Replace me 5 | /*}*/ 6 | } 7 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/Network.t.dfy: -------------------------------------------------------------------------------- 1 | include "UtilitiesLibrary.t.dfy" 2 | include "Types.t.dfy" 3 | //#extract Types.t.template inherit Types.t.dfy 4 | include "MessageType.v.dfy" 5 | //#extract MessageType.v.template inherit MessageType.v.dfy 6 | 7 | module Network { 8 | import opened UtilitiesLibrary 9 | import opened Types 10 | import opened MessageType 11 | 12 | type HostId = nat 13 | 14 | datatype MessageOps = MessageOps(recv: Option, send: Option) 15 | 16 | datatype Constants = Constants // no constants for network 17 | 18 | datatype Variables = Variables(inFlightMessages:set) 19 | 20 | ghost predicate Init(c: Constants, v: Variables) 21 | { 22 | && v.inFlightMessages == {} 23 | } 24 | 25 | ghost predicate Next(c: Constants, v: Variables, v': Variables, msgOps: MessageOps) 26 | { 27 | // Only allow receipt of a message if we've seen it has been sent. 28 | && (msgOps.recv.Some? ==> msgOps.recv.value in v.inFlightMessages) 29 | 30 | ////////////////////////////////////////////////////////////////////////////// 31 | // _ ___ ___ _ __ _ _ _____ ____ _____ 32 | // | | / _ \ / _ \| |/ / | | | | ____| _ \| ____| 33 | // | | | | | | | | | ' / | |_| | _| | |_) | _| 34 | // | |__| |_| | |_| | . \ | _ | |___| _ <| |___ 35 | // |_____\___/ \___/|_|\_\ |_| |_|_____|_| \_\_____| 36 | // 37 | // This network model differs from chapter 08. It is a magical network that 38 | // prevents the host from sending a duplicate message until the first copy 39 | // is delivered! A little unrealistic, but it'll make your proof a little 40 | // easier. Read the following comment & conjunct. 41 | // 42 | ////////////////////////////////////////////////////////////////////////////// 43 | 44 | // Only allow sending a message if there isn't a duplicate of that 45 | // message already sent but not yet delivered. 46 | // Two better approaches I didn't take: 47 | // * Define the inFlightMessages as a multiset. Turns out this leads 48 | // to a much more challenging definition of disjoint in the proof. 49 | // * Demand the host provide nonces and do its own duplicate prevention, 50 | // proving it as an invariant. Ugh, too much to ask of students. 51 | // So instead, for this class project, we provide this little helpful 52 | // leg-up from the trusted network model. 53 | && (msgOps.send.Some? ==> msgOps.send.value !in v.inFlightMessages) 54 | 55 | // Record the sent message, if there was one. 56 | && v'.inFlightMessages == 57 | v.inFlightMessages 58 | // remove a message "used up" by receipt 59 | - (if msgOps.recv.None? then {} else { msgOps.recv.value }) 60 | // add a new message supplied by send 61 | + (if msgOps.send.None? then {} else { msgOps.send.value }) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/RefinementObligation.t.dfy: -------------------------------------------------------------------------------- 1 | include "AtomicKVSpec.t.dfy" 2 | //#extract AtomicKVSpec.t.template inherit AtomicKVSpec.t.dfy 3 | include "DistributedSystem.t.dfy" 4 | //#extract DistributedSystem.t.template inherit DistributedSystem.t.dfy 5 | 6 | abstract module RefinementObligation { 7 | import opened UtilitiesLibrary 8 | import opened Types 9 | import opened DistributedSystem 10 | import AtomicKVSpec 11 | 12 | ghost function ConstantsAbstraction(c: Constants) : AtomicKVSpec.Constants 13 | requires c.WF() 14 | 15 | ghost function VariablesAbstraction(c: Constants, v: Variables) : AtomicKVSpec.Variables 16 | requires v.WF(c) 17 | 18 | ghost predicate Inv(c: Constants, v: Variables) 19 | 20 | lemma RefinementInit(c: Constants, v: Variables) 21 | requires Init(c, v) 22 | ensures Inv(c, v) 23 | ensures AtomicKVSpec.Init(ConstantsAbstraction(c), VariablesAbstraction(c, v)) 24 | 25 | // The key idea in this refinement obligation is that every step of the DistributedSystem 26 | // has an event label, and that event label must match whatever step of the spec 27 | // is implied by Player 2's abstraction function. 28 | lemma RefinementNext(c: Constants, v: Variables, v': Variables, event: Event) 29 | requires Next(c, v, v', event) 30 | requires Inv(c, v) 31 | ensures Inv(c, v') 32 | ensures AtomicKVSpec.Next(ConstantsAbstraction(c), VariablesAbstraction(c, v), VariablesAbstraction(c, v'), event) 33 | } 34 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/Types.t.dfy: -------------------------------------------------------------------------------- 1 | module Types { 2 | 3 | // TODO: should we ask students to define these? 4 | datatype Event = 5 | | Get(key: int, value: int) 6 | | Put(key: int, value: int) 7 | | NoOp() 8 | } 9 | 10 | -------------------------------------------------------------------------------- /2022/project02-sharded-kv-store/exercises/UtilitiesLibrary.t.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Published Here](https://glados-michigan.github.io/verification-class/2022/) 2 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/DirectionsLibrary.dfy: -------------------------------------------------------------------------------- 1 | //#desc Library for exercises 12 & 14 2 | 3 | // This is tagged union, a "sum" datatype. 4 | datatype Direction = North() | East() | South() | West() 5 | 6 | function TurnRight(direction:Direction) : Direction 7 | { 8 | // This function introduces two new bits of syntax. 9 | // First, the if-else expression: if then T else T 10 | // Second, the element.Ctor? built-in predicate, which tests whether 11 | // the datatype `element` was built by `Ctor`. 12 | if direction.North? 13 | then East 14 | else if direction.East? 15 | then South 16 | else if direction.South? 17 | then West 18 | else // By elimination, West! 19 | North 20 | } 21 | 22 | lemma Rotation() 23 | { 24 | assert TurnRight(North) == East; 25 | } 26 | 27 | function TurnLeft(direction:Direction) : Direction 28 | { 29 | // Another nice way to take apart a datatype element is with match-case 30 | // construct. Each case argument is a constructor; each body must be of the 31 | // same type, which is the type of the entire `match` expression. 32 | match direction { 33 | case North => West 34 | case West => South 35 | case South => East // Try changing "East" to 7. 36 | case East => North 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/LunchLibrary.dfy: -------------------------------------------------------------------------------- 1 | //#desc Library for exercises 13 & 14 2 | 3 | // This whole product-sum idea gets clearer when we use both powers 4 | // (struct/product, union/sum) at the same time. 5 | 6 | datatype Meat = Salami | Ham 7 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 8 | datatype Veggie = Olive | Onion | Pepper 9 | datatype Order = 10 | Sandwich(meat:Meat, cheese:Cheese) 11 | | Pizza(meat:Meat, veggie:Veggie) 12 | | Appetizer(cheese:Cheese) 13 | 14 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 15 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 16 | // Thus there are 8+6+4 = 18 Orders. 17 | // This is why they're called "algebraic" datatypes. 18 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Lemmas and assertions 2 | 3 | lemma IntegerOrdering() 4 | { 5 | // An assertion is a **static** check of a boolean expression -- a mathematical truth. 6 | // This boolean expression is about (mathematical) literal integers. 7 | // Run dafny on this file. See where it fails. Fix it. 8 | assert /*{*/ 5 < 3 /*}*/; 9 | } 10 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Boolean logic 2 | 3 | lemma BooleanLogic() 4 | { 5 | // An assertion is a static check of a boolean expression. 6 | // This boolean expression is about a boolean implication. 7 | // Run dafny on this file. See where it fails. Fix it. 8 | assert true ==> /*{*/ false /*}*/; 9 | } 10 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Functions 2 | 3 | // A `function` is a mathematical function. 4 | // This one has a domain of the integers and the range is (within) the 5 | // integers. Again, `int` is the entire set of mathematical integers. 6 | 7 | // Run dafny on this file. See where it fails. Fix it. 8 | 9 | ghost function Double(val:int) : int 10 | { 11 | // The body of a function is an expression context. No semicolon 12 | // at the end. 13 | 2 * val 14 | } 15 | 16 | // A lemma is like a C++ method or C function (hence the statement context). 17 | // The proof it contains is like a program: a sequence of statements. 18 | // As in C, statements terminate with semicolons and can be grouped into blocks 19 | // with braces. 20 | lemma DoubleIsLikePlus() 21 | { 22 | assert Double(6) == 6 + 6; 23 | { 24 | assert Double(-2) == /*{*/4/*}*/; 25 | } 26 | } 27 | 28 | // A lemma can take arguments. This is one way to prove a statement about 29 | // *any* value, not just a particular literal. 30 | lemma foo4(val:int) 31 | { 32 | assert Double(val) == val + /*{*/val + val/*}*/; 33 | } 34 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise04.dfy: -------------------------------------------------------------------------------- 1 | //#title Predicates 2 | 3 | // A common thing you'll want is a function with a boolean result. 4 | ghost function AtLeastTwiceAsBigFunction(a:int, b:int) : bool 5 | { 6 | a >= 2*b 7 | } 8 | 9 | // It's so fantastically common that there's a shorthand for it: `predicate`. 10 | ghost predicate AtLeastTwiceAsBigPredicate(a:int, b:int) 11 | { 12 | a >= 2*b 13 | } 14 | 15 | ghost function Double(a:int) : int 16 | { 17 | 2 * a 18 | } 19 | 20 | lemma TheseTwoPredicatesAreEquivalent(x:int, y:int) 21 | { 22 | assert AtLeastTwiceAsBigFunction(x, y) == AtLeastTwiceAsBigPredicate(x, y); 23 | } 24 | 25 | // Add a 'requires' precondition to make this lemma verify. 26 | // Keep it as simple as possible (e.g. avoid named predicates). 27 | lemma FourTimesIsPrettyBig(x:int) 28 | /*{*/ 29 | /*}*/ 30 | { 31 | assert AtLeastTwiceAsBigPredicate(Double(Double(x)), x); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise05.dfy: -------------------------------------------------------------------------------- 1 | //#title Sets 2 | 3 | // This predicate takes a set of integers as an argument. 4 | // set is a built-in templated type. 5 | ghost predicate HasSevenAndNotNine(intset:set) 6 | { 7 | 7 in intset && 9 !in intset 8 | } 9 | 10 | lemma TryOutSomeSetLiterals() 11 | { 12 | assert {1,3,8} == {8,1,3}; 13 | 14 | assert HasSevenAndNotNine({7}); 15 | 16 | // None of these asserions are correct. Try them. 17 | // Then delete these first two... 18 | /*{*/ 19 | assert HasSevenAndNotNine({7,9}); 20 | assert HasSevenAndNotNine({1,3,5,7,8,9,10}); 21 | /*}*/ 22 | // ...and replace the argument of this assert with a set that does satisfy 23 | // the predicate. 24 | assert HasSevenAndNotNine({/*{*//*}*/}); 25 | } 26 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise06.dfy: -------------------------------------------------------------------------------- 1 | //#title More set tools 2 | 3 | // <= on sets is subset. 4 | ghost predicate HasFourFiveSix(intset:set) 5 | { 6 | {6,5,4} <= intset // I can because they're sets! 7 | } 8 | 9 | lemma SomeAssertionsAboutSets() 10 | { 11 | assert !HasFourFiveSix({1,2,4,6,7}); 12 | 13 | // This is just a mathematical "let" statement. 14 | // It's safe to substitute the value wherever "happySet" appears. 15 | var happySet := {1,2,4,6,7,5}; 16 | assert HasFourFiveSix(happySet); 17 | 18 | // - on sets is difference. 19 | assert happySet - {4,5,6} == {7,2,1}; 20 | 21 | // + on sets is union. 22 | assert HasFourFiveSix({4,6} + {5}); 23 | 24 | // |x| on a set is cardinality. 25 | // (set is always finite; there is another type iset for 26 | // possibly-infinite sets.) 27 | assert |happySet| == /*{*/7/*}*/; 28 | } 29 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise07.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: Literals, indexing 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | // [x,y,z] is a literal sequence; this one is a seq. 6 | var fibo := [1,1,2,3,5,8,13,21,34]; 7 | // Index into a sequence. 8 | assert fibo[4] == 5; 9 | 10 | // Sequences have cardinality (and hence are always finite length). 11 | assert |fibo| == 9; 12 | assert fibo[0] == 1; 13 | assert fibo[8] == 34; 14 | assert fibo[/*{*/9/*}*/] == 21; 15 | } 16 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise08.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: Slices 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | var fibo := [1,1,2,3,5,8,13,21,34]; 6 | 7 | // A slice of a sequence is a sequence. 8 | // The left argument is inclusive, the right exclusive. 9 | assert fibo[2..4] == [2,3]; 10 | 11 | // You can omit either endpoint to refer to the beginning or end of the 12 | // sequence. 13 | assert fibo[..3] == [1,1,2]; 14 | assert fibo[7..] == [21,34]; 15 | 16 | assert fibo[5..6] == /*{*/8/*}*/; 17 | } 18 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise09.dfy: -------------------------------------------------------------------------------- 1 | //#title Sequences: types, cardinality 2 | 3 | lemma ExperimentsWithSequences() 4 | { 5 | var fibo := [1,1,2,3,5,8,13,21,34]; 6 | 7 | // The type of fibo is seq. 8 | // Here, we explicitly declare the type of `copy`. In previous examples, the 9 | // type has always been inferred by the compiler. I just wanted you to see 10 | // what it was inferring. 11 | var copy:seq := fibo; 12 | 13 | // You can, of course, have a seq of other stuff. 14 | var seqOfSets:seq> := [{0}, {0,1}, {0,1,2}]; 15 | 16 | var whatsMyProblem := [0, /*{*/1, false/*}*/]; 17 | 18 | // |expr| below is sequence-length 19 | assert |seqOfSets| == 3; 20 | // Type checking means the |expr| below is a set-cardinality operator. 21 | assert |seqOfSets[1]| == /*{*/3/*}*/; 22 | } 23 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise10.dfy: -------------------------------------------------------------------------------- 1 | //#title Type synonyms 2 | 3 | // So by now you see me composing types and you're itching to 4 | // construct some of your own. 5 | 6 | // First, type renaming: 7 | type SeqOfSets = seq> 8 | 9 | lemma TryATypeSynonym() 10 | { 11 | var seqOfSets:SeqOfSets := [{0}, {0,1}, {0,1,2}]; 12 | assert 1 in /*{*/seqOfSets[0]/*}*/; 13 | } 14 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise11.dfy: -------------------------------------------------------------------------------- 1 | //#title Struct (product) datatypes. 2 | 3 | // Okay, but I know you won't settle for merely renaming some fancy type 4 | // expression. You actually want to define something new. 5 | 6 | // Dafny has "algebraic" datatypes which capture both "struct" 7 | // and (tagged) "union". 8 | // First, structs: 9 | datatype Point = PointCtor(x:int, y:int) 10 | 11 | // You could alternatively write this as: 12 | // datatype Point = Point(x:int, y:int) 13 | // The first "Point" is the type name, the second is the constructor name. When 14 | // the type has only one constructor, it's conventional to give them the same 15 | // name since the language can distinguish the two uses from context. 16 | 17 | /*{*/ 18 | ghost function subtractPoints(tip:Point, tail:Point) : Point 19 | { 20 | PointCtor(tip.x - tail.x, tip.y - tail.x) 21 | } 22 | /*}*/ 23 | 24 | lemma PointArithmetic() 25 | { 26 | var a := PointCtor(1,13); 27 | var b := PointCtor(2,7); 28 | 29 | // NB Points (and every other `datatype`) are mathematical, immutable 30 | // objects, so the one we get back from the function must be equal 31 | // (identical) to the one we construct manually. There's no implicit 32 | // user-overridable Equals() method; these are platonic mathematical objects. 33 | 34 | // This exercise is a little harder than the previous ones; take a moment 35 | // to investigate it carefully! 36 | assert subtractPoints(a, b) == PointCtor(-1, 6); 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise12.dfy: -------------------------------------------------------------------------------- 1 | //#title include directive and Union (sum) datatypes 2 | 3 | // You can include code from another file. includes must all appear at the 4 | // beginning of a file, before any other definitions. 5 | // Open and read DirectionsLibrary.dfy 6 | include "DirectionsLibrary.dfy" 7 | 8 | lemma TwoWrongsDontMakeARight(dir:Direction) 9 | { 10 | assert TurnLeft(/*{*/TurnLeft(TurnLeft(dir))/*}*/) == TurnRight(TurnRight(dir)); 11 | } 12 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise13.dfy: -------------------------------------------------------------------------------- 1 | //#title More with algebraic datatypes. 2 | 3 | // Begin by reading LunchLibrary.dfy. We extracted it 4 | // to a separate file because we'll use it again later. 5 | include "LunchLibrary.dfy" 6 | 7 | lemma AlgebraicLunch() 8 | { 9 | var meal:set := { 10 | Pizza(Ham, Olive), 11 | Sandwich(Ham, Provolone), 12 | Pizza(Ham, Olive) 13 | }; 14 | // Fix this assertion. Hint: The two pizzas are the same element of the datatype. 15 | assert |meal| == /*{*/3/*}*/; 16 | } 17 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise14.dfy: -------------------------------------------------------------------------------- 1 | //#title Quantifiers 2 | include "LunchLibrary.dfy" 3 | include "DirectionsLibrary.dfy" 4 | 5 | // Most of what we'll be working with in proof are quantified 6 | // statements: for all inputs, my program produces the right output! 7 | lemma Forall() 8 | { 9 | assert forall x:int :: x+x == 2*x; 10 | } 11 | 12 | // Remember this critter from exercise12? We can rewrite it in a forall. 13 | lemma AnotherForall() 14 | { 15 | // "Two wrongs don't make a right, but ..." 16 | assert forall dir :: TurnLeft(/*{*/TurnLeft(TurnLeft(dir))/*}*/) == TurnRight(TurnRight(dir)); 17 | } 18 | 19 | // Here's there-exists, forall's evil twin. 20 | // exists x :: P(x) == !forall x :: !P(x) 21 | lemma TryThatCheeseOnASandwich() 22 | { 23 | // Hey, neat. Dafny has a hard time proving exists. It needs 24 | // a "witness". 25 | // To proceed, replace 'false' with 'true', and move on to the 26 | // next lemma to read about how to solve it. 27 | // If the '?' syntax is surprising, go re-read DirectionsLibrary.dfy. 28 | assert (forall o1:Order :: 29 | o1.Appetizer? 30 | ==> exists o2:Order :: o2.Sandwich? && o1.cheese == o2.cheese) 31 | || /*{*/ false /*}*/; 32 | } 33 | 34 | lemma CheeseTakeTwo() 35 | { 36 | // So here's the "statement" version of a forall expression. 37 | // With nothing in the body, it's exactly equivalent to the assertion 38 | // above. 39 | forall o1:Order 40 | // The assumptions follow a '|' ("such that") 41 | | o1.Appetizer? 42 | // The conclusions follow a "requires" keyword. 43 | ensures exists o2:Order :: o2.Sandwich? && o1.cheese == o2.cheese 44 | { 45 | // The body of the forall statement is a proof context for the 46 | // statement's conclusion. Inside here, o1 is defined, and we 47 | // can use it to complete the proof. 48 | 49 | // But how? What's missing is that Dafny needs a "witness" to the 50 | // there-exists. We need to show an expression that satisfies the 51 | // body of the exists. Try uncommenting these lines: 52 | /*{*////*}*/ var o3 := Sandwich(Ham, o1.cheese); 53 | /*{*////*}*/ assert o3.Sandwich? && o1.cheese == o3.cheese; 54 | // Simply *mentioning* an Order that satisfies the predicate 55 | // on o2 above is enough for Dafny to see the proof; once we mention 56 | // it, Dafny will try plugging it into the expression. Try removing 57 | // the assertion above this comment; notice that the proof still goes 58 | // through. 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise15.dfy: -------------------------------------------------------------------------------- 1 | //#title Maps. Set, Map and Sequence comprehensions. 2 | 3 | ghost predicate IsEven(x:int) 4 | { 5 | x/2*2==x 6 | } 7 | 8 | lemma SetComprehension() 9 | { 10 | // Here's how you define a "big" (perhaps unknown size, but finite) set: 11 | // Read it as "the set of values x such that (|) x is between 0 and 10 and is even." 12 | // (In general, it's "the set of value x such that predicate P(x) is true".) 13 | var modestEvens := set x | 0 <= x < 10 && IsEven(x); 14 | assert modestEvens == {/*{*/0,2,4,8/*}*/}; 15 | } 16 | 17 | lemma Maps() 18 | { 19 | // Map generic type, map literal syntax 20 | var doubleMap:map := map[1:=2, 2:=4, 3:=6, 4:=8]; 21 | 22 | assert doubleMap[3] == 6; 23 | 24 | var replaceMap := doubleMap[3 := 7]; 25 | assert replaceMap[1] == 2; 26 | assert replaceMap[2] == 4; 27 | assert replaceMap[3] == /*{*/6/*}*/; 28 | } 29 | 30 | lemma MapComprehension() 31 | { 32 | // Here's how you define a "big" (but finite-domain) map. Read it as 33 | // "The map with domain x such that 0<=x<5" (that is, domain is defined just like a set comprehension) 34 | // ..."and for which the value at [x] is 2*x" (the thing after :: is an expression of the value type). 35 | // This map is type-inferred to be map. 36 | var doublyMap := map x | 0<=x<5 :: 2*x; 37 | assert doublyMap[1] == 2; 38 | assert doublyMap[4] == /*{*/4/*}*/; 39 | } 40 | 41 | lemma SeqComprehension() 42 | { 43 | // The sequence comprehension syntax is, unfortunately, kinda hideous compared 44 | // to the set & map comprehensions. seq(N, f) is a function. 45 | // 46 | // N is the size of the output sequence (that is, |eventsInOrder| == 5). 47 | // 48 | // f is a function -- in this case an anonymous lambda -- that gives the value 49 | // at each index. The "i" before the "=>" is the parameter list of the lambda; 50 | // "i*2" is the expression body of the lambda function. The "requires 0<=i<5" 51 | // is a way to pass into the lambda the knowledge that seq() will only call 52 | // it with those particular values. It's not actually needed here (since the 53 | // expression i*2 works on all integers), but it's quite often necessary. 54 | var evensInOrder := seq(5, i requires 0<=i<5 => i*2); 55 | assert evensInOrder[2] == 4; 56 | assert evensInOrder == [/*{*/8,6,4,2,0/*}*/]; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise16.dfy: -------------------------------------------------------------------------------- 1 | //#title IsEven 2 | //#desc Hoare logic 3 | 4 | // So far, we have introduced function and datatype definitions; 5 | // the definition of each is entirely visible to its users. 6 | // We have also discussed lemmas. The body of a lemma is invisible 7 | // to its callers -- but we haven't ever called a lemma! 8 | // Calling lemmas is how we can compose proofs to prove larger concepts. 9 | 10 | ghost predicate IsEven(x:int) 11 | { 12 | x/2*2==x 13 | } 14 | 15 | // A lemma is like a C function; it can return values. Let's return a value 16 | // and then ensure a property of it. 17 | lemma ExplainEvenNumbers(x:int) returns (twocount:int) 18 | // This lemma doesn't work unless we know x is even. 19 | // This requires clause is a fact we get to assume inside the lemma. 20 | requires IsEven(x) 21 | // To export knowledge from a lemma, we declare it in an `ensures` clause. 22 | ensures twocount*2 == x 23 | { 24 | // return twocount by assigning it. 25 | twocount := x / /*{*/3/*}*/; 26 | } 27 | 28 | ghost predicate AlternateEven(x:int) 29 | { 30 | exists twocount :: twocount * 2 == x 31 | } 32 | 33 | // Instead of hiding the thing we prove inside the body as an assert, 34 | // let's export it. 35 | lemma EvenDefinitionsAreEquivalent(x:int) 36 | ensures IsEven(x) == AlternateEven(x) 37 | { 38 | // Wow, that proved without us providing a witness! 39 | } 40 | 41 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise17.dfy: -------------------------------------------------------------------------------- 1 | //#title Fibo 2 | //#desc Recursion challenge. 3 | 4 | ghost function fibo(val:nat) : nat 5 | { 6 | /*{*/ 7 | 0 8 | /*}*/ 9 | } 10 | 11 | lemma Check() 12 | ensures fibo(0) == 0 13 | ensures fibo(20) == 6765 14 | { 15 | } 16 | 17 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise18.dfy: -------------------------------------------------------------------------------- 1 | //#title FindMax 2 | //#desc Loop invariants. 3 | 4 | method FindMax(intSeq:seq) returns (maxIndex:nat) 5 | requires |intSeq| > 0 6 | ensures maxIndex<|intSeq| 7 | ensures forall idx:nat | idx<|intSeq| :: intSeq[idx] <= intSeq[maxIndex] 8 | { 9 | var count:nat := 0; 10 | maxIndex := 0; 11 | while(count < |intSeq|) 12 | /*{*/ 13 | invariant true // hint: you'll need three invariants 14 | invariant true 15 | invariant true 16 | /*}*/ 17 | { 18 | if(intSeq[maxIndex] < intSeq[count]) { 19 | maxIndex := count; 20 | } 21 | count := count+1; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise19.dfy: -------------------------------------------------------------------------------- 1 | //#title IsSeqSorted 2 | //#desc Build an entire imperative loop method implementation with loop 3 | //#desc invariants. 4 | 5 | predicate IsSorted(intseq:seq) { 6 | forall i:nat,j:nat | i) returns (issorted:bool) 10 | ensures issorted <==> IsSorted(intSeq[..]) 11 | { 12 | /*{*/ 13 | return true; 14 | /*}*/ 15 | } 16 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise20.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Search 2 | //#desc Method implementation; writing a Hoare spec. 3 | 4 | ghost predicate IsSorted(seqint:seq) { 5 | forall i:nat,j:nat | i= to the needle. 10 | // If the needle is present, this should be the index of the needle. 11 | // If needle is bigger than every element, return the length of the 12 | // sequence: It's not a valid index in the sequence, but it's bigger 13 | // than the indices of all the elements that have smaller values. 14 | 15 | method BinarySearch(haystack:seq, needle:int) returns (index:nat) 16 | requires IsSorted(haystack) 17 | /*{*/ 18 | /*}*/ 19 | { 20 | /*{*/ 21 | return 0; // Replace me with an implementation. 22 | /*}*/ 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise21.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Tree Is Sorted 2 | //#desc Prove an implementation meets its spec. 3 | //#desc Practice with proof diagnosis. 4 | 5 | include "UtilitiesLibrary.dfy" 6 | import opened UtilitiesLibrary 7 | 8 | // Define a Binary Tree and write a method to check if it is sorted 9 | 10 | // A binary tree is a tree data structure in which each (internal) node has a value and at 11 | // most two children, which are referred to as the left child and the right child. 12 | 13 | /*{*/ 14 | // you should define your Tree datatype here. 15 | datatype Tree = Tree 16 | /*}*/ 17 | 18 | // This lemma is here to guide you in defining the tree in a way 19 | // that will help with the rest of the exercise. 20 | lemma DatatypeCheck() 21 | { 22 | var emptyTree := Nil; 23 | var littleTree := Node(9, Nil, Nil); 24 | var biggerTree := Node(10, littleTree, littleTree); // Note: not sorted 25 | } 26 | 27 | // You will find the following function method useful. It is meant to express 28 | // the given tree as a sequence. 29 | // 30 | // Note: a function method is just like a ghostfunction, except it 31 | // can be used in an "imperative" context (i.e., inside a method) 32 | 33 | ghost function TreeAsSequence(tree:Tree) : seq 34 | { 35 | /*{*/ 36 | [] // Replace me 37 | /*}*/ 38 | } 39 | 40 | // If this predicate is true about sorted sequences, then everything 41 | // in seq1 is <= everything in seq2. 42 | ghost predicate SequencesOrderedAtInterface(seq1:seq, seq2:seq) 43 | { 44 | if |seq1|==0 || |seq2|==0 45 | then true 46 | else Last(seq1) <= seq2[0] 47 | } 48 | 49 | // Write a recursive definition for what it means for a Tree to be sorted 50 | ghost predicate IsSortedTree(tree:Tree) { 51 | /*{*/ 52 | true // Replace me 53 | /*}*/ 54 | } 55 | 56 | // You may find it useful to relate your recursive definition of IsSortedTree to 57 | // a sequential representation of the tree structure 58 | 59 | datatype TreeSortedness = Unsorted | Empty | Bounded(low: int, high: int) 60 | 61 | // Write a recursive implementation that checks if a tree 62 | // is sorted by checking the children, then using TreeAsSequence 63 | // on the children to confirm that both children stay on their 64 | // respective sides of the pivot. 65 | method CheckIfSortedTree(tree:Tree) returns (out: TreeSortedness) 66 | ensures IsSortedTree(tree) <==> !out.Unsorted? 67 | /*{*/ 68 | /*}*/ 69 | { 70 | /*{*/ 71 | return Unsorted; 72 | // Implement this method. Feel free to make this a recursive method. 73 | /*}*/ 74 | } 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /fall2024/chapter01-basics/exercises/exercise22.dfy: -------------------------------------------------------------------------------- 1 | //#title Binary Tree Search 2 | //#desc Implement search in a binary tree and prove it works. 3 | //#desc Practice with proof diagnosis. 4 | 5 | include "exercise21.dfy" 6 | //#extract exercise21.template solution exercise21.dfy 7 | 8 | // This exercise builds on exercise21 (so make sure you have completed 9 | // that one, too). If in doubt about your solution to exercise21, contact 10 | // an instructor during office hours to make sure you're on the right path. 11 | 12 | predicate SequenceIsSorted(intseq:seq) { 13 | forall i:nat,j:nat | i needle in TreeAsSequence(tree) 25 | { 26 | /*{*/ 27 | /*}*/ 28 | } 29 | -------------------------------------------------------------------------------- /fall2024/chapter02-specification/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title IsPrimeSpec I 2 | //#desc Basic specification. 3 | // Implement a predicate that tells whether a natural number is prime. 4 | 5 | /*{*/ 6 | /*}*/ 7 | ghost predicate IsPrimeSpec(candidate:nat) 8 | { 9 | /*{*/ 10 | false // Replace me 11 | /*}*/ 12 | } 13 | 14 | // illustrate IsPrimeSpec on a few examples (note that the verifier is able to 15 | // check these only with some help to find divisors for non-prime numbers) 16 | lemma ConstantObligations() 17 | ensures !IsPrimeSpec(0) 18 | ensures !IsPrimeSpec(1) 19 | ensures IsPrimeSpec(2) 20 | ensures IsPrimeSpec(3) 21 | ensures !IsPrimeSpec(4) 22 | ensures !IsPrimeSpec(6) 23 | ensures IsPrimeSpec(7) 24 | ensures !IsPrimeSpec(9) 25 | { 26 | /*{*/ 27 | /*}*/ 28 | } 29 | 30 | lemma CompositeIsntPrime(p: nat) 31 | requires 1 < p 32 | ensures !IsPrimeSpec(p*66) 33 | { 34 | /*{*/ 35 | /*}*/ 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /fall2024/chapter02-specification/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title IsPrime II 2 | //#desc Working with an implementation proof 3 | 4 | // Let's try "implementing" (with a recursive function) a check for 5 | // primeness. 6 | 7 | // The definition of IsPrime will be included from exercise01.dfy. Make sure 8 | // that definition is correct before you start implementing it. 9 | include "exercise01.dfy" 10 | //#extract exercise01.template solution exercise01.dfy 11 | 12 | // A recursive implementation of IsPrime. The function HasDivisorBelow should 13 | // check if n is divisible by something between 1 and limit (including limit, 14 | // not including 1). 15 | function 16 | HasDivisorBelow(n:nat, limit:nat): bool 17 | requires limit >= 1 18 | { 19 | if limit == 1 then false else 20 | /*{*/ 21 | true // replace this with an appropriate definition 22 | /*}*/ 23 | } 24 | 25 | function 26 | IsPrime(n: nat): bool { 27 | if n <= 1 then false else 28 | !HasDivisorBelow(n, n-1) 29 | } 30 | 31 | // You'll now prove IsPrime(n) == IsPrimeSpec(n). This will require a helper 32 | // lemma to deal with the recursion. 33 | 34 | // An intermediate spec for what HasDivisorBelow returns. The solution is expressed using an 35 | // exists; you may find it more natural to write a forall. 36 | lemma HasDivisorBelow_ok(n: nat, limit: nat) 37 | requires 1 <= limit 38 | /*{*/ 39 | ensures true // replace this with an appropriate postcondition 40 | /*}*/ 41 | { 42 | /*{*/ 43 | /*}*/ 44 | } 45 | 46 | lemma IsPrime_ok(n: nat) 47 | ensures IsPrime(n) == IsPrimeSpec(n) 48 | { 49 | /*{*/ 50 | // This proof should work if your postcondition for HasDivisorBelow_ok is 51 | // correct, but you can change it if needed. 52 | if n <= 2 { 53 | return; 54 | } 55 | HasDivisorBelow_ok(n, n-1); 56 | /*}*/ 57 | } 58 | -------------------------------------------------------------------------------- /fall2024/chapter02-specification/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Merge Sort 2 | //#desc More specification practice. 3 | 4 | // Implement a merge sort that guarantees the result is sorted. 5 | // merge() should merge its two sorted inputs into a sorted output. 6 | // merge_sort picks a pivot, recursively merge_sort()s the subsequences, 7 | // and then uses merge() to put them back together. We've provided 8 | // signatures for merge and merge_sort to get you started. 9 | 10 | predicate IsSorted(seqint:seq) 11 | { 12 | forall idx :: 0 <= idx < |seqint|-1 ==> seqint[idx] <= seqint[idx+1] 13 | } 14 | 15 | /*{*/ 16 | /*}*/ 17 | method merge_sort(input:seq) returns (output:seq) 18 | /*{*/ 19 | ensures true // Replace me 20 | /*}*/ 21 | { 22 | /*{*/ 23 | // Supply the body. 24 | /*}*/ 25 | } 26 | 27 | method merge(seqa:seq, seqb:seq) returns (output:seq) 28 | requires IsSorted(seqa) 29 | requires IsSorted(seqb) 30 | /*{*/ 31 | ensures true // Replace me 32 | /*}*/ 33 | { 34 | /*{*/ 35 | // Supply the body. 36 | /*}*/ 37 | } 38 | 39 | -------------------------------------------------------------------------------- /fall2024/chapter03-state-machines/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Coke Machine 2 | //#desc The first state machine specification exercise: fill in actions. 3 | 4 | // You are asked to define the state machine for a coke vending machine. 5 | // The machine starts empty and has a capacity of 7 cokes. 6 | // The machine should support the following actions: 7 | // Purchase: dispense one coke from the machine 8 | // Restock: add a number of cokes to the machine 9 | 10 | datatype Constants = Constants(capacity:int) 11 | datatype Variables = Variables(numCokes:int) 12 | 13 | ghost predicate Init(c:Constants, v:Variables) { 14 | /*{*/ 15 | true // Replace me 16 | /*}*/ 17 | } 18 | 19 | ghost predicate Purchase(c:Constants, v:Variables, v':Variables) { 20 | /*{*/ 21 | true // Replace me 22 | /*}*/ 23 | } 24 | 25 | ghost predicate Restock(c:Constants, v:Variables, v':Variables, numRestock:int) 26 | { 27 | /*{*/ 28 | true // Replace me 29 | /*}*/ 30 | } 31 | 32 | // Jay-Normal-Form: pack all the nondeterminism into a single object 33 | datatype Step = 34 | | PurchaseStep 35 | | RestockStep(num: int) 36 | 37 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 38 | match step 39 | case PurchaseStep => Purchase(c, v, v') 40 | case RestockStep(num) => Restock(c, v, v', num) 41 | } 42 | 43 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 44 | exists step :: NextStep(c, v, v', step) 45 | } 46 | 47 | //========================== 48 | // Everything below this line is not part of the specification. It allows 49 | // you to use the verifier to confirm that your state machine has a number 50 | // of desirable properties. 51 | 52 | ghost predicate Inv(c:Constants, v:Variables) { 53 | 0 <= v.numCokes <= c.capacity 54 | } 55 | 56 | lemma SafetyProof() 57 | ensures forall c, v | Init(c, v) :: Inv(c, v) 58 | ensures forall c, v, v' | Inv(c, v) && Next(c, v, v') :: Inv(c, v') 59 | { 60 | forall c, v, v' | Inv(c, v) && Next(c, v, v') 61 | ensures Inv(c, v') 62 | { 63 | if(Purchase(c, v, v')) { 64 | assert Inv(c, v'); 65 | } else { 66 | var num :| Restock(c, v, v', num); 67 | assert Inv(c, v'); 68 | } 69 | } 70 | } 71 | 72 | lemma NonTrivialPurchase() 73 | ensures exists c, v, v' :: Inv(c, v) && Next(c, v, v') && v'.numCokes + 1 == v.numCokes 74 | { 75 | var c := Constants(7); 76 | var v := Variables(1); 77 | var v' := Variables(0); 78 | assert NextStep(c, v, v', PurchaseStep); 79 | assert Inv(c, v) && Next(c, v, v') && v'.numCokes + 1 == v.numCokes; 80 | } 81 | 82 | lemma NonTrivialRestock() 83 | ensures exists c, v, v' :: Inv(c, v) && Next(c, v, v') && v.numCokes < v'.numCokes 84 | { 85 | var c := Constants(7); 86 | var v := Variables(4); 87 | var v' := Variables(7); 88 | assert NextStep(c, v, v', RestockStep(3)); 89 | assert Inv(c, v) && Next(c, v, v') && v.numCokes < v'.numCokes; 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /fall2024/chapter03-state-machines/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Dining Philosophers 2 | //#desc A more challenging state machine: define the state datatype. 3 | 4 | // Define the state machine for the Dining Philosophers. 5 | // There are N philosophers sitting around a round table with N chairs. 6 | // Between every pair of philosophers lies a chopstick. 7 | // Every philosopher has three possible actions: 8 | // * Acquire the chopstick to their left. 9 | // * Acquire the chopstick to their right. 10 | // * Release both chopsticks (in a single step). 11 | // 12 | // (Nota bene: The dining philosophers problem is used to illustrate deadlocks 13 | // and deadlock-freedom. We're not doing any of that here, just using the 14 | // example to teach you to set up a state machine model.) 15 | 16 | datatype Constants = Constants(tableSize:nat) 17 | { 18 | // An initial predicate to define well-formed constants. 19 | ghost predicate WellFormed() { 20 | && 0 < tableSize 21 | } 22 | } 23 | 24 | 25 | /*{*/ 26 | /*}*/ 27 | // Define all the relevant state in this datatype. 28 | /*{*/ 29 | datatype Variables = Variables() 30 | { 31 | ghost predicate WellFormed(c: Constants) { 32 | && c.WellFormed() 33 | } 34 | } 35 | /*}*/ 36 | 37 | ghost predicate Init(c:Constants, v:Variables) { 38 | /*{*/ 39 | true // Replace me 40 | /*}*/ 41 | } 42 | 43 | /*{*/ 44 | /*}*/ 45 | 46 | // Philosopher with index philosopherIndex acquires left chopstick 47 | ghost predicate AcquireLeft(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 48 | /*{*/ 49 | true // Replace me 50 | /*}*/ 51 | } 52 | 53 | // Philosopher with index philosopherIndex acquires right chopstick 54 | ghost predicate AcquireRight(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 55 | /*{*/ 56 | true // Replace me 57 | /*}*/ 58 | } 59 | 60 | // Philosopher with index philosopherIndex releases both chopsticks 61 | ghost predicate ReleaseBoth(c:Constants, v:Variables, v':Variables, philosopherIndex:nat) { 62 | /*{*/ 63 | true // Replace me 64 | /*}*/ 65 | } 66 | 67 | datatype Step = 68 | /*{*/ 69 | Step() // Replace me 70 | /*}*/ 71 | 72 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 73 | match step 74 | /*{*/ 75 | case Step => false // Replace me 76 | /*}*/ 77 | } 78 | 79 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 80 | exists step :: NextStep(c, v, v', step) 81 | } 82 | 83 | // This predicate should be true if and only if no philosopher holds a 84 | // chopstick. 85 | // Since you defined the Variables state, you must define this predicate in 86 | // those terms. Avoid using existential quantifiers. 87 | ghost predicate NoSticksAcquired(c:Constants, v: Variables) 88 | requires v.WellFormed(c) 89 | { 90 | /*{*/ 91 | true 92 | /*}*/ 93 | } 94 | 95 | // Change this predicate to be true if and only if philosopher 96 | // `philosopherIndex` holds both of their chopsticks. 97 | // Since you defined the Variables state, you must define this predicate in 98 | // those terms. Avoid using existential quantifiers. 99 | ghost predicate BothSticksAcquired(c:Constants, v: Variables, philosopherIndex: nat) 100 | requires philosopherIndex < c.tableSize 101 | requires v.WellFormed(c) 102 | { 103 | /*{*/ 104 | true 105 | /*}*/ 106 | } 107 | 108 | // Show that, in the Init state, no philosopher has chopsticks. 109 | lemma InitProperty(c:Constants, v: Variables, philosopherIndex:nat) 110 | requires Init(c, v) 111 | ensures NoSticksAcquired(c, v) 112 | { 113 | /*{*/ 114 | /*}*/ 115 | } 116 | 117 | 118 | // Show a behavior that evolves from the init state to one where a philosopher 119 | // has completed acquiring both chopsticks. 120 | lemma PseudoLiveness(c:Constants, philosopherIndex:nat) returns (behavior:seq) 121 | requires c.tableSize == 3 122 | requires philosopherIndex == 1 123 | ensures 0 < |behavior| // precondition for index operators below 124 | ensures forall i | 0 <= i < |behavior|-1 :: Next(c, behavior[i], behavior[i+1]) // Behavior satisfies your state machine 125 | ensures behavior[0].WellFormed(c) // precondition for calling NoSticksAcquired 126 | ensures Init(c, behavior[0]) 127 | ensures behavior[|behavior|-1].WellFormed(c) // precondition for calling BothSticksAcquired 128 | ensures BothSticksAcquired(c, behavior[|behavior|-1], philosopherIndex) // Behavior ultimately achieves acquisition for philosopherIndex 129 | { 130 | /*{*/ 131 | /*}*/ 132 | } 133 | -------------------------------------------------------------------------------- /fall2024/chapter03-state-machines/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Single-Server Lock Service Model 2 | //#desc A complex state machine 3 | //#desc including a Safety predicate on the state type. 4 | 5 | // Model a lock service that consists of a single server and an 6 | // arbitrary number of clients. 7 | // 8 | // The state of the system includes the server's state (whether the server 9 | // knows that some client holds the lock, and if so which one) 10 | // and the clients' states (for each client, whether that client knows 11 | // it holds the lock). 12 | // 13 | // The system should begin with the server holding the lock. 14 | // An acquire step atomically transfers the lock from the server to some client. 15 | // (Note that we're not modeling the network yet -- the lock disappears from 16 | // the server and appears at a client in a single atomic transition.) 17 | // A release step atomically transfers the lock from the client back to the server. 18 | // 19 | // The safety property is that no two clients ever hold the lock 20 | // simultaneously. 21 | 22 | datatype Constants = Constants( 23 | /*{*/ // You define this ... 24 | /*}*/ 25 | ) { 26 | ghost predicate WellFormed() { true } 27 | /*{*/ 28 | /*}*/ 29 | } 30 | 31 | /*{*/ 32 | /*}*/ 33 | 34 | datatype Variables = Variables( 35 | /*{*/ // You define this ... 36 | /*}*/ 37 | ) { 38 | ghost predicate WellFormed(c: Constants) { 39 | /*{*/ 40 | true 41 | /*}*/ 42 | } 43 | } 44 | 45 | ghost predicate Init(c:Constants, v:Variables) { 46 | && v.WellFormed(c) 47 | /*{*/ 48 | && true // Replace me 49 | /*}*/ 50 | } 51 | 52 | /*{*/ 53 | /*}*/ 54 | // Jay-Normal-Form: pack all the nondeterminism into a single object 55 | // that gets there-exist-ed once. 56 | datatype Step = 57 | /*{*/ 58 | | SomeStep(somearg: int) // Replace me 59 | /*}*/ 60 | 61 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 62 | match step 63 | /*{*/ 64 | case SomeStep(somearg) => false // Replace me 65 | /*}*/ 66 | } 67 | 68 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 69 | exists step :: NextStep(c, v, v', step) 70 | } 71 | 72 | // A good definition of safety for the lock server is that no two clients 73 | // may hold the lock simultaneously. This predicate should capture that 74 | // idea in terms of the Variables you have defined. 75 | ghost predicate Safety(c:Constants, v:Variables) { 76 | /*{*/ 77 | false // Replace me 78 | /*}*/ 79 | } 80 | 81 | 82 | // This predicate should be true if and only if the client with index `clientIndex` 83 | // has the lock acquired. 84 | // Since you defined the Variables state, you must define this predicate in 85 | // those terms. 86 | ghost predicate ClientHoldsLock(c: Constants, v: Variables, clientIndex: nat) 87 | requires v.WellFormed(c) 88 | { 89 | /*{*/ 90 | false // Replace me 91 | /*}*/ 92 | } 93 | 94 | // Show a behavior that the system can release a lock from clientA and deliver 95 | // it to clientB. 96 | lemma PseudoLiveness(clientA:nat, clientB:nat) returns (c: Constants, behavior:seq) 97 | requires clientA == 2 98 | requires clientB == 0 99 | ensures 0 < |behavior| // precondition for index operators below 100 | ensures forall i | 0 <= i < |behavior|-1 :: Next(c, behavior[i], behavior[i+1]) // Behavior satisfies your state machine 101 | ensures forall i | 0 <= i < |behavior| :: Safety(c, behavior[i]) // Behavior always satisfies the Safety predicate 102 | ensures behavior[0].WellFormed(c) // precondition for calling ClientHoldsLock 103 | ensures ClientHoldsLock(c, behavior[0], clientA) 104 | ensures behavior[|behavior|-1].WellFormed(c) // precondition for calling ClientHoldsLock 105 | ensures ClientHoldsLock(c, behavior[|behavior|-1], clientB) 106 | { 107 | /*{*/ 108 | /*}*/ 109 | } 110 | 111 | -------------------------------------------------------------------------------- /fall2024/chapter04-invariants/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Crawler 2 | //#desc Introduction to inductive invariants 3 | //#desc -- implement the visualization from the lecture. 4 | 5 | module Crawler { 6 | //datatype Constants = Constants() 7 | datatype Variables = Variables(x:int, y:int) 8 | 9 | ghost predicate Init(v:Variables) { 10 | && v.x == 0 11 | && v.y == 5 12 | } 13 | 14 | ghost predicate MoveNorth(v:Variables, v':Variables) { 15 | && v'.x == v.x 16 | && v'.y == v.y + 1 17 | } 18 | 19 | ghost predicate MoveSouthEast(v:Variables, v':Variables) { 20 | && v'.x == v.x + 1 21 | && v'.y == v.y - 1 22 | } 23 | 24 | ghost predicate Next(v:Variables, v':Variables) { 25 | || MoveNorth(v, v') 26 | || MoveSouthEast(v, v') 27 | } 28 | 29 | ghost predicate InHole(v:Variables) { 30 | v.x*v.x + v.y*v.y <= 3*3 31 | } 32 | 33 | ghost predicate Safety(v:Variables) { 34 | !InHole(v) 35 | } 36 | 37 | ghost predicate Inv(v:Variables) { 38 | /*{*/ 39 | true // probably not strong enough. :v) 40 | /*}*/ 41 | } 42 | 43 | // Here's your proof obligation that Safety predicate holds in every behavior 44 | // allowed by the state machine. 45 | // With the correct invariant, this proof goes through without a body. 46 | lemma SafetyTheorem(v:Variables, v':Variables) 47 | ensures Init(v) ==> Inv(v) 48 | ensures Inv(v) && Next(v, v') ==> Inv(v') 49 | ensures Inv(v) ==> Safety(v) 50 | { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /fall2024/chapter04-invariants/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Single-Server Lock Service Proof 2 | //#desc A more realistic invariant proof of the previous chapter's lock 3 | //#desc service. 4 | 5 | // Copy your solution for chapter03/exercise03 into the current directory with 6 | // this name: 7 | include "chapter03-exercise03.dfy" 8 | //#extract ../../chapter03-state-machines/exercises/exercise03.template solution chapter03-exercise03.dfy 9 | 10 | 11 | /*{*/ 12 | /*}*/ 13 | ghost predicate Inv(c:Constants, v:Variables) { 14 | /*{*/ 15 | true // Replace me: probably not strong enough. :v) 16 | /*}*/ 17 | } 18 | 19 | // Here's your obligation. Probably easiest to break this up into three 20 | // lemmas, each P==>Q becomes requires P ensures Q. 21 | lemma SafetyTheorem(c:Constants, v:Variables, v':Variables) 22 | ensures Init(c, v) ==> Inv(c, v) 23 | ensures Inv(c, v) && Next(c, v, v') ==> Inv(c, v') 24 | ensures Inv(c, v) ==> Safety(c, v) 25 | { 26 | /*{*/ 27 | /*}*/ 28 | } 29 | -------------------------------------------------------------------------------- /fall2024/chapter04-invariants/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Crawler quadrants 2 | //#desc Introduction to inductive invariants 3 | //#desc A more advanced crawler state machine 4 | 5 | // You are asked to write the state machine, safety property and inductive invariant 6 | // for the following crawler, which moves through the X-Y Cartesian space. 7 | // The crawler can take three types of actions: it can move one step in its current 8 | // vertical direction; it can move one step in its current horizontal direction; or 9 | // it can warp. A horizontal warp would take it to a position that mirrors its current 10 | // position on the Y-axis (e.g. (1,5) would go to (-1,5)), while also flipping its 11 | // horizontal direction (i.e. from left to right or vice versa). Similarly, a vertical 12 | // warp would take it to a position that mirrors its current position on the X-axis 13 | // (e.g. (1,5) would go to (1,-5)), while also flipping its vertical direction (i.e. 14 | // from up to down or vice versa). 15 | 16 | // The crawler starts in position (5,5) and with a horizontal direction of "right" and 17 | // a vertical direction of "up". 18 | 19 | // The desired safety property is that the crawler should always be at least 5 points 20 | // away from both axes. 21 | 22 | /*{*/ 23 | // Editable space, in case you need any definitions 24 | /*}*/ 25 | 26 | datatype Variables = Variables( 27 | /*{*/ 28 | /*}*/ 29 | ) 30 | 31 | ghost predicate Init(v: Variables) { 32 | /*{*/ 33 | true // Replace me 34 | /*}*/ 35 | } 36 | 37 | // Define your actions here 38 | 39 | /*{*/ 40 | /*}*/ 41 | 42 | ghost predicate Next(v: Variables, v': Variables) { 43 | /*{*/ 44 | true // Replace me 45 | /*}*/ 46 | } 47 | 48 | /*{*/ 49 | // Editable space, in case you need any definitions 50 | /*}*/ 51 | 52 | ghost predicate Safety(v: Variables) { 53 | /*{*/ 54 | false // Replace me 55 | /*}*/ 56 | } 57 | 58 | ghost predicate Inv(v: Variables) { 59 | /*{*/ 60 | true // Probably not strong enough! 61 | /*}*/ 62 | } 63 | 64 | lemma InvImpliesSafety(v: Variables) 65 | requires Inv(v) 66 | ensures Safety(v) 67 | { 68 | /*{*/ 69 | /*}*/ 70 | } 71 | 72 | lemma InitImpliesInv(v: Variables) 73 | requires Init(v) 74 | ensures Inv(v) 75 | { 76 | /*{*/ 77 | /*}*/ 78 | } 79 | 80 | lemma NextPreservesInv(v: Variables, v': Variables) 81 | requires Inv(v) 82 | requires Next(v, v') 83 | ensures Inv(v') 84 | { 85 | /*{*/ 86 | /*}*/ 87 | } 88 | 89 | -------------------------------------------------------------------------------- /fall2024/chapter05-distributed-state-machines/exercises/CommitTypes.dfy: -------------------------------------------------------------------------------- 1 | 2 | module CommitTypes { 3 | // How a particular participant feels. 4 | datatype Vote = Yes | No 5 | // What decision has been reached by the protocol. 6 | datatype Decision = Commit | Abort 7 | } 8 | 9 | -------------------------------------------------------------------------------- /fall2024/chapter05-distributed-state-machines/exercises/exercise02.dfy: -------------------------------------------------------------------------------- 1 | //#title Two Phase Commit Safety Specification Predicate 2 | //#desc Express the English Atomic Commit safety properties as predicates 3 | //#desc over the compound state machine model from exercise01. 4 | 5 | // 2PC should satisfy the Atomic Commit specification. English design doc: 6 | // 7 | // AC-1: All processes that reach a decision reach the same one. 8 | // AC-3: The Commit decision can only be reached if all processes prefer Yes. 9 | // AC-4: If all processes prefer Yes, then the decision must be Commit. 10 | // 11 | // Note that the full Atomic Commit spec includes these additional properties, 12 | // but you should ignore them for this exercise: 13 | // AC-2: (stability) A process cannot reverse its decision after it has reached one. 14 | // (best modeled with refinement) 15 | // AC-5: (liveness) All processes eventually decide. 16 | 17 | // Note that we include the model of exercise01, so you should write your 18 | // spec accordingly. Of course, that also means double-checking that your 19 | // model performs all actions as described. 20 | include "exercise01.dfy" 21 | //#extract exercise01.template solution exercise01.dfy 22 | 23 | module Obligations { 24 | import opened CommitTypes 25 | import opened Types 26 | import opened UtilitiesLibrary 27 | import opened DistributedSystem 28 | 29 | /*{*/ 30 | /*}*/ 31 | 32 | // AC-1: All processes that reach a decision reach the same one. 33 | ghost predicate SafetyAC1(c: Constants, v: Variables) 34 | requires v.WF(c) 35 | { 36 | // All hosts that reach a decision reach the same one 37 | /*{*/ 38 | true // Replace me 39 | /*}*/ 40 | } 41 | 42 | // AC2 is sort of a history predicate; we're going to ignore it. 43 | 44 | // AC-3: The Commit decision can only be reached if all processes prefer Yes. 45 | ghost predicate SafetyAC3(c: Constants, v: Variables) 46 | requires v.WF(c) 47 | { 48 | /*{*/ 49 | true // Replace me 50 | /*}*/ 51 | } 52 | 53 | // AC-4: If all processes prefer Yes, then the decision must be Commit. 54 | ghost predicate SafetyAC4(c: Constants, v: Variables) 55 | requires v.WF(c) 56 | { 57 | /*{*/ 58 | true // Replace me 59 | /*}*/ 60 | } 61 | 62 | // AC5 is a liveness proprety, we're definitely going to ignore it. 63 | 64 | ghost predicate Safety(c: Constants, v: Variables) 65 | requires v.WF(c) 66 | { 67 | && SafetyAC1(c, v) 68 | && SafetyAC3(c, v) 69 | && SafetyAC4(c, v) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /fall2024/chapter05-distributed-state-machines/exercises/exercise03.dfy: -------------------------------------------------------------------------------- 1 | //#title Two Phase Commit Safety Proof 2 | //#desc Prove that the 2PC distributed system (from exercise01) accomplishes the Safety spec (from exercise02) 3 | 4 | include "exercise02.dfy" 5 | //#extract exercise02.template solution exercise02.dfy 6 | 7 | module TwoPCInvariantProof { 8 | import opened CommitTypes 9 | import opened Types 10 | import opened UtilitiesLibrary 11 | import opened DistributedSystem 12 | import opened Obligations 13 | 14 | /*{*/ 15 | /*}*/ 16 | // This is a conjunct of the inductive invariant, indicating that the messages carrying 17 | // decisions should reflect the votes of the participants as relayed to the coordinator 18 | ghost predicate DecisionMsgsAgreeWithDecision(c: Constants, v: Variables) 19 | requires v.WF(c) 20 | { 21 | /*{*/ 22 | true // Replace me 23 | /*}*/ 24 | } 25 | 26 | ghost predicate Inv(c: Constants, v: Variables) 27 | { 28 | && v.WF(c) 29 | /*{*/ 30 | /*}*/ 31 | // We give you the blueprint for one invariant to get you started... 32 | && DecisionMsgsAgreeWithDecision(c, v) 33 | // ...but you'll need more. 34 | && Safety(c, v) 35 | } 36 | 37 | lemma InitImpliesInv(c: Constants, v: Variables) 38 | requires Init(c, v) 39 | ensures Inv(c, v) 40 | { 41 | /*{*/ 42 | /*}*/ 43 | } 44 | 45 | lemma InvInductive(c: Constants, v: Variables, v': Variables) 46 | requires Inv(c, v) 47 | requires Next(c, v, v') 48 | ensures Inv(c, v') 49 | { 50 | /*{*/ 51 | /*}*/ 52 | } 53 | 54 | lemma InvImpliesSafety(c: Constants, v: Variables) 55 | requires Inv(c, v) 56 | ensures Safety(c, v) 57 | { // Trivial, as usual, since safety is a conjunct in Inv. 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /fall2024/chapter06-refinement/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /fall2024/chapter07-async-clients/exercises/UtilitiesLibrary.dfy: -------------------------------------------------------------------------------- 1 | module UtilitiesLibrary { 2 | function DropLast(theSeq: seq) : seq 3 | requires 0 < |theSeq| 4 | { 5 | theSeq[..|theSeq|-1] 6 | } 7 | 8 | function Last(theSeq: seq) : T 9 | requires 0 < |theSeq| 10 | { 11 | theSeq[|theSeq|-1] 12 | } 13 | 14 | function UnionSeqOfSets(theSets: seq>) : set 15 | { 16 | if |theSets| == 0 then {} else 17 | UnionSeqOfSets(DropLast(theSets)) + Last(theSets) 18 | } 19 | 20 | // As you can see, Dafny's recursion heuristics easily complete the recursion 21 | // induction proofs, so these two statements could easily be ensures of 22 | // UnionSeqOfSets. However, the quantifiers combine with native map axioms 23 | // to be a bit trigger-happy, so we've pulled them into independent lemmas 24 | // you can invoke only when needed. 25 | // Suggestion: hide calls to this lemma in a an 26 | // assert P by { SetsAreSubsetsOfUnion(...) } 27 | // construct so you can get your conclusion without "polluting" the rest of the 28 | // lemma proof context with this enthusiastic forall. 29 | lemma SetsAreSubsetsOfUnion(theSets: seq>) 30 | ensures forall idx | 0<=idx<|theSets| :: theSets[idx] <= UnionSeqOfSets(theSets) 31 | { 32 | } 33 | 34 | lemma EachUnionMemberBelongsToASet(theSets: seq>) 35 | ensures forall member | member in UnionSeqOfSets(theSets) :: 36 | exists idx :: 0<=idx<|theSets| && member in theSets[idx] 37 | { 38 | } 39 | 40 | // Convenience function for learning a particular index (invoking Hilbert's 41 | // Choose on the exists in EachUnionMemberBelongsToASet). 42 | lemma GetIndexForMember(theSets: seq>, member: T) returns (idx:int) 43 | requires member in UnionSeqOfSets(theSets) 44 | ensures 0<=idx<|theSets| 45 | ensures member in theSets[idx] 46 | { 47 | EachUnionMemberBelongsToASet(theSets); 48 | var chosenIdx :| 0<=chosenIdx<|theSets| && member in theSets[chosenIdx]; 49 | idx := chosenIdx; 50 | } 51 | 52 | datatype Option = Some(value:T) | None 53 | 54 | function {:opaque} MapRemoveOne(m:map, key:K) : (m':map) 55 | ensures forall k :: k in m && k != key ==> k in m' 56 | ensures forall k :: k in m' ==> k in m && k != key 57 | ensures forall j :: j in m' ==> m'[j] == m[j] 58 | ensures |m'.Keys| <= |m.Keys| 59 | ensures |m'| <= |m| 60 | { 61 | var m':= map j | j in m && j != key :: m[j]; 62 | assert m'.Keys == m.Keys - {key}; 63 | m' 64 | } 65 | 66 | ////////////// Library code for exercises 12 and 14 ///////////////////// 67 | 68 | // This is tagged union, a "sum" datatype. 69 | datatype Direction = North() | East() | South() | West() 70 | 71 | function TurnRight(direction:Direction) : Direction 72 | { 73 | // This function introduces two new bis of syntax. 74 | // First, the if-else expression: if then T else T 75 | // Second, the element.Ctor? built-in predicate, which tests whether 76 | // the datatype `element` was built by `Ctor`. 77 | if direction.North? 78 | then East 79 | else if direction.East? 80 | then South 81 | else if direction.South? 82 | then West 83 | else // By elimination, West! 84 | North 85 | } 86 | 87 | lemma Rotation() 88 | { 89 | assert TurnRight(North) == East; 90 | } 91 | 92 | function TurnLeft(direction:Direction) : Direction 93 | { 94 | // Another nice way to take apart a datatype element is with match-case 95 | // construct. Each case argument is a constructor; each body must be of the 96 | // same type, which is the type of the entire `match` expression. 97 | match direction { 98 | case North => West 99 | case West => South 100 | case South => East // Try changing "East" to 7. 101 | case East => North 102 | } 103 | } 104 | 105 | ////////////// Library code for exercises 13 and 14 ///////////////////// 106 | 107 | // This whole product-sum idea gets clearer when we use both powers 108 | // (struct/product, union/sum) at the same time. 109 | 110 | datatype Meat = Salami | Ham 111 | datatype Cheese = Provolone | Swiss | Cheddar | Jack 112 | datatype Veggie = Olive | Onion | Pepper 113 | datatype Order = 114 | Sandwich(meat:Meat, cheese:Cheese) 115 | | Pizza(meat:Meat, veggie:Veggie) 116 | | Appetizer(cheese:Cheese) 117 | 118 | // There are 2 Meats, 4 Cheeses, and 3 Veggies. 119 | // Thus there are 8 Sandwiches, 6 Pizzas, and 4 Appetizers. 120 | // Thus there are 8+6+4 = 18 Orders. 121 | // This is why they're called "algebraic" datatypes. 122 | 123 | } 124 | -------------------------------------------------------------------------------- /fall2024/lectures/lecture1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture1-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture1-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture1-9.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture1.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture1.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture1.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture10-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture10-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture10-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture10-6.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture10.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture10.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture10.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture11-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture11-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture11.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture11.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture11.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture12-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture12-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture12.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture12.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture12.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture13-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture13-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture13-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture13-7.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture13.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture13.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture13.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture13.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture14-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture14-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture14.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture14.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture14.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture14.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture15-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture15-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture15.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture15.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture15.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture15.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture16-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture16-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture16-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture16-6.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture16.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture16.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture16.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture16.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture17-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture17-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture17-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture17-5.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture17.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture17.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture17.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture17.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture18-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture18-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture18-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture18-3.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture18.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture18.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture18.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture18.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture19-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture19-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture19-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture19-5.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture19.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture19.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture19.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture19.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture2-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture2-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture2-4.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture2.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture2.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture20-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture20-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture20-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture20-6.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture20.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture20.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture20.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture20.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture3-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture3.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture3.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture3.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture4-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture4-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture4.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture4.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture4.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture5-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture5-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture5-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture5-4.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture5.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture5.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture5.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture6-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture6-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture6.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture6.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture6.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture7-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture7-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture7-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture7-4.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture7.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture7.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture7.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture8-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture8-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture8-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture8-4.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture8.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture8.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture8.pptx -------------------------------------------------------------------------------- /fall2024/lectures/lecture9-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture9-2.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture9-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture9-6.png -------------------------------------------------------------------------------- /fall2024/lectures/lecture9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture9.pdf -------------------------------------------------------------------------------- /fall2024/lectures/lecture9.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GLaDOS-Michigan/verification-class/4f337c2ebe1549519850cee178b7b56418d2a266/fall2024/lectures/lecture9.pptx -------------------------------------------------------------------------------- /fall2024/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Open Sans, Arial; 3 | color: #454545; 4 | font-size: 16px; 5 | margin: 2em auto; 6 | max-width: 800px; 7 | padding: 1em; 8 | line-height: 1.4; 9 | text-align: justify; 10 | } 11 | 12 | h1, 13 | h2, 14 | h3 { 15 | text-align: left; 16 | } 17 | 18 | .lec-preview { 19 | display: inline-block; 20 | border: 2px solid black; 21 | width: 300px; 22 | height: 180px; 23 | margin: auto; 24 | } 25 | 26 | .li-none { 27 | list-style-type: none; 28 | } 29 | -------------------------------------------------------------------------------- /fall2024/project01-distributed-lock-server/exercises/distributed_system.t.dfy: -------------------------------------------------------------------------------- 1 | //#title DistributedSystem 2 | //#desc This file isn't editable because it's a trusted file that specifies how 3 | //#desc hosts interact with one another over the network. 4 | 5 | include "host.v.dfy" 6 | //#extract host.v.template solution host.v.dfy 7 | 8 | // Before we get here, caller must define a type Message that we'll 9 | // use to instantiate network.s.dfy. 10 | 11 | module DistributedSystem { 12 | import opened HostIdentifiers 13 | import Host 14 | import Network 15 | 16 | datatype Constants = Constants( 17 | hosts:seq, 18 | network:Network.Constants) { 19 | ghost predicate WF() { 20 | // Network numHosts and each host's numHosts agree with the size of our 21 | // own host list 22 | && network.Configure(|hosts|) 23 | && (forall id | ValidHostId(id) :: hosts[id].Configure(|hosts|, id)) // every host knows its id (and ids are unique) 24 | } 25 | 26 | ghost predicate ValidHostId(hostid: HostId) { 27 | HostIdentifiers.ValidHostId(|hosts|, hostid) 28 | } 29 | } 30 | 31 | datatype Variables = Variables( 32 | hosts:seq, 33 | network:Network.Variables) { 34 | ghost predicate WF(c: Constants) { 35 | && c.WF() 36 | && |hosts| == |c.hosts| 37 | } 38 | } 39 | 40 | ghost predicate Init(c:Constants, v:Variables) { 41 | && v.WF(c) 42 | && (forall id | c.ValidHostId(id) :: Host.Init(c.hosts[id], v.hosts[id])) 43 | && Network.Init(c.network, v.network) 44 | } 45 | 46 | // JayNF 47 | datatype Step = Step(id:HostId, msgOps: Network.MessageOps) 48 | 49 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, step: Step) { 50 | && v.WF(c) 51 | && v'.WF(c) 52 | && c.ValidHostId(step.id) 53 | && Host.Next(c.hosts[step.id], v.hosts[step.id], v'.hosts[step.id], step.msgOps) 54 | && (forall other | c.ValidHostId(other) && other != step.id :: v'.hosts[other] == v.hosts[other]) 55 | && Network.Next(c.network, v.network, v'.network, step.msgOps) 56 | } 57 | 58 | ghost predicate Next(c:Constants, v:Variables, v':Variables) { 59 | exists step :: NextStep(c, v, v', step) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fall2024/project01-distributed-lock-server/exercises/exercise01.dfy: -------------------------------------------------------------------------------- 1 | //#title Midterm Project 2 | //#desc Build a distributed lock server. Define how a host implements your 3 | //#desc protocol in host.v.dfy; write your safety spec and proof here. 4 | 5 | // This challenge differs from LockServer (from chapters 03 and 04) in two 6 | // ways. First, there is no central server that coordinates the activity. 7 | // Second, the hosts can communicate only via asynchronous messages; a single 8 | // state machine transition cannot simultaneously read or update the state of 9 | // two hosts. 10 | // 11 | // To guard against duplicate messages, the nodes associate a monotonically 12 | // increasing epoch number with the lock. Initially, node 0 holds the lock and 13 | // its epoch number is 1, while all other nodes with an epoch of 0 (and not 14 | // holding the lock). A node that holds the lock can “grant” it to another 15 | // node by sending them a “Grant” message which has an epoch number that is 16 | // greater than the node's epoch number. A node that receives such a message 17 | // will become the new holder and will set its epoch number to the message’s 18 | // epoch number. 19 | 20 | // You'll first need to modify 'host.v.dfy' to define the protocol message 21 | // format and the host behavior. 22 | // Then come back here to define the safety condition and prove that the 23 | // distributed system made from that protocol maintains it. 24 | 25 | include "distributed_system.t.dfy" 26 | //#extract distributed_system.t.template solution distributed_system.t.dfy 27 | 28 | module SafetySpec { 29 | import opened HostIdentifiers 30 | import DistributedSystem 31 | 32 | // Define this predicate to be true if idx is a valid host ID and that host's 33 | // Variables indicates that it holds the lock. 34 | ghost predicate HostHoldsLock(c:DistributedSystem.Constants, v:DistributedSystem.Variables, idx: int) { 35 | && v.WF(c) 36 | /*{*/ 37 | && false 38 | /*}*/ 39 | } 40 | 41 | // No two hosts think they hold the lock simultaneously. 42 | ghost predicate Safety(c:DistributedSystem.Constants, v:DistributedSystem.Variables) { 43 | /*{*/ 44 | true // Replace this placeholder with an appropriate safety condition 45 | /*}*/ 46 | } 47 | } 48 | 49 | module Proof { 50 | import opened HostIdentifiers 51 | import Host 52 | import opened DistributedSystem 53 | import opened SafetySpec 54 | 55 | // Here's a predicate that will be very useful in constructing invariant conjuncts. 56 | ghost predicate InFlight(c:Constants, v:Variables, message:Host.Message) { 57 | && v.WF(c) 58 | && message in v.network.sentMsgs 59 | /*{*/ 60 | && false // ...and then add a check that the message's epoch is still valid. 61 | /*}*/ 62 | } 63 | 64 | /*{*/ 65 | /*}*/ 66 | 67 | ghost predicate Inv(c: Constants, v:Variables) { 68 | /*{*/ 69 | false // Replace this placeholder with an invariant that's inductive and supports Safety. 70 | /*}*/ 71 | } 72 | 73 | lemma SafetyProof(c: Constants, v:Variables, v':Variables) 74 | ensures Init(c, v) ==> Inv(c, v) 75 | ensures Inv(c, v) && Next(c, v, v') ==> Inv(c, v') 76 | ensures Inv(c, v) ==> Safety(c, v) 77 | { 78 | // Develop any necessary proof here. 79 | /*{*/ 80 | /*}*/ 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /fall2024/project01-distributed-lock-server/exercises/host.v.dfy: -------------------------------------------------------------------------------- 1 | //#title Host protocol 2 | //#desc Define the host state machine here: message type, state machine for executing one 3 | //#desc host's part of the protocol. 4 | 5 | // See exercise01.dfy for an English design of the protocol. 6 | 7 | include "network.t.dfy" 8 | //#extract network.t.template solution network.t.dfy 9 | 10 | module Host { 11 | import opened UtilitiesLibrary 12 | import opened HostIdentifiers 13 | import Network 14 | 15 | // Define your Message datatype here. 16 | datatype Message = 17 | /*{*/ 18 | Message() // Populate this datatype. 19 | /*}*/ 20 | 21 | // Define your Host protocol state machine here. 22 | datatype Constants = Constants(numHosts: nat, myId:HostId) { 23 | // host constants coupled to DistributedSystem Constants: 24 | // DistributedSystem tells us our id so we can recognize inbound messages. 25 | ghost predicate Configure(numHosts: nat, id:HostId) { 26 | && this.numHosts == numHosts 27 | && this.myId == id 28 | } 29 | } 30 | 31 | datatype Variables = Variables( 32 | /*{*/ 33 | // Fill me in. 34 | /*}*/ 35 | ) 36 | 37 | ghost predicate Init(c:Constants, v:Variables) { 38 | /*{*/ 39 | true // Replace me 40 | /*}*/ 41 | } 42 | 43 | /*{*/ 44 | /*}*/ 45 | // JayNF 46 | datatype Step = 47 | /*{*/ 48 | | SomeStep // Replace me 49 | /*}*/ 50 | 51 | ghost predicate NextStep(c:Constants, v:Variables, v':Variables, msgOps:Network.MessageOps, step: Step) { 52 | match step 53 | /*{*/ 54 | case SomeStep => true 55 | /*}*/ 56 | } 57 | 58 | ghost predicate Next(c:Constants, v:Variables, v':Variables, msgOps:Network.MessageOps) { 59 | exists step :: NextStep(c, v, v', msgOps, step) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fall2024/project01-distributed-lock-server/exercises/network.t.dfy: -------------------------------------------------------------------------------- 1 | //#title Network 2 | //#desc This file isn't editable because it's a trusted file that specifies how 3 | //#desc the network delivers packets, allowing reorder and duplicate delivery. 4 | 5 | include "UtilitiesLibrary.dfy" 6 | 7 | module HostIdentifiers { 8 | type HostId = int // Pretty type synonym (a la C typedef) 9 | 10 | ghost predicate ValidHostId(numHosts: nat, hostid: HostId) { 11 | 0 <= hostid < numHosts 12 | } 13 | 14 | // The set of all host identities. 15 | ghost function AllHosts(numHosts: nat) : set { 16 | set hostid:HostId | 17 | && 0 <= hostid < numHosts // This line is entirely redundant, but it satisfies Dafny's finite-set heuristic; see chapter01 exercise15 18 | && ValidHostId(numHosts, hostid) 19 | } 20 | } 21 | 22 | // This version of Network uses a template parameter to avoid having to declare 23 | // the Message type before the Network module. (Contrast with ch05/ex02.) 24 | module Network { 25 | import opened UtilitiesLibrary 26 | 27 | // A MessageOps is a "binding variable" used to connect a Host's Next step 28 | // (what message got received, what got sent?) with the Network (only allow 29 | // receipt of messages sent prior; record newly-sent messages). 30 | // Note that both fields are Option. A step predicate can say recv.None? 31 | // to indicate that it doesn't need to receive a message to occur. 32 | // It can say send.None? to indicate that it doesn't want to transmit a message. 33 | datatype MessageOps = MessageOps(recv:Option, send:Option) 34 | 35 | datatype Constants = Constants(numHosts: nat) 36 | { 37 | ghost predicate Configure(numHosts: nat) { 38 | this.numHosts == numHosts 39 | } 40 | } 41 | 42 | // Network state is the set of messages ever sent. Once sent, we'll 43 | // allow it to be delivered over and over. 44 | // (We don't have packet headers, so duplication, besides being realistic, 45 | // also doubles as how multiple parties can hear the message.) 46 | datatype Variables = Variables(sentMsgs:set) 47 | 48 | ghost predicate Init(c: Constants, v: Variables) 49 | { 50 | && v.sentMsgs == {} 51 | } 52 | 53 | ghost predicate Next(c: Constants, v: Variables, v': Variables, msgOps: MessageOps) 54 | { 55 | // Only allow receipt of a message if we've seen it has been sent. 56 | && (msgOps.recv.Some? ==> msgOps.recv.value in v.sentMsgs) 57 | // Record the sent message, if there was one. 58 | && v'.sentMsgs == 59 | v.sentMsgs + if msgOps.send.None? then {} else { msgOps.send.value } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/AtomicKVSpec.t.dfy: -------------------------------------------------------------------------------- 1 | include "IMapHelpers.t.dfy" 2 | include "Types.t.dfy" 3 | //#extract Types.t.template inherit Types.t.dfy 4 | 5 | // The application spec for this system is a key-value store 6 | // that maintains a map of int keys to int values. 7 | // The type of the state in this state machine is simply a total imap: one in 8 | // which every possible key is in the domain. 9 | // The user-visible actions are Get and Put operations. 10 | // Get accepts a key and returns a value. 11 | // Put accepts a key and a value and returns nothing. 12 | // 13 | // You should write a synchronous spec that produces the world-visible 14 | // events defined in Types.t.dfy: Get and Put (plus NoOp). 15 | 16 | module AtomicKVSpec { 17 | import opened IMapHelpers 18 | import opened Types 19 | 20 | datatype Constants = Constants() // don't need any here 21 | datatype Variables = Variables( 22 | /*{*/ 23 | // define me 24 | /*}*/ 25 | ) 26 | 27 | // The initial map should assign the value zero to every key. 28 | // Be sure to check out IMapHelpers.t.dfy. It's helpful. 29 | ghost predicate Init(c: Constants, v: Variables) { 30 | /*{*/ 31 | && true // define me 32 | /*}*/ 33 | } 34 | 35 | /*{*/ 36 | /*}*/ 37 | 38 | ghost predicate NextStep(c: Constants, v: Variables, v': Variables, event: Event) { 39 | /*{*/ 40 | true // Replace me 41 | /*}*/ 42 | } 43 | 44 | ghost predicate Next(c: Constants, v: Variables, v': Variables, event: Event) { 45 | // All the nondeterminism is encoded in `event`! No `exists` required. 46 | NextStep(c, v, v', event) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/DistributedSystem.t.dfy: -------------------------------------------------------------------------------- 1 | include "Network.t.dfy" 2 | //#extract Network.t.template inherit Network.t.dfy 3 | include "Host.v.dfy" 4 | //#extract Host.v.template inherit Host.v.dfy 5 | 6 | module DistributedSystem { 7 | import opened UtilitiesLibrary 8 | import opened Types 9 | import Network 10 | import Host 11 | 12 | type HostId = Network.HostId 13 | 14 | /*{*/ 15 | datatype Constants = Constants() 16 | { 17 | ghost predicate WF() { 18 | && true 19 | } 20 | } 21 | datatype Variables = Variables() 22 | { 23 | ghost predicate WF(c: Constants) { 24 | && true 25 | } 26 | } 27 | 28 | ghost predicate Init(c: Constants, v: Variables) 29 | { 30 | && true // define me 31 | } 32 | 33 | ghost predicate Next(c: Constants, v: Variables, v': Variables, event: Event) 34 | { 35 | && true // define me 36 | } 37 | /*}*/ 38 | } 39 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/Host.v.dfy: -------------------------------------------------------------------------------- 1 | include "UtilitiesLibrary.t.dfy" 2 | include "IMapHelpers.t.dfy" 3 | include "Types.t.dfy" 4 | //#extract Types.t.template inherit Types.t.dfy 5 | include "MessageType.v.dfy" 6 | //#extract MessageType.v.template inherit MessageType.v.dfy 7 | include "Network.t.dfy" 8 | //#extract Network.t.template inherit Network.t.dfy 9 | 10 | // 11 | // Your protocol should capture the idea that keys "live" on different hosts 12 | // *and can move around* from host to host. So, in addition to implementing 13 | // client-visible actions as described in AtomicKVSpec, each host should have a way 14 | // to send part of its state to another host, and to receive the corresponding 15 | // message from another sender. (The messages can move a batch of key-value 16 | // pairs, or a single pair at a time; neither is particularly harder than the 17 | // other.) 18 | // 19 | // Obviously, the hosts must be aware of which fraction of the keyspace they 20 | // own at any given time, so that a host doesn't try to service a Get or Put 21 | // request when the "real state" is off at some other host right now. 22 | // 23 | // Initially host 0 should own all the keys. 24 | // 25 | // Don't forget about the helper functions in IMapHelpers.t.dfy. They can be 26 | // quite useful! 27 | 28 | module Host { 29 | import opened UtilitiesLibrary 30 | import opened IMapHelpers 31 | import opened Types 32 | import opened MessageType 33 | import Network 34 | 35 | type HostId = Network.HostId 36 | 37 | /*{*/ 38 | // Replace these definitions with more meaningful ones that capture the operations 39 | // of a key-value store described above. 40 | datatype Constants = Constants() 41 | datatype Variables = Variables() 42 | /*}*/ 43 | } 44 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/IMapHelpers.t.dfy: -------------------------------------------------------------------------------- 1 | module IMapHelpers { 2 | ghost predicate IsKey(k: int) { true } // a useless symbol for dafny to trigger on 3 | 4 | ghost function ZeroMap() : imap 5 | { 6 | imap i | IsKey(i) :: 0 7 | } 8 | 9 | ghost function EmptyMap() : imap 10 | { 11 | imap i | !IsKey(i) :: 0 12 | } 13 | 14 | ghost function MapUnionPreferLeft(a:map, b:map) : map 15 | { 16 | map key | key in a.Keys + b.Keys :: if key in a then a[key] else b[key] 17 | } 18 | 19 | ghost function IMapUnionPreferLeft(a:imap, b:imap) : imap 20 | { 21 | imap key | key in a || key in b :: if key in a then a[key] else b[key] 22 | } 23 | 24 | ghost function MapRemove(table:imap, removeKeys:iset) : imap 25 | requires removeKeys <= table.Keys 26 | { 27 | imap key | key in table && key !in removeKeys :: table[key] 28 | } 29 | 30 | ghost predicate IsFull(m:imap) { 31 | forall i :: i in m 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/MessageType.v.dfy: -------------------------------------------------------------------------------- 1 | module MessageType { 2 | datatype Message = 3 | /*{*/ 4 | | SomeMessage() // Replace me 5 | /*}*/ 6 | } 7 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/Network.t.dfy: -------------------------------------------------------------------------------- 1 | include "UtilitiesLibrary.t.dfy" 2 | include "Types.t.dfy" 3 | //#extract Types.t.template inherit Types.t.dfy 4 | include "MessageType.v.dfy" 5 | //#extract MessageType.v.template inherit MessageType.v.dfy 6 | 7 | module Network { 8 | import opened UtilitiesLibrary 9 | import opened Types 10 | import opened MessageType 11 | 12 | type HostId = nat 13 | 14 | datatype MessageOps = MessageOps(recv: Option, send: Option) 15 | 16 | datatype Constants = Constants // no constants for network 17 | 18 | datatype Variables = Variables(inFlightMessages:set) 19 | 20 | ghost predicate Init(c: Constants, v: Variables) 21 | { 22 | && v.inFlightMessages == {} 23 | } 24 | 25 | ghost predicate Next(c: Constants, v: Variables, v': Variables, msgOps: MessageOps) 26 | { 27 | // Only allow receipt of a message if we've seen it has been sent. 28 | && (msgOps.recv.Some? ==> msgOps.recv.value in v.inFlightMessages) 29 | 30 | ////////////////////////////////////////////////////////////////////////////// 31 | // _ ___ ___ _ __ _ _ _____ ____ _____ 32 | // | | / _ \ / _ \| |/ / | | | | ____| _ \| ____| 33 | // | | | | | | | | | ' / | |_| | _| | |_) | _| 34 | // | |__| |_| | |_| | . \ | _ | |___| _ <| |___ 35 | // |_____\___/ \___/|_|\_\ |_| |_|_____|_| \_\_____| 36 | // 37 | // This is the stronger network model that we used in the moving counter example 38 | // in class. It is a magical network that prevents the host from sending a 39 | // duplicate message until the first copy is delivered! A little 40 | // unrealistic, but it'll make your proof a little 41 | // easier. Read the following comment & conjunct. 42 | // 43 | ////////////////////////////////////////////////////////////////////////////// 44 | 45 | // Only allow sending a message if there isn't a duplicate of that 46 | // message already sent but not yet delivered. 47 | && (msgOps.send.Some? ==> msgOps.send.value !in v.inFlightMessages) 48 | 49 | // Record the sent message, if there was one. 50 | && v'.inFlightMessages == 51 | v.inFlightMessages 52 | // remove a message "used up" by receipt 53 | - (if msgOps.recv.None? then {} else { msgOps.recv.value }) 54 | // add a new message supplied by send 55 | + (if msgOps.send.None? then {} else { msgOps.send.value }) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/RefinementObligation.t.dfy: -------------------------------------------------------------------------------- 1 | include "AtomicKVSpec.t.dfy" 2 | //#extract AtomicKVSpec.t.template inherit AtomicKVSpec.t.dfy 3 | include "DistributedSystem.t.dfy" 4 | //#extract DistributedSystem.t.template inherit DistributedSystem.t.dfy 5 | 6 | abstract module RefinementObligation { 7 | import opened UtilitiesLibrary 8 | import opened Types 9 | import opened DistributedSystem 10 | import AtomicKVSpec 11 | 12 | ghost function ConstantsAbstraction(c: Constants) : AtomicKVSpec.Constants 13 | requires c.WF() 14 | 15 | ghost function VariablesAbstraction(c: Constants, v: Variables) : AtomicKVSpec.Variables 16 | requires v.WF(c) 17 | 18 | ghost predicate Inv(c: Constants, v: Variables) 19 | 20 | lemma RefinementInit(c: Constants, v: Variables) 21 | requires Init(c, v) 22 | ensures Inv(c, v) 23 | ensures AtomicKVSpec.Init(ConstantsAbstraction(c), VariablesAbstraction(c, v)) 24 | 25 | // Note that this refinement obligation doesn't explicitly account for NoOp events. 26 | // You will need to account for these in your spec state machine. 27 | lemma RefinementNext(c: Constants, v: Variables, v': Variables, event: Event) 28 | requires Next(c, v, v', event) 29 | requires Inv(c, v) 30 | ensures Inv(c, v') 31 | ensures AtomicKVSpec.Next(ConstantsAbstraction(c), VariablesAbstraction(c, v), VariablesAbstraction(c, v'), event) 32 | } 33 | -------------------------------------------------------------------------------- /fall2024/project02-sharded-kv-store/exercises/Types.t.dfy: -------------------------------------------------------------------------------- 1 | module Types { 2 | 3 | datatype Event = 4 | | Get(key: int, value: int) 5 | | Put(key: int, value: int) 6 | | NoOp() 7 | } 8 | 9 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirecting to Fall 2024 Course 5 | 6 | 7 | This page has moved. Click here to go to the new page. 8 | 9 | 10 | --------------------------------------------------------------------------------