Zulip Chat Archive

Stream: new members

Topic: Generalize proof of equality over given FinVec


Bernardo Borges (Nov 21 2024 at 18:51):

Hello everyone,
I'm trying to create a proof that all elements of my FinVec of tuples are zeros:

import Mathlib.Data.Fin.Tuple.Reflection

open FinVec

example :  (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) := by
  intro i
  -- Maybe something like
  -- cases' i <;> rfl
  match i with
  | 0 => rfl
  | 1 => rfl

As you can see, I just went through every value of this Fin 2 types to finish the proof. As you can see, this wouldn't scale for a Fin 100 vector and so on, and also won't allow me to create a general proof. Any suggestions on how to finish this one? Thanks

Bjørn Kjos-Hanssen (Nov 21 2024 at 18:58):

You can use fin_cases:

import Mathlib

example :  (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) := by
  intro i
  fin_cases i <;> rfl

Bernardo Borges (Nov 21 2024 at 18:59):

Yes this works, Thanks! I'm just wondering, is this "performance heavy"? As in, it'll take a long time to unify for larger Fin type?

Bernardo Borges (Nov 21 2024 at 19:05):

# The `fin_cases` tactic.

Given a hypothesis of the form `h : x  (A : List α)`, `x  (A : Finset α)`,
or `x  (A : Multiset α)`,
or a hypothesis of the form `h : A`, where `[Fintype A]` is available,
`fin_cases h` will repeatedly call `cases` to split the goal into
separate cases for each possible value.

Idk, this looked heavy to me

Bjørn Kjos-Hanssen (Nov 21 2024 at 19:15):

But do you really want to write ![(0, 0), (0, 0),(0, 0), (0, 0),(0, 0), (0, 0),(0, 0), (0, 0), (...a hundred entries...) ]? :smile:

Edward van de Meent (Nov 21 2024 at 19:20):

Bernardo Borges said:

and also won't allow me to create a general proof

indeed, but for that you first need a function to create these vectors for any given size. as soon as you do that, proving it becomes a lot simpler suddenly, as you get access to induction.

Bernardo Borges (Nov 21 2024 at 19:22):

What I really mean is that this doesnt work:

import Mathlib.Data.Fin.Tuple.Reflection
import Mathlib.Tactic.FinCases

open FinVec

example :  (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) := by
  intro i
  fin_cases i <;> rfl

def zerosVec : (n : )  Fin n  ( × )
| 0 => ![]
| (n+1) => Matrix.vecCons (0,0) (zerosVec n)

-- Works fine on constant n
#eval zerosVec 7
example :  (i : Fin 7), (zerosVec 7) i = (0, 0) := by
  intro i
  fin_cases i <;> rfl

-- Doesn't generalize really
example (n : Nat) :  (i : Fin n), (zerosVec n) i = (0, 0) := by
  intro i
  -- fin_cases i <;> rfl
-- tactic 'cases' failed, nested error:
-- dependent elimination failed, failed to solve equation
--   List.pmap Fin.mk (List.range n) ⋯ = i :: as✝
-- at case List.Mem.head
  sorry

Edward van de Meent (Nov 21 2024 at 19:22):

indeed. however, since you define it inductively, using induction actually becomes a better proof strategy.

Bernardo Borges (Nov 21 2024 at 19:23):

How can I apply induction on the zerosVec function?

Eric Wieser (Nov 21 2024 at 19:27):

This works:

import Mathlib.Data.Fin.Tuple.Reflection

open FinVec

def FinVec.const {α} (x : α) : (n : )  Fin n  α
  | 0 => ![]
  | (n + 1) => Matrix.vecCons x (FinVec.const x n)


def FinVec.const_eq {α} (x : α) : (n : )  FinVec.const x n = fun i => x
  | 0 => funext fun x => x.elim0
  | (n + 1) => funext <| by
    rw [Fin.forall_fin_succ]
    refine rfl, fun i => ?_⟩
    rw [const, FinVec.const_eq x n]
    rfl

example :  (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) := by
  intro i
  refine congr_fun (FinVec.const_eq _ 2) i

Edward van de Meent (Nov 21 2024 at 19:27):

you start with induction on n. then use Fin.induction on i.

Eric Wieser (Nov 21 2024 at 19:27):

(this is the general pattern used in Mathlib.Data.Fin.Tuple.Reflection)

Edward van de Meent (Nov 21 2024 at 19:28):

my solution:

Code

Eric Wieser (Nov 21 2024 at 19:30):

Even shorter:

example :  (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) := by
  exact congr_fun (FinVec.etaExpand_eq fun i => (0, 0))

Bernardo Borges (Nov 21 2024 at 19:39):

Very interesting. By using congr_fun did you prove that fun i => (0,0) is equal to the finvec above?

Eric Wieser (Nov 21 2024 at 19:40):

Well, rather I proved that using FinVec.etaExpand_eq fun i => (0, 0))

Eric Wieser (Nov 21 2024 at 19:41):

congr_fun just says "since the functions equal, their applications are equal"

Bernardo Borges (Nov 21 2024 at 19:44):

I've never seen this way to define the FinVec, it will surely be useful as well. i.e.

#eval @FinVec.etaExpand (Nat×Nat) 3 (λ _i => (0,0))

Bernardo Borges (Nov 21 2024 at 19:45):

The whole point of the proof, to get the forall expression
∀ (i : Fin 2), ![(0, 0), (0, 0)] i = (0, 0) boils down if I just had defined the vector this way

Eric Wieser (Nov 21 2024 at 19:49):

You should not actually use etaExpand for defining anything

Eric Wieser (Nov 21 2024 at 19:49):

It exists strictly for assembling proof tricks like the one I give above

Eric Wieser (Nov 21 2024 at 19:50):

Note that #eval (fun _i : Fin 3 => (0,0)) gives exactly the same output as what you wrote

Bernardo Borges (Nov 21 2024 at 20:40):

Understood!

Eric Wieser said:

You should not actually use etaExpand for defining anything


Last updated: May 02 2025 at 03:31 UTC