Zulip Chat Archive

Stream: new members

Topic: Complex Numbers in Matrices


Jake Jongejans (Feb 15 2024 at 11:52):

I am trying to get into proving identities concerning matrices and complex numbers and walked into quite a weird issue. This code works:

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

def Identity : Matrix (Fin 2) (Fin 2)  :=
  !![1, 0; 0, 1]

theorem HadamardSquared : Hadamard  Hadamard = 2  Identity :=
  by
    rw [Hadamard, Identity]
    simp [Matrix.mul_apply]
    rfl

As in, it simplifies to !![1, 0; 0, 1] and RFL is able to see that they are equivalent, while this code:

theorem vecHeadOfIMul (a b : ) : vecHead (I  ![a, b]) = I  a :=
  by
    simp [vecHead, Matrix.smul_apply]

theorem vecTailOfIMul (a b : ) : vecHead (vecTail (I  ![a, b])) = (I  b) :=
  by
    simp [vecTail, Matrix.smul_apply, vecHead]

theorem OnePlusOneEqTwo : 1 + 1 = 2 := rfl


def ComplexHadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, -I; I, -1]

def CIdentity : Matrix (Fin 2) (Fin 2)  :=
  !![1, 0; 0, 1]

theorem ComplexHadamardSquared : ComplexHadamard  ComplexHadamard = 2  CIdentity :=
  by
    rw [ComplexHadamard, CIdentity]
    simp [Matrix.mul_apply]
    rw [vecHeadOfIMul, vecTailOfIMul]
    simp [Matrix.smul_apply]
    -- rfl does not work due to the ℂ type
    rfl

also does give back !![1, 0; 0, 1], but rfl now doesn't work anymore. I am confident it is because the numbers used now are of the \C type instead of \Z, but I do not know how to deal with that yet. Any suggestions?

Riccardo Brasca (Feb 15 2024 at 12:18):

Yes, rfl is basically useless for complex numbers. Let me have a look, but in general norm_num can handle explicit equalities between complex numbers.

Riccardo Brasca (Feb 15 2024 at 12:19):

Also, can you provide a #mwe? With all the imports and stuff

Jake Jongejans (Feb 15 2024 at 12:25):

Thank you, Riccardo, norm_num actually works in my case. Do you happen to know whether I can use it for square root things, as well? I'd love to make my Hadamard normalised. Here's a MWE of the previous thing, btw.

import Mathlib.Data.Matrix.Basic
import Mathlib.Data.Matrix.Notation
import Mathlib.Data.Complex.Basic


namespace QuantumGates

open Real
open Matrix
open Complex

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

def Identity : Matrix (Fin 2) (Fin 2)  :=
  !![1, 0; 0, 1]

theorem HadamardSquared : Hadamard  Hadamard = 2  Identity :=
  by
    rw [Hadamard, Identity]
    simp [Matrix.mul_apply]
    rfl

theorem vecHeadOfIMul (a b : ) : vecHead (I  ![a, b]) = I  a :=
  by
    simp [vecHead, Matrix.smul_apply]

theorem vecTailOfIMul (a b : ) : vecHead (vecTail (I  ![a, b])) = (I  b) :=
  by
    simp [vecTail, Matrix.smul_apply, vecHead]

def ComplexHadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, -I; I, -1]

def CIdentity : Matrix (Fin 2) (Fin 2)  :=
  !![1, 0; 0, 1]

theorem ComplexHadamardSquared : ComplexHadamard  ComplexHadamard = 2  CIdentity :=
  by
    rw [ComplexHadamard, CIdentity]
    simp [Matrix.mul_apply]
    rw [vecHeadOfIMul, vecTailOfIMul]
    simp [Matrix.smul_apply]
    -- rfl does not work due to the ℂ type, thank you to Riccardo Brasca for the suggestion of using norm_num
    norm_num

Jake Jongejans (Feb 15 2024 at 12:26):

And is it possible to automatically simplify these vecTail and vecHead parts?

Yaël Dillies (Feb 15 2024 at 12:33):

No, norm_num currently does not handle square roots. There are ideas around, but nothing concrete yet.

Riccardo Brasca (Feb 15 2024 at 12:38):

I am not sure I understand your question. A few comments: first of all I get two errors in the code you posted above, when writing a #mwe please try to post code without errors (unless the question is why there is an error): sorry are of course fine, no problem in asking how to replace them with a proof. Also, you redefine the identity matrix, but you can use (1 : Matrix (Fin 2) (Fin 2)) and use the existent API.

Jake Jongejans (Feb 15 2024 at 12:58):

