From a2aabfa9c0adc39aade0908808f7aa4be1e5b2c6 Mon Sep 17 00:00:00 2001 From: polarke Date: Fri, 9 Oct 2015 17:36:35 +0200 Subject: [PATCH 01/14] add same constructors as array --- base/sharedarray.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 24b1679bbe855..b4a1d2b7b1b48 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -24,6 +24,17 @@ type SharedArray{T,N} <: DenseArray{T,N} SharedArray(d,p,r,sn) = new(d,p,r,sn) end +call{T,N}(::Type{SharedArray{T}}, d::NTuple{N,Int}; kwargs...) = + SharedArray(T, d; kwargs...) +call{T}(::Type{SharedArray{T}}, d::Integer...; kwargs...) = + SharedArray(T, d; kwargs...) +call{T}(::Type{SharedArray{T}}, m::Integer; kwargs...) = + SharedArray(T, m; kwargs...) +call{T}(::Type{SharedArray{T}}, m::Integer, n::Integer; kwargs...) = + SharedArray(T, m, n; kwargs...) +call{T}(::Type{SharedArray{T}}, m::Integer, n::Integer, o::Integer; kwargs...) = + SharedArray(T, m, n, o; kwargs...) + function SharedArray(T::Type, dims::NTuple; init=false, pids=Int[]) N = length(dims) From 2298652cbd2390635f5d9caa33395052c98db683 Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Fri, 9 Oct 2015 12:33:13 -0400 Subject: [PATCH 02/14] display ranges with their elements --- base/range.jl | 46 ++++++++++++++++++++++++++++++++++++++++++++++ base/replutil.jl | 25 +++++++++++++++++-------- test/ranges.jl | 6 ++++++ 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/base/range.jl b/base/range.jl index 52db2504d032b..d469d9323f322 100644 --- a/base/range.jl +++ b/base/range.jl @@ -244,6 +244,52 @@ function show(io::IO, r::LinSpace) print(io, ')') end +# print_range() prints out a nice looking range in terms of its elements +# as if it were collect(range), dependent on the size of the +# terminal, and taking into account whether compact numbers should be shown. +# It figures out the width in characters of each element, and if they +# end up too wide, it shows the first and last elements separated by a +# horizontal elipsis. +# Optional parameters include sz for the (rows,cols) of the screen, +# pre and post characters for each printed row, a separator string sep between +# printed elements, string for the horizontal ellipsis. +# typical output will look like this (for a narrow screen): +# 1.0,2.0,3.0,…,4.0,5.0,6.0 +# This function is borrowed from print_matrix in show.jl +# It is usually called by writemime (from replutil.jl) +function print_range(io::IO, r::Union{Range,LinSpace}, + sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), + pre::AbstractString = " ", + sep::AbstractString = ",", + post::AbstractString = "", + hdots::AbstractString = ",\u2026,") # horiz ellipsis + rows, cols = sz + cols -= length(pre) + length(post) + postsp = "" + sepsize = length(sep) + m = 1 # treat the range as a one-row matrix + n = length(r) + rowmatrix = r' # pretend the range is a one-row matrix for output + A = alignment(rowmatrix,1:m,1:n,cols,cols,sepsize) # how much space range takes + if n <= length(A) # cols fit screen, so print out all elements + print(io, pre) # put in pre chars + print_matrix_row(io,rowmatrix,A,1,1:n,sep) # the entire range + print(io, post) # add the post characters + else # cols don't fit so put horiz ellipsis in the middle + # how many chars left after dividing width of screen in half + # and accounting for the horiz ellipsis + c = div(cols-length(hdots)+1,2)+1 # chars remaining for each side of r + colsR = reverse(alignment(rowmatrix,1:m,n:-1:1,c,c,sepsize)) # which cols of r to put on the right + c = cols - sum(map(sum,colsR)) - (length(colsR)-1)*sepsize - length(hdots) + colsL = alignment(rowmatrix,1:m,1:n,c,c,sepsize) # which cols of r to put on the left + print(io, pre) # put in pre chars + print_matrix_row(io, rowmatrix,colsL,1,1:length(colsL),sep) # left part of range + print(io, hdots) # horizontal ellipsis + print_matrix_row(io, rowmatrix,colsR,1,n-length(colsR)+1:n,sep) # right part of range + print(io, post) # post chars + end +end + logspace(start::Real, stop::Real, n::Integer=50) = 10.^linspace(start, stop, n) ## interface implementations diff --git a/base/replutil.jl b/base/replutil.jl index 6e4412aaa5256..1cfab1b5e3344 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -13,15 +13,24 @@ function writemime(io::IO, ::MIME"text/plain", f::Function) end end +# writemime for ranges, e.g. +# 3-element UnitRange{Int64,Int} +# 1,2,3 +# or for more elements than fit on screen: +# 1.0,2.0,3.0,…,6.0,7.0,8.0 +function writemime(io::IO, ::MIME"text/plain", r::Union{Range, LinSpace}) + print(io, summary(r)) + if !isempty(r) + println(io, ":") + with_output_limit(()->print_range(io, r)) + end +end + function writemime(io::IO, ::MIME"text/plain", v::AbstractVector) - if isa(v, Range) - show(io, v) - else - print(io, summary(v)) - if !isempty(v) - println(io, ":") - with_output_limit(()->print_matrix(io, v)) - end + print(io, summary(v)) + if !isempty(v) + println(io, ":") + with_output_limit(()->print_matrix(io, v)) end end diff --git a/test/ranges.jl b/test/ranges.jl index a4a53ed49cc02..3eb3cd749822d 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -544,6 +544,12 @@ for x in r end @test i == 7 +# writemime should display the range or linspace nicely +replstr(x) = sprint((io,x) -> writemime(io,MIME("text/plain"),x), x) +@test replstr(1:4) == "4-element UnitRange{Int64}:\n 1,2,3,4" +@test replstr(linspace(1,5,7)) == "7-element LinSpace{Float64}:\n 1.0,1.66667,2.33333,3.0,3.66667,4.33333,5.0" +@test replstr(0:100.) == "101-element FloatRange{Float64}:\n 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,…,94.0,95.0,96.0,97.0,98.0,99.0,100.0" + # Issue 11049 and related @test promote(linspace(0f0, 1f0, 3), linspace(0., 5., 2)) === (linspace(0., 1., 3), linspace(0., 5., 2)) From 19ddb5fee6504871086df7debfcb30cecc76d2cc Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Fri, 9 Oct 2015 22:47:22 -0400 Subject: [PATCH 03/14] Code comments for show.jl; no changes to execution code, only comments added while trying to figure out print_matrix and related functions. --- base/show.jl | 60 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/base/show.jl b/base/show.jl index 177ef7e7e43a0..ea4a61d5f74fe 100644 --- a/base/show.jl +++ b/base/show.jl @@ -956,6 +956,11 @@ dump(io::IO, x::DataType) = dump(io, x, 5, "") dump(io::IO, x::TypeVar, n::Int, indent) = println(io, x.name) +# alignment() returns a tuple (left,right) showing how many characters are +# needed on either side of an alignment feature such as a decimal point. +# For example, 42 yields (2,0) +# 4.20 yields (1,3) because decimal point is included on right +# 1 + 10im yields (3,5) because + sign is included on left alignment(x::Any) = (0, length(sprint(showcompact_lim, x))) alignment(x::Number) = (length(sprint(showcompact_lim, x)), 0) alignment(x::Integer) = (length(sprint(showcompact_lim, x)), 0) @@ -978,22 +983,28 @@ end const undef_ref_str = "#undef" const undef_ref_alignment = (3,3) +# alignment(X, rows, cols, cols_if_complete, cols_otherwise, sep) returns the +# alignment for specified parts of array X, returning the (left,right) info. +# It will look in X's rows, cols (index lists) +# and figure out what's needed to be fully aligned, for example looking all +# the way down a column and finding out the maximum size of each element. +# Parameter sep is number of spaces to put between elements. function alignment( X::AbstractVecOrMat, rows::AbstractVector, cols::AbstractVector, cols_if_complete::Integer, cols_otherwise::Integer, sep::Integer ) a = Tuple{Int, Int}[] - for j in cols + for j in cols # need to go down each column one at a time l = r = 0 - for i in rows + for i in rows # plumb down and see what largest element sizes are if isassigned(X,i,j) aij = alignment(X[i,j]) else aij = undef_ref_alignment end - l = max(l, aij[1]) - r = max(r, aij[2]) + l = max(l, aij[1]) # left characters + r = max(r, aij[2]) # right characters end push!(a, (l, r)) if length(a) > 1 && sum(map(sum,a)) + sep*length(a) >= cols_if_complete @@ -1009,6 +1020,11 @@ function alignment( return a end +# print_matrix_row(io, X, A, i, cols, sep) produces the aligned output for +# a singel matrix row X[i, cols] where the desired list of columns is given. +# The corresponding alignment A is used, and the separation between elements +# is specified as string sep. +# print_matrix_row will also respect compact output for elements function print_matrix_row(io::IO, X::AbstractVecOrMat, A::Vector, i::Integer, cols::AbstractVector, sep::AbstractString @@ -1023,13 +1039,16 @@ function print_matrix_row(io::IO, a = undef_ref_alignment sx = undef_ref_str end - l = repeat(" ", A[k][1]-a[1]) + l = repeat(" ", A[k][1]-a[1]) # pad on left and right as needed r = repeat(" ", A[k][2]-a[2]) print(io, l, sx, r) if k < length(A); print(io, sep); end end end +# print_matrix_vdots is used to show a series of vertical ellipsis instead +# of a bunch of rows for long matrices. Not only is the string vdots shown +# but it also repeated every M elements if desired. function print_matrix_vdots(io::IO, vdots::AbstractString, A::Vector, sep::AbstractString, M::Integer, m::Integer ) @@ -1046,6 +1065,13 @@ function print_matrix_vdots(io::IO, end end +# print_matrix composes an entire matrix, taking into account the screen size +# to determine when vertical, horizontal, or diagonal ellipsis are desired. +# Parameters are the matrix X, screen size tuple sz such as (24,80), +# String pre on left of each row and post on right, and sep as separator +# between elements. Also options to use different ellipsis characters hdots, +# vdots, ddots. The ellipsis are separated every hmod or vmod apart. +# The printing works mostly by composing print_matrix_row in various ways. function print_matrix(io::IO, X::AbstractVecOrMat, sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), pre::AbstractString = " ", @@ -1064,18 +1090,18 @@ function print_matrix(io::IO, X::AbstractVecOrMat, m, n = size(X,1), size(X,2) if m <= rows # rows fit A = alignment(X,1:m,1:n,cols,cols,ss) - if n <= length(A) # rows and cols fit + if n <= length(A) # rows and cols fit so just print whole matrix in one piece for i = 1:m print(io, i == 1 ? pre : presp) print_matrix_row(io, X,A,i,1:n,sep) print(io, i == m ? post : postsp) if i != m; println(io, ); end end - else # rows fit, cols don't - c = div(cols-length(hdots)+1,2)+1 - R = reverse(alignment(X,1:m,n:-1:1,c,c,ss)) + else # rows fit, cols don't so need horizontal ellipsis + c = div(cols-length(hdots)+1,2)+1 # what goes to right of ellipsis + R = reverse(alignment(X,1:m,n:-1:1,c,c,ss)) # alignments for right c = cols - sum(map(sum,R)) - (length(R)-1)*ss - length(hdots) - L = alignment(X,1:m,1:n,c,c,ss) + L = alignment(X,1:m,1:n,c,c,ss) # alignments for left of ellipsis for i = 1:m print(io, i == 1 ? pre : presp) print_matrix_row(io, X,L,i,1:length(L),sep) @@ -1085,11 +1111,11 @@ function print_matrix(io::IO, X::AbstractVecOrMat, if i != m; println(io, ); end end end - else # rows don't fit + else # rows don't fit so will need vertical ellipsis t = div(rows,2) I = [1:t; m-div(rows-1,2)+1:m] A = alignment(X,I,1:n,cols,cols,ss) - if n <= length(A) # rows don't fit, cols do + if n <= length(A) # rows don't fit, cols do, so only vertical ellipsis for i in I print(io, i == 1 ? pre : presp) print_matrix_row(io, X,A,i,1:n,sep) @@ -1101,7 +1127,7 @@ function print_matrix(io::IO, X::AbstractVecOrMat, println(io, i == m ? post : postsp) end end - else # neither rows nor cols fit + else # neither rows nor cols fit, so use all 3 kinds of ellipsis c = div(cols-length(hdots)+1,2)+1 R = reverse(alignment(X,I,n:-1:1,c,c,ss)) c = cols - sum(map(sum,R)) - (length(R)-1)*ss - length(hdots) @@ -1126,15 +1152,18 @@ function print_matrix(io::IO, X::AbstractVecOrMat, end end -summary(x) = string(typeof(x)) +summary(x) = string(typeof(x)) # e.g. Int64 +# sizes such as 0-dimensional, 4-dimensional, 2x3 dims2string(d) = length(d) == 0 ? "0-dimensional" : length(d) == 1 ? "$(d[1])-element" : join(map(string,d), 'x') +# anything array-like gets summarized e.g. 10-element Array{Int64,1} summary(a::AbstractArray) = string(dims2string(size(a)), " ", typeof(a)) +# n-dimensional arrays function show_nd(io::IO, a::AbstractArray, limit, print_matrix, label_slices) if isempty(a) return @@ -1181,6 +1210,7 @@ end # for internal use in showing arrays. _limit_output = false +# print matrix with opening and closing square brackets function print_matrix_repr(io, X::AbstractArray) compact, prefix = array_eltype_show_how(X) prefix *= "[" @@ -1247,7 +1277,7 @@ end show(io::IO, X::AbstractArray) = showarray(io, X, header=_limit_output, repr=!_limit_output) -function with_output_limit(thk, lim=true) +function with_output_limit(thk, lim=true) # thk is usually show() global _limit_output last = _limit_output _limit_output = lim From 6acb5105d607c457e7929d9098085a6a93b48b1c Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Sat, 10 Oct 2015 01:26:22 -0400 Subject: [PATCH 04/14] make sure test works on either 32- or 64-bit systems (Int32 or Int64) --- test/ranges.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/ranges.jl b/test/ranges.jl index 3eb3cd749822d..a41668a1e1e59 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -546,7 +546,8 @@ end # writemime should display the range or linspace nicely replstr(x) = sprint((io,x) -> writemime(io,MIME("text/plain"),x), x) -@test replstr(1:4) == "4-element UnitRange{Int64}:\n 1,2,3,4" +@test replstr(1:4) == "4-element UnitRange{Int64}:\n 1,2,3,4" || + replstr(1:4) == "4-element UnitRange{Int32}:\n 1,2,3,4" @test replstr(linspace(1,5,7)) == "7-element LinSpace{Float64}:\n 1.0,1.66667,2.33333,3.0,3.66667,4.33333,5.0" @test replstr(0:100.) == "101-element FloatRange{Float64}:\n 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,…,94.0,95.0,96.0,97.0,98.0,99.0,100.0" From 8e98763048d56a769ff2a2a92bb65c2c23cc135b Mon Sep 17 00:00:00 2001 From: polarke Date: Sun, 11 Oct 2015 20:10:12 +0200 Subject: [PATCH 05/14] add test for sharedarray constructor --- test/parallel.jl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/parallel.jl b/test/parallel.jl index dc4a01a8e58c8..7c4e523b14fcf 100644 --- a/test/parallel.jl +++ b/test/parallel.jl @@ -179,6 +179,20 @@ end ### Utility functions +# construct PR #13514 +S = SharedArray{Int}((1,2,3)) +@test size(S) == (1,2,3) +@test typeof(S) <: SharedArray{Int} +S = SharedArray{Int}(2) +@test size(S) == (2,) +@test typeof(S) <: SharedArray{Int} +S = SharedArray{Int}(1,2) +@test size(S) == (1,2) +@test typeof(S) <: SharedArray{Int} +S = SharedArray{Int}(1,2,3) +@test size(S) == (1,2,3) +@test typeof(S) <: SharedArray{Int} + # reshape d = Base.shmem_fill(1.0, (10,10,10)) From 721350ec9d9da7c5997c7baeedfbeaf07362cea2 Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Tue, 13 Oct 2015 18:20:10 -0400 Subject: [PATCH 06/14] improved print_range, tweaked comments and tests --- base/range.jl | 68 ++++++++++++++++++++++++++++++++------------------ test/ranges.jl | 10 ++++++-- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/base/range.jl b/base/range.jl index d469d9323f322..ba2e0f8fe4498 100644 --- a/base/range.jl +++ b/base/range.jl @@ -244,33 +244,53 @@ function show(io::IO, r::LinSpace) print(io, ')') end -# print_range() prints out a nice looking range in terms of its elements -# as if it were collect(range), dependent on the size of the -# terminal, and taking into account whether compact numbers should be shown. -# It figures out the width in characters of each element, and if they -# end up too wide, it shows the first and last elements separated by a -# horizontal elipsis. -# Optional parameters include sz for the (rows,cols) of the screen, -# pre and post characters for each printed row, a separator string sep between -# printed elements, string for the horizontal ellipsis. -# typical output will look like this (for a narrow screen): -# 1.0,2.0,3.0,…,4.0,5.0,6.0 -# This function is borrowed from print_matrix in show.jl -# It is usually called by writemime (from replutil.jl) -function print_range(io::IO, r::Union{Range,LinSpace}, +""" +`print_range(io, r)` prints out a nice looking range r in terms of its elements +as if it were `collect(r)`, dependent on the size of the +terminal, and taking into account whether compact numbers should be shown. +It figures out the width in characters of each element, and if they +end up too wide, it shows the first and last elements separated by a +horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. + +`print_range(io, r, sz, pre, sep, post, hdots)` uses optional +parameters `sz` for the (rows,cols) of the screen, +`pre` and `post` characters for each printed row, `sep` separator string between +printed elements, `hdots` string for the horizontal ellipsis. +""" +""" +`print_range(io, r)` prints out a nice looking range r in terms of its elements +as if it were `collect(r)`, dependent on the size of the +terminal, and taking into account whether compact numbers should be shown. +It figures out the width in characters of each element, and if they +end up too wide, it shows the first and last elements separated by a +horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. + +`print_range(io, r, sz, pre, sep, post, hdots)` uses optional +parameters `sz` for the (rows,cols) of the screen, +`pre` and `post` characters for each printed row, `sep` separator string between +printed elements, `hdots` string for the horizontal ellipsis. +""" +function print_range(io::IO, r::Range, sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), pre::AbstractString = " ", sep::AbstractString = ",", post::AbstractString = "", hdots::AbstractString = ",\u2026,") # horiz ellipsis - rows, cols = sz - cols -= length(pre) + length(post) +# This function borrows from print_matrix() in show.jl +# and should be called by writemime (replutil.jl) and by display() + screenheight, screenwidth = sz + screenwidth -= length(pre) + length(post) postsp = "" sepsize = length(sep) m = 1 # treat the range as a one-row matrix n = length(r) - rowmatrix = r' # pretend the range is a one-row matrix for output - A = alignment(rowmatrix,1:m,1:n,cols,cols,sepsize) # how much space range takes + # Figure out spacing alignments for r, but only need to examine the + # left and right edge columns, as many as could conceivably fit on the + # screen, with the middle columns summarized by ellipsis + maxpossiblecols = div(screenwidth, 1+sepsize) # assume each element is at least 1 char + 1 separator + colsr = n <= maxpossiblecols ? (1:n) : [1:div(maxpossiblecols,2)+1; (n-div(maxpossiblecols,2)):n] + rowmatrix = r[colsr]' # treat the range as a one-row matrix for print_matrix_row + A = alignment(rowmatrix,1:m,1:length(rowmatrix),screenwidth,screenwidth,sepsize) # how much space range takes if n <= length(A) # cols fit screen, so print out all elements print(io, pre) # put in pre chars print_matrix_row(io,rowmatrix,A,1,1:n,sep) # the entire range @@ -278,14 +298,14 @@ function print_range(io::IO, r::Union{Range,LinSpace}, else # cols don't fit so put horiz ellipsis in the middle # how many chars left after dividing width of screen in half # and accounting for the horiz ellipsis - c = div(cols-length(hdots)+1,2)+1 # chars remaining for each side of r - colsR = reverse(alignment(rowmatrix,1:m,n:-1:1,c,c,sepsize)) # which cols of r to put on the right - c = cols - sum(map(sum,colsR)) - (length(colsR)-1)*sepsize - length(hdots) - colsL = alignment(rowmatrix,1:m,1:n,c,c,sepsize) # which cols of r to put on the left + c = div(screenwidth-length(hdots)+1,2)+1 # chars remaining for each side of rowmatrix + alignR = reverse(alignment(rowmatrix,1:m,length(rowmatrix):-1:1,c,c,sepsize)) # which cols of rowmatrix to put on the right + c = screenwidth - sum(map(sum,alignR)) - (length(alignR)-1)*sepsize - length(hdots) + alignL = alignment(rowmatrix,1:m,1:length(rowmatrix),c,c,sepsize) # which cols of rowmatrix to put on the left print(io, pre) # put in pre chars - print_matrix_row(io, rowmatrix,colsL,1,1:length(colsL),sep) # left part of range + print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep) # left part of range print(io, hdots) # horizontal ellipsis - print_matrix_row(io, rowmatrix,colsR,1,n-length(colsR)+1:n,sep) # right part of range + print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep) # right part of range print(io, post) # post chars end end diff --git a/test/ranges.jl b/test/ranges.jl index a41668a1e1e59..d3da204203207 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -544,12 +544,18 @@ for x in r end @test i == 7 -# writemime should display the range or linspace nicely -replstr(x) = sprint((io,x) -> writemime(io,MIME("text/plain"),x), x) +# stringmime/writemime should display the range or linspace nicely +# to test print_range in range.jl +replstr(x) = stringmime("text/plain", x) @test replstr(1:4) == "4-element UnitRange{Int64}:\n 1,2,3,4" || replstr(1:4) == "4-element UnitRange{Int32}:\n 1,2,3,4" @test replstr(linspace(1,5,7)) == "7-element LinSpace{Float64}:\n 1.0,1.66667,2.33333,3.0,3.66667,4.33333,5.0" @test replstr(0:100.) == "101-element FloatRange{Float64}:\n 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,…,94.0,95.0,96.0,97.0,98.0,99.0,100.0" +# next is to test a very large range, which should be fast because print_range +# only examines spacing of the left and right edges of the range, sufficient +# to cover the designated screen size. +@test replstr(0:10^9) == "1000000001-element UnitRange{Int64}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" || + replstr(0:10^9) == "1000000001-element UnitRange{Int32}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" # Issue 11049 and related @test promote(linspace(0f0, 1f0, 3), linspace(0., 5., 2)) === From 690bc2b8c022ca31e730e509c1b7dc8386a0ac9f Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Sun, 11 Oct 2015 15:28:53 -0400 Subject: [PATCH 07/14] Docstring comments for print_X methods in show. Comments are for un-exported methods such as alignment. --- base/show.jl | 79 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/base/show.jl b/base/show.jl index ea4a61d5f74fe..b478d7d7a7a36 100644 --- a/base/show.jl +++ b/base/show.jl @@ -956,19 +956,21 @@ dump(io::IO, x::DataType) = dump(io, x, 5, "") dump(io::IO, x::TypeVar, n::Int, indent) = println(io, x.name) -# alignment() returns a tuple (left,right) showing how many characters are -# needed on either side of an alignment feature such as a decimal point. -# For example, 42 yields (2,0) -# 4.20 yields (1,3) because decimal point is included on right -# 1 + 10im yields (3,5) because + sign is included on left +""" +`alignment(X)` returns a tuple (left,right) showing how many characters are +needed on either side of an alignment feature such as a decimal point. +""" alignment(x::Any) = (0, length(sprint(showcompact_lim, x))) alignment(x::Number) = (length(sprint(showcompact_lim, x)), 0) +"`alignment(42)` yields (2,0)" alignment(x::Integer) = (length(sprint(showcompact_lim, x)), 0) +"`alignment(4.23)` yields (1,3) for `4` and `.23`" function alignment(x::Real) m = match(r"^(.*?)((?:[\.eE].*)?)$", sprint(showcompact_lim, x)) m === nothing ? (length(sprint(showcompact_lim, x)), 0) : (length(m.captures[1]), length(m.captures[2])) end +"`alignment(1 + 10im)` yields (3,5) for `1 +` and `_10im` (plus sign on left, space on right)" function alignment(x::Complex) m = match(r"^(.*[\+\-])(.*)$", sprint(showcompact_lim, x)) m === nothing ? (length(sprint(showcompact_lim, x)), 0) : @@ -983,12 +985,17 @@ end const undef_ref_str = "#undef" const undef_ref_alignment = (3,3) -# alignment(X, rows, cols, cols_if_complete, cols_otherwise, sep) returns the -# alignment for specified parts of array X, returning the (left,right) info. -# It will look in X's rows, cols (index lists) -# and figure out what's needed to be fully aligned, for example looking all -# the way down a column and finding out the maximum size of each element. -# Parameter sep is number of spaces to put between elements. +""" +`alignment(X, rows, cols, cols_if_complete, cols_otherwise, sep)` returns the +alignment for specified parts of array `X`, returning the (left,right) info. +It will look in X's `rows`, `cols` (both lists of indices) +and figure out what's needed to be fully aligned, for example looking all +the way down a column and finding out the maximum size of each element. +Parameter `sep::Integer` is number of spaces to put between elements. +`cols_if_complete` and `cols_otherwise` indicate screen width to use. +Alignment is reported as a vector of (left,right) tuples, one for each +column going across the screen. +""" function alignment( X::AbstractVecOrMat, rows::AbstractVector, cols::AbstractVector, @@ -1006,9 +1013,9 @@ function alignment( l = max(l, aij[1]) # left characters r = max(r, aij[2]) # right characters end - push!(a, (l, r)) + push!(a, (l, r)) # one tuple per column of X, pruned to screen width if length(a) > 1 && sum(map(sum,a)) + sep*length(a) >= cols_if_complete - pop!(a) + pop!(a) # remove this latest tuple if we're already beyond screen width break end end @@ -1020,11 +1027,13 @@ function alignment( return a end -# print_matrix_row(io, X, A, i, cols, sep) produces the aligned output for -# a singel matrix row X[i, cols] where the desired list of columns is given. -# The corresponding alignment A is used, and the separation between elements -# is specified as string sep. -# print_matrix_row will also respect compact output for elements +""" +`print_matrix_row(io, X, A, i, cols, sep)` produces the aligned output for +a single matrix row X[i, cols] where the desired list of columns is given. +The corresponding alignment A is used, and the separation between elements +is specified as string sep. +`print_matrix_row` will also respect compact output for elements. +""" function print_matrix_row(io::IO, X::AbstractVecOrMat, A::Vector, i::Integer, cols::AbstractVector, sep::AbstractString @@ -1046,9 +1055,11 @@ function print_matrix_row(io::IO, end end -# print_matrix_vdots is used to show a series of vertical ellipsis instead -# of a bunch of rows for long matrices. Not only is the string vdots shown -# but it also repeated every M elements if desired. +""" +`print_matrix_vdots` is used to show a series of vertical ellipsis instead +of a bunch of rows for long matrices. Not only is the string vdots shown +but it also repeated every M elements if desired. +""" function print_matrix_vdots(io::IO, vdots::AbstractString, A::Vector, sep::AbstractString, M::Integer, m::Integer ) @@ -1065,13 +1076,16 @@ function print_matrix_vdots(io::IO, end end -# print_matrix composes an entire matrix, taking into account the screen size -# to determine when vertical, horizontal, or diagonal ellipsis are desired. -# Parameters are the matrix X, screen size tuple sz such as (24,80), -# String pre on left of each row and post on right, and sep as separator -# between elements. Also options to use different ellipsis characters hdots, -# vdots, ddots. The ellipsis are separated every hmod or vmod apart. -# The printing works mostly by composing print_matrix_row in various ways. +""" +`print_matrix(io, X)` composes an entire matrix X, taking into account the screen size +to determine when vertical, horizontal, or diagonal ellipsis are desired. +`print_matrix(io, X, sz, pre, sep, post, vdots, ddots, hmod)` has optional +parameters: screen size tuple `sz` such as (24,80), +string `pre` prior to the matrix, with same-size indent on following rows, +and string `post` on the end of the last row of the matrix. +Also options to use different ellipsis characters `hdots`, +`vdots`, `ddots`. The ellipsis are separated every `hmod` or `vmod` apart. +""" function print_matrix(io::IO, X::AbstractVecOrMat, sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), pre::AbstractString = " ", @@ -1088,7 +1102,10 @@ function print_matrix(io::IO, X::AbstractVecOrMat, @assert strwidth(hdots) == strwidth(ddots) ss = length(sep) m, n = size(X,1), size(X,2) - if m <= rows # rows fit + if m <= rows # rows fit vertically on screen + # is there a reasonable chance of fitting all columns across screen? + # evaluate by assuming minimum width of 1 char and separator per element + A = alignment(X,1:m,1:n,cols,cols,ss) if n <= length(A) # rows and cols fit so just print whole matrix in one piece for i = 1:m @@ -1097,7 +1114,7 @@ function print_matrix(io::IO, X::AbstractVecOrMat, print(io, i == m ? post : postsp) if i != m; println(io, ); end end - else # rows fit, cols don't so need horizontal ellipsis + else # rows fit on screen but cols don't, so need horizontal ellipsis c = div(cols-length(hdots)+1,2)+1 # what goes to right of ellipsis R = reverse(alignment(X,1:m,n:-1:1,c,c,ss)) # alignments for right c = cols - sum(map(sum,R)) - (length(R)-1)*ss - length(hdots) @@ -1152,6 +1169,7 @@ function print_matrix(io::IO, X::AbstractVecOrMat, end end +"`summary(x)` a string of type information, e.g. `Int64`" summary(x) = string(typeof(x)) # e.g. Int64 # sizes such as 0-dimensional, 4-dimensional, 2x3 @@ -1160,6 +1178,7 @@ dims2string(d) = length(d) == 0 ? "0-dimensional" : join(map(string,d), 'x') # anything array-like gets summarized e.g. 10-element Array{Int64,1} +"`summary(A)` for array is a string of size and type info, e.g. `10-element Array{Int64,1}`" summary(a::AbstractArray) = string(dims2string(size(a)), " ", typeof(a)) From 2b3f95d7204884843f0536cd1f0431c7efc1b28a Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Tue, 13 Oct 2015 19:08:34 -0400 Subject: [PATCH 08/14] streamlined writemime range type --- base/replutil.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/replutil.jl b/base/replutil.jl index 1cfab1b5e3344..f666512c5d8a8 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -18,7 +18,7 @@ end # 1,2,3 # or for more elements than fit on screen: # 1.0,2.0,3.0,…,6.0,7.0,8.0 -function writemime(io::IO, ::MIME"text/plain", r::Union{Range, LinSpace}) +function writemime(io::IO, ::MIME"text/plain", r::Range) print(io, summary(r)) if !isempty(r) println(io, ":") From f81b4f678997c59ec7e672ec3e2ba61fdb18f88b Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Tue, 13 Oct 2015 20:16:11 -0400 Subject: [PATCH 09/14] more concise tests --- test/ranges.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/ranges.jl b/test/ranges.jl index d3da204203207..a88f6c02ede77 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -547,15 +547,13 @@ end # stringmime/writemime should display the range or linspace nicely # to test print_range in range.jl replstr(x) = stringmime("text/plain", x) -@test replstr(1:4) == "4-element UnitRange{Int64}:\n 1,2,3,4" || - replstr(1:4) == "4-element UnitRange{Int32}:\n 1,2,3,4" +@test replstr(1:4) == "4-element UnitRange{$Int}:\n 1,2,3,4" @test replstr(linspace(1,5,7)) == "7-element LinSpace{Float64}:\n 1.0,1.66667,2.33333,3.0,3.66667,4.33333,5.0" @test replstr(0:100.) == "101-element FloatRange{Float64}:\n 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,…,94.0,95.0,96.0,97.0,98.0,99.0,100.0" # next is to test a very large range, which should be fast because print_range # only examines spacing of the left and right edges of the range, sufficient # to cover the designated screen size. -@test replstr(0:10^9) == "1000000001-element UnitRange{Int64}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" || - replstr(0:10^9) == "1000000001-element UnitRange{Int32}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" +@test replstr(0:10^9) == "1000000001-element UnitRange{$Int}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" # Issue 11049 and related @test promote(linspace(0f0, 1f0, 3), linspace(0., 5., 2)) === From 2d445e047724f3832c15550b3ee7055dcc76d484 Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Tue, 13 Oct 2015 20:37:15 -0400 Subject: [PATCH 10/14] removed unwanted dup of docstring --- base/range.jl | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/base/range.jl b/base/range.jl index ba2e0f8fe4498..9679a9b098c24 100644 --- a/base/range.jl +++ b/base/range.jl @@ -252,19 +252,6 @@ It figures out the width in characters of each element, and if they end up too wide, it shows the first and last elements separated by a horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. -`print_range(io, r, sz, pre, sep, post, hdots)` uses optional -parameters `sz` for the (rows,cols) of the screen, -`pre` and `post` characters for each printed row, `sep` separator string between -printed elements, `hdots` string for the horizontal ellipsis. -""" -""" -`print_range(io, r)` prints out a nice looking range r in terms of its elements -as if it were `collect(r)`, dependent on the size of the -terminal, and taking into account whether compact numbers should be shown. -It figures out the width in characters of each element, and if they -end up too wide, it shows the first and last elements separated by a -horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. - `print_range(io, r, sz, pre, sep, post, hdots)` uses optional parameters `sz` for the (rows,cols) of the screen, `pre` and `post` characters for each printed row, `sep` separator string between From 5e05afe9c24d0f4972ea68e5e88447bfe06df3d7 Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Tue, 13 Oct 2015 22:29:08 -0400 Subject: [PATCH 11/14] moved docstring below, due to strange problem with compilation --- base/range.jl | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/base/range.jl b/base/range.jl index 9679a9b098c24..345d6262690bf 100644 --- a/base/range.jl +++ b/base/range.jl @@ -244,27 +244,26 @@ function show(io::IO, r::LinSpace) print(io, ')') end -""" -`print_range(io, r)` prints out a nice looking range r in terms of its elements -as if it were `collect(r)`, dependent on the size of the -terminal, and taking into account whether compact numbers should be shown. -It figures out the width in characters of each element, and if they -end up too wide, it shows the first and last elements separated by a -horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. - -`print_range(io, r, sz, pre, sep, post, hdots)` uses optional -parameters `sz` for the (rows,cols) of the screen, -`pre` and `post` characters for each printed row, `sep` separator string between -printed elements, `hdots` string for the horizontal ellipsis. -""" +# `print_range(io, r)` prints out a nice looking range r in terms of its elements +# as if it were `collect(r)`, dependent on the size of the +# terminal, and taking into account whether compact numbers should be shown. +# It figures out the width in characters of each element, and if they +# end up too wide, it shows the first and last elements separated by a +# horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. +# +# `print_range(io, r, sz, pre, sep, post, hdots)` uses optional +# parameters `sz` for the (rows,cols) of the screen, +# `pre` and `post` characters for each printed row, `sep` separator string between +# printed elements, `hdots` string for the horizontal ellipsis. +# See docstring below. function print_range(io::IO, r::Range, sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), pre::AbstractString = " ", sep::AbstractString = ",", post::AbstractString = "", hdots::AbstractString = ",\u2026,") # horiz ellipsis -# This function borrows from print_matrix() in show.jl -# and should be called by writemime (replutil.jl) and by display() + # This function borrows from print_matrix() in show.jl + # and should be called by writemime (replutil.jl) and by display() screenheight, screenwidth = sz screenwidth -= length(pre) + length(post) postsp = "" @@ -297,6 +296,23 @@ function print_range(io::IO, r::Range, end end +# For some reason, compilation is successful when the docstring is put here +# instead of above the function definition. +""" +`print_range(io, r)` prints out a nice looking range r in terms of its elements +as if it were `collect(r)`, dependent on the size of the +terminal, and taking into account whether compact numbers should be shown. +It figures out the width in characters of each element, and if they +end up too wide, it shows the first and last elements separated by a +horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. + +`print_range(io, r, sz, pre, sep, post, hdots)` uses optional +parameters `sz` for the (rows,cols) of the screen, +`pre` and `post` characters for each printed row, `sep` separator string between +printed elements, `hdots` string for the horizontal ellipsis. +""" +print_range + logspace(start::Real, stop::Real, n::Integer=50) = 10.^linspace(start, stop, n) ## interface implementations From d8b6a24f98551d3ad00c2fc31f1f5a02579fbd48 Mon Sep 17 00:00:00 2001 From: Michael Hatherly Date: Wed, 14 Oct 2015 08:04:42 +0200 Subject: [PATCH 12/14] Fix doc bootstrap method error. Docstrings defined before `==` is available for `Symbol` comparisons causes a build error. Fix by comparing with `===`. Ref: https://github.com/JuliaLang/julia/pull/13534#issuecomment-147906630 --- base/docs/bootstrap.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/base/docs/bootstrap.jl b/base/docs/bootstrap.jl index 9fbe4b4bfafe9..62f6e7cfc01d0 100644 --- a/base/docs/bootstrap.jl +++ b/base/docs/bootstrap.jl @@ -21,8 +21,8 @@ setexpand!(f) = global _expand_ = f function __bootexpand(str, obj) global docs = List((ccall(:jl_get_current_module, Any, ()), str, obj), docs) - (isa(obj, Expr) && obj.head == :call) && return nothing - (isa(obj, Expr) && obj.head == :module) && return esc(Expr(:toplevel, obj)) + (isa(obj, Expr) && obj.head === :call) && return nothing + (isa(obj, Expr) && obj.head === :module) && return esc(Expr(:toplevel, obj)) esc(obj) end @@ -45,6 +45,11 @@ that were stored in `DocBootstrap.docs` are migrated to their correct modules us """ DocBootstrap +""" + loaddocs() + +Move all docstrings from `DocBootstrap.docs` to their module's `__META__` dict. +""" function loaddocs() node = docs while node ≠ nothing From 87131f399eda8e8e35adfce16ce3e34b988a523e Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Thu, 8 Oct 2015 10:02:58 -0400 Subject: [PATCH 13/14] Deprecate A_ldiv_B!(SparseMatrixCSC, StrideVecOrMat) thereby fixing #10787 --- NEWS.md | 3 +++ base/deprecated.jl | 4 ++++ base/sparse/linalg.jl | 14 -------------- test/sparsedir/sparse.jl | 3 --- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/NEWS.md b/NEWS.md index 75a5cc9246855..8adc4a08e24ae 100644 --- a/NEWS.md +++ b/NEWS.md @@ -45,6 +45,9 @@ Library improvements Deprecated or removed --------------------- + * The method `A_ldiv_B!(SparseMatrixCSC, StrideVecOrMat)` has been deprecated in favor + of versions that require the matrix to in factored form ([#13496]). + Julia v0.4.0 Release Notes ========================== diff --git a/base/deprecated.jl b/base/deprecated.jl index 687ff736c9316..555bcc2197013 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -843,6 +843,7 @@ for f in (:remotecall, :remotecall_fetch, :remotecall_wait) end end +#13465 @deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) covm(x, mean, corrected) @deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) covm(X, mean, vardim, corrected) @deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) covm(x, mean[1], y, mean[2], corrected) @@ -854,3 +855,6 @@ end @deprecate cor(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) corm(X, mean[1], Y, mean[2], vardim) @deprecate_binding SparseMatrix SparseArrays + +#13496 +@deprecate A_ldiv_B!(A::SparseMatrixCSC, B::StridedVecOrMat) A_ldiv_B!(factorize(A), B) diff --git a/base/sparse/linalg.jl b/base/sparse/linalg.jl index 9475575073df7..526365ab55b0f 100644 --- a/base/sparse/linalg.jl +++ b/base/sparse/linalg.jl @@ -165,20 +165,6 @@ function spmatmul{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}; end ## solvers -function A_ldiv_B!(A::SparseMatrixCSC, b::AbstractVecOrMat) - if eltype(b)<:Complex; A = complex(A); end - - if istril(A) - # TODO: Fix diagonal case. Diagonal(A.nzval) needs to handle - # the case where there are zeros on the diagonal and error out. - # It also does not work in the complex case. VBS. - #if istriu(A); return A_ldiv_B!(Diagonal(A.nzval), b); end - return fwdTriSolve!(A, b) - end - if istriu(A); return bwdTriSolve!(A, b); end - return A_ldiv_B!(lufact(A),b) -end - function fwdTriSolve!(A::SparseMatrixCSC, B::AbstractVecOrMat) # forward substitution for CSC matrices n = length(B) diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index 27e363354888b..1fa66634cec7a 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -126,7 +126,6 @@ for i = 1:5 @test (maximum(abs(a\b - full(a)\b)) < 1000*eps()) @test (maximum(abs(a'\b - full(a')\b)) < 1000*eps()) @test (maximum(abs(a.'\b - full(a.')\b)) < 1000*eps()) - @test (maximum(abs(A_ldiv_B!(a,copy(b)) - full(a)\b)) < 1000*eps()) a = speye(5) + tril(0.1*sprandn(5, 5, 0.2) + 0.1*im*sprandn(5, 5, 0.2)) b = randn(5,3) @@ -145,7 +144,6 @@ for i = 1:5 @test (maximum(abs(a\b - full(a)\b)) < 1000*eps()) @test (maximum(abs(a'\b - full(a')\b)) < 1000*eps()) @test (maximum(abs(a.'\b - full(a.')\b)) < 1000*eps()) - @test (maximum(abs(A_ldiv_B!(a,copy(b)) - full(a)\b)) < 1000*eps()) a = speye(5) + triu(0.1*sprandn(5, 5, 0.2) + 0.1*im*sprandn(5, 5, 0.2)) b = randn(5,3) @@ -164,7 +162,6 @@ for i = 1:5 @test (maximum(abs(a\b - full(a)\b)) < 1000*eps()) @test (maximum(abs(a'\b - full(a')\b)) < 1000*eps()) @test (maximum(abs(a.'\b - full(a.')\b)) < 1000*eps()) - @test (maximum(abs(A_ldiv_B!(a,copy(b)) - full(a)\b)) < 1000*eps()) a = spdiagm(randn(5)) + im*spdiagm(randn(5)) b = randn(5,3) From bd30aceb9bd6cff3c33b620ea9c8d94f107dbfd1 Mon Sep 17 00:00:00 2001 From: Art Kuo Date: Fri, 9 Oct 2015 12:33:13 -0400 Subject: [PATCH 14/14] added print_range for Range objects, to show the elements of the Range in REPL. Previous commits squashed, docstring moved back to front, builds and passes tests --- base/range.jl | 53 ++++++++++++++++++++++++++++++ base/replutil.jl | 25 +++++++++----- base/show.jl | 85 ++++++++++++++++++++++++++++++++++++++---------- test/ranges.jl | 11 +++++++ 4 files changed, 148 insertions(+), 26 deletions(-) diff --git a/base/range.jl b/base/range.jl index 52db2504d032b..af2f4dab0be4d 100644 --- a/base/range.jl +++ b/base/range.jl @@ -244,6 +244,59 @@ function show(io::IO, r::LinSpace) print(io, ')') end +""" +`print_range(io, r)` prints out a nice looking range r in terms of its elements +as if it were `collect(r)`, dependent on the size of the +terminal, and taking into account whether compact numbers should be shown. +It figures out the width in characters of each element, and if they +end up too wide, it shows the first and last elements separated by a +horizontal elipsis. Typical output will look like `1.0,2.0,3.0,…,4.0,5.0,6.0`. + +`print_range(io, r, sz, pre, sep, post, hdots)` uses optional +parameters `sz` for the (rows,cols) of the screen, +`pre` and `post` characters for each printed row, `sep` separator string between +printed elements, `hdots` string for the horizontal ellipsis. +""" +function print_range(io::IO, r::Range, + sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), + pre::AbstractString = " ", + sep::AbstractString = ",", + post::AbstractString = "", + hdots::AbstractString = ",\u2026,") # horiz ellipsis + # This function borrows from print_matrix() in show.jl + # and should be called by writemime (replutil.jl) and by display() + screenheight, screenwidth = sz + screenwidth -= length(pre) + length(post) + postsp = "" + sepsize = length(sep) + m = 1 # treat the range as a one-row matrix + n = length(r) + # Figure out spacing alignments for r, but only need to examine the + # left and right edge columns, as many as could conceivably fit on the + # screen, with the middle columns summarized by horz, vert, or diag ellipsis + maxpossiblecols = div(screenwidth, 1+sepsize) # assume each element is at least 1 char + 1 separator + colsr = n <= maxpossiblecols ? (1:n) : [1:div(maxpossiblecols,2)+1; (n-div(maxpossiblecols,2)):n] + rowmatrix = r[colsr]' # treat the range as a one-row matrix for print_matrix_row + A = alignment(rowmatrix,1:m,1:length(rowmatrix),screenwidth,screenwidth,sepsize) # how much space range takes + if n <= length(A) # cols fit screen, so print out all elements + print(io, pre) # put in pre chars + print_matrix_row(io,rowmatrix,A,1,1:n,sep) # the entire range + print(io, post) # add the post characters + else # cols don't fit so put horiz ellipsis in the middle + # how many chars left after dividing width of screen in half + # and accounting for the horiz ellipsis + c = div(screenwidth-length(hdots)+1,2)+1 # chars remaining for each side of rowmatrix + alignR = reverse(alignment(rowmatrix,1:m,length(rowmatrix):-1:1,c,c,sepsize)) # which cols of rowmatrix to put on the right + c = screenwidth - sum(map(sum,alignR)) - (length(alignR)-1)*sepsize - length(hdots) + alignL = alignment(rowmatrix,1:m,1:length(rowmatrix),c,c,sepsize) # which cols of rowmatrix to put on the left + print(io, pre) # put in pre chars + print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep) # left part of range + print(io, hdots) # horizontal ellipsis + print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep) # right part of range + print(io, post) # post chars + end +end + logspace(start::Real, stop::Real, n::Integer=50) = 10.^linspace(start, stop, n) ## interface implementations diff --git a/base/replutil.jl b/base/replutil.jl index 6e4412aaa5256..f666512c5d8a8 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -13,15 +13,24 @@ function writemime(io::IO, ::MIME"text/plain", f::Function) end end +# writemime for ranges, e.g. +# 3-element UnitRange{Int64,Int} +# 1,2,3 +# or for more elements than fit on screen: +# 1.0,2.0,3.0,…,6.0,7.0,8.0 +function writemime(io::IO, ::MIME"text/plain", r::Range) + print(io, summary(r)) + if !isempty(r) + println(io, ":") + with_output_limit(()->print_range(io, r)) + end +end + function writemime(io::IO, ::MIME"text/plain", v::AbstractVector) - if isa(v, Range) - show(io, v) - else - print(io, summary(v)) - if !isempty(v) - println(io, ":") - with_output_limit(()->print_matrix(io, v)) - end + print(io, summary(v)) + if !isempty(v) + println(io, ":") + with_output_limit(()->print_matrix(io, v)) end end diff --git a/base/show.jl b/base/show.jl index 68279acb7756d..c76e6c6c4b0e6 100644 --- a/base/show.jl +++ b/base/show.jl @@ -972,14 +972,21 @@ dump(io::IO, x::DataType) = dump(io, x, 5, "") dump(io::IO, x::TypeVar, n::Int, indent) = println(io, x.name) +""" +`alignment(X)` returns a tuple (left,right) showing how many characters are +needed on either side of an alignment feature such as a decimal point. +""" alignment(x::Any) = (0, length(sprint(showcompact_lim, x))) alignment(x::Number) = (length(sprint(showcompact_lim, x)), 0) +"`alignment(42)` yields (2,0)" alignment(x::Integer) = (length(sprint(showcompact_lim, x)), 0) +"`alignment(4.23)` yields (1,3) for `4` and `.23`" function alignment(x::Real) m = match(r"^(.*?)((?:[\.eE].*)?)$", sprint(showcompact_lim, x)) m === nothing ? (length(sprint(showcompact_lim, x)), 0) : (length(m.captures[1]), length(m.captures[2])) end +"`alignment(1 + 10im)` yields (3,5) for `1 +` and `_10im` (plus sign on left, space on right)" function alignment(x::Complex) m = match(r"^(.*[\+\-])(.*)$", sprint(showcompact_lim, x)) m === nothing ? (length(sprint(showcompact_lim, x)), 0) : @@ -994,26 +1001,37 @@ end const undef_ref_str = "#undef" const undef_ref_alignment = (3,3) +""" +`alignment(X, rows, cols, cols_if_complete, cols_otherwise, sep)` returns the +alignment for specified parts of array `X`, returning the (left,right) info. +It will look in X's `rows`, `cols` (both lists of indices) +and figure out what's needed to be fully aligned, for example looking all +the way down a column and finding out the maximum size of each element. +Parameter `sep::Integer` is number of spaces to put between elements. +`cols_if_complete` and `cols_otherwise` indicate screen width to use. +Alignment is reported as a vector of (left,right) tuples, one for each +column going across the screen. +""" function alignment( X::AbstractVecOrMat, rows::AbstractVector, cols::AbstractVector, cols_if_complete::Integer, cols_otherwise::Integer, sep::Integer ) a = Tuple{Int, Int}[] - for j in cols + for j in cols # need to go down each column one at a time l = r = 0 - for i in rows + for i in rows # plumb down and see what largest element sizes are if isassigned(X,i,j) aij = alignment(X[i,j]) else aij = undef_ref_alignment end - l = max(l, aij[1]) - r = max(r, aij[2]) + l = max(l, aij[1]) # left characters + r = max(r, aij[2]) # right characters end - push!(a, (l, r)) + push!(a, (l, r)) # one tuple per column of X, pruned to screen width if length(a) > 1 && sum(map(sum,a)) + sep*length(a) >= cols_if_complete - pop!(a) + pop!(a) # remove this latest tuple if we're already beyond screen width break end end @@ -1025,6 +1043,13 @@ function alignment( return a end +""" +`print_matrix_row(io, X, A, i, cols, sep)` produces the aligned output for +a single matrix row X[i, cols] where the desired list of columns is given. +The corresponding alignment A is used, and the separation between elements +is specified as string sep. +`print_matrix_row` will also respect compact output for elements. +""" function print_matrix_row(io::IO, X::AbstractVecOrMat, A::Vector, i::Integer, cols::AbstractVector, sep::AbstractString @@ -1039,13 +1064,18 @@ function print_matrix_row(io::IO, a = undef_ref_alignment sx = undef_ref_str end - l = repeat(" ", A[k][1]-a[1]) + l = repeat(" ", A[k][1]-a[1]) # pad on left and right as needed r = repeat(" ", A[k][2]-a[2]) print(io, l, sx, r) if k < length(A); print(io, sep); end end end +""" +`print_matrix_vdots` is used to show a series of vertical ellipsis instead +of a bunch of rows for long matrices. Not only is the string vdots shown +but it also repeated every M elements if desired. +""" function print_matrix_vdots(io::IO, vdots::AbstractString, A::Vector, sep::AbstractString, M::Integer, m::Integer ) @@ -1062,6 +1092,16 @@ function print_matrix_vdots(io::IO, end end +""" +`print_matrix(io, X)` composes an entire matrix X, taking into account the screen size +to determine when vertical, horizontal, or diagonal ellipsis are desired. +`print_matrix(io, X, sz, pre, sep, post, vdots, ddots, hmod)` has optional +parameters: screen size tuple `sz` such as (24,80), +string `pre` prior to the matrix, with same-size indent on following rows, +and string `post` on the end of the last row of the matrix. +Also options to use different ellipsis characters `hdots`, +`vdots`, `ddots`. The ellipsis are separated every `hmod` or `vmod` apart. +""" function print_matrix(io::IO, X::AbstractVecOrMat, sz::Tuple{Integer, Integer} = (s = tty_size(); (s[1]-4, s[2])), pre::AbstractString = " ", @@ -1078,20 +1118,23 @@ function print_matrix(io::IO, X::AbstractVecOrMat, @assert strwidth(hdots) == strwidth(ddots) ss = length(sep) m, n = size(X,1), size(X,2) - if m <= rows # rows fit + if m <= rows # rows fit vertically on screen + # is there a reasonable chance of fitting all columns across screen? + # evaluate by assuming minimum width of 1 char and separator per element + A = alignment(X,1:m,1:n,cols,cols,ss) - if n <= length(A) # rows and cols fit + if n <= length(A) # rows and cols fit so just print whole matrix in one piece for i = 1:m print(io, i == 1 ? pre : presp) print_matrix_row(io, X,A,i,1:n,sep) print(io, i == m ? post : postsp) if i != m; println(io, ); end end - else # rows fit, cols don't - c = div(cols-length(hdots)+1,2)+1 - R = reverse(alignment(X,1:m,n:-1:1,c,c,ss)) + else # rows fit on screen but cols don't, so need horizontal ellipsis + c = div(cols-length(hdots)+1,2)+1 # what goes to right of ellipsis + R = reverse(alignment(X,1:m,n:-1:1,c,c,ss)) # alignments for right c = cols - sum(map(sum,R)) - (length(R)-1)*ss - length(hdots) - L = alignment(X,1:m,1:n,c,c,ss) + L = alignment(X,1:m,1:n,c,c,ss) # alignments for left of ellipsis for i = 1:m print(io, i == 1 ? pre : presp) print_matrix_row(io, X,L,i,1:length(L),sep) @@ -1101,11 +1144,11 @@ function print_matrix(io::IO, X::AbstractVecOrMat, if i != m; println(io, ); end end end - else # rows don't fit + else # rows don't fit so will need vertical ellipsis t = div(rows,2) I = [1:t; m-div(rows-1,2)+1:m] A = alignment(X,I,1:n,cols,cols,ss) - if n <= length(A) # rows don't fit, cols do + if n <= length(A) # rows don't fit, cols do, so only vertical ellipsis for i in I print(io, i == 1 ? pre : presp) print_matrix_row(io, X,A,i,1:n,sep) @@ -1117,7 +1160,7 @@ function print_matrix(io::IO, X::AbstractVecOrMat, println(io, i == m ? post : postsp) end end - else # neither rows nor cols fit + else # neither rows nor cols fit, so use all 3 kinds of ellipsis c = div(cols-length(hdots)+1,2)+1 R = reverse(alignment(X,I,n:-1:1,c,c,ss)) c = cols - sum(map(sum,R)) - (length(R)-1)*ss - length(hdots) @@ -1142,15 +1185,20 @@ function print_matrix(io::IO, X::AbstractVecOrMat, end end -summary(x) = string(typeof(x)) +"`summary(x)` a string of type information, e.g. `Int64`" +summary(x) = string(typeof(x)) # e.g. Int64 +# sizes such as 0-dimensional, 4-dimensional, 2x3 dims2string(d) = length(d) == 0 ? "0-dimensional" : length(d) == 1 ? "$(d[1])-element" : join(map(string,d), 'x') +# anything array-like gets summarized e.g. 10-element Array{Int64,1} +"`summary(A)` for array is a string of size and type info, e.g. `10-element Array{Int64,1}`" summary(a::AbstractArray) = string(dims2string(size(a)), " ", typeof(a)) +# n-dimensional arrays function show_nd(io::IO, a::AbstractArray, limit, print_matrix, label_slices) if isempty(a) return @@ -1197,6 +1245,7 @@ end # for internal use in showing arrays. _limit_output = false +# print matrix with opening and closing square brackets function print_matrix_repr(io, X::AbstractArray) compact, prefix = array_eltype_show_how(X) prefix *= "[" @@ -1263,7 +1312,7 @@ end show(io::IO, X::AbstractArray) = showarray(io, X, header=_limit_output, repr=!_limit_output) -function with_output_limit(thk, lim=true) +function with_output_limit(thk, lim=true) # thk is usually show() global _limit_output last = _limit_output _limit_output = lim diff --git a/test/ranges.jl b/test/ranges.jl index a4a53ed49cc02..a88f6c02ede77 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -544,6 +544,17 @@ for x in r end @test i == 7 +# stringmime/writemime should display the range or linspace nicely +# to test print_range in range.jl +replstr(x) = stringmime("text/plain", x) +@test replstr(1:4) == "4-element UnitRange{$Int}:\n 1,2,3,4" +@test replstr(linspace(1,5,7)) == "7-element LinSpace{Float64}:\n 1.0,1.66667,2.33333,3.0,3.66667,4.33333,5.0" +@test replstr(0:100.) == "101-element FloatRange{Float64}:\n 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,…,94.0,95.0,96.0,97.0,98.0,99.0,100.0" +# next is to test a very large range, which should be fast because print_range +# only examines spacing of the left and right edges of the range, sufficient +# to cover the designated screen size. +@test replstr(0:10^9) == "1000000001-element UnitRange{$Int}:\n 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,…,999999998,999999999,1000000000" + # Issue 11049 and related @test promote(linspace(0f0, 1f0, 3), linspace(0., 5., 2)) === (linspace(0., 1., 3), linspace(0., 5., 2))