-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SparseMatrix and SparseArray don't consitently define zero elements and allowed element types #24790
Comments
Could you give a code snippet as an example where these "inconsistencies" lead to an inconsistent result? |
The issue needs a better title! Would be nice to have consistency. |
Another code snippet, demonstrating the need (v0.6.1 and v0.7-DEV):
Generally it is not possible to take advantage of the storage economy of sparse arrays for dimensionful or unitful element types. |
Ref #9325 |
@KristofferC : I see that this issue has bee discussed 3 years ago. The main argument then, not to change anything (as I undestood), was performance. |
I ran into this while giving a demonstration of Julia to a friend. We had a custom struct type with Due to the julia> struct MyType
val::Bool
end
julia> Base.zero(::Type{MyType}) = MyType(false)
julia> Base.iszero(x::MyType) = x.val == false
julia> sparse([MyType(true), MyType(false)])
2-element SparseVector{MyType,Int64} with 2 stored entries:
[1] = MyType(true)
[2] = MyType(false) |
I had same issue, is there a progress on this issue ? What are the challenges ? |
In best case, changing some |
@yurivish I made a PR on your problem. Now returning:
Is it ok for you ? |
Thanks! That is the behavior I think is right in this case. |
@KlausC do you think my commit has a chance to be merged? |
@Lecrapouille, which PR do you mean exactly? You know I have been trying to clean-up some of the inconsistencies in The bugs you point out in issue https://github.com/JuliaLang/julia/issues/33332 are still not fixed. I support your fixes mentioned there, but lost overview of which is the PR providing the fix. BTW, the example you mention here: #24790 (comment) seems to work for me without your PR merged. (not in v"1.2" but in v"1.5.0") |
When I first worked with sparse matrices, I was convinced, that the element type of those objects were
AbstractFloat
types. I am easily convinced, that allNumber
types make sense as well. Nevertheless there there seems to be a sloppy idea of which element types are actually intended.The constructors of sparse arrays accept any element type. But you can call certain functions on sparse arrays only, if the element type supports certain methods. So the element types are de facto restricted by a kind of duck typing. The methods, which I refer to, include
!= 0, == 0, != zero, == zero, isequal, iszero
for the question, if an element to be processed is zero or not.I see, that all those alternatives lead to the same result for
Number
s (with the exception of==
andisequal
, which deserves a separate consideration in the case of±0.0
).But if I want to use a different element type
Tv
, I have to support this type with a consistent behaviour for all of those methods. That is far more inconvenient than just have to definezero(::Type{Tv})
, what would be sufficient in the case of a consistent use within theSparseArrays
module.Using
iszero(x)
would be a proper choice. It falls back tox == zero(typeof(x))
. Comparison with0
is good for ifx isa Number
, but leads into a blind alley, for other types, because all elements would be stored silently (even ifzero
is defined).Here is a list of the current implementation (v0.7 2017-11-24) which illustrates the diversity in handling zeros:
How (and where) is defined, if an entry is considered a zero?
v != 0
v != 0
v != 0
v != zero(Tv)
x != 0
x != 0
x != 0
x != 0
x != 0
x != 0
x != 0
x != 0
x != 0
convert(eltype(A), x) != zero(eltype(A))
v != zero(v)
v == zero(T)
isequal(f(zero(Tv)), zero(Tv)
iszero(A.nzval)
iszero(x)
sparsematrix.jl:1520isequal(v, zero(T))
x == 0
Base.iszero(x::Number)
Base.iszero(x::AbstractArray)
How is zero element created?
zero(eltype(A))
zero(Tv)
zero(T)
zero(Tv)
zero(eltype(S))
zero(eltype(S))
zeros(Tv, m, n)
zero(T)
zero(T)
zero(T)
zero(T)
zeros(Tv,m)
zeros(eltype(A))
Inconsitencies
setindex!(A, -0.0, ind...)
behavior depends on ind is structural zero or notExample where the result of
getindex
depends on the pre-history (before the lastsetindex!
):Proposal:
Change in sparse/*jl all the checks if x is zero by the call
iszero(x)
.Amend the documentation with a hint, that the element types of
SparseArrays
need to define the `zero(::Type{T}) method.Change the values of all
AbstractFloat
zero values-0.0
to+0.0
of the same type, before they are stored intonzvals
.Change the documentation about
getindex(::AbstractSparseArray{T},...)
to mention, that all returned zeros have positive signs forT<:Number
.Define a fallback method
Base.zero(x) = zero(typeof(x))
andBase.zero(::Type{T}) where T = error("...")
. That would be in accordance to current doc ofzero
.The text was updated successfully, but these errors were encountered: