Zulip Chat Archive

Stream: lean4

Topic: Proof of inverse


Scott Godwin (May 02 2023 at 00:20):

I'm trying to prove that a function is an inverse of another one, but I'm getting stuck trying to do a rw or simplifying the goal. What I have is:

inductive Foo where
  | foo₁
  | foo₂

inductive Bar : List Foo  Foo  Type where
  | here {fs : List Foo} {f : Foo} : Bar (f :: fs) f
  | there {fs : List Foo} {f₁ f₂ : Foo} : Bar fs f₂  Bar (f₁ :: fs) f₂

def from_fin : (fs : List Foo)  Fin fs.length  Σ f : Foo, Bar fs f
  | f :: _, 0, _ => f, Bar.here
  | _ :: fs, Nat.succ n, lt =>
      let f, b := from_fin fs n, Nat.lt_of_succ_lt_succ lt
      f, Bar.there b

def to_fin {fs : List Foo} {f : Foo} : (Bar fs f)  Fin fs.length
  | .here => 0, Nat.zero_lt_succ _
  | .there b => (to_fin b).succ

theorem inverse {fs : List Foo} {f : Foo} (b : Bar fs f) : from_fin fs (to_fin b) = f, b := by
  cases b with
  | here => rfl
  | there b =>
      have h := inverse b

      simp [to_fin, Fin.succ, from_fin]

      -- This is what I want to do, but it causes `tactic 'rewrite' failed, motive is not type correct`
      -- rw [Nat.add_zero (to_fin b).val]
      -- rw [h]

      -- Tried a different approach
      congr
      . simp; rw [h]
      . simp; rw [h]
      . -- `simp` doesn't work here nor does a direct `rw` or `subst`
        rw [Nat.add_zero (to_fin b).val]
        sorry

The goal seems trivially true, but I don't know how I can do the rewrite (since it says it's not "type correct") to use the inductive hypothesis. Any suggestions?

Mario Carneiro (May 02 2023 at 00:56):

kind of a silly solution, but this works:

theorem inverse {fs : List Foo} {f : Foo} (b : Bar fs f) : from_fin fs (to_fin b) = f, b := by
  cases b with
  | here => rfl
  | @there fs f₁ _ b =>
    show (let f, b := from_fin fs to_fin b, _; (⟨f, Bar.there b : Sigma _)) = _
    rw [inverse b]

Scott Godwin (May 02 2023 at 01:15):

Thanks! I'll admit I'm a bit confused why that works but the other approaches didn't. If I understand it correctly, show normalizes both the goal and the given term and unifies them. But that would require it to normalize (to_fin b).val + 0 to (to_fin b).val which, while obvious, isn't being normalized when using simp, rw, and subst

Mario Carneiro (May 02 2023 at 01:21):

show doesn't normalize anything, it changes the goal to a specified term and unifies it with the goal. The key advantage it has over dsimp and unfold and the like is that you are giving explicitly where you want to end up, rather than what procedure you want to apply. The issue with those other methods is that they don't produce a goal which has the LHS of inverse b syntactically within them

Mario Carneiro (May 02 2023 at 01:22):

note that it is important to use only definitional rewriting tactics here (like dsimp over simp), because your goal has a dependent function and so non-definitional rewrites are either not going to apply or will result in a type incorrect term

Mario Carneiro (May 02 2023 at 01:25):

the presence of the let ⟨f, b⟩ := ...; ⟨f, Bar.there b⟩ in the definition is messing up dsimp and making it try the wrong thing


Last updated: Dec 20 2023 at 11:08 UTC