Uh oh!
There was an error while loading. Please reload this page.
Mooncake testsuite refactor - #175
Conversation
add QR gauge projection
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Jutho <Jutho@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
kshyatt
commented
Feb 23, 2026
I guess I really don't see the point of removing all the |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
kshyatt
commented
Feb 24, 2026
Once this merges, I'll update the other PR |
| Q2 = view(Q, (p + 1):size(Q, 1), :) | ||
| ΔQ2 = view(ΔQ, (p + 1):size(Q, 1), :) | ||
| ΔQ2Q1ᴴ = ΔQ2 * Q1' | ||
| check_lq_full_cotangents(Q1, ΔQ2, ΔQ2Q1ᴴ; gauge_atol) |
There was a problem hiding this comment.
For a rank-deficient matrix p < minmn, check_lq_full_cotangents can also be called by lq_compact (i.e. size(Q,1) == minmn for lq_compact and size(Q,1) == n for lq_full). Since this is not a change from the current PR, I will try to look into when this was introduced, and whether everything is still fully correct.
There was a problem hiding this comment.
Does that mean we can go ahead with this one? That seems somewhat unrelated to the testsuite refactor anyways, so might be clearer in a separate PR anyways
| remove_eig_gauge_dependence!(ΔV, D, V) | ||
| Remove the gauge-dependent part from the cotangent `ΔV` of the eigenvector matrix `V`. The | ||
| eigenvectors are only determined up to complex phase (and unitary mixing for degenerate |
There was a problem hiding this comment.
In the eig case there can also be non-unitary mixing. I think the only convention respected by LAPACK is that all the eigenvectors have norm 1, but that condition cannot easily be transformed into a restriction onto a restriction on the matrices. In fact, even for non-degenerate eigenvalues we actually require v' * Δv (the diagonal element of V' * ΔV) to be completely zero, not just the imaginary part of it (the imaginary part corresponds to phase rotations, the real part to norm changes).
| ΔU[:, (minmn + 1):end] .= 0 | ||
| ΔVᴴ[(minmn + 1):end, :] .= 0 |
There was a problem hiding this comment.
Do we also want to support rank deficient matrices, where we should use some p instead of minmn?
| Q₁ = @view Q[:, 1:r] | ||
| ΔQ₂ = @view ΔQ[:, (r + 1):end] |
There was a problem hiding this comment.
For consistency, since you do use regular view in the last line:
| Q₁ =@view Q[:, 1:r] | |
| ΔQ₂ =@view ΔQ[:, (r +1):end] | |
| Q₁ =view(Q, :, 1:r) | |
| ΔQ₂ =view(ΔQ, :, (r +1):end) |
| ambiguity. Additionally, rows of `ΔR` beyond the rank are zeroed out. | ||
| """ | ||
| function remove_qr_gauge_dependence!(ΔQ, ΔR, A, Q, R) | ||
| r = MatrixAlgebraKit.qr_rank(R) |
There was a problem hiding this comment.
Do we want to support a rank_atol keyword to be passed along from remove_qr_gauge_dependence! to qr_rank?
| Q₁ = @view Q[1:r, :] | ||
| ΔQ₂ = @view ΔQ[(r + 1):end, :] |
There was a problem hiding this comment.
| Q₁ =@view Q[1:r, :] | |
| ΔQ₂ =@view ΔQ[(r +1):end, :] | |
| Q₁ =view(Q, 1:r, :) | |
| ΔQ₂ =view(ΔQ, (r +1):end, :) |
| Additionally, columns of `ΔL` beyond the rank are zeroed out. | ||
| """ | ||
| function remove_lq_gauge_dependence!(ΔL, ΔQ, A, L, Q) | ||
| r = MatrixAlgebraKit.lq_rank(L) |
| Q, _ = qr_compact(A) | ||
| mul!(ΔN, Q, Q' * ΔN) | ||
| return ΔN |
There was a problem hiding this comment.
Any reason to not simply pass this on to remove_qr_null_gauge_dependence in order to avoid code duplication?
| null space basis is only determined up to a unitary rotation, so `ΔNᴴ` is projected onto the | ||
| row span of the compact LQ factor `Q₁` of `A`. | ||
| """ | ||
| function remove_right_null_gauge_dependence!(ΔNᴴ, A, Nᴴ) |
There was a problem hiding this comment.
Same question with remove_lq_null_gauge_dependence!?
| ΔD2 = Diagonal(randn!(similar(A, complex(T), m))) | ||
| return DV, (ΔD, ΔV), (ΔD2, ΔV) | ||
| ΔV = remove_eig_gauge_dependence!(ΔV, D, V) | ||
| ΔD = Diagonal(randn!(similar(A, complex(T), m))) |
There was a problem hiding this comment.
| ΔD =Diagonal(randn!(similar(A, complex(T), m))) | |
| ΔD =Diagonal(randn!(similar(diagview(D)))) |
| ΔV = randn!(similar(A.diag, T, m, m)) | ||
| ΔV = remove_eiggauge_dependence!(ΔV, D, V) | ||
| ΔV = remove_eig_gauge_dependence!(ΔV, D, V) | ||
| ΔD = Diagonal(randn!(similar(A.diag, T, m))) |
There was a problem hiding this comment.
| ΔD =Diagonal(randn!(similar(A.diag, T, m))) | |
| ΔD =Diagonal(randn!(similar(D.diag))) |
or also using diagview(D) if we don't want to access .diag.
| ΔD2 = Diagonal(randn!(similar(A, real(T), m))) | ||
| return DV, (ΔD, ΔV), (ΔD2, ΔV) | ||
| ΔV = remove_eigh_gauge_dependence!(ΔV, D, V) | ||
| ΔD = Diagonal(randn!(similar(A, real(T), m))) |
There was a problem hiding this comment.
| ΔD =Diagonal(randn!(similar(A, real(T), m))) | |
| ΔD =Diagonal(randn!(similar(diagview(D)))) |
| m, n = size(A) | ||
| T = complex(eltype(A)) | ||
| D = eig_vals(A) | ||
| ΔD = randn!(similar(A, complex(T), m)) |
There was a problem hiding this comment.
| ΔD =randn!(similar(D)) |
| m, n = size(A) | ||
| T = complex(eltype(A)) | ||
| D = eig_vals(A) | ||
| ΔD = randn!(similar(A.diag, T, m)) |
There was a problem hiding this comment.
| ΔD =randn!(similar(D)) |
| m, n = size(A) | ||
| T = eltype(A) | ||
| D = eigh_vals(A) | ||
| ΔD = randn!(similar(A, real(T), m)) |
There was a problem hiding this comment.
| ΔD =randn!(similar(D)) |
| function ad_svd_compact_setup(A) | ||
| m, n = size(A) | ||
| T = eltype(A) | ||
| minmn = min(m, n) | ||
| ΔU = randn!(similar(A, T, m, minmn)) | ||
| ΔS = randn!(similar(A, real(T), minmn, minmn)) | ||
| ΔS2 = Diagonal(randn!(similar(A, real(T), minmn))) | ||
| ΔS = Diagonal(randn!(similar(A, real(T), minmn))) | ||
| ΔVᴴ = randn!(similar(A, T, minmn, n)) | ||
| U, S, Vᴴ = svd_compact(A) | ||
| ΔU, ΔVᴴ = remove_svdgauge_dependence!(ΔU, ΔVᴴ, U, S, Vᴴ) | ||
| return (U, S, Vᴴ), (ΔU, ΔS, ΔVᴴ), (ΔU, ΔS2, ΔVᴴ) | ||
| ΔU, ΔVᴴ = remove_svd_gauge_dependence!(ΔU, ΔVᴴ, U, S, Vᴴ) | ||
| return (U, S, Vᴴ), (ΔU, ΔS, ΔVᴴ) | ||
| end |
There was a problem hiding this comment.
Not sure why I cannot make a suggestion here, but anyway
functionad_svd_compact_setup(A)
U, S, Vᴴ =svd_compact(A)
ΔU =randn!(similar(U))
ΔVᴴ =randn!(similar(Vᴴ))
ΔS =Diagonal(randn!(similar(diagview(S))))
ΔU, ΔVᴴ =remove_svd_gauge_dependence!(ΔU, ΔVᴴ, U, S, Vᴴ)
return (U, S, Vᴴ), (ΔU, ΔS, ΔVᴴ)
endThere was a problem hiding this comment.
That would probably even remove the need to special case A::Diagonal below.
| @@ -324,7 +440,7 @@ | |||
| U, S, Vᴴ = svd_full(A) | |||
There was a problem hiding this comment.
It seems a bit wasteful to do svd_compact in ad_svd_compact_setup, and the again svd_full here.
| diagview(ΔSfull)[1:minmn] .= diagview(ΔS2) | ||
| diagview(ΔSfull)[1:minmn] .= diagview(ΔS) | ||
| return (U, S, Vᴴ), (ΔUfull, ΔSfull, ΔVᴴfull) | ||
| end |
There was a problem hiding this comment.
functionad_svd_full_setup(A)
U, S, Vᴴ =svd_full(A)
ΔU =randn!(similar(U))
ΔVᴴ =randn!(similar(Vᴴ))
ΔS =zero(S)
rand!(diagview(ΔS)) # although I think nonzero random contributions in all of ΔS would also just work fine
ΔU, ΔVᴴ =remove_svd_gauge_dependence!(ΔU, ΔVᴴ, U, S, Vᴴ)
return (U, S, Vᴴ), (ΔU, ΔS, ΔVᴴ)
end| m, n = size(A) | ||
| T = eltype(A) | ||
| WP = left_polar(A) | ||
| ΔWP = (randn!(similar(A, T, m, n)), randn!(similar(A, T, n, n))) |
There was a problem hiding this comment.
| ΔWP =randn!.(similar.(WP)) |
There was a problem hiding this comment.
Since this is not about this PR, I should probably make some changes to ad_utils.jl in a separate PR.
Jutho
left a comment
There was a problem hiding this comment.
I left some suggestions, but I already approve!
Uh oh!
There was an error while loading. Please reload this page.
kshyatt
commented
Feb 26, 2026
Yay congrats! |
Jutho
commented
Feb 26, 2026
I didn't realize automerge was in effect. |
Jutho
commented
Feb 26, 2026
I will try to make a PR with the |
This is a somewhat large refactor of the Mooncake test suite that hinges on the idea to wrap the in-place functions in such a way that they become admissible to the internal Mooncake testing framework. (Based on ideas suggested by @Jutho, thanks!)
The basic idea is that for a function
f!(A, input, alg)we need to:Aspace to not count finite-differences resultsinputvariablesI also somewhat reorganized the tests to get a slightly better overview of the mooncake tests.
Finally, this also allowed me to find some small mistakes in the mutating rules, which I have here fixed.
This is also relevant for #174 and #173.