From 6e96e27a2a052e6af2a10937bdd1c53ea02ed58d Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Mon, 4 Nov 2024 00:48:28 +0100 Subject: [PATCH 1/9] set lookups as Unordered after Vector{Int} indexing --- src/Lookups/indexing.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index 5c86a1882..d17652e8d 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -5,8 +5,11 @@ for f in (:getindex, :view, :dotview) @propagate_inbounds Base.$f(l::Lookup, i::Union{Int,CartesianIndex}) = Base.$f(parent(l), i) # AbstractArray, Colon and CartesianIndices: the lookup is rebuilt around a new parent - @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractArray,Colon}) = + @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractVector,Colon}) = rebuild(l; data=Base.$f(parent(l), i)) + @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractVector{Int}) + rebuild(l; data=Base.$f(parent(l), i), order=Unordered()) + end # Selector gets processed with `selectindices` @propagate_inbounds Base.$f(l::Lookup, i::SelectorOrInterval) = Base.$f(l, selectindices(l, i)) @propagate_inbounds function Base.$f(l::Lookup, i) From 93ad378d2fa2f505264d479a5c05315a58fce2e9 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Mon, 4 Nov 2024 00:57:18 +0100 Subject: [PATCH 2/9] check AbstractVector{Int} index sorted order --- src/Lookups/indexing.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index d17652e8d..05b691126 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -8,7 +8,10 @@ for f in (:getindex, :view, :dotview) @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractVector,Colon}) = rebuild(l; data=Base.$f(parent(l), i)) @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractVector{Int}) - rebuild(l; data=Base.$f(parent(l), i), order=Unordered()) + if isordered(l) + issorted(i) || throw(ArgumentError("For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order")) + end + rebuild(l; data=Base.$f(parent(l), i)) end # Selector gets processed with `selectindices` @propagate_inbounds Base.$f(l::Lookup, i::SelectorOrInterval) = Base.$f(l, selectindices(l, i)) From fa2ec720e73443f5076212275e36aa78fe530e08 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Wed, 5 Nov 2025 21:37:52 +1100 Subject: [PATCH 3/9] add local and global short circuits for checkorder --- docs/src/api/reference.md | 5 +- src/DimensionalData.jl | 3 +- src/Lookups/indexing.jl | 41 ++++++++- src/array/indexing.jl | 4 +- test/indexing.jl | 170 +++++++++++++++++++++++--------------- 5 files changed, 149 insertions(+), 74 deletions(-) diff --git a/docs/src/api/reference.md b/docs/src/api/reference.md index 7c3bb7961..3ae6f72ff 100644 --- a/docs/src/api/reference.md +++ b/docs/src/api/reference.md @@ -105,7 +105,8 @@ reorder ## Global lookup strictness settings Control how strict DimensionalData when comparing [`Lookup`](@ref)s -before doing broadcasts and matrix multipications. +before doing broadcasts, matrix multipications, or indexing with +possibly unordered `AbstractVector{Int}`. In some cases (especially `DimVector` and small `DimArray`) checking lookup values match may be too costly compared to the operations. @@ -117,6 +118,8 @@ DimensionalData.strict_broadcast DimensionalData.strict_broadcast! DimensionalData.strict_matmul DimensionalData.strict_matmul! +DimensionalData.strict_order +DimensionalData.strict_order! ``` ## Base methods diff --git a/src/DimensionalData.jl b/src/DimensionalData.jl index ede289b04..d1e5450de 100644 --- a/src/DimensionalData.jl +++ b/src/DimensionalData.jl @@ -39,7 +39,8 @@ using .Dimensions: StandardIndices, DimOrDimType, DimTuple, DimTupleOrEmpty, Dim using .Dimensions: INTERFACE_QUERY_FUNCTION_NAMES import .Lookups: metadata, set, _set, rebuild, basetypeof, order, span, sampling, locus, val, bounds, intervalbounds, - hasselection, units, SelectorOrInterval, Begin, End + hasselection, units, SelectorOrInterval, Begin, End, + strict_order, strict_order! import .Dimensions: dims, refdims, name, lookup, kw2dims, hasdim, label, _astuple using OrderedCollections: OrderedDict diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index 05b691126..be7ffabdc 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -1,4 +1,31 @@ +const STRICT_ORDER_CHECKS = Ref(true) +const STRICT_ORDER_DOCS = """ +By default indexing with Vector{Int} is required +to be ordered if lookups are ordered to avoid broken lookups. +`@inbounds` annotations skip this check, but in some cases where +outputs are not used you may wish to disable it completely. +""" + +""" + strict_order() + +Check if strick broadcasting checks are active. + +$STRICT_ORDER_DOCS +""" +strict_order() = STRICT_ORDER_CHECKS[] + +""" + strict_order!(x::Bool) + +Set global AbstractVector{Int} indexing checks to `strict`, or not, for all `AbstractDimArray`. + +$STRICT_ORDER_DOCS +""" +strict_order!(x::Bool) = STRICT_ORDER_CHECKS[] = x + + for f in (:getindex, :view, :dotview) @eval begin # Int and CartesianIndex forward to the parent @@ -8,9 +35,8 @@ for f in (:getindex, :view, :dotview) @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractVector,Colon}) = rebuild(l; data=Base.$f(parent(l), i)) @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractVector{Int}) - if isordered(l) - issorted(i) || throw(ArgumentError("For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order")) - end + @boundscheck checkorder(l, i) + # Allow skipping this check with @inbounds rebuild(l; data=Base.$f(parent(l), i)) end # Selector gets processed with `selectindices` @@ -21,3 +47,12 @@ for f in (:getindex, :view, :dotview) end end end + +function checkorder(l, i) + if strict_order() && isordered(l) + issorted(i) || throw(ArgumentError(""" + For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order. + Use `@inbounds` to avoid this check locally, and `DimensionalData.strict_order!(false)` globally. + """)) + end +end diff --git a/src/array/indexing.jl b/src/array/indexing.jl index 438eb8424..717a80645 100644 --- a/src/array/indexing.jl +++ b/src/array/indexing.jl @@ -116,8 +116,8 @@ for f in (:getindex, :view, :dotview) # Special case zero dimensional arrays being indexed with missing dims if f == :getindex # Catch this before the dimension is converted to () - @eval $_dim_f(A::AbstractDimArray{<:Any,0}) = rebuild(A, fill(A[])) - @eval function $_dim_f(A::AbstractDimArray{<:Any,0}, d1::Dimension, ds::Dimension...) + @eval @propagate_inbounds $_dim_f(A::AbstractDimArray{<:Any,0}) = rebuild(A, fill(A[])) + @eval @propagate_inbounds function $_dim_f(A::AbstractDimArray{<:Any,0}, d1::Dimension, ds::Dimension...) Dimensions._extradimswarn((d1, ds...)) return rebuild(A, fill(A[])) end diff --git a/test/indexing.jl b/test/indexing.jl index 6a804437c..527267fae 100644 --- a/test/indexing.jl +++ b/test/indexing.jl @@ -35,40 +35,40 @@ end @test l[Begin+1:End-1] ==l[Begin+1:4] == l[2:End-1] == l[2:4] @test l[Begin:End] isa typeof(l) @test l[1:5] isa typeof(l) - @test l[[1, 3, 4]] == view(l, [1, 3, 4]) == + @test l[[1, 3, 4]] == view(l, [1, 3, 4]) == Base.dotview(l, [1, 3, 4]) == Sampled([2.0, 6.0, 8.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), NoMetadata()) - @test l[Int[]] == view(l, Int[]) == Base.dotview(l, Int[]) == + @test l[Int[]] == view(l, Int[]) == Base.dotview(l, Int[]) == Sampled(Float64[], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Near(2.1)] == Base.dotview(l, Near(2.1)) == 2.0 @test view(l, Near(2.1)) == fill(2.0) - @test l[[false, true, true, false, true]] == - view(l, [false, true, true, false, true]) == - Base.dotview(l, [false, true, true, false, true]) == + @test l[[false, true, true, false, true]] == + view(l, [false, true, true, false, true]) == + Base.dotview(l, [false, true, true, false, true]) == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[2] == Base.dotview(l, 2) === 4.0 @test view(l, 2) == fill(4.0) @test l[CartesianIndex((4,))] === Base.dotview(l, CartesianIndex((4,))) === 8.0 @test view(l, CartesianIndex((4,))) == fill(8.0) - @test l[CartesianIndices((1:3,))] == - view(l, CartesianIndices((1:3,))) == - Base.dotview(l, CartesianIndices((1:3,))) == + @test l[CartesianIndices((1:3,))] == + view(l, CartesianIndices((1:3,))) == + Base.dotview(l, CartesianIndices((1:3,))) == Sampled(2.0:2.0:6.0, ForwardOrdered(), Regular(2.0), Points(), NoMetadata()) - @test l[2:2:4] == - view(l, 2:2:4) == - Base.dotview(l, 2:2:4) == + @test l[2:2:4] == + view(l, 2:2:4) == + Base.dotview(l, 2:2:4) == Sampled(4.0:4.0:8.0, ForwardOrdered(), Regular(4.0), Points(), nothing) # End Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus DateTime l = Sampled(DateTime(2001, 1, 1):Day(1):DateTime(2001, 1, 5), ForwardOrdered(), Regular(Day(1)), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([DateTime(2001, 1, 2), DateTime(2001, 1, 3), DateTime(2001, 1, 5)], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Reverse l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) @@ -78,7 +78,7 @@ end @test l[[1, 3, 4]] == Sampled([10.0, 6.0, 4.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Int[]] == Sampled(Float64[], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[2] === 8.0 @test l[CartesianIndex((4,))] == 4.0 @@ -86,15 +86,15 @@ end @test l[2:2:4] == Sampled(8.0:-4.0:4.0, ReverseOrdered(), Regular(-4.0), Points(), nothing) # End Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus DateTime l = Sampled(DateTime(2001, 1, 5):Day(-1):DateTime(2001, 1, 1), ReverseOrdered(), Regular(Day(-1)), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([DateTime(2001, 1, 4), DateTime(2001, 1, 3), DateTime(2001, 1, 1)], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) end @@ -107,20 +107,20 @@ end @test l[[1, 3, 4]] == Sampled([2.0, 6.0, 8.0], ForwardOrdered(), Irregular(2.0, 10.0), Intervals(Start()), nothing) @test l[Int[]] == Sampled(Float64[], ForwardOrdered(), Irregular(nothing, nothing), Intervals(Start()), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(4.0, 12.0), Intervals(Start()), nothing) @test l[2] === 4.0 @test l[CartesianIndex((4,))] == 8.0 - @test l[CartesianIndices((1:3,))] == + @test l[CartesianIndices((1:3,))] == Sampled(2.0:2.0:6.0, ForwardOrdered(), Regular(2.0), Intervals(Start()), NoMetadata()) @test l[2:2:4] == Sampled(4.0:4.0:8.0, ForwardOrdered(), Regular(4.0), Intervals(Start()), nothing) # End Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Intervals(End()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(2.0, 10.0), Intervals(End()), nothing) # Center Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Intervals(Center()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(3.0, 11.0), Intervals(Center()), nothing) # Reverse Start Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(Start()), nothing) @@ -129,27 +129,27 @@ end @test l[1:5] isa typeof(l) @test l[[1, 3, 4]] == Sampled([10.0, 6.0, 4.0], ReverseOrdered(), Irregular(4.0, 12.0), Intervals(Start()), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(2.0, 10.0), Intervals(Start()), nothing) @test l[2] === 8.0 @test l[CartesianIndex((4,))] == 4.0 - @test l[CartesianIndices((1:3,))] == + @test l[CartesianIndices((1:3,))] == Sampled(10.0:-2.0:6.0, ReverseOrdered(), Regular(-2.0), Intervals(Start()), nothing) @test l[2:2:4] == Sampled(8.0:-4.0:4.0, ReverseOrdered(), Regular(-4.0), Intervals(Start()), nothing) # End Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(End()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(0.0, 8.0), Intervals(End()), nothing) # Center Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(Center()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(1.0, 9.0), Intervals(Center()), nothing) end @testset "NoLookup" begin nl = NoLookup(1:100) @test nl[100] == 100 @test nl[1:5] isa typeof(nl) - @test nl[CartesianIndex((1,))] == 1 + @test nl[CartesianIndex((1,))] == 1 @test view(nl, 50) === view(1:100, 50) @test Base.dotview(nl, 50) === 50 end @@ -173,7 +173,7 @@ end d = Y(NoLookup(1:100)) @test d[100] == 100 @test d[1:5] isa typeof(d) - @test d[CartesianIndex((1,))] == 1 + @test d[CartesianIndex((1,))] == 1 @test view(d, 50) === view(1:100, 50) @test Base.dotview(d, 50) === 50 end @@ -205,8 +205,8 @@ end @test da[:] == da[Begin:End] == vec(da) b = @inferred da[[!iseven(i) for i in 1:length(da)]] @test b isa Array - @test b == da[1:2:end] == da[Begin:2:End] - + @test b == da[1:2:end] == da[Begin:2:End] + v = @inferred da[1, :] @test v isa DimVector @test @inferred v[1:2] isa DimArray @@ -218,7 +218,7 @@ end end @testset "mixed CartesianIndex and CartesianIndices indexing works" begin - da3 = cat(da, 10da; dims=Z) + da3 = cat(da, 10da; dims=Z) @test @inferred da3[1, CartesianIndex(1, 2)] == 10 @test @inferred view(da3, 1:2, CartesianIndex(1, 2)) == [10, 30] @test @inferred da3[1, CartesianIndices((1:2, 1:1))] isa DimArray @@ -231,7 +231,7 @@ end @test a == [1, 3] @test typeof(a) <: DimArray{Int,1} @test dims(a) == (X(Sampled(143.0:2.0:145.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) - @test refdims(a) == + @test refdims(a) == (Ti(1:1), Y(Sampled(-38.0:2.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) @test name(a) == :test @test metadata(a) === ameta @@ -245,7 +245,7 @@ end @test typeof(a) <: DimArray{Int,1} @test typeof(parent(a)) <: Array{Int,1} @test dims(a) == (Y(Sampled(-38.0:2.0:-36.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) - @test refdims(a) == + @test refdims(a) == (Ti(1:1), X(Sampled(143.0:2.0:143.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) @test name(a) == :test @test metadata(a) == ameta @@ -288,7 +288,7 @@ end @test da == da1 @test da == da2 end - + @testset "selectors work" begin @test @inferred da[At(143), -38.0..36.0] == [1, 2] @test @inferred da[144.0..146.0, Near(-37.1)] == [3] @@ -303,7 +303,7 @@ end @test typeof(parent(v)) <:SubArray{Int,0} @test typeof(dims(v)) == Tuple{} @test dims(v) == () - @test refdims(v) == + @test refdims(v) == (Ti(1:1), X(Sampled(143.0:2.0:143, ForwardOrdered(), Regular(2.0), Points(), xmeta)), Y(Sampled(-38.0:2.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta))) @test name(v) == :test @@ -316,7 +316,7 @@ end @test typeof(parent(v)) <: SubArray{Int,1} @test typeof(dims(v)) <: Tuple{<:X} @test dims(v) == (X(Sampled(143.0:2.0:145.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) - @test refdims(v) == + @test refdims(v) == (Ti(1:1), Y(Sampled(-38.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) @test name(v) == :test @test metadata(v) == ameta @@ -340,7 +340,7 @@ end @test typeof(parent(v)) <: SubArray{Int,1} @test typeof(dims(v)) <: Tuple{<:Y} @test dims(v) == (Y(Sampled(-38.0:2.0:-36.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) - @test refdims(v) == + @test refdims(v) == (Ti(1:1), X(Sampled(143.0:2.0:143.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) @test bounds(v) == ((-38.0, -36.0),) @@ -361,7 +361,7 @@ end for inds in ((1,), (1, 1), (2, 1, 1), (CartesianIndex(2),)) @test typeof(parent(view(da1, inds...))) === typeof(view(parent(da1), inds...)) @test parent(view(da1, inds...)) == view(parent(da1), inds...) - a = view(da1, inds...) + a = view(da1, inds...) @test a isa DimArray{eltype(da1),0} @test length(dims(a)) == 0 @test length(refdims(a)) == 1 @@ -387,7 +387,7 @@ end @testset "setindex!" begin da_set = deepcopy(da) - da_set[X(2), Y(2)] = 77 + da_set[X(2), Y(2)] = 77 @test da_set == [1 2; 3 77] da_set[X(1:2), Y(1)] .= 99 @test da_set == [99 2; 99 77] @@ -423,8 +423,8 @@ end end @testset "Cartesian indices work as usual" begin - @test da[CartesianIndex(2, 2)] == 4 - @test view(da, CartesianIndex(2, 2)) == view(parent(da), 2, 2) + @test da[CartesianIndex(2, 2)] == 4 + @test view(da, CartesianIndex(2, 2)) == view(parent(da), 2, 2) da_set = deepcopy(da) da_set[CartesianIndex(2, 2)] = 5 @test da_set[2, 2] == 5 @@ -487,7 +487,7 @@ end # Type inference breaks with 6 arguments. # @inferred getindex(da2, a=1, b=2, c=3, d=4, e=5, f=6) # @code_warntype getindex(da2, a=1, b=2, c=3, d=4, e=5, f=6) - + end @testset "trailing colon" begin @@ -526,33 +526,33 @@ end @testset "cartesian Int" begin @inferred s[1, 1] @inferred view(s, 1, 1) - @test view(s, Begin, Begin)[] === view(s, 1, 1)[] === + @test view(s, Begin, Begin)[] === view(s, 1, 1)[] === s[Begin, Begin] === s[1, 1] === (one=1.0, two=2.0f0, three=3) - @test view(s_mixed, 1, 1)[] == view(s_mixed, 1, 1)[] == + @test view(s_mixed, 1, 1)[] == view(s_mixed, 1, 1)[] == s_mixed[Begin, Begin] == (one=1.0, two=2.0f0, three=3, four=4) end @testset "cartesian mixed" begin - @inferred s[At(:a), :] + @inferred s[At(:a), :] @inferred view(s, At(:a), :) - @inferred s_mixed[At(:a), :] + @inferred s_mixed[At(:a), :] @inferred view(s_mixed, At(:a), :) - @test s[At(:a), :] == view(s, At(:a), :) == - s[1, :] == view(s, 1, :) == - s[Begin, :] == view(s, Begin, :) == - s[1, 1:3] == view(s, 1, 1:3) == - s[1, Begin:End] == view(s, 1, Begin:End) == + @test s[At(:a), :] == view(s, At(:a), :) == + s[1, :] == view(s, 1, :) == + s[Begin, :] == view(s, Begin, :) == + s[1, 1:3] == view(s, 1, 1:3) == + s[1, Begin:End] == view(s, 1, Begin:End) == s[X=1, Y=Begin:End] == view(s, X=1, Y=Begin:End) == s[X=At(:a), Y=Begin:End] == view(s, X=At(:a), Y=Begin:End) == s[Y=Begin:End, X=1] == view(s, Y=Begin:End, X=1) == DimStack((one=[1.0, 2.0, 3.0], two=[2.0f0, 4.0f0, 6.0f0], three=[3, 6, 9]), (Y(10.0:10:30.0),)) y = dims(s, Y) - @test s_mixed[At(:a), :] == view(s_mixed, At(:a), :) == - s_mixed[1, :] == view(s_mixed, 1, :) == - s_mixed[Begin, :] == view(s_mixed, Begin, :) == - s_mixed[1, 1:3] == view(s_mixed, 1, 1:3) == - s_mixed[1, Begin:End] == view(s_mixed, 1, Begin:End) == + @test s_mixed[At(:a), :] == view(s_mixed, At(:a), :) == + s_mixed[1, :] == view(s_mixed, 1, :) == + s_mixed[Begin, :] == view(s_mixed, Begin, :) == + s_mixed[1, 1:3] == view(s_mixed, 1, 1:3) == + s_mixed[1, Begin:End] == view(s_mixed, 1, Begin:End) == s_mixed[X=1, Y=Begin:End] == view(s_mixed, X=1, Y=Begin:End) == s_mixed[X=At(:a), Y=Begin:End] == view(s_mixed, X=At(:a), Y=Begin:End) == s_mixed[Y=Begin:End, X=1] == view(s_mixed, Y=Begin:End, X=1) == @@ -563,7 +563,7 @@ end s1d = s[X(2)] @inferred s[1] @inferred s[:] - @inferred s[[1, 2]] + @inferred s[[1, 2]] @inferred s[1:2] @inferred s1d[1] @inferred s1d[:] @@ -590,8 +590,8 @@ end @testset "Colon and Vector{Int/Bool} indexing" begin b = [false, false, false, true, false, true] v = [4, 6] - @test s[:][b] == s[b] == - s[:][v] == s[v] == [s[4], s[6]] == + @test s[:][b] == s[b] == + s[:][v] == s[v] == [s[4], s[6]] == view(s, :)[b] == view(s, b) == view(s, :)[v] == view(s, v) == [ (one = 5.0, two = 10.0, three = 15), @@ -599,7 +599,7 @@ end ] @test s_mixed[:][b] == s_mixed[b] == s_mixed[:][v] == s_mixed[v] == [s_mixed[4], s_mixed[6]] == - view(s_mixed, :)[b] == view(s_mixed, b) == + view(s_mixed, :)[b] == view(s_mixed, b) == view(s_mixed, :)[v] == view(s_mixed, v) == [ (one = 5.0, two = 10.0, three = 15, four=16), (one = 6.0, two = 12.0, three = 18, four=16), @@ -621,28 +621,28 @@ end @testset "CartesianIndex" begin @inferred s[CartesianIndex(2, 2)] @inferred view(s, CartesianIndex(2, 2)) - @test s[CartesianIndex(2, 2)] == + @test s[CartesianIndex(2, 2)] == view(s, CartesianIndex(2, 2))[] == (one=5.0, two=10.0, three=15.0) end @testset "CartesianIndices" begin @inferred s[CartesianIndices((1, 2))] @inferred view(s, CartesianIndices((1, 2))) - @test s[CartesianIndices((1, 2))] == + @test s[CartesianIndices((1, 2))] == view(s, CartesianIndices((1, 2))) == s[X=1:1, Y=1:2] end @testset "CartesianIndex Vector" begin @inferred s[[CartesianIndex(1, 2)]] - @inferred view(s, [CartesianIndex(1, 2)]) - @test s[[CartesianIndex(1, 2)]] == + @inferred view(s, [CartesianIndex(1, 2)]) + @test s[[CartesianIndex(1, 2)]] == view(s, [CartesianIndex(1, 2)]) == s[[3]] end @testset "Mixed CartesianIndex and CartesianIndices" begin - da3d = cat(da1, 10da1; dims=Z) + da3d = cat(da1, 10da1; dims=Z) s3 = merge(s, (; ten=da3d)) @test @inferred s3[2, CartesianIndex(2, 2)] === (one=5.0, two=10.0f0, three=15, ten=50.0) @test @inferred view(s3, 1:2, CartesianIndex(1, 2)) isa DimStack @@ -687,9 +687,9 @@ end s_set[1] = (one=4, two=5, three=6) @test s_set[1, 1] === (one=4.0, two=5.0f0, three=6) s_set[1, 1] = (one=9, two=10, three=11) - @test s_set[1, 1] === (one=9.0, two=10.0f0, three=11) + @test s_set[1, 1] === (one=9.0, two=10.0f0, three=11) s_set[X=At(:b), Y=At(10.0)] = (one=7, two=11, three=13) - @test s_set[2, 1] === (one=7.0, two=11.0f0, three=13) + @test s_set[2, 1] === (one=7.0, two=11.0f0, three=13) s_set = deepcopy(s) s_set[CartesianIndex(2, 2)] = (one=5, two=6, three=7) @@ -808,3 +808,39 @@ end @test Base.checkindex(Bool, 1:10, Begin:2:8) end end + +@testset "order breaking indexing" begin + @testset "on Ordered dimensions" begin + A = DimArray(reshape(1:12, 3, 4), (X(Sampled(3:-1:1; order=ReverseOrdered())), Y(10:10:40))) + @testset "Sorted Int vectors works" begin + @test A[X([1, 3]), Y([2, 4])] == [4 10; 6 12] + end + @testset "Unsorted Int vector throws ArgumentError" begin + @test_throws ArgumentError A[X([1, 3]), Y([4, 2])] + @test_throws ArgumentError A[X([3, 1]), Y([2, 4])] + end + @testset "@inbounds skips order checks" begin + f(A, i) = (@inbounds A[i]) + @test_nowarn f(A, (X([1, 3]), Y([4, 2]))) + @test_nowarn f(A, (X([3, 1]), Y([2, 4]))) + end + @testset "strict_order!(false) skips order checks" begin + DimensionalData.strict_order!(false) + @test DimensionalData.strict_order() == false + @test_nowarn A[(X([1, 3]), Y([4, 2]))] + @test_nowarn A[(X([3, 1]), Y([2, 4]))] + DimensionalData.strict_order!(true) + @test DimensionalData.strict_order() + end + end + + @testset "on Unordered dimension" begin + A = DimArray(reshape(1:12, 3, 4), (X(Sampled([3, 1, 2]; order=Unordered())), Y(10:10:40))) + @testset "Unsorted Int vector on Unordered works" begin + @test A[X([3, 1, 2]), Y([2, 4])] == [6 12; 4 10; 5 11] + end + @testset "Unsorted Int vector on Ordered throws ArgumentError" begin + @test_throws ArgumentError A[X([1, 3]), Y([4, 1, 2])] + end + end +end From 72ba19a5b3f6553914264dc9df38bb91bd8a2589 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Wed, 5 Nov 2025 21:44:41 +1100 Subject: [PATCH 4/9] dont remove whitespace --- test/indexing.jl | 134 +++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/test/indexing.jl b/test/indexing.jl index 527267fae..2d32f3820 100644 --- a/test/indexing.jl +++ b/test/indexing.jl @@ -35,40 +35,40 @@ end @test l[Begin+1:End-1] ==l[Begin+1:4] == l[2:End-1] == l[2:4] @test l[Begin:End] isa typeof(l) @test l[1:5] isa typeof(l) - @test l[[1, 3, 4]] == view(l, [1, 3, 4]) == + @test l[[1, 3, 4]] == view(l, [1, 3, 4]) == Base.dotview(l, [1, 3, 4]) == Sampled([2.0, 6.0, 8.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), NoMetadata()) - @test l[Int[]] == view(l, Int[]) == Base.dotview(l, Int[]) == + @test l[Int[]] == view(l, Int[]) == Base.dotview(l, Int[]) == Sampled(Float64[], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Near(2.1)] == Base.dotview(l, Near(2.1)) == 2.0 @test view(l, Near(2.1)) == fill(2.0) - @test l[[false, true, true, false, true]] == - view(l, [false, true, true, false, true]) == - Base.dotview(l, [false, true, true, false, true]) == + @test l[[false, true, true, false, true]] == + view(l, [false, true, true, false, true]) == + Base.dotview(l, [false, true, true, false, true]) == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[2] == Base.dotview(l, 2) === 4.0 @test view(l, 2) == fill(4.0) @test l[CartesianIndex((4,))] === Base.dotview(l, CartesianIndex((4,))) === 8.0 @test view(l, CartesianIndex((4,))) == fill(8.0) - @test l[CartesianIndices((1:3,))] == - view(l, CartesianIndices((1:3,))) == - Base.dotview(l, CartesianIndices((1:3,))) == + @test l[CartesianIndices((1:3,))] == + view(l, CartesianIndices((1:3,))) == + Base.dotview(l, CartesianIndices((1:3,))) == Sampled(2.0:2.0:6.0, ForwardOrdered(), Regular(2.0), Points(), NoMetadata()) - @test l[2:2:4] == - view(l, 2:2:4) == - Base.dotview(l, 2:2:4) == + @test l[2:2:4] == + view(l, 2:2:4) == + Base.dotview(l, 2:2:4) == Sampled(4.0:4.0:8.0, ForwardOrdered(), Regular(4.0), Points(), nothing) # End Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus DateTime l = Sampled(DateTime(2001, 1, 1):Day(1):DateTime(2001, 1, 5), ForwardOrdered(), Regular(Day(1)), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([DateTime(2001, 1, 2), DateTime(2001, 1, 3), DateTime(2001, 1, 5)], ForwardOrdered(), Irregular(nothing, nothing), Points(), nothing) # Reverse l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) @@ -78,7 +78,7 @@ end @test l[[1, 3, 4]] == Sampled([10.0, 6.0, 4.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Int[]] == Sampled(Float64[], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) @test l[2] === 8.0 @test l[CartesianIndex((4,))] == 4.0 @@ -86,15 +86,15 @@ end @test l[2:2:4] == Sampled(8.0:-4.0:4.0, ReverseOrdered(), Regular(-4.0), Points(), nothing) # End Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) # Center Locus DateTime l = Sampled(DateTime(2001, 1, 5):Day(-1):DateTime(2001, 1, 1), ReverseOrdered(), Regular(Day(-1)), Points(), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([DateTime(2001, 1, 4), DateTime(2001, 1, 3), DateTime(2001, 1, 1)], ReverseOrdered(), Irregular(nothing, nothing), Points(), nothing) end @@ -107,20 +107,20 @@ end @test l[[1, 3, 4]] == Sampled([2.0, 6.0, 8.0], ForwardOrdered(), Irregular(2.0, 10.0), Intervals(Start()), nothing) @test l[Int[]] == Sampled(Float64[], ForwardOrdered(), Irregular(nothing, nothing), Intervals(Start()), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(4.0, 12.0), Intervals(Start()), nothing) @test l[2] === 4.0 @test l[CartesianIndex((4,))] == 8.0 - @test l[CartesianIndices((1:3,))] == + @test l[CartesianIndices((1:3,))] == Sampled(2.0:2.0:6.0, ForwardOrdered(), Regular(2.0), Intervals(Start()), NoMetadata()) @test l[2:2:4] == Sampled(4.0:4.0:8.0, ForwardOrdered(), Regular(4.0), Intervals(Start()), nothing) # End Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Intervals(End()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(2.0, 10.0), Intervals(End()), nothing) # Center Locus l = Sampled(2.0:2.0:10.0, ForwardOrdered(), Regular(2.0), Intervals(Center()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([4.0, 6.0, 10.0], ForwardOrdered(), Irregular(3.0, 11.0), Intervals(Center()), nothing) # Reverse Start Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(Start()), nothing) @@ -129,27 +129,27 @@ end @test l[1:5] isa typeof(l) @test l[[1, 3, 4]] == Sampled([10.0, 6.0, 4.0], ReverseOrdered(), Irregular(4.0, 12.0), Intervals(Start()), nothing) @test l[Near(2.1)] == 2.0 - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(2.0, 10.0), Intervals(Start()), nothing) @test l[2] === 8.0 @test l[CartesianIndex((4,))] == 4.0 - @test l[CartesianIndices((1:3,))] == + @test l[CartesianIndices((1:3,))] == Sampled(10.0:-2.0:6.0, ReverseOrdered(), Regular(-2.0), Intervals(Start()), nothing) @test l[2:2:4] == Sampled(8.0:-4.0:4.0, ReverseOrdered(), Regular(-4.0), Intervals(Start()), nothing) # End Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(End()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(0.0, 8.0), Intervals(End()), nothing) # Center Locus l = Sampled(10.0:-2.0:2.0, ReverseOrdered(), Regular(-2.0), Intervals(Center()), nothing) - @test l[[false, true, true, false, true]] == + @test l[[false, true, true, false, true]] == Sampled([8.0, 6.0, 2.0], ReverseOrdered(), Irregular(1.0, 9.0), Intervals(Center()), nothing) end @testset "NoLookup" begin nl = NoLookup(1:100) @test nl[100] == 100 @test nl[1:5] isa typeof(nl) - @test nl[CartesianIndex((1,))] == 1 + @test nl[CartesianIndex((1,))] == 1 @test view(nl, 50) === view(1:100, 50) @test Base.dotview(nl, 50) === 50 end @@ -173,7 +173,7 @@ end d = Y(NoLookup(1:100)) @test d[100] == 100 @test d[1:5] isa typeof(d) - @test d[CartesianIndex((1,))] == 1 + @test d[CartesianIndex((1,))] == 1 @test view(d, 50) === view(1:100, 50) @test Base.dotview(d, 50) === 50 end @@ -205,8 +205,8 @@ end @test da[:] == da[Begin:End] == vec(da) b = @inferred da[[!iseven(i) for i in 1:length(da)]] @test b isa Array - @test b == da[1:2:end] == da[Begin:2:End] - + @test b == da[1:2:end] == da[Begin:2:End] + v = @inferred da[1, :] @test v isa DimVector @test @inferred v[1:2] isa DimArray @@ -218,7 +218,7 @@ end end @testset "mixed CartesianIndex and CartesianIndices indexing works" begin - da3 = cat(da, 10da; dims=Z) + da3 = cat(da, 10da; dims=Z) @test @inferred da3[1, CartesianIndex(1, 2)] == 10 @test @inferred view(da3, 1:2, CartesianIndex(1, 2)) == [10, 30] @test @inferred da3[1, CartesianIndices((1:2, 1:1))] isa DimArray @@ -231,7 +231,7 @@ end @test a == [1, 3] @test typeof(a) <: DimArray{Int,1} @test dims(a) == (X(Sampled(143.0:2.0:145.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) - @test refdims(a) == + @test refdims(a) == (Ti(1:1), Y(Sampled(-38.0:2.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) @test name(a) == :test @test metadata(a) === ameta @@ -245,7 +245,7 @@ end @test typeof(a) <: DimArray{Int,1} @test typeof(parent(a)) <: Array{Int,1} @test dims(a) == (Y(Sampled(-38.0:2.0:-36.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) - @test refdims(a) == + @test refdims(a) == (Ti(1:1), X(Sampled(143.0:2.0:143.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) @test name(a) == :test @test metadata(a) == ameta @@ -288,7 +288,7 @@ end @test da == da1 @test da == da2 end - + @testset "selectors work" begin @test @inferred da[At(143), -38.0..36.0] == [1, 2] @test @inferred da[144.0..146.0, Near(-37.1)] == [3] @@ -303,7 +303,7 @@ end @test typeof(parent(v)) <:SubArray{Int,0} @test typeof(dims(v)) == Tuple{} @test dims(v) == () - @test refdims(v) == + @test refdims(v) == (Ti(1:1), X(Sampled(143.0:2.0:143, ForwardOrdered(), Regular(2.0), Points(), xmeta)), Y(Sampled(-38.0:2.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta))) @test name(v) == :test @@ -316,7 +316,7 @@ end @test typeof(parent(v)) <: SubArray{Int,1} @test typeof(dims(v)) <: Tuple{<:X} @test dims(v) == (X(Sampled(143.0:2.0:145.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) - @test refdims(v) == + @test refdims(v) == (Ti(1:1), Y(Sampled(-38.0:-38.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) @test name(v) == :test @test metadata(v) == ameta @@ -340,7 +340,7 @@ end @test typeof(parent(v)) <: SubArray{Int,1} @test typeof(dims(v)) <: Tuple{<:Y} @test dims(v) == (Y(Sampled(-38.0:2.0:-36.0, ForwardOrdered(), Regular(2.0), Points(), ymeta)),) - @test refdims(v) == + @test refdims(v) == (Ti(1:1), X(Sampled(143.0:2.0:143.0, ForwardOrdered(), Regular(2.0), Points(), xmeta)),) @test bounds(v) == ((-38.0, -36.0),) @@ -361,7 +361,7 @@ end for inds in ((1,), (1, 1), (2, 1, 1), (CartesianIndex(2),)) @test typeof(parent(view(da1, inds...))) === typeof(view(parent(da1), inds...)) @test parent(view(da1, inds...)) == view(parent(da1), inds...) - a = view(da1, inds...) + a = view(da1, inds...) @test a isa DimArray{eltype(da1),0} @test length(dims(a)) == 0 @test length(refdims(a)) == 1 @@ -387,7 +387,7 @@ end @testset "setindex!" begin da_set = deepcopy(da) - da_set[X(2), Y(2)] = 77 + da_set[X(2), Y(2)] = 77 @test da_set == [1 2; 3 77] da_set[X(1:2), Y(1)] .= 99 @test da_set == [99 2; 99 77] @@ -423,8 +423,8 @@ end end @testset "Cartesian indices work as usual" begin - @test da[CartesianIndex(2, 2)] == 4 - @test view(da, CartesianIndex(2, 2)) == view(parent(da), 2, 2) + @test da[CartesianIndex(2, 2)] == 4 + @test view(da, CartesianIndex(2, 2)) == view(parent(da), 2, 2) da_set = deepcopy(da) da_set[CartesianIndex(2, 2)] = 5 @test da_set[2, 2] == 5 @@ -487,7 +487,7 @@ end # Type inference breaks with 6 arguments. # @inferred getindex(da2, a=1, b=2, c=3, d=4, e=5, f=6) # @code_warntype getindex(da2, a=1, b=2, c=3, d=4, e=5, f=6) - + end @testset "trailing colon" begin @@ -526,33 +526,33 @@ end @testset "cartesian Int" begin @inferred s[1, 1] @inferred view(s, 1, 1) - @test view(s, Begin, Begin)[] === view(s, 1, 1)[] === + @test view(s, Begin, Begin)[] === view(s, 1, 1)[] === s[Begin, Begin] === s[1, 1] === (one=1.0, two=2.0f0, three=3) - @test view(s_mixed, 1, 1)[] == view(s_mixed, 1, 1)[] == + @test view(s_mixed, 1, 1)[] == view(s_mixed, 1, 1)[] == s_mixed[Begin, Begin] == (one=1.0, two=2.0f0, three=3, four=4) end @testset "cartesian mixed" begin - @inferred s[At(:a), :] + @inferred s[At(:a), :] @inferred view(s, At(:a), :) - @inferred s_mixed[At(:a), :] + @inferred s_mixed[At(:a), :] @inferred view(s_mixed, At(:a), :) - @test s[At(:a), :] == view(s, At(:a), :) == - s[1, :] == view(s, 1, :) == - s[Begin, :] == view(s, Begin, :) == - s[1, 1:3] == view(s, 1, 1:3) == - s[1, Begin:End] == view(s, 1, Begin:End) == + @test s[At(:a), :] == view(s, At(:a), :) == + s[1, :] == view(s, 1, :) == + s[Begin, :] == view(s, Begin, :) == + s[1, 1:3] == view(s, 1, 1:3) == + s[1, Begin:End] == view(s, 1, Begin:End) == s[X=1, Y=Begin:End] == view(s, X=1, Y=Begin:End) == s[X=At(:a), Y=Begin:End] == view(s, X=At(:a), Y=Begin:End) == s[Y=Begin:End, X=1] == view(s, Y=Begin:End, X=1) == DimStack((one=[1.0, 2.0, 3.0], two=[2.0f0, 4.0f0, 6.0f0], three=[3, 6, 9]), (Y(10.0:10:30.0),)) y = dims(s, Y) - @test s_mixed[At(:a), :] == view(s_mixed, At(:a), :) == - s_mixed[1, :] == view(s_mixed, 1, :) == - s_mixed[Begin, :] == view(s_mixed, Begin, :) == - s_mixed[1, 1:3] == view(s_mixed, 1, 1:3) == - s_mixed[1, Begin:End] == view(s_mixed, 1, Begin:End) == + @test s_mixed[At(:a), :] == view(s_mixed, At(:a), :) == + s_mixed[1, :] == view(s_mixed, 1, :) == + s_mixed[Begin, :] == view(s_mixed, Begin, :) == + s_mixed[1, 1:3] == view(s_mixed, 1, 1:3) == + s_mixed[1, Begin:End] == view(s_mixed, 1, Begin:End) == s_mixed[X=1, Y=Begin:End] == view(s_mixed, X=1, Y=Begin:End) == s_mixed[X=At(:a), Y=Begin:End] == view(s_mixed, X=At(:a), Y=Begin:End) == s_mixed[Y=Begin:End, X=1] == view(s_mixed, Y=Begin:End, X=1) == @@ -563,7 +563,7 @@ end s1d = s[X(2)] @inferred s[1] @inferred s[:] - @inferred s[[1, 2]] + @inferred s[[1, 2]] @inferred s[1:2] @inferred s1d[1] @inferred s1d[:] @@ -590,8 +590,8 @@ end @testset "Colon and Vector{Int/Bool} indexing" begin b = [false, false, false, true, false, true] v = [4, 6] - @test s[:][b] == s[b] == - s[:][v] == s[v] == [s[4], s[6]] == + @test s[:][b] == s[b] == + s[:][v] == s[v] == [s[4], s[6]] == view(s, :)[b] == view(s, b) == view(s, :)[v] == view(s, v) == [ (one = 5.0, two = 10.0, three = 15), @@ -599,7 +599,7 @@ end ] @test s_mixed[:][b] == s_mixed[b] == s_mixed[:][v] == s_mixed[v] == [s_mixed[4], s_mixed[6]] == - view(s_mixed, :)[b] == view(s_mixed, b) == + view(s_mixed, :)[b] == view(s_mixed, b) == view(s_mixed, :)[v] == view(s_mixed, v) == [ (one = 5.0, two = 10.0, three = 15, four=16), (one = 6.0, two = 12.0, three = 18, four=16), @@ -621,28 +621,28 @@ end @testset "CartesianIndex" begin @inferred s[CartesianIndex(2, 2)] @inferred view(s, CartesianIndex(2, 2)) - @test s[CartesianIndex(2, 2)] == + @test s[CartesianIndex(2, 2)] == view(s, CartesianIndex(2, 2))[] == (one=5.0, two=10.0, three=15.0) end @testset "CartesianIndices" begin @inferred s[CartesianIndices((1, 2))] @inferred view(s, CartesianIndices((1, 2))) - @test s[CartesianIndices((1, 2))] == + @test s[CartesianIndices((1, 2))] == view(s, CartesianIndices((1, 2))) == s[X=1:1, Y=1:2] end @testset "CartesianIndex Vector" begin @inferred s[[CartesianIndex(1, 2)]] - @inferred view(s, [CartesianIndex(1, 2)]) - @test s[[CartesianIndex(1, 2)]] == + @inferred view(s, [CartesianIndex(1, 2)]) + @test s[[CartesianIndex(1, 2)]] == view(s, [CartesianIndex(1, 2)]) == s[[3]] end @testset "Mixed CartesianIndex and CartesianIndices" begin - da3d = cat(da1, 10da1; dims=Z) + da3d = cat(da1, 10da1; dims=Z) s3 = merge(s, (; ten=da3d)) @test @inferred s3[2, CartesianIndex(2, 2)] === (one=5.0, two=10.0f0, three=15, ten=50.0) @test @inferred view(s3, 1:2, CartesianIndex(1, 2)) isa DimStack @@ -687,9 +687,9 @@ end s_set[1] = (one=4, two=5, three=6) @test s_set[1, 1] === (one=4.0, two=5.0f0, three=6) s_set[1, 1] = (one=9, two=10, three=11) - @test s_set[1, 1] === (one=9.0, two=10.0f0, three=11) + @test s_set[1, 1] === (one=9.0, two=10.0f0, three=11) s_set[X=At(:b), Y=At(10.0)] = (one=7, two=11, three=13) - @test s_set[2, 1] === (one=7.0, two=11.0f0, three=13) + @test s_set[2, 1] === (one=7.0, two=11.0f0, three=13) s_set = deepcopy(s) s_set[CartesianIndex(2, 2)] = (one=5, two=6, three=7) From 930a7cc677d131a0bc0cd5e9bac0d07180f701ab Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Wed, 5 Nov 2025 21:48:06 +1100 Subject: [PATCH 5/9] fix ambiguities --- src/Lookups/indexing.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index be7ffabdc..ce366a40f 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -32,9 +32,9 @@ for f in (:getindex, :view, :dotview) @propagate_inbounds Base.$f(l::Lookup, i::Union{Int,CartesianIndex}) = Base.$f(parent(l), i) # AbstractArray, Colon and CartesianIndices: the lookup is rebuilt around a new parent - @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractVector,Colon}) = + @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractArray,Colon}) = rebuild(l; data=Base.$f(parent(l), i)) - @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractVector{Int}) + @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractArray{Int}) @boundscheck checkorder(l, i) # Allow skipping this check with @inbounds rebuild(l; data=Base.$f(parent(l), i)) @@ -52,7 +52,7 @@ function checkorder(l, i) if strict_order() && isordered(l) issorted(i) || throw(ArgumentError(""" For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order. - Use `@inbounds` to avoid this check locally, and `DimensionalData.strict_order!(false)` globally. + Use `@inbounds` to avoid this check locally, and `DimensionalData.strict_order!(false)` it globally. """)) end end From fa804ac5e91fd75c41a191f8138f9340d9eb3cb5 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Thu, 6 Nov 2025 13:06:57 +1100 Subject: [PATCH 6/9] bugfix and reorganise --- src/Lookups/indexing.jl | 22 ++++++++++++++++++---- src/Lookups/lookup_arrays.jl | 10 ---------- test/indexing.jl | 4 ++-- test/runtests.jl | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index ce366a40f..329689e5c 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -34,13 +34,25 @@ for f in (:getindex, :view, :dotview) # AbstractArray, Colon and CartesianIndices: the lookup is rebuilt around a new parent @propagate_inbounds Base.$f(l::Lookup, i::Union{AbstractArray,Colon}) = rebuild(l; data=Base.$f(parent(l), i)) - @propagate_inbounds function Base.$f(l::Union{Sampled,Categorical}, i::AbstractArray{Int}) + # span may need its step size or bounds updated + @propagate_inbounds function Base.$f(l::AbstractSampled, i::AbstractArray) + i1 = Base.to_indices(l, (i,))[1] + rebuild(l; data=Base.$f(parent(l), i1), span=slicespan(l, i1)) + end + # With ordered lookups AbstractArray{Integer} needs to be ordered + @propagate_inbounds function Base.$f(l::AbstractSampled, i::AbstractArray{<:Integer}) + @boundscheck checkorder(l, i) + i1 = only(Base.to_indices(l, (i,))) + rebuild(l; data=Base.$f(parent(l), i1), span=slicespan(l, i1)) + end + @propagate_inbounds function Base.$f(l::AbstractCategorical, i::AbstractArray{<:Integer}) @boundscheck checkorder(l, i) - # Allow skipping this check with @inbounds rebuild(l; data=Base.$f(parent(l), i)) end # Selector gets processed with `selectindices` - @propagate_inbounds Base.$f(l::Lookup, i::SelectorOrInterval) = Base.$f(l, selectindices(l, i)) + @propagate_inbounds Base.$f(l::Lookup, i::SelectorOrInterval) = + Base.$f(l, selectindices(l, i)) + # Everything else we just index the parent and check if the result is an array @propagate_inbounds function Base.$f(l::Lookup, i) x = Base.$f(parent(l), i) x isa AbstractArray ? rebuild(l; data=x) : x @@ -52,7 +64,9 @@ function checkorder(l, i) if strict_order() && isordered(l) issorted(i) || throw(ArgumentError(""" For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order. - Use `@inbounds` to avoid this check locally, and `DimensionalData.strict_order!(false)` it globally. + Use `@inbounds` to avoid this check inside a specific function, or `DimensionalData.strict_order!(false)` globally. """)) end end +# Avoid checks for Bool, Bool indexing is ordered +checkorder(l, i::AbstractArray{Bool}) = nothing diff --git a/src/Lookups/lookup_arrays.jl b/src/Lookups/lookup_arrays.jl index 7c254eb44..364a73d3c 100644 --- a/src/Lookups/lookup_arrays.jl +++ b/src/Lookups/lookup_arrays.jl @@ -188,16 +188,6 @@ function Base.:(==)(l1::AbstractSampled, l2::AbstractSampled) parent(l1) == parent(l2) end -for f in (:getindex, :view, :dotview) - @eval begin - # span may need its step size or bounds updated - @propagate_inbounds function Base.$f(l::AbstractSampled, i::AbstractArray) - i1 = Base.to_indices(l, (i,))[1] - rebuild(l; data=Base.$f(parent(l), i1), span=slicespan(l, i1)) - end - end -end - function Adapt.adapt_structure(to, l::AbstractSampled) rebuild(l; data=Adapt.adapt(to, parent(l)), metadata=NoMetadata(), span=Adapt.adapt(to, span(l))) end diff --git a/test/indexing.jl b/test/indexing.jl index 2d32f3820..f068f510a 100644 --- a/test/indexing.jl +++ b/test/indexing.jl @@ -266,8 +266,8 @@ end @test bounds(a) == ((143.0, 145.0), (-38.0, -36.0)) @test bounds(a, X) == (143.0, 145.0) - a = da[X([2, 1]), Y([2, 1])] # Indexing with array works - @test a == [4 3; 2 1] + # Indexing with array works + @test da[X([1, 2]), Y([1, 2])] == [1 2; 3 4] end @testset "dimindices and dimselectors" begin diff --git a/test/runtests.jl b/test/runtests.jl index 18cfd1815..bf7b29be0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,7 +20,7 @@ end @time @safetestset "dimension" begin include("dimension.jl") end @time @safetestset "primitives" begin include("primitives.jl") end @time @safetestset "lookup" begin include("lookup.jl") end -@time @safetestset "selector" begin include("selector.jl") end +@time @safetestset "slector" begin include("selector.jl") end @time @safetestset "merged" begin include("merged.jl") end @time @safetestset "DimUnitRange" begin include("dimunitrange.jl") end @time @safetestset "format" begin include("format.jl") end From 0332371daa0b87d659ac2682211861b6eb8edc1d Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Sat, 8 Nov 2025 14:57:07 +1100 Subject: [PATCH 7/9] fix ambiguity --- src/Lookups/indexing.jl | 8 +++++++- src/Lookups/lookup_arrays.jl | 7 ------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Lookups/indexing.jl b/src/Lookups/indexing.jl index 329689e5c..7ed7839bb 100644 --- a/src/Lookups/indexing.jl +++ b/src/Lookups/indexing.jl @@ -49,6 +49,12 @@ for f in (:getindex, :view, :dotview) @boundscheck checkorder(l, i) rebuild(l; data=Base.$f(parent(l), i)) end + # Indexing AbstractCyclic with `AbstractArray` must rebuild the lookup as + # `Sampled` as we no longer have the whole cycle. + @propagate_inbounds function Base.$f(l::AbstractCyclic, i::AbstractArray{<:Integer}) + @boundscheck checkorder(l, i) + Sampled(rebuild(l; data=Base.$f(parent(l), i))) + end # Selector gets processed with `selectindices` @propagate_inbounds Base.$f(l::Lookup, i::SelectorOrInterval) = Base.$f(l, selectindices(l, i)) @@ -64,7 +70,7 @@ function checkorder(l, i) if strict_order() && isordered(l) issorted(i) || throw(ArgumentError(""" For `ForwardOrdered` or `ReverseOrdered` lookups, indices of `AbstractVector{Int}` must be in ascending order. - Use `@inbounds` to avoid this check inside a specific function, or `DimensionalData.strict_order!(false)` globally. + Use `@inbounds` to avoid this check locally, or `DimensionalData.strict_order!(false)` globally. """)) end end diff --git a/src/Lookups/lookup_arrays.jl b/src/Lookups/lookup_arrays.jl index 364a73d3c..d126fcc6d 100644 --- a/src/Lookups/lookup_arrays.jl +++ b/src/Lookups/lookup_arrays.jl @@ -335,13 +335,6 @@ cycle_status(l::AbstractCyclic) = l.cycle_status bounds(l::AbstractCyclic{<:Any,T}) where T = (typemin(T), typemax(T)) -# Indexing with `AbstractArray` must rebuild the lookup as -# `Sampled` as we no longer have the whole cycle. -for f in (:getindex, :view, :dotview) - @eval @propagate_inbounds Base.$f(l::AbstractCyclic, i::AbstractArray) = - Sampled(rebuild(l; data=Base.$f(parent(l), i))) -end - no_cycling(l::AbstractCyclic) = rebuild(l; cycle_status=NotCycling()) From 26469d1abefc6cba481238808dbb8393fb0cc565 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Sat, 8 Nov 2025 14:57:32 +1100 Subject: [PATCH 8/9] fix tests name --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index bf7b29be0..18cfd1815 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,7 +20,7 @@ end @time @safetestset "dimension" begin include("dimension.jl") end @time @safetestset "primitives" begin include("primitives.jl") end @time @safetestset "lookup" begin include("lookup.jl") end -@time @safetestset "slector" begin include("selector.jl") end +@time @safetestset "selector" begin include("selector.jl") end @time @safetestset "merged" begin include("merged.jl") end @time @safetestset "DimUnitRange" begin include("dimunitrange.jl") end @time @safetestset "format" begin include("format.jl") end From 1fe2468be55ec10adf885e17f58dc9629e10d18b Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Fri, 14 Nov 2025 14:03:14 +1100 Subject: [PATCH 9/9] move Statistics to extras --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4bf406104..4cf11ff3a 100644 --- a/Project.toml +++ b/Project.toml @@ -19,7 +19,6 @@ OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TableTraits = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" @@ -128,6 +127,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"