Skip to content
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

Implement mapslices for AxisArrays #195

Closed
wants to merge 10 commits into from

Conversation

glennmoy
Copy link

@glennmoy glennmoy commented Feb 25, 2021

Closes #193, replacing #194 as it now accepts integer and Axis dims arguments

julia> A = AxisArray(collect(reshape(1:15,3,5)), :y, :x)
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(3)
    :x, Base.OneTo(5)
And data, a 3×5 Array{Int64,2}:
 1  4  7  10  13
 2  5  8  11  14
 3  6  9  12  15

julia> mapslices(sum, A; dims=1)
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(1)
    :x, Base.OneTo(5)
And data, a 1×5 Array{Int64,2}:
 6  15  24  33  42

julia> mapslices(sum, A; dims=Axis{:y})
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(1)
    :x, Base.OneTo(5)
And data, a 1×5 Array{Int64,2}:
 6  15  24  33  42

julia> mapslices(sum, A; dims=Axis{:y}())
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(1)
    :x, Base.OneTo(5)
And data, a 1×5 Array{Int64,2}:
 6  15  24  33  42

julia> mapslices(sum, A; dims=[Axis{:y}, Axis{:x}])
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(1)
    :x, Base.OneTo(1)
And data, a 1×1 Array{Int64,2}:
 120

EDIT: and can also replace non-integer axis values

julia> A_non_int = AxisArray(reshape(1:15,3,5), Axis{:y}(range(0.1, length=3)), Axis{:x}(range(0.1, length=5)))
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, 0.1:1.0:2.1
    :x, 0.1:1.0:4.1
And data, a 3×5 reshape(::UnitRange{Int64}, 3, 5) with eltype Int64:
 1  4  7  10  13
 2  5  8  11  14
 3  6  9  12  15

julia> mapslices(sum, A; dims=Axis{:x})
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, 0.1:1.0:2.1
    :x, Base.OneTo(1)
And data, a 3×1 Array{Int64,2}:
 35
 40
 45

and non-reducing operations

