Zulip Chat Archive

Stream: maths

Topic: Matrix simplification tactics


Anirudh Suresh (Apr 04 2025 at 18:45):

I am trying to prove some Quantum lemmas on Lean.

import Mathlib
open scoped Matrix

def tensor_product_2 {m n o p : } (A : Matrix (Fin m) (Fin n) )
  (B : Matrix (Fin o) (Fin p) ) : Matrix (Fin (m * o)) (Fin (n * p))  :=
(Matrix.kroneckerMap (fun (a:) (b:) => a*b) A B).reindex finProdFinEquiv finProdFinEquiv

infixl:80 " ⊗ " => tensor_product_2

@[reducible]
def ket0: Matrix (Fin 2) (Fin 1)  :=  -- Assuming ℂ is the complex number type
  !![(1:);0]

@[reducible]
def ket1:Matrix (Fin 2) (Fin 1)   :=  -- Assuming ℂ is the complex number type
  !![0;1]

postfix:1024 "|0⟩" => ket0

postfix:1024 "|1⟩" => ket1
noncomputable def H_gate : Matrix (Fin 2) (Fin 2)  :=
  let c := Complex.ofReal (1 / Real.sqrt 2)
  !![ c,  c;
      c, -c ]

def CNOT1 : Matrix (Fin 4) (Fin 4)  :=
   !![1, 0, 0, 0;
      0, 1, 0, 0;
      0, 0, 0, 1;
      0, 0, 1, 0]

lemma sqrt_lemma_1 : (2)⁻¹ * (2)⁻¹ = 2⁻¹ := by {
  rw [ mul_inv]
  simp [Real.mul_self_sqrt]
}

theorem H_tensor_H_on_ket0_ket0 : (H_gate  H_gate) * (ket0  ket0) = (1/2 : )  ((ket0  ket0) + (ket0  ket1) + (ket1  ket0) + (ket1  ket1)) :=by {
  ext (i : Fin (2 * 2)) j
  revert i j
  simp_rw [finProdFinEquiv.surjective.forall]
  rintro i1, i2 j1, j2
  have hj1:j1=0:=by {
    fin_cases j1
    simp
  }
  have hj2:j2=0:=by {
    fin_cases j2
    simp
  }
  rw [hj1,hj2]
  fin_cases i1; fin_cases i2;
  {
    simp [H_gate, ket0, ket1, tensor_product_2, Matrix.mul_apply, Matrix.kroneckerMap]
    simp [Fin.sum_univ_four]
    simp [finProdFinEquiv, Fin.divNat, Fin.modNat]
    let i : Fin 2 := (3 : ) / 2, by norm_num
    let j : Fin 2 := (3 : ) % 2, by norm_num
    have h1 : i = 1 := by dsimp [i]
    have h2 : j = 1 := by dsimp [j]
    conv_lhs=>enter [2,1,1,3];change(1)
    conv_lhs=>enter [2,1,2,3];change(1)
    simp
    conv_lhs=>enter [2,2,1,3];change(1)
    conv_lhs=>enter [2,2,2,3];change(1)
    simp
    norm_cast
    rw[sqrt_lemma_1]
    simp
  }
  {
    simp [H_gate, ket0, ket1, tensor_product_2, Matrix.mul_apply, Matrix.kroneckerMap]
    simp [Fin.sum_univ_four]
    simp [finProdFinEquiv, Fin.divNat, Fin.modNat]
    conv_lhs=>enter [2,1,1,3];change(1)
    conv_lhs=>enter [2,1,2,3];change(1)
    simp
    conv_lhs=>enter [2,1,2,1,3];change(1)
    conv_lhs=>enter [2,1,2,2,3];change(1)
    simp
    norm_cast
    rw[sqrt_lemma_1]
    simp
  }
  {
    fin_cases i2
    {
      simp [H_gate, ket0, ket1, tensor_product_2, Matrix.mul_apply, Matrix.kroneckerMap]
      simp [Fin.sum_univ_four]
      simp [finProdFinEquiv, Fin.divNat, Fin.modNat]
      conv_lhs=>enter [2,1,1,3];change(1)
      conv=>enter [1,2,2,1,3];change(1)
      simp
      norm_cast
      rw[sqrt_lemma_1]
      simp
    }
    {
      simp [H_gate, ket0, ket1, tensor_product_2, Matrix.mul_apply, Matrix.kroneckerMap]
      simp [Fin.sum_univ_four]
      simp [finProdFinEquiv, Fin.divNat, Fin.modNat]
      conv_lhs=>enter [2,1,1,3];change(1)
      conv=>enter [1,2,2,1,3];change(1)
      simp
      norm_cast
      rw[sqrt_lemma_1]
      simp
    }
  }

}

I am trying to prove the above theorem. However, it is an extremely long proof even though it is essentially a result of matrix operations. Is there any Lean tactic that can help me prove this faster without having to write so many lines of proof? This is a relatively simple thing to prove Mathematically so it is kinda annoying that it takes this much work in Lean.

Frédéric Dupuis (Apr 04 2025 at 19:00):

This might be a bit counterintuitive, but explicit numerical calculations with complex numbers like this is one of the worst places to start with Lean. None of the automation for numerics can handle complex numbers at the moment (norm_num can't deal with them at all, nor can simp +arith), so you're basically stuck doing everything manually. Starting out with more abstract arguments will almost certainly guarantee a better experience.

Anirudh Suresh (Apr 04 2025 at 19:08):

Would it be possible to unfold the complex number definition in Lean some way and then use the automation for the numerics?

Yaël Dillies (Apr 04 2025 at 19:12):

You could try using docs#Complex.ext and lemmas like docs#Complex.mul_re

Frédéric Dupuis (Apr 04 2025 at 19:15):

Sure, you can definitely get through the computations in this way. But if the goal was just to try something simple to get started, it's good to keep in mind that Lean is a very different beast from (say) Matlab, and this is definitely not what I would recommend!

Bhavik Mehta (Apr 04 2025 at 19:33):

lemma sqrt_lemma_2 : ((2 : ) : )⁻¹ * ((2 : ) : )⁻¹ = 2⁻¹ := by {
  norm_cast
  simp [sqrt_lemma_1]
}

theorem H_tensor_H_on_ket0_ket0 :
    (H_gate  H_gate) * (ket0  ket0) = (1/2 : )  ((ket0  ket0) + (ket0  ket1) + (ket1  ket0) + (ket1  ket1)) := by
  ext (i : Fin (2 * 2)) j
  revert i j
  simp_rw [finProdFinEquiv.surjective.forall]
  simp [Fin.forall_fin_one, Fin.forall_fin_two, tensor_product_2]
  simp [Matrix.mul_apply, H_gate, Fintype.sum_prod_type, sqrt_lemma_2]

This works instead - there aren't really many complex number computations, it's really just matrix simplification in the right order. If you remove the sqrt_lemma_2 at the end, you'll see the only complex number result that's needed, the rest is just abstract comm ring stuff


Last updated: May 02 2025 at 03:31 UTC