Skip to content
Open
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
7 changes: 5 additions & 2 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ julia> I = [1, 4, 3, 5]; J = [4, 7, 18, 9]; V = [1, 2, -5, 3];
julia> S = sparse(I,J,V)
5×18 SparseMatrixCSC{Int64, Int64} with 4 stored entries:
⎡⠀⠈⠀⠀⠀⠀⠀⠀⢀⎤
⎣⠀⠀⠀⠂⡀⠀⠀⠀⠀⎦
⋅ ⋅ ⋅ 1 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ -5
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 2 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 3 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
julia> R = sparsevec(I,V)
5-element SparseVector{Int64, Int64} with 4 stored entries:
Expand Down
12 changes: 6 additions & 6 deletions src/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2094,19 +2094,19 @@ julia> A[4:4:8] .= 1;

julia> A
3×3 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
1.0 ⋅
⋅ 1.0
⋅ ⋅
1.0 ⋅
⋅ 1.0
⋅ ⋅

julia> C = spzeros(3,3);

julia> C[2:4:6] .= 2;

julia> C
3×3 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
⋅ ⋅
2.0 ⋅
⋅ 2.0
⋅ ⋅ ⋅
2.0 ⋅ ⋅
⋅ 2.0 ⋅

julia> SparseArrays.mergeinds!(C, A)
3×3 SparseMatrixCSC{Float64, Int64} with 4 stored entries:
Expand Down
12 changes: 6 additions & 6 deletions src/solvers/spqr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ Q factor:
4×4 SparseArrays.SPQR.QRSparseQ{Float64, Int64}
R factor:
2×2 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
-1.41421 ⋅
-1.41421
-1.41421
-1.41421
Row permutation:
4-element Vector{Int64}:
1
Expand Down Expand Up @@ -471,10 +471,10 @@ when the problem is underdetermined.
```jldoctest
julia> A = sparse([1,2,4], [1,1,1], [1.0,1.0,1.0], 4, 2)
4×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
1.0
1.0
1.0
1.0 ⋅
1.0 ⋅
⋅ ⋅
1.0 ⋅

julia> qr(A)\\fill(1.0, 4)
2-element Vector{Float64}:
Expand Down
111 changes: 93 additions & 18 deletions src/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ end
Base.replace_in_print_matrix(A::AbstractSparseMatrixCSCInclAdjointAndTranspose, i::Integer, j::Integer, s::AbstractString) =
Base.isstored(A, i, j) ? s : Base.replace_with_centered_mark(s)

function Base.array_summary(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose, dims::Tuple{Vararg{Base.OneTo}})
function Base.summary(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose)
_checkbuffers(S)

xnnz = nnz(S)
Expand All @@ -347,12 +347,22 @@ function Base.array_summary(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTran
nothing
end

# called by `show(io, MIME("text/plain"), ::AbstractSparseMatrixCSCInclAdjointAndTranspose)`
function Base.print_array(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose)
if max(size(S)...) < 16
Base.print_matrix(io, S)
else
using Base: show_circular
function Base.show(io::IO, ::MIME"text/plain", S::AbstractSparseMatrixCSCInclAdjointAndTranspose)
isempty(S) && get(io, :compact, false) && return show(io, S)
summary(io, S)
isempty(S) && return

screen = displaysize(io)
get(io, :limit, false) && screen[1] <= 4 && return print(io, ": …")

show_circular(io, S) && return
io = IOContext(io, :compact=>true, :typeinfo=>eltype(S), :SHOWN_SET=>S)

if (screen[1] < size(S, 1) + 5) | (screen[2] < 3size(S, 2))
_show_with_braille_patterns(io, S)
else
_show_with_dotted_zeros(io, S)
end
end

Expand Down Expand Up @@ -405,7 +415,14 @@ function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjoi
# The maximal number of characters we allow to display the matrix
local maxHeight::Int, maxWidth::Int
maxHeight = displaysize(io)[1] - 4 # -4 from [Prompt, header, newline after elements, new prompt]
maxWidth = displaysize(io)[2] ÷ 2
maxWidth = displaysize(io)[2] - 2 # -2 from brackets

try
zero(eltype(S))
catch
printstyled(stderr, "WARNING: could not find generic zero for given elements. expect errors and wrong results\n", color=:red)
maxHeight = maxHeight - 1
end

# In the process of generating the braille pattern to display the nonzero
# structure of `S`, we need to be able to scale the matrix `S` to a
Expand All @@ -417,7 +434,7 @@ function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjoi
# `scaleHeight` and `scaleWidth` accordingly. Note that each available
# character can contain up to 4 braille dots in its height (⡇) and up to
# 2 braille dots in its width (⠉).
if get(io, :limit, true) && (m > 4maxHeight || n > 2maxWidth)
if get(io, :limit, false) && (m > 4maxHeight || n > 2maxWidth)
s = min(2maxWidth / n, 4maxHeight / m)
scaleHeight = floor(Int, s * m)
scaleWidth = floor(Int, s * n)
Expand Down Expand Up @@ -450,6 +467,12 @@ function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjoi
rvals = rowvals(parent(S))
rowscale = max(1, scaleHeight - 1) / max(1, m - 1)
colscale = max(1, scaleWidth - 1) / max(1, n - 1)

if rowscale != 1 || colscale != 1
print(io, " (downscaled to fit on screen)")
end
println(io, ":")

if isa(S, AbstractSparseMatrixCSC)
@inbounds for j in axes(S,2)
# Scale the column index `j` to the best matching column index
Expand Down Expand Up @@ -489,6 +512,58 @@ function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjoi
foreach(c -> print(io, Char(c)), @view brailleGrid[1:end-1])
end

using Base: alignment
function _show_with_dotted_zeros(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose)
rows, cols, vals = rowvals(parent(S)), ColumnIndices(parent(S)), nonzeros(parent(S))
(S isa Adjoint) | (S isa Transpose) && ((rows, cols) = (cols, rows))

align = [isassigned(vals, val) ? alignment(io, vals[val]) : (3, 3) for val in eachindex(vals)]
colwidths = [max.((0, 0), align[findall(==(col), cols)]...) for col in axes(S,2)]
displaysize(io)[2] < sum(sum.(colwidths) .+ 2) && return _show_with_braille_patterns(io, S)

println(io, ":")

try
zero(eltype(S))
catch
printstyled(stderr, "WARNING: could not find generic zero for given elements. expect errors and wrong results\n", color=:red)
end

for row in axes(S,1)
for col in axes(S,2)
index = findall(==(col), cols)
index = index[findall(==(row), rows[index])]
l, r = colwidths[col]
if isempty(index) # no value here, print an aligned dot
l, r = cld(l+r-1, 2) + 1, div(l+r-1, 2) + 1
print(io, " "^l * "⋅" * (col==axes(S,2)[end] ? "" : " "^r))
else
try # print the element with 1 space of buffer on each side
l, r = (l+1, r+1) .- align[index][]
print(io, " "^l)
isassigned(vals, index[]) ? show(io, vals[index][]) : print(io, "#undef")
col == axes(S,2)[end] || print(io, " "^r)
catch # if there's overlapping entries, [] will error. default to summing
# entries, but print in red to warn user that something's wrong
elm = any(!isassigned(vals, id) for id in index) ? "#undef" :
try repr(sum(vals[index]); context=:compact=>true) catch e "#NaN" end

if length(elm) <= l+r # give up on alignment, center item in column
l, r = cld(l+r-length(elm), 2) + 1, div(l+r-length(elm), 2) + 1
else # len of new item does not fit in column
elm = ' ' * "▒"^(l+r) * ' '
l, r = 0, 0
end

printstyled(io, " "^l, elm, color=:red)
col == axes(S,2)[end] || print(io, " "^r)
end
end
end
row == axes(S,1)[end] || println(io)
end
end

for QT in (:LinAlgLeftQs, :LQPackedQ)
@eval (*)(Q::$QT, B::AbstractSparseMatrixCSC) = Q * Matrix(B)
@eval (*)(Q::$QT, B::AdjOrTrans{<:Any,<:AbstractSparseMatrixCSC}) = Q * copy(B)
Expand Down Expand Up @@ -631,7 +706,7 @@ function _sparse_copyto!(dest::AbstractMatrix, src::AbstractSparseMatrixCSC)
@inbounds for col in axes(src, 2), ptr in nzrange(src, col)
row = rowvals(src)[ptr]
val = nonzeros(src)[ptr]
dest[isrc[row, col]] = val
dest[isrc[row, col]] += val
end
return dest
end
Expand All @@ -655,7 +730,7 @@ function copyto!(dest::AbstractMatrix, Rdest::CartesianIndices{2},
if row in rows
val = nonzeros(src′)[ptr]
I = Rdest[lin[row, col]]
dest[I] = val
dest[I] += val
end
end
return dest
Expand All @@ -680,7 +755,7 @@ function Base.copyto!(A::Array{T}, S::SparseMatrixCSC{<:Number}) where {T<:Numbe
for i in nzrange(S, col)
row = rowval[i]
val = nzval[i]
A[linear_index_col0+row] = val
A[linear_index_col0+row] += val
end
linear_index_col0 += num_rows
end
Expand Down Expand Up @@ -1905,9 +1980,9 @@ julia> A = sparse([1, 2, 3], [1, 2, 3], [1.0, 0.0, 1.0])

julia> dropzeros(A)
3×3 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
1.0
1.0
1.0
1.0
```
"""
dropzeros(A::AbstractSparseMatrixCSC) = dropzeros!(copy(A))
Expand Down Expand Up @@ -2077,7 +2152,7 @@ argument specifies a random number generator, see [Random Numbers](@ref).
```jldoctest; setup = :(using Random; Random.seed!(0))
julia> sprandn(2, 2, 0.75)
2×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
-1.20577 ⋅
-1.20577
0.311817 -0.234641
```
"""
Expand All @@ -2104,9 +2179,9 @@ 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
Expand Down
28 changes: 26 additions & 2 deletions test/issues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -758,14 +758,14 @@ let
B = similar(A, T12960)
@test repr(B) == "sparse([1, 2, 3], [1, 2, 3], $T12960[#undef, #undef, #undef], 3, 3)"
@test occursin(
"\n #undef \n #undef \n #undef",
" #undef ⋅ \n ⋅ #undef \n ⋅ #undef",
repr(MIME("text/plain"), B),
)

