diff --git a/docs/src/index.md b/docs/src/index.md index cb2760c5..27fc0521 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -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: diff --git a/src/linalg.jl b/src/linalg.jl index 69e2a0d5..2f6f6ab6 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -2094,9 +2094,9 @@ 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); @@ -2104,9 +2104,9 @@ 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: diff --git a/src/solvers/spqr.jl b/src/solvers/spqr.jl index 2f71dd65..9e5f2ebb 100644 --- a/src/solvers/spqr.jl +++ b/src/solvers/spqr.jl @@ -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 @@ -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}: diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 51ff5caf..8219f9f8 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -334,10 +334,7 @@ function Base.isstored(A::AdjOrTrans{<:Any,<:AbstractSparseMatrixCSC}, i::Intege return false 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) @@ -347,12 +344,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) + 4) | (screen[2] < 3size(S, 2)) _show_with_braille_patterns(io, S) + else + _show_with_dotted_zeros(io, S) end end @@ -399,96 +406,101 @@ end const brailleBlocks = UInt16['⠁', '⠂', '⠄', '⡀', '⠈', '⠐', '⠠', '⢀'] function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose) + # The maximum number of characters we allow to display the matrix + h, w = get(io, :limit, false) ? displaysize(io) .- (4, 2) : (typemax(Int)÷4, typemax(Int)÷2) m, n = size(S) - (m == 0 || n == 0) && return show(io, MIME("text/plain"), S) - - # 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 - - # 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 - # smaller matrix with the same aspect ratio as `S`, but fits on the - # available screen space. The size of that smaller matrix is stored - # in the variables `scaleHeight` and `scaleWidth`. If no scaling is needed, - # we can use the size `m × n` of `S` directly. - # We determine if scaling is needed and set the scaling factors - # `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) - s = min(2maxWidth / n, 4maxHeight / m) - scaleHeight = floor(Int, s * m) - scaleWidth = floor(Int, s * n) - else - scaleHeight = m - scaleWidth = n - end - - # Make sure that the matrix size is big enough to be able to display all - # the corner border characters - if scaleHeight < 8 - scaleHeight = 8 - end - if scaleWidth < 4 - scaleWidth = 4 - end - - # `brailleGrid` is used to store the needed braille characters for - # the matrix `S`. Each row of the braille pattern to print is stored - # in a column of `brailleGrid`. - brailleGrid = fill(UInt16(10240), (scaleWidth - 1) ÷ 2 + 4, (scaleHeight - 1) ÷ 4 + 1) - brailleGrid[1,:] .= '⎢' - brailleGrid[end-1,:] .= '⎥' - brailleGrid[1,1] = '⎡' - brailleGrid[1,end] = '⎣' - brailleGrid[end-1,1] = '⎤' - brailleGrid[end-1,end] = '⎦' - brailleGrid[end, :] .= '\n' - - rvals = rowvals(parent(S)) - rowscale = max(1, scaleHeight - 1) / max(1, m - 1) - colscale = max(1, scaleWidth - 1) / max(1, n - 1) - if isa(S, AbstractSparseMatrixCSC) - @inbounds for j in axes(S,2) - # Scale the column index `j` to the best matching column index - # of a matrix of size `scaleHeight × scaleWidth` - sj = round(Int, (j - 1) * colscale + 1) - for x in nzrange(S, j) - # Scale the row index `i` to the best matching row index - # of a matrix of size `scaleHeight × scaleWidth` - si = round(Int, (rvals[x] - 1) * rowscale + 1) - - # Given the index pair `(si, sj)` of the scaled matrix, - # calculate the corresponding triple `(k, l, p)` such that the - # element at `(si, sj)` can be found at position `(k, l)` in the - # braille grid `brailleGrid` and corresponds to the 1-dot braille - # character `brailleBlocks[p]` - k = (sj - 1) ÷ 2 + 2 - l = (si - 1) ÷ 4 + 1 - p = ((sj - 1) % 2) * 4 + ((si - 1) % 4 + 1) - - brailleGrid[k, l] |= brailleBlocks[p] - end + + warn = false + try + zero(eltype(S)) + catch + warn = true + h -= 1 + end + + # In order to prevent aliasing, we only scale down by full integers. + # While 1 to 1/2 is a big jump, it's less noticeable as you get bigger. + # Note each character has 4 dots of height and 2 dots of width. + scale = max(n÷2w, m÷4h) + 1 + char_h, char_w = fld1(m, 4scale), fld1(n, 2scale) + + scale != 1 && print(io, " (displaying at 1/$scale scale)") + println(io, ":") + warn && printstyled(stderr, "WARNING: could not find generic zero for given elements. expect errors and wrong results\n", color=:red) + + # Rows of output are cols of `brailleGrid` since julia is column-major + brailleGrid = fill(UInt16(10240), char_w + 3, char_h) + brailleGrid[[1,end-1,end],:] .= ['⎢', '⎥', '\n'] + brailleGrid[[1,end-1],[1,end]] .= ['⎡' '⎣';'⎤' '⎦'] + char_h == 1 && (brailleGrid[[1,end-1],1] .= ['[', ']']) + + rinds = rowvals(parent(S)) + cinds = ColumnIndices(parent(S)) + + if S isa AbstractSparseMatrixCSC + for cords in zip(rinds, cinds) + row, col = fld1.(cords, scale) |>x-> fldmod1.(x, (4, 2)) + brailleGrid[col[1]+1, row[1]] |= brailleBlocks[row[2] + 4(col[2]-1)] end - else - # If `S` is a adjoint or transpose of a sparse matrix we invert the - # roles of the indices `i` and `j` - @inbounds for i = 1:m - si = round(Int, (i - 1) * rowscale + 1) - for x in nzrange(parent(S), i) - sj = round(Int, (rvals[x] - 1) * colscale + 1) - k = (sj - 1) ÷ 2 + 2 - l = (si - 1) ÷ 4 + 1 - p = ((sj - 1) % 2) * 4 + ((si - 1) % 4 + 1) - brailleGrid[k, l] |= brailleBlocks[p] - end + else # swap rows / cols for adj and transpose + for cords in zip(rinds, cinds) + col, row = fld1.(cords, scale) |>x-> fldmod1.(x, (2, 4)) + brailleGrid[col[1]+1, row[1]] |= brailleBlocks[row[2] + 4(col[2]-1)] end end 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, ind) ? alignment(io, vals[ind]) : (3, 3) for ind 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 2+ entries, index[] errors. default to summing + # entries, but print red to warn user that something's wrong + elm = any(!isassigned(vals, ind) for ind 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 the 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 = 1, 1 + 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) @@ -631,7 +643,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 @@ -655,7 +667,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 @@ -680,7 +692,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 @@ -1905,9 +1917,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)) @@ -2077,7 +2089,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 ``` """ @@ -2104,9 +2116,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 diff --git a/test/issues.jl b/test/issues.jl index 9f46a639..7667e88a 100644 --- a/test/issues.jl +++ b/test/issues.jl @@ -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 @@ -805,6 +805,15 @@ 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) @@ -812,6 +821,21 @@ end @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 diff --git a/test/sparsematrix_constructors_indexing.jl b/test/sparsematrix_constructors_indexing.jl index 9fd1567c..f1750c78 100644 --- a/test/sparsematrix_constructors_indexing.jl +++ b/test/sparsematrix_constructors_indexing.jl @@ -1514,9 +1514,9 @@ end A = spzeros(Float32, Int64, 2, 2) for (transform, showstring) in zip( (identity, adjoint, transpose), ( - "2×2 $SparseMatrixCSC{Float32, Int64} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", - "2×2 $Adjoint{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", - "2×2 $Transpose{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", + "2×2 $SparseMatrixCSC{Float32, Int64} with 0 stored entries:\n ⋅ ⋅\n ⋅ ⋅", + "2×2 $Adjoint{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅\n ⋅ ⋅", + "2×2 $Transpose{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅\n ⋅ ⋅", )) show(io, MIME"text/plain"(), transform(A)) @test String(take!(io)) == showstring @@ -1529,16 +1529,11 @@ end "2×1 $Adjoint{Float64, $SparseMatrixCSC{Float64, Int64}} with 2 stored entries:\n 1.0\n 2.0", "2×1 $Transpose{Float64, $SparseMatrixCSC{Float64, Int64}} with 2 stored entries:\n 1.0\n 2.0", ), - ("⎡⠁⠈⎤\n" * - "⎣⠀⠀⎦", - "⎡⠁⠀⎤\n" * - "⎣⡀⠀⎦", - "⎡⠁⠀⎤\n" * - "⎣⡀⠀⎦")) + ("\n[⠉]", "\n[⠃]", "\n[⠃]")) show(io, MIME"text/plain"(), transform(A)) @test String(take!(io)) == showstring _show_with_braille_patterns(convert(IOContext, io), transform(A)) - @test String(take!(io)) == braille + @test contains(String(take!(io)), braille) end # every 1-dot braille pattern @@ -1555,11 +1550,11 @@ end end # empty braille pattern Char(10240) - A = spzeros(Int64, Int64, 4, 2) + A = spzeros(Int64, Int64, 2, 2) for transform in (identity, adjoint, transpose) - expected = "⎡" * Char(10240)^2 * "⎤\n⎣" * Char(10240)^2 * "⎦" + expected = ":\n[" * Char(10240) * "]" _show_with_braille_patterns(convert(IOContext, io), transform(A)) - @test String(take!(io)) == expected + @test contains(String(take!(io)), expected) end A = sparse(Int64[1, 2, 4, 2, 3], Int64[1, 1, 1, 2, 2], Int64[1, 1, 1, 1, 1], 4, 2) @@ -1569,16 +1564,11 @@ end "2×4 $Adjoint{Int64, $SparseMatrixCSC{Int64, Int64}} with 5 stored entries:\n 1 1 ⋅ 1\n ⋅ 1 1 ⋅", "2×4 $Transpose{Int64, $SparseMatrixCSC{Int64, Int64}} with 5 stored entries:\n 1 1 ⋅ 1\n ⋅ 1 1 ⋅", ), - ("⎡⠅⠠⎤\n" * - "⎣⡀⠐⎦", - "⎡⠉⠈⎤\n" * - "⎣⢀⡀⎦", - "⎡⠉⠈⎤\n" * - "⎣⢀⡀⎦")) + ("\n[⡳]", "\n[⠙⠊]", "\n[⠙⠊]")) show(io, MIME"text/plain"(), transform(A)) @test String(take!(io)) == showstring _show_with_braille_patterns(convert(IOContext, io), transform(A)) - @test String(take!(io)) == braille + @test contains(String(take!(io)), braille) end A = sparse(Int64[1, 3, 2, 4], Int64[1, 1, 2, 2], Int64[1, 1, 1, 1], 7, 3) @@ -1590,14 +1580,12 @@ end ), ("⎡⢕⠀⎤\n" * "⎣⠀⠀⎦", - "⎡⢁⢁⠀⠀⎤\n" * - "⎣⠀⠀⠀⠀⎦", - "⎡⢁⢁⠀⠀⎤\n" * - "⎣⠀⠀⠀⠀⎦")) + "[⠑⠑⠀⠀]", + "[⠑⠑⠀⠀]")) show(io, MIME"text/plain"(), transform(A)) @test String(take!(io)) == showstring _show_with_braille_patterns(convert(IOContext, io), transform(A)) - @test String(take!(io)) == braille + @test contains(String(take!(io)), braille) end A = sparse(Int64[1:10;], Int64[1:10;], fill(Float64(1), 10)) @@ -1606,7 +1594,7 @@ end "⎣⠀⠀⠀⠀⠑⎦" for transform in (identity, adjoint, transpose) _show_with_braille_patterns(convert(IOContext, io), transform(A)) - @test String(take!(io)) == brailleString + @test contains(String(take!(io)), brailleString) end # Issue #30589 @@ -1622,22 +1610,18 @@ end # vertical scaling ioc = IOContext(io, :displaysize => (5, 80), :limit => true) _show_with_braille_patterns(ioc, _filled_sparse(10, 10)) - @test String(take!(io)) == "⎡⣿⣿⎤\n" * - "⎣⣿⣿⎦" + @test contains(String(take!(io)), "\n[⣿⣿]") _show_with_braille_patterns(ioc, _filled_sparse(20, 10)) - @test String(take!(io)) == "⎡⣿⣿⎤\n" * - "⎣⣿⣿⎦" + @test contains(String(take!(io)), "\n[⣿]") # horizontal scaling ioc = IOContext(io, :displaysize => (80, 4), :limit => true) _show_with_braille_patterns(ioc, _filled_sparse(8, 8)) - @test String(take!(io)) == "⎡⣿⣿⎤\n" * - "⎣⣿⣿⎦" + @test contains(String(take!(io)), "\n[⠿⠇]") _show_with_braille_patterns(ioc, _filled_sparse(8, 16)) - @test String(take!(io)) == "⎡⣿⣿⎤\n" * - "⎣⣿⣿⎦" + @test contains(String(take!(io)), "\n[⠛⠛]") # respect IOContext while displaying J I, J, V = shuffle(1:50), shuffle(1:50), [1:50;]