Built with Alectryon, running Coq+SerAPI v8.20.0+0.20.0. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+βCtrl+β to navigate, Ctrl+π±οΈ to focus. On Mac, use β instead of Ctrl.
[Loading ML file ssrmatching_plugin.cmxs (using legacy method) ... done]
[Loading ML file ssreflect_plugin.cmxs (using legacy method) ... done]
[Loading ML file ring_plugin.cmxs (using legacy method) ... done]
[Loading ML file zify_plugin.cmxs (using legacy method) ... done]
[Loading ML file micromega_core_plugin.cmxs (using legacy method) ... done]
[Loading ML file micromega_plugin.cmxs (using legacy method) ... done]
[Loading ML file btauto_plugin.cmxs (using legacy method) ... done]
[Loading ML file ltac2_plugin.cmxs (using legacy method) ... done]
Serlib plugin: coq-core.plugins.ltac2_ltac1 is not available: serlib support is missing.
Incremental checking for commands in this plugin will be impacted.
[Loading ML file ltac2_ltac1_plugin.cmxs (using legacy method) ... done]
(** * deletetree from the Separation Logic CACM paper by O'Hearn *)(** A tree will be a pointer to either None (represented InjL #()) or Some(l,r)(represented InjR (l, r)), where l and r are themselves trees. *)(** delete_tree is a version of the deletetree function from the paper, writtenin an OCaml-like language rather than the C code in the paper. *)Definitiondelete_tree: val :=
(* the rec: here starts a recursive function *)
rec: "delete_tree""x" :=
(* !"x" deferences the variable x (variables need to be quoted) *)match: !"x"with
SOME "tree" =>
(* if this tree has children, delete them first. Recall the tree is just a tuple of the left and right child tree pointers. *)
(let: "left" := Fst "tree"inlet: "right" := Snd "tree"in"delete_tree""left";;
"delete_tree""right";;
(* then free the root pointer *)
Free "x")
| NONE =>
(* the way we've represented trees, even an empty tree is a pointer to a None, so free that, too *)
Free "x"end.Sectionproof.Context `{!heapGS Ξ£}.Implicit Types (tlr:loc).(* You can ignore some magic that creates the recursive tree predicate. *)Definitiontree_pre (tree: loc -d> iPropO Ξ£): loc -d> iPropO Ξ£ :=
(Ξ»t, t β¦ NONEV β¨
(βlr, t β¦ SOMEV (#l, #r) β
β· tree l β β· tree r))%I.
Ξ£: gFunctors heapGS0: heapGS Ξ£
Contractive tree_pre
Ξ£: gFunctors heapGS0: heapGS Ξ£
Contractive tree_pre
solve_contractive.Qed.Definitiontree : loc β iProp Ξ£ := fixpoint tree_pre.(** You can take the following as a definition for [tree], in terms of arecursive equation - the β£β’ symbol means "equivalent". You can pretend β·P is thesame as P; this is a technicality required to write recursive definitions. *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
tree t
β£β’ t β¦ NONEV
β¨ βlr, t β¦ SOMEV (#l, #r) β β· tree l β β· tree r
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
tree t
β£β’ t β¦ NONEV
β¨ βlr, t β¦ SOMEV (#l, #r) β β· tree l β β· tree r
apply (fixpoint_unfold tree_pre).Qed.
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
tree t -β WP delete_tree #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
tree t -β WP delete_tree #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"Ht" : tree t
--------------------------------------β
WP delete_tree #t {{ _, emp }}
(* First we should understand how Hoare logic proofs are encoded in Iris. In Iris the goal is going to be [WP e {{ Q }}], which is a separation logic predicate, not a Coq assertion. For intuition, keep in mind that {{P}} e {{Q}} is the same thing as P β’ WP e {{ Q }}. Then, you can think of the spec being proven as one where the precondition is all of the premises (the hypotheses) and the program and postcondition are in the goal. *)(* this is how we start a recursive proof: *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : tree t
--------------------------------------β
WP delete_tree #t {{ _, emp }}
(* What we get from iLΓΆb is an assumption that delete_tree follows the specification. How is that possible? Couldn't we just use it right away and not have to any work? Indeed! That's why this assumption has the β· (pronounced "later") in front. β· P means we only get to know that P holds after one "step" within our function. This is enough to handle all the recursive calls but can't be used to just dismiss the whole proof (otherwise proofs would be easy but not very meaningful) *)(* We destruct the tree predicate into the two branches of the [β¨], and carry out the proof separately in each case. *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ NONEV
--------------------------------------β
WP delete_tree #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : βlr, t β¦ SOMEV (#l, #r) β β· tree l β β· tree r
--------------------------------------β
WP delete_tree #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ NONEV
--------------------------------------β
WP delete_tree #t {{ _, emp }}
(* The first case corresponds to an empty tree, where t β¦ None. In that case the code reduces down to just executing a Free on the root pointer. *)
(* I won't go through the motions of using the frame rule and load/store/free axioms; there's a tactic for that *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ NONEV
--------------------------------------β
WP Free #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
|={β€}=> emp
auto.
Ξ£: gFunctors heapGS0: heapGS Ξ£ t: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : βlr, t β¦ SOMEV (#l, #r) β β· tree l β β· tree r
--------------------------------------β
WP delete_tree #t {{ _, emp }}
(* In the other case we need to further destruct [tree] to get out the left and right subtrees (both their root pointers and the corresponding [tree] predicates) *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : β· βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hl" : β· tree l
"Hr" : β· tree r
--------------------------------------β
WP delete_tree #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hl" : tree l
"Hr" : tree r
--------------------------------------β
WP match: ! #t with
InjL <> => Free #t
| InjR "tree" =>
let: "left" := Fst "tree"inlet: "right" := Snd "tree"in
delete_tree "left";;
delete_tree "right";; Free #t
end
{{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hl" : tree l
"Hr" : tree r
--------------------------------------β
WP delete_tree #l;; delete_tree #r;; Free #t
{{ _, emp }}
(* wp_bind is a tactic to apply the sequencing rule (it takes an argument to pick what should be sequenced, for example in e1;; e2;; e3 you can isolate (e1;;e2) if you want) *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hl" : tree l
"Hr" : tree r
--------------------------------------β
WP delete_tree #l
{{ v, WP v;; delete_tree #r;; Free #t {{ _, emp }} }}
(* The recursive calls make use of the inductive hypothesis "IH", which says any recursive calls to delete_tree can be assumed to satisfy this specification. *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hl" : tree l
"Hr" : tree r
--------------------------------------β
WP delete_tree #l {{ v, ?Goal v }} β
βr0 : val,
?Goal r0 -β
WP r0;; delete_tree #r;; Free #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Hl" : tree l
--------------------------------------β
WP delete_tree #l {{ v, ?Goal v }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hr" : tree r
--------------------------------------β
βr0 : val,
?Goal r0 -β
WP r0;; delete_tree #r;; Free #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Hl" : tree l
--------------------------------------β
WP delete_tree #l {{ v, ?Goal v }}
iApply ("IH"with"Hl").
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hr" : tree r
--------------------------------------β
βr0 : val,
(Ξ»_ : language.val heap_lang, emp) r0 -β
WP r0;; delete_tree #r;; Free #t {{ _, emp }}
(* I'm naming the postcondition from the [delete_tree] specification "Hl" just to emphasize where it came from (it's an [emp] and thus unimportant, the separation logic equivalent of having a hypothesis [True]) *)
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc r0: val
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hr" : tree r
"Hl" : emp
--------------------------------------β
WP delete_tree #r;; Free #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc r0: val
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hr" : tree r
"Hl" : emp
--------------------------------------β
WP delete_tree #r {{ v, WP v;; Free #t {{ _, emp }} }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc r0: val
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Ht" : t β¦ SOMEV (#l, #r)
"Hr" : tree r
"Hl" : emp
--------------------------------------β
WP delete_tree #r {{ v, ?Goal v }} β
βr1 : val, ?Goal r1 -β WP r1;; Free #t {{ _, emp }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc r0: val
"IH" : βt, tree t -β WP delete_tree #t {{ _, emp }}
--------------------------------------β‘
"Hr" : tree r
--------------------------------------β
WP delete_tree #r {{ v, ?Goal v }}
Ξ£: gFunctors heapGS0: heapGS Ξ£ t, l, r: loc r0: val