|
233 | 233 |
|
234 | 234 | _diagonal_qr_null!(A::AbstractMatrix, N; positive::Bool = false) = N |
235 | 235 |
|
236 | | -### GPU logic |
237 | | -# placed here to avoid code duplication since much of the logic is replicable across |
238 | | -# CUDA and AMDGPU |
239 | | -### |
| 236 | +# GPU logic |
| 237 | +# -------------- |
| 238 | +# placed here to avoid code duplication since much of the logic is replicable across CUDA and AMDGPU |
240 | 239 | function MatrixAlgebraKit.qr_full!( |
241 | 240 | A::AbstractMatrix, QR, alg::Union{CUSOLVER_HouseholderQR, ROCSOLVER_HouseholderQR} |
242 | 241 | ) |
@@ -325,3 +324,85 @@ function _gpu_qr_null!( |
325 | 324 | N = _gpu_unmqr!('L', 'N', A, τ, N) |
326 | 325 | return N |
327 | 326 | end |
| 327 | + |
| 328 | +# Native logic |
| 329 | +# -------------- |
| 330 | +function qr_full!(A::AbstractMatrix, QR, alg::Native_HouseholderQR) |
| 331 | + check_input(qr_full!, A, QR, alg) |
| 332 | + Q, R = QR |
| 333 | + A === Q && |
| 334 | + throw(ArgumentError("inplace Q not supported with native QR implementation")) |
| 335 | + _native_qr!(A, Q, R; alg.kwargs...) |
| 336 | + return Q, R |
| 337 | +end |
| 338 | +function qr_compact!(A::AbstractMatrix, QR, alg::Native_HouseholderQR) |
| 339 | + check_input(qr_compact!, A, QR, alg) |
| 340 | + Q, R = QR |
| 341 | + A === Q && |
| 342 | + throw(ArgumentError("inplace Q not supported with native QR implementation")) |
| 343 | + _native_qr!(A, Q, R; alg.kwargs...) |
| 344 | + return Q, R |
| 345 | +end |
| 346 | +function qr_null!(A::AbstractMatrix, N, alg::Native_HouseholderQR) |
| 347 | + check_input(qr_null!, A, N, alg) |
| 348 | + _native_qr_null!(A, N; alg.kwargs...) |
| 349 | + return N |
| 350 | +end |
| 351 | + |
| 352 | +function _native_qr!( |
| 353 | + A::AbstractMatrix, Q::AbstractMatrix, R::AbstractMatrix; |
| 354 | + positive::Bool = true # always true regardless of setting |
| 355 | + ) |
| 356 | + m, n = size(A) |
| 357 | + minmn = min(m, n) |
| 358 | + @inbounds for j in 1:minmn |
| 359 | + for i in 1:(j - 1) |
| 360 | + R[i, j] = A[i, j] |
| 361 | + end |
| 362 | + β, v, R[j, j] = _householder!(view(A, j:m, j), 1) |
| 363 | + for i in (j + 1):size(R, 1) |
| 364 | + R[i, j] = 0 |
| 365 | + end |
| 366 | + H = Householder(β, v, j:m) |
| 367 | + lmul!(H, A; cols = (j + 1):n) |
| 368 | + # A[j,j] == 1; store β instead |
| 369 | + A[j, j] = β |
| 370 | + end |
| 371 | + # copy remaining columns if m < n |
| 372 | + @inbounds for j in (minmn + 1):n |
| 373 | + for i in 1:size(R, 1) |
| 374 | + R[i, j] = A[i, j] |
| 375 | + end |
| 376 | + end |
| 377 | + # build Q |
| 378 | + one!(Q) |
| 379 | + @inbounds for j in minmn:-1:1 |
| 380 | + β = A[j, j] |
| 381 | + A[j, j] = 1 |
| 382 | + Hᴴ = Householder(conj(β), view(A, j:m, j), j:m) |
| 383 | + lmul!(Hᴴ, Q) |
| 384 | + end |
| 385 | + return Q, R |
| 386 | +end |
| 387 | + |
| 388 | +function _native_qr_null!(A::AbstractMatrix, N::AbstractMatrix; positive::Bool = true) |
| 389 | + m, n = size(A) |
| 390 | + minmn = min(m, n) |
| 391 | + @inbounds for j in 1:minmn |
| 392 | + β, v, ν = _householder!(view(A, j:m, j), 1) |
| 393 | + H = Householder(β, v, j:m) |
| 394 | + lmul!(H, A; cols = (j + 1):n) |
| 395 | + # A[j,j] == 1; store β instead |
| 396 | + A[j, j] = β |
| 397 | + end |
| 398 | + # build N |
| 399 | + fill!(N, zero(eltype(N))) |
| 400 | + one!(view(N, (minmn + 1):m, 1:(m - minmn))) |
| 401 | + @inbounds for j in minmn:-1:1 |
| 402 | + β = A[j, j] |
| 403 | + A[j, j] = 1 |
| 404 | + Hᴴ = Householder(conj(β), view(A, j:m, j), j:m) |
| 405 | + lmul!(Hᴴ, N) |
| 406 | + end |
| 407 | + return N |
| 408 | +end |
0 commit comments