From 72dfaaa1c9e54b46d93e71a93a7a4d9b6fa70771 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 27 May 2016 17:04:33 -0400 Subject: [PATCH 1/4] fix shuffle(1:10), improve shuffle and randperm docs --- base/docs/helpdb/Base.jl | 11 ++++++++--- base/random.jl | 2 +- test/random.jl | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 0827af1c319e5..a6b6165b36af8 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -1417,7 +1417,8 @@ permutedims """ shuffle!([rng,] v) -In-place version of [`shuffle`](:func:`shuffle`). +In-place version of [`shuffle`](:func:`shuffle`): randomly permute the array `v` in-place, +optionally supplying the random-number generator `rng`. """ shuffle! @@ -5934,7 +5935,9 @@ wait shuffle([rng,] v) Return a randomly permuted copy of `v`. The optional `rng` argument specifies a random -number generator, see [Random Numbers](:ref:`Random Numbers `). +number generator (see [Random Numbers](:ref:`Random Numbers `)). +To permute `v` in-place, see [`shuffle!`](:func:`shuffle!`). To obtain randomly permuted +indices, see [`randperm`](:func:`randperm`). """ shuffle @@ -10004,7 +10007,9 @@ filter randperm([rng,] n) Construct a random permutation of length `n`. The optional `rng` argument specifies a random -number generator, see [Random Numbers](:ref:`Random Numbers `). +number generator (see [Random Numbers](:ref:`Random Numbers `)). +To randomly permute a arbitrary vector, see [`shuffle`](:func:`shuffle`) +or [`shuffle!`](:func:`shuffle!`). """ randperm diff --git a/base/random.jl b/base/random.jl index 659015a306f39..e7083e4044534 100644 --- a/base/random.jl +++ b/base/random.jl @@ -1338,7 +1338,7 @@ end shuffle!(a::AbstractVector) = shuffle!(GLOBAL_RNG, a) -shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copy(a)) +shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copy!(similar(a), a)) shuffle(a::AbstractVector) = shuffle(GLOBAL_RNG, a) function randperm(r::AbstractRNG, n::Integer) diff --git a/test/random.jl b/test/random.jl index e3cf808615079..619507b8a2ed4 100644 --- a/test/random.jl +++ b/test/random.jl @@ -376,8 +376,10 @@ let mta = MersenneTwister(42), mtb = MersenneTwister(42) @test shuffle(mta,collect(1:10)) == shuffle(mtb,collect(1:10)) @test shuffle!(mta,collect(1:10)) == shuffle!(mtb,collect(1:10)) + @test shuffle(mta,collect(2:11)) == shuffle(mtb,2:11) @test randperm(mta,10) == randperm(mtb,10) + @test sort!(randperm(10)) == sort!(shuffle(1:10)) == collect(1:10) @test randperm(mta,big(10)) == randperm(mtb,big(10)) # cf. #16376 @test randperm(0) == [] @test_throws ErrorException randperm(-1) From 5f96297b9e1bbf44ddff487bb31b349fbfd49772 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 27 May 2016 17:10:42 -0400 Subject: [PATCH 2/4] fix two more cases where a mutable copy was needed --- base/collections.jl | 2 +- base/statistics.jl | 2 +- test/priorityqueue.jl | 3 +++ test/statistics.jl | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/base/collections.jl b/base/collections.jl index 2f64f3a48c5f4..41adaf881fe23 100644 --- a/base/collections.jl +++ b/base/collections.jl @@ -106,7 +106,7 @@ end Returns a new vector in binary heap order, optionally using the given ordering. """ -heapify(xs::AbstractArray, o::Ordering=Forward) = heapify!(copy(xs), o) +heapify(xs::AbstractArray, o::Ordering=Forward) = heapify!(copy!(similar(xs), xs), o) """ isheap(v, [ord]) diff --git a/base/statistics.jl b/base/statistics.jl index 3d240cadafc0d..61d7bbe855d4a 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -507,7 +507,7 @@ function median!{T}(v::AbstractVector{T}) end median!{T}(v::AbstractArray{T}) = median!(vec(v)) -median{T}(v::AbstractArray{T}) = median!(vec(copy(v))) +median{T}(v::AbstractArray{T}) = median!(vec(copy!(similar(v), v))) median{T}(v::AbstractArray{T}, region) = mapslices(median!, v, region) # for now, use the R/S definition of quantile; may want variants later diff --git a/test/priorityqueue.jl b/test/priorityqueue.jl index a554b2958796a..557da010a9731 100644 --- a/test/priorityqueue.jl +++ b/test/priorityqueue.jl @@ -88,6 +88,9 @@ end xs = heapify!([v for v in values(priorities)]) @test issorted([heappop!(xs) for _ in length(priorities)]) +xs = heapify(10:-1:1) +@test issorted([heappop!(xs) for _ in 1:10]) + xs = Array(Int, 0) for priority in values(priorities) heappush!(xs, priority) diff --git a/test/statistics.jl b/test/statistics.jl index cb8b29462eea1..75d826bb4ec03 100644 --- a/test/statistics.jl +++ b/test/statistics.jl @@ -44,6 +44,8 @@ end @test median!([1 2 3 4]) == 2.5 @test median!([1 2; 3 4]) == 2.5 +@test invoke(median, (AbstractVector,), 1:10) == median(1:10) == 5.5 + # mean @test_throws ArgumentError mean(()) @test mean((1,2,3)) === 2. From cde9472a4741211e6a6dcb5ece7c5ecf6bfa2ed7 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 27 May 2016 17:35:55 -0400 Subject: [PATCH 3/4] consolidate copy!(similar(a),a) method into copymutable(a) --- base/abstractarray.jl | 14 +++++++++++++- base/collections.jl | 4 ++-- base/combinatorics.jl | 4 ++-- base/random.jl | 3 ++- base/sort.jl | 6 +++--- base/statistics.jl | 4 ++-- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index c9668fd467584..b269ac81d8598 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -290,7 +290,7 @@ function copy!(dest::AbstractArray, doffs::Integer, return dest end -copy(a::AbstractArray) = copy!(similar(a), a) +copy(a::AbstractArray) = copymutable(a) function copy!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_dest::Range{Int}, A::AbstractVecOrMat{S}, ir_src::Range{Int}, jr_src::Range{Int}) @@ -340,6 +340,18 @@ function copy_transpose!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_de return B end +copymutable(a::AbstractArray) = copy!(similar(a), a) +copymutable(itr) = collect(itr) +""" + copymutable(a) + +Make a mutable copy of an array or iterable `a`. For `a::Array`, +this is equivalent to `copy(a)`, but for other array types it may +differ depending on the type of `similar(a)`. For generic iterables +this is equivalent to `collect(a)`. +""" +copymutable + zero{T}(x::AbstractArray{T}) = fill!(similar(x), zero(T)) ## iteration support for arrays by iterating over `eachindex` in the array ## diff --git a/base/collections.jl b/base/collections.jl index 41adaf881fe23..11d3d23cc66cf 100644 --- a/base/collections.jl +++ b/base/collections.jl @@ -2,7 +2,7 @@ module Collections -import Base: setindex!, done, get, hash, haskey, isempty, length, next, getindex, start +import Base: setindex!, done, get, hash, haskey, isempty, length, next, getindex, start, copymutable import ..Order: Forward, Ordering, lt export @@ -106,7 +106,7 @@ end Returns a new vector in binary heap order, optionally using the given ordering. """ -heapify(xs::AbstractArray, o::Ordering=Forward) = heapify!(copy!(similar(xs), xs), o) +heapify(xs::AbstractArray, o::Ordering=Forward) = heapify!(copymutable(xs), o) """ isheap(v, [ord]) diff --git a/base/combinatorics.jl b/base/combinatorics.jl index e91b827131c02..1478aa8a3e85c 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -100,7 +100,7 @@ to verify that `p` is a permutation. To return a new permutation, use `v[p]`. Note that this is generally faster than `permute!(v,p)` for large vectors. """ -permute!(a, p::AbstractVector) = permute!!(a, copy!(similar(p), p)) +permute!(a, p::AbstractVector) = permute!!(a, copymutable(p)) function ipermute!!{T<:Integer}(a, p::AbstractVector{T}) count = 0 @@ -130,7 +130,7 @@ end Like `permute!`, but the inverse of the given permutation is applied. """ -ipermute!(a, p::AbstractVector) = ipermute!!(a, copy!(similar(p), p)) +ipermute!(a, p::AbstractVector) = ipermute!!(a, copymutable(p)) """ invperm(v) diff --git a/base/random.jl b/base/random.jl index e7083e4044534..844c25d6eb7b2 100644 --- a/base/random.jl +++ b/base/random.jl @@ -4,6 +4,7 @@ module Random using Base.dSFMT using Base.GMP: GMP_VERSION, Limb +import Base.copymutable export srand, rand, rand!, @@ -1338,7 +1339,7 @@ end shuffle!(a::AbstractVector) = shuffle!(GLOBAL_RNG, a) -shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copy!(similar(a), a)) +shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copymutable(a)) shuffle(a::AbstractVector) = shuffle(GLOBAL_RNG, a) function randperm(r::AbstractRNG, n::Integer) diff --git a/base/sort.jl b/base/sort.jl index 9c9be1e8581fc..62ffe0c9e8ee1 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -2,7 +2,7 @@ module Sort -using Base.Order +using Base.Order, Base.copymutable import Base.sort, @@ -66,7 +66,7 @@ select!(v::AbstractVector, k::Union{Int,OrdinalRange}; lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) = select!(v, k, ord(lt,by,rev,order)) -select(v::AbstractVector, k::Union{Int,OrdinalRange}; kws...) = select!(copy!(similar(v), v), k; kws...) +select(v::AbstractVector, k::Union{Int,OrdinalRange}; kws...) = select!(copymutable(v), k; kws...) # reference on sorted binary search: @@ -410,7 +410,7 @@ function sort!(v::AbstractVector; sort!(v, alg, ord(lt,by,rev,order)) end -sort(v::AbstractVector; kws...) = sort!(copy!(similar(v), v); kws...) +sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...) ## selectperm: the permutation to sort the first k elements of an array ## diff --git a/base/statistics.jl b/base/statistics.jl index 61d7bbe855d4a..a9220a43979f5 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -507,7 +507,7 @@ function median!{T}(v::AbstractVector{T}) end median!{T}(v::AbstractArray{T}) = median!(vec(v)) -median{T}(v::AbstractArray{T}) = median!(vec(copy!(similar(v), v))) +median{T}(v::AbstractArray{T}) = median!(copy!(Array(T, length(v)), v)) median{T}(v::AbstractArray{T}, region) = mapslices(median!, v, region) # for now, use the R/S definition of quantile; may want variants later @@ -612,4 +612,4 @@ for `k = 1:n` where `n = length(v)`. This corresponds to Definition 7 of Hyndman *The American Statistician*, Vol. 50, No. 4, pp. 361-365 """ quantile(v::AbstractVector, p; sorted::Bool=false) = - quantile!(sorted ? v : copy!(similar(v),v), p; sorted=sorted) + quantile!(sorted ? v : copymutable(v), p; sorted=sorted) From 974994b7422f18938bb68545a6ca39e2a1c72d29 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 27 May 2016 17:39:37 -0400 Subject: [PATCH 4/4] re-run genstdlib --- doc/stdlib/arrays.rst | 6 +++--- doc/stdlib/io-network.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/stdlib/arrays.rst b/doc/stdlib/arrays.rst index 44b0060c0ebee..695a5fa594063 100644 --- a/doc/stdlib/arrays.rst +++ b/doc/stdlib/arrays.rst @@ -732,7 +732,7 @@ Combinatorics .. Docstring generated from Julia source - Construct a random permutation of length ``n``\ . The optional ``rng`` argument specifies a random number generator, see :ref:`Random Numbers `\ . + Construct a random permutation of length ``n``\ . The optional ``rng`` argument specifies a random number generator (see :ref:`Random Numbers `\ ). To randomly permute a arbitrary vector, see :func:`shuffle` or :func:`shuffle!`\ . .. function:: invperm(v) @@ -770,13 +770,13 @@ Combinatorics .. Docstring generated from Julia source - Return a randomly permuted copy of ``v``\ . The optional ``rng`` argument specifies a random number generator, see :ref:`Random Numbers `\ . + Return a randomly permuted copy of ``v``\ . The optional ``rng`` argument specifies a random number generator (see :ref:`Random Numbers `\ ). To permute ``v`` in-place, see :func:`shuffle!`\ . To obtain randomly permuted indices, see :func:`randperm`\ . .. function:: shuffle!([rng,] v) .. Docstring generated from Julia source - In-place version of :func:`shuffle`\ . + In-place version of :func:`shuffle`\ : randomly permute the array ``v`` in-place, optionally supplying the random-number generator ``rng``\ . .. function:: reverse(v [, start=1 [, stop=length(v) ]] ) diff --git a/doc/stdlib/io-network.rst b/doc/stdlib/io-network.rst index 4c6a92f808b15..2fcfc38e4cbfc 100644 --- a/doc/stdlib/io-network.rst +++ b/doc/stdlib/io-network.rst @@ -713,9 +713,9 @@ Julia environments (such as the IPython-based IJulia notebook). For example, if you define a ``MyImage`` type and know how to write it to a PNG file, you could define a function ``show(stream, ::MIME"image/png", x::MyImage) = ...`` to allow your images to be displayed on any PNG-capable ``Display`` (such as IJulia). As usual, be sure to ``import Base.show`` in order to add new methods to the built-in Julia function ``show``\ . - Technically, the ``MIME"mime"`` macro defines a singleton type for the given ``mime`` string, which allows us to exploit Julia's dispatch mechanisms in determining how to display objects of any given type. + The default MIME type is ``MIME"text/plain"``\ . There is a fallback definition for ``text/plain`` output that calls ``show`` with 2 arguments. Therefore, this case should be handled by defining a 2-argument ``show(stream::IO, x::MyType)`` method. - The default MIME type is ``MIME"text/plain"``\ . There is a fallback definition for ``text/plain`` output that calls ``show`` with 2 arguments. Therefore, this case should be handled by defining a 2-argument ``show`` method. + Technically, the ``MIME"mime"`` macro defines a singleton type for the given ``mime`` string, which allows us to exploit Julia's dispatch mechanisms in determining how to display objects of any given type. .. function:: mimewritable(mime, x)