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
9 changes: 9 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ Base.require_one_based_indexing(ans)
Base.require_one_based_indexing(OA)
```

[`OffsetArrays.Origin`](@ref) can be convenient if you want to directly specify the origin of the output
OffsetArray, it will automatically compute the needed offsets. For example:

```@repl index
OffsetArray(A, OffsetArrays.Origin(-1, -1))
OffsetArray(OA, OffsetArrays.Origin(-1, -1))
```


## Example: Relativistic Notation

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
Expand Down
1 change: 1 addition & 0 deletions docs/src/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

```@docs
OffsetArray
OffsetArrays.Origin
OffsetArrays.IdOffsetRange
OffsetArrays.no_offset_view
```
24 changes: 23 additions & 1 deletion src/OffsetArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export OffsetArray, OffsetMatrix, OffsetVector

include("axes.jl")
include("utils.jl")
include("origin.jl")

# Technically we know the length of CartesianIndices but we need to convert it first, so here we
# don't put it in OffsetAxisKnownLength.
Expand All @@ -25,7 +26,7 @@ const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
Return an `AbstractArray` that shares element type and size with the first argument, but
used the given `indices`, which are checked for compatible size.

# Example
# Example: offsets

There are two types of `indices`: integers and ranges-like types.

Expand Down Expand Up @@ -68,6 +69,25 @@ julia> OffsetArray(reshape(1:6, 2, 3), 0, -1:1)
ERROR: [...]
```

# Example: origin

[`OffsetArrays.Origin`](@ref) can be used to directly specify the origin of the output OffsetArray.

```jldoctest; setup=:(using OffsetArrays)
julia> a = [1 2; 3 4];

julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
2×2 OffsetArray(::$(Array{Int64,2}), 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
1 2
3 4

julia> OffsetArray(a, OffsetArrays.Origin(0)) # short notation for `Origin(0, ..., 0)`
2×2 OffsetArray(::$(Array{Int64, 2}), 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
1 2
3 4
```


"""
struct OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N}
parent::AA
Expand Down Expand Up @@ -115,6 +135,8 @@ for FT in (:OffsetArray, :OffsetVector, :OffsetMatrix)
$FT(A, indsN)
end
@eval $FT(A::AbstractArray{T}, inds::Vararg{OffsetAxis,N}) where {T, N} = $FT(A, inds)

@eval $FT(A::AbstractArray, origin::Origin) = OffsetArray(A, origin(A))
end

# array initialization
Expand Down
35 changes: 35 additions & 0 deletions src/origin.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Origin(indices...)
Origin(origin::Tuple)
Origin(origin::CartesianIndex)

A helper type to construct OffsetArray with given origin.

The `origin` of an array is defined as the index of its first element, i.e., `first.(axes(A))`.

# Example

```jldoctest; setup=:(using OffsetArrays)
julia> a = [1 2; 3 4];

julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
2×2 OffsetArray(::$(Array{Int64,2}), 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
1 2
3 4

julia> OffsetArray(a, OffsetArrays.Origin(0)) # short notation for `Origin(0, 0)`
2×2 OffsetArray(::$(Array{Int64, 2}), 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
1 2
3 4
```
"""
struct Origin{T<:Union{Tuple, Int}}
index::T
end
Origin(I::NTuple{N, Int}) where N = Origin{typeof(I)}(I)
Origin(I::CartesianIndex) = Origin(I.I)
Origin(I1::Int, In::Int...) = Origin((I1, In...))
# Origin(0) != Origin((0, )) but they work the same with broadcasting
Origin(n::Int) = Origin{Int}(n)

(o::Origin)(A::AbstractArray) = o.index .- first.(axes(A))
30 changes: 30 additions & 0 deletions test/origin.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using OffsetArrays: Origin
@testset "Origin" begin
get_origin(A::AbstractArray) = first.(axes(A))

@test Origin(0) != Origin((0, ))
@test Origin(CartesianIndex(1, 2)) === Origin((1, 2)) === Origin(1, 2)

# 1d
v = [1, 2]
@test get_origin(OffsetArray(v, Origin(2))) == (2, )
ov = OffsetArray(v, -3)
@test get_origin(OffsetArray(ov, Origin(2))) == (2, )
@test get_origin(OffsetVector(ov, Origin(2))) == (2, )
@test get_origin(OffsetArray(ov, Origin((2, )))) == (2, )

# 2d
a = [1 2;3 4]
@test get_origin(OffsetArray(a, Origin(0))) == (0, 0)
oa = OffsetArray(a, -3, -3)
@test get_origin(OffsetArray(oa, Origin(0))) == (0, 0)
@test get_origin(OffsetMatrix(oa, Origin(0))) == (0, 0)
@test get_origin(OffsetArray(oa, Origin(1, 2))) == (1, 2)

# 3d
a = ones(3, 3, 3)
@test get_origin(OffsetArray(a, Origin(0))) == (0, 0, 0)
oa = OffsetArray(a, -3, -3, -3)
@test get_origin(OffsetArray(oa, Origin(0))) == (0, 0, 0)
@test get_origin(OffsetArray(oa, Origin(1, 2, 3))) == (1, 2, 3)
end
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1112,3 +1112,5 @@ end
@test searchsorted(o, 5) == 2:2
@test searchsorted(o, 6) == 3:2
end

include("origin.jl")