Sprand fails to construct a SparseVector

I can construct a random SparseMatrixCSC, but not a SparseVector in the same way. Where am I wrong?

julia> using SparseArrays

julia> rfn = n -> rand(-9:.1:9, n)
#1 (generic function with 1 method)

julia> sprand(7, 8, .2, rfn)
7×8 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
   ⋅   4.3   ⋅    2.5    ⋅    ⋅   0.1    ⋅ 
   ⋅    ⋅    ⋅   -3.0    ⋅    ⋅    ⋅     ⋅ 
   ⋅    ⋅    ⋅     ⋅    5.3   ⋅    ⋅     ⋅ 
  5.1   ⋅   3.8    ⋅    4.9   ⋅    ⋅     ⋅ 
 -3.4   ⋅    ⋅     ⋅     ⋅   4.3   ⋅     ⋅ 
   ⋅    ⋅    ⋅     ⋅     ⋅    ⋅    ⋅     ⋅ 
   ⋅    ⋅    ⋅     ⋅   -0.1   ⋅   3.0  -6.6

julia> sprand(8, .2, rfn)
ERROR: MethodError: no method matching (::var"#1#2")(::Random.TaskLocalRNG, ::Int64)
The function `#1` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  (::var"#1#2")(::Any)
   @ Main REPL[2]:1

Stacktrace:
 [1] sprand(r::Random.TaskLocalRNG, n::Int64, p::Float64, rfn::var"#1#2")
   @ SparseArrays K:\julia-1.11.5\share\julia\stdlib\v1.11\SparseArrays\src\sparsevector.jl:648
 [2] sprand(n::Int64, p::Float64, rfn::Function)
   @ SparseArrays K:\julia-1.11.5\share\julia\stdlib\v1.11\SparseArrays\src\sparsevector.jl:645
 [3] top-level scope
   @ REPL[4]:1

julia> sprand(8, .2)
8-element SparseVector{Float64, Int64} with 1 stored entry:
  [3]  =  0.724307

As explained in the sprand docstring, the requirement for the rfn argument is that it has two methods, rfn(k) and rfn(rng, k). So the following works:

julia> using SparseArrays

julia> rfn(k) = rand(-9:0.1:9, k)
rfn (generic function with 1 method)

julia> rfn(rng, k) = rand(rng, -9:0.1:9, k)
rfn (generic function with 2 methods)

julia> sprand(7, .2, rfn)
7-element SparseVector{Float64, Int64} with 3 stored entries:
  [4]  =  8.5
  [5]  =  -3.2
  [7]  =  4.4
1 Like

Make some sense, but I think it is unjustly involved.

julia> using SparseArrays

julia> my_range, N, p = -9:.1:9, 30, .15
(-9.0:0.1:9.0, 30, 0.15)

julia> my_vector        = rand(my_range, N);

julia> my_sparse_vector = sprand(N, p, (rng, n) -> rand(rng, my_range, n))
30-element SparseVector{Float64, Int64} with 3 stored entries:
  [1 ]  =  -6.7
  [17]  =  -5.4
  [21]  =  7.7

To be honest, the interface is not intuitive or consistent enough.

There’s an open issue for that:

The rfn signature must be preserved for backward compatibility, but if you can think of better signatures that can be added without breaking or removing the existing ones, please submit a comment or PR! I don’t think anyone particularly likes the current interface for sampling sparse arrays with arbitrary distributions.

1 Like