Skip to content

Commit

Permalink
Add rng field to the struct
Browse files Browse the repository at this point in the history
  • Loading branch information
giordano committed May 10, 2020
1 parent 8caafb8 commit 95c1b78
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 68 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ os:
- osx
julia:
- 1.0
- 1.1
- 1.2
- 1
- nightly
matrix:
allow_failures:
Expand Down
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ uuid = "079b6ec6-a4f7-11e9-0358-1904ae85a441"
authors = ["Mosè Giordano"]
version = "0.1.0"

[deps]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[compat]
julia = "1"

[extras]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Random", "Test"]
test = ["Test"]
54 changes: 0 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,60 +18,6 @@ the first index is random, so you don’t have to remember whether Julia uses 0-
or 1-based indexing: you simply cannot ever know what the initial element will
be.

## Motivation

This package takes a new stance in the longstanding debate whether arrays should
have [0-based](https://en.wikipedia.org/wiki/Zero-based_numbering) or 1-based
indexing.

It is incredibly hard to convince people that there is no "one size fits all"
indexing in programming, both alternatives have their merits:

* 0-based indexing is natural every time you deal with offsets, e.g., when
referencing memory addresses
* 1-based indexing is natural when you are counting elements: the 1st element is
"1", the 2nd element is "2", etc...

It is pointless to claim the superiority of one indexing over the other one, as
they’re useful in different situations.

As a matter of fact, many "math-oriented" languages (e.g., Fortran, Julia,
Mathematica, MATLAB, R), that are less likely to fiddle with pointers'
addresses, default to 1-based indexing, even though probably the majority of the
programming languages nowadays uses 0-based indexing.

A good programming language, whatever indexing convention it uses, should
provide an abstraction layer to let users forget which is the initial index.
For example, Fortran has [`lbound`](http://fortranwiki.org/fortran/show/lbound)
to reference the first element of an array. Besides the
[`first`](https://docs.julialang.org/en/v1/base/collections/#Base.first)
function to reference the first element of a collection, the Julia programming
language has different utilities to iterate over collections:

* arrays are iterables, this means that you can write a `for` loop like
```julia
for element in my_array
# do things with the `element`...
end
```
without using indices at all
* [`eachindex`](https://docs.julialang.org/en/v1/base/arrays/#Base.eachindex) is
a function that returns an iterable object with all the indices of the array.

Certainly, some times you need to use the indices of an array and know which is
the first one. In this case, the abstraction layer above is not useful. Thus,
it is important for a programming language to provide also a way to easily
switch to the most appropriate indexing for the task at hand. In Fortran you
can set a different initial index for an array with the
[`dimension`](https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn8a/index.html)
statement. Julia allows you to define custom indices for you new array-like
type, as described in the
[documentation](https://docs.julialang.org/en/v1/devdocs/offset-arrays/). The
most notable application of custom indices is probably the
[`OffsetArrays.jl`](https://github.com/JuliaArrays/OffsetArrays.jl) package.
Other use cases of custom indices are shown in [this blog
post](https://julialang.org/blog/2017/04/offset-arrays).

## Installation

The latest version of `RandomBasedArrays.jl` is available for Julia v1.0 and
Expand Down
27 changes: 17 additions & 10 deletions src/RandomBasedArrays.jl
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
module RandomBasedArrays

using Random

export RandomBasedArray

struct RandomBasedArray{T,N,P<:AbstractArray} <: AbstractArray{T,N}
const _default_rng = if VERSION < v"1.3"
() -> Random.GLOBAL_RNG
else
Random.default_rng
end

struct RandomBasedArray{T,N,P<:AbstractArray,R<:AbstractRNG} <: AbstractArray{T,N}
parent::P
rng::R
end
RandomBasedArray(p::P) where {T,N,P<:AbstractArray{T,N}} =
RandomBasedArray{T,N,P}(p)
RandomBasedArray(p::P, rng::R = _default_rng()) where {T,N,P<:AbstractArray{T,N},R<:AbstractRNG} =
RandomBasedArray{T,N,P,R}(p, rng)

index(p::AbstractArray) = rand(eachindex(p))
index(A::RandomBasedArray) = rand(A.rng, eachindex(parent(A)))

Base.parent(A::RandomBasedArray) = A.parent
Base.size(A::RandomBasedArray) = size(parent(A))
Base.getindex(A::RandomBasedArray, ::Int) =
@inbounds getindex(parent(A), index(parent(A)))
@inbounds getindex(parent(A), index(A))
Base.getindex(A::RandomBasedArray{T,N}, ::Vararg{Int,N}) where {T,N} =
getindex(parent(A), Base._ind2sub(parent(A), index(parent(A)))...)
getindex(parent(A), Base._ind2sub(parent(A), index(A))...)
Base.setindex!(A::RandomBasedArray, v, ::Int) =
@inbounds setindex!(parent(A), v, index(parent(A)))
@inbounds setindex!(parent(A), v, index(A))
Base.setindex!(A::RandomBasedArray{T,N}, v, ::Vararg{Int,N}) where {T,N} =
setindex!(parent(A), v, Base._ind2sub(parent(A), index(parent(A)))...)
# Show a fixed copy of the array, otherwise the alignment algorithm would get
# crazy trying to show a "mutating" array
setindex!(parent(A), v, Base._ind2sub(parent(A), index(A))...)
Base.show(io::IO, m::MIME"text/plain", A::RandomBasedArray) = show(io, m, copy(A))

end # module

0 comments on commit 95c1b78

Please sign in to comment.