Skip to content

Separate Algorithm and Driver#178

Open
lkdvos wants to merge 19 commits intomainfrom
ld-algmerge
Open

Separate Algorithm and Driver#178
lkdvos wants to merge 19 commits intomainfrom
ld-algmerge

Conversation

@lkdvos
Copy link
Member

@lkdvos lkdvos commented Feb 26, 2026

This is a start for tackling #176, while refactoring some of the QR/LQ implementation to share more code between the different backends -> drivers.

As usual, to keep this somewhat contained I only looked at QR/LQ decompositions to allow for some discussion first.
The next steps would be to include the SVD and eigenvalue decompositions in a similar manner.

From what I can tell, I managed to implement this in a non-breaking way, deprecating the previous *_Householder* structs without removing them.

@lkdvos lkdvos force-pushed the ld-algmerge branch 3 times, most recently from d8adb73 to 6a2bd16 Compare February 27, 2026 16:23
@lkdvos lkdvos requested review from Jutho and kshyatt February 27, 2026 16:23
@lkdvos lkdvos force-pushed the ld-algmerge branch 2 times, most recently from ded565e to 841ebac Compare February 27, 2026 21:39
Copy link
Member

@Jutho Jutho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good. Does this in any way give rise to conflicts with the whole algorithm selection mechanism via keywords and symbols?

@lkdvos
Copy link
Member Author

lkdvos commented Feb 27, 2026

Not really, I think mostly the alg is still there for the algorithm selection mechanism, which should then become alg = :Householder (which I will fix in a moment), while the driver is just an additional keyword argument that may or may not be there. I think in the end this is not changing all that much, just adding one more layer of delaying choices, based on the assumption that you probably don't want to change the driver, while it is more reasonable to try and change the algorithm.

@codecov
Copy link

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 85.60311% with 37 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/implementations/qr.jl 88.29% 11 Missing ⚠️
src/implementations/lq.jl 92.92% 8 Missing ⚠️
ext/MatrixAlgebraKitGenericLinearAlgebraExt.jl 68.42% 6 Missing ⚠️
src/common/householder.jl 28.57% 5 Missing ⚠️
...MatrixAlgebraKitCUDAExt/MatrixAlgebraKitCUDAExt.jl 40.00% 3 Missing ⚠️
src/interface/decompositions.jl 50.00% 2 Missing ⚠️
src/interface/lq.jl 66.66% 1 Missing ⚠️
src/interface/qr.jl 66.66% 1 Missing ⚠️
Files with missing lines Coverage Δ
...ixAlgebraKitAMDGPUExt/MatrixAlgebraKitAMDGPUExt.jl 65.90% <100.00%> (-6.10%) ⬇️
src/algorithms.jl 89.36% <100.00%> (-1.01%) ⬇️
src/interface/lq.jl 83.33% <66.66%> (+19.69%) ⬆️
src/interface/qr.jl 83.33% <66.66%> (+19.69%) ⬆️
src/interface/decompositions.jl 69.56% <50.00%> (-4.12%) ⬇️
...MatrixAlgebraKitCUDAExt/MatrixAlgebraKitCUDAExt.jl 64.15% <40.00%> (+3.21%) ⬆️
src/common/householder.jl 59.45% <28.57%> (ø)
ext/MatrixAlgebraKitGenericLinearAlgebraExt.jl 85.91% <68.42%> (-8.07%) ⬇️
src/implementations/lq.jl 95.02% <92.92%> (-2.17%) ⬇️
src/implementations/qr.jl 95.04% <88.29%> (-0.16%) ⬇️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kshyatt kshyatt enabled auto-merge (squash) March 3, 2026 14:25
@lkdvos lkdvos disabled auto-merge March 3, 2026 14:34
@lkdvos lkdvos enabled auto-merge (squash) March 3, 2026 15:41
@lkdvos lkdvos disabled auto-merge March 3, 2026 21:26
@lkdvos
Copy link
Member Author

lkdvos commented Mar 3, 2026

So, I actually did manage to break the whole type stability chain in the LTS version. As a possible solution, I know just @assume_effects :foldable, but this does kind of mean that we are fighting the compiler a bit (which we were really already doing, with the @inline annotations everywhere).

@Jutho, @kshyatt , @mtfishman I'd like to hear opinions on this, I think this will save me a lot of annoyance in the long run, but might also lead to accidents if used incorrectly, so there is definitely some trade-off there

@mtfishman
Copy link
Collaborator

What about only calling @assume_effects :foldable in versions that need that, anticipating that it can be removed once the LTS moves past Julia v1.10? Then at least going forward we can make sure that with smarter Julia compilers the code is type stable without that.

@lkdvos
Copy link
Member Author

lkdvos commented Mar 5, 2026

Hmm, I think in that case it might be better to simply eat the type-instability in LTS, since then we still have the hazard of causing a hang somewhere but only on specific versions of Julia, which might lead to issues that are even harder to debug.

It's just really unfortunate that there is some heuristic about how deep the compiler propagates constants, so even in the current code I assume there are ways to nest functions enough such that these function calls become type unstable...

One other way I could approach this is to simply change the Driver from a struct to an @enum, which then no longer allows for external additions, and can do "runtime dispatch" between the different drivers, avoiding the type instability (I guess this would be manual union-splitting, in some sense)

return LQViaTransposedQR(qr_alg)
end
function MatrixAlgebraKit.default_svd_algorithm(::Type{Base.ReshapedArray{T, 2, SubArray{T, 1, A, Tuple{UnitRange{Int}}, true}, Tuple{}}}; kwargs...) where {T <: BlasFloat, A <: CuVecOrMat{T}}
const BlockView{T, A} = Base.ReshapedArray{T, 2, SubArray{T, 1, A, Tuple{UnitRange{Int}}, true}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this specific for TensorKit?
Do we need the default_driver and default_algorithm primitives to operate on types, or could we have some

default_driver(A::ReshapedArray{T,2}) = default_driver(parent(A))

I guess that can even work in type domain

default_driver(::Type{<:ReshapedArray{T,N,A}}) where {T,N,A} = default_driver(A)
default_driver(::Type{<:SubArray{T,N,A}}) where {T,N,A} = default_driver(A)

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this specific for TensorKit?

Yes, we were unhappy with it at the time but couldn't really see a better way around it now. With the change of blocktype that's waiting to be merged it may be unnecessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you are right, I can make a generic implementation for default_householder_driver since that one is not being called in the type domain. Additionally, I like the type-domain default algorithm things as well, so I might also migrate that (less specializations in the extensions is easier to manage)!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what change of blocktype? To return it as StridedView. Was this not causing all kinds of other issues? I don't think StridedView objects would currently be gracefully handled by MatrixAlgebraKit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants