-
-
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
make SparseMatrixCSC and SparseVector work on non-numerical values #30580
Conversation
Approach 3 using "AbstractMatrixCSC" I noted in #30173 (comment) could be used to alter the behavior for One approach could be to define (say): absent(::AbstractMatrixCSC{T}) where T = zero(T)
isabsentvalue(::AbstractMatrixCSC, x) = iszero(x) so that users can overload |
Sure, or absent/background value could be stored in the matrix itself (one may would like to use the same type with two different absent values). This seems nice. |
Considering a non-zero absent value can be considered separately from this issue. To avoid delaying the improvement of this PR, I'll suggest that we discuss it elsewhere. I believe it is already covered by existing issues. |
Let's rebase on master and try another go at the CI, and hope we pick up CI fixes. |
Sure, thanks @ViralBShah. At first sight errors seem related though (even if I don't understand exactly how). Question: does it make sense to add the following lines somewhere:
The rationale is that whenever a type has |
For now, in order to get tests to pass, let's add it to the sparse matrix code. But before merging, we do need to find the right place to add it to (assuming everything else works out) |
Rethinking, the alternatives I see are
Maybe 2) is the less disruptive? |
I like option 2 as well. That would mean the user of a new type has to at best define |
Errr... please advise. With this PR, it will be forbidden to make a BTW this uncovers yet another type ( |
EDIT: I commented out the test for the time being and all checks pass now. |
Following up on Any of the proposals in |
Note that |
I found #10410 addressing this, but no associated PR. I think it makes perfect sense, especially for purely numerical matrices. I don't really know how hard would it be to implement, but even a partial implementation would help with non-numerical types. In any case I agree that it is something that should be discussed separately, sorry. |
You mean without a specific element type? With an element type a matrix of zeros of that element type is the correct matrix zero element. |
I don't think so, even knowing the element type, because it would depend on the size. |
I think the point is that @abraunst Why is it that you are using |
The rationale was to avoid forcing the user to define both EDIT: Said that, it is a matter of rolling back one commit, because that is what I started with. One could maybe add #30580 (comment) to make a default zero(x::T) |
Duh, of course. |
I like consistently using I didn't quite catch the issue that precipitated the problem with
I think that's an okay situation for now. It maintains the property that we can construct We can try to improve |
Yes, exactly. I worried about the fact that this PR eliminates functionality (the ability to construct arrays of
Okay, I'll roll back the commits! EDIT: done |
I think, replacing the checks for In the case of |
What do you think about adding:
|
Was reminded by this when looking into Graph Algorithms in the Language of Linear Algebra. With the changes in this pr and similar changes to struct SemiRing{T,P,M} <: Number
val::T
end
import Base: +, *
(+)(x::SemiRing{T,A,M}, y::SemiRing{T,A,M}) where {T,A,M} = SemiRing{T,A,M}(A(x.val, y.val))
(*)(x::SemiRing{T,A,M}, y::SemiRing{T,A,M}) where {T,A,M} = SemiRing{T,A,M}(M(x.val, y.val))
Base.promote_rule(::Type{SemiRing{T,A,M}}, ::Type{SemiRing{S,A,M}}) where {T,S,A,M} = SemiRing{promote_type(T,S),A,M}
Base.zero(::Type{SemiRing{T,min,M}}) where {T,M} = SemiRing{T,min,M}(typemax(T))
Base.one(::Type{SemiRing{T,A,+}}) where {T,A} = SemiRing{T,A,+}(zero(T))
Base.iszero(x::SemiRing{T,A,M}) where {T,A,M} = x == zero(SemiRing{T,A,M})
Base.isone(x::SemiRing{T,A,M}) where {T,A,M} = x == one(SemiRing{T,A,M})
Base.conj(x::SemiRing{<:Real}) = x and then example from Figure 24.6 in Algorithms becomes (notice that julia> ∞ = Inf
Inf
julia> A = sparse(SemiRing{Float64,min,+}[0 10 5 ∞ ∞
∞ 0 ∞ 1 ∞
∞ 3 0 9 2
∞ ∞ ∞ 0 4
7 ∞ ∞ 6 0]);
julia> d = SemiRing{Float64,min,+}[0,∞,∞,∞,∞];
julia> d = A'd
5-element Array{SemiRing{Float64,min,+},1}:
SemiRing{Float64,min,+}(0.0)
SemiRing{Float64,min,+}(10.0)
SemiRing{Float64,min,+}(5.0)
SemiRing{Float64,min,+}(Inf)
SemiRing{Float64,min,+}(Inf)
julia> d = A'd
5-element Array{SemiRing{Float64,min,+},1}:
SemiRing{Float64,min,+}(0.0)
SemiRing{Float64,min,+}(8.0)
SemiRing{Float64,min,+}(5.0)
SemiRing{Float64,min,+}(11.0)
SemiRing{Float64,min,+}(7.0)
julia> d = A'd
5-element Array{SemiRing{Float64,min,+},1}:
SemiRing{Float64,min,+}(0.0)
SemiRing{Float64,min,+}(8.0)
SemiRing{Float64,min,+}(5.0)
SemiRing{Float64,min,+}(9.0)
SemiRing{Float64,min,+}(7.0) |
This is nice at least as a pedagogical tool 👍
If I remember correctly, the changes in |
I think, this PR should be re-based onto the current status. |
Let's rebase and get this in if there is still interest. |
I've resolved the conflicts. There haven't been any objections to the proposal here so I'll merge. We can handle/discuss remaining details regarding |
Aweomse! |
There still seems to be |
This addresses #30573. It amounts essentially in replacing
!= 0
byiszero
in sparsematrix.jl and sparsevector.jl. For a type T to work, it needs to define zero(T) and zero(x::T). Is it possible/reasonable to add a fallback definitionzero(x::T) where T = zero(T)
somewhere (where)?