Skip to content

Conversation

@max-vassili3v
Copy link
Contributor

This pull request alters some behaviour of addition/subtraction of the Zeros and OneElement types. It ensures that the sparsity of any array structure that undergoes addition or subtraction with one of these types preserves its sparsity by avoiding the materialisation of dense arrays where possible:

-Adding or subtracting a Zeros and any array v now preserves the type of v (while still obeying type promotion rules)
-Adding or subtracting a OneElement to any array v is now O(1) and preserves the type of v unless the underlying setindex! operation is invalid (e.g adding a OneElement with a nondiagonal entry to a Diagonal), in which case a dense array is materialised
-Adding or subtracting two OneElements now returns a OneElement if their indices are the same. Otherwise it materialises a dense vector. If SparseArrays is imported, it instead creates a SparseArray.

Changes have been covered with unit tests

@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 62.85714% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.71%. Comparing base (0a58cd8) to head (33466e1).

Files with missing lines Patch % Lines
src/oneelement.jl 48.83% 22 Missing ⚠️
ext/FillArraysSparseArraysExt.jl 33.33% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #422       +/-   ##
===========================================
+ Coverage    0.00%   97.71%   +97.71%     
===========================================
  Files           8        9        +1     
  Lines        1152     1224       +72     
===========================================
+ Hits            0     1196     +1196     
+ Misses       1152       28     -1124     

☔ 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.

@max-vassili3v max-vassili3v changed the title Zeros operations Zeros and OneElement addition/subtraction Dec 5, 2025

# OneElements with different indices should return
# SparseArrays under addition
function FillArrays.oneelement_addsub(a::OneElementVector, b::OneElementVector, aval, bval)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure whether having the behaviour depend on loading an extension is a good idea...

ret = copy(b)
try
ret[a.ind...] += getindex_value(a)
catch
Copy link
Member

Choose a reason for hiding this comment

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

This is a non-standard idiom and introduces a type instability

catch
# Fallback to materialising dense array if setindex!
# goes wrong (e.g on a Diagonal)
ret = Array(ret)
Copy link
Member

Choose a reason for hiding this comment

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

type unstable


@test B - B isa OneElement
@test B - B == OneElement(0, 2, 5)
@test B - A == [0, -1, 1, 0, 0]
Copy link
Member

Choose a reason for hiding this comment

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

Add test with adding AbstractArray

B = OneElement(3, 5)

@test A + A isa OneElement
@test A + A == OneElement(2, 2, 5)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@test A + A == OneElement(2, 2, 5)
@test @inferred(A + A) == OneElement(2, 2, 5)

nzind = ntuple(i -> [a.ind[i], b.ind[i]], ndims(a))
return sparse(nzind..., nzval, size(a)...)
end

Copy link
Member

Choose a reason for hiding this comment

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

ADd one element + sparse array special case

-(a::AbstractArray, b::OneElement) = sub_one_elem(a, b)
-(a::OneElement, b::AbstractArray) = sub_one_elem(a, b)
# disambiguity
function +(a::AbstractZeros, b::OneElement)
Copy link
Member

Choose a reason for hiding this comment

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

Should we be overloading broadcast + too?

if a.ind == b.ind
return OneElement($op(getindex_value(a), getindex_value(b)), a.ind, axes(a))
else
return oneelement_addsub(a, b, getindex_value(a), $bop)
Copy link
Member

Choose a reason for hiding this comment

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

type unstable

@dlfivefifty
Copy link
Member

dlfivefifty commented Dec 10, 2025

Main suggestions:

  • split off StaticArrays.jl extension into separate PR
  • make SparseArrays.jl a hard dependency (others may have opinions about this...)
  • make sure 100% of the diff is covered

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