Sparsification of a Type

My first steps in julia, and one of the first in programming;)
I have defined MyType ( I need it both for Float, Rational{BigInt} and Complex, hence T<:Number

type MyType{T<:Number}
coords::Vector{T}
name::String
some_field::OtherType
etc.

I have defined methods for MyType e.g.

length(X::MyType) = length(X.coords)

Now I noticed that it would be nice to have coords stored as SparseVector.
How should I sparsify MyType? One obvious thing is to just rewrite everything with X.coords::SparseVector{T}. But there should be a better (less tedious) way… I tried to define MyType.coords as AbstractArray{T,1}. This somewhat works but (understandably) results in huge penalty in speed even for dense vectors…
(This is probably work for julia-0.6.0, as on 0.5 eg. enumeration of a sparse vector is painfully slow)

Side question: is there a way to make julia convert MyType automatically to Vector{T} so I don’t have to define non-specific methods (e.g. length above) for MyType?? I tried to go with convert:

import Base: convert
convert{T<:Number}(::Type{Vector{T}}, X::MyType) = X.coords

but this doesn’t work…

You could use type MyType{T<:AbstractVector}; coords::T; ... since e.g. SparseVector{Float64} is a subtype of AbstractVector.

If you want to make sure that non-real element types cannot be used, you can do:

typealias CoordVector{T<:Real} AbstractVector{T}
type MyType{T<:CoordVector}
    coords::T
    ...
end

Thanks for the answers;

I tried

typealias CoordinateVector{T<:Number} AbstractVector{T}

type MyType{T<:Number}
    coords::CoordinateVector{T}

but then Julia has problems inferring type of X.coords and plenty of ANY springs in the @code_warntype when using e.g zeros(X.coords). This is more or less the same what happened when I replaced coords by AbstractVector{T}.

Or does that actually comes from me insisting MyType to be parametrised by the type of elements of coords??

That won’t work because coords is still an abstract type. What about my suggestion?

I’m still trying to implement it, but this somehow requires more changes to the codebase;

I’m implementing an algebraic structure (ala polynomial ring), so thinking of MyType as
parametrised by the type of coefficients is very natural, whereas parametrising by type of coords list is inintuitive (but I’m fighting with this right now)

Since I already’ve answered:

This new parametrisation means that I have to change every definition (e.g.)

(+){S<:Number, T<:Number}(X::MyType{S},Y::MyType{T}) = ...

to

(+){S<:CoordinateVector, T<:CoordinateVector}(X::MyType{S},Y::MyType{T}) = ...

and more… before simple (+){S,T}(X::MyType{S},Y::MyType{T}) = ... was sufficient. Do You know why?

Ok, so I’ve run into some problems: well maybe not problems, but…
previously I had (the warn is important to me)

function (*){T<:Number, S<:Number}(a::T, X::MyType{S})
   T<:S || warn("coords and scalar are in different rings!")
   return MyType(a*X.coords)
end

Now I can not think of anything better than

function (*){<:Number, S<:CoordinateVector}(a::T, X::MyType{S})
    W = typeof(X.coordinates[1])
    T <: W || warn("coords and scalar are in different rings!")
    return MyType(a*X.coords)
end

which feels clunky…

If you wabt to dispatch by the type of coefficient, you can add another type parameter:

typealias CoordVector{T<:Real} AbstractVector{T}
type MyType{T<:Real,V<:CoordVector}
    coords::V
    ...
end
MyType(coords,...) = MyType{eltype(coords),typeof(coords)}(coords,...)

What you really want, it sounds like, is to parameterize on the type of coefficient, but also to ensure that your vector uses the same type, e.g.

type MyType{T<:Number,V<:AbstractVector{T}}
    coords::V
    ... other stuff depending on T ...
end

Unfortunately, this kind of type declaration (in which T appears twice in the parameters) is not currently possible. The good news is that it should be available soonish, once @JeffBezanson’s new subtyping branch (https://github.com/JuliaLang/julia/pull/18457) is merged. We’re all hoping that this can be merged in time for Julia 0.6.

1 Like

This was exactly what I tried after Your hint on the parametrisation by the type of coordinates/coefficients; glad to hear that something like this is on the list.

At the moment I went back to standard

type MyType{T}
    coords::Vector{T}
    ...
end

as the size of problems is too small to justify usage of sparse vectors

Thanks!