julia> mapslices(x->x*x', A; dims=(1, 2))
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, 0.1:1.0:2.1
    :x, Base.OneTo(3)
And data, a 3×3 Array{Int64,2}:
 335  370  405
 370  410  450
 405  450  495

I will note that when mapslices changes the length of an Axis (as in the non-reducing example) it's not possible to know what the new axis values will be so substituting the default axis values Base.OneTo(n) seemed appropriate.

Another example might be:

julia> mapslices(x->fill(1, 7), A; dims=1)
2-dimensional AxisArray{Int64,2,...} with axes:
    :y, Base.OneTo(7)
    :x, 0.1:1.0:4.1
And data, a 7×5 Array{Int64,2}:
 1  1  1  1  1
 1  1  1  1  1
 1  1  1  1  1
 1  1  1  1  1
 1  1  1  1  1
 1  1  1  1  1
 1  1  1  1  1

src/core.jl Outdated Show resolved Hide resolved
src/core.jl Outdated Show resolved Hide resolved
src/core.jl Outdated Show resolved Hide resolved
@iamed2
Copy link
Collaborator

iamed2 commented Feb 26, 2021

This only handles reductions. For example:

julia> A
10×5×2 reshape(::UnitRange{Int64}, 10, 5, 2) with eltype Int64:
[:, :, 1] =
  1  11  21  31  41
  2  12  22  32  42
  3  13  23  33  43
  4  14  24  34  44
  5  15  25  35  45
  6  16  26  36  46
  7  17  27  37  47
  8  18  28  38  48
  9  19  29  39  49
 10  20  30  40  50

[:, :, 2] =
 51  61  71  81   91
 52  62  72  82   92
 53  63  73  83   93
 54  64  74  84   94
 55  65  75  85   95
 56  66  76  86   96
 57  67  77  87   97
 58  68  78  88   98
 59  69  79  89   99
 60  70  80  90  100

julia> AA
3-dimensional AxisArray{Int64,3,...} with axes:
    :x, Base.OneTo(10)
    :y, Base.OneTo(5)
    :z, Base.OneTo(2)
And data, a 10×5×2 reshape(::UnitRange{Int64}, 10, 5, 2) with eltype Int64:
[:, :, 1] =
  1  11  21  31  41
  2  12  22  32  42
  3  13  23  33  43
  4  14  24  34  44
  5  15  25  35  45
  6  16  26  36  46
  7  17  27  37  47
  8  18  28  38  48
  9  19  29  39  49
 10  20  30  40  50

[:, :, 2] =
 51  61  71  81   91
 52  62  72  82   92
 53  63  73  83   93
 54  64  74  84   94
 55  65  75  85   95
 56  66  76  86   96
 57  67  77  87   97
 58  68  78  88   98
 59  69  79  89   99
 60  70  80  90  100

julia> mapslices(A, dims=(1,3)) do x
           x * x'
       end
10×5×10 Array{Int64,3}:
[:, :, 1] =
 2602  3842  5482  7522   9962
 2654  3914  5574  7634  10094
 2706  3986  5666  7746  10226
 2758  4058  5758  7858  10358
 2810  4130  5850  7970  10490
 2862  4202  5942  8082  10622
 2914  4274  6034  8194  10754
 2966  4346  6126  8306  10886
 3018  4418  6218  8418  11018
 3070  4490  6310  8530  11150

[:, :, 2] =
 2654  3914  5574  7634  10094
 2708  3988  5668  7748  10228
 2762  4062  5762  7862  10362
 2816  4136  5856  7976  10496
 2870  4210  5950  8090  10630
 2924  4284  6044  8204  10764
 2978  4358  6138  8318  10898
 3032  4432  6232  8432  11032
 3086  4506  6326  8546  11166
 3140  4580  6420  8660  11300

[:, :, 3] =
 2706  3986  5666  7746  10226
 2762  4062  5762  7862  10362
 2818  4138  5858  7978  10498
 2874  4214  5954  8094  10634
 2930  4290  6050  8210  10770
 2986  4366  6146  8326  10906
 3042  4442  6242  8442  11042
 3098  4518  6338  8558  11178
 3154  4594  6434  8674  11314
 3210  4670  6530  8790  11450

[:, :, 4] =
 2758  4058  5758  7858  10358
 2816  4136  5856  7976  10496
 2874  4214  5954  8094  10634
 2932  4292  6052  8212  10772
 2990  4370  6150  8330  10910
 3048  4448  6248  8448  11048
 3106  4526  6346  8566  11186
 3164  4604  6444  8684  11324
 3222  4682  6542  8802  11462
 3280  4760  6640  8920  11600

[:, :, 5] =
 2810  4130  5850  7970  10490
 2870  4210  5950  8090  10630
 2930  4290  6050  8210  10770
 2990  4370  6150  8330  10910
 3050  4450  6250  8450  11050
 3110  4530  6350  8570  11190
 3170  4610  6450  8690  11330
 3230  4690  6550  8810  11470
 3290  4770  6650  8930  11610
 3350  4850  6750  9050  11750

[:, :, 6] =
 2862  4202  5942  8082  10622
 2924  4284  6044  8204  10764
 2986  4366  6146  8326  10906
 3048  4448  6248  8448  11048
 3110  4530  6350  8570  11190
 3172  4612  6452  8692  11332
 3234  4694  6554  8814  11474
 3296  4776  6656  8936  11616
 3358  4858  6758  9058  11758
 3420  4940  6860  9180  11900

[:, :, 7] =
 2914  4274  6034  8194  10754
 2978  4358  6138  8318  10898
 3042  4442  6242  8442  11042
 3106  4526  6346  8566  11186
 3170  4610  6450  8690  11330
 3234  4694  6554  8814  11474
 3298  4778  6658  8938  11618
 3362  4862  6762  9062  11762
 3426  4946  6866  9186  11906
 3490  5030  6970  9310  12050

[:, :, 8] =
 2966  4346  6126  8306  10886
 3032  4432  6232  8432  11032
 3098  4518  6338  8558  11178
 3164  4604  6444  8684  11324
 3230  4690  6550  8810  11470
 3296  4776  6656  8936  11616
 3362  4862  6762  9062  11762
 3428  4948  6868  9188  11908
 3494  5034  6974  9314  12054
 3560  5120  7080  9440  12200

[:, :, 9] =
 3018  4418  6218  8418  11018
 3086  4506  6326  8546  11166
 3154  4594  6434  8674  11314
 3222  4682  6542  8802  11462
 3290  4770  6650  8930  11610
 3358  4858  6758  9058  11758
 3426  4946  6866  9186  11906
 3494  5034  6974  9314  12054
 3562  5122  7082  9442  12202
 3630  5210  7190  9570  12350

[:, :, 10] =
 3070  4490  6310  8530  11150
 3140  4580  6420  8660  11300
 3210  4670  6530  8790  11450
 3280  4760  6640  8920  11600
 3350  4850  6750  9050  11750
 3420  4940  6860  9180  11900
 3490  5030  6970  9310  12050
 3560  5120  7080  9440  12200
 3630  5210  7190  9570  12350
 3700  5300  7300  9700  12500

julia> mapslices(AA, dims=(1,3)) do x
           x * x'
       end
ERROR: ArgumentError: the length of each axis must match the corresponding size of data
Stacktrace:
 [1] AxisArray(::Array{Int64,3}, ::Tuple{Axis{:x,Base.OneTo{Int64}},Axis{:y,Base.OneTo{Int64}},Axis{:z,Base.OneTo{Int64}}}) at /Users/ericdavies/repos/AxisArrays.jl/src/core.jl:229
 [2] AxisArray(::Array{Int64,3}, ::Axis{:x,Base.OneTo{Int64}}, ::Vararg{Union{Axis, AbstractArray{T,1} where T},N} where N) at /Users/ericdavies/repos/AxisArrays.jl/src/core.jl:222
 [3] mapslices(::Function, ::AxisArray{Int64,3,Base.ReshapedArray{Int64,3,UnitRange{Int64},Tuple{}},Tuple{Axis{:x,Base.OneTo{Int64}},Axis{:y,Base.OneTo{Int64}},Axis{:z,Base.OneTo{Int64}}}}; dims::Tuple{Int64,Int64}) at /Users/ericdavies/repos/AxisArrays.jl/src/core.jl:445
 [4] top-level scope at REPL[10]:1

@iamed2
Copy link
Collaborator

iamed2 commented Feb 26, 2021

This also only handles integer axis values, e.g.:

julia> BB = AxisArray(B, Axis{:x}(range(0.1, length=3)), Axis{:y}(range(0.1, length=4)))
2-dimensional AxisArray{Int64,2,...} with axes:
    :x, 0.1:1.0:2.1
    :y, 0.1:1.0:3.1
And data, a 3×4 reshape(::UnitRange{Int64}, 3, 4) with eltype Int64:
 1  4  7  10
 2  5  8  11
 3  6  9  12

julia> mapslices(sum, BB, dims=2)
ERROR: MethodError: Cannot `convert` an object of type
  Axis{:y,Base.OneTo{Int64}} to an object of type
  Axis{name,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}} where name
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:171
Stacktrace:
 [1] setindex!(::Array{Axis{name,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}} where name,1}, ::Axis{:y,Base.OneTo{Int64}}, ::Int64) at ./array.jl:847
 [2] mapslices(::Function, ::AxisArray{Int64,2,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}},Tuple{Axis{:x,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}},Axis{:y,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}}}}; dims::Int64) at /Users/ericdavies/repos/AxisArrays.jl/src/core.jl:441
 [3] top-level scope at REPL[13]:1

@glennmoy
Copy link
Author

glennmoy commented Mar 9, 2021

closing since we have worked around this downstream. I might open again if folks want it in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mapslices errors for AxisArrays
3 participants