Skip to content

Conversation

@DanielVandH
Copy link
Collaborator

@DanielVandH DanielVandH commented Nov 26, 2025

Now going to use this PR to get various other fixes for propagating CachedArrayStyle. Makes it easier for me when debugging but if it's preferred I can later break it up into smaller PRs. Once all the changes are in, I'll edit in all the new features here. Original PR text below.


This changes Vcat and Hcat to use the combined BroadcastStyle between a LazyArrayStyle and the combined style of its arguments. This fixes e.g. Vcat of cached arguments not being recognised as a CachedArrayStyle.

The implementation needs to use some recursion to get the BroadcastStyle of the arguments via tuple_type_broadcastlayout, but basically it's just doing the same as what you'd get from result_style(LazyArrayStyle{N}(), combine_style(A.args...)) where A is a Vcat/Hcat


@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

❌ Patch coverage is 0% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.00%. Comparing base (8bf603d) to head (6905338).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/lazyoperations.jl 0.00% 13 Missing ⚠️
src/lazyconcat.jl 0.00% 10 Missing ⚠️
ext/LazyArraysBandedMatricesExt.jl 0.00% 6 Missing ⚠️
src/lazyapplying.jl 0.00% 2 Missing ⚠️
src/lazybroadcasting.jl 0.00% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (8bf603d) and HEAD (6905338). Click for more details.

HEAD has 7 uploads less than BASE
Flag BASE (8bf603d) HEAD (6905338)
13 6
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #391       +/-   ##
==========================================
- Coverage   95.90%   0.00%   -95.91%     
==========================================
  Files          17      17               
  Lines        3372    3348       -24     
==========================================
- Hits         3234       0     -3234     
- Misses        138    3348     +3210     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@DanielVandH
Copy link
Collaborator Author

DanielVandH commented Nov 26, 2025

Similar cases missing a CachedArray style also show up in e.g. BlockArrays and LazyBandedMatrices:

julia> v = Accumulate(*, 1:10);

julia> (Base.BroadcastStyle  typeof).((v, unitblocks(v), BlockBroadcastArray(vcat, unitblocks(v), unitblocks(v))))
(LazyArrays.CachedArrayStyle{1}(), BlockArrays.BlockedStyle{1}(), LazyArrays.LazyArrayStyle{1}())

So I might have to eventually go and fix these, assuming it would be appropriate that these all return CachedArrayStyle{1}()? Similarly,

julia> Base.BroadcastStyle(typeof(vec(Vcat(v', v')))) # interlaced
Base.Broadcast.DefaultArrayStyle{1}()

will get a fix (this last one is now fixed in JuliaLinearAlgebra/ArrayLayouts.jl#268)

@DanielVandH DanielVandH changed the title Change BroadcastStyle of Vcat/Hcat to depend on BroadcastStyle of arguments Various fixes for propagating CachedArrayStyle correctly Nov 27, 2025
@DanielVandH DanielVandH marked this pull request as draft November 27, 2025 00:40
dlfivefifty pushed a commit to JuliaLinearAlgebra/ArrayLayouts.jl that referenced this pull request Nov 27, 2025
This allows e.g.

```julia-repl
julia> v = Accumulate(*, 1:10); Base.BroadcastStyle(typeof(vec(Vcat(v', v'))))
LazyArrays.LazyArrayStyle{2}()
```

(and, after JuliaArrays/LazyArrays.jl#391, this
would return `CachedArrayStyle{2}()`)
@dlfivefifty
Copy link
Member

I guess we don't need a CachedBandedArrayStyle because CachedStyle lowers to the data after resizing?

@DanielVandH
Copy link
Collaborator Author

I think that's right. I wasn't too sure exactly about cases like that (and e.g. the block matrices like I mentioned in my previous comment), but I think I reasoned similarly that CachedArrayStyle is fine

@DanielVandH
Copy link
Collaborator Author

DanielVandH commented Nov 27, 2025

This QRCompactWYQ type always seems to run into this issue. I'm not sure how to get around it properly this time, since there would need to be somewhere to call broadcastable earlier (which converts it into a Matrix), since by the time the calls get into using type information only it's too late. If LinearAlgebra just had

BroadcastStyle(::Type{<:LinearAlgebra.QRCompactWYQ}) = DefaultArrayStyle{2}()
BroadcastStyle(::Type{<:LinearAlgebra.AdjointQ}) = DefaultArrayStyle{2}()

it would be fine, but can't do that on our side without piracy. I don't really understand why they don't already do this.

Solutions like defining an internal _BroadcastStyle or overloading combine_styles seem like code smell. Have you had to deal with something similar before @dlfivefifty? An MWE for this is

julia> using LazyArrays, LinearAlgebra

julia> B = LazyArrays.CachedArray(randn(3, 3)); Q = qr(randn(3, 3)).Q; collect(B); Q * B  Q * B.data
ERROR: MethodError: no method matching ndims(::Type{LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}})
The function `ndims` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  ndims(::Type{Union{}}, Any...)
   @ Base abstractarray.jl:276
  ndims(::Type{<:Ref})
   @ Base refpointer.jl:104
  ndims(::Type{<:Applied{<:Any, typeof(*), Args}}) where Args
   @ LazyArrays c:\Users\djv23\.julia\dev\LazyArrays.jl\src\linalg\mul.jl:41
  ...

