From 7e2ce0e5433af4fcaee9f7893f90d80c21316044 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 2 May 2018 15:11:34 -0500 Subject: [PATCH] RFC: Deprecate implicit scalar broadcasting in setindex! (#26347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current `setindex!` function (the `A[i] = b` syntax) does three very different operations: * Given an index `i` that refers to only one location (scalar indexing), `A[i] = b` modifies `A` in that location to hold `b`. * Given an index `I` that refers to more than one location (non-scalar indexing), `A[I] = b` can mean one of two things: * If `b` is an AbstractArray (multi-value), assign the values it contains to those locations `I` in `A`. That is, essentially, `[A[i] = bᵢ for (i, bᵢ) in zip(I, b)]`. * If `b` is not an AbstractArray (scalar-value), then broadcast its value to every location selected by `I` in `A`. These two different behaviors in the non-scalar indexing case basically make using this function in a generic way impossible. If you want to _always_ set the value `b` to many indices of `A`, you _cannot_ use this syntax because `b` might happen to be an array in some cases, radically changing the meaning of the expression. You need to manually iterate over the indices, using scalar setindex methods. But we now also have the new `broadcast!` syntax, `A[I] .= B`, which uses the usual broadcasting semantics to determine how `B` should fill into the values of `A`. This PR deprecates the implicit broadcasting of scalar values in non-scalar indexing in favor of an explicit `.=` broadcast syntax, leaving multi-value non-scalar indexing intact. This is the _exact opposite_ of PR #24368. --- NEWS.md | 12 +++ base/abstractarray.jl | 22 ++-- base/abstractarraymath.jl | 6 +- base/array.jl | 26 ----- base/bitarray.jl | 38 +------ base/bitset.jl | 8 +- base/broadcast.jl | 35 +++++- base/char.jl | 5 +- base/compiler/ssair/ir.jl | 4 +- base/compiler/ssair/slot2ssa.jl | 2 +- base/deprecated.jl | 21 ++++ base/iobuffer.jl | 4 +- base/multidimensional.jl | 32 +++--- stdlib/FileWatching/src/FileWatching.jl | 2 +- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/qr.jl | 6 +- stdlib/LinearAlgebra/src/uniformscaling.jl | 9 +- stdlib/LinearAlgebra/test/dense.jl | 2 +- stdlib/Pkg3/src/GraphType.jl | 2 +- stdlib/SHA/src/sha3.jl | 2 +- stdlib/SharedArrays/test/runtests.jl | 16 +-- stdlib/SparseArrays/src/deprecated.jl | 9 ++ stdlib/SparseArrays/src/higherorderfns.jl | 9 +- stdlib/SparseArrays/src/linalg.jl | 2 +- stdlib/SparseArrays/src/sparsematrix.jl | 64 ++++++----- stdlib/SparseArrays/src/sparsevector.jl | 6 +- stdlib/SparseArrays/test/sparse.jl | 120 +++++++++++---------- stdlib/SparseArrays/test/sparsevector.jl | 15 +-- stdlib/SuiteSparse/src/spqr.jl | 2 +- test/arrayops.jl | 22 ++-- test/bitarray.jl | 41 ++++--- test/copy.jl | 2 +- test/subarray.jl | 14 +-- 33 files changed, 316 insertions(+), 246 deletions(-) diff --git a/NEWS.md b/NEWS.md index 67fc1343e9cbc..b072cbf94f0e1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -697,6 +697,18 @@ Deprecated or removed `Matrix{Int}(undef, (2, 4))`, and `Array{Float32,3}(11, 13, 17)` is now `Array{Float32,3}(undef, 11, 13, 17)` ([#24781]). + * Previously `setindex!(A, x, I...)` (and the syntax `A[I...] = x`) supported two + different modes of operation when supplied with a set of non-scalar indices `I` + (e.g., at least one index is an `AbstractArray`) depending upon the value of `x` + on the right hand side. If `x` is an `AbstractArray`, its _contents_ are copied + elementwise into the locations in `A` selected by `I` and it must have the same + number of elements as `I` selects locations. Otherwise, if `x` is not an + `AbstractArray`, then its _value_ is implicitly broadcast to all locations to + all locations in `A` selected by `I`. This latter behavior—implicitly broadcasting + "scalar"-like values across many locations—is now deprecated in favor of explicitly + using the broadcasted assignment syntax `A[I...] .= x` or `fill!(view(A, I...), x)` + ([#26347]). + * `LinAlg.fillslots!` has been renamed `LinAlg.fillstored!` ([#25030]). * `fill!(A::Diagonal, x)` and `fill!(A::AbstractTriangular, x)` have been deprecated diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 5755ed8e7d999..ec65d728c2a54 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1181,8 +1181,8 @@ function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,Abst # Linear indexing ind = findall(in(1:length(A)), I) X[ind] = A[I[ind]] - X[1:first(ind)-1] = default - X[last(ind)+1:length(X)] = default + fill!(view(X, 1:first(ind)-1), default) + fill!(view(X, last(ind)+1:length(X)), default) X end @@ -1380,7 +1380,11 @@ function _cat(A, shape::NTuple{N}, catdims, X...) where N end end I::NTuple{N, UnitRange{Int}} = (inds...,) - A[I...] = x + if x isa AbstractArray + A[I...] = x + else + fill!(view(A, I...), x) + end end return A end @@ -1930,10 +1934,10 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) ridx[d] = axes(R,d) end - R[ridx...] = r1 + concatenate_setindex!(R, r1, ridx...) nidx = length(otherdims) - indices = Iterators.drop(CartesianIndices(itershape), 1) + indices = Iterators.drop(CartesianIndices(itershape), 1) # skip the first element, we already handled it inner_mapslices!(safe_for_reuse, indices, nidx, idx, otherdims, ridx, Aslice, A, f, R) end @@ -1941,16 +1945,16 @@ end if safe_for_reuse # when f returns an array, R[ridx...] = f(Aslice) line copies elements, # so we can reuse Aslice - for I in indices # skip the first element, we already handled it + for I in indices replace_tuples!(nidx, idx, ridx, otherdims, I) _unsafe_getindex!(Aslice, A, idx...) - R[ridx...] = f(Aslice) + concatenate_setindex!(R, f(Aslice), ridx...) end else # we can't guarantee safety (#18524), so allocate new storage for each slice for I in indices replace_tuples!(nidx, idx, ridx, otherdims, I) - R[ridx...] = f(A[idx...]) + concatenate_setindex!(R, f(A[idx...]), ridx...) end end @@ -1963,6 +1967,8 @@ function replace_tuples!(nidx, idx, ridx, otherdims, I) end end +concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R) +concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X) ## 1 argument diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index cd723ffd449e7..df3f1caddbe92 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -363,10 +363,6 @@ _rshps(shp, shp_i, sz, i, ::Tuple{}) = _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * "($n) cannot be less than number of dimensions of input ($N)")) -# We need special handling when repeating arrays of arrays -cat_fill!(R, X, inds) = (R[inds...] = X) -cat_fill!(R, X::AbstractArray, inds) = fill!(view(R, inds...), X) - @noinline function _repeat(A::AbstractArray, inner, outer) shape, inner_shape = rep_shapes(A, inner, outer) @@ -385,7 +381,7 @@ cat_fill!(R, X::AbstractArray, inds) = fill!(view(R, inds...), X) n = inner[i] inner_indices[i] = (1:n) .+ ((c[i] - 1) * n) end - cat_fill!(R, A[c], inner_indices) + fill!(view(R, inner_indices...), A[c]) end end diff --git a/base/array.jl b/base/array.jl index 2f6956960a6fb..30dd5edc8b5d8 100644 --- a/base/array.jl +++ b/base/array.jl @@ -706,29 +706,6 @@ function setindex! end @eval setindex!(A::Array{T}, x, i1::Int, i2::Int, I::Int...) where {T} = (@_inline_meta; arrayset($(Expr(:boundscheck)), A, convert(T,x)::T, i1, i2, I...)) -# These are redundant with the abstract fallbacks but needed for bootstrap -function setindex!(A::Array, x, I::AbstractVector{Int}) - @_propagate_inbounds_meta - I′ = unalias(A, I) - for i in I′ - A[i] = x - end - return A -end -function setindex!(A::Array, X::AbstractArray, I::AbstractVector{Int}) - @_propagate_inbounds_meta - @boundscheck setindex_shape_check(X, length(I)) - X′ = unalias(A, X) - I′ = unalias(A, I) - count = 1 - for i in I′ - @inbounds x = X′[count] - A[i] = x - count += 1 - end - return A -end - # Faster contiguous setindex! with copyto! function setindex!(A::Array{T}, X::Array{T}, I::UnitRange{Int}) where T @_inline_meta @@ -750,9 +727,6 @@ function setindex!(A::Array{T}, X::Array{T}, c::Colon) where T return A end -setindex!(A::Array, x::Number, ::Colon) = fill!(A, x) -setindex!(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) where {T, N} = fill!(A, x) - # efficiently grow an array _growbeg!(a::Vector, delta::Integer) = diff --git a/base/bitarray.jl b/base/bitarray.jl index be4600713110b..fd826ef13cd1d 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -584,7 +584,7 @@ function gen_bitarray_from_itr(itr, st) end end if ind > 1 - @inbounds C[ind:bitcache_size] = false + @inbounds C[ind:bitcache_size] .= false resize!(B, length(B) + ind - 1) dumpbitcache(Bc, cind, C) end @@ -608,7 +608,7 @@ function fill_bitarray_from_itr!(B::BitArray, itr, st) end end if ind > 1 - @inbounds C[ind:bitcache_size] = false + @inbounds C[ind:bitcache_size] .= false dumpbitcache(Bc, cind, C) end return B @@ -653,44 +653,10 @@ end indexoffset(i) = first(i)-1 indexoffset(::Colon) = 0 -@inline function setindex!(B::BitArray, x, J0::Union{Colon,UnitRange{Int}}) - I0 = to_indices(B, (J0,))[1] - @boundscheck checkbounds(B, I0) - y = Bool(x) - l0 = length(I0) - l0 == 0 && return B - f0 = indexoffset(I0)+1 - fill_chunks!(B.chunks, y, f0, l0) - return B -end @propagate_inbounds function setindex!(B::BitArray, X::AbstractArray, J0::Union{Colon,UnitRange{Int}}) _setindex!(IndexStyle(B), B, X, to_indices(B, (J0,))[1]) end -# logical indexing - -# When indexing with a BitArray, we can operate whole chunks at a time for a ~100x gain -@inline function setindex!(B::BitArray, x, I::BitArray) - @boundscheck checkbounds(B, I) - _unsafe_setindex!(B, x, I) -end -function _unsafe_setindex!(B::BitArray, x, I::BitArray) - y = convert(Bool, x) - Bc = B.chunks - Ic = I.chunks - length(Bc) == length(Ic) || throw_boundserror(B, I) - @inbounds if y - for i = 1:length(Bc) - Bc[i] |= Ic[i] - end - else - for i = 1:length(Bc) - Bc[i] &= ~Ic[i] - end - end - return B -end - # Assigning an array of bools is more complicated, but we can still do some # work on chunks by combining X and I 64 bits at a time to improve perf by ~40% @inline function setindex!(B::BitArray, X::AbstractArray, I::BitArray) diff --git a/base/bitset.jl b/base/bitset.jl index 330b11e77430f..395a61505b85b 100644 --- a/base/bitset.jl +++ b/base/bitset.jl @@ -114,12 +114,16 @@ end @inline function _growend0!(b::Bits, nchunks::Int) len = length(b) _growend!(b, nchunks) - @inbounds b[len+1:end] = CHK0 # resize! gives dirty memory + for i in len+1:length(b) + @inbounds b[i] = CHK0 # resize! gives dirty memory + end end @inline function _growbeg0!(b::Bits, nchunks::Int) _growbeg!(b, nchunks) - @inbounds b[1:nchunks] = CHK0 + for i in 1:nchunks + @inbounds b[i] = CHK0 + end end function _matched_map!(f, s1::BitSet, s2::BitSet) diff --git a/base/broadcast.jl b/base/broadcast.jl index bda3daf818431..b9c275d2d031e 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -832,7 +832,7 @@ end end end if ind > 1 - @inbounds tmp[ind:bitcache_size] = false + @inbounds tmp[ind:bitcache_size] .= false dumpbitcache(destc, cind, tmp) end return dest @@ -1108,6 +1108,39 @@ See [`broadcast_getindex`](@ref) for examples of the treatment of `inds`. end end +## In specific instances, we can broadcast masked BitArrays whole chunks at a time +# Very intentionally do not support much functionality here: scalar indexing would be O(n) +struct BitMaskedBitArray{N,M} + parent::BitArray{N} + mask::BitArray{M} + BitMaskedBitArray{N,M}(parent, mask) where {N,M} = new(parent, mask) +end +@inline function BitMaskedBitArray(parent::BitArray{N}, mask::BitArray{M}) where {N,M} + @boundscheck checkbounds(parent, mask) + BitMaskedBitArray{N,M}(parent, mask) +end +Base.@propagate_inbounds dotview(B::BitArray, i::BitArray) = BitMaskedBitArray(B, i) +Base.show(io::IO, B::BitMaskedBitArray) = foreach(arg->show(io, arg), (typeof(B), (B.parent, B.mask))) +# Override materialize! to prevent the BitMaskedBitArray from escaping to an overrideable method +@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any,<:Any,typeof(identity),Tuple{Bool}}) = fill!(B, bc.args[1]) +@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(SubArray(B.parent, to_indices(B.parent, (B.mask,))), bc) +function Base.fill!(B::BitMaskedBitArray, b::Bool) + Bc = B.parent.chunks + Ic = B.mask.chunks + @inbounds if b + for i = 1:length(Bc) + Bc[i] |= Ic[i] + end + else + for i = 1:length(Bc) + Bc[i] &= ~Ic[i] + end + end + return B +end + + + ############################################################ # x[...] .= f.(y...) ---> broadcast!(f, dotview(x, ...), y...). diff --git a/base/char.jl b/base/char.jl index 768919d493c24..97e74d2d0758a 100644 --- a/base/char.jl +++ b/base/char.jl @@ -215,7 +215,10 @@ widen(::Type{T}) where {T<:AbstractChar} = T print(io::IO, c::Char) = (write(io, c); nothing) print(io::IO, c::AbstractChar) = print(io, Char(c)) # fallback: convert to output UTF-8 -const hex_chars = UInt8['0':'9';'a':'z'] +const hex_chars = UInt8['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] function show_invalid(io::IO, c::Char) write(io, 0x27) diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index 854533d83dbe2..97a202855a1f6 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -588,7 +588,9 @@ function resize!(compact::IncrementalCompact, nnewnodes) resize!(compact.result_lines, nnewnodes) resize!(compact.result_flags, nnewnodes) resize!(compact.used_ssas, nnewnodes) - compact.used_ssas[(old_length+1):nnewnodes] = 0 + for i in (old_length+1):nnewnodes + compact.used_ssas[i] = 0 + end nothing end diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index f23dd97280256..603e2ea943dd9 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -377,8 +377,8 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree) end old_inst_range = ir.cfg.blocks[bb].stmts inst_range = (bb_start_off+1):(bb_start_off+length(old_inst_range)) - inst_rename[old_inst_range] = Any[SSAValue(x) for x in inst_range] for (nidx, idx) in zip(inst_range, old_inst_range) + inst_rename[idx] = SSAValue(nidx) stmt = ir.stmts[idx] if isa(stmt, PhiNode) result_stmts[nidx] = rename_phinode_edges(stmt, bb, result_order, bb_rename) diff --git a/base/deprecated.jl b/base/deprecated.jl index a59338c29a9b7..edfe71ca0074a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1491,6 +1491,27 @@ function slicedim(A::AbstractVector, d::Integer, i::Number) end end +# PR #26347: Deprecate implicit scalar broadcasting in setindex! +_axes(::Ref) = () +_axes(x) = axes(x) +function deprecate_scalar_setindex_broadcast_message(v, I...) + value = (_axes(Base.Broadcast.broadcastable(v)) == () ? "x" : "(x,)") + "using `A[I...] = x` to implicitly broadcast `x` across many locations is deprecated. Use `A[I...] .= $value` instead." +end +deprecate_scalar_setindex_broadcast_message(v, ::Colon, ::Vararg{Colon}) = + "using `A[:] = x` to implicitly broadcast `x` across many locations is deprecated. Use `fill!(A, x)` instead." + +function _iterable(v, I...) + depwarn(deprecate_scalar_setindex_broadcast_message(v, I...), :setindex!) + Iterators.repeated(v) +end +function setindex!(B::BitArray, x, I0::Union{Colon,UnitRange{Int}}, I::Union{Int,UnitRange{Int},Colon}...) + depwarn(deprecate_scalar_setindex_broadcast_message(x, I0, I...), :setindex!) + B[I0, I...] .= (x,) + B +end + + # PR #26283 @deprecate contains(haystack, needle) occursin(needle, haystack) @deprecate contains(s::AbstractString, r::Regex, offset::Integer) occursin(r, s, offset=offset) diff --git a/base/iobuffer.jl b/base/iobuffer.jl index 88ce78dc77aec..c42093b9d2c59 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -117,7 +117,7 @@ function IOBuffer(; append=flags.append, truncate=flags.truncate, maxsize=maxsize) - buf.data[:] = 0 + fill!(buf.data, 0) return buf end @@ -246,7 +246,7 @@ function truncate(io::GenericIOBuffer, n::Integer) if n > length(io.data) resize!(io.data, n) end - io.data[io.size+1:n] = 0 + io.data[io.size+1:n] .= 0 io.size = n io.ptr = min(io.ptr, n+1) ismarked(io) && io.mark > n && unmark(io) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 7e157ccc9a21f..6b864dfcf2be8 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -662,12 +662,11 @@ function _setindex!(l::IndexStyle, A::AbstractArray, x, I::Union{Real, AbstractA A end -_iterable(v::AbstractArray) = v -_iterable(v) = Iterators.repeated(v) +_iterable(X::AbstractArray, I...) = X @generated function _unsafe_setindex!(::IndexStyle, A::AbstractArray, x, I::Union{Real,AbstractArray}...) N = length(I) quote - x′ = _iterable(unalias(A, x)) + x′ = unalias(A, _iterable(x, I...)) @nexprs $N d->(I_d = unalias(A, I[d])) idxlens = @ncall $N index_lengths I @ncall $N setindex_shape_check x′ (d->idxlens[d]) @@ -1204,19 +1203,26 @@ end end end -@inline function setindex!(B::BitArray, x, - I0::Union{Colon,UnitRange{Int}}, I::Union{Int,UnitRange{Int},Colon}...) - J = to_indices(B, (I0, I...)) - @boundscheck checkbounds(B, J...) - _unsafe_setindex!(B, x, J...) -end @propagate_inbounds function setindex!(B::BitArray, X::AbstractArray, I0::Union{Colon,UnitRange{Int}}, I::Union{Int,UnitRange{Int},Colon}...) _setindex!(IndexStyle(B), B, X, to_indices(B, (I0, I...))...) end -@generated function _unsafe_setindex!(B::BitArray, x, - I0::Union{Slice,UnitRange{Int}}, I::Union{Int,UnitRange{Int},Slice}...) +## fill! contiguous views of BitArrays with a single value +function fill!(V::SubArray{Bool, <:Any, <:BitArray, Tuple{AbstractUnitRange{Int}}}, x) + B = V.parent + I0 = V.indices[1] + l0 = length(I0) + l0 == 0 && return V + fill_chunks!(B.chunks, Bool(x), first(I0), l0) + return V +end + +fill!(V::SubArray{Bool, <:Any, <:BitArray, Tuple{AbstractUnitRange{Int}, Vararg{Union{Int,AbstractUnitRange{Int}}}}}, x) = + _unsafe_fill_indices!(V.parent, x, V.indices...) + +@generated function _unsafe_fill_indices!(B::BitArray, x, + I0::AbstractUnitRange{Int}, I::Union{Int,AbstractUnitRange{Int}}...) N = length(I) quote y = Bool(x) @@ -1469,7 +1475,9 @@ julia> extrema(A, (1,2)) """ function extrema(A::AbstractArray, dims) sz = [size(A)...] - sz[[dims...]] = 1 + for d in dims + sz[d] = 1 + end B = Array{Tuple{eltype(A),eltype(A)}}(undef, sz...) return extrema!(B, A) end diff --git a/stdlib/FileWatching/src/FileWatching.jl b/stdlib/FileWatching/src/FileWatching.jl index d2a9c4edd3724..e2759f7fa29f7 100644 --- a/stdlib/FileWatching/src/FileWatching.jl +++ b/stdlib/FileWatching/src/FileWatching.jl @@ -158,7 +158,7 @@ mutable struct _FDWatcher if fdnum > length(FDWatchers) old_len = length(FDWatchers) resize!(FDWatchers, fdnum) - FDWatchers[(old_len + 1):fdnum] = nothing + FDWatchers[(old_len + 1):fdnum] .= nothing elseif FDWatchers[fdnum] !== nothing this = FDWatchers[fdnum]::_FDWatcher this.refcount = (this.refcount[1] + Int(readable), this.refcount[2] + Int(writable)) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index a83cf1d7b55ac..9e1bfa4ab0454 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -1297,7 +1297,7 @@ function pinv(A::StridedMatrix{T}, tol::Real) where T Sinv = zeros(Stype, length(SVD.S)) index = SVD.S .> tol*maximum(SVD.S) Sinv[index] = one(Stype) ./ SVD.S[index] - Sinv[findall(.!isfinite.(Sinv))] = zero(Stype) + Sinv[findall(.!isfinite.(Sinv))] .= zero(Stype) return SVD.Vt' * (Diagonal(Sinv) * SVD.U') end function pinv(A::StridedMatrix{T}) where T diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 1408ffc04d85d..2e7f0eb437402 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -774,7 +774,7 @@ function ldiv!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasF end ar = abs(A.factors[1]) if ar == 0 - B[1:nA, :] = 0 + B[1:nA, :] .= 0 return B, 0 end rnk = 1 @@ -795,7 +795,7 @@ function ldiv!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasF end C, τ = LAPACK.tzrzf!(A.factors[1:rnk,:]) ldiv!(UpperTriangular(C[1:rnk,1:rnk]),view(lmul!(adjoint(A.Q), view(B, 1:mA, 1:nrhs)), 1:rnk, 1:nrhs)) - B[rnk+1:end,:] = zero(T) + B[rnk+1:end,:] .= zero(T) LAPACK.ormrz!('L', eltype(B)<:Complex ? 'C' : 'T', C, τ, view(B,1:nA,1:nrhs)) B[1:nA,:] = view(B, 1:nA, :)[invperm(A.p),:] return B, rnk @@ -832,7 +832,7 @@ function ldiv!(A::QR{T}, B::StridedMatrix{T}) where T end LinearAlgebra.ldiv!(UpperTriangular(view(R, :, 1:minmn)), view(B, 1:minmn, :)) if n > m # Apply elementary transformation to solution - B[m + 1:mB,1:nB] = zero(T) + B[m + 1:mB,1:nB] .= zero(T) for j = 1:nB for k = 1:m vBj = B[k,j] diff --git a/stdlib/LinearAlgebra/src/uniformscaling.jl b/stdlib/LinearAlgebra/src/uniformscaling.jl index 6c04450da0b07..9cfed3941c575 100644 --- a/stdlib/LinearAlgebra/src/uniformscaling.jl +++ b/stdlib/LinearAlgebra/src/uniformscaling.jl @@ -378,7 +378,14 @@ chol(J::UniformScaling, args...) = ((C, info) = _chol!(J, nothing); @assertposde ## Matrix construction from UniformScaling -Matrix{T}(s::UniformScaling, dims::Dims{2}) where {T} = setindex!(Base.zeros(T, dims), T(s.λ), diagind(dims...)) +function Matrix{T}(s::UniformScaling, dims::Dims{2}) where {T} + A = zeros(T, dims) + v = T(s.λ) + for i in diagind(dims...) + @inbounds A[i] = v + end + return A +end Matrix{T}(s::UniformScaling, m::Integer, n::Integer) where {T} = Matrix{T}(s, Dims((m, n))) Matrix(s::UniformScaling, m::Integer, n::Integer) = Matrix(s, Dims((m, n))) Matrix(s::UniformScaling, dims::Dims{2}) = Matrix{eltype(s)}(s, dims) diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index b9e094d2801f0..9bbd914047462 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -340,7 +340,7 @@ end dim=2 S=zeros(Complex,dim,dim) T=zeros(Complex,dim,dim) - T[:] = 1 + fill!(T, 1) z = 2.5 + 1.5im S[1] = z @test S*T == [z z; 0 0] diff --git a/stdlib/Pkg3/src/GraphType.jl b/stdlib/Pkg3/src/GraphType.jl index c207f0cad1935..35bb07f8eecdc 100644 --- a/stdlib/Pkg3/src/GraphType.jl +++ b/stdlib/Pkg3/src/GraphType.jl @@ -1266,7 +1266,7 @@ function build_eq_classes_soft1!(graph::Graph, p0::Int) # disable the other versions by introducing additional constraints fill!(gconstr0, false) - gconstr0[repr_vers] = true + gconstr0[repr_vers] .= true return end diff --git a/stdlib/SHA/src/sha3.jl b/stdlib/SHA/src/sha3.jl index 89e15e7403c2f..38bc547f7208e 100644 --- a/stdlib/SHA/src/sha3.jl +++ b/stdlib/SHA/src/sha3.jl @@ -61,7 +61,7 @@ function digest!(context::T) where {T<:SHA3_CTX} # Begin padding with a 0x06 context.buffer[usedspace+1] = 0x06 # Fill with zeros up until the last byte - context.buffer[usedspace+2:end-1] = 0x00 + context.buffer[usedspace+2:end-1] .= 0x00 # Finish it off with a 0x80 context.buffer[end] = 0x80 else diff --git a/stdlib/SharedArrays/test/runtests.jl b/stdlib/SharedArrays/test/runtests.jl index f71494f7945ed..d26e84bdfbcbc 100644 --- a/stdlib/SharedArrays/test/runtests.jl +++ b/stdlib/SharedArrays/test/runtests.jl @@ -34,7 +34,7 @@ function check_pids_all(S::SharedArray) parentindices(D.loc_subarr_1d)[1] end @test all(sdata(S)[idxes_in_p] .== p) - pidtested[idxes_in_p] = true + pidtested[idxes_in_p] .= true end @test all(pidtested) end @@ -124,7 +124,7 @@ finalize(S) # Creating a new file fn2 = tempname() -S = SharedArray{Int,2}(fn2, sz, init=D->D[localindices(D)] = myid()) +S = SharedArray{Int,2}(fn2, sz, init=D->(for i in localindices(D); D[i] = myid(); end)) @test S == filedata filedata2 = similar(Atrue) read!(fn2, filedata2) @@ -134,7 +134,7 @@ finalize(S) # Appending to a file fn3 = tempname() write(fn3, fill(0x1, 4)) -S = SharedArray{UInt8}(fn3, sz, 4, mode="a+", init=D->D[localindices(D)]=0x02) +S = SharedArray{UInt8}(fn3, sz, 4, mode="a+", init=D->(for i in localindices(D); D[i] = 0x02; end)) len = prod(sz)+4 @test filesize(fn3) == len filedata = Vector{UInt8}(undef, len) @@ -190,25 +190,25 @@ s = copy(sdata(d)) ds = deepcopy(d) @test ds == d pids_d = procs(d) -remotecall_fetch(setindex!, pids_d[findfirst(id->(id != myid()), pids_d)::Int], d, 1.0, 1:10) +@everywhere bcast_setindex!(S, v, I) = (for i in I; S[i] = v; end; S) +remotecall_fetch(bcast_setindex!, pids_d[findfirst(id->(id != myid()), pids_d)::Int], d, 1.0, 1:10) @test ds != d @test s != d copyto!(d, s) -@everywhere setid!(A) = A[localindices(A)] = myid() +@everywhere setid!(A) = (for i in localindices(A); A[i] = myid(); end; A) @everywhere procs(ds) setid!($ds) @test d == s @test ds != s @test first(ds) == first(procs(ds)) @test last(ds) == last(procs(ds)) - # SharedArray as an array # Since the data in d will depend on the nprocs, just test that these operations work a = d[1:5] @test_throws BoundsError d[-1:5] a = d[1,1,1:3:end] -d[2:4] = 7 -d[5,1:2:4,8] = 19 +d[2:4] .= 7 +d[5,1:2:4,8] .= 19 AA = rand(4,2) A = @inferred(convert(SharedArray, AA)) diff --git a/stdlib/SparseArrays/src/deprecated.jl b/stdlib/SparseArrays/src/deprecated.jl index 7c1aab2046e6f..8f372098d86b0 100644 --- a/stdlib/SparseArrays/src/deprecated.jl +++ b/stdlib/SparseArrays/src/deprecated.jl @@ -222,6 +222,15 @@ end import Base: asyncmap @deprecate asyncmap(f, s::AbstractSparseArray...; kwargs...) sparse(asyncmap(f, map(Array, s)...; kwargs...)) +# PR 26347: implicit scalar broadcasting within setindex! +@deprecate setindex!(A::SparseMatrixCSC, x::Number, i::Integer, J::AbstractVector{<:Integer}) (A[i, J] .= x; A) +@deprecate setindex!(A::SparseMatrixCSC, x::Number, I::AbstractVector{<:Integer}, j::Integer) (A[I, j] .= x; A) +@deprecate setindex!(A::SparseMatrixCSC, x, ::Colon) fill!(A, x) +@deprecate setindex!(A::SparseMatrixCSC, x, ::Colon, ::Colon) fill!(A, x) +@deprecate setindex!(A::SparseMatrixCSC, x, ::Colon, j::Union{Integer, AbstractVector}) (A[:, j] .= x; A) +@deprecate setindex!(A::SparseMatrixCSC, x, i::Union{Integer, AbstractVector}, ::Colon) (A[i, :] .= x; A) +@deprecate setindex!(A::SparseMatrixCSC, x::Number, I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) (A[I, J] .= x; A) + #25395 keywords unlocked @deprecate dropzeros(x, trim) dropzeros(x, trim = trim) @deprecate dropzeros!(x, trim) dropzeros!(x, trim = trim) diff --git a/stdlib/SparseArrays/src/higherorderfns.jl b/stdlib/SparseArrays/src/higherorderfns.jl index 3ee447c8a2c54..a6509299d86e1 100644 --- a/stdlib/SparseArrays/src/higherorderfns.jl +++ b/stdlib/SparseArrays/src/higherorderfns.jl @@ -522,11 +522,16 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV end # Cases with vertical expansion else # numrows(A) != numrows(C) (=> numrows(A) == 1) + svA, svC = storedvals(A), storedvals(C) @inbounds for (j, jo) in zip(columns(C), _densecoloffsets(C)) Ak, stopAk = numcols(A) == 1 ? (colstartind(A, 1), colboundind(A, 1)) : (colstartind(A, j), colboundind(A, j)) - Ax = Ak < stopAk ? storedvals(A)[Ak] : zero(eltype(A)) + Ax = Ak < stopAk ? svA[Ak] : zero(eltype(A)) fofAx = f(Ax) - fofAx != fillvalue && (storedvals(C)[(jo + 1):(jo + numrows(C))] = fofAx) + if fofAx != fillvalue + for i in (jo + 1):(jo + numrows(C)) + svC[i] = fofAx + end + end end end return C diff --git a/stdlib/SparseArrays/src/linalg.jl b/stdlib/SparseArrays/src/linalg.jl index 052a777445696..c304d3c3821fa 100644 --- a/stdlib/SparseArrays/src/linalg.jl +++ b/stdlib/SparseArrays/src/linalg.jl @@ -618,7 +618,7 @@ function normestinv(A::SparseMatrixCSC{T}, t::Integer = min(2,maximum(size(A)))) # Generate the block matrix X = Matrix{Ti}(undef, n, t) - X[1:n,1] = 1 + X[1:n,1] .= 1 for j = 2:t while true _rand_pm1!(view(X,1:n,j)) diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index 134897631050c..441c26bb6a20a 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -969,7 +969,7 @@ end function _ispermutationvalid_permute!(perm::AbstractVector{<:Integer}, checkspace::Vector{<:Integer}) n = length(perm) - checkspace[1:n] = 0 + checkspace[1:n] .= 0 for k in perm (0 < k ≤ n) && ((checkspace[k] ⊻= 1) == 1) || return false end @@ -2326,10 +2326,10 @@ getindex(A::SparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{Boo getindex(A::SparseMatrixCSC, I::AbstractVector{Bool}, J::AbstractVector{<:Integer}) = A[findall(I),J] ## setindex! -function setindex!(A::SparseMatrixCSC{Tv,Ti}, v, i::Integer, j::Integer) where Tv where Ti - setindex!(A, convert(Tv, v), convert(Ti, i), convert(Ti, j)) -end -function setindex!(A::SparseMatrixCSC{Tv,Ti}, v::Tv, i::Ti, j::Ti) where Tv where Ti<:Integer +function setindex!(A::SparseMatrixCSC{Tv,Ti}, _v, _i::Integer, _j::Integer) where Tv where Ti + v = convert(Tv, _v) + i = convert(Ti, _i) + j = convert(Ti, _j) if !((1 <= i <= A.m) & (1 <= j <= A.n)) throw(BoundsError(A, (i,j))) end @@ -2353,20 +2353,14 @@ function setindex!(A::SparseMatrixCSC{Tv,Ti}, v::Tv, i::Ti, j::Ti) where Tv wher return A end -setindex!(A::SparseMatrixCSC, v::AbstractMatrix, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, v, [i], J) -setindex!(A::SparseMatrixCSC, v::AbstractMatrix, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, v, I, [j]) - -setindex!(A::SparseMatrixCSC, x::Number, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, x, [i], J) -setindex!(A::SparseMatrixCSC, x::Number, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, x, I, [j]) +setindex!(A::SparseMatrixCSC, x::AbstractArray, ::Colon) = setindex!(A, x, 1:length(A)) +setindex!(A::SparseMatrixCSC, x::AbstractArray, ::Colon, ::Colon) = setindex!(A, x, 1:size(A, 1), 1:size(A,2)) +setindex!(A::SparseMatrixCSC, x::AbstractArray, ::Colon, j::Union{Integer, AbstractVector}) = setindex!(A, x, 1:size(A, 1), j) +setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Union{Integer, AbstractVector}, ::Colon) = setindex!(A, x, i, 1:size(A, 2)) -# Colon translation -setindex!(A::SparseMatrixCSC, x, ::Colon) = setindex!(A, x, 1:length(A)) -setindex!(A::SparseMatrixCSC, x, ::Colon, ::Colon) = setindex!(A, x, 1:size(A, 1), 1:size(A,2)) -setindex!(A::SparseMatrixCSC, x, ::Colon, j::Union{Integer, AbstractVector}) = setindex!(A, x, 1:size(A, 1), j) -setindex!(A::SparseMatrixCSC, x, i::Union{Integer, AbstractVector}, ::Colon) = setindex!(A, x, i, 1:size(A, 2)) - -function setindex!(A::SparseMatrixCSC{Tv}, x::Number, - I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) where Tv +function Base.fill!(V::SubArray{Tv, <:Any, <:SparseMatrixCSC, Tuple{Vararg{Union{Integer, AbstractVector{<:Integer}},2}}}, x) where Tv + A = V.parent + I, J = V.indices if isempty(I) || isempty(J); return A; end # lt=≤ to check for strict sorting if !issorted(I, lt=≤); I = sort!(unique(I)); end @@ -2385,7 +2379,7 @@ Helper method for immediately preceding setindex! method. For all (i,j) such tha j in J, assigns zero to A[i,j] if A[i,j] is a presently-stored entry, and otherwise does nothing. """ function _spsetz_setindex!(A::SparseMatrixCSC, - I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) + I::Union{Integer, AbstractVector{<:Integer}}, J::Union{Integer, AbstractVector{<:Integer}}) lengthI = length(I) for j in J coljAfirstk = A.colptr[j] @@ -2421,7 +2415,7 @@ and j in J, assigns x to A[i,j] if A[i,j] is a presently-stored entry, and alloc assigns x to A[i,j] if A[i,j] is not presently stored. """ function _spsetnz_setindex!(A::SparseMatrixCSC{Tv}, x::Tv, - I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) where Tv + I::Union{Integer, AbstractVector{<:Integer}}, J::Union{Integer, AbstractVector{<:Integer}}) where Tv m, n = size(A) lenI = length(I) @@ -2526,16 +2520,18 @@ function _spsetnz_setindex!(A::SparseMatrixCSC{Tv}, x::Tv, return A end -setindex!(A::SparseMatrixCSC{Tv,Ti}, S::Matrix, I::AbstractVector{T}, J::AbstractVector{T}) where {Tv,Ti,T<:Integer} = - setindex!(A, convert(SparseMatrixCSC{Tv,Ti}, S), I, J) +setindex!(A::SparseMatrixCSC{Tv,Ti}, S::Matrix, I::Integer, J::Integer) where {Tv,Ti} = setindex!(A, convert(Tv, S), I, J) +setindex!(A::SparseMatrixCSC{Tv,Ti}, S::Matrix, I::Union{Integer, AbstractVector{<:Integer}}, J::Union{Integer, AbstractVector{<:Integer}}) where {Tv,Ti} = + setindex!(A, convert(SparseMatrixCSC{Tv,Ti}, S), I, J) -setindex!(A::SparseMatrixCSC, v::AbstractVector, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, v, I, [j]) -setindex!(A::SparseMatrixCSC, v::AbstractVector, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, v, [i], J) -setindex!(A::SparseMatrixCSC, v::AbstractVector, I::AbstractVector{T}, J::AbstractVector{T}) where {T<:Integer} = - setindex!(A, reshape(v, length(I), length(J)), I, J) +setindex!(A::SparseMatrixCSC, v::AbstractVector, I::Integer, J::Integer) = setindex!(A, convert(Tv, v), I, J) +setindex!(A::SparseMatrixCSC, v::AbstractVector, I::Union{Integer, AbstractVector{<:Integer}}, J::Union{Integer, AbstractVector{<:Integer}}) = + setindex!(A, reshape(v, length(I), length(J)), I, J) -# A[I,J] = B -function setindex!(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}, I::AbstractVector{T}, J::AbstractVector{T}) where {Tv,Ti,T<:Integer} +# Nonscalar A[I,J] = B +setindex!(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}, I::Integer, J::Integer) where {Tv,Ti} = + setindex!(A, convert(Tv, I, J), I, J) +function setindex!(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}, I::Union{Integer, AbstractVector{<:Integer}}, J::Union{Integer, AbstractVector{<:Integer}}) where {Tv,Ti} if size(B,1) != length(I) || size(B,2) != length(J) throw(DimensionMismatch("")) end @@ -2585,7 +2581,7 @@ function setindex!(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}, I::Abst asgn_col = J[colB] I_asgn = falses(m) - I_asgn[I] = true + I_asgn[I] .= true ptrS = 1 @@ -2674,8 +2670,8 @@ setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{Bool}, J::AbstractVec setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{Bool}) = setindex!(A, Array(x), I, findall(J)) setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{Bool}, J::AbstractVector{<:Integer}) = setindex!(A, Array(x), findall(I), J) -setindex!(A::SparseMatrixCSC, x, I::AbstractVector{Bool}) = throw(BoundsError()) -function setindex!(A::SparseMatrixCSC, x, I::AbstractMatrix{Bool}) +setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractVector{Bool}) = setindex!(A, x, findall(I)) +function setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractMatrix{Bool}) checkbounds(A, I) n = sum(I) (n == 0) && (return A) @@ -2692,7 +2688,7 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractMatrix{Bool}) for row in 1:A.m if I[row, col] - v = isa(x, AbstractArray) ? x[xidx] : x + v = x[xidx] xidx += 1 if r1 <= r2 @@ -2775,7 +2771,7 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractMatrix{Bool}) A end -function setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Real}) +function setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractVector{<:Real}) n = length(I) (n == 0) && (return A) @@ -2800,7 +2796,7 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Real}) (sxidx < n) && (I[sxidx] == I[sxidx+1]) && continue row,col = Base._ind2sub(szA, I[sxidx]) - v = isa(x, AbstractArray) ? x[sxidx] : x + v = x[sxidx] if col > lastcol r1 = Int(colptrA[col]) diff --git a/stdlib/SparseArrays/src/sparsevector.jl b/stdlib/SparseArrays/src/sparsevector.jl index a1d2973d533ed..cb51a09e9725c 100644 --- a/stdlib/SparseArrays/src/sparsevector.jl +++ b/stdlib/SparseArrays/src/sparsevector.jl @@ -1799,7 +1799,7 @@ function _densifyfirstnztoend!(x::SparseVector) nzi = x.nzind[oldpos] nzv = x.nzval[oldpos] newpos = nzi - x.nzind[1] + 1 - newpos < nextpos && (x.nzval[newpos+1:nextpos] = 0) + newpos < nextpos && (x.nzval[newpos+1:nextpos] .= 0) newpos == oldpos && break x.nzval[newpos] = nzv nextpos = newpos - 1 @@ -1821,12 +1821,12 @@ function _densifystarttolastnz!(x::SparseVector) @inbounds for oldpos in oldnnz:-1:1 nzi = x.nzind[oldpos] nzv = x.nzval[oldpos] - nzi < nextpos && (x.nzval[nzi+1:nextpos] = 0) + nzi < nextpos && (x.nzval[nzi+1:nextpos] .= 0) nzi == oldpos && (nextpos = 0; break) x.nzval[nzi] = nzv nextpos = nzi - 1 end - nextpos > 0 && (x.nzval[1:nextpos] = 0) + nextpos > 0 && (x.nzval[1:nextpos] .= 0) # finally update lengthened nzinds x.nzind[1:newnnz] = 1:newnnz x diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index ba896ff3a705c..09d24e711fed8 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -16,7 +16,12 @@ end @testset "iszero specialization for SparseMatrixCSC" begin @test !iszero(sparse(I, 3, 3)) # test failure @test iszero(spzeros(3, 3)) # test success with no stored entries - @test iszero(setindex!(sparse(I, 3, 3), 0, :)) # test success with stored zeros + S = sparse(I, 3, 3) + S[:] .= 0 + @test iszero(S) # test success with stored zeros via broadcasting + S = sparse(I, 3, 3) + fill!(S, 0) + @test iszero(S) # test success with stored zeros via fill! @test iszero(SparseMatrixCSC(2, 2, [1,2,3], [1,2], [0,0,1])) # test success with nonzeros beyond data range end @testset "isone specialization for SparseMatrixCSC" begin @@ -148,8 +153,8 @@ let @testset "sparse assignment" begin p = [4, 1, 3] - a116[p, p] = -1 - s116[p, p] = -1 + a116[p, p] .= -1 + s116[p, p] .= -1 @test a116 == s116 p = [2, 1, 4] @@ -747,10 +752,10 @@ end @testset "setindex" begin a = spzeros(Int, 10, 10) @test count(!iszero, a) == 0 - a[1,:] = 1 + a[1,:] .= 1 @test count(!iszero, a) == 10 @test a[1,:] == sparse(fill(1,10)) - a[:,2] = 2 + a[:,2] .= 2 @test count(!iszero, a) == 19 @test a[:,2] == sparse(fill(2,10)) b = copy(a) @@ -764,20 +769,20 @@ end @test count(!iszero, a) == 18 # Zero-assignment behavior of setindex!(A, v, I, J) - a[1,:] = 0 + a[1,:] .= 0 @test nnz(a) == 19 @test count(!iszero, a) == 9 - a[2,:] = 0 + a[2,:] .= 0 @test nnz(a) == 19 @test count(!iszero, a) == 8 - a[:,1] = 0 + a[:,1] .= 0 @test nnz(a) == 19 @test count(!iszero, a) == 8 - a[:,2] = 0 + a[:,2] .= 0 @test nnz(a) == 19 @test count(!iszero, a) == 0 a = copy(b) - a[:,:] = 0 + a[:,:] .= 0 @test nnz(a) == 19 @test count(!iszero, a) == 0 @@ -806,13 +811,13 @@ end @test a[1,:] == sparse([1; 1; 3:10]) a[1:0,2] = [] @test a[:,2] == sparse([1:10;]) - a[1,1:0] = 0 + a[1,1:0] .= 0 @test a[1,:] == sparse([1; 1; 3:10]) - a[1:0,2] = 0 + a[1:0,2] .= 0 @test a[:,2] == sparse([1:10;]) - a[1,1:0] = 1 + a[1,1:0] .= 1 @test a[1,:] == sparse([1; 1; 3:10]) - a[1:0,2] = 1 + a[1:0,2] .= 1 @test a[:,2] == sparse([1:10;]) @test_throws BoundsError a[:,11] = spzeros(10,1) @@ -820,16 +825,16 @@ end @test_throws BoundsError a[:,-1] = spzeros(10,1) @test_throws BoundsError a[-1,:] = spzeros(1,10) @test_throws BoundsError a[0:9] = spzeros(1,10) - @test_throws BoundsError a[:,11] = 0 - @test_throws BoundsError a[11,:] = 0 - @test_throws BoundsError a[:,-1] = 0 - @test_throws BoundsError a[-1,:] = 0 - @test_throws BoundsError a[0:9] = 0 - @test_throws BoundsError a[:,11] = 1 - @test_throws BoundsError a[11,:] = 1 - @test_throws BoundsError a[:,-1] = 1 - @test_throws BoundsError a[-1,:] = 1 - @test_throws BoundsError a[0:9] = 1 + @test_throws BoundsError (a[:,11] .= 0; a) + @test_throws BoundsError (a[11,:] .= 0; a) + @test_throws BoundsError (a[:,-1] .= 0; a) + @test_throws BoundsError (a[-1,:] .= 0; a) + @test_throws BoundsError (a[0:9] .= 0; a) + @test_throws BoundsError (a[:,11] .= 1; a) + @test_throws BoundsError (a[11,:] .= 1; a) + @test_throws BoundsError (a[:,-1] .= 1; a) + @test_throws BoundsError (a[-1,:] .= 1; a) + @test_throws BoundsError (a[0:9] .= 1; a) @test_throws DimensionMismatch a[1:2,1:2] = 1:3 @test_throws DimensionMismatch a[1:2,1] = 1:3 @@ -837,16 +842,16 @@ end @test_throws DimensionMismatch a[1:2] = 1:3 A = spzeros(Int, 10, 20) - A[1:5,1:10] = 10 - A[1:5,1:10] = 10 + A[1:5,1:10] .= 10 + A[1:5,1:10] .= 10 @test count(!iszero, A) == 50 @test A[1:5,1:10] == fill(10, 5, 10) - A[6:10,11:20] = 0 + A[6:10,11:20] .= 0 @test count(!iszero, A) == 50 - A[6:10,11:20] = 20 + A[6:10,11:20] .= 20 @test count(!iszero, A) == 100 @test A[6:10,11:20] == fill(20, 5, 10) - A[4:8,8:16] = 15 + A[4:8,8:16] .= 15 @test count(!iszero, A) == 121 @test A[4:8,8:16] == fill(15, 5, 9) @@ -857,13 +862,13 @@ end nA = count(!iszero, A) x = A[1:TSZ, 1:(2*TSZ)] nx = count(!iszero, x) - A[1:TSZ, 1:(2*TSZ)] = 0 + A[1:TSZ, 1:(2*TSZ)] .= 0 nB = count(!iszero, A) @test nB == (nA - nx) A[1:TSZ, 1:(2*TSZ)] = x @test count(!iszero, A) == nA @test A == B - A[1:TSZ, 1:(2*TSZ)] = 10 + A[1:TSZ, 1:(2*TSZ)] .= 10 @test count(!iszero, A) == nB + 2*TSZ*TSZ A[1:TSZ, 1:(2*TSZ)] = x @test count(!iszero, A) == nA @@ -902,22 +907,22 @@ end sumS1 = sum(S) sumFI = sum(S[FI]) nnzS1 = nnz(S) - S[FI] = 0 + S[FI] .= 0 sumS2 = sum(S) cnzS2 = count(!iszero, S) @test sum(S[FI]) == 0 @test nnz(S) == nnzS1 @test (sum(S) + sumFI) == sumS1 - S[FI] = 10 + S[FI] .= 10 nnzS3 = nnz(S) @test sum(S) == sumS2 + 10*sum(FI) - S[FI] = 0 + S[FI] .= 0 @test sum(S) == sumS2 @test nnz(S) == nnzS3 @test count(!iszero, S) == cnzS2 - S[FI] = [1:sum(FI);] + S[FI] .= [1:sum(FI);] @test sum(S) == sumS2 + sum(1:sum(FI)) S = sprand(50, 30, 0.5, x -> round.(Int, rand(x) * 100)) @@ -926,9 +931,9 @@ end J = randperm(N) sumS1 = sum(S) sumS2 = sum(S[I]) - S[I] = 0 + S[I] .= 0 @test sum(S) == (sumS1 - sumS2) - S[I] = J + S[I] .= J @test sum(S) == (sumS1 - sumS2 + sum(J)) end end @@ -936,8 +941,8 @@ end @testset "dropstored!" begin A = spzeros(Int, 10, 10) # Introduce nonzeros in row and column two - A[1,:] = 1 - A[:,2] = 2 + A[1,:] .= 1 + A[:,2] .= 2 @test nnz(A) == 19 # Test argument bounds checking for dropstored!(A, i, j) @@ -968,8 +973,8 @@ end SparseArrays.dropstored!(A, :, 2) @test nnz(A) == 0 # --> Introduce nonzeros in rows one and two and columns two and three - A[1:2,:] = 1 - A[:,2:3] = 2 + A[1:2,:] .= 1 + A[:,2:3] .= 2 @test nnz(A) == 36 # --> Test dropping multiple rows containing stored and nonstored entries SparseArrays.dropstored!(A, 1:3, :) @@ -978,7 +983,7 @@ end SparseArrays.dropstored!(A, :, 2:4) @test nnz(A) == 0 # --> Introduce nonzeros in every other row - A[1:2:9, :] = 1 + A[1:2:9, :] .= 1 @test nnz(A) == 50 # --> Test dropping a block of the matrix towards the upper left SparseArrays.dropstored!(A, 2:5, 2:5) @@ -1419,9 +1424,12 @@ end struczerosA = findall(x -> x == 0, A) poszerosinds = unique(rand(struczerosA, targetnumposzeros)) negzerosinds = unique(rand(struczerosA, targetnumnegzeros)) - Aposzeros = setindex!(copy(A), 2, poszerosinds) - Anegzeros = setindex!(copy(A), -2, negzerosinds) - Abothsigns = setindex!(copy(Aposzeros), -2, negzerosinds) + Aposzeros = copy(A) + Aposzeros[poszerosinds] .= 2 + Anegzeros = copy(A) + Anegzeros[negzerosinds] .= -2 + Abothsigns = copy(Aposzeros) + Abothsigns[negzerosinds] .= -2 map!(x -> x == 2 ? 0.0 : x, Aposzeros.nzval, Aposzeros.nzval) map!(x -> x == -2 ? -0.0 : x, Anegzeros.nzval, Anegzeros.nzval) map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, Abothsigns.nzval, Abothsigns.nzval) @@ -1598,21 +1606,21 @@ end @test A1!=A2 nonzeros(A1)[end]=1 @test A1==A2 - A1[1:4,end] = 1 + A1[1:4,end] .= 1 @test A1!=A2 - nonzeros(A1)[end-4:end-1]=0 + nonzeros(A1)[end-4:end-1].=0 @test A1==A2 - A2[1:4,end-1] = 1 + A2[1:4,end-1] .= 1 @test A1!=A2 - nonzeros(A2)[end-5:end-2]=0 + nonzeros(A2)[end-5:end-2].=0 @test A1==A2 - A2[2:3,1] = 1 + A2[2:3,1] .= 1 @test A1!=A2 - nonzeros(A2)[2:3]=0 + nonzeros(A2)[2:3].=0 @test A1==A2 - A1[2:5,1] = 1 + A1[2:5,1] .= 1 @test A1!=A2 - nonzeros(A1)[2:5]=0 + nonzeros(A1)[2:5].=0 @test A1==A2 @test sparse([1,1,0])!=sparse([0,1,1]) end @@ -1946,11 +1954,11 @@ end @testset "setindex issue #20657" begin local A = spzeros(3, 3) I = [1, 1, 1]; J = [1, 1, 1] - A[I, 1] = 1 + A[I, 1] .= 1 @test nnz(A) == 1 - A[1, J] = 1 + A[1, J] .= 1 @test nnz(A) == 1 - A[I, J] = 1 + A[I, J] .= 1 @test nnz(A) == 1 end diff --git a/stdlib/SparseArrays/test/sparsevector.jl b/stdlib/SparseArrays/test/sparsevector.jl index 45f82ae14427f..8ad9273fe6f96 100644 --- a/stdlib/SparseArrays/test/sparsevector.jl +++ b/stdlib/SparseArrays/test/sparsevector.jl @@ -208,7 +208,7 @@ end let x = sprand(10, 10, 0.5) I = rand(1:size(x, 2), 10) bI = falses(size(x, 2)) - bI[I] = true + bI[I] .= true r = x[1,bI] @test isa(r, SparseVector{Float64,Int}) @test all(!iszero, nonzeros(r)) @@ -218,7 +218,7 @@ end let x = sprand(10, 0.5) I = rand(1:length(x), 5) bI = falses(length(x)) - bI[I] = true + bI[I] .= true r = x[bI] @test isa(r, SparseVector{Float64,Int}) @test all(!iszero, nonzeros(r)) @@ -1045,9 +1045,12 @@ end struczerosv = findall(x -> x == 0, v) poszerosinds = unique(rand(struczerosv, targetnumposzeros)) negzerosinds = unique(rand(struczerosv, targetnumnegzeros)) - vposzeros = setindex!(copy(v), 2, poszerosinds) - vnegzeros = setindex!(copy(v), -2, negzerosinds) - vbothsigns = setindex!(copy(vposzeros), -2, negzerosinds) + vposzeros = copy(v) + vposzeros[poszerosinds] .= 2 + vnegzeros = copy(v) + vnegzeros[negzerosinds] .= -2 + vbothsigns = copy(vposzeros) + vbothsigns[negzerosinds] .= -2 map!(x -> x == 2 ? 0.0 : x, vposzeros.nzval, vposzeros.nzval) map!(x -> x == -2 ? -0.0 : x, vnegzeros.nzval, vnegzeros.nzval) map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, vbothsigns.nzval, vbothsigns.nzval) @@ -1067,7 +1070,7 @@ end end # original dropzeros! test xdrop = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7) - xdrop.nzval[[2, 4, 6]] = 0.0 + xdrop.nzval[[2, 4, 6]] .= 0.0 SparseArrays.dropzeros!(xdrop) @test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.])) end diff --git a/stdlib/SuiteSparse/src/spqr.jl b/stdlib/SuiteSparse/src/spqr.jl index edb22812ec643..05467cdc4bef0 100644 --- a/stdlib/SuiteSparse/src/spqr.jl +++ b/stdlib/SuiteSparse/src/spqr.jl @@ -381,7 +381,7 @@ function _ldiv_basic(F::QRSparse, B::StridedVecOrMat) LinearAlgebra.lmul!(adjoint(F.Q), X0) # Zero out to get basic solution - X[rnk + 1:end, :] = 0 + X[rnk + 1:end, :] .= 0 # Solve R*X = B LinearAlgebra.ldiv!(UpperTriangular(view(F.R, Base.OneTo(rnk), Base.OneTo(rnk))), diff --git a/test/arrayops.jl b/test/arrayops.jl index bd20fe6cd35be..2061d100712a7 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -54,13 +54,13 @@ using Random, LinearAlgebra b = copy(a') @test a[1,1] == 1. && a[1,2] == 2. && a[2,1] == 3. && a[2,2] == 4. @test b[1,1] == 1. && b[2,1] == 2. && b[1,2] == 3. && b[2,2] == 4. - a[[1 2 3 4]] = 0 + a[[1 2 3 4]] .= 0 @test a == zeros(2,2) - a[[1 2], [1 2]] = 1 + a[[1 2], [1 2]] .= 1 @test a == fill(1.,2,2) - a[[1 2], 1] = 0 + a[[1 2], 1] .= 0 @test a[1,1] == 0. && a[1,2] == 1. && a[2,1] == 0. && a[2,2] == 1. - a[:, [1 2]] = 2 + a[:, [1 2]] .= 2 @test a == fill(2.,2,2) a = Array{Float64}(undef, 2, 2, 2, 2, 2) @@ -301,7 +301,7 @@ end @test B == [0 0 1 0 0; 11 12 13 14 15; 0 0 3 0 0; 0 0 4 0 0] B[[3,1],[2,4]] = [21 22; 23 24] @test B == [0 23 1 24 0; 11 12 13 14 15; 0 21 3 22 0; 0 0 4 0 0] - B[4,[2,3]] = 7 + B[4,[2,3]] .= 7 @test B == [0 23 1 24 0; 11 12 13 14 15; 0 21 3 22 0; 0 7 7 0 0] @test isequal(reshape(reshape(1:27, 3, 3, 3), Val(2))[1,:], [1, 4, 7, 10, 13, 16, 19, 22, 25]) @@ -916,7 +916,7 @@ end @test_throws BoundsError [1:5;][[true,false,true,false]] @test_throws BoundsError [1:5;][[true,false,true,false,true,false]] a = [1:5;] - a[[true,false,true,false,true]] = 6 + a[[true,false,true,false,true]] .= 6 @test a == [6,2,6,4,6] a[[true,false,true,false,true]] = [7,8,9] @test a == [7,2,8,4,9] @@ -933,7 +933,7 @@ end @test A == [1 1 1 1 1; 2 1 3 4 1; 1 1 1 1 1] @test_throws DimensionMismatch A[[true,false,true], 5] = [19] @test_throws DimensionMismatch A[[true,false,true], 5] = 19:21 - A[[true,false,true], 5] = 7 + A[[true,false,true], 5] .= 7 @test A == [1 1 1 1 7; 2 1 3 4 1; 1 1 1 1 7] B = cat(3, 1, 2, 3) @@ -1050,7 +1050,7 @@ end end a = [1,3,5] b = [1 3] - a[b] = 8 + a[b] .= 8 @test a == [8,3,8] end @@ -1642,7 +1642,7 @@ end @test a[1,CartesianIndex{2}(3,4)] == -2 a[CartesianIndex{1}(2),3,CartesianIndex{1}(3)] = -3 @test a[CartesianIndex{1}(2),3,CartesianIndex{1}(3)] == -3 - a[[CartesianIndex(1,3),CartesianIndex(2,4)],3:3] = -4 + a[[CartesianIndex(1,3),CartesianIndex(2,4)],3:3] .= -4 @test a[1,3,3] == -4 @test a[2,4,3] == -4 end @@ -1983,7 +1983,7 @@ copyto!(S, A) # issue #13250 x13250 = zeros(3) -x13250[UInt(1):UInt(2)] = 1.0 +x13250[UInt(1):UInt(2)] .= 1.0 @test x13250[1] == 1.0 @test x13250[2] == 1.0 @test x13250[3] == 0.0 @@ -2323,7 +2323,7 @@ Float64(x::F21666) = Float64(x.x) # test that cumsum uses more stable algorithm # for types with unknown/rounding arithmetic # we make v pretty large, because stable algorithm may have a large base case - v = zeros(300); v[1] = 2; v[200:end] = eps(Float32) + v = zeros(300); v[1] = 2; v[200:end] .= eps(Float32) f_rounds = Float64.(cumsum(F21666{Base.ArithmeticRounds}.(v))) f_unknown = Float64.(cumsum(F21666{Base.ArithmeticUnknown}.(v))) diff --git a/test/bitarray.jl b/test/bitarray.jl index f88a5d8a02913..6c3ee50c7561b 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -12,6 +12,7 @@ tc(r1,r2) = false bitcheck(b::BitArray) = Test._check_bitarray_consistency(b) bitcheck(x) = true +bcast_setindex!(b, x, I...) = (b[I...] .= x; b) function check_bitop_call(ret_type, func, args...; kwargs...) r1 = func(args...; kwargs...) @@ -156,7 +157,7 @@ timesofar("conversions") b1 = bitrand(v1) @test_throws BoundsError resize!(b1, -1) @check_bit_operation resize!(b1, v1 ÷ 2) BitVector - gr(b) = (resize!(b, v1)[(v1÷2):end] = 1; b) + gr(b) = (resize!(b, v1)[(v1÷2):end] .= 1; b) @check_bit_operation gr(b1) BitVector end @@ -251,39 +252,41 @@ timesofar("constructors") for j in [1, 63, 64, 65, 127, 128, 129, 191, 192, 193, l-1] x = rand(Bool) - @check_bit_operation setindex!(b1, x, 1:j) T + @check_bit_operation fill!(b1, x) T + rand!(b1) + @check_bit_operation bcast_setindex!(b1, x, 1:j) b2 = bitrand(j) for bb in (b2, view(b2, 1:j), view(Array{Any}(b2), :)) @check_bit_operation setindex!(b1, bb, 1:j) T end x = rand(Bool) - @check_bit_operation setindex!(b1, x, j+1:l) T + @check_bit_operation bcast_setindex!(b1, x, j+1:l) T b2 = bitrand(l-j) @check_bit_operation setindex!(b1, b2, j+1:l) T end for j in [1, 63, 64, 65, 127, 128, 129, div(l,2)] m1 = j:(l-j) x = rand(Bool) - @check_bit_operation setindex!(b1, x, m1) T + @check_bit_operation bcast_setindex!(b1, x, m1) T b2 = bitrand(length(m1)) @check_bit_operation setindex!(b1, b2, m1) T end x = rand(Bool) - @check_bit_operation setindex!(b1, x, 1:100) T + @check_bit_operation bcast_setindex!(b1, x, 1:100) T b2 = bitrand(100) @check_bit_operation setindex!(b1, b2, 1:100) T y = rand(0.0:1.0) - @check_bit_operation setindex!(b1, y, 1:100) T + @check_bit_operation bcast_setindex!(b1, y, 1:100) T t1 = findall(bitrand(l)) x = rand(Bool) - @check_bit_operation setindex!(b1, x, t1) T + @check_bit_operation bcast_setindex!(b1, x, t1) T b2 = bitrand(length(t1)) @check_bit_operation setindex!(b1, b2, t1) T y = rand(0.0:1.0) - @check_bit_operation setindex!(b1, y, t1) T + @check_bit_operation bcast_setindex!(b1, y, t1) T end @testset "multidimensional" begin @@ -405,8 +408,16 @@ timesofar("constructors") for (b2, k1, k2) in Channel(gen_setindex_data) # println(typeof(b2), " ", typeof(k1), " ", typeof(k2)) # uncomment to debug - for bb in ((b2 isa AbstractArray) ? (b2, view(b2, :), view(Array{Any}(b2), :)) : (b2,)) - @check_bit_operation setindex!(b1, bb, k1, k2) BitMatrix + if b2 isa AbstractArray + for bb in (b2, view(b2, :), view(Array{Any}(b2), :)) + @check_bit_operation setindex!(b1, bb, k1, k2) BitMatrix + end + else + if k1 isa Integer && k2 isa Integer + @check_bit_operation setindex!(b1, b2, k1, k2) BitMatrix + else + @check_bit_operation bcast_setindex!(b1, b2, k1, k2) BitMatrix + end end end @@ -415,7 +426,7 @@ timesofar("constructors") @check_bit_operation setindex!(b1, b2, m1, 1:m2) BitMatrix x = rand(Bool) b2 = bitrand(1, m2, 1) - @check_bit_operation setindex!(b1, x, m1, 1:m2, 1) BitMatrix + @check_bit_operation bcast_setindex!(b1, x, m1, 1:m2, 1) BitMatrix @check_bit_operation setindex!(b1, b2, m1, 1:m2, 1) BitMatrix b1 = bitrand(s1, s2, s3, s4) @@ -461,7 +472,11 @@ timesofar("constructors") for (b2, k1, k2, k3, k4) in Channel(gen_setindex_data4) # println(typeof(b2), " ", typeof(k1), " ", typeof(k2), " ", typeof(k3), " ", typeof(k4)) # uncomment to debug - @check_bit_operation setindex!(b1, b2, k1, k2, k3, k4) BitArray{4} + if b2 isa Bool + @check_bit_operation bcast_setindex!(b1, b2, k1, k2, k3, k4) BitArray{4} + else + @check_bit_operation setindex!(b1, b2, k1, k2, k3, k4) BitArray{4} + end end for p1 = [rand(1:v1) 1 63 64 65 191 192 193] @@ -489,7 +504,7 @@ timesofar("constructors") b1 = bitrand(n1, n2) t1 = bitrand(n1, n2) - @check_bit_operation setindex!(b1, true, t1) BitMatrix + @check_bit_operation bcast_setindex!(b1, true, t1) BitMatrix t1 = bitrand(n1, n2) b2 = bitrand(count(t1)) diff --git a/test/copy.jl b/test/copy.jl index fd0128c2a661a..80a83ed7b2cab 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -61,7 +61,7 @@ end RA = CartesianIndices(axes(A)) copyto!(B, CartesianIndices((5:7,2:3)), A, RA) @test B[5:7,2:3] == A - B[5:7,2:3] = 0 + B[5:7,2:3] .= 0 @test all(x->x==0, B) end end diff --git a/test/subarray.jl b/test/subarray.jl index 2b5ab06fc36ff..12aa0464ace42 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -354,7 +354,7 @@ sA = view(A, 2:2, 1:5, :) @test size(sA) == (1, 5, 8) @test axes(sA) === (Base.OneTo(1), Base.OneTo(5), Base.OneTo(8)) @test sA[1, 2, 1:8][:] == [5:15:120;] -sA[2:5:end] = -1 +sA[2:5:end] .= -1 @test all(sA[2:5:end] .== -1) @test all(A[5:15:120] .== -1) @test @inferred(strides(sA)) == (1,3,15) @@ -363,10 +363,12 @@ sA[2:5:end] = -1 test_bounds(sA) sA = view(A, 1:3, 1:5, 5) @test Base.parentdims(sA) == [1:2;] -sA[1:3,1:5] = -2 +sA[1:3,1:5] .= -2 @test all(A[:,:,5] .== -2) -sA[:] = -3 +fill!(sA, -3) @test all(A[:,:,5] .== -3) +sA[:] .= 4 +@test all(A[:,:,5] .== 4) @test @inferred(strides(sA)) == (1,3) test_bounds(sA) sA = view(A, 1:3, 3:3, 2:5) @@ -413,7 +415,7 @@ sA = view(A, 2, :, 1:8) @test sA[2, 1:8][:] == [5:15:120;] @test sA[:,1] == [2:3:14;] @test sA[2:5:end] == [5:15:110;] -sA[2:5:end] = -1 +sA[2:5:end] .= -1 @test all(sA[2:5:end] .== -1) @test all(A[5:15:120] .== -1) test_bounds(sA) @@ -441,7 +443,7 @@ A = rand(2, 2, 3) msk = fill(true, 2, 2) msk[2,1] = false sA = view(A, :, :, 1) -sA[msk] = 1.0 +sA[msk] .= 1.0 @test sA[msk] == fill(1, count(msk)) # bounds checking upon construction; see #4044, #10296 @@ -531,7 +533,7 @@ end @test x[1:3] isa SubArray @test x[2] === 11 @test Dict((1:3) => 4)[1:3] === 4 - x[1:2] = 0 + x[1:2] .= 0 @test x == [0,0,19,4] x[1:2] .= 5:6 @test x == [5,6,19,4]