Skip to content
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 sparse arrays print more consistently, also add some doctests #20488

Merged
merged 10 commits into from
Feb 13, 2017
2 changes: 1 addition & 1 deletion base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ Example for a sparse 2-d array:

```jldoctest
julia> A = sparse([1, 1, 2], [1, 3, 1], [1, 2, -5])
2×3 sparse matrix with 3 Int64 stored entries:
2×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
[1, 1] = 1
[2, 1] = -5
[1, 3] = 2
Expand Down
83 changes: 66 additions & 17 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Returns the number of stored (filled) elements in a sparse array.

```jldoctest
julia> A = speye(3)
3×3 sparse matrix with 3 Float64 stored entries:
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand All @@ -58,7 +58,7 @@ modifications to the returned vector will mutate `A` as well. See

```jldoctest
julia> A = speye(3)
3×3 sparse matrix with 3 Float64 stored entries:
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand All @@ -82,7 +82,7 @@ nonzero values. See also [`nonzeros`](@ref) and [`nzrange`](@ref).

```jldoctest
julia> A = speye(3)
3×3 sparse matrix with 3 Float64 stored entries:
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -118,8 +118,10 @@ column. In conjunction with [`nonzeros`](@ref) and
nzrange(S::SparseMatrixCSC, col::Integer) = S.colptr[col]:(S.colptr[col+1]-1)

function Base.show(io::IO, ::MIME"text/plain", S::SparseMatrixCSC)
print(io, S.m, "×", S.n, " sparse matrix with ", nnz(S), " ", eltype(S), " stored entries")
if nnz(S) != 0
xnnz = nnz(S)
print(io, S.m, "×", S.n, " ", typeof(S), " with ", xnnz, " stored ",
xnnz == 1 ? "entry" : "entries")
if xnnz != 0
print(io, ":")
show(io, S)
end
Expand Down Expand Up @@ -147,8 +149,8 @@ function Base.show(io::IOContext, S::SparseMatrixCSC)
for col = 1:S.n, k = S.colptr[col] : (S.colptr[col+1]-1)
if k < half_screen_rows || k > nnz(S)-half_screen_rows
print(io, sep, '[', rpad(S.rowval[k], pad), ", ", lpad(col, pad), "] = ")
if isassigned(S.nzval, k)
Base.show(io, S.nzval[k])
if isassigned(S.nzval, Int(k))
show(io, S.nzval[k])
else
print(io, Base.undef_ref_str)
end
Expand Down Expand Up @@ -291,7 +293,12 @@ function copy!(A::SparseMatrixCSC, B::SparseMatrixCSC)
end

similar(S::SparseMatrixCSC, Tv::Type=eltype(S)) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), Array{Tv}(length(S.nzval)))
similar{Tv,Ti}(S::SparseMatrixCSC, ::Type{Tv}, ::Type{Ti}) = SparseMatrixCSC(S.m, S.n, convert(Array{Ti}, S.colptr), convert(Array{Ti}, S.rowval), Array{Tv}(length(S.nzval)))
function similar{Tv,Ti}(S::SparseMatrixCSC, ::Type{Tv}, ::Type{Ti})
new_colptr = copy!(similar(S.colptr, Ti), S.colptr)
new_rowval = copy!(similar(S.rowval, Ti), S.rowval)
new_nzval = copy!(similar(S.nzval, Tv), S.nzval)
SparseMatrixCSC(S.m, S.n, new_colptr, new_rowval, new_nzval)
end
@inline similar{Tv}(S::SparseMatrixCSC, ::Type{Tv}, d::Dims) = spzeros(Tv, d...)

# convert'ing between SparseMatrixCSC types
Expand Down Expand Up @@ -340,7 +347,7 @@ Convert a sparse matrix or vector `S` into a dense matrix or vector.

