New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create #1
Merged
Create #1
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
862be29
Add name2dim function
oxinabox 4ffd467
fix author
oxinabox 37dc374
Implement array type
oxinabox 0daa863
start work on overloading functions (Currently broken)
oxinabox ecbc6c5
Simplify code by using more named tuple stuff
oxinabox ae62415
overload functions
oxinabox 79a45ea
more array stuff
oxinabox a945872
Make indexing keep the named dimensions
oxinabox 523490d
add readme
oxinabox b7485d7
Update src/name_core.jl
rofinn e79557b
Apply suggestions from code review
oxinabox 699c645
rename all the things
oxinabox 25bb72b
Update src/name_core.jl
nicoleepp f2180fb
Add Docstring
oxinabox 88814d5
expand on commend about allocation
oxinabox efa957f
Add dropdims
oxinabox bbb87d8
make functions of NamedDimsArrays return NamedDimsArrays
oxinabox 10540bd
Update src/wrapper_array.jl
iamed2 c4082dd
Update test/name_core.jl
nickrobinson251 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
module NamedDims | ||
|
||
greet() = print("Hello World!") | ||
export NamedDimsArray, name2dim, dim_names | ||
|
||
include("wrapper_array.jl") | ||
include("name2dim.jl") | ||
include("base_functions.jl") | ||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
|
||
function Base.sum(f::Base.Callable, a::NamedDimsArray; dims) | ||
return sum(f, parent(a); dims=name2dim(A, dims)) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
|
||
function NamedNotFoundException(name, cands) | ||
return ArgumentError( | ||
"No dimensioned called $name exists. Dimension names: $(join(cands, ", "))" | ||
) | ||
end | ||
|
||
################################### | ||
|
||
# We change the name into a `Val` because that will trigger constant propergation | ||
oxinabox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# and allow this to resolve at compile time when the `name` is a constant | ||
name2dim(namemap, name) = _name2dim(namemap, Val(name)) | ||
oxinabox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# `_name2dim` returns 0 for names not found, because throwing an error would make it inpure | ||
# And then it couldn't run at compile time. | ||
|
||
# Generic case | ||
#TODO: for speed this could be made into a generated function, so it happens at compile time | ||
function _name2dim(::Type{T}, ::Val{name}) where {T<:Tuple, name} | ||
return something(findfirst(isequal(name), T.parameters), 0) | ||
end | ||
|
||
## Hand roll out special cases to help this optimize to run at compile time | ||
_name2dim(::Type{Tuple{A}}, ::Val{A}) where A = 1 | ||
_name2dim(::Type{Tuple{A}}, ::Val{name}) where {A,name} = 0 | ||
|
||
_name2dim(::Type{Tuple{A,B}}, ::Val{A}) where {A,B} = 1 | ||
_name2dim(::Type{Tuple{A,B}}, ::Val{B}) where {A,B} = 2 | ||
_name2dim(::Type{Tuple{A,B}}, ::Val{name}) where {A,B,name} = 0 | ||
|
||
_name2dim(::Type{Tuple{A,B,C}}, ::Val{A}) where {A,B,C} = 1 | ||
_name2dim(::Type{Tuple{A,B,C}}, ::Val{B}) where {A,B,C} = 2 | ||
_name2dim(::Type{Tuple{A,B,C}}, ::Val{C}) where {A,B,C} = 3 | ||
_name2dim(::Type{Tuple{A,B,C}}, ::Val{name}) where {A,B,C,name} = 0 | ||
|
||
_name2dim(::Type{Tuple{A,B,C,D}}, ::Val{A}) where {A,B,C,D} = 1 | ||
_name2dim(::Type{Tuple{A,B,C,D}}, ::Val{B}) where {A,B,C,D} = 2 | ||
_name2dim(::Type{Tuple{A,B,C,D}}, ::Val{C}) where {A,B,C,D} = 3 | ||
_name2dim(::Type{Tuple{A,B,C,D}}, ::Val{D}) where {A,B,C,D} = 4 | ||
_name2dim(::Type{Tuple{A,B,C,D}}, ::Val{name}) where {A,B,C,D, name} = 0 | ||
|
||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{A}) where {A,B,C,D,E} = 1 | ||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{B}) where {A,B,C,D,E} = 2 | ||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{C}) where {A,B,C,D,E} = 3 | ||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{D}) where {A,B,C,D,E} = 4 | ||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{E}) where {A,B,C,D,E} = 5 | ||
_name2dim(::Type{Tuple{A,B,C,D,E}}, ::Val{name}) where {A,B,C,D,E, name} = 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
|
||
struct NamedDimsArray{L<:Tuple, T, N, A<:AbstractArray{T,N}} <: AbstractArray{T,N} | ||
data::A | ||
end | ||
|
||
function NamedDimsArray(orig::AbstractArray{T,N}, names) where {T, N} | ||
if length(names) != N | ||
throw(ArgumentError("A $N dimentional array, need $N dimension names. Got: $names")) | ||
end | ||
names_tt = Tuple{names...} | ||
return NamedDimsArray{names_tt, T, N, typeof(orig)}(orig) | ||
end | ||
|
||
|
||
Base.parent(x::NamedDimsArray) = x.data | ||
|
||
|
||
""" | ||
dim_names(A) | ||
|
||
Returns a tuple of containing the names of all the dimensions of the array `A`. | ||
""" | ||
dim_names(::Type{<:NamedDimsArray{L}}) where L = Tuple(L.parameters) | ||
dim_names(x::T) where T = dim_names(T) | ||
|
||
|
||
name2dim(a::NamedDimsArray{L}, name) where L = name2dim(L, name) | ||
|
||
|
||
|
||
############################# | ||
# AbstractArray Interface | ||
# https://docs.julialang.org/en/v1/manual/interfaces/index.html#man-interface-array-1 | ||
|
||
Base.size(a::NamedDimsArray) = size(parent(a)) | ||
Base.getindex(A::NamedDimsArray, inds...) = getindex(parent(A), inds...) | ||
Base.setindex(A::NamedDimsArray, value, inds...) = setindex(parent(A), value, inds...) | ||
|
||
|
||
############################### | ||
# kwargs indexing | ||
|
||
""" | ||
order_named_inds(A, named_inds...) | ||
|
||
Returns the indices that have the names and values given by `named_inds` | ||
sorted into the order expected for the dimension of the array `A`. | ||
If any dimensions of `A` are not present in the named_inds, | ||
then they are given the value `:`, for slicing | ||
|
||
For example: | ||
``` | ||
A = NamedDimArray(rand(4,4), (:x,, :y)) | ||
order_named_inds(A; y=10, x=13) == (13,10) | ||
order_named_inds(A; x=2, y=1:3) == (2, 1:3) | ||
order_named_inds(A; y=5) == (:, 5) | ||
``` | ||
|
||
This provides the core indexed lookup for `getindex` and `setindex` on the Array `A` | ||
""" | ||
function order_named_inds(A; named_inds...) | ||
keys(named_inds) ⊆ dim_names(A) || throw( | ||
DimensionMismatch("Expected $(dim_names(A)), got $(keys(named_inds))") | ||
) | ||
|
||
|
||
inds = map(dim_names(A)) do name | ||
get(named_inds, name, :) # default to slicing | ||
end | ||
end | ||
oxinabox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function Base.getindex(A::NamedDimsArray; named_inds...) | ||
inds = order_named_inds(A; named_inds...) | ||
return getindex(parent(A), inds...) | ||
end | ||
|
||
|
||
function Base.setindex(A::NamedDimsArray, value; named_inds...) | ||
inds = order_named_inds(A; named_inds...) | ||
return setindex(parent(A), value, inds...) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using NamedDims | ||
using Test | ||
|
||
@testset "sum" begin | ||
nda = NamedDimsArray([10 20; 30 40], (:x, :y)) | ||
|
||
@test sum(nda) == 100 == sum(identity, nda) | ||
|
||
@test sum(nda; dims=:x) == [40 60] | ||
@test sum(nda; dims=1) == [40 60] | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using NamedDims | ||
using Test | ||
|
||
|
||
@testset "name2dim" begin | ||
@testset "small case, that hits unrolled method" begin | ||
@test name2dim(Tuple{:x, :y}, :x)==1 | ||
@test name2dim(Tuple{:x, :y}, :y)==2 | ||
@test name2dim(Tuple{:x, :y}, :z)==0 # not found | ||
end | ||
@testset "large case that hits generic fallback" begin | ||
@test name2dim(Tuple{:x, :y, :a, :b, :c, :d}, :x)==1 | ||
@test name2dim(Tuple{:x, :y, :a, :b, :c, :d}, :a)==3 | ||
@test name2dim(Tuple{:x, :y, :a, :b, :c, :d}, :d)==6 | ||
@test name2dim(Tuple{:x, :y, :a, :b, :c, :d}, :z)==0 # not found | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using NamedDims | ||
using Test | ||
|
||
|
||
@testset "get the parent array that was wrapped" begin | ||
orig = [1 2; 3 4] | ||
@test parent(NamedDimsArray(orig, (:x, :y))) === orig | ||
end | ||
|
||
|
||
@testset "get the named array that was wrapped" begin | ||
@test dim_names(NamedDimsArray([10 20; 30 40], (:x, :y))) === (:x, :y) | ||
end | ||
|
||
|
||
@testset "getindex" begin | ||
nda = NamedDimsArray([10 20; 30 40], (:x, :y)) | ||
|
||
@test nda[x=1, y=1] == nda[y=1, x=1] == nda[1, 1] == 10 | ||
@test nda[y=end,x=end] == nda[end, end] == 40 | ||
|
||
# Missing dims become slices | ||
@test nda[y=1] == nda[y=1, x=:] == nda[:, 1] == [10; 30] | ||
|
||
end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems weird to only partially follow the
_
convention.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i prefer
a2b
naming only forDict
s but I don't have a good alternativeAlthough if
name2dim
is part of the public API i'd like to try finding a better name :)Is
dim[s]
ordimension[s]
better or worse?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so
name_to_dim
?I am ok with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_dim
?dim
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i quite to like
dims(names)
anddims(names, name)
...but maybe it's scarily short?plus
NamedDims.dims
goes nicely withNamedDims.names
edit: think
dims
better thandim
:)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have
axes
it is only slightly shorter.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't do
dims
,it is a kwarg on functions that want to call this.
e.g.
sum(xs::NamedDimArray; dims)=sum(parent(xs), dims(xs, dims))
does not work; and
sum(xs::NamedDimArray; dims)=sum(parent(xs), NamedDimArray.dims(xs, dims))
is ugly.