Skip to content

Commit c3336c8

Browse files
authored
add Origin to specify the origin of output OffsetArray (#147)
1 parent a78ee17 commit c3336c8

File tree

6 files changed

+100
-1
lines changed

6 files changed

+100
-1
lines changed

docs/src/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ Base.require_one_based_indexing(ans)
5555
Base.require_one_based_indexing(OA)
5656
```
5757

58+
[`OffsetArrays.Origin`](@ref) can be convenient if you want to directly specify the origin of the output
59+
OffsetArray, it will automatically compute the needed offsets. For example:
60+
61+
```@repl index
62+
OffsetArray(A, OffsetArrays.Origin(-1, -1))
63+
OffsetArray(OA, OffsetArrays.Origin(-1, -1))
64+
```
65+
66+
5867
## Example: Relativistic Notation
5968

6069
Suppose we have a position vector `r = [:x, :y, :z]` which is naturally one-based, ie. `r[1] == :x`, `r[2] == :y`, `r[3] == :z` and we also want to construct a relativistic position vector which includes time as the 0th component. This can be done with OffsetArrays like

docs/src/reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
```@docs
44
OffsetArray
5+
OffsetArrays.Origin
56
OffsetArrays.IdOffsetRange
67
OffsetArrays.no_offset_view
78
```

src/OffsetArrays.jl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export OffsetArray, OffsetMatrix, OffsetVector
1111

1212
include("axes.jl")
1313
include("utils.jl")
14+
include("origin.jl")
1415

1516
# Technically we know the length of CartesianIndices but we need to convert it first, so here we
1617
# don't put it in OffsetAxisKnownLength.
@@ -25,7 +26,7 @@ const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
2526
Return an `AbstractArray` that shares element type and size with the first argument, but
2627
used the given `indices`, which are checked for compatible size.
2728
28-
# Example
29+
# Example: offsets
2930
3031
There are two types of `indices`: integers and ranges-like types.
3132
@@ -68,6 +69,25 @@ julia> OffsetArray(reshape(1:6, 2, 3), 0, -1:1)
6869
ERROR: [...]
6970
```
7071
72+
# Example: origin
73+
74+
[`OffsetArrays.Origin`](@ref) can be used to directly specify the origin of the output OffsetArray.
75+
76+
```jldoctest; setup=:(using OffsetArrays)
77+
julia> a = [1 2; 3 4];
78+
79+
julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
80+
2×2 OffsetArray(::$(Array{Int64,2}), 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
81+
1 2
82+
3 4
83+
84+
julia> OffsetArray(a, OffsetArrays.Origin(0)) # short notation for `Origin(0, ..., 0)`
85+
2×2 OffsetArray(::$(Array{Int64, 2}), 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
86+
1 2
87+
3 4
88+
```
89+
90+
7191
"""
7292
struct OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N}
7393
parent::AA
@@ -115,6 +135,8 @@ for FT in (:OffsetArray, :OffsetVector, :OffsetMatrix)
115135
$FT(A, indsN)
116136
end
117137
@eval $FT(A::AbstractArray{T}, inds::Vararg{OffsetAxis,N}) where {T, N} = $FT(A, inds)
138+
139+
@eval $FT(A::AbstractArray, origin::Origin) = OffsetArray(A, origin(A))
118140
end
119141

120142
# array initialization

src/origin.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Origin(indices...)
3+
Origin(origin::Tuple)
4+
Origin(origin::CartesianIndex)
5+
6+
A helper type to construct OffsetArray with given origin.
7+
8+
The `origin` of an array is defined as the index of its first element, i.e., `first.(axes(A))`.
9+
10+
# Example
11+
12+
```jldoctest; setup=:(using OffsetArrays)
13+
julia> a = [1 2; 3 4];
14+
15+
julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
16+
2×2 OffsetArray(::$(Array{Int64,2}), 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
17+
1 2
18+
3 4
19+
20+
julia> OffsetArray(a, OffsetArrays.Origin(0)) # short notation for `Origin(0, 0)`
21+
2×2 OffsetArray(::$(Array{Int64, 2}), 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
22+
1 2
23+
3 4
24+
```
25+
"""
26+
struct Origin{T<:Union{Tuple, Int}}
27+
index::T
28+
end
29+
Origin(I::NTuple{N, Int}) where N = Origin{typeof(I)}(I)
30+
Origin(I::CartesianIndex) = Origin(I.I)
31+
Origin(I1::Int, In::Int...) = Origin((I1, In...))
32+
# Origin(0) != Origin((0, )) but they work the same with broadcasting
33+
Origin(n::Int) = Origin{Int}(n)
34+
35+
(o::Origin)(A::AbstractArray) = o.index .- first.(axes(A))

test/origin.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using OffsetArrays: Origin
2+
@testset "Origin" begin
3+
get_origin(A::AbstractArray) = first.(axes(A))
4+
5+
@test Origin(0) != Origin((0, ))
6+
@test Origin(CartesianIndex(1, 2)) === Origin((1, 2)) === Origin(1, 2)
7+
8+
# 1d
9+
v = [1, 2]
10+
@test get_origin(OffsetArray(v, Origin(2))) == (2, )
11+
ov = OffsetArray(v, -3)
12+
@test get_origin(OffsetArray(ov, Origin(2))) == (2, )
13+
@test get_origin(OffsetVector(ov, Origin(2))) == (2, )
14+
@test get_origin(OffsetArray(ov, Origin((2, )))) == (2, )
15+
16+
# 2d
17+
a = [1 2;3 4]
18+
@test get_origin(OffsetArray(a, Origin(0))) == (0, 0)
19+
oa = OffsetArray(a, -3, -3)
20+
@test get_origin(OffsetArray(oa, Origin(0))) == (0, 0)
21+
@test get_origin(OffsetMatrix(oa, Origin(0))) == (0, 0)
22+
@test get_origin(OffsetArray(oa, Origin(1, 2))) == (1, 2)
23+
24+
# 3d
25+
a = ones(3, 3, 3)
26+
@test get_origin(OffsetArray(a, Origin(0))) == (0, 0, 0)
27+
oa = OffsetArray(a, -3, -3, -3)
28+
@test get_origin(OffsetArray(oa, Origin(0))) == (0, 0, 0)
29+
@test get_origin(OffsetArray(oa, Origin(1, 2, 3))) == (1, 2, 3)
30+
end

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,3 +1112,5 @@ end
11121112
@test searchsorted(o, 5) == 2:2
11131113
@test searchsorted(o, 6) == 3:2
11141114
end
1115+
1116+
include("origin.jl")

0 commit comments

Comments
 (0)