```jldoctest
julia> A = speye(3)
3×3 sparse matrix with 3 Float64 stored entries:
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -376,7 +383,7 @@ julia> A = eye(3)
0.0 0.0 1.0

julia> sparse(A)
3×3 sparse matrix with 3 Float64 stored entries:
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -457,7 +464,7 @@ julia> Js = [1; 2; 3];
julia> Vs = [1; 2; 3];

julia> sparse(Is, Js, Vs)
3×3 sparse matrix with 3 Int64 stored entries:
3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
[1, 1] = 1
[2, 2] = 2
[3, 3] = 3
Expand Down Expand Up @@ -1253,6 +1260,19 @@ which the probability of any element being nonzero is independently given by
values are sampled from the distribution specified by `rfn` and have the type `type`. The uniform
distribution is used in case `rfn` is not specified. The optional `rng`
argument specifies a random number generator, see [Random Numbers](@ref).

```jldoctest
julia> rng = MersenneTwister(1234);

julia> sprand(rng, Bool, 2, 2, 0.5)
2×2 SparseMatrixCSC{Bool,Int64} with 2 stored entries:
[1, 1] = true
[2, 1] = true

julia> sprand(rng, Float64, 3, 0.75)
3-element SparseVector{Float64,Int64} with 1 stored entry:
[3] = 0.298614
````
"""
function sprand{T}(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat,
rfn::Function, ::Type{T}=eltype(rfn(r,1)))
Expand Down Expand Up @@ -1291,6 +1311,16 @@ Create a random sparse vector of length `m` or sparse matrix of size `m` by `n`
with the specified (independent) probability `p` of any entry being nonzero,
where nonzero values are sampled from the normal distribution. The optional `rng`
argument specifies a random number generator, see [Random Numbers](@ref).

```jldoctest
julia> rng = MersenneTwister(1234);

julia> sprandn(rng, 2, 2, 0.75)
2×2 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 0.532813
[2, 1] = -0.271735
[2, 2] = 0.502334
```
"""
sprandn(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat) = sprand(r,m,n,density,randn,Float64)
sprandn(m::Integer, n::Integer, density::AbstractFloat) = sprandn(GLOBAL_RNG,m,n,density)
Expand All @@ -1304,14 +1334,14 @@ element having the value `1.0`.

```jldoctest
julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.])
4×4 sparse matrix with 4 Float64 stored entries:
4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
[4, 1] = 2.0
[1, 2] = 5.0
[3, 3] = 3.0
[2, 4] = 4.0

julia> spones(A)
4×4 sparse matrix with 4 Float64 stored entries:
4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
[4, 1] = 1.0
[1, 2] = 1.0
[3, 3] = 1.0
Expand All @@ -1330,6 +1360,14 @@ Create a sparse vector of length `m` or sparse matrix of size `m x n`. This
sparse array will not contain any nonzero values. No storage will be allocated
for nonzero values during construction. The type defaults to `Float64` if not
specified.

```jldoctest
julia> spzeros(3, 3)
3×3 SparseMatrixCSC{Float64,Int64} with 0 stored entries

julia> spzeros(Float32, 4)
4-element SparseVector{Float32,Int64} with 0 stored entries
```
"""
spzeros(m::Integer, n::Integer) = spzeros(Float64, m, n)
spzeros(Tv::Type, m::Integer, n::Integer) = spzeros(Tv, Int, m, n)
Expand All @@ -1351,14 +1389,14 @@ Create a sparse identity matrix with the same size as `S`.

```jldoctest
julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.])
4×4 sparse matrix with 4 Float64 stored entries:
4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
[4, 1] = 2.0
[1, 2] = 5.0
[3, 3] = 3.0
[2, 4] = 4.0

julia> speye(A)
4×4 sparse matrix with 4 Float64 stored entries:
4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -2733,6 +2771,17 @@ end
dropstored!(A::SparseMatrixCSC, i::Integer, j::Integer)

Drop entry `A[i,j]` from `A` if `A[i,j]` is stored, and otherwise do nothing.

