HimplHeap Entailment
Implicit Types
First Pass
Lemma triple_conseq : ∀ t H Q H' Q',
triple t H' Q' →
H ==> H' →
Q' ===> Q →
triple t H Q. This chapter presents:
- the formal definition of the entailment relations,
- the fundamental properties of the Separation Logic operators: these properties are expressed either as entailments, or as equalities, which denote symmetric entailments,
- the 4 structural rules of Separation Logic: the rule of consequence, the frame rule (which can be combined with the rule of consequence), and the extractions rules for pure facts and for quantifiers,
- the tactics xsimpl and xchange that are critically useful for manipulating entailments in practice,
- (optional) details on how to prove the fundamental properties and the structural rules.
Definition of Entailment
Definition himpl (H1 H2:hprop) : Prop :=
∀ (h:heap), H1 h → H2 h.
Notation "H1 ==> H2" := (himpl H1 H2) (at level 55).
∀ (h:heap), H1 h → H2 h.
Notation "H1 ==> H2" := (himpl H1 H2) (at level 55).
H1 ==> H2 captures the fact that H1 is a stronger precondition
than H2, in the sense that it is more restrictive.
As we show next, the entailment relation is reflexive, transitive,
and antisymmetric. It thus forms an order relation on heap predicates.
Lemma himpl_refl : ∀ H,
H ==> H.
Proof using. intros h. hnf. auto. Qed.
Lemma himpl_trans : ∀ H2 H1 H3,
(H1 ==> H2) →
(H2 ==> H3) →
(H1 ==> H3).
Proof using. introv M1 M2. intros h H1h. eauto. Qed.
H ==> H.
Proof using. intros h. hnf. auto. Qed.
Lemma himpl_trans : ∀ H2 H1 H3,
(H1 ==> H2) →
(H2 ==> H3) →
(H1 ==> H3).
Proof using. introv M1 M2. intros h H1h. eauto. Qed.
Exercise: 1 star, standard, especially useful (himpl_antisym)
Prove the antisymmetry of entailment result shown below using extensionality for heap predicates, as captured by lemma predicate_extensionality (or lemma hprop_eq) introduced in the previous chapter (Hprop).
Lemma himpl_antisym : ∀ H1 H2,
(H1 ==> H2) →
(H2 ==> H1) →
H1 = H2.
Proof using. (* FILL IN HERE *) Admitted.
☐
(H1 ==> H2) →
(H2 ==> H1) →
H1 = H2.
Proof using. (* FILL IN HERE *) Admitted.
☐
Entailment for Postconditions
Definition qimpl (Q1 Q2:val→hprop) : Prop :=
∀ (v:val), Q1 v ==> Q2 v.
Notation "Q1 ===> Q2" := (qimpl Q1 Q2) (at level 55).
∀ (v:val), Q1 v ==> Q2 v.
Notation "Q1 ===> Q2" := (qimpl Q1 Q2) (at level 55).
Remark: equivalently, Q1 ===> Q2 holds if for any value v and
any heap h, the proposition Q1 v h implies Q2 v h.
Entailment on postconditions also forms an order relation:
it is reflexive, transitive, and antisymmetric.
Lemma qimpl_refl : ∀ Q,
Q ===> Q.
Proof using. intros Q v. applys himpl_refl. Qed.
Lemma qimpl_trans : ∀ Q2 Q1 Q3,
(Q1 ===> Q2) →
(Q2 ===> Q3) →
(Q1 ===> Q3).
Proof using. introv M1 M2. intros v. applys himpl_trans; eauto. Qed.
Lemma qimpl_antisym : ∀ Q1 Q2,
(Q1 ===> Q2) →
(Q2 ===> Q1) →
(Q1 = Q2).
Proof using.
introv M1 M2. apply functional_extensionality.
intros v. applys himpl_antisym; eauto.
Qed.
Q ===> Q.
Proof using. intros Q v. applys himpl_refl. Qed.
Lemma qimpl_trans : ∀ Q2 Q1 Q3,
(Q1 ===> Q2) →
(Q2 ===> Q3) →
(Q1 ===> Q3).
Proof using. introv M1 M2. intros v. applys himpl_trans; eauto. Qed.
Lemma qimpl_antisym : ∀ Q1 Q2,
(Q1 ===> Q2) →
(Q2 ===> Q1) →
(Q1 = Q2).
Proof using.
introv M1 M2. apply functional_extensionality.
intros v. applys himpl_antisym; eauto.
Qed.
Fundamental Properties of Separation Logic Operators
(2) The star operator is commutative.
(3) The empty heap predicate is a neutral for the star.
Because star is commutative, it is equivalent to state that
hempty is a left or a right neutral for hstar.
We chose, arbitrarily, to state the left-neutral property.
(4) Existentials can be "extruded" out of stars, that is:
(\∃ x, J x) \* H is equivalent to \∃ x, (J x \* H).
(5) The star operator is "monotone" with respect to entailment, meaning
that if H1 ==> H1' then (H1 \* H2) ==> (H1' \* H2).
Viewed the other way around, if we have to prove the entailment relation
(H1 \* H2) ==> (H1' \* H2), we can "cancel out" H2 on both sides.
In this view, the monotonicity property is a sort of "frame rule for
the entailment relation".
Here again, due to commutativity of star, it only suffices to state
the left version of the monotonicity property.
Exercise: 1 star, standard, especially useful (hstar_comm_assoc)
The commutativity and associativity results combine into one result that is sometimes convenient to exploit in proofs.
Lemma hstar_comm_assoc : ∀ H1 H2 H3,
H1 \* H2 \* H3 = H2 \* H1 \* H3.
Proof using. (* FILL IN HERE *) Admitted.
☐
H1 \* H2 \* H3 = H2 \* H1 \* H3.
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 1 star, standard, especially useful (himpl_frame_r)
Prove himpl_frame_r, which is the symmetric of himpl_frame_l.
Lemma himpl_frame_r : ∀ H1 H2 H2',
H2 ==> H2' →
(H1 \* H2) ==> (H1 \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
H2 ==> H2' →
(H1 \* H2) ==> (H1 \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 1 star, standard, especially useful (himpl_frame_lr)
The monotonicity property of the star operator w.r.t. entailment can also be stated in a symmetric fashion, as shown next. Prove this result. Hint: exploit the transitivity of entailment (himpl_trans) and the asymmetric monotonicity result (himpl_frame_l).
Lemma himpl_frame_lr : ∀ H1 H1' H2 H2',
H1 ==> H1' →
H2 ==> H2' →
(H1 \* H2) ==> (H1' \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
H1 ==> H1' →
H2 ==> H2' →
(H1 \* H2) ==> (H1' \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
Introduction and Elimination Rules w.r.t. Entailments
Exercise: 2 stars, standard, especially useful (himpl_hstar_hpure_r).
Prove the rule himpl_hstar_hpure_r. Hint: recall from Hprop the lemma hstar_hpure_l, which asserts the equality (\[P] \* H) h = (P ∧ H h).
Lemma himpl_hstar_hpure_r : ∀ P H H',
P →
(H ==> H') →
H ==> (\[P] \* H').
Proof using. (* FILL IN HERE *) Admitted.
☐
P →
(H ==> H') →
H ==> (\[P] \* H').
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, especially useful (himpl_hstar_hpure_l).
Prove the rule himpl_hstar_hpure_l.
Lemma himpl_hstar_hpure_l : ∀ (P:Prop) (H H':hprop),
(P → H ==> H') →
(\[P] \* H) ==> H'.
Proof using. (* FILL IN HERE *) Admitted.
☐
(P → H ==> H') →
(\[P] \* H) ==> H'.
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, especially useful (himpl_hexists_r).
Prove the rule himpl_hexists_r.
Lemma himpl_hexists_r : ∀ A (x:A) H J,
(H ==> J x) →
H ==> (\∃ x, J x).
Proof using. (* FILL IN HERE *) Admitted.
☐
(H ==> J x) →
H ==> (\∃ x, J x).
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, especially useful (himpl_hexists_l).
Prove the rule himpl_hexists_l.
Lemma himpl_hexists_l : ∀ (A:Type) (H:hprop) (J:A→hprop),
(∀ x, J x ==> H) →
(\∃ x, J x) ==> H.
Proof using. (* FILL IN HERE *) Admitted.
☐
(∀ x, J x ==> H) →
(\∃ x, J x) ==> H.
Proof using. (* FILL IN HERE *) Admitted.
☐
Extracting Information from Heap Predicates
The proof of this result exploits a result on finite maps.
Essentially, the domain of a single singleton map that binds
a location p to some value is the singleton set \{p}, thus
such a singleton map cannot be disjoint from another singleton
map that binds the same location p.
Check disjoint_single_single_same_inv : ∀ (p:loc) (v1 v2:val),
Fmap.disjoint (Fmap.single p v1) (Fmap.single p v2) →
False.
Using this lemma, we can prove hstar_hsingle_same_loc
by unfolding the definition of hstar to reveal the
contradiction on the disjointness assumption.
Check disjoint_single_single_same_inv : ∀ (p:loc) (v1 v2:val),
Fmap.disjoint (Fmap.single p v1) (Fmap.single p v2) →
False.
Proof using.
intros. unfold hsingle. intros h (h1&h2&E1&E2&D&E). false.
subst. applys Fmap.disjoint_single_single_same_inv D.
Qed.
intros. unfold hsingle. intros h (h1&h2&E1&E2&D&E). false.
subst. applys Fmap.disjoint_single_single_same_inv D.
Qed.
More generally, a heap predicate of the form H \* H is generally
suspicious in Separation Logic. In (the simplest variant of) Separation
Logic, such a predicate can only be satisfied if H covers no memory
cell at all, that is, if H is a pure predicate of the form \[P]
for some proposition P.
Consequence, Frame, and their Combination
Recall the frame rule introduced in the previous chapter.
Observe that, stated as such, it is very unlikely for the frame rule
to be applicable in practice, because the precondition must be exactly
of the form H \* H' and the postcondition exactly of the form
Q \*+ H', for some H'. For example, the frame rule would not apply
to a proof obligation of the form triple t (H' \* H) (Q \*+ H'),
simply because H' \* H does not match H \* H'.
This limitation of the frame rule can be addressed by combining the frame
rule with the rule of consequence into a single rule, called the
"consequence-frame rule". This rule, shown below, enables deriving
a triple from another triple, without any restriction on the exact
shape of the precondition and postcondition of the two triples involved.
Lemma triple_conseq_frame : ∀ H2 H1 Q1 t H Q,
triple t H1 Q1 →
H ==> H1 \* H2 →
Q1 \*+ H2 ===> Q →
triple t H Q.
triple t H1 Q1 →
H ==> H1 \* H2 →
Q1 \*+ H2 ===> Q →
triple t H Q.
Exercise: 1 star, standard, especially useful (triple_conseq_frame)
Prove the combined consequence-frame rule.
Proof using. (* FILL IN HERE *) Admitted.
☐
☐
The Extraction Rules for Triples
A judgment of the form triple t (\∃ x, J x) Q is equivalent
to ∀ x, triple t (J x) Q. This structural rule is called
triple_hexists and formalized as shown below. It captures the
extraction of an existential quantifier out of the precondition
of a triple, in a similar way as himpl_hexists_l for entailments.
Parameter triple_hexists : ∀ t (A:Type) (J:A→hprop) Q,
(∀ x, triple t (J x) Q) →
triple t (\∃ x, J x) Q.
(∀ x, triple t (J x) Q) →
triple t (\∃ x, J x) Q.
Quiz: For each entailment relation, indicate (without a Coq proof)
whether it is true or false. Solutions appear further on.
Parameter case_study_1 : ∀ p q,
p ~~> 3 \* q ~~> 4
==> q ~~> 4 \* p ~~> 3.
Parameter case_study_2 : ∀ p q,
p ~~> 3
==> q ~~> 4 \* p ~~> 3.
Parameter case_study_3 : ∀ p q,
q ~~> 4 \* p ~~> 3
==> p ~~> 4.
Parameter case_study_4 : ∀ p q,
q ~~> 4 \* p ~~> 3
==> p ~~> 3.
Parameter case_study_5 : ∀ p q,
\[False] \* p ~~> 3
==> p ~~> 4 \* q ~~> 4.
Parameter case_study_6 : ∀ p q,
p ~~> 3 \* q ~~> 4
==> \[False].
Parameter case_study_7 : ∀ p,
p ~~> 3 \* p ~~> 4
==> \[False].
Parameter case_study_8 : ∀ p,
p ~~> 3 \* p ~~> 3
==> \[False].
Parameter case_study_9 : ∀ p,
p ~~> 3
==> \∃ n, p ~~> n.
Parameter case_study_10 : ∀ p,
∃ n, p ~~> n
==> p ~~> 3.
Parameter case_study_11 : ∀ p,
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Parameter case_study_12 : ∀ p q,
p ~~> 3 \* q ~~> 3
==> \∃ n, p ~~> n \* q ~~> n.
Parameter case_study_13 : ∀ p n,
p ~~> n \* \[n > 0] \* \[n < 0] ==> p ~~> n \* p ~~> n.
End CaseStudy.
Module CaseStudyAnswers.
p ~~> 3 \* q ~~> 4
==> q ~~> 4 \* p ~~> 3.
Parameter case_study_2 : ∀ p q,
p ~~> 3
==> q ~~> 4 \* p ~~> 3.
Parameter case_study_3 : ∀ p q,
q ~~> 4 \* p ~~> 3
==> p ~~> 4.
Parameter case_study_4 : ∀ p q,
q ~~> 4 \* p ~~> 3
==> p ~~> 3.
Parameter case_study_5 : ∀ p q,
\[False] \* p ~~> 3
==> p ~~> 4 \* q ~~> 4.
Parameter case_study_6 : ∀ p q,
p ~~> 3 \* q ~~> 4
==> \[False].
Parameter case_study_7 : ∀ p,
p ~~> 3 \* p ~~> 4
==> \[False].
Parameter case_study_8 : ∀ p,
p ~~> 3 \* p ~~> 3
==> \[False].
Parameter case_study_9 : ∀ p,
p ~~> 3
==> \∃ n, p ~~> n.
Parameter case_study_10 : ∀ p,
∃ n, p ~~> n
==> p ~~> 3.
Parameter case_study_11 : ∀ p,
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Parameter case_study_12 : ∀ p q,
p ~~> 3 \* q ~~> 3
==> \∃ n, p ~~> n \* q ~~> n.
Parameter case_study_13 : ∀ p n,
p ~~> n \* \[n > 0] \* \[n < 0] ==> p ~~> n \* p ~~> n.
End CaseStudy.
Module CaseStudyAnswers.
The answers to the quiz are as follows.
1. True, by commutativity.
2. False, because one cell does not entail two cells.
3. False, because one cell does not entail two cells.
4. False, because one cell does not entail two cells.
5. True, because \False entails anything.
6. False, because a satisfiable heap predicate does not entail \False.
7. True, because a cell cannot be starred with itself.
8. True, because a cell cannot be starred with itself.
9. True, by instantiating n with 3.
10. False, because n could be something else than 3.
11. True, by instantiating n in RHS with n+1 for the n of the LHS.
12. True, by instantiating n with 3.
13. True, because it is equivalent to \[False] ==> \[False].
Proofs for the true results appear below.
Implicit Types p q : loc.
Implicit Types n m : int.
Lemma case_study_1 : ∀ p q,
p ~~> 3 \* q ~~> 4
==> q ~~> 4 \* p ~~> 3.
Proof using. xsimpl. Qed.
Lemma case_study_5 : ∀ p q,
\[False] \* p ~~> 3
==> p ~~> 4 \* q ~~> 4.
Proof using. xsimpl. Qed.
Lemma case_study_7 : ∀ p,
p ~~> 3 \* p ~~> 4
==> \[False].
Proof using. intros. xchange (hstar_hsingle_same_loc p). Qed.
Lemma case_study_8 : ∀ p,
p ~~> 3 \* p ~~> 3
==> \[False].
Proof using. intros. xchange (hstar_hsingle_same_loc p). Qed.
Lemma case_study_9 : ∀ p,
p ~~> 3
==> \∃ n, p ~~> n.
Proof using. xsimpl. Qed.
Lemma case_study_11 : ∀ p,
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Proof using.
intros. xpull. intros n Hn. xsimpl (n+1).
math. math.
Qed.
Lemma case_study_12 : ∀ p q,
p ~~> 3 \* q ~~> 3
==> \∃ n, p ~~> n \* q ~~> n.
Proof using. xsimpl. Qed.
Lemma case_study_13 : ∀ p n,
p ~~> n \* \[n > 0] \* \[n < 0] ==> p ~~> n \* p ~~> n.
Proof using. intros. xsimpl. intros Hn1 Hn2. false. math. Qed.
End CaseStudyAnswers.
Implicit Types n m : int.
Lemma case_study_1 : ∀ p q,
p ~~> 3 \* q ~~> 4
==> q ~~> 4 \* p ~~> 3.
Proof using. xsimpl. Qed.
Lemma case_study_5 : ∀ p q,
\[False] \* p ~~> 3
==> p ~~> 4 \* q ~~> 4.
Proof using. xsimpl. Qed.
Lemma case_study_7 : ∀ p,
p ~~> 3 \* p ~~> 4
==> \[False].
Proof using. intros. xchange (hstar_hsingle_same_loc p). Qed.
Lemma case_study_8 : ∀ p,
p ~~> 3 \* p ~~> 3
==> \[False].
Proof using. intros. xchange (hstar_hsingle_same_loc p). Qed.
Lemma case_study_9 : ∀ p,
p ~~> 3
==> \∃ n, p ~~> n.
Proof using. xsimpl. Qed.
Lemma case_study_11 : ∀ p,
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Proof using.
intros. xpull. intros n Hn. xsimpl (n+1).
math. math.
Qed.
Lemma case_study_12 : ∀ p q,
p ~~> 3 \* q ~~> 3
==> \∃ n, p ~~> n \* q ~~> n.
Proof using. xsimpl. Qed.
Lemma case_study_13 : ∀ p n,
p ~~> n \* \[n > 0] \* \[n < 0] ==> p ~~> n \* p ~~> n.
Proof using. intros. xsimpl. intros Hn1 Hn2. false. math. Qed.
End CaseStudyAnswers.
Proving an entailment by hand is generally a tedious task. This is why
most Separation Logic based framework include an automated tactic for
simplifying entailments. In this course, the relevant tactic is named
xsimpl. Further in this chapter, we describe by means of examples the
behavior of this tactic. But in order to best appreciate what the tactic
provides and best understand how it works, it is very useful to complete
a few proofs by hand.
Exercise: 3 stars, standard, optional (himpl_example_1)
Prove the example entailment below. Hint: exploit hstar_comm, hstar_assoc, or hstar_comm_assoc which combines the two, and exploit himpl_frame_l or himpl_frame_r to cancel out matching pieces.
Lemma himpl_example_1 : ∀ p1 p2 p3 p4,
p1 ~~> 6 \* p2 ~~> 7 \* p3 ~~> 8 \* p4 ~~> 9
==> p4 ~~> 9 \* p3 ~~> 8 \* p2 ~~> 7 \* p1 ~~> 6.
Proof using. (* FILL IN HERE *) Admitted.
☐
p1 ~~> 6 \* p2 ~~> 7 \* p3 ~~> 8 \* p4 ~~> 9
==> p4 ~~> 9 \* p3 ~~> 8 \* p2 ~~> 7 \* p1 ~~> 6.
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 3 stars, standard, optional (himpl_example_2)
Prove the example entailment below. Hint: use himpl_hstar_hpure_l to extract pure facts, once they appear at the head of the left-hand side of the entailment. For arithmetic inequalities, use the math tactic.
Lemma himpl_example_2 : ∀ p1 p2 p3 n,
p1 ~~> 6 \* \[n > 0] \* p2 ~~> 7 \* \[n < 0]
==> p3 ~~> 8.
Proof using. (* FILL IN HERE *) Admitted.
☐
p1 ~~> 6 \* \[n > 0] \* p2 ~~> 7 \* \[n < 0]
==> p3 ~~> 8.
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 3 stars, standard, optional (himpl_example_3)
Prove the example entailment below. Hint: use lemmas among himpl_hexists_r, himpl_hexists_l, himpl_hstar_hpure_r and himpl_hstar_hpure_r to deal with pure facts and quantifiers.
Lemma himpl_example_3 : ∀ p,
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Proof using. (* FILL IN HERE *) Admitted.
☐
\∃ n, p ~~> n \* \[n > 0]
==> \∃ n, \[n > 1] \* p ~~> (n-1).
Proof using. (* FILL IN HERE *) Admitted.
☐
The xsimpl Tactic
xsimpl to Extract Pure Facts and Quantifiers in LHS
Lemma xsimpl_demo_lhs_hpure : ∀ H1 H2 H3 H4 (n:int),
H1 \* H2 \* \[n > 0] \* H3 ==> H4.
Proof using.
intros. xsimpl. intros Hn.
Abort.
H1 \* H2 \* \[n > 0] \* H3 ==> H4.
Proof using.
intros. xsimpl. intros Hn.
Abort.
In case the LHS includes a contradiction, such as the pure fact
False, the goal gets solved immediately by xsimpl.
Lemma xsimpl_demo_lhs_hpure : ∀ H1 H2 H3 H4,
H1 \* H2 \* \[False] \* H3 ==> H4.
Proof using.
intros. xsimpl.
Qed.
H1 \* H2 \* \[False] \* H3 ==> H4.
Proof using.
intros. xsimpl.
Qed.
The xsimpl tactic also extracts existential quantifier from the LHS.
It turns them into universally quantified variables outside of the
entailment relation, as illustrated through the following example.
Lemma xsimpl_demo_lhs_hexists : ∀ H1 H2 H3 H4 (p:loc),
H1 \* \∃ (n:int), (p ~~> n \* H2) \* H3 ==> H4.
Proof using.
intros. xsimpl. intros n.
Abort.
H1 \* \∃ (n:int), (p ~~> n \* H2) \* H3 ==> H4.
Proof using.
intros. xsimpl. intros n.
Abort.
A call to xsimpl, or to its degraded version xpull, extract at once
all the pure facts and quantifiers from the LHS, as illustrated next.
Lemma xsimpl_demo_lhs_several : ∀ H1 H2 H3 H4 (p q:loc),
H1 \* \∃ (n:int), (p ~~> n \* \[n > 0] \* H2) \* \[p ≠ q] \* H3 ==> H4.
Proof using.
intros.
xsimpl. (* or xpull *)
intros n Hn Hp.
Abort.
H1 \* \∃ (n:int), (p ~~> n \* \[n > 0] \* H2) \* \[p ≠ q] \* H3 ==> H4.
Proof using.
intros.
xsimpl. (* or xpull *)
intros n Hn Hp.
Abort.
xsimpl to Cancel Out Heap Predicates from LHS and RHS
Lemma xsimpl_demo_cancel_one : ∀ H1 H2 H3 H4 H5 H6 H7,
H1 \* H2 \* H3 \* H4 ==> H5 \* H6 \* H2 \* H7.
Proof using.
intros. xsimpl.
Abort.
H1 \* H2 \* H3 \* H4 ==> H5 \* H6 \* H2 \* H7.
Proof using.
intros. xsimpl.
Abort.
xsimpl actually cancels out at once all the heap predicates that it
can spot appearing on both sides. In the example below, H2, H3,
and H4 are canceled out.
Lemma xsimpl_demo_cancel_many : ∀ H1 H2 H3 H4 H5,
H1 \* H2 \* H3 \* H4 ==> H4 \* H3 \* H5 \* H2.
Proof using.
intros. xsimpl.
Abort.
H1 \* H2 \* H3 \* H4 ==> H4 \* H3 \* H5 \* H2.
Proof using.
intros. xsimpl.
Abort.
If all the pieces of heap predicate get canceled out, the remaining
proof obligation is \[] ==> \[]. In this case, xsimpl automatically
solves the goal by invoking the reflexivity property of entailment.
Lemma xsimpl_demo_cancel_all : ∀ H1 H2 H3 H4,
H1 \* H2 \* H3 \* H4 ==> H4 \* H3 \* H1 \* H2.
Proof using.
intros. xsimpl.
Qed.
H1 \* H2 \* H3 \* H4 ==> H4 \* H3 \* H1 \* H2.
Proof using.
intros. xsimpl.
Qed.
xsimpl to Instantiate Pure Facts and Quantifiers in RHS
Lemma xsimpl_demo_rhs_hpure : ∀ H1 H2 H3 (n:int),
H1 ==> H2 \* \[n > 0] \* H3.
Proof using.
intros. xsimpl.
Abort.
H1 ==> H2 \* \[n > 0] \* H3.
Proof using.
intros. xsimpl.
Abort.
When it encounters an existential quantifier in the RHS, the xsimpl
tactic introduces a unification variable denoted by a question mark,
that is, an "evar", in Coq terminology. In the example below, the xsimpl
tactic turns \∃ n, .. p ~~> n .. into .. p ~~> ?x ...
Lemma xsimpl_demo_rhs_hexists : ∀ H1 H2 H3 H4 (p:loc),
H1 ==> H2 \* \∃ (n:int), (p ~~> n \* H3) \* H4.
Proof using.
intros. xsimpl.
Abort.
H1 ==> H2 \* \∃ (n:int), (p ~~> n \* H3) \* H4.
Proof using.
intros. xsimpl.
Abort.
The "evar" often gets subsequently instantiated as a result of
a cancellation step. For example, in the example below, xsimpl
instantiates the existentially quantified variable n as ?x,
then cancels out p ~~> ?x from the LHS against p ~~> 3 on
the right-hand-side, thereby unifying ?x with 3.
Lemma xsimpl_demo_rhs_hexists_unify : ∀ H1 H2 H3 H4 (p:loc),
H1 \* (p ~~> 3) ==> H2 \* \∃ (n:int), (p ~~> n \* H3) \* H4.
Proof using.
intros. xsimpl.
Abort.
H1 \* (p ~~> 3) ==> H2 \* \∃ (n:int), (p ~~> n \* H3) \* H4.
Proof using.
intros. xsimpl.
Abort.
The instantiation of the evar ?x can be observed if there is
another occurrence of the same variable in the entailment.
In the next example, which refines the previous one, observe how
n > 0 becomes 3 > 0.
Lemma xsimpl_demo_rhs_hexists_unify_view : ∀ H1 H2 H4 (p:loc),
H1 \* (p ~~> 3) ==> H2 \* \∃ (n:int), (p ~~> n \* \[n > 0]) \* H4.
Proof using.
intros. xsimpl.
Abort.
H1 \* (p ~~> 3) ==> H2 \* \∃ (n:int), (p ~~> n \* \[n > 0]) \* H4.
Proof using.
intros. xsimpl.
Abort.
(Advanced.) In some cases, it is desirable to provide an explicit value
for instantiating an existential quantifier that occurs in the RHS.
The xsimpl tactic accepts arguments, which will be used to instantiate
the existentials (on a first-match basis). The syntax is xsimpl v1 .. vn,
or xsimpl (>> v1 .. vn) in the case n > 3.
Lemma xsimpl_demo_rhs_hints : ∀ H1 (p q:loc),
H1 ==> \∃ (n m:int), (p ~~> n \* q ~~> m).
Proof using.
intros. xsimpl 3 4.
Abort.
H1 ==> \∃ (n m:int), (p ~~> n \* q ~~> m).
Proof using.
intros. xsimpl 3 4.
Abort.
(Advanced.) If two existential quantifiers quantify variables of the same
type, it is possible to provide a value for only the second quantifier
by passing as first argument to xsimpl the special value __.
The following example shows how, on LHS of the form \∃ n m, ...,
the tactic xsimpl __ 4 instantiates m with 4 while leaving n
as an unresolved evar.
Lemma xsimpl_demo_rhs_hints_evar : ∀ H1 (p q:loc),
H1 ==> \∃ (n m:int), (p ~~> n \* q ~~> m).
Proof using.
intros. xsimpl __ 4.
Abort.
H1 ==> \∃ (n m:int), (p ~~> n \* q ~~> m).
Proof using.
intros. xsimpl __ 4.
Abort.
xsimpl on Entailments Between Postconditions
Lemma qimpl_example_1 : ∀ (Q1 Q2:val→hprop) (H2 H3:hprop),
Q1 \*+ H2 ===> Q2 \*+ H2 \*+ H3.
Proof using. intros. xsimpl. intros r. Abort.
Q1 \*+ H2 ===> Q2 \*+ H2 \*+ H3.
Proof using. intros. xsimpl. intros r. Abort.
Lemma himpl_example_1 : ∀ (p:loc),
p ~~> 3 ==>
\∃ (n:int), p ~~> n.
Proof using. xsimpl. Qed.
Lemma himpl_example_2 : ∀ (p q:loc),
p ~~> 3 \* q ~~> 3 ==>
\∃ (n:int), p ~~> n \* q ~~> n.
Proof using. xsimpl. Qed.
Lemma himpl_example_4 : ∀ (p:loc),
\∃ (n:int), p ~~> n ==>
\∃ (m:int), p ~~> (m + 1).
Proof using.
intros. (* observe that xsimpl here does not work well. *)
xpull. intros n. xsimpl (n-1). math.
Qed.
Lemma himpl_example_5 : ∀ (H:hprop),
\[False] ==> H.
Proof using. xsimpl. Qed.
p ~~> 3 ==>
\∃ (n:int), p ~~> n.
Proof using. xsimpl. Qed.
Lemma himpl_example_2 : ∀ (p q:loc),
p ~~> 3 \* q ~~> 3 ==>
\∃ (n:int), p ~~> n \* q ~~> n.
Proof using. xsimpl. Qed.
Lemma himpl_example_4 : ∀ (p:loc),
\∃ (n:int), p ~~> n ==>
\∃ (m:int), p ~~> (m + 1).
Proof using.
intros. (* observe that xsimpl here does not work well. *)
xpull. intros n. xsimpl (n-1). math.
Qed.
Lemma himpl_example_5 : ∀ (H:hprop),
\[False] ==> H.
Proof using. xsimpl. Qed.
The xchange Tactic
Lemma xchange_demo_base : ∀ H1 H2 H2' H3 H4,
H2 ==> H2' →
H1 \* H2 \* H3 ==> H4.
Proof using.
introv M. xchange M.
(* Note that freshly produced items appear to the front *)
Abort.
H2 ==> H2' →
H1 \* H2 \* H3 ==> H4.
Proof using.
introv M. xchange M.
(* Note that freshly produced items appear to the front *)
Abort.
The tactic xchange can also take as argument equalities.
The tactic xchange M exploits the left-to-right direction of an
equality M, whereas xchange <- M exploits the right-to-left
direction .
Lemma xchange_demo_eq : ∀ H1 H2 H3 H4 H5,
H1 \* H3 = H5 →
H1 \* H2 \* H3 ==> H4.
Proof using.
introv M. xchange M.
xchange <- M.
Abort.
H1 \* H3 = H5 →
H1 \* H2 \* H3 ==> H4.
Proof using.
introv M. xchange M.
xchange <- M.
Abort.
The tactic xchange M does accept a lemma or hypothesis M
featuring universal quantifiers, as long as its conclusion
is an equality or an entailment. In such case, xchange M
instantiates M before attemting to perform a replacement.
Lemma xchange_demo_inst : ∀ H1 (J J':int→hprop) H3 H4,
(∀ n, J n = J' (n+1)) →
H1 \* J 3 \* H3 ==> H4.
Proof using.
introv M. xchange M.
(* Note that freshly produced items appear to the front *)
Abort.
(∀ n, J n = J' (n+1)) →
H1 \* J 3 \* H3 ==> H4.
Proof using.
introv M. xchange M.
(* Note that freshly produced items appear to the front *)
Abort.
How does the xchange tactic work? Consider a goal of the form H ==> H'
and assume xchange is invoked with an hypothesis of type H1 ==> H1'
as argument. The tactic xchange should attempt to decompose H as the
star of H1 and the rest of H, call it H2. If it succeeds, then the
goal H ==> H' can be rewritten as H1 \* H2 ==> H'. To exploit the
hypothesis H1 ==> H1', the tactic should replace the goal with the
entailment H1' \* H2 ==> H'. The lemma shown below captures this piece
of reasoning implemented by the tactic xchange.
Exercise: 2 stars, standard, especially useful (xchange_lemma)
Prove, without using the tactic xchange, the following lemma which captures the internal working of xchange.
Lemma xchange_lemma : ∀ H1 H1' H H' H2,
H1 ==> H1' →
H ==> H1 \* H2 →
H1' \* H2 ==> H' →
H ==> H'.
Proof using. (* FILL IN HERE *) Admitted.
☐
H1 ==> H1' →
H ==> H1 \* H2 →
H1' \* H2 ==> H' →
H ==> H'.
Proof using. (* FILL IN HERE *) Admitted.
☐
We next show the details of the proofs establishing the fundamental
properties of the Separation Logic operators.
Note that all these results must be proved without help of the tactic
xsimpl, because the implementation of the tactic xsimpl itself
depends on these fundamental properties.
We begin with the frame property, which is the simplest to prove.
Exercise: 1 star, standard, especially useful (himpl_frame_l)
Prove the frame property for entailment. Hint: unfold the definition of hstar.
Lemma himpl_frame_l : ∀ H2 H1 H1',
H1 ==> H1' →
(H1 \* H2) ==> (H1' \* H2).
Proof using. (* FILL IN HERE *) Admitted.
☐
H1 ==> H1' →
(H1 \* H2) ==> (H1' \* H2).
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 1 star, standard, especially useful (himpl_frame_r)
Prove the lemma himpl_frame_r, symmetric to himpl_frame_l.
Lemma himpl_frame_r : ∀ H1 H2 H2',
H2 ==> H2' →
(H1 \* H2) ==> (H1 \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
H2 ==> H2' →
(H1 \* H2) ==> (H1 \* H2').
Proof using. (* FILL IN HERE *) Admitted.
☐
Lemma hstar_hexists : ∀ A (J:A→hprop) H,
(\∃ x, J x) \* H = \∃ x, (J x \* H).
Proof using.
intros. applys himpl_antisym.
{ intros h (h1&h2&M1&M2&D&U). destruct M1 as (x&M1). ∃* x h1 h2. }
{ intros h (x&M). destruct M as (h1&h2&M1&M2&D&U). ∃ h1 h2.
splits¬. ∃* x. }
Qed.
(\∃ x, J x) \* H = \∃ x, (J x \* H).
Proof using.
intros. applys himpl_antisym.
{ intros h (h1&h2&M1&M2&D&U). destruct M1 as (x&M1). ∃* x h1 h2. }
{ intros h (x&M). destruct M as (h1&h2&M1&M2&D&U). ∃ h1 h2.
splits¬. ∃* x. }
Qed.
There remains to establish the commutativity and associativity of the star
operator, and the fact that the empty heap predicate is its neutral element.
To establish these properties, we need to exploit a few basic facts about
finite maps. We introduce them as we go along.
To prove the commutativity of the star operator, i.e. H1 \* H2 = H2 \* H1,
it is sufficient to prove the entailement in one direction, e.g.,
H1 \* H2 ==> H2 \* H1. Indeed, the other other direction is symmetrical.
The symmetry argument is captured by the following lemma, which we will
exploit in the proof of hstar_comm.
Lemma hprop_op_comm : ∀ (op:hprop→hprop→hprop),
(∀ H1 H2, op H1 H2 ==> op H2 H1) →
(∀ H1 H2, op H1 H2 = op H2 H1).
Proof using. introv M. intros. applys himpl_antisym; applys M. Qed.
(∀ H1 H2, op H1 H2 ==> op H2 H1) →
(∀ H1 H2, op H1 H2 = op H2 H1).
Proof using. introv M. intros. applys himpl_antisym; applys M. Qed.
To prove commutativity of star, we need to exploit the fact that the union
of two finite maps with disjoint domains commutes. This fact is captured
by the following lemma.
Check Fmap.union_comm_of_disjoint : ∀ h1 h2,
Fmap.disjoint h1 h2 →
h1 \u h2 = h2 \u h1. The commutativity result is then proved as follows. Observe the use of the lemma hprop_op_comm, which allows establishing the entailment in only one of the two directions.
Check Fmap.union_comm_of_disjoint : ∀ h1 h2,
Fmap.disjoint h1 h2 →
h1 \u h2 = h2 \u h1. The commutativity result is then proved as follows. Observe the use of the lemma hprop_op_comm, which allows establishing the entailment in only one of the two directions.
Lemma hstar_comm : ∀ H1 H2,
H1 \* H2 = H2 \* H1.
Proof using.
applys hprop_op_comm. intros. intros h (h1&h2&M1&M2&D&U). ∃ h2 h1.
subst. splits¬. { rewrite Fmap.union_comm_of_disjoint; auto. }
Qed.
H1 \* H2 = H2 \* H1.
Proof using.
applys hprop_op_comm. intros. intros h (h1&h2&M1&M2&D&U). ∃ h2 h1.
subst. splits¬. { rewrite Fmap.union_comm_of_disjoint; auto. }
Qed.
Exercise: 3 stars, standard, especially useful (hstar_hempty_l)
Prove that the empty heap predicate is a neutral element for the star. You will need to exploit the fact that the union with an empty map is the identity, as captured by lemma Fmap.union_empty_l.Check Fmap.union_empty_l : ∀ h,
Fmap.empty \u h = h.
Lemma hstar_hempty_r : ∀ H,
H \* \[] = H.
Proof using.
intros. rewrite hstar_comm. rewrite hstar_hempty_l. auto.
Qed.
H \* \[] = H.
Proof using.
intros. rewrite hstar_comm. rewrite hstar_hempty_l. auto.
Qed.
Associativity of star is the most tedious result to derive.
We need to exploit the associativity of union on finite maps,
as well as lemmas about the disjointness of a map with the
result of the union of two maps.
Check Fmap.union_assoc : ∀ h1 h2 h3,
(h1 \u h2) \u h3 = h1 \u (h2 \u h3).
Check Fmap.disjoint_union_eq_l : ∀ h1 h2 h3,
Fmap.disjoint (h2 \u h3) h1
= (Fmap.disjoint h1 h2 ∧ Fmap.disjoint h1 h3).
Check Fmap.disjoint_union_eq_r : ∀ h1 h2 h3,
Fmap.disjoint h1 (h2 \u h3)
= (Fmap.disjoint h1 h2 ∧ Fmap.disjoint h1 h3).
Check Fmap.union_assoc : ∀ h1 h2 h3,
(h1 \u h2) \u h3 = h1 \u (h2 \u h3).
Check Fmap.disjoint_union_eq_l : ∀ h1 h2 h3,
Fmap.disjoint (h2 \u h3) h1
= (Fmap.disjoint h1 h2 ∧ Fmap.disjoint h1 h3).
Check Fmap.disjoint_union_eq_r : ∀ h1 h2 h3,
Fmap.disjoint h1 (h2 \u h3)
= (Fmap.disjoint h1 h2 ∧ Fmap.disjoint h1 h3).
Exercise: 1 star, standard, optional (hstar_assoc)
Complete the right-to-left part of the proof of associativity of the star operator.
Lemma hstar_assoc : ∀ H1 H2 H3,
(H1 \* H2) \* H3 = H1 \* (H2 \* H3).
Proof using.
intros. applys himpl_antisym.
{ intros h (h'&h3&M1&M2&D&U). destruct M1 as (h1&h2&M3&M4&D'&U').
subst h'. rewrite Fmap.disjoint_union_eq_l in D.
∃ h1 (h2 \u h3). splits.
{ applys M3. }
{ ∃* h2 h3. }
{ rewrite* @Fmap.disjoint_union_eq_r. }
{ rewrite* @Fmap.union_assoc in U. } }
(* FILL IN HERE *) Admitted.
☐
(H1 \* H2) \* H3 = H1 \* (H2 \* H3).
Proof using.
intros. applys himpl_antisym.
{ intros h (h'&h3&M1&M2&D&U). destruct M1 as (h1&h2&M3&M4&D'&U').
subst h'. rewrite Fmap.disjoint_union_eq_l in D.
∃ h1 (h2 \u h3). splits.
{ applys M3. }
{ ∃* h2 h3. }
{ rewrite* @Fmap.disjoint_union_eq_r. }
{ rewrite* @Fmap.union_assoc in U. } }
(* FILL IN HERE *) Admitted.
☐
Recall the statement of the rule of consequence.
A direct proof of triple_conseq goes through the low-level
interpretation of Separation Logic triples in terms of heaps.
Proof using.
(* No need to follow through this low-level proof. *)
introv M WH WQ. rewrite triple_iff_triple_lowlevel in *.
intros h1 h2 D HH. forwards (h1'&v&D'&R&HQ): M D. applys WH HH.
∃ h1' v. splits¬. applys WQ HQ.
Qed.
(* No need to follow through this low-level proof. *)
introv M WH WQ. rewrite triple_iff_triple_lowlevel in *.
intros h1 h2 D HH. forwards (h1'&v&D'&R&HQ): M D. applys WH HH.
∃ h1' v. splits¬. applys WQ HQ.
Qed.
An alternative proof leverages the consequence rule for the hoare
judgment, namely lemma hoare_conseq.
Exercise: 2 stars, standard, especially useful (triple_conseq)
Prove the consequence rule by leveraging the lemma hoare_conseq. Hint: unfold the definition of triple, apply the lemma hoare_conseq with the appropriate arguments, then exploit himpl_frame_l to prove the entailment relations.
Lemma triple_conseq : ∀ t H Q H' Q',
triple t H' Q' →
H ==> H' →
Q' ===> Q →
triple t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
triple t H' Q' →
H ==> H' →
Q' ===> Q →
triple t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
Recall the extraction rule for pure facts.
To prove this lemma, we first the establish corresponding
result on hoare, then derive its version for triple.
Lemma hoare_hpure : ∀ t (P:Prop) H Q,
(P → hoare t H Q) →
hoare t (\[P] \* H) Q.
Proof using.
introv M. intros h (h1&h2&M1&M2&D&U). destruct M1 as (M1&HP).
subst. rewrite Fmap.union_empty_l. applys M HP M2.
Qed.
Lemma triple_hpure : ∀ t (P:Prop) H Q,
(P → triple t H Q) →
triple t (\[P] \* H) Q.
Proof using.
introv M. unfold triple. intros H'.
rewrite hstar_assoc. applys hoare_hpure.
intros HP. applys M HP.
Qed.
(P → hoare t H Q) →
hoare t (\[P] \* H) Q.
Proof using.
introv M. intros h (h1&h2&M1&M2&D&U). destruct M1 as (M1&HP).
subst. rewrite Fmap.union_empty_l. applys M HP M2.
Qed.
Lemma triple_hpure : ∀ t (P:Prop) H Q,
(P → triple t H Q) →
triple t (\[P] \* H) Q.
Proof using.
introv M. unfold triple. intros H'.
rewrite hstar_assoc. applys hoare_hpure.
intros HP. applys M HP.
Qed.
Similarly, the extraction rule for existentials for
triple can be derived from that for hoare.
Exercise: 2 stars, standard, especially useful (triple_hexists)
Prove the extraction rule triple_hexists. Hint: start by stating and proving The corresponding lemma for hoare triples, named hoare_hexists.
(* FILL IN HERE *)
Lemma triple_hexists : ∀ t (A:Type) (J:A→hprop) Q,
(∀ x, triple t (J x) Q) →
triple t (\∃ x, J x) Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
Lemma triple_hexists : ∀ t (A:Type) (J:A→hprop) Q,
(∀ x, triple t (J x) Q) →
triple t (\∃ x, J x) Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
Parameter hstar_hexists' : ∀ A (J:A→hprop) H,
(hexists J) \* H = hexists (J \*+ H).
Parameter triple_hexists' : ∀ t (A:Type) (J:A→hprop) Q,
(∀ x, triple t (J x) Q) →
triple t (hexists J) Q.
(hexists J) \* H = hexists (J \*+ H).
Parameter triple_hexists' : ∀ t (A:Type) (J:A→hprop) Q,
(∀ x, triple t (J x) Q) →
triple t (hexists J) Q.
Remark: in chapter Hprop, we observed that \[P] can be
encoded as \∃ (p:P), \[]. When this encoding is used,
the rule triple_hpure turns out to be a particular instance
of the rule triple_hexists, as we prove next.
Parameter hpure_encoding : ∀ P,
\[P] = (\∃ (p:P), \[]).
Lemma triple_hpure_from_triple_hexists : ∀ t (P:Prop) H Q,
(P → triple t H Q) →
triple t (\[P] \* H) Q.
Proof using.
introv M. rewrite hpure_encoding.
rewrite hstar_hexists. (* disable notation printing to see the effect *)
applys triple_hexists. (* ∀ (p:P), ... is the same as P → ... *)
rewrite hstar_hempty_l. applys M.
Qed.
End ProveExtractionRules.
\[P] = (\∃ (p:P), \[]).
Lemma triple_hpure_from_triple_hexists : ∀ t (P:Prop) H Q,
(P → triple t H Q) →
triple t (\[P] \* H) Q.
Proof using.
introv M. rewrite hpure_encoding.
rewrite hstar_hexists. (* disable notation printing to see the effect *)
applys triple_hexists. (* ∀ (p:P), ... is the same as P → ... *)
rewrite hstar_hempty_l. applys M.
Qed.
End ProveExtractionRules.
Rules for Naming Heaps
Exercise: 3 stars, standard, optional (hexists_named_eq)
Prove that a heap predicate H is equivalent to the heap predicate which asserts that the heap is, for a heap h such that H h, exactly equal to H.
Lemma hexists_named_eq : ∀ H,
H = (\∃ h, \[H h] \* (= h)).
Proof using. (* FILL IN HERE *) Admitted.
☐
H = (\∃ h, \[H h] \* (= h)).
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 1 star, standard, optional (hoare_named_heap)
Prove that the proposition hoare t H Q is equivalent to: for any heap h satisfying the precondition H, the Hoare triple whose precondition requires the input heap to be exactly equal to h, and whose postcondition is Q holds.
Lemma hoare_named_heap : ∀ t H Q,
(∀ h, H h → hoare t (= h) Q) →
hoare t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
(∀ h, H h → hoare t (= h) Q) →
hoare t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
Exercise: 3 stars, standard, optional (triple_named_heap)
Prove the counterpart of hoare_named_heap for Separation Logic triples.
Lemma triple_named_heap : ∀ t H Q,
(∀ h, H h → triple t (= h) Q) →
triple t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
(∀ h, H h → triple t (= h) Q) →
triple t H Q.
Proof using. (* FILL IN HERE *) Admitted.
☐
Traditional papers on Separation Logic do not include triple_hexists,
but instead a rule called triple_hexists2 that includes an existential
quantifier both in the precondition and the postcondition.
As we show next, in the presence of the consequence rule,
the two rules are equivalent.
The formulation of triple_hexists is not only more concise, it is
also better suited for practical applications.
Lemma triple_hexists2 : ∀ A (Hof:A→hprop) (Qof:A→val→hprop) t,
(∀ x, triple t (Hof x) (Qof x)) →
triple t (\∃ x, Hof x) (fun v ⇒ \∃ x, Qof x v).
Proof using.
introv M.
applys triple_hexists. intros x.
applys triple_conseq (M x).
{ applys himpl_refl. }
{ intros v. applys himpl_hexists_r x. applys himpl_refl. }
Qed.
Lemma triple_hexists_of_triple_hexists2 : ∀ t (A:Type) (Hof:A→hprop) Q,
(∀ x, triple t (Hof x) Q) →
triple t (\∃ x, Hof x) Q.
Proof using.
introv M.
applys triple_conseq (\∃ x, Hof x) (fun (v:val) ⇒ \∃ (x:A), Q v).
{ applys triple_hexists2. intros x. applys M. }
{ applys himpl_refl. }
{ intros v. applys himpl_hexists_l. intros _. applys himpl_refl. }
Qed.
End AlternativeExistentialRule.
(∀ x, triple t (Hof x) (Qof x)) →
triple t (\∃ x, Hof x) (fun v ⇒ \∃ x, Qof x v).
Proof using.
introv M.
applys triple_hexists. intros x.
applys triple_conseq (M x).
{ applys himpl_refl. }
{ intros v. applys himpl_hexists_r x. applys himpl_refl. }
Qed.
Lemma triple_hexists_of_triple_hexists2 : ∀ t (A:Type) (Hof:A→hprop) Q,
(∀ x, triple t (Hof x) Q) →
triple t (\∃ x, Hof x) Q.
Proof using.
introv M.
applys triple_conseq (\∃ x, Hof x) (fun (v:val) ⇒ \∃ (x:A), Q v).
{ applys triple_hexists2. intros x. applys M. }
{ applys himpl_refl. }
{ intros v. applys himpl_hexists_l. intros _. applys himpl_refl. }
Qed.
End AlternativeExistentialRule.
Historical Notes
(* 2022-09-20 16:51 *)