B[1,2] = T12960()
@test repr(B) == "sparse([1, 1, 2, 3], [1, 2, 2, 3], $T12960[#undef, $T12960(), #undef, #undef], 3, 3)"
@test occursin(
"\n #undef T12960() \n #undef \n #undef",
"\n #undef T12960() \n ⋅ #undef \n ⋅ #undef",
repr(MIME("text/plain"), B),
)
end
Expand Down Expand Up @@ -805,13 +805,37 @@ end
7 16 4])
end

@testset "Issue #512" begin # suppresses but does not fix the error mentioned
x = sparse([1, 1, 3], [1, 4, 3], [20, 0, [2]])
@test_warn "WARNING: could not find generic zero" repr(MIME("text/plain"), x)
x = sparse([1, 100, 3], [1, 4, 300], [20, 0, [2]])
@test_warn "WARNING: could not find generic zero" repr(MIME("text/plain"), x)

@test_broken repr(MIME("text/plain"), transpose(x'))
end

@testset "Issue #574" begin
a = spzeros(Float32, Int16, 2, 3)
v = spzeros(Float32, Int16, 2)
@test eltype(rowvals(zero(a))) <: Int16
@test eltype(rowvals(zero(v))) <: Int16
end

@testset "Issue #618" begin
x = SparseMatrixCSC(3, 3, [1, 3, 4, 5], [1, 1, 2, 3], [1.0, 1.0, 1.0, 1.0])
@test contains(repr(MIME"text/plain"(), x), "2.0")
x = SparseMatrixCSC(3, 3, [1, 3, 4, 5], [1, 1, 2, 3], [7.0, 7.0, 1.0, 1.0])
@test contains(repr(MIME"text/plain"(), x), "▒▒▒")
x = SparseMatrixCSC(3, 3, [1, 3, 4, 5], [1, 1, 2, 3], [7.0, 'o', 1.0, 1.0])
@test contains(repr(MIME"text/plain"(), x), "#NaN")
v = similar(Any[1, 2, 3, 4]); v[2:4] = [1.0, 1.0, 1.0]
x = SparseMatrixCSC(3, 3, [1, 3, 4, 5], [1, 1, 2, 3], v)
@test contains(repr(MIME"text/plain"(), x), "#undef")

x = SparseMatrixCSC(3, 3, [1, 3, 4, 5], [1, 1, 2, 3], [1, 1, 1, 1])
@test 2 == Matrix(x)[1,1]
end

end # SparseTestsBase

end # module
Loading
Loading