Thanks, Yaël. I'll have to follow the development on that, then.

Strange, I didn't get any errors in my own environment in VS Code. If I did, I would have fixed them on my end first, of course.
I am not quite sure how you intended me to use (1 : Matrix (Fin 2) (Fin 2)), to my mind it feels incomplete, requiring \Z after the second Fin 2. Do you intend for me to replace the Identity usage in my theorems (e.g. HadamardSquared) with this usage, or my definition of Identity?

Thank you for the help, I appreciate it :)

Yaël Dillies (Feb 15 2024 at 13:02):

Indeed Riccardo meant (1 : Matrix (Fin 2) (Fin 2) ℤ). You can use it anywhere you would have used CIdentity

Riccardo Brasca (Feb 15 2024 at 13:04):

Ops, sorry

Jake Jongejans (Feb 15 2024 at 13:13):

No worries. I don't get working code substituting this, sadly.

import Mathlib.Data.Matrix.Basic
import Mathlib.Data.Matrix.Notation
import Mathlib.Data.Complex.Basic

open Real
open Matrix
open Complex

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

theorem HadamardSquared : Hadamard  Hadamard = 2  (1 : Matrix (Fin 2) (Fin 2) ) :=
  by
    rw [Hadamard]  -- This gives me the goal: of ![![1, 1], ![1, -1]] • of ![![1, 1], ![1, -1]] = 2 • 1
    simp [Matrix.mul_apply]
    rfl

As annotated in the code, somehow, this notation is replaced with a single number instead of the I matrix. Is this intended behaviour?

Yaël Dillies (Feb 15 2024 at 13:16):

The number is the I matrix

Jake Jongejans (Feb 15 2024 at 13:23):

Oh, huh. That will get some taking use to.
The code doesn't solve the goal anymore—it now gets stuck at the goal of ![![2, 0], ![0, 2]] = 2 when I replace rfl with norm_num. Do I need to do something to allow comparison between ![![2, 0], ![0, 2]] and !![2, 0; 0, 2]?

Yaël Dillies (Feb 15 2024 at 13:25):

You shouldn't use ![![2, 0], ![0, 2]] as a matrix. That's a tuple of tuples, not a matrix. !![2, 0; 0, 2] is the correct syntax for matrices

Yaël Dillies (Feb 15 2024 at 13:26):

@Eric Wieser, do your reflection lemmas cover of ![![2, 0], ![0, 2]] = !![2, 0; 0, 2] and !![2, 0; 0, 2] = 2?

Eric Wieser (Feb 15 2024 at 13:27):

In the meantime we should add

theorem ofNat_fin_two (n : ) [n.AtLeastTwo] :
    (no_index (OfNat.ofNat) n : Matrix (Fin 2) (Fin 2) α) = !![OfNat.ofNat n, 0; 0, OfNat.ofNat n] := by

Jake Jongejans (Feb 15 2024 at 13:27):

That's what is generated by the simp, though. Not sure how I'd go about altering that, to be frank.

Eric Wieser (Feb 15 2024 at 13:27):

(Pr incoming)

Eric Wieser (Feb 15 2024 at 13:31):

#10592

Riccardo Brasca (Feb 15 2024 at 13:31):

Why are you using instead of *?

Riccardo Brasca (Feb 15 2024 at 13:32):

