66datatype Status = Shelf | Patron (name: string )
77datatype Book = Book (title: string )
88
9- // no constants
10- datatype Constants = Constants ()
11-
129// The state of the whole library is just the status of every book owned by the
1310// library.
1411datatype Variables = Variables (library: map <Book , Status>)
@@ -17,7 +14,7 @@ datatype Variables = Variables(library: map<Book, Status>)
1714 // a set of _member functions_, which can be called as v.f(), just like Java,
1815 // C++, or Rust methods. Just like in Java or C++, the body can use the `this`
1916 // keyword to refer to an implicit argument of type Variables.
20- ghost predicate WellFormed (c: Constants )
17+ ghost predicate WellFormed ()
2118 {
2219 // New syntax (x in m for maps): maps have a domain and we can write x in m
2320 // to say x is in the domain of m (similarly, `x !in m` is a more readable
@@ -30,20 +27,20 @@ datatype Variables = Variables(library: map<Book, Status>)
3027 }
3128}
3229
33- ghost predicate Init (c: Constants , v: Variables )
30+ ghost predicate Init (v: Variables )
3431{
35- && v. WellFormed (c )
32+ && v. WellFormed ()
3633 && forall b :: b in v. library ==> v. library[b]. Shelf?
3734}
3835
3936// The transitions of the library state machine.
4037
4138datatype Step = Checkout (b: Book , to: string ) | Return (b: Book )
4239
43- ghost predicate CheckoutStep (c: Constants , v: Variables , v': Variables , step: Step )
40+ ghost predicate CheckoutStep (v: Variables , v': Variables , step: Step )
4441 requires step. Checkout?
4542{
46- && v. WellFormed (c )
43+ && v. WellFormed ()
4744 && step. b in v. library
4845 && v. library[step. b]. Shelf?
4946 // New syntax (datatype update): here we define the new Variables from the old
@@ -53,28 +50,33 @@ ghost predicate CheckoutStep(c: Constants, v: Variables, v': Variables, step: St
5350 && v' == v. (library := v. library[step. b := Patron (step.to)])
5451}
5552
56- ghost predicate ReturnStep (c: Constants , v: Variables , v': Variables , step: Step )
53+ ghost predicate ReturnStep (v: Variables , v': Variables , step: Step )
5754 requires step. Return?
5855{
59- && v. WellFormed (c )
56+ && v. WellFormed ()
6057 && step. b in v. library
6158 && v. library[step. b]. Patron?
6259 && v' == v. (library := v. library[step. b := Shelf])
6360}
6461
65- ghost predicate NextStep (c: Constants , v: Variables , v': Variables , step: Step )
62+ ghost predicate NextStep (v: Variables , v': Variables , step: Step )
6663{
6764 match step {
68- case Checkout (_, _) => CheckoutStep (c, v, v', step)
69- case Return (_) => ReturnStep (c, v, v', step)
65+ case Checkout (_, _) => CheckoutStep (v, v', step)
66+ case Return (_) => ReturnStep (v, v', step)
7067 }
7168}
7269
73- ghost predicate Next (c: Constants , v: Variables , v': Variables )
70+ ghost predicate Next (v: Variables , v': Variables )
7471{
75- exists step :: NextStep (c, v, v', step)
72+ exists step :: NextStep (v, v', step)
7673}
7774
75+ lemma NextStepDeterministicGivenStep (v:Variables , v':Variables , step: Step )
76+ requires NextStep (v, v', step)
77+ ensures forall v'' | NextStep (v, v'', step) :: v' == v''
78+ {}
79+
7880/*
7981In this lemma we'll write a concrete sequence of states which forms a (short)
8082execution of this state machine, and prove that it really is an execution.
@@ -83,24 +85,23 @@ This can be a good sanity check on the definitions (for example, to make sure
8385that it's at least possible to take every transition).
8486*/
8587lemma ExampleExec () {
86- var c := Constants ();
8788 var e := [
88- Variables (map[Book("Snow Crash") := Shelf, Book ("The Stand") := Shelf]),
89- Variables (map[Book("Snow Crash") := Patron ("Jon"), Book ("The Stand") := Shelf]),
90- Variables (map[Book("Snow Crash") := Patron ("Jon"), Book ("The Stand") := Patron ("Tej")]),
91- Variables (map[Book("Snow Crash") := Shelf, Book ("The Stand") := Patron ("Tej")])
89+ Variables (library := map[Book("Snow Crash") := Shelf, Book ("The Stand") := Shelf]),
90+ Variables (library := map[Book("Snow Crash") := Patron ("Jon"), Book ("The Stand") := Shelf]),
91+ Variables (library := map[Book("Snow Crash") := Patron ("Jon"), Book ("The Stand") := Patron ("Tej")]),
92+ Variables (library := map[Book("Snow Crash") := Shelf, Book ("The Stand") := Patron ("Tej")])
9293 ];
9394
9495 // Next we'll prove that e is a valid execution.
9596
96- assert Init (c, e[0]);
97+ assert Init (e[0]);
9798
9899 // These steps will be witnesses to help prove Next between every pair of Variables.
99100 var steps := [
100101 Checkout (Book("Snow Crash"), "Jon"),
101102 Checkout (Book("The Stand"), "Tej"),
102103 Return (Book("Snow Crash"))
103104 ];
104- assert forall n: nat | n < |e|- 1 :: NextStep (c, e[n], e[n+1], steps[n]);
105- assert forall n: nat | n < |e|- 1 :: Next (c, e[n], e[n+1]);
105+ assert forall n: nat | n < |e|- 1 :: NextStep (e[n], e[n+1], steps[n]);
106+ assert forall n: nat | n < |e|- 1 :: Next (e[n], e[n+1]);
106107}
0 commit comments