Skip to content

Commit

Permalink
Merge pull request #4 from JuliaArrays/v2
Browse files Browse the repository at this point in the history
Total rework
  • Loading branch information
JeffFessler authored Jul 8, 2021
2 parents ace2888 + 4734318 commit 2df7816
Show file tree
Hide file tree
Showing 15 changed files with 432 additions and 15 deletions.
16 changes: 9 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
name: CI
on:
- push
paths-ignore:
- 'docs/**'
- pull_request
paths-ignore:
- 'docs/**'
push:
paths-ignore:
- '*/*.md'
- 'docs/**'
pull_request:
paths-ignore:
- '*/*.md'
- 'docs/**'

jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
Expand All @@ -14,7 +17,6 @@ jobs:
fail-fast: false
matrix:
version:
- '1.5'
- '1'
os:
- ubuntu-latest
Expand Down
2 changes: 0 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ authors = ["Sheehan Olver <[email protected]>", "Jeff Fessler <fessler@umic
version = "0.1.0"

[deps]
LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"

[compat]
LazyArrays = "0.21"
julia = "1.6"
10 changes: 6 additions & 4 deletions src/ndgrid.jl → archive/src/ndgrid-repeat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ lazy and non-lazy versions of ndgrid

using LazyArrays: Applied, ApplyArray

export ndgrid, ndgrid_lazy
export ndgrid_array, ndgrid_lazy

"""
grid = ndgrid_repeat(v::AbstractVector, dims::Dims{D}, d::Int)
Expand All @@ -24,16 +24,18 @@ end


"""
ndgrid(args::AbstractVector...)
ndgrid_array(args::AbstractVector...)
Returns tuple of `length(args)` arrays, each of size `tuple(length.(args)...)`.
This method is provided for convenience and testing,
but `ndgrid` is less efficient than broadcast so should be avoided.
The tuple returned here requires `prod(length.(args)) * length(args)` memory;
using `ndgrid_lazy` is an alternative that uses `O(length(args))` memory.
"""
function ndgrid(args::AbstractVector...)
function ndgrid_array(args::AbstractVector...)
D = length(args)
T = Tuple{ntuple(i -> Array{eltype(args[i]), D}, D)...} # return type
fun = i -> ndgrid_repeat(args[i], length.(args), i)
ntuple(fun, Val(length(args)))
ntuple(fun, D)::T
end


Expand Down
File renamed without changes.
19 changes: 18 additions & 1 deletion src/LazyGrids.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
"""
LazyGrids
Module for representing grids in a lazy way.
"""
module LazyGrids

include("ndgrid.jl")
"""
AbstractGrid{T,d,D} <: AbstractArray{T,D}
Abstract type for representing the `d`th component of
of a `D`-dimensional `ndgrid(x_1, x_2, ...)`
where `1 ≤ d ≤ D` and where `eltype(x_d) = T`.
"""
abstract type AbstractGrid{T,d,D} <: AbstractArray{T,D} end


include("ndgrid-oneto.jl")
include("ndgrid-unitr.jl")
include("ndgrid-range.jl")
include("ndgrid-avect.jl")
include("array.jl")

end # module
30 changes: 30 additions & 0 deletions src/array.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# array.jl

export ndgrid_array


"""
(xg, yg, ...) = ndgrid_array(v1, v2, ...)
Method to construct a tuple of (dense) `Array`s from a set of vectors.
This tuple can use a lot of memory so should be avoided in general!
It is provided mainly for testing and timing comparisons.
Each input should be an `AbstractVector` of some type.
The corresponding output Array will have the same element type.
This method provides similar functionality as Matlab's `ndarray` function
but is more general because the vectors can be any type.
# Examples
```jldoctest
julia> ndgrid_array(1:3, 1:2)
([1 1; 2 2; 3 3], [1 2; 1 2; 1 2])
julia> ndgrid(1:3, [:a,:b])
([1 1; 2 2; 3 3], [:a :b; :a :b; :a :b])
```
"""
ndgrid_array(vs::AbstractVector...) = Array.(ndgrid(vs...))
78 changes: 78 additions & 0 deletions src/ndgrid-avect.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#=
ndgrid-avect.jl
ndgrid for a set of AbstractVector inputs.
=#

export ndgrid

"""
GridAV{T,d,D} <: AbstractGrid{T,d,D}
The `d`th component of `D`-dimensional `ndgrid(x, y, ...)`
where `1 ≤ d ≤ D` and `x, y, ...` are each an `AbstractVector`.
"""
struct GridAV{T,d,D} <: AbstractGrid{T,d,D}
dims::Dims{D}
v::AbstractVector{T}

function GridAV(dims::Dims{D}, v::AbstractVector{T}, d::Int) where {D, T}
1 d D || throw(ArgumentError("$d for $dims"))
new{T,d,D}(dims, v)
end
end

Base.size(a::GridAV) = a.dims
Base.eltype(::GridAV{T}) where T = T

@inline Base.@propagate_inbounds function Base.getindex(
a::GridAV{T,d,D},
i::Vararg{Int,D},
) where {T, d, D}
@boundscheck checkbounds(a, i...)
# @boundscheck checkbounds(i, d)
@boundscheck checkbounds(a.v, i[d])
return @inbounds a.v[ @inbounds i[d] ]
end


_grid(d::Int, dims::Dims, v::Base.OneTo{T}) where T = GridOT(T, dims, d)
_grid(d::Int, dims::Dims, v::UnitRange) = GridUR(dims, v, d)
_grid(d::Int, dims::Dims, v::AbstractRange) = GridAR(dims, v, d)
_grid(d::Int, dims::Dims, v::AbstractVector) = GridAV(dims, v, d)

_grid_type(d::Int, D::Int, ::Base.OneTo{T}) where T = GridOT{T, d, D}
_grid_type(d::Int, D::Int, ::UnitRange{T}) where T = GridUR{T, d, D}
_grid_type(d::Int, D::Int, ::AbstractRange{T}) where T = GridAR{T, d, D}
_grid_type(d::Int, D::Int, ::AbstractVector{T}) where T = GridAV{T, d, D}


"""
(xg, yg, ...) = ndgrid(v1, v2, ...)
Construct `ndgrid` tuple for `AbstractVector` inputs.
Each output has a lazy grid type (subtype of `AbstractGrid`)
according to the corresponding input vector type.
# Examples
```jldoctest
julia> xg, yg = ndgrid(1:3, [:a, :b])
([1 1; 2 2; 3 3], [:a :b; :a :b; :a :b])
julia> xg
3×2 LazyGrids.GridUR{Int64, 1, 2}:
1 1
2 2
3 3
julia> yg
3×2 LazyGrids.GridAV{Symbol, 2, 2}:
:a :b
:a :b
:a :b
```
"""
function ndgrid(vs::Vararg{AbstractVector})
D = length(vs)
dims = ntuple(d -> length(vs[d]), D)
T = Tuple{ntuple(d -> _grid_type(d, D, vs[d]), D)...} # return type
return ntuple(d -> _grid(d, dims, vs[d]), D)::T
end
69 changes: 69 additions & 0 deletions src/ndgrid-oneto.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#=
ndgrid-oneto.jl
ndgrid for a set of "OneTo" ranges: probably the simplest possible ndgrid
=#

export ndgrid

"""
GridOT{T,d,D} <: AbstractArray{T,D}
The `d`th component of `D`-dimensional `ndgrid(1:M, 1:N, ...)`
where `1 ≤ d ≤ D`.
"""
struct GridOT{T,d,D} <: AbstractGrid{T,d,D}
dims::Dims{D}

function GridOT(T::DataType, dims::Dims{D}, d::Int) where D
1 d D || throw(ArgumentError("$d for $dims"))
T <: Integer || throw(ArgumentError("T = $T"))
new{T,d,D}(dims)
end
end

Base.size(a::GridOT) = a.dims
# Base.eltype(::GridOT) = Int # default

@inline Base.@propagate_inbounds function Base.getindex(
a::GridOT{T,d,D},
i::Vararg{Int,D},
) where {T,d,D}
@boundscheck checkbounds(a, i...)
return @inbounds i[d]
end


"""
(xg, yg, ...) = ndgrid(M, N, ...)
Shorthand for `ndgrid(1:M, 1:N, ...)`.
# Example
```jldoctest
julia> ndgrid(2,3)
([1 1 1; 2 2 2], [1 2 3; 1 2 3])
```
"""
function ndgrid(ns::Vararg{Int})
all(>(0), ns) || throw(ArgumentError("$n ≤ 0"))
return ndgrid(Base.OneTo.(ns)...)
end


#=
"""
(xg, yg, ...) = ndgrid(Base.OneTo{M}, Base.OneTo{N}, ...)
Construct `ndgrid` tuple for essentially `ndgrid(1:M, 1:N, ...)`.
# Example
```jldoctest
julia> ndgrid(Base.OneTo(2), Base.OneTo(3))
([1 1 1; 2 2 2], [1 2 3; 1 2 3])
```
"""
function ndgrid(os::Vararg{Base.OneTo{Int}})
D = length(os)
dims = ntuple(i -> os[i].stop, D)
return ntuple(i -> GridOT(dims, i), D)
end
=#
55 changes: 55 additions & 0 deletions src/ndgrid-range.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#=
ndgrid-range
ndgrid for a set of AbstractRange inputs.
=#

export ndgrid


"""
GridAR{T,d,D} <: AbstractGrid{T,d,D}
The `d`th component of `D`-dimensional `ndgrid(x, y ...)`
where `1 ≤ d ≤ D` and `x, y, ...` are each an `AbstractRange`.
"""
struct GridAR{T,d,D} <: AbstractGrid{T,d,D}
dims::Dims{D}
first0::T # first - step
step::T

function GridAR(dims::Dims{D}, v::AbstractRange{T}, d::Int) where {D, T}
1 d D || throw(ArgumentError("$d for $dims"))
new{T,d,D}(dims, first(v) - step(v), step(v))
end
end

Base.size(a::GridAR) = a.dims
Base.eltype(::GridAR{T}) where T = T

@inline Base.@propagate_inbounds function Base.getindex(
a::GridAR{T,d,D},
i::Vararg{Int,D},
) where {T,d,D}
@boundscheck checkbounds(a, i...)
return a.first0 + (@inbounds i[d]) * a.step
end


#=
"""
(xg, yg, ...) = ndgrid(v1, v2,, ...)
Construct `ndgrid` tuple for `AbstractRange` inputs.
# Example
```jldoctest
julia> ndgrid(1:3, 5:2:7)
([1 1; 2 2; 3 3], [5 7; 5 7; 5 7])
```
"""
function ndgrid(vs::Vararg{AbstractRange})
D = length(vs)
dims = ntuple(i -> length(vs[i]), D)
T = Tuple{ntuple(i -> GridAR{eltype(vs[i]), i, D}, D)...} # return type
return ntuple(i -> GridAR(dims, vs[i], i), D)::T
end
=#
55 changes: 55 additions & 0 deletions src/ndgrid-unitr.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#=
ndgrid-unitr.jl
ndgrid for a set of "UnitRange{Int}" inputs.
=#

export ndgrid


"""
GridUR{T,d,D} <: AbstractGrid{T,d,D}
The `d`th component of `D`-dimensional `ndgrid(a:b, c:d, ...)`
where `1 ≤ d ≤ D`.
"""
struct GridUR{T,d,D} <: AbstractGrid{T,d,D}
dims::Dims{D}
first0::T # first-1

function GridUR(dims::Dims{D}, v::AbstractRange{T}, d::Int) where {T,D}
1 d D || throw(ArgumentError("$d for $dims"))
T == Int || throw(ArgumentError("only Int supported"))
new{T,d,D}(dims, first(v) - one(T))
end
end

Base.size(a::GridUR) = a.dims
Base.eltype(::GridUR{T}) where T = T

@inline Base.@propagate_inbounds function Base.getindex(
a::GridUR{T,d,D},
i::Vararg{Int,D},
) where {T <: Int, d, D}
@boundscheck checkbounds(a, i...)
# @boundscheck checkbounds(i, d)
return a.first0 + @inbounds i[d] # i don't want to deal with one(T) here
end


#=
"""
(xg, yg, ...) = ndgrid(a:b, c:d, ...)
Construct `ndgrid` tuple for `UnitRange{Int}` inputs.
# Example
```jldoctest
julia> ndgrid(1:2, 3:5)
([1 1 1; 2 2 2], [3 4 5; 3 4 5])
```
"""
function ndgrid(vs::Vararg{UnitRange{Int}})
D = length(vs)
dims = ntuple(i -> length(vs[i]), D)
return ntuple(i -> GridUR(dims, vs[i], i), D)
end
=#
Loading

2 comments on commit 2df7816

@JeffFessler
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator() register

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/40528

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.0 -m "<description of version>" 2df7816d6bd703e2aec14e57b5158869365685c3
git push origin v0.1.0

Please sign in to comment.