Repository navigation
Keep the stored zeros of sparse arguments in hcat, vcat and cat with dense arrays - #1102
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1102 +/- ##
=======================================
Coverage 94.82% 94.83%
=======================================
Files 16 16
Lines 10234 10252 +18
=======================================
+ Hits 9704 9722 +18
Misses 530 530 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… arrays `hcat`, `vcat` and `cat` that mix a sparse argument with a dense array, a vector, a number, `I` or a `Diagonal` built the result through Base's generic concatenation, which writes each block with `setindex!` and so drops the stored zeros of the sparse arguments. Assemble a matrix result from the stored entries of the blocks instead, with the kernels that `hvcat` and `blockdiag` use, as concatenating sparse matrices alone does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`_hvcat_csc` picks a block by an index known only at run time, which boxes the block once per column and block row when the blocks are of different types, as with the `Bool` block that `I` becomes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ViralBShah
force-pushed
the
vs/concat-keep-stored-zeros
branch
from
October 16, 2026 03:25
b7f9491 to
1023a80
Compare
ViralBShah
enabled auto-merge (squash)
October 16, 2026 03:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Concatenating sparse arrays alone keeps their stored zeros, but as soon as a dense array, a vector, a number,
Ior aDiagonaljoins in,hcat,vcatandcatdrop them.hvcatalready keeps them in both cases.Before
After
Time (median over three processes of the minimum of 200 samples) and allocations, with
S = sprand(2000, 2000, 0.001)afterRandom.seed!(1),D = rand(2000, 50),v = rand(2000)andDg = Diagonal(rand(2000)):[S I][S; I][S I; I S][S S][S D][S; D'][S v][S Dg]cat(S, S; dims=(1, 2))hcat(S, fill(1.0, 2000))The mixed path converts every argument to a sparse array and then hands them to Base's generic
typed_hcat,typed_vcator__cat, which allocate a sparse destination and write each block into it withsetindex!. Sparsesetindex!does not store a zero, so the stored zeros of the sparse arguments were lost; a dense argument loses its zeros in the conversion, assparse(D)does, which is unchanged._sparse_cat_t_shapednow assembles a matrix result from the stored entries of the blocks with_hvcat_csc(horizontal or vertical) or_blockdiag(dims=(1, 2)), and_sparse_typed_hcat/_sparse_typed_vcatroute through it, sosparse_hcat,sparse_vcatand theUniformScalingconcatenations take the same path. A number still fills its whole block, as in densecat(#383). The result keeps the element and index type it had: the index type of the first array, widened toIntby a leading number, not the promotion that concatenating sparse matrices alone does. A vector result (vcatof vectors and numbers) already kept stored zeros and still goes through Base._hvcat_cscpicks a block by an index known only at run time, which boxed the block once per column and block row when the blocks were of different types, as with theBoolblock thatIbecomes; it now converts such blocks to the result type first, which also removes the per-column allocations that[S I; I S]had on main. Sincecat(...; dims=(1, 2))now reaches_blockdiag, it reads only the firstnnzentries of each block's row and value arrays, which may be longer, and it and_hvcat_csccheck that the stored entries fit the index type, as thesetindex!path did.Left out: typed concatenation such as
Float64[A D]orFloat64[A A]goes through Base'styped_hcat/typed_vcatwithout reaching SparseArrays, and still drops stored zeros, also with sparse arguments only.Authored with Claude Code.
🤖 Generated with Claude Code