Zulip Chat Archive
Stream: new members
Topic: what the heq, PosSemidef
Alex Meiburg (Apr 18 2024 at 15:58):
So I'm trying to prove some things about PSD matrices and I ran into issues where sqrt
requires a proof that the matrix is PSD, which meant I got HEq
issues because PosSemidef A
and PosSemidef B
are different types even if A = B
. A minimized chunk of my proof looks like this:
import Mathlib
variable {m n R : Type*} [Fintype m] [Fintype n]
variable [RCLike R] [DecidableEq n] [DecidableEq m]
namespace Matrix
open scoped ComplexOrder
theorem sqrt_neg (A : Matrix m n R) : (Matrix.posSemidef_conjTranspose_mul_self (-A)).sqrt =
(Matrix.posSemidef_conjTranspose_mul_self A).sqrt := by
have : (-A)ᴴ * -A = (A)ᴴ * A := by
rw [Matrix.conjTranspose_neg, Matrix.neg_mul, Matrix.mul_neg]
exact neg_neg _
apply congr_heq
rw [this]
exact heq_prop _ _
so I was eventually able to get it with
apply congr_heq
rw [this]
exact heq_prop _ _
but what I really "meant" was just rw [this]
. Is there a better way to handle these types of things ... ?
Alex Meiburg (Apr 18 2024 at 16:04):
If I just cared about sqrt
, I could just write a lemma like
lemma sqrt_eq {A B : Matrix m m R} (h : A = B) (hA : A.PosSemidef) (hB : B.PosSemidef) :
hA.sqrt = hB.sqrt := by
apply congr_heq
rw [h]
exact heq_prop _ _
and rely on that. But there are many such matrix functions, like IsHermitian.eigenvalues
, IsHermitian..eigenvectorMatrix
, IsHermitian.eigenvectorMatrixInv
, and it feels wrong to have to write so many similar "casting" lemmas.
Jireh Loreaux (Apr 18 2024 at 16:15):
Note: @Jon Bannon is currently in the process of refactoring Matrix.IsHermitian.eigen*
stuff, so expect some things around that to change very soon. I think there's a PR, but it's not in an appropriate state yet, so I won't link it.
Jireh Loreaux (Apr 18 2024 at 16:17):
Moreover, note that some of this will be fixed by using the continuous functional calculus. There will be an instance of that for hermitian and positive semidefinite matrices soon (but it needs the refactor first). And I have material about sqrt
for the cfc waiting in another repo which I'll PR soonish.
Jireh Loreaux (Apr 18 2024 at 16:20):
Also, I would bet that using the term constructor congr
(or the tactic congrm
) can help you here, but I haven't tested it.
Jireh Loreaux (Apr 18 2024 at 16:20):
Can you share what you're working on concerning positive semidefinite matrices?
Note that there's currently lots of defeq abuse in those files, which is part of the thing that Jon is cleaning up.
Alex Meiburg (Apr 18 2024 at 16:33):
I'm trying to write up some things from quantum information theory. Just basic stuff right now. :)
Jireh Loreaux (Apr 18 2024 at 16:52):
@Kyle Miller I know this is kind of cursed, but do you understand why the congrm
tactic succeeds here but the declaration fails because the kernel says it still has free variables? Seems like a bug in congr
, which I know you're currently working on.
import Mathlib
variable {m n R : Type*} [Fintype m] [Fintype n]
variable [RCLike R] [DecidableEq n] [DecidableEq m]
namespace Matrix
open scoped ComplexOrder
lemma sqrt_eq {A B : Matrix m m R} (h : A = B) (hA : A.PosSemidef) (hB : B.PosSemidef) :
hA.sqrt = hB.sqrt := by
congrm(Matrix.PosSemidef.sqrt (A := $(h)) ‹_›)
Kyle Miller (Apr 18 2024 at 17:20):
congr!
works here:
lemma sqrt_eq {A B : Matrix m m R} (h : A = B) (hA : A.PosSemidef) (hB : B.PosSemidef) :
hA.sqrt = hB.sqrt := by
congr!
That tactic is "goal directed" vs congrm
and congr(...)
which are "term directed" (the former can use whatever it finds in the goal, the latter needs to synthesize what it needs). The issue appears to be ‹_›
, which doesn't seem to play nice with congrm
/congr(...)
, though I'm not sure what the issue is exactly.
Kyle Miller (Apr 18 2024 at 18:59):
@Jireh Loreaux Thanks for that example. There was a bad bug deep within congr(...)
: #12253
Jireh Loreaux (Apr 18 2024 at 19:18):
Lol, I can't believe I didn't think of congr!
in this case. Thanks for the bug fix Kyle!
Kyle Miller (Apr 18 2024 at 19:24):
It's neat to see that congrm
/congr(...)
actually works with ‹_›
. (That didn't turn out to be the problem by the way. The real issue was that congr(...)
was building a term that used Subsingleton
instances to automatically handle discrepancies between arguments, but it wasn't substituting it in everywhere, leaving a stray fvar in the term.)
Jireh Loreaux (Apr 18 2024 at 19:26):
Yeah, I didn't know if it would work with ‹_›
either, and was a bit surprised to see that it did. I also realized you can postpone goals with metavariable holes like ?_
. I tried that first, found it was very cool that it worked, then tried with ‹_›
. Unsurprisingly, given what the issue ended up being, the fvar
error also occurred with ?_
.
Last updated: May 02 2025 at 03:31 UTC