Skip to content

Commit 5b5a602

Browse files
committed
update and add more docs
1 parent b2fd31a commit 5b5a602

File tree

7 files changed

+151
-108
lines changed

7 files changed

+151
-108
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/Manifest.toml
2+
/docs/Manifest.toml

README.md

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,24 @@ fall within these axis ranges. Example:
2323

2424
```julia
2525
using OffsetArrays
26-
A = reshape(1:15, 3, 5)
27-
println("here is A:")
28-
display(A)
29-
OA = OffsetArray(A, -1:1, 0:4) # OA will have axes (-1:1, 0:4)
30-
println("here is OA:")
31-
display(OA)
32-
@show OA[-1,0] OA[1,4]
33-
```
34-
35-
which prints out
36-
37-
```
38-
here is A:
39-
3×5 reshape(::UnitRange{Int64}, 3, 5) with eltype Int64:
40-
1 4 7 10 13
41-
2 5 8 11 14
42-
3 6 9 12 15
43-
here is OA:
44-
OffsetArray(reshape(::UnitRange{Int64}, 3, 5), -1:1, 0:4) with eltype Int64 with indices -1:1×0:4:
45-
1 4 7 10 13
46-
2 5 8 11 14
47-
3 6 9 12 15
48-
OA[-1, 0] = 1
49-
OA[1, 4] = 15
26+
julia> A = Float64.(reshape(1:15, 3, 5))
27+
3×5 Matrix{Float64}:
28+
1.0 4.0 7.0 10.0 13.0
29+
2.0 5.0 8.0 11.0 14.0
30+
3.0 6.0 9.0 12.0 15.0
31+
32+
julia> OA = OffsetArray(A, -1:1, 0:4) # OA will have axes (-1:1, 0:4)
33+
3×5 OffsetArray(::Matrix{Float64}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
34+
1.0 4.0 7.0 10.0 13.0
35+
2.0 5.0 8.0 11.0 14.0
36+
3.0 6.0 9.0 12.0 15.0
37+
38+
julia> OA = OffsetArray(A, CartesianIndex(-1, 0):CartesianIndex(1, 4))
39+
3×5 OffsetArray(::Matrix{Float64}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
40+
[...]
41+
42+
julia> OA[-1,0], OA[1,4]
43+
(1.0, 15.0)
5044
```
5145

5246
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/O/OffsetArrays.svg

docs/Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
34

45
[compat]
5-
Documenter = "0.24"
6+
Documenter = "0.25"

docs/src/index.md

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,66 +16,54 @@ OA = OffsetArray(A, axis1, axis2, ...)
1616
```
1717

1818
where you want `OA` to have axes `(axis1, axis2, ...)` and be indexed by values that
19-
fall within these axis ranges. Example:
19+
fall within these axis ranges.
2020

21-
```julia
21+
```@repl index
2222
using OffsetArrays
23+
2324
A = Float64.(reshape(1:15, 3, 5))
24-
println("Here is A:")
25-
display(A)
26-
OA = OffsetArray(A, -1:1, 0:4) # OA will have axes (-1:1, 0:4)
27-
println("Here is OA:")
28-
display(OA)
29-
@show OA[-1,0] OA[1,4]
25+
26+
OA = OffsetArray(A, -1:1, 0:4) # OA will have axes (-1:1, 0:4)
27+
28+
OA = OffsetArray(A, CartesianIndex(-1, 0):CartesianIndex(1, 4))
29+
30+
OA[-1,0], OA[1,4]
3031
```
3132

32-
gives the output
33+
You could also pass integers as offsets, where `0` means no offsets are applied:
3334

34-
```julia
35-
here is A:
36-
3×5 Array{Float64,2}:
37-
1.0 4.0 7.0 10.0 13.0
38-
2.0 5.0 8.0 11.0 14.0
39-
3.0 6.0 9.0 12.0 15.0
40-
here is OA:
41-
3×5 OffsetArray(::Array{Float64,2}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
42-
1.0 4.0 7.0 10.0 13.0
43-
2.0 5.0 8.0 11.0 14.0
44-
3.0 6.0 9.0 12.0 15.0
45-
OA[-1, 0] = 1.0
46-
OA[1, 4] = 15.0
35+
```@repl index
36+
OA = OffsetArray(A, -2, -1)
4737
```
4838

49-
OffsetArrays works for arbitrary dimensionality:
39+
When you create a new `OffsetArray` on the top of another `OffsetArray`, the offsets are
40+
accumulated:
5041

51-
```julia
52-
julia> using OffsetArrays
42+
```@repl index
43+
OOA = OffsetArray(OA, 2, 1)
44+
```
5345