```jldoctest
julia> A = sparse([1 2; 0 0])
2×2 SparseMatrixCSC{Int64,Int64} with 2 stored entries:
[1, 1] = 1
[1, 2] = 2

julia> Base.SparseArrays.dropstored!(A, 1, 2); A
2×2 SparseMatrixCSC{Int64,Int64} with 1 stored entry:
[1, 1] = 1
```
"""
function dropstored!(A::SparseMatrixCSC, i::Integer, j::Integer)
if !((1 <= i <= A.m) & (1 <= j <= A.n))
Expand Down Expand Up @@ -2935,7 +2984,7 @@ Concatenate matrices block-diagonally. Currently only implemented for sparse mat
# Example
```jldoctest
julia> blkdiag(speye(3), 2*speye(2))
5×5 sparse matrix with 5 Float64 stored entries:
5×5 SparseMatrixCSC{Float64,Int64} with 5 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -3143,7 +3192,7 @@ of the resulting sparse matrix.

```jldoctest
julia> spdiagm(([1,2,3,4],[4,3,2,1]),(-1,1))
5×5 sparse matrix with 8 Int64 stored entries:
5×5 SparseMatrixCSC{Int64,Int64} with 8 stored entries:
[2, 1] = 1
[1, 2] = 4
[3, 2] = 2
Expand Down
86 changes: 74 additions & 12 deletions base/sparse/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ count(x::SparseVector) = count(x.nzval)
nonzeros(x::SparseVector) = x.nzval
nonzeroinds(x::SparseVector) = x.nzind

similar(x::SparseVector, Tv::Type=eltype(x)) = SparseVector(x.n, copy(x.nzind), Array{Tv}(length(x.nzval)))
function similar{Tv,Ti}(x::SparseVector, ::Type{Tv}, ::Type{Ti})
return SparseVector(x.n, copy!(similar(x.nzind, Ti), x.nzind), copy!(similar(x.nzval, Tv), x.nzval))
end
similar{T}(x::SparseVector, ::Type{T}, D::Dims) = spzeros(T, D...)

### Construct empty sparse vector

spzeros(len::Integer) = spzeros(Float64, len)
spzeros{T}(::Type{T}, len::Integer) = SparseVector(len, Int[], T[])
spzeros{Tv, Ti <: Integer}(::Type{Tv}, ::Type{Ti}, len::Integer) = SparseVector(len, Ti[], Tv[])

# Construction of same structure, but with all ones
spones{T}(x::SparseVector{T}) = SparseVector(x.n, copy(x.nzind), ones(T, length(x.nzval)))
Expand Down Expand Up @@ -97,6 +102,28 @@ Create a sparse vector `S` of length `m` such that `S[I[k]] = V[k]`.
Duplicates are combined using the `combine` function, which defaults to
`+` if no `combine` argument is provided, unless the elements of `V` are Booleans
in which case `combine` defaults to `|`.

```jldoctest
julia> II = [1, 3, 3, 5]; V = [0.1, 0.2, 0.3, 0.2];

julia> sparsevec(II, V)
5-element SparseVector{Float64,Int64} with 3 stored entries:
[1] = 0.1
[3] = 0.5
[5] = 0.2

julia> sparsevec(II, V, 8, -)
8-element SparseVector{Float64,Int64} with 3 stored entries:
[1] = 0.1
[3] = -0.1
[5] = 0.2

julia> sparsevec([1, 3, 1, 2, 2], [true, true, false, false, false])
3-element SparseVector{Bool,Int64} with 3 stored entries:
[1] = true
[2] = false
[3] = true
```
"""
function sparsevec(I::AbstractVector{<:Integer}, V::AbstractVector, combine::Function)
length(I) == length(V) ||
Expand Down Expand Up @@ -144,10 +171,17 @@ sparsevec(I::AbstractVector, v::Number, len::Integer, combine::Function) =