And maybe 2 : Matrix... is the matrix you want (but you should check it's not the matrix full of 2)

Riccardo Brasca (Feb 15 2024 at 13:32):

Ah ok, it's eric's PR

Riccardo Brasca (Feb 15 2024 at 13:34):

@Javernus you can add lemmas like

@[simp] lemma Hadamard_apply (j : Fin 2) : Hadamard j 0 = 1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply11 : Hadamard 1 1 = -1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply01 : Hadamard 0 1 = 1 := by simp [Hadamard]

so that simp becomes more powerful on your matrix.

Riccardo Brasca (Feb 15 2024 at 13:35):

For example this

import Mathlib.Data.Matrix.Basic
import Mathlib.Data.Matrix.Notation
import Mathlib.Data.Complex.Basic

open Real
open Matrix
open Complex

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

@[simp] lemma Hadamard_apply (j : Fin 2) : Hadamard j 0 = 1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply11 : Hadamard 1 1 = -1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply01 : Hadamard 0 1 = 1 := by simp [Hadamard]

theorem HadamardSquared : Hadamard  Hadamard = 2  (1 : Matrix (Fin 2) (Fin 2) ) := by
    ext i j
    by_cases hij : i = j
    · fin_cases j <;> simp [hij, mul_apply]
    · fin_cases i <;> fin_cases j <;> simp [hij, mul_apply]

works (but it is not very elegant)

Eric Wieser (Feb 15 2024 at 13:35):

Yaël Dillies said:

Eric Wieser, do your reflection lemmas cover of ![![2, 0], ![0, 2]] = !![2, 0; 0, 2]

This is a syntactic tautology

and !![2, 0; 0, 2] = 2?

No, but adding a diagonalᵣ to Data.Matrix.Reflection would be an easy project

Ruben Van de Velde (Feb 15 2024 at 13:48):

Is it really a tautology? Don't they have different types?

Jake Jongejans (Feb 15 2024 at 13:48):

I think the • solved an issue for me once and I ended up replacing the rest of the * with it to avoid the issue, but I may have forgotten the initial issue. It seems to have no effect anymore.

Yaël Dillies (Feb 15 2024 at 13:50):

Ruben Van de Velde said:

Is it really a tautology? Don't they have different types?

Watch out for the of in the LHS

Jake Jongejans (Feb 15 2024 at 13:50):

Riccardo Brasca said:

For example this

import Mathlib.Data.Matrix.Basic
import Mathlib.Data.Matrix.Notation
import Mathlib.Data.Complex.Basic

open Real
open Matrix
open Complex

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

@[simp] lemma Hadamard_apply (j : Fin 2) : Hadamard j 0 = 1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply11 : Hadamard 1 1 = -1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply01 : Hadamard 0 1 = 1 := by simp [Hadamard]

theorem HadamardSquared : Hadamard  Hadamard = 2  (1 : Matrix (Fin 2) (Fin 2) ) := by
    ext I j
    by_cases hij : i = j
    · fin_cases j <;> simp [hij, mul_apply]
    · fin_cases i <;> fin_cases j <;> simp [hij, mul_apply]

works (but it is not very elegant)

I found this to work only when adding <;> norm_num at the end of both fin_cases. Does anyone know why I needed this while Riccardo did not?

Eric Wieser (Feb 15 2024 at 13:51):

Relatedly, we're missing the pretty-printer that hides of in the goal view

Riccardo Brasca (Feb 15 2024 at 14:10):

Javernus said:

Riccardo Brasca said:

For example this

import Mathlib.Data.Matrix.Basic
import Mathlib.Data.Matrix.Notation
import Mathlib.Data.Complex.Basic

open Real
open Matrix
open Complex

def Hadamard : Matrix (Fin 2) (Fin 2)  :=
  !![1, 1; 1, -1]

@[simp] lemma Hadamard_apply (j : Fin 2) : Hadamard j 0 = 1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply11 : Hadamard 1 1 = -1 := by simp [Hadamard]

@[simp] lemma Hadamard_apply01 : Hadamard 0 1 = 1 := by simp [Hadamard]

theorem HadamardSquared : Hadamard  Hadamard = 2  (1 : Matrix (Fin 2) (Fin 2) ) := by
    ext I j
    by_cases hij : i = j
    · fin_cases j <;> simp [hij, mul_apply]
    · fin_cases i <;> fin_cases j <;> simp [hij, mul_apply]

works (but it is not very elegant)

I found this to work only when adding <;> norm_num at the end of both fin_cases. Does anyone know why I needed this while Riccardo did not?

This is weird, it works on live.lean-lang.org

Riccardo Brasca (Feb 15 2024 at 14:12):

Did you replace by ?

Jake Jongejans (Feb 15 2024 at 14:32):

No, I copied the code verbatim. I am on v0.0.127 for the lean extension with version 4.5.0-rc1 of lean installed on my system.

Jake Jongejans (Feb 15 2024 at 14:38):

I can see it work on that website, though. Strange.

Jake Jongejans (Feb 15 2024 at 14:46):

Updating to stable, maybe that helps.

Eric Wieser (Feb 15 2024 at 14:53):

Yaël Dillies said:

Eric Wieser, do your reflection lemmas cover!![2, 0; 0, 2] = 2?

Actually, yes:

example : 2 = !![2, 0; 0, 2] := (etaExpand_eq _).symm

Jake Jongejans (Feb 15 2024 at 16:07):

Eric Wieser said:

(Pr incoming)

Would you mind sharing a link once this is in PR? Then I can watch it :)

Eric Wieser (Feb 15 2024 at 16:08):

Eric Wieser said:

#10592

I already did :)

Jake Jongejans (Feb 15 2024 at 16:12):

I am so blind! Thank you very much :)


Last updated: May 02 2025 at 03:31 UTC