54-
julia> y = OffsetArray{Float64}(undef, -1:1, -7:7, -128:512, -5:5, -1:1, -3:3, -2:2, -1:1);
46+
For the special cases that you want to compensate the offset back to the ordinary 1-based array, you
47+
can use [`OffsetArrays.no_offset_view(A)`](@ref). Furthermore, you could use
48+
`Base.require_one_based_indexing` if you want to ensure the array does not have offsets.
5549

56-
julia> summary(y)
57-
"OffsetArrays.OffsetArray{Float64,8,Array{Float64,8}} with indices -1:1×-7:7×-128:512×-5:5×-1:1×-3:3×-2:2×-1:1"
50+
```@repl index
51+
OffsetArrays.no_offset_view(OA)
5852
59-
julia> y[-1,-7,-128,-5,-1,-3,-2,-1] = 14
60-
14
53+
Base.require_one_based_indexing(ans)
6154
62-
julia> y[-1,-7,-128,-5,-1,-3,-2,-1] += 5
63-
19.0
55+
Base.require_one_based_indexing(OA)
6456
```
6557

66-
You can use `OffsetArrays.no_offset_view(A)` if you want to return a view of the data in `A` but where indexing starts at 1.
67-
6858
## Example: Relativistic Notation
6959

7060
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
7161

72-
```jldoctest
73-
julia> using OffsetArrays
74-
62+
```jldoctest; setup = :(using OffsetArrays)
7563
julia> r = [:x, :y, :z];
7664
7765
julia> x = OffsetVector([:t, r...], 0:3)
78-
4-element OffsetArray(::Array{Symbol,1}, 0:3) with eltype Symbol with indices 0:3:
66+
4-element OffsetArray(::Vector{Symbol}, 0:3) with eltype Symbol with indices 0:3:
7967
:t
8068
:x
8169
:y
@@ -85,7 +73,7 @@ julia> x[0]
8573
:t
8674
8775
julia> x[1:3]
88-
3-element Array{Symbol,1}:
76+
3-element Vector{Symbol}:
8977
:x
9078
:y
9179
:z
@@ -94,17 +82,17 @@ julia> x[1:3]
9482
## Example: Polynomials
9583

9684
Suppose one wants to represent the Laurent polynomial
97-
```
85+
86+
```math
9887
6/x + 5 - 2*x + 3*x^2 + x^3
9988
```
100-
in julia. The coefficients of this polynomial are a naturally `-1` based list, since the `n`th element of the list
101-
(counting from `-1`) `6, 5, -2, 3, 1` is the coefficient corresponding to the `n`th power of `x`. This Laurent polynomial can be evaluated at say `x = 2` as follows.
10289

103-
```jldoctest
104-
julia> using OffsetArrays
90+
The coefficients of this polynomial are a naturally `-1` based list, since the `n`th element of the list
91+
(counting from `-1`) `6, 5, -2, 3, 1` is the coefficient corresponding to the `n`th power of `x`. This Laurent polynomial can be evaluated at say `x = 2` as follows.
10592

93+
```jldoctest; setup = :(using OffsetArrays)
10694
julia> coeffs = OffsetVector([6, 5, -2, 3, 1], -1:3)
107-
5-element OffsetArray(::Array{Int64,1}, -1:3) with eltype Int64 with indices -1:3:
95+
5-element OffsetArray(::Vector{Int64}, -1:3) with eltype Int64 with indices -1:3:
10896
6
10997
5
11098
-2

docs/src/internals.md

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The majority of cases can be handled with these tips:
77
- replace `1:length(A)` with `eachindex(A)`, or if you need an integer index with `LinearIndices(A)`
88
- replace explicit allocations like `Array{Int}(undef, size(B))` with `similar(Array{Int}, axes(B))`
99

10-
More information can be found in [Julia's developer documentation](https://docs.julialang.org/en/v1.0/devdocs/offset-arrays/).
10+
More information can be found in [Julia's developer documentation](https://docs.julialang.org/en/v1/devdocs/offset-arrays/).
1111
The most subtle issues tend to arise around the axes, and further detail specific to
1212
OffsetArrays.jl follows below.
1313

@@ -19,12 +19,12 @@ with an index offset:
1919

2020
```jldoctest oa; setup=:(using OffsetArrays)
2121
julia> oa = OffsetArray([1 2; 3 4], 0:1, 5:6)
22-
2×2 OffsetArray(::Array{Int64,2}, 0:1, 5:6) with eltype Int64 with indices 0:1×5:6:
22+
2×2 OffsetArray(::Matrix{Int64}, 0:1, 5:6) with eltype Int64 with indices 0:1×5:6:
2323
1 2
2424
3 4
2525
2626
julia> parent(oa)
27-
2×2 Array{Int64,2}:
27+
2×2 Matrix{Int64}:
2828
1 2
2929
3 4
3030
@@ -39,61 +39,48 @@ indexes and then returns the value in the parent.
3939

