datatype Status = Shelf | Patron(name: string)
datatype Book = Book(title: string)
datatype Variables = Variables(library: map<Book, Status>)
ghost predicate WellFormed()
forall b: Book :: b.title == "" ==> b !in this.library
ghost predicate Init(v: Variables)
&& forall b :: b in v.library ==> v.library[b].Shelf?
datatype Step = Checkout(b: Book, to: string) | Return(b: Book)
ghost predicate CheckoutStep(v: Variables, v': Variables, step: Step)
&& v.library[step.b].Shelf?
&& v' == v.(library := v.library[step.b := Patron(step.to)])
ghost predicate ReturnStep(v: Variables, v': Variables, step: Step)
&& v.library[step.b].Patron?
&& v' == v.(library := v.library[step.b := Shelf])
ghost predicate NextStep(v: Variables, v': Variables, step: Step)
case Checkout(_, _) => CheckoutStep(v, v', step)
case Return(_) => ReturnStep(v, v', step)
ghost predicate Next(v: Variables, v': Variables)
exists step :: NextStep(v, v', step)
lemma NextStepDeterministicGivenStep(v:Variables, v':Variables, step: Step)
requires NextStep(v, v', step)
ensures forall v'' | NextStep(v, v'', step) :: v' == v''
Variables(library := map[Book("Snow Crash") := Shelf, Book("The Stand") := Shelf]),
Variables(library := map[Book("Snow Crash") := Patron("Jon"), Book("The Stand") := Shelf]),
Variables(library := map[Book("Snow Crash") := Patron("Jon"), Book("The Stand") := Patron("Tej")]),
Variables(library := map[Book("Snow Crash") := Shelf, Book("The Stand") := Patron("Tej")])
Checkout(Book("Snow Crash"), "Jon"),
Checkout(Book("The Stand"), "Tej"),
Return(Book("Snow Crash"))
assert forall n: nat | n < |e|-1 :: NextStep(e[n], e[n+1], steps[n]);
assert forall n: nat | n < |e|-1 :: Next(e[n], e[n+1]);