Skip to content

Commit

Permalink
make sparse and dense arrays print more similarly
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferC committed Feb 7, 2017
1 parent 0900553 commit 5526b5f
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 28 deletions.
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
70 changes: 57 additions & 13 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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 @@ -57,7 +57,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 @@ -81,7 +81,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 @@ -117,7 +117,9 @@ 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")
xnnz = nnz(S)
print(io, S.m, "×", S.n, " ", typeof(S), " with ", nnz(S), " stored ",
xnnz == 1 ? "entry" : "entries")
if nnz(S) != 0
print(io, ":")
show(io, S)
Expand Down Expand Up @@ -339,7 +341,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 @@ -375,7 +377,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 @@ -456,7 +458,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 @@ -1252,6 +1254,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 @@ -1290,6 +1305,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 @@ -1303,14 +1328,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 @@ -1329,6 +1354,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 @@ -1350,14 +1383,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 @@ -2732,6 +2765,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 entries:
[1, 2] = 1
```
"""
function dropstored!(A::SparseMatrixCSC, i::Integer, j::Integer)
if !((1 <= i <= A.m) & (1 <= j <= A.n))
Expand Down Expand Up @@ -2934,7 +2978,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 @@ -3142,7 +3186,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
75 changes: 64 additions & 11 deletions base/sparse/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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{Ti<:Integer}(I::AbstractVector{Ti}, V::AbstractVector, combine::Function)
length(I) == length(V) ||
Expand Down Expand Up @@ -144,10 +166,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 => 4))
2-element SparseVector{Int64,Int64} with 2 stored entries:
[1] = 3
[2] = 4
```
"""
function sparsevec{Tv,Ti<:Integer}(dict::Associative{Ti,Tv})
m = length(dict)
Expand Down Expand Up @@ -218,6 +247,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 entries:
[1] = 1.0
julia> Base.SparseArrays.dropstored!(x, 2)
3-element SparseVector{Float64,Int64} with 1 stored entries:
[1] = 1.0
```
"""
function dropstored!(x::SparseVector, i::Integer)
if !(1 <= i <= x.n)
Expand Down Expand Up @@ -255,6 +299,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 @@ -678,8 +730,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 ", nnz == 1 ? "entry" : "entries")
if xnnz != 0
println(io, ":")
show(io, x)
end
end

function show(io::IO, x::AbstractSparseVector)
Expand All @@ -688,11 +745,12 @@ function show(io::IO, 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"
io = IOContext(io)
if !haskey(io, :compact)
io = IOContext(io, :compact => true)
Expand All @@ -701,18 +759,13 @@ function show(io::IO, x::AbstractSparseVector)
if k < half_screen_rows || k > xnnz - half_screen_rows
print(io, " ", '[', rpad(nzind[k], pad), "] = ")
Base.show(io, nzval[k])
println(io)
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{TvD,TiD,Tv,Ti}(::Type{SparseMatrixCSC{TvD,TiD}}, x::AbstractSparseVector{Tv,Ti})
Expand Down
6 changes: 3 additions & 3 deletions doc/src/manual/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -754,10 +754,10 @@ sparse matrices instead, you can use the same names with an `sp` prefix:

```jldoctest
julia> spzeros(3,5)
3×5 sparse matrix with 0 Float64 stored entries
3×5 SparseMatrixCSC{Float64,Int64} with 0 stored entries
julia> speye(3,5)
3×5 sparse matrix with 3 Float64 stored entries:
3×5 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 1.0
[2, 2] = 1.0
[3, 3] = 1.0
Expand Down Expand Up @@ -794,7 +794,7 @@ the [`sparse()`](@ref) function:

```jldoctest
julia> sparse(eye(5))
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
8 changes: 8 additions & 0 deletions test/sparse/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1705,3 +1705,11 @@ end
@testset "issue #14398" begin
@test transpose(view(speye(10), 1:5, 1:5)) eye(5,5)
end

@testset "show" begin
io = IOBuffer()
show(io, MIME"text/plain"(), sparse([1], [1], [1.0]))
@test String(take!(io)) == "1×1 SparseMatrixCSC{Float64,Int64} with 1 stored entry:\n [1, 1] = 1.0"
show(io, MIME"text/plain"(), spzeros(Float32, 2))
@test String(take!(io)) == "2-element SparseVector{Float32,Int64} with 0 stored entries"
end
8 changes: 8 additions & 0 deletions test/sparse/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1122,3 +1122,11 @@ end

@test issparse([sprand(10,.1) rand(10)])
@test issparse([sprand(10,.1); rand(10)])

@testset "show" begin
io = IOBuffer()
show(io, MIME"text/plain"(), sparsevec(Int64[1], [1.0]))
@test String(take!(io)) == "1-element SparseVector{Float64,Int64} with 1 stored entry:\n [1] = 1.0"
show(io, MIME"text/plain"(), spzeros(2))
@test String(take!(io)) == "2-element SparseVector{Float64,Int64} with 0 stored entries"
end

0 comments on commit 5526b5f

Please sign in to comment.