Skip to content

Add broadcasting and slicing using a lazy view structure#50

Open
trulsf wants to merge 10 commits into
mainfrom
tf/view
Open

Add broadcasting and slicing using a lazy view structure#50
trulsf wants to merge 10 commits into
mainfrom
tf/view

Conversation

@trulsf
Copy link
Copy Markdown
Member

@trulsf trulsf commented May 23, 2026

My apologies for a too large PR, but I got a bit carried away :)

The purpose of this PR is two-fold 1) Broadcasting support 2) A more unified approach when slicing an AbstractSparseArray.

There is still some open issues to discuss, both on naming and preferred ergonomics. I have supported old syntax, but have also added a new slice() function that provides the same syntax as doing it directly when indexing.

I will follow up this PR with an updates to benchmarks and documentation (depending upon where it goes).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a unified, lazy slicing/view mechanism for AbstractSparseArray and introduces broadcast support that materializes results as SparseArray, aiming to improve ergonomics and consistency when indexing/slicing sparse containers (including JuMP-backed IndexedVarArray).

Changes:

  • Introduces SparseArraySlice and a slice(sa, mask...) API, and updates getindex selection logic to return lazy slices for non-exact selectors.
  • Adds broadcasting support for AbstractSparseArray via a custom BroadcastStyle, producing SparseArray results.
  • Extends IndexedVarArray selection with a cache cutoff knob (set_cache_cutoff!) and integrates slice key-projection helpers into cached selection.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/testdata.jl Adds a small SparseArray fixture used by new slice/broadcast tests.
test/runtests.jl Adds coverage for SparseArraySlice behavior and broadcasting across SparseArray, slices, and IndexedVarArray.
src/SparseVariables.jl Wires in new slice.jl/broadcast.jl and exports new APIs/types.
src/sparsearray.jl Introduces _keytype interface and a generic haskey for AbstractSparseArray.
src/slice.jl Implements SparseArraySlice, key projection/reconstruction, and core slice behaviors.
src/indexedarray.jl Adds _keytype for IndexedVarArray, cache cutoff configuration, and slice-specific optimizations (cached key selection + efficient JuMP sum).
src/dictionaries.jl Refactors index classification (isfixed) and routes non-lookup indexing through _make_slice.
src/broadcast.jl Implements broadcast style, key compatibility checks, and materialization into SparseArray.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/dictionaries.jl
isfixed(::Type{T} where {T<:UnitRange}) = false
iscolon(t) = false
iscolon(::Type{T} where {T<:Colon}) = true
isfixed(::Type{T} where {T<:AbstractRange}) = false
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Colon() is a Function so there is no problem

Comment thread src/dictionaries.jl
Comment on lines 228 to +229
isfixed(::Type{T} where {T<:Function}) = false
isfixed(::Type{T} where {T<:UnitRange}) = false
iscolon(t) = false
iscolon(::Type{T} where {T<:Colon}) = true
isfixed(::Type{T} where {T<:AbstractRange}) = false
Comment thread src/slice.jl
Comment on lines +179 to +182
function Base.setindex!(::SparseArraySlice, _, _...)
return error("SparseArraySlice is read-only")
end

Comment thread src/broadcast.jl
bc::Base.Broadcast.Broadcasted{SparseBroadcastStyle{N,K}},
) where {N,K}
indices = _sparse_indices(bc)
isempty(indices) && return SparseArray(Dictionary{K,Any}())
Comment thread src/slice.jl
sa::P,
mask::MT,
) where {P<:AbstractSparseArray,MT<:Tuple}
K = _parent_keytype(P)
Comment thread src/slice.jl
Comment on lines +49 to +50
parent type, `NF` is the number of free (Colon) dimensions, and `FT` is the
projected key tuple type covering only the free dimensions. Implements
Comment thread src/slice.jl
return haskey(_data(v.parent), _reconstruct_key(v.mask, free_key, T))
end

Base.length(v::SparseArraySlice) = length(_view_matching_keys(v))
Comment thread src/indexedarray.jl
unsafe_insertvar!(var::indexedVarArray{V,N,T}, index...)

Insert a new variable with the given index withouth checking if the index is valid or
Insert a new variable with the given index withouth checking if the index is valid or
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.

2 participants