Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/constructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ You can sample nonzero values from a different distribution by passing a
custom `rfn` function instead of `rand`. This should be a function `rfn(k)`
that returns an array of `k` random numbers sampled from the desired distribution;
alternatively, if `rng` is supplied, it should instead be a function `rfn(rng, k)`.
Passing `T` after `rfn` converts the values that `rfn` returns to `T`.

# Examples
```jldoctest; setup = :(using Random; Random.seed!(1234))
Expand All @@ -711,16 +712,27 @@ julia> sprand(Float64, 3, 0.75)
[2] = 0.49425
```
"""
function sprand(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, rfn::Function, ::Type{T}=eltype(rfn(r, 1))) where T
function sprand(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, rfn::Function, ::Type{T}) where T
m, n = Int(m), Int(n)
I, V = _sprandvalues(r, m, n, density, rfn)
return sparse_sortedlinearindices!(I, convert(Vector{T}, V), m, n)
end
function sprand(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, rfn::Function)
m, n = Int(m), Int(n)
I, V = _sprandvalues(r, m, n, density, rfn)
return sparse_sortedlinearindices!(I, convert(Vector{eltype(V)}, V), m, n)
end
function _sprandvalues(r::AbstractRNG, m::Int, n::Int, density::AbstractFloat, rfn::F) where {F}
(m < 0 || n < 0) && throw(ArgumentError("invalid Array dimensions"))
0 <= density <= 1 || throw(ArgumentError("$density not in [0,1]"))
I = randsubseq(r, 1:(m*n), density)
return sparse_sortedlinearindices!(I, convert(Vector{T}, rfn(r,length(I))), m, n)
return I, rfn(r, length(I))
end

sprand(m::Integer, n::Integer, density::AbstractFloat, rfn::Function, ::Type{T} = eltype(rfn(1))) where {T} =
sprand(m::Integer, n::Integer, density::AbstractFloat, rfn::Function) =
sprand(default_rng(), m, n, density, (r, i) -> rfn(i))
sprand(m::Integer, n::Integer, density::AbstractFloat, rfn::Function, ::Type{T}) where {T} =
sprand(default_rng(), m, n, density, (r, i) -> rfn(i), T)

truebools(r::AbstractRNG, n::Integer) = fill(true, n)

Expand Down
11 changes: 8 additions & 3 deletions src/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -768,11 +768,16 @@ end


### Rand Construction
sprand(n::Integer, p::AbstractFloat, rfn::Function, ::Type{T}) where {T} = sprand(default_rng(), n, p, rfn, T)
# `rfn(rng, T, k)` predates the documented `rfn(k)` and `rfn(rng, k)` and is still accepted
function sprand(n::Integer, p::AbstractFloat, rfn::Function, ::Type{T}) where {T}
r = default_rng()
applicable(rfn, r, T, 0) && return sprand(r, n, p, rfn, T)
return sprand(r, n, p, (r, i) -> rfn(i), T)
end
function sprand(r::AbstractRNG, n::Integer, p::AbstractFloat, rfn::Function, ::Type{T}) where T
I = randsubseq(r, 1:convert(Int, n), p)
V = rfn(r, T, length(I))
SparseVector(n, I, V)
V = applicable(rfn, r, T, length(I)) ? rfn(r, T, length(I)) : rfn(r, length(I))
SparseVector(n, I, convert(Vector{T}, V))
end

sprand(n::Integer, p::AbstractFloat, rfn::Function) = sprand(default_rng(), n, p, (r, i) -> rfn(i))
Expand Down
1 change: 1 addition & 0 deletions test/constructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ end
@static if COMPREHENSIVE
m = sprand(Float32, 10, 10, 0.1)
@test eltype(m) == Float32
@test eltype(sprand(10, 10, 0.5, k -> rand(Int8, k), Float64)) == Float64
end
m = sprand(Float64, 10, 10, 0.1)
@test eltype(m) == Float64
Expand Down
8 changes: 8 additions & 0 deletions test/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,14 @@ end
@test xv == xr
@test sprand(20, 1, 0.5, rfn1) isa SparseMatrixCSC{Int8,Int}
@test sprand(MersenneTwister(5), 20, 1, 0.5, rfn2) isa SparseMatrixCSC{Int8,Int}
# and with `T`, which the older `rfn(rng, T, k)` still accepts
@test sprand(20, 0.5, rfn1, Float64) isa SparseVector{Float64,Int}
@test sprand(MersenneTwister(5), 20, 0.5, rfn2, Float64) isa SparseVector{Float64,Int}
@test sprand(MersenneTwister(5), 20, 0.5, (r, T, k) -> rand(r, T, k), Float64) isa SparseVector{Float64,Int}
# without `T`, `rfn` is called once, for the values
calls = Ref(0)
sprand(MersenneTwister(5), 4, 4, 0.5, (r, k) -> (calls[] += 1; rand(r, Int8, k)))
@test calls[] == 1
end
end
end
Expand Down
Loading