Files
julia/base/arraymath.jl
johroj 9aff288d6d
Some checks failed
Whitespace / Check whitespace (push) Has been cancelled
Fix unary plus (#61052)
Solves https://github.com/JuliaLang/julia/issues/61046 by reviving the
behavior for unary `+` since before
https://github.com/JuliaLang/julia/pull/60164/changes was merged.

---------

Co-authored-by: Jishnu Bhattacharya <jishnub.github@gmail.com>
2026-02-20 08:53:36 -05:00

318 lines
7.0 KiB
Julia
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# This file is a part of Julia. License is MIT: https://julialang.org/license
## Binary arithmetic operators ##
function _broadcast_preserving_zero_d(f, A, B)
broadcast_preserving_zero_d(f, A, B)
end
# Using map over broadcast enables vectorization for wide matrices with few rows.
# This is because we use linear indexing in `map` as opposed to Cartesian indexing in broadcasting.
# https://github.com/JuliaLang/julia/issues/47873#issuecomment-1352472461
function _broadcast_preserving_zero_d(f, A::Array{<:Any,N}, B::Array{<:Any,N}, Cs::Array{<:Any,N}...) where {N}
map(f, A, B, Cs...)
end
function _broadcast_preserving_zero_d(f, A::Array, B::Array, Cs::Array...)
# we already know that the shapes are compatible.
# We just need to select the size corresponding to the highest ndims
# and reshape all the arrays to that size
arrays = (A, B, Cs...)
sz = mapreduce(size, (x,y) -> length(x) > length(y) ? x : y, arrays)
# Skip reshaping where possible to avoid the overhead
arrays_sameshape = map(x -> length(sz) == ndims(x) ? x : reshape(x, sz), arrays)
map(f, arrays_sameshape...)
end
function _broadcast_preserving_zero_d(f, A::Array, B::Number)
map(Fix2(f, B), A)
end
function _broadcast_preserving_zero_d(f, A::Number, B::Array)
map(Fix1(f, A), B)
end
for f in (:+, :-)
@eval function ($f)(A::AbstractArray, B::AbstractArray)
promote_shape(A, B) # check size compatibility
_broadcast_preserving_zero_d($f, A, B)
end
end
+(A::Array) = map(+, A)
function +(A::Array, B::Array, Cs::Array...)
promote_shape(A, B)
for C in Cs
promote_shape(A, C) # check size compatibility
end
_broadcast_preserving_zero_d(+, A, B, Cs...)
end
for f in (:/, :\, :*)
if f !== :/
@eval ($f)(A::Number, B::AbstractArray) = _broadcast_preserving_zero_d($f, A, B)
end
if f !== :\
@eval ($f)(A::AbstractArray, B::Number) = _broadcast_preserving_zero_d($f, A, B)
end
end
## data movement ##
"""
reverse(A; dims=:)
Reverse `A` along dimension `dims`, which can be an integer (a
single dimension), a tuple of integers (a tuple of dimensions)
or `:` (reverse along all the dimensions, the default). See
also [`reverse!`](@ref) for in-place reversal.
# Examples
```jldoctest
julia> b = Int64[1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> reverse(b, dims=2)
2×2 Matrix{Int64}:
2 1
4 3
julia> reverse(b)
2×2 Matrix{Int64}:
4 3
2 1
```
!!! compat "Julia 1.6"
Prior to Julia 1.6, only single-integer `dims` are supported in `reverse`.
"""
reverse(A::AbstractArray; dims::D=:) where {D} = _reverse(A, dims)
_reverse(A, dims::D) where {D} = reverse!(copymutable(A); dims)
"""
reverse!(A; dims=:)
Like [`reverse`](@ref), but operates in-place in `A`.
!!! compat "Julia 1.6"
Multidimensional `reverse!` requires Julia 1.6.
"""
reverse!(A::AbstractArray; dims::D=:) where {D} = _reverse!(A, dims)
_reverse!(A::AbstractArray{<:Any,N}, ::Colon) where {N} = _reverse!(A, ntuple(identity, Val{N}()))
_reverse!(A, dim::Integer) = _reverse!(A, (Int(dim),))
_reverse!(A, dims::NTuple{M,Integer}) where {M} = _reverse!(A, Int.(dims))
function _reverse!(A::AbstractArray{<:Any,N}, dims::NTuple{M,Int}) where {N,M}
dims === () && return A # nothing to reverse
dimrev = ntuple(k -> k in dims, Val{N}()) # boolean tuple indicating reversed dims
if N < M || M != sum(dimrev)
throw(ArgumentError("invalid dimensions $dims in reverse!"))
end
# swapping loop only needs to traverse ≈half of the array
halfsz = ntuple(k -> k == dims[1] ? size(A,k) ÷ 2 : size(A,k), Val{N}())
last1 = ntuple(k -> lastindex(A,k)+firstindex(A,k), Val{N}()) # offset for reversed index
for i in CartesianIndices(ntuple(k -> firstindex(A,k):firstindex(A,k)-1+@inbounds(halfsz[k]), Val{N}()))
iₜ = Tuple(i)
iᵣ = CartesianIndex(ifelse.(dimrev, last1 .- iₜ, iₜ))
@inbounds A[iᵣ], A[i] = A[i], A[iᵣ]
end
if M > 1 && isodd(size(A, dims[1]))
# middle slice for odd dimensions must be recursively flipped
mid = firstindex(A, dims[1]) + (size(A, dims[1]) ÷ 2)
midslice = CartesianIndices(ntuple(k -> k == dims[1] ? (mid:mid) : (firstindex(A,k):lastindex(A,k)), Val{N}()))
_reverse!(view(A, midslice), dims[2:end])
end
return A
end
# fix ambiguity with array.jl:
_reverse!(A::AbstractVector, dim::Tuple{Int}) = _reverse!(A, first(dim))
"""
rotl90(A)
Rotate matrix `A` left 90 degrees.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rotl90(a)
2×2 Matrix{Int64}:
2 4
1 3
```
"""
function rotl90(A::AbstractMatrix)
ind1, ind2 = axes(A)
B = similar(A, (ind2,ind1))
n = first(ind2)+last(ind2)
for i=axes(A,1), j=ind2
B[n-j,i] = A[i,j]
end
return B
end
"""
rotr90(A)
Rotate matrix `A` right 90 degrees.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rotr90(a)
2×2 Matrix{Int64}:
3 1
4 2
```
"""
function rotr90(A::AbstractMatrix)
ind1, ind2 = axes(A)
B = similar(A, (ind2,ind1))
m = first(ind1)+last(ind1)
for i=ind1, j=axes(A,2)
B[j,m-i] = A[i,j]
end
return B
end
"""
rot180(A)
Rotate matrix `A` 180 degrees.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rot180(a)
2×2 Matrix{Int64}:
4 3
2 1
```
"""
function rot180(A::AbstractMatrix)
B = similar(A)
ind1, ind2 = axes(A,1), axes(A,2)
m, n = first(ind1)+last(ind1), first(ind2)+last(ind2)
for j=ind2, i=ind1
B[m-i,n-j] = A[i,j]
end
return B
end
"""
rotl90(A, k)
Left-rotate matrix `A` 90 degrees counterclockwise an integer `k` number of times.
If `k` is a multiple of four (including zero), this is equivalent to a `copy`.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rotl90(a,1)
2×2 Matrix{Int64}:
2 4
1 3
julia> rotl90(a,2)
2×2 Matrix{Int64}:
4 3
2 1
julia> rotl90(a,3)
2×2 Matrix{Int64}:
3 1
4 2
julia> rotl90(a,4)
2×2 Matrix{Int64}:
1 2
3 4
```
"""
function rotl90(A::AbstractMatrix, k::Integer)
k = mod(k, 4)
k == 1 ? rotl90(A) :
k == 2 ? rot180(A) :
k == 3 ? rotr90(A) : copy(A)
end
"""
rotr90(A, k)
Right-rotate matrix `A` 90 degrees clockwise an integer `k` number of times.
If `k` is a multiple of four (including zero), this is equivalent to a `copy`.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rotr90(a,1)
2×2 Matrix{Int64}:
3 1
4 2
julia> rotr90(a,2)
2×2 Matrix{Int64}:
4 3
2 1
julia> rotr90(a,3)
2×2 Matrix{Int64}:
2 4
1 3
julia> rotr90(a,4)
2×2 Matrix{Int64}:
1 2
3 4
```
"""
rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k)
"""
rot180(A, k)
Rotate matrix `A` 180 degrees an integer `k` number of times.
If `k` is even, this is equivalent to a `copy`.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> rot180(a,1)
2×2 Matrix{Int64}:
4 3
2 1
julia> rot180(a,2)
2×2 Matrix{Int64}:
1 2
3 4
```
"""
rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A)