Skip to content

Commit 0e8a97b

Browse files
committed
Update library state machine example
1 parent 17dd02f commit 0e8a97b

File tree

1 file changed

+24
-23
lines changed

1 file changed

+24
-23
lines changed

src/examples/library.dfy

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
datatype Status = Shelf | Patron(name: string)
77
datatype 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.
1411
datatype 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

4138
datatype 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
/*
7981
In this lemma we'll write a concrete sequence of states which forms a (short)
8082
execution 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
8385
that it's at least possible to take every transition).
8486
*/
8587
lemma 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

Comments
 (0)