Zulip Chat Archive
Stream: mathlib4
Topic: the identity matrix and decidable equality
Emily Riehl (Feb 18 2025 at 17:06):
For expository purposes, I've been trying to formalize a tiny bit of linear algebra, and I'm having some difficulties with the identity matrix.
Firstly, this must surely be in mathlib somewhere, but where is it?
In any case, it's nice sometimes to do something yourself, so I wrote this:
import Mathlib.Data.Matrix.Basic
open Matrix
variable (R : Type) [Field R]
variable (n : Type) [DecidableEq n] [Fintype n] [Inhabited n]
/-- The identity matrix. -/
def I : Matrix n n R := by
refine Matrix.of ?_
intro i j
cases (decEq i j)
· exact 0
· exact 1
This is my first time using decidable equality in Lean. Was this the right approach?
In particular, I can't seem to do anything with this definition. In particular, I'm unable to prove that I R n i j = I R n j i
for i j : n
e.g. by case splitting on whether or not i = j
.
Riccardo Brasca (Feb 18 2025 at 17:08):
1 : Matrix _ _ _
should work.
Floris van Doorn (Feb 18 2025 at 17:09):
Emily Riehl said:
This is my first time using decidable equality in Lean. Was this the right approach?
You can also use the tactic by_cases h : i = j
Floris van Doorn (Feb 18 2025 at 17:10):
IIRC that uses a decidability proof if there is one, otherwise uses classical principles.
Riccardo Brasca (Feb 18 2025 at 17:10):
In general defining data in tactic mode is not a very good idea. I would do something like
def I : Matrix n n R := Matrix.of (fun i j ↦ if i = j then 0 else 1)
Floris van Doorn (Feb 18 2025 at 17:11):
True, my comments works, but for definitions Riccardo's suggestion is better.
Floris van Doorn (Feb 18 2025 at 17:11):
(if the 1 and 0 are swapped)
Riccardo Brasca (Feb 18 2025 at 17:13):
import Mathlib
variable (R : Type) [Field R]
variable (n : Type) [DecidableEq n]
def I : Matrix n n R := Matrix.of (fun i j ↦ if i = j then 1 else 0)
example (i j : n) : I R n i j = I R n j i := by
dsimp only [I]
aesop
Emily Riehl (Feb 18 2025 at 17:17):
Thanks for the suggestions. It's great that aesop can prove this but I want to be able to prove it too!
Right now I'm trying (using @Riccardo Brasca's definition):
theorem one : I R n = 1 := by
ext i j
unfold I
by_cases h : i = j
· sorry
· sorry
Riccardo Brasca (Feb 18 2025 at 17:18):
Concerning DecidableEq
, the rule of thumb is: if it's needed in a statement or in a def add it as you did. If it is needed in a proof just start the proof by classical
and Lean should find it automatically.
Emily Riehl (Feb 18 2025 at 17:19):
When I use the if .. then .. else
in a def and I have either the first hypothesis or its negation how do I reduce that def to the appropriate case?
Riccardo Brasca (Feb 18 2025 at 17:19):
simp
usually does it
Emily Riehl (Feb 18 2025 at 17:21):
Blerg. Actually the reason I was stuck was I copied your first definition which has a typo.
Riccardo Brasca (Feb 18 2025 at 17:21):
Ops, sorry!
Emily Riehl (Feb 18 2025 at 17:22):
Lol. Serves me right for not being careful.
So simp
is best practice to reduce an if .. then .. else
?
Edward van de Meent (Feb 18 2025 at 17:23):
i tend to do rw [if_pos h]
or rw [if_neg h]
Edward van de Meent (Feb 18 2025 at 17:24):
also note docs#dif_pos and docs#dif_neg for the dependent version
Riccardo Brasca (Feb 18 2025 at 17:29):
I am a little bit sad that simp [h]
does not work in the first case.
import Mathlib
variable (R : Type) [Field R]
variable (n : Type) [DecidableEq n]
def I : Matrix n n R := Matrix.of (fun i j ↦ if i = j then 1 else 0)
theorem one : I R n = 1 := by
ext i j
unfold I
by_cases h : i = j
· rw [h]
simp
· simp [h]
Emily Riehl (Feb 18 2025 at 17:33):
Weirdly by_cases h : i = j <;> rfl
works, though.
Regarding @Edward van de Meent's suggestion is this supposed to follow a by_cases h : i = j
? Because I'm getting an error
tactic 'rewrite' failed, did not find instance of the pattern in the target expression
if i = j then ?m.2305 else ?m.2306
even though it looks like it's there to me.
Riccardo Brasca (Feb 18 2025 at 17:36):
rfl
works because 1
is literally defined like that
Riccardo Brasca (Feb 18 2025 at 17:36):
I mean, theorem one : I R n = 1 := rfl
also works.
Riccardo Brasca (Feb 18 2025 at 17:36):
In particular it does nothing about the cases
Edward van de Meent (Feb 18 2025 at 17:38):
Emily Riehl said:
Weirdly
by_cases h : i = j <;> rfl
works, though.Regarding Edward van de Meent's suggestion is this supposed to follow a
by_cases h : i = j
? Because I'm getting an errortactic 'rewrite' failed, did not find instance of the pattern in the target expression if i = j then ?m.2305 else ?m.2306
even though it looks like it's there to me.
the fix seems to be to do rw [Matrix.of_apply]
before the cases, as there technically wasn't an appropriate pattern in the goal.
Edward van de Meent (Feb 18 2025 at 17:39):
i.e. the goal contains (Matrix.of (fun x y => if x = y then 1 else 0)) i j
, which is not reducibly defeq to if i = j then 1 else 0
, i think
Riccardo Brasca (Feb 18 2025 at 17:40):
Edward van de Meent said:
i.e. the goal contains
(Matrix.of (fun x y => if x = y then 1 else 0)) i j
, which is not reducibly defeq toif i = j then 1 else 0
, i think
Yes,
theorem one : I R n = 1 := by
with_reducible rfl
does not work.
Riccardo Brasca (Feb 18 2025 at 17:41):
@Emily Riehl my personal opinion is that, if you're doing mathematics and you don't want to enter into such technicalities, simp [h]
in practice works well.
Emily Riehl (Feb 18 2025 at 17:43):
Thanks. This works now
theorem one : I R n = 1 := by
ext i j
unfold I
rw [Matrix.of_apply]
by_cases h : i = j
· rw [if_pos h, h]
simp
· rw [if_neg h]
simp [h]
as does
theorem one : I R n = 1 := by
ext i j
unfold I
rw [Matrix.of_apply]
by_cases h : i = j <;> rfl
Emily Riehl (Feb 18 2025 at 17:47):
Riccardo Brasca said:
Emily Riehl my personal opinion is that, if you're doing mathematics and you don't want to enter into such technicalities,
simp [h]
in practice works well.
It bothers me, though, that I still can't do very basic things in Lean because there are a lot of tactics I don't know (eg the if .. then .. else
, which I've never used before, or case splitting over decidable equality). When things that I'm expecting to work (like rw
or simp
) get stuck then I'm very stuck.
Emily Riehl (Feb 18 2025 at 17:48):
Anyway I appreciate your help!
Riccardo Brasca (Feb 18 2025 at 17:49):
DecidableEq
is rather simple. Just ignore it until Lean complains, and add it if needed (unless you want to write an algorithm that actually computes stuff, then you have to pay attention).
Emily Riehl (Feb 18 2025 at 17:58):
And actually --- more to the point this time --- I'm trying to prepare a sample proof for a talk for a non-math audience that illustrates what a formal proof looks like. So I'm trying to use more basic (read "human understandable") tactics.
Edward van de Meent (Feb 18 2025 at 18:00):
if you'd like to have a purely syntactic proof:
theorem one : I R n = 1 := by
ext i j
unfold I
rw [Matrix.of_apply]
by_cases h : i = j
· rw [if_pos h, h, Matrix.one_apply_eq]
· rw [if_neg h, Matrix.one_apply_ne h]
Floris van Doorn (Feb 18 2025 at 18:25):
If you have a subterm if ... then ... else ...
in your goal (or hypotheses) you can also use the tactics split
or split_ifs
(which are similar)
Kevin Buzzard (Feb 18 2025 at 23:52):
Here's my effort:
import Mathlib
variable (R : Type) [Field R]
variable (n : Type) [DecidableEq n]
def I : Matrix n n R := Matrix.of (fun i j ↦ if i = j then 1 else 0)
theorem one : I R n = 1 := by
unfold I
ext i j
-- look near the definition of `Matrix.one` in mathlib to see what the useful
-- lemmas are called
simp [Matrix.one_apply]
I was expecting to have to use split_ifs
but I found the right lemma in the API.
Eric Wieser (Feb 19 2025 at 00:21):
of course, there's always
theorem one : I R n = 1 := by exact? -- rfl
which makes this not so ideal as a pedagogical example
Last updated: May 02 2025 at 03:31 UTC