Stacktrace:
  [1] Base.Broadcast.BroadcastStyle(::Type{LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}})
    @ Base.Broadcast .\broadcast.jl:103
  [2] tuple_type_broadcastlayout
    @ c:\Users\djv23\.julia\dev\LazyArrays.jl\src\lazyconcat.jl:445 [inlined]
  [3] applybroadcaststyle(::Type{ApplyArray{Float64, 2, typeof(*), Tuple{…}}}, ::ApplyLayout{typeof(*)})
    @ LazyArrays c:\Users\djv23\.julia\dev\LazyArrays.jl\src\lazyapplying.jl:334
  [4] Base.Broadcast.BroadcastStyle(M::Type{ApplyArray{Float64, 2, typeof(*), Tuple{…}}})
    @ LazyArrays c:\Users\djv23\.julia\dev\LazyArrays.jl\src\lazyapplying.jl:336
  [5] combine_styles(c::ApplyArray{Float64, 2, typeof(*), Tuple{LinearAlgebra.QRCompactWYQ{…}, CachedArray{…}}})
    @ Base.Broadcast .\broadcast.jl:433
  [6] combine_styles(c1::ApplyArray{Float64, 2, typeof(*), Tuple{…}}, c2::Matrix{Float64})
    @ Base.Broadcast .\broadcast.jl:438
  [7] broadcasted
    @ .\broadcast.jl:1353 [inlined]
  [8] broadcast_preserving_zero_d
    @ .\broadcast.jl:882 [inlined]
  [9] -(A::ApplyArray{Float64, 2, typeof(*), Tuple{LinearAlgebra.QRCompactWYQ{…}, CachedArray{…}}}, B::Matrix{Float64})
    @ Base .\arraymath.jl:8
 [10] isapprox(x::ApplyArray{…}, y::Matrix{…}; atol::Int64, rtol::Float64, nans::Bool, norm::typeof(norm))
    @ LinearAlgebra C:\Users\djv23\.julia\juliaup\julia-1.12.1+0.x64.w64.mingw32\share\julia\stdlib\v1.12\LinearAlgebra\src\generic.jl:1982
 [11] isapprox(x::ApplyArray{Float64, 2, typeof(*), Tuple{LinearAlgebra.QRCompactWYQ{…}, CachedArray{…}}}, y::Matrix{Float64})
    @ LinearAlgebra C:\Users\djv23\.julia\juliaup\julia-1.12.1+0.x64.w64.mingw32\share\julia\stdlib\v1.12\LinearAlgebra\src\generic.jl:1978
 [12] top-level scope
    @ REPL[100]:1
Some type information was truncated. Use `show(err)` to see complete types.

…/BoundsError issue with cacheddata storing a Vcat+scalar
@dlfivefifty
Copy link
Member

I think

defining an internal _BroadcastStyle

is probably the best way around this?

I have played around in the past with making a type so that Q's are <: AbstractMatrix (I think AbstractQ is kinda poorly thought out btw):

JuliaLinearAlgebra/MatrixFactorizations.jl#69

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.

3 participants