Zulip Chat Archive

Stream: mathlib4

Topic: Woodbury identity


Kim Morrison (Aug 14 2024 at 02:22):

Ahmad Alkhalawi said:

Woodbury identity

Hopefully you are planning on proving it in an arbitrary ring? Hopefully the proof is quite short, using e.g. the "algebraic proof" on the wikipedia page and the ring tactic.

Ahmad Alkhalawi (Aug 14 2024 at 08:33):

Kim Morrison said:

Ahmad Alkhalawi said:

Woodbury identity

Hopefully you are planning on proving it in an arbitrary ring? Hopefully the proof is quite short, using e.g. the "algebraic proof" on the wikipedia page and the ring tactic.

I have a proof for it in matrices over a commutative ring. Unfortunately I don't think ring helps since matrices are noncommutative, and abel/noncomm_ring helped but not much. I followed the direct proof in Wikipedia and it was about 22 lines.

Kim Morrison (Aug 15 2024 at 00:58):

Ahmad Alkhalawi said:

I have a proof for it in matrices over a commutative ring. Unfortunately I don't think ring helps since matrices are noncommutative, and abel/noncomm_ring helped but not much. I followed the direct proof in Wikipedia and it was about 22 lines.

But why restrict the result to matrices? From what I understand it's just true in any ring. Indeed I am wrong however about the ring tactic being helpful.

Ahmad Alkhalawi (Aug 15 2024 at 10:18):

Kim Morrison said:

Ahmad Alkhalawi said:

I have a proof for it in matrices over a commutative ring. Unfortunately I don't think ring helps since matrices are noncommutative, and abel/noncomm_ring helped but not much. I followed the direct proof in Wikipedia and it was about 22 lines.

But why restrict the result to matrices? From what I understand it's just true in any ring. Indeed I am wrong however about the ring tactic being helpful.

I proved it over general rings as well, but it seems like that doesnt imply the matrix version since the matrices don't have to be the same size. Maybe I could submit both?

MohanadAhmed (Aug 15 2024 at 16:05):

Ahmad Alkhalawi said:

Kim Morrison said:

Ahmad Alkhalawi said:

I have a proof for it in matrices over a commutative ring. Unfortunately I don't think ring helps since matrices are noncommutative, and abel/noncomm_ring helped but not much. I followed the direct proof in Wikipedia and it was about 22 lines.

But why restrict the result to matrices? From what I understand it's just true in any ring. Indeed I am wrong however about the ring tactic being helpful.

I proved it over general rings as well, but it seems like that doesnt imply the matrix version since the matrices don't have to be the same size. Maybe I could submit both?

Hi Ahamd,
Can you share both versions for the woodbury identity? I am interested in seeing how different they are.

Ahmad Alkhalawi (Aug 15 2024 at 23:48):

MohanadAhmed said:

Ahmad Alkhalawi said:

Kim Morrison said:

Ahmad Alkhalawi said:

I have a proof for it in matrices over a commutative ring. Unfortunately I don't think ring helps since matrices are noncommutative, and abel/noncomm_ring helped but not much. I followed the direct proof in Wikipedia and it was about 22 lines.

But why restrict the result to matrices? From what I understand it's just true in any ring. Indeed I am wrong however about the ring tactic being helpful.

I proved it over general rings as well, but it seems like that doesnt imply the matrix version since the matrices don't have to be the same size. Maybe I could submit both?

Hi Ahamd,
Can you share both versions for the woodbury identity? I am interested in seeing how different they are.

Hello, this is the matrix version:

theorem add_mul_inv
  (A: Matrix n n R) (U : Matrix n m R) (C : Matrix m m R) (V : Matrix m n R)
  [Invertible A] [Invertible C][Invertible (C⁻¹ + V * A⁻¹* U)] :
  (A+U*C*V)⁻¹=A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹:= by
    refine Matrix.inv_eq_right_inv ?h
    calc
      (A+U*C*V)*(A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹)
      _ = A*A⁻¹-A*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹-U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        rw[Matrix.add_mul, Matrix.mul_sub,Matrix.mul_sub]
        repeat rw[Matrix.mul_assoc]
        rw[←@add_sub_assoc]
      _ = (1+U*C*V*A⁻¹)-(U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹) := by
        simp
        abel
      _ = 1+U*C*V*A⁻¹-(U+U*C*V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        simp
        rw [Matrix.add_mul,Matrix.add_mul,Matrix.add_mul]
      _ = 1+U*C*V*A⁻¹-U*C*(C⁻¹+V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        congr
        rw [Matrix.mul_add]
        simp
        rw [Matrix.mul_assoc,Matrix.mul_assoc]
      _ = 1 := by simp

Note R is commutative
This is the ring version

theorem add_mul_inv
  (A: S) (U : S) (C : S) (V : S)
  [Invertible A] [Invertible C][Invertible (C + V * A* U)]:
  (A+U*C*V)*(A-⅟A*U*⅟(C+V*⅟A*U)*V*⅟A)=1:= by
    calc
      (A+U*C*V)*(A-⅟A*U*⅟(C+V*⅟A*U)*V*⅟A)
      _ = A*⅟A-A*⅟A*U*⅟(C+V*⅟A*U)*V*⅟A+U*C*V*⅟A-U*C*V*⅟A*U*⅟(C+V*⅟A*U)*V*⅟A := by
        rw[add_mul, mul_sub,mul_sub]
        repeat rw[mul_assoc]
        rw[←@add_sub_assoc]
      _ = (1+U*C*V*⅟A)-(U*⅟(C+V*⅟A*U)*V*⅟A+U*C*V*⅟A*U*⅟(C+V*⅟A*U)*V*⅟A) := by
        simp
        abel
      _ = 1+U*C*V*⅟A-(U+U*C*V*⅟A*U)*⅟(C+V*⅟A*U)*V*⅟A := by
        simp
        rw [add_mul,add_mul,add_mul]
      _ = 1+U*C*V*⅟A-U*C*(C+V*⅟A*U)*⅟(C+V*⅟A*U)*V*⅟A := by
        congr
        rw [mul_add]
        rw [mul_assoc U C C]
        simp
        rw [mul_assoc,mul_assoc]
      _ = 1 := by simp

Here \frac1 instead of \inv since \inv isnt defined, and i only prove it is a left inverse, since im not sure its two-sided

Notification Bot (Aug 16 2024 at 14:37):

11 messages were moved here from #mathlib4 > github permission by Eric Wieser.

MohanadAhmed (Aug 18 2024 at 20:44):

Thanks @Ahmad Alkhalawi

I tried to golf it but I could not do much. Compared to my earlier proof, I think this is much neater.
@Eric Wieser Any golfs you can think of?

import Mathlib.LinearAlgebra.Matrix.NonsingularInverse

theorem add_mul_inv {n m R: Type*}[CommRing R]
  [Fintype n][Fintype m][DecidableEq m][DecidableEq n]
  (A: Matrix n n R) (U : Matrix n m R) (C : Matrix m m R) (V : Matrix m n R)
  [Invertible A] [Invertible C][Invertible (C⁻¹ + V * A⁻¹* U)] :
  (A+U*C*V)⁻¹=A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹:= by
    refine Matrix.inv_eq_right_inv ?_
    calc
      (A+U*C*V)*(A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹)
      _ = A*A⁻¹-A*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹-U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        simp_rw [add_sub_assoc, Matrix.add_mul, Matrix.mul_sub, Matrix.mul_assoc]
      _ = (1+U*C*V*A⁻¹)-(U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹) := by
        rw [Matrix.mul_inv_of_invertible, Matrix.one_mul]
        abel
      _ = 1+U*C*V*A⁻¹-(U+U*C*V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        rw [sub_right_inj, Matrix.add_mul,Matrix.add_mul,Matrix.add_mul]
      _ = 1+U*C*V*A⁻¹-U*C*(C⁻¹+V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        congr
        simp only [Matrix.mul_add, Matrix.mul_inv_cancel_right_of_invertible, Matrix.mul_assoc]
      _ = 1 := by simp

Eric Wieser (Aug 18 2024 at 20:48):

Not a golf, but it would be great to show the inverse for the other side too, and bundle the resulting two-sided inverse up as Invertible (A + U*C*V)

Eric Wieser (Aug 18 2024 at 20:48):

(I guess the right-inverse follows quickly from the left-inverse)

MohanadAhmed (Aug 18 2024 at 20:50):

Should that not follow from: docs#Matrix.mul_eq_one_comm

MohanadAhmed (Aug 19 2024 at 23:19):

Eric Wieser said:

Not a golf, but it would be great to show the inverse for the other side too, and bundle the resulting two-sided inverse up as Invertible (A + U*C*V)

Is this what you meant?

lemma add_mul_mul_inv_mul_eq_one {n m R: Type*}[CommRing R]
  [Fintype n][Fintype m][DecidableEq m][DecidableEq n]
  (A: Matrix n n R) (U : Matrix n m R) (C : Matrix m m R) (V : Matrix m n R)
  [Invertible A] [Invertible C][Invertible (C⁻¹ + V * A⁻¹* U)] :
  (A+U*C*V)*(A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹) = 1 := by
  calc
      (A+U*C*V)*(A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹)
      _ = A*A⁻¹-A*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹-U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        simp_rw [add_sub_assoc, Matrix.add_mul, Matrix.mul_sub, Matrix.mul_assoc]
      _ = (1+U*C*V*A⁻¹)-(U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹+U*C*V*A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹) := by
        rw [Matrix.mul_inv_of_invertible, Matrix.one_mul]
        abel
      _ = 1+U*C*V*A⁻¹-(U+U*C*V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        rw [sub_right_inj, Matrix.add_mul,Matrix.add_mul,Matrix.add_mul]
      _ = 1+U*C*V*A⁻¹-U*C*(C⁻¹+V*A⁻¹*U)*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹ := by
        congr
        simp only [Matrix.mul_add, Matrix.mul_inv_cancel_right_of_invertible, Matrix.mul_assoc]
      _ = 1 := by simp

noncomputable def invertibleWoodburyLHS {n m R: Type*}[CommRing R]
  [Fintype n][Fintype m][DecidableEq m][DecidableEq n]
  (A: Matrix n n R) (U : Matrix n m R) (C : Matrix m m R) (V : Matrix m n R)
  [Invertible A] [Invertible C] [Invertible (C⁻¹ + V * A⁻¹* U)]  : Invertible (A+U*C*V) := by
  apply Matrix.invertibleOfRightInverse _ _ (add_mul_mul_inv_mul_eq_one A U C V)

theorem woodbury_identity {n m R: Type*}[CommRing R]
  [Fintype n][Fintype m][DecidableEq m][DecidableEq n]
  (A: Matrix n n R) (U : Matrix n m R) (C : Matrix m m R) (V : Matrix m n R)
  [Invertible A] [Invertible C][Invertible (C⁻¹ + V * A⁻¹* U)] :
  (A+U*C*V)⁻¹=A⁻¹-A⁻¹*U*(C⁻¹+V*A⁻¹*U)⁻¹*V*A⁻¹:=
  Matrix.inv_eq_right_inv (add_mul_mul_inv_mul_eq_one _ _ _ _)

MohanadAhmed (Aug 21 2024 at 13:00):

@Ahmad Alkhalawi Did you get non master mathlib access yet?
I think we should pr this before it becomes mathlib outdated like my earlier code

MohanadAhmed (Aug 21 2024 at 13:13):

@Eric Wieser Do you have any more thoughts on this?

Ahmad Alkhalawi (Aug 21 2024 at 14:17):

MohanadAhmed said:

Ahmad Alkhalawi Did you get non master mathlib access yet?
I think we should pr this before it becomes mathlib outdated like my earlier code

I did not

MohanadAhmed (Aug 21 2024 at 19:09):

@maintainers Maintainers, can someone please @Ahmad Alkhalawi (github name 4hma4d access to PR his proof of Woodbury (aka Sherman Morrison) identity to mathlib?

Matthew Ballard (Aug 21 2024 at 19:11):

@Ahmad Alkhalawi invitation sent!

Ahmad Alkhalawi (Aug 21 2024 at 19:11):

Thanks!

Eric Wieser (Sep 22 2024 at 22:16):

Kim Morrison said:

But why restrict the result to matrices? From what I understand it's just true in any ring.

Ahmad Alkhalawi said:

I proved it over general rings as well, but it seems like that doesnt imply the matrix version since the matrices don't have to be the same size. Maybe I could submit both?

I think the correct generality here is over a ring equipped with additive maps, trading the key steps using

(U*C*V)*A*(U*B*V) = U*(C*(V*A*U)*B)*V

for

Fuv C*A*Fuv B = Fuv (C * Fvu A * B)

where on matrices all the * are still square multiplications. This can be instantiated separately for Fuv C = U*C*V for regular and matrix multiplication.

I think @Ahmad Alkhalawi's #16325 can get merged without that generalization though, assuming everything else looks fine.


Last updated: May 02 2025 at 03:31 UTC