Built with Alectryon, running vsrocq-language-server v9.4+alpha 5.4.1 / 2.5.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.
(** Lesson 3 -- The structural argument is a proof. (About 30 minutes.) Read after L02_Obligations.v. Keep the Preterm output nearby. We inspect the actual Corelib recursor used in that term and build the evidence package for the same [then] call, one piece at a time.*)From Corelib Require Import Init.Nat Program.Wf.From TerminationStudy Require Import Euclid.Set Guard Checking.SetUniverseChecking.(** Read [Acc R x] as: from [x], every [R]-smaller state is accessible. The constructor holds a function producing the child proofs. The orientation is [R child parent]. *)
InductiveAcc (A : Type) (R : A -> A -> Prop) (x : A) : Prop :=
Acc_intro : (forally : A, R y x -> Acc R y) -> Acc R x.
Arguments Acc [A]%_type_scope R%_function_scope x
Arguments Acc_intro [A]%_type_scope [R]%_function_scope x _%_function_scope
Acc_inv =
fun (A : Type) (R : A -> A -> Prop) (x : A) (H : Acc R x) =>
match H with
| Acc_intro _ x0 => (funH0 : forally : A, R y x -> Acc R y => H0) x0
end
: forall [A : Type] [R : A -> A -> Prop] [x : A],
Acc R x -> forall [y : A], R y x -> Acc R y
Arguments Acc_inv [A]%_type_scope [R]%_function_scope
[x] _ [y] _, [_] [_] [_] _ _ _
well_founded =
fun (A : Type) (R : A -> A -> Prop) => foralla : A, Acc R a
: forall [A : Type], (A -> A -> Prop) -> PropArguments well_founded [A]%_type_scope R%_function_scope
(** [well_founded R] supplies [Acc R x] for EVERY starting state [x]. A decrease proof establishes one edge. Well-foundedness supplies the accessibility proof with which the recursion starts. Program packs our two inputs in a dependent pair [sigT], even though the second input's type is simply [nat]. This is the same shape as Lesson 2's [recarg : {a : nat & nat}]. *)DefinitionState : Type := {a : nat & nat}.Definitionpack (ab : nat) : State := existT (fun_ : nat => nat) a b.Definitionweight (x : State) : nat := projT1 x + projT2 x.Definitionsmaller (childparent : State) : Prop :=
weight child < weight parent.
smaller = MR lt weight
smaller = MR lt weight
reflexivity.Qed.(** Spell out the [then] call from parent (S a', S b'). The inner [existT] packages its two numbers. The outer [exist] packages that state WITH its decrease proof. These are different jobs. *)Definitionright_call (a'b' : nat) :
{child : State | smaller child (pack (S a') (S b'))} :=
exist _ (pack (S a') (S b' - S a'))
(TerminationFacts.subtract_right_decreases a' b').
right_call
: foralla'b' : nat,
{child : State | smaller child (pack (S a') (S b'))}
= existT (fun_ : nat => nat) 1830
: State
(* The state (18,48) calls (18,30); its measure goes from 66 to 48. *)
= 66
: nat
= 48
: nat
(** A spelling of the same global justification as obligation 4. No new arithmetic proof is needed: lift well-founded [lt] along weight. *)Definitionstates_accessible : well_founded smaller :=
@measure_wf State nat lt TerminationFacts.nat_lt_wf weight.(** The critical connection: use the EXACT proof carried by this call to obtain an accessibility proof for its EXACT next state. *)Definitionright_child_accessible (a'b' : nat)
(parent_proof : Acc smaller (pack (S a') (S b'))) :
Acc smaller (proj1_sig (right_call a' b')) :=
Acc_inv parent_proof (proj2_sig (right_call a' b')).
right_child_accessible
: foralla'b' : nat,
Acc smaller (pack (S a') (S b')) ->
Acc smaller (proj1_sig (right_call a' b'))
Fetching opaque proofs from disk for Corelib.Init.Peano
Closed under the globalcontext
Closed under the globalcontext
(** Now inspect the library definitions, rather than guessing which recursor Program uses. Look for [{struct r}] in [Fix_F_sub]. *)
Fix_sub =
fun (A : Type) (R : A -> A -> Prop) (Rwf : well_founded R)
(P : A -> Type)
(F_sub : forallx : A, (forally : {y : A | R y x}, P (proj1_sig y)) -> P x)
(x : A) =>
Fix_F_sub A R P F_sub x (Rwf x)
: forall (A : Type) (R : A -> A -> Prop),
well_founded R ->
forallP : A -> Type,
(forallx : A, (forally : {y : A | R y x}, P (proj1_sig y)) -> P x) ->
forallx : A, P x
Arguments Fix_sub A%_type_scope R%_function_scope
Rwf (P F_sub)%_function_scope x
Fix_F_sub =
fun (A : Type) (R : A -> A -> Prop) (P : A -> Type)
(F_sub : forallx : A, (forally : {y : A | R y x}, P (proj1_sig y)) -> P x) =>
fix Fix_F_sub (x : A) (r : Acc R x) {struct r} : P x :=
F_sub x
(funy : {y : A | R y x} =>
Fix_F_sub (proj1_sig y) (Acc_inv r (proj2_sig y)))
: forall (A : Type) (R : A -> A -> Prop) (P : A -> Type),
(forallx : A, (forally : {y : A | R y x}, P (proj1_sig y)) -> P x) ->
forallx : A, Acc R x -> P x
Arguments Fix_F_sub A%_type_scope (R P F_sub)%_function_scope x r
(** At [theories/Corelib/Program/Wf.v:27] the recursive call is: Fix_F_sub (proj1_sig y) (Acc_inv r (proj2_sig y)) Unfold [Acc_inv]: matching [r = Acc_intro ... children] exposes [children], and [children child decrease] is a structurally smaller accessibility proof. The state itself need not be a syntactic subterm. The existing guard checker recognizes this recursion on [r]. The following equality checks one actual unfolding of the library recursor. Section variables become explicit parameters on closing the section; they introduce no global axioms. *)SectionOneUnfolding.VariableA : Type.VariableR : A -> A -> Prop.VariableP : A -> Type.Variablebody : forallx : A,
(forally : {child : A | R child x}, P (proj1_sig y)) -> P x.
A: Type R: A -> A -> Prop P: A -> Type body: forallx : A, (forally : {child : A | R child x}, P (proj1_sig y)) -> P x x: A children: forallchild : A, R child x -> Acc R child
Fix_F_sub A R P body x (Acc_intro x children) =
body x
(funy : {child : A | R child x} =>
Fix_F_sub A R P body (proj1_sig y) (children (proj1_sig y) (proj2_sig y)))
A: Type R: A -> A -> Prop P: A -> Type body: forallx : A, (forally : {child : A | R child x}, P (proj1_sig y)) -> P x x: A children: forallchild : A, R child x -> Acc R child
Fix_F_sub A R P body x (Acc_intro x children) =
body x
(funy : {child : A | R child x} =>
Fix_F_sub A R P body (proj1_sig y) (children (proj1_sig y) (proj2_sig y)))
reflexivity.Qed.EndOneUnfolding.
Closed under the globalcontext
(** [Acc] lives in Prop, but its singleton-elimination permission allows this recursion to return values in Type (here, nat). Inspect the actual generated eliminator; an arbitrary proposition does not enjoy this permission. [Init/Wf.v:31] documents this point. *)
Acc_rect
: forall (A : Type) (R : A -> A -> Prop) (P : A -> Type),
(forallx : A,
(forally : A, R y x -> Acc R y) ->
(forally : A, R y x -> P y) -> P x) ->
forallx : A, Acc R x -> P x
(** Checkpoint: 1. Identify the two projections from [right_call]: state and proof. 2. What supplies the initial [r]? What supplies the child's [r]? 3. Is [a + b] the structural argument of [Fix_F_sub]? 4. Did proving the decrease replace the guard checker? Answer cues: [proj1_sig]/[proj2_sig]; well-foundedness/[Acc_inv]; no, [r] is the structural argument; no, the evidence enables a construction accepted by that checker. This is not yet an opacity experiment: the one-step equality above explicitly provides a visible [Acc_intro]. We have not established which opaque proofs would block a particular reduction strategy. Next: L04_Admission.v -- connect these pieces to the installed term.*)