### Construction from dictionary
"""
sparsevec(D::Dict, [m])
sparsevec(d::Dict, [m])

Create a sparse vector of length `m` where the nonzero indices are keys from
the dictionary, and the nonzero values are the values from the dictionary.

```jldoctest
julia> sparsevec(Dict(1 => 3, 2 => 2))
2-element SparseVector{Int64,Int64} with 2 stored entries:
[1] = 3
[2] = 2
```
"""
function sparsevec{Tv,Ti<:Integer}(dict::Associative{Ti,Tv})
m = length(dict)
Expand Down Expand Up @@ -218,6 +252,21 @@ setindex!{Tv, Ti<:Integer}(x::SparseVector{Tv,Ti}, v, i::Integer) =
dropstored!(x::SparseVector, i::Integer)

Drop entry `x[i]` from `x` if `x[i]` is stored and otherwise do nothing.

```jldoctest
julia> x = sparsevec([1, 3], [1.0, 2.0])
3-element SparseVector{Float64,Int64} with 2 stored entries:
[1] = 1.0
[3] = 2.0

julia> Base.SparseArrays.dropstored!(x, 3)
3-element SparseVector{Float64,Int64} with 1 stored entry:
[1] = 1.0

julia> Base.SparseArrays.dropstored!(x, 2)
3-element SparseVector{Float64,Int64} with 1 stored entry:
[1] = 1.0
```
"""
function dropstored!(x::SparseVector, i::Integer)
if !(1 <= i <= x.n)
Expand Down Expand Up @@ -255,6 +304,14 @@ convert{Tv,Ti}(::Type{SparseVector}, s::SparseMatrixCSC{Tv,Ti}) =
sparsevec(A)

Convert a vector `A` into a sparse vector of length `m`.

```jldoctest
julia> sparsevec([1.0, 2.0, 0.0, 0.0, 3.0, 0.0])
6-element SparseVector{Float64,Int64} with 3 stored entries:
[1] = 1.0
[2] = 2.0
[5] = 3.0
```
"""
sparsevec{T}(a::AbstractVector{T}) = convert(SparseVector{T, Int}, a)
sparsevec(a::AbstractArray) = sparsevec(vec(a))
Expand Down Expand Up @@ -677,8 +734,13 @@ getindex(x::AbstractSparseVector, ::Colon) = copy(x)
### show and friends

function show(io::IO, ::MIME"text/plain", x::AbstractSparseVector)
println(io, summary(x))
show(io, x)
xnnz = length(nonzeros(x))
print(io, length(x), "-element ", typeof(x), " with ", xnnz,
" stored ", xnnz == 1 ? "entry" : "entries")
if xnnz != 0
println(io, ":")
show(io, x)
end
end

show(io::IO, x::AbstractSparseVector) = show(convert(IOContext, io), x)
Expand All @@ -688,30 +750,30 @@ function show(io::IOContext, x::AbstractSparseVector)
nzind = nonzeroinds(x)
nzval = nonzeros(x)
xnnz = length(nzind)

if length(nzind) == 0
return show(io, MIME("text/plain"), x)
end
limit::Bool = get(io, :limit, false)
half_screen_rows = limit ? div(displaysize(io)[1] - 8, 2) : typemax(Int)
pad = ndigits(n)
sep = "\n\t"
if !haskey(io, :compact)
io = IOContext(io, :compact => true)
end
for k = 1:length(nzind)
if k < half_screen_rows || k > xnnz - half_screen_rows
print(io, " ", '[', rpad(nzind[k], pad), "] = ")
Base.show(io, nzval[k])
println(io)
if isassigned(nzval, Int(k))
show(io, nzval[k])
else
print(io, Base.undef_ref_str)
end
k != length(nzind) && println(io)
elseif k == half_screen_rows
println(io, " ", " "^pad, " \u22ee")
end
end
end

function summary(x::AbstractSparseVector)
string("Sparse vector of length ", length(x), " with ", length(nonzeros(x)),
" ", eltype(x), " nonzero entries:")
end

### Conversion to matrix

function convert{Tv,Ti}(::Type{SparseMatrixCSC{Tv,Ti}}, x::AbstractSparseVector)
Expand Down
Loading