Skip to content

Commit eabc5de

Browse files
authored
Merge pull request #29827 from stev47/feature/diff
base: make diff() use views and broadcasting
2 parents 6ec7dd0 + e827fbb commit eabc5de

File tree

3 files changed

+21
-15
lines changed

3 files changed

+21
-15
lines changed

NEWS.md

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Standard library changes
2929
* Channels now convert inserted values (like containers) instead of requiring types to match ([#29092]).
3030
* `range` can accept the stop value as a positional argument, e.g. `range(1,10,step=2)` ([#28708]).
3131
* `edit` can now be called on a module to edit the file that defines it ([#29636]).
32+
* `diff` now supports arrays of arbitrary dimensionality and can operate over any dimension ([#29827]).
3233

3334
Compiler/Runtime improvements
3435
-----------------------------

base/multidimensional.jl

+14-15
Original file line numberDiff line numberDiff line change
@@ -663,17 +663,15 @@ end
663663
end
664664
end
665665

666-
function diff(a::AbstractVector)
667-
@assert !has_offset_axes(a)
668-
[ a[i+1] - a[i] for i=1:length(a)-1 ]
669-
end
666+
diff(a::AbstractVector) = diff(a, dims=1)
670667

671668
"""
672669
diff(A::AbstractVector)
673-
diff(A::AbstractMatrix; dims::Integer)
670+
diff(A::AbstractArray; dims::Integer)
674671
675-
Finite difference operator of matrix or vector `A`. If `A` is a matrix,
676-
specify the dimension over which to operate with the `dims` keyword argument.
672+
Finite difference operator on a vector or a multidimensional array `A`. In the
673+
latter case the dimension to operate on needs to be specified with the `dims`
674+
keyword argument.
677675
678676
# Examples
679677
```jldoctest
@@ -694,14 +692,15 @@ julia> diff(vec(a))
694692
12
695693
```
696694
"""
697-
function diff(A::AbstractMatrix; dims::Integer)
698-
if dims == 1
699-
[A[i+1,j] - A[i,j] for i=1:size(A,1)-1, j=1:size(A,2)]
700-
elseif dims == 2
701-
[A[i,j+1] - A[i,j] for i=1:size(A,1), j=1:size(A,2)-1]
702-
else
703-
throw(ArgumentError("dimension must be 1 or 2, got $dims"))
704-
end
695+
function diff(a::AbstractArray{T,N}; dims::Integer) where {T,N}
696+
has_offset_axes(a) && throw(ArgumentError("offset axes unsupported"))
697+
1 <= dims <= N || throw(ArgumentError("dimension $dims out of range (1:$N)"))
698+
699+
r = axes(a)
700+
r0 = ntuple(i -> i == dims ? UnitRange(1, last(r[i]) - 1) : UnitRange(r[i]), N)
701+
r1 = ntuple(i -> i == dims ? UnitRange(2, last(r[i])) : UnitRange(r[i]), N)
702+
703+
return view(a, r1...) .- view(a, r0...)
705704
end
706705

707706
### from abstractarray.jl

test/arrayops.jl

+6
Original file line numberDiff line numberDiff line change
@@ -2283,6 +2283,9 @@ end
22832283

22842284
@testset "diff" begin
22852285
# test diff, throw ArgumentError for invalid dimension argument
2286+
v = [7, 3, 5, 1, 9]
2287+
@test diff(v) == [-4, 2, -4, 8]
2288+
@test diff(v,dims=1) == [-4, 2, -4, 8]
22862289
X = [3 9 5;
22872290
7 4 2;
22882291
2 1 10]
@@ -2292,6 +2295,9 @@ end
22922295
@test diff(view(X, 1:2, 1:2),dims=2) == reshape([6; -3], (2,1))
22932296
@test diff(view(X, 2:3, 2:3),dims=1) == [-3 8]
22942297
@test diff(view(X, 2:3, 2:3),dims=2) == reshape([-2; 9], (2,1))
2298+
Y = cat([1 3; 4 3], [6 5; 1 4], dims=3)
2299+
@test diff(Y, dims=3) == reshape([5 2; -3 1], (2, 2, 1))
2300+
@test_throws UndefKeywordError diff(X)
22952301
@test_throws ArgumentError diff(X,dims=3)
22962302
@test_throws ArgumentError diff(X,dims=-1)
22972303
end

0 commit comments

Comments
 (0)