Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## ShiftedArrays 0.3 release notes

### Breaking changes

- Removed the `dim` keyword: instead of e.g. `lag(v, 3, dim = 2)` write `lag(v, (0, 3))` (in agreement with `circshift` from Julia Base)
- Changed direction of shifting for `ShiftedArray` and `CircShiftedArray` constructors. For example `CircShiftedArray(v, n)` with a positive `n` shifts to the right (in agreement with `circshift(v, n)` from Julia Base).

## New features

- `CircShiftedArray` type to shift arrays circularly.
- A lazy version of `circshift`: `ShiftedArray.circshift`
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ julia> copy(s)
2 6 10 14
```

If you only need to shift in one dimension, you can use the commodity method:
If you pass an integer, it will shift in the first dimension:

```julia
ShiftedArray(v, n; dim = 1)
julia> ShiftedArray(v, 1)
4×4 ShiftedArrays.ShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
missing missing missing missing
1 5 9 13
2 6 10 14
3 7 11 15
```

## Shifting the data
Expand Down
3 changes: 3 additions & 0 deletions deps/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ if !isfile(joinpath(@__DIR__, "already_showed"))
The shift index convention has changed to be in agreement with Julia's function
`circshift`. Now a positive shift shits to the right, i.e. `ShiftedVector(v, 1)[2] == v[2-1] == v[1]`.
Similarly `copy(CircShiftedVector(v, 1)) == circshift(v, 1)`.
In agreement with the Base function `circshift`, the `dim` keyword argument is no longer
supported. If the shift vector is too short (or if you input an integer) only the first
few dimensions will be shifted.
For more details see https://github.com/piever/ShiftedArrays.jl
""")
touch("already_showed")
Expand Down
32 changes: 6 additions & 26 deletions src/circshift.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"""
circshift(v::AbstractArray, n::Int = 1; dim = 1)
circshift(v::AbstractArray, n)

Return a `ShiftedArray` object, with underlying data `v`, circularly shifted by `n` steps
along dimension `dim`
Return a `CircShiftedArray` object, with underlying data `v`. The second argument gives the amount
to circularly shift in each dimension. If it is an integer, it is assumed to refer to the
first dimension.

# Examples

```jldoctest circshift
julia> v = [1, 3, 5, 4];

julia> ShiftedArrays.circshift(v)
julia> ShiftedArrays.circshift(v, 1)
4-element ShiftedArrays.CircShiftedArray{Int64,1,Array{Int64,1}}:
4
1
Expand All @@ -18,27 +19,6 @@ julia> ShiftedArrays.circshift(v)

julia> w = reshape(1:16, 4, 4);

julia> ShiftedArrays.circshift(w, -1, dim = 2)
4×4 ShiftedArrays.CircShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
5 9 13 1
6 10 14 2
7 11 15 3
8 12 16 4
```
"""
circshift(v::AbstractArray, n::Int = 1; dim = 1) = CircShiftedArray(v, n; dim = dim)

"""
circshift(v::AbstractArray{T, N}, n::NTuple{N, Int}) where {T, N}

Return a `ShiftedArray` object, with underlying data `v`, circularly shifted by `n` steps,
where `n` is a `Tuple` denoting the shift in each dimension.

# Examples

```jldoctest circshift
julia> w = reshape(1:16, 4, 4);

julia> ShiftedArrays.circshift(w, (1, -1))
4×4 ShiftedArrays.CircShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
8 12 16 4
Expand All @@ -47,4 +27,4 @@ julia> ShiftedArrays.circshift(w, (1, -1))
7 11 15 3
```
"""
circshift(v::AbstractArray{T, N}, n::NTuple{N, Int}) where {T, N} = CircShiftedArray(v, n)
circshift(v::AbstractArray, n) = CircShiftedArray(v, n)
34 changes: 5 additions & 29 deletions src/circshiftedarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,11 @@ struct CircShiftedArray{T, N, S<:AbstractArray} <: AbstractArray{T, N}
shifts::NTuple{N, Int64}
end

CircShiftedArray(v::AbstractArray{T, N}, n = Tuple(0 for i in 1:N)) where {T, N} = CircShiftedArray{T, N, typeof(v)}(v, n)
CircShiftedArray(v::AbstractArray{T, N}, n::NTuple{N, Int} = Tuple(0 for i in 1:N)) where {T, N} =
CircShiftedArray{T, N, typeof(v)}(v, n)

"""
CircShiftedArray(parent::AbstractArray, n::Int; dim = 1)

Auxiliary method to create a `CircShiftedArray` shifted of `n` steps on dimension `dim`.

# Examples

```jldoctest circshiftedarray
julia> v = reshape(1:16, 4, 4);

julia> s = CircShiftedArray(v, 2; dim = 1)
4×4 ShiftedArrays.CircShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
3 7 11 15
4 8 12 16
1 5 9 13
2 6 10 14

julia> shifts(s)
(2, 0)
```
"""
function CircShiftedArray(v::AbstractArray{T, N}, n::Int; dim = 1) where {T, N}
tup = Tuple(i == dim ? n : 0 for i in 1:N)
CircShiftedArray(v, tup)
end
CircShiftedArray(v::AbstractArray{T, N}, n) where {T, N} =
CircShiftedArray(v, _padded_tuple(n, N))

"""
CircShiftedVector{T, S<:AbstractArray}
Expand All @@ -65,9 +43,7 @@ Shorthand for `CircShiftedArray{T, 1, S}`.
"""
const CircShiftedVector{T, S<:AbstractArray} = CircShiftedArray{T, 1, S}

CircShiftedVector(v::AbstractVector{T}, n = (0,)) where {T} = CircShiftedArray(v, n)
CircShiftedVector(v::AbstractVector{T}, n::Int; dim = 1) where {T} =
CircShiftedArray(v, n::Int; dim = 1)
CircShiftedVector(v::AbstractVector, n = (0,)) = CircShiftedArray(v, n)

Base.size(s::CircShiftedArray) = Base.size(parent(s))

Expand Down
35 changes: 28 additions & 7 deletions src/lag.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
lag(v::AbstractArray, n = 1; dim = 1)
lag(v::AbstractArray, n = 1)

Return a `ShiftedArray` object, with underlying data `v`, shifted by `n` steps
along dimension `dim`
Return a `ShiftedArray` object, with underlying data `v`. The second argument gives the amount
to shift in each dimension. If it is an integer, it is assumed to refer to the first dimension.

# Examples

Expand Down Expand Up @@ -34,14 +34,26 @@ julia> copy(s)
1
3
5

julia> v = reshape(1:16, 4, 4);

julia> s = lag(v, (0, 2))
4×4 ShiftedArrays.ShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
missing missing 1 5
missing missing 2 6
missing missing 3 7
missing missing 4 8
```
"""
lag(v::AbstractArray, n = 1; dim = 1) = ShiftedArray(v, n; dim = dim)
lag(v::AbstractArray, n = 1) = ShiftedArray(v, n)

"""
lead(v::AbstractArray, n = 1; dim = 1)
lead(v::AbstractArray, n = 1)

Return a `ShiftedArray` object, with underlying data `v`. The second argument gives the amount
to shift negatively in each dimension. If it is an integer, it is assumed to refer
to the first dimension.

Return a `ShiftedArray` object, with underlying data `v`, shifted by `-n` steps.

# Examples

Expand Down Expand Up @@ -73,6 +85,15 @@ julia> copy(s)
9
missing
missing

julia> v = reshape(1:16, 4, 4);

julia> s = lag(v, (0, 2))
4×4 ShiftedArrays.ShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
missing missing 1 5
missing missing 2 6
missing missing 3 7
missing missing 4 8
```
"""
lead(v::AbstractArray, n = 1; dim = 1) = ShiftedArray(v, -n; dim = dim)
lead(v::AbstractArray, n = 1) = ShiftedArray(v, map(-, n))
47 changes: 19 additions & 28 deletions src/shiftedarray.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
_padded_tuple(n, N) = Tuple(i <= length(n) ? n[i] : 0 for i in 1:N)
_padded_tuple(n::Int, N) = _padded_tuple((n,), N)

"""
ShiftedArray(parent::AbstractArray, shifts)

Expand Down Expand Up @@ -34,51 +37,39 @@ julia> copy(s)
1
3
5
```
"""
struct ShiftedArray{T, N, S<:AbstractArray} <: AbstractArray{Union{T, Missing}, N}
parent::S
shifts::NTuple{N, Int64}
end

ShiftedArray(v::AbstractArray{T, N}, n = Tuple(0 for i in 1:N)) where {T, N} = ShiftedArray{T, N, typeof(v)}(v, n)

"""
ShiftedArray(parent::AbstractArray, n::Int; dim = 1)

Auxiliary method to create a `ShiftedArray` shifted of `n` steps on dimension `dim`.

# Examples

```jldoctest shiftedarray
julia> v = reshape(1:16, 4, 4);

julia> s = ShiftedArray(v, 2; dim = 1)
julia> s = ShiftedArray(v, (0, 2))
4×4 ShiftedArrays.ShiftedArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
missing missing missing missing
missing missing missing missing
1 5 9 13
2 6 10 14
missing missing 1 5
missing missing 2 6
missing missing 3 7
missing missing 4 8

julia> shifts(s)
(2, 0)
(0, 2)
```
"""
function ShiftedArray(v::AbstractArray{T, N}, n::Int; dim = 1) where {T, N}
tup = Tuple(i == dim ? n : 0 for i in 1:N)
ShiftedArray(v, tup)
struct ShiftedArray{T, N, S<:AbstractArray} <: AbstractArray{Union{T, Missing}, N}
parent::S
shifts::NTuple{N, Int64}
end

ShiftedArray(v::AbstractArray{T, N}, n::NTuple{N, Int} = Tuple(0 for i in 1:N)) where {T, N} =
ShiftedArray{T, N, typeof(v)}(v, n)

ShiftedArray(v::AbstractArray{T, N}, n) where {T, N} =
ShiftedArray(v, _padded_tuple(n, N))

"""
ShiftedVector{T, S<:AbstractArray}

Shorthand for `ShiftedArray{T, 1, S}`.
"""
const ShiftedVector{T, S<:AbstractArray} = ShiftedArray{T, 1, S}

ShiftedVector(v::AbstractVector{T}, n = (0,)) where {T} = ShiftedArray(v, n)
ShiftedVector(v::AbstractVector{T}, n::Int; dim = 1) where {T} =
ShiftedArray(v, n::Int; dim = 1)
ShiftedVector(v::AbstractVector, n = (0,)) = ShiftedArray(v, n)

Base.size(s::ShiftedArray) = Base.size(parent(s))

Expand Down
32 changes: 14 additions & 18 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ using Compat.Test
@testset "ShiftedVector" begin
v = [1, 3, 5, 4]
sv = ShiftedVector(v, -1)
@test isequal(sv, ShiftedVector(v, -1; dim = 1))
@test isequal(sv, ShiftedVector(v, (-1,)))
@test length(sv) == 4
@test sv[2] == 5
@test all(sv[1:3] .== [3, 5, 4])
@test ismissing(sv[4])
diff = v .- sv
@test diff[1:3] == [-2, -2, 1]
@test ismissing(diff[4])
@test isequal(diff, [-2, -2, 1, missing])
@test shifts(sv) == (-1,)
end

Expand All @@ -23,7 +21,7 @@ end
@test ismissing(sv[3,3])
@test shifts(sv) == (-2,0)
@test isequal(sv, ShiftedArray(v, -2))
@test isequal(ShiftedArray(v, (0, 2)), ShiftedArray(v, 2; dim = 2))
@test isequal(ShiftedArray(v, (2,)), ShiftedArray(v, 2))
s = ShiftedArray(v, (0, -2))
@test isequal(collect(s), [ 9 13 missing missing;
10 14 missing missing;
Expand All @@ -34,18 +32,19 @@ end
@testset "CircShiftedVector" begin
v = [1, 3, 5, 4]
sv = CircShiftedVector(v, -1)
@test isequal(sv, CircShiftedVector(v, -1; dim = 1))
@test isequal(sv, CircShiftedVector(v, (-1,)))
@test length(sv) == 4
@test sv[2] == 5
@test sv[4] == 1
@test all(sv .== [3, 5, 4, 1])
diff = v .- sv
@test diff == [-2, -2, 1, 3]
@test shifts(sv) == (-1,)
sv2 = CircShiftedVector(v, 1)
diff = v .- sv2
@test copy(sv2) == [4, 1, 3, 5]
@test all(CircShiftedVector(v, 1) .== circshift(v,1))
sv[2] = 0
@test collect(sv) == [3, 0, 4, 1]
@test v == [1, 3, 0, 4]
end

@testset "CircShiftedArray" begin
Expand All @@ -55,7 +54,7 @@ end
@test sv[1, 3] == 11
@test shifts(sv) == (-2,0)
@test isequal(sv, CircShiftedArray(v, -2))
@test isequal(CircShiftedArray(v, (0, 2)), CircShiftedArray(v, 2; dim = 2))
@test isequal(CircShiftedArray(v, 2), CircShiftedArray(v, (2,)))
s = CircShiftedArray(v, (0, 2))
@test isequal(collect(s), [ 9 13 1 5;
10 14 2 6;
Expand All @@ -66,26 +65,23 @@ end
@testset "circshift" begin
v = reshape(1:16, 4, 4)
@test all(circshift(v, (1, -1)) .== ShiftedArrays.circshift(v, (1, -1)))
@test all(circshift(v, (0, -1)) .== ShiftedArrays.circshift(v, -1, dim = 2))
@test all(circshift(v, (1,)) .== ShiftedArrays.circshift(v, (1,)))
@test all(circshift(v, 3) .== ShiftedArrays.circshift(v, 3))
end

@testset "laglead" begin
v = [1, 3, 8, 12]
diff = v .- lag(v)
@test diff[2:4] == [2, 5, 4]
@test ismissing(diff[1])
@test isequal(diff, [missing, 2, 5, 4])

diff2 = v .- lag(v, 2)
@test diff2[3:4] == [7, 9]
@test ismissing(diff2[1]) && ismissing(diff2[2])
@test isequal(diff2, [missing, missing, 7, 9])

diff = v .- lead(v)
@test diff[1:3] == [-2, -5, -4]
@test ismissing(diff[4])
@test isequal(diff, [-2, -5, -4, missing])

diff2 = v .- lead(v, 2)
@test diff2[1:2] == [-7, -9]
@test ismissing(diff2[3]) && ismissing(diff2[4])
@test isequal(diff2, [-7, -9, missing, missing])
end

@testset "reduce" begin
Expand Down