-
Notifications
You must be signed in to change notification settings - Fork 32
[MadNLPGPU] cuDSS: recover inertia under matching; guard matching off ubatch #633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,7 +47,12 @@ function set_cudss_options!(solver::CUDSS.CudssSolver, opt::CudssSolverOptions) | |
| CUDSS.cudss_set(solver, "pivot_threshold", opt.cudss_pivot_threshold) | ||
| end | ||
| if opt.cudss_matching | ||
| if pkgversion(CUDSS) < v"0.8" | ||
| if solver.matrix.nbatch > 1 | ||
| # cuDSS matching (`matching_alg`) fails the *analysis* phase with | ||
| # CUDSS_STATUS_NOT_SUPPORTED on a uniform-batch solver (through cuDSS 0.8), | ||
| # so never enable it there (e.g. the two-stage per-scenario batch solver). | ||
| Base.@warn "cuDSS matching is not supported on uniform-batch (ubatch) solvers; ignoring `cudss_matching = true` for this batched solver." maxlog = 1 | ||
| elseif pkgversion(CUDSS) < v"0.8" | ||
| CUDSS.cudss_set(solver, "use_matching", 1) | ||
| if opt.cudss_matching_alg != "default" | ||
| CUDSS.cudss_set(solver, "matching_alg", opt.cudss_matching_alg) | ||
|
|
@@ -90,6 +95,7 @@ mutable struct CUDSSSolver{T, V} <: MadNLP.AbstractLinearSolver{T} | |
| x_gpu::CUDSS.CudssMatrix{T} | ||
| b_gpu::CUDSS.CudssMatrix{T} | ||
| buffer::V | ||
| diag::V | ||
|
|
||
| opt::CudssSolverOptions | ||
| logger::MadNLP.MadNLPLogger | ||
|
|
@@ -151,9 +157,13 @@ function CUDSSSolver( | |
| # Always allocate it to support dynamic updates to opt.cudss_ir | ||
| buffer = CuVector{T}(undef, n * nbatch) | ||
|
|
||
| # Scratch for the factor diagonal, used to recover the inertia when matching is on | ||
| # (cuDSS misreports it as (0, 0)); only the nbatch == 1 path ever queries inertia. | ||
| diag = CuVector{T}(undef, n) | ||
|
|
||
| return CUDSSSolver( | ||
| solver, csc, | ||
| x_gpu, b_gpu, buffer, | ||
| x_gpu, b_gpu, buffer, diag, | ||
| opt, logger, | ||
| ) | ||
| end | ||
|
|
@@ -183,6 +193,25 @@ end | |
| MadNLP.input_type(::Type{CUDSSSolver}) = :csc | ||
| MadNLP.default_options(::Type{CUDSSSolver}) = CudssSolverOptions() | ||
| MadNLP.is_inertia(M::CUDSSSolver) = (M.inner.matrix.nbatch == 1) # Uncomment if MadNLP.LU is supported -- (M.opt.cudss_algorithm ∈ (MadNLP.CHOLESKY, MadNLP.LDL)) | ||
|
|
||
| # Recover the inertia from the sign counts of the factor diagonal D, dumped via the | ||
| # cuDSS "diag" data parameter ("Diagonal of the factorized matrix", i.e. D of P·S·A·S·Pᵀ | ||
| # = L·D·Lᵀ — a congruence of A, so the sign counts equal A's inertia by Sylvester's law, | ||
| # matching scaling/permutation included). Only meaningful for an LDLᵀ factorization, | ||
| # hence the hard check. Exact only for 1×1 pivots, which holds for the (quasi-definite) | ||
| # condensed KKT family this solver targets. | ||
| function inertia_from_diag(M::CUDSSSolver) | ||
| @assert M.opt.cudss_algorithm == MadNLP.LDL "the factor diagonal D only determines the inertia for an LDLᵀ factorization" | ||
| n = size(M.tril, 1) | ||
| CUDSS.cudss_set(M.inner, "diag", M.diag) | ||
| CUDSS.cudss_get(M.inner, "diag") | ||
| d = Array(M.diag) | ||
| z = zero(eltype(d)) | ||
| npos = count(>(z), d) | ||
| nneg = count(<(z), d) | ||
| return (npos, n - npos - nneg, nneg) | ||
| end | ||
|
|
||
| function MadNLP.inertia(M::CUDSSSolver) | ||
| @assert M.inner.matrix.nbatch == 1 | ||
| n = size(M.tril, 1) | ||
|
|
@@ -202,6 +231,13 @@ function MadNLP.inertia(M::CUDSSSolver) | |
| elseif M.opt.cudss_algorithm == MadNLP.LDL | ||
| # N.B.: cuDSS does not always return the correct inertia. | ||
| if info == 0 | ||
| if M.opt.cudss_matching | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @frapac @sshin23 @amontoison Is this what we want to do, or do we want to automatically switch to inertia-free if matching is enabled?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think your solution is the most appropriate. Are we sure
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes but we should always check that the factorization is an
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes — cuDSS's Verified empirically on an RTX 4080 with cuDSS 0.8 on KKT-like symmetric indefinite matrices ( @amontoison addressed in 9010247: the recovery is extracted into |
||
| # cuDSS (through 0.8) reports inertia (0, 0) whenever matching is enabled, | ||
| # even though the factorization is correct — trusting it sends | ||
| # InertiaBased/InertiaAuto into an endless regularization bump and then | ||
| # restoration. Recover the inertia from D instead. | ||
| return inertia_from_diag(M) | ||
| end | ||
| (k, l) = CUDSS.cudss_get(M.inner, "inertia") | ||
| @assert 0 ≤ k + l ≤ n | ||
| return (k, n - k - l, l) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NVIDIA is using an external library for the matching (HSL MC64).
They probably didn't extended it for batch...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That matches what we observe: the ubatch analysis phase itself returns
CUDSS_STATUS_NOT_SUPPORTEDas soon asmatching_algis set, so the guard just skips matching with a one-time warning instead of failing the whole batched solver.