The Bove-Cappretta method
From Equations Require Import Equations.
Require Import Arith Lia Relations Utf8.
Import Sigma_Notations.
The graph of the f91 function.
Inductive f91_graph : nat → nat → Prop :=
| f91_gt n : n > 100 → f91_graph n (n - 10)
| f91_le n nest res :
n ≤ 100 → f91_graph (n + 11) nest →
f91_graph nest res →
f91_graph n res.
Derive Signature for f91_graph.
It is easy to derive the spec of f91 from it, by induction.
Lemma f91_spec n m : f91_graph n m → if le_lt_dec n 100 then m = 91 else m = n - 10.
Proof.
induction 1; repeat destruct le_lt_dec; try lia; auto.
Qed.
(* Do not simpl the (101 - n) call *)
Arguments minus : simpl never.
Proof.
induction 1; repeat destruct le_lt_dec; try lia; auto.
Qed.
(* Do not simpl the (101 - n) call *)
Arguments minus : simpl never.
One can construct the graph using a (relatively) complex termination argument.
Note that it is required to know that the result is in the graph to show
termination at the second, nested recursive call to f91_exists.
Equations? f91_exists n : Σ r, f91_graph n r by wf (101 - n) lt :=
f91_exists n with le_lt_dec n 100 := {
| left H := ((f91_exists (f91_exists (n + 11)).1).1, _) ;
| right H := (n - 10, _) }.
Proof.
all:hnf. 2-3:edestruct f91_exists; cbn.
3:destruct f91_exists. lia.
apply f91_spec in pr2. destruct le_lt_dec; subst; lia.
econstructor 2; eauto. constructor. lia.
Defined.
Combining these two things allow us to derive the spec of f91.
Lemma f91 n : (f91_exists n).1 = if le_lt_dec n 100 then 91 else n - 10.
Proof.
destruct f91_exists. simpl. generalize (f91_spec _ _ pr2).
destruct le_lt_dec; auto.
Qed.
Proof.
destruct f91_exists. simpl. generalize (f91_spec _ _ pr2).
destruct le_lt_dec; auto.
Qed.
This extracts to f91.
(* Extraction f91_exists. *)
An alternative is to use the domain of f91 instead,
which for nested recursive calls requires a quantification
on the graph relation.
Inductive f91_dom : nat → Prop :=
| f91_dom_gt n : n > 100 → f91_dom n
| f91_dom_le n :
n ≤ 100 → f91_dom (n + 11) →
(∀ n', f91_graph (n + 11) n' → f91_dom n') →
f91_dom n.
Lemma le_nle n : n ≤ 100 → 100 < n → False.
Proof. lia. Qed.
These two structural inversion lemmas are essential: we rely on the fact
that they return subterms of their prf argument below to define f91_ongraph
by structural recursion.
Equations f91_dom_le_inv_l {n} (prf : f91_dom n) (Hle : n ≤ 100) : f91_dom (n + 11) :=
| f91_dom_gt n H | Hle := ltac:(elimtype False; eauto using le_nle);
| f91_dom_le n H Hd Hg | Hle := Hd.
Equations f91_dom_le_inv_r {n} (prf : f91_dom n) (Hle : n ≤ 100) : (∀ n', f91_graph (n + 11) n' → f91_dom n') :=
| f91_dom_gt n H | Hle := ltac:(elimtype False; eauto using le_nle);
| f91_dom_le n H Hd Hg | Hle := Hg.
Module WithSigma.
In this case, f91_ongraph is recursive on the domain proof, but only does
inversion of it, not direct pattern-matching which would be forbidden as it
lives in Prop.
Equations? f91_ongraph n (prf : f91_dom n) : Σ r, f91_graph n r by struct prf :=
f91_ongraph n prf with le_lt_dec n 100 :=
{ | left H ⇒ ((f91_ongraph (f91_ongraph (n + 11) _).1 _).1, _);
| right H ⇒ (n - 10, _) }.
Proof.
clear f91_ongraph.
destruct prf. elimtype False; lia.
apply prf.
destruct f91_ongraph. clear f91_ongraph. simpl. eapply f91_dom_le_inv_r in prf; eauto.
destruct f91_ongraph. simpl in ×.
destruct f91_ongraph. clear f91_ongraph. simpl in ×.
econstructor 2; eauto.
constructor. lia.
Defined.
The proof witness f91_dom n disappears at extraction time.
But the polymorphic sigma type makes it leave a dummy unit value
on the side.
Same thing with a subset type for cleaner extraction. We use Program Mode to
avoid explicit projections/injections into subset types.
Set Program Mode.
Equations? f91_ongraph n (prf : f91_dom n) : { r | f91_graph n r } by struct prf :=
f91_ongraph n prf with le_lt_dec n 100 :=
{ | left H ⇒ f91_ongraph (f91_ongraph (n + 11) _) _;
| right H ⇒ n - 10 }.
Proof.
clear f91_ongraph.
destruct prf. elimtype False; lia.
apply prf.
destruct f91_ongraph. clear f91_ongraph. simpl. eapply f91_dom_le_inv_r in prf; eauto.
destruct f91_ongraph. simpl in ×.
destruct f91_ongraph. clear f91_ongraph. simpl in ×.
econstructor 2; eauto.
constructor. lia.
Defined.
Lemma f91_ongraph_spec n dom : proj1_sig (f91_ongraph n dom) = if le_lt_dec n 100 then 91 else n - 10.
Proof.
destruct f91_ongraph. simpl. generalize (f91_spec _ _ f).
destruct le_lt_dec; auto.
Qed.
All proof witnesses f91_dom n and f91_graph n r disappear at extraction time, giving
the "real" f91 implementation.
This page has been generated by coqdoc