Zulip Chat Archive

Stream: general

Topic: Fix induction


Bolton Bailey (Feb 18 2022 at 00:35):

Looking at the recursion principle for the fixpoint operator docs#fix_induction, we have

def fix_induction
  {f : α →. β  α} {b : β} {C : α  Sort*} {a : α} (h : b  f.fix a)
  (H :  a', b  f.fix a' 
    ( a'', b  f.fix a''  sum.inr a''  f a'  C a'')  C a') : C a

It seems like an easier to understand and more useful principle would be

lemma inheriting_from_chains
  (f : α →. β  α) (b : β) {C : α  Sort*} {a : α} (h : b  f.fix a)
  (hbase : ( a_final : α, sum.inl b  f a_final -> C a_final))
  (hind : ( a_0 a_1 : α, sum.inr a_1  f a_0 -> C a_1 -> C a_0)) : C a

But I'm finding it hard to prove the latter from the former. Is there a particular reason why the latter isn't provided?

Yaël Dillies (Feb 18 2022 at 00:37):

This is a very @Mario Carneiro question.

Bolton Bailey (Feb 18 2022 at 00:38):

Yeah, I guess I'm thrown for a loop by this forall within an implication within a forall in a hypothesis. I have a hard time even getting it straight in my head what the first lemma is saying.

Bolton Bailey (Feb 18 2022 at 00:39):

Note that I've edited it to remove the reuse of the variable a.

Yaël Dillies (Feb 18 2022 at 00:39):

I remember writing the docstring for that recursor. Although I didn't end up saying much, I think I understood it at some point.

Yaël Dillies (Feb 18 2022 at 00:42):

Okay so the problem I see with your recursor is that it requires too strong of an hypothesis. It asks for stuff about branches that never fix.

Bolton Bailey (Feb 18 2022 at 00:44):

Ok, can you give me an example of something you can prove with the first one but not the second?

Yaël Dillies (Feb 18 2022 at 00:44):

No, the opposite.

Yaël Dillies (Feb 18 2022 at 00:45):

Or are you telling you managed to prove inheriting_from_chains from fix_induction? I think that's impossible.

Bolton Bailey (Feb 18 2022 at 00:46):

I haven't managed to prove the second one, but I think it's true and I want it

Bolton Bailey (Feb 18 2022 at 00:47):

At first I thought I would be able to prove it from induction_fix by just using a bunch of apply statements, but somehow I can't

Yaël Dillies (Feb 18 2022 at 00:47):

Argh sorry I am the one who is confused. inheriting_from_chains is certainly true, but you can't prove fix_induction from it.

Bolton Bailey (Feb 18 2022 at 00:47):

Ok, I believe you but I don't see why

Eric Rodriguez (Feb 18 2022 at 00:48):

I think Bolton wants to go the other way round, Yael

Yaël Dillies (Feb 18 2022 at 00:48):

Yeah, and I think this is possible.

Bolton Bailey (Feb 18 2022 at 00:48):

Right, I would like to prove inheriting _from_chains using fix_induction

Bolton Bailey (Feb 18 2022 at 00:49):

Hmm, maybe I need to use mem_fix_iff?

Bolton Bailey (Feb 18 2022 at 00:51):

lemma inheriting_predicates
  (f : α →. β  α) (b : β) {C : α  Sort*} {a : α} (h : b  f.fix a)
  (hbase : ( a_final : α, sum.inl b  f a_final -> C a_final))
  (hind : ( a_0 a_1 : α, sum.inr a_1  f a_0 -> C a_1 -> C a_0)) : C a :=
begin
  apply fix_induction h,
  intros a' hba' H,
  clear H,
  rw mem_fix_iff at hba',
  cases hba',-- induction tactic failed, recursor 'or.dcases_on' can only eliminate into Prop

end

Reid Barton (Feb 18 2022 at 00:52):

You have lemma ... : C a but C : α → Sort*--is that what you wanted?

Bolton Bailey (Feb 18 2022 at 00:53):

Well, I don't really care about proving it for Sorts, let me switch to Prop

Yaël Dillies (Feb 18 2022 at 00:53):

Probably C : α → Prop, because it won't be able to construct data anymore anyway.

Bolton Bailey (Feb 18 2022 at 00:58):

This is as far as I get Got it.

lemma inheriting_predicates
  (f : α →. β  α) (b : β) {C : α  Prop} {a : α} (h : b  f.fix a)
  (hbase : ( a_final : α, sum.inl b  f a_final -> C a_final))
  (hind : ( a_0 a_1 : α, sum.inr a_1  f a_0 -> C a_1 -> C a_0)) : C a :=
begin
  apply fix_induction h,
  intros a' hba' H,
  -- clear H,
  rw mem_fix_iff at hba',
  cases hba',
  { apply hbase, exact hba', },
  { rcases hba',
    apply hind a' hba'_w,
    exact hba'_h.left,
    apply H,
    exact hba'_h.right,
    exact hba'_h.left, },
end

Bolton Bailey (Feb 18 2022 at 01:08):

(I'm dumb, you actually do need H)

Bolton Bailey (Feb 18 2022 at 01:14):

Now for my own edification: Why is it impossible to prove fix_induction from inheriting_from_chains?

Bolton Bailey (Feb 18 2022 at 01:15):

Or is it only that inheriting uses Prop?

Mario Carneiro (Feb 18 2022 at 01:29):

I think they are equivalent

Mario Carneiro (Feb 18 2022 at 01:52):

Proving the reverse direction is annoying because you don't have the b ∈ f.fix a' assumption in the hypotheses

Mario Carneiro (Feb 18 2022 at 01:58):

import data.pfun

namespace pfun
variables {α β : Type*}

@[elab_as_eliminator]
def inheriting_from_chains
  (f : α →. β  α) (b : β) {C : α  Sort*} {a : α} (h : b  f.fix a)
  (hbase : ( a_final : α, sum.inl b  f a_final -> C a_final))
  (hind : ( a_0 a_1 : α, sum.inr a_1  f a_0 -> C a_1 -> C a_0)) : C a :=
begin
  refine fix_induction h (λ a' h ih, _),
  cases e : (f a').get (dom_of_mem_fix h) with b' a''; replace e : _  f a' := _, e⟩,
  { have : b' = b,
    { obtain h'' | a, h'', _ := mem_fix_iff.1 h; cases part.mem_unique e h'', refl },
    subst this, exact hbase _ e },
  { have : b  f.fix a'',
    { obtain h'' | a, h'', e' := mem_fix_iff.1 h; cases part.mem_unique e h'', exact e' },
    refine hind _ _ e (ih _ this e) },
end

@[elab_as_eliminator]
def fix_induction'
  {f : α →. β  α} {b : β} {C : α  Sort*} {a : α} (h : b  f.fix a)
  (H :  a', b  f.fix a' 
    ( a'', b  f.fix a''  sum.inr a''  f a'  C a'')  C a') : C a :=
begin
  have := h, revert this,
  refine inheriting_from_chains _ _ h (λ a' h _, _) (λ a' a'' h ih h', _),
  { refine H _ (mem_fix_iff.2 (or.inl h)) (λ a₂ _ h₂, _),
    cases part.mem_unique h h₂ },
  { refine H _ h' (λ a₂ h₂ e, _),
    cases part.mem_unique h e,
    apply ih,
    obtain h'' | a, h'', e' := mem_fix_iff.1 h'; cases part.mem_unique h h'', exact e' },
end

end pfun

Mario Carneiro (Feb 18 2022 at 01:59):

There should probably be a simpler to use version of mem_fix_iff in the case where you know f has a next element

Mario Carneiro (Feb 18 2022 at 02:05):

Here's a version that adds the fix assumption in inheriting_from_chains:

import data.pfun

namespace pfun
variables {α β : Type*}

@[elab_as_eliminator]
def inheriting_from_chains
  (f : α →. β  α) (b : β) {C : α  Sort*} {a : α} (h : b  f.fix a)
  (hbase : ( a_final : α, sum.inl b  f a_final  C a_final))
  (hind : ( a_0 a_1 : α, b  f.fix a_1  sum.inr a_1  f a_0  C a_1  C a_0)) : C a :=
begin
  refine fix_induction h (λ a' h ih, _),
  cases e : (f a').get (dom_of_mem_fix h) with b' a''; replace e : _  f a' := _, e⟩,
  { have : b' = b,
    { obtain h'' | a, h'', _ := mem_fix_iff.1 h; cases part.mem_unique e h'', refl },
    subst this, exact hbase _ e },
  { have : b  f.fix a'',
    { obtain h'' | a, h'', e' := mem_fix_iff.1 h; cases part.mem_unique e h'', exact e' },
    refine hind _ _ this e (ih _ this e) },
end

@[elab_as_eliminator]
def fix_induction'
  {f : α →. β  α} {b : β} {C : α  Sort*} {a : α} (h : b  f.fix a)
  (H :  a', b  f.fix a' 
    ( a'', b  f.fix a''  sum.inr a''  f a'  C a'')  C a') : C a :=
begin
  refine inheriting_from_chains _ _ h (λ a' h, _) (λ a' a'' h' h ih, _),
  { refine H _ (mem_fix_iff.2 (or.inl h)) (λ a₂ _ h₂, _),
    cases part.mem_unique h h₂ },
  { refine H _ (mem_fix_iff.2 (or.inr _, h, h'⟩)) (λ a₂ h₂ e, _),
    cases part.mem_unique h e,
    exact ih },
end

end pfun

Last updated: Dec 20 2023 at 11:08 UTC