4040
## The axes of OffsetArrays
4141

42-
```jldoctest oa
43-
julia> axes(oa)
44-
(0:1, 5:6)
45-
```
46-
47-
This looks straightforward, but if you dive deeper you'll notice some complexities:
42+
The internal of offset computing is achieved by [`IdOffsetRange`](@ref OffsetArrays.IdOffsetRange)
43+
type:
4844

4945
```jldoctest oa
5046
julia> ax = axes(oa, 2)
51-
5:6
52-
53-
julia> typeof(ax)
54-
OffsetArrays.IdOffsetRange{Int64,Base.OneTo{Int64}}
47+
OffsetArrays.IdOffsetRange(5:6)
48+
```
5549

56-
julia> ax[1]
57-
ERROR: BoundsError: attempt to access 2-element Base.OneTo{Int64} at index [-3]
58-
Stacktrace:
59-
[1] throw_boundserror(::Base.OneTo{Int64}, ::Int64) at ./abstractarray.jl:538
60-
[2] getindex at ./range.jl:625 [inlined]
61-
[3] getindex(::OffsetArrays.IdOffsetRange{Int64,Base.OneTo{Int64}}, ::Int64) at /home/tim/.julia/dev/OffsetArrays/src/axes.jl:139
62-
[4] top-level scope at none:0
50+
This has a similar design to `Base.IdentityUnitRange` that `ax[x] == x` always holds.
6351

52+
```jldoctest oa
6453
julia> ax[5]
6554
5
55+
julia> ax[1]
56+
ERROR: BoundsError: attempt to access 2-element Base.OneTo{Int64} at index [-3]
57+
[...]
6658
```
6759

68-
The axes are of type [`OffsetArrays.IdOffsetRange`](@ref).
69-
`IdOffsetRange`s are essentially OffsetArrays specialized for ranges, with the additional
70-
property that they tend to be their own axes:
60+
This property makes sure that they tend to be their own axes:
7161

7262
```jldoctest oa
73-
julia> ax
74-
5:6
75-
7663
julia> axes(ax)
77-
(5:6,)
64+
(OffsetArrays.IdOffsetRange(5:6),)
7865
7966
julia> axes(ax[ax])
80-
(5:6,)
67+
(OffsetArrays.IdOffsetRange(5:6),)
8168
```
8269

8370
This example of indexing is [idempotent](https://en.wikipedia.org/wiki/Idempotence).
8471
This is a useful characteristic for ensuring the "fundamental axiom" of generalized indexing,
85-
that `a[rng][i] == a[rng[i]]`:
72+
that `a[ax][i] == a[ax[i]]`:
8673

8774
```jldoctest; setup=:(using OffsetArrays)
8875
julia> oa2 = OffsetArray([5, 10, 15, 20], 0:3)
89-
4-element OffsetArray(::Array{Int64,1}, 0:3) with eltype Int64 with indices 0:3:
76+
4-element OffsetArray(::Vector{Int64}, 0:3) with eltype Int64 with indices 0:3:
9077
5
9178
10
9279
15
9380
20
9481
9582
julia> ax2 = axes(oa2, 1)
96-
0:3
83+
OffsetArrays.IdOffsetRange(0:3)
9784
9885
julia> oa2[2]
9986
15
@@ -116,3 +103,43 @@ julia> oa2[ax2[2]]
116103
- conversion will succeed only if it can preserve both the values and the axes (Examples: `convert(RangeType, rng)`, `oftype(rng1, rng2)`)
117104

118105
While these behave equivalently now (conversion currently performs coercion), developers are encouraged to "future-proof" their code by choosing the behavior appropriate for each usage.
106+
107+
## Caveats
108+
109+
Because `IdOffsetRange` behaves quite differently to the normal `UnitRange` type, there are some
110+
cases that you should be aware of, especially when you are working with multi-dimensional arrays.
111+
112+
One such cases is `getindex`:
113+
114+
```jldoctest getindex; setup = :(using OffsetArrays)
115+
julia> Ao = zeros(-3:3, -3:3); Ao[:] .= 1:49;
116+
117+
julia> Ao[-3:0, :] |> axes # the first dimension does not preserve offsets
118+
(OffsetArrays.IdOffsetRange(1:4), OffsetArrays.IdOffsetRange(-3:3))
119+
120+
julia> Ao[-3:0, -3:3] |> axes # neither dimensions preserve offsets
121+
(Base.OneTo(4), Base.OneTo(7))
122+
123+
julia> Ao[axes(Ao)...] |> axes # offsets are preserved
124+
(OffsetArrays.IdOffsetRange(-3:3), OffsetArrays.IdOffsetRange(-3:3))
125+
126+
julia> Ao[:] |> axes # This is linear indexing
127+
(Base.OneTo(49),)
128+
```
129+
130+
Note that if you pass a `UnitRange`, the offsets in corresponding dimension will not be preserved.
131+
This might look weird at first, but since it follows the `a[ax][i] == a[ax[i]]` rule, it is not a
132+
bug.
133+
134+
```jldoctest getindex
135+
julia> I = -3:0; # UnitRange always starts at index 1
136+
137+
julia> Ao[I, 0][1] == Ao[I[1], 0]
138+
true
139+
140+
julia> ax = axes(Ao, 1) # ax starts at index -3
141+
OffsetArrays.IdOffsetRange(-3:3)
142+
143+
julia> Ao[ax, 0][1] == Ao[ax[1], 0]
144+
true
145+
```

src/OffsetArrays.jl

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,47 @@ used the given `indices`, which are checked for compatible size.
6969
7070
# Example
7171
72+
There are two types of `indices`: integers and ranges-like types.
73+
74+
Integers are recognized as offsets, where `0` means no offsets are applied:
75+
7276
```jldoctest; setup=:(using OffsetArrays)
73-
julia> A = OffsetArray(reshape(1:6, 2, 3), 0:1, -1:1)
77+
julia> A = OffsetArray(reshape(1:6, 2, 3), -1, -2)
7478
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
7579
1 3 5
7680
2 4 6
7781
7882
julia> A[0, 1]
7983
5
8084
```
85+
86+
Examples of range-like types are: `Colon()`(aka `:`), `UnitRange`(e.g, `-1:2`), and
87+
`CartesianIndices`.
88+
89+
```jldoctest; setup=:(using OffsetArrays)
90+
julia> OffsetArray(reshape(1:6, 2, 3), 0:1, -1:1)
91+
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
92+
1 3 5
93+
2 4 6
94+
95+
julia> OffsetArray(reshape(1:6, 2, 3), :, -1:1) # : as a placeholder means no offset is applied at this dimension
96+
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 1:2, -1:1) with eltype Int64 with indices 1:2×-1:1:
97+
1 3 5
98+
2 4 6
99+
100+
julia> OffsetArray(reshape(1:6, 2, 3), CartesianIndex(0, -1):CartesianIndex(1, 1))
101+
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
102+
1 3 5
103+
2 4 6
104+
```
105+
106+
Integers and range-like types can't be used interchangebly:
107+
108+
```julia
109+
julia> OffsetArray(reshape(1:6, 2, 3), 0, -1:1)
110+
ERROR: [...]
111+
```
112+
81113
"""
82114
function OffsetArray(A::AbstractArray{T,N}, inds::NTuple{N,AbstractUnitRange}) where {T,N}
83115
axparent = axes(A)
@@ -347,15 +379,15 @@ specific to remove a level of indirection when applicable.
347379
julia> A = [1 3 5; 2 4 6];
348380
349381
julia> O = OffsetArray(A, 0:1, -1:1)
350-
2×3 OffsetArray(::Array{Int64,2}, 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
382+
2×3 OffsetArray(::Matrix{Int64}, 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
351383
1 3 5
352384
2 4 6
353385
354386
julia> OffsetArrays.no_offset_view(O)[1,1] = -9
355387
-9
356388
357389
julia> A
358-
2×3 Array{Int64,2}:
390+
2×3 Matrix{Int64}:
359391
-9 3 5
360392
2 4 6
361393
```

0 commit comments

Comments
 (0)