Skip to content

Commit 626407c

Browse files
committed
set tweaks
1 parent 68be9bc commit 626407c

9 files changed

Lines changed: 162 additions & 77 deletions

File tree

src/DimensionalData.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ using .Dimensions: StandardIndices, DimOrDimType, DimTuple, DimTupleOrEmpty, Dim
4141
import .Dimensions: dims, refdims, name, lookup, kw2dims, hasdim, label, checkaxes, _astuple
4242

4343
import .Lookups: Safety, Safe, Unsafe, SelectorOrInterval, Begin, End
44-
import .Lookups: metadata, reorder, set, _set, rebuild, basetypeof,
44+
import .Lookups: metadata, reorder, set, unsafe_set, _set, rebuild, basetypeof,
4545
order, span, sampling, locus, val, index, bounds, intervalbounds,
4646
hasselection, units
4747

src/Dimensions/set.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ unsafe_set(dims::DimTuple, a1::Union{Dimension,Pair}, a2::Union{Dimension,Pair},
1313
_set(Unsafe(), dims, a1, a2, args...)
1414

1515
_set(s::Safety, dims::DimTuple, l::LookupSetters) =
16-
_set(s, dims, map(d -> basedims(d) => l, dims)...)
16+
_set(s, dims, map(d -> rebuild(d, l), dims)...)
1717

1818
# Convert pairs to wrapped dims and set
1919
_set(s::Safety, dims::DimTuple, p::Pair, ps::Pair...) =
@@ -40,10 +40,12 @@ end
4040
# Set things wrapped in dims
4141
_set(s::Safety, dim::Dimension, wrapper::Dimension{<:DimSetters}) = begin
4242
rewrapped = _set(s, dim, basetypeof(wrapper))
43-
@show rewrapped val(wrapper)
44-
x = _set(s, rewrapped, val(wrapper))
45-
@show x
46-
x
43+
_set(s, rewrapped, val(wrapper))
44+
end
45+
_set(s::Safety, dim::Dimension, l::Union{Lookup,LookupSetters}) = begin
46+
re = rebuild(dim, _set(s, val(dim), l))
47+
@show typeof(re) typeof(val(dim))
48+
re
4749
end
4850
# Set the dim, checking the lookup
4951
_set(s::Safety, dim::Dimension, newdim::Dimension) =

src/Lookups/set.jl

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,41 +31,45 @@ _set_lookup(s::Safety, lookup::AbstractCategorical, newlookup::AutoLookup) = beg
3131
l1 = _set(Unsafe(), lookup, order(newlookup))
3232
l2 =_set(Unsafe(), l1, parent(newlookup))
3333
l3 = _set(s, l2, order(newlookup))
34-
_set(l3, metadata(newlookup))
34+
_set(s, l3, metadata(newlookup))
3535
end
3636
_set_lookup(s::Safety, lookup::AbstractSampled, newlookup::AutoLookup) = begin
3737
# With autolookup we have to allow for missing fields and detect them
3838
# First force the new order to avoid unnecessary reordering of arrays
39-
lookup2 =_set(Unsafe(), lookup, order(newlookup))
4039
# Then update lookup values
4140
lookup1 =_set(s, lookup, parent(newlookup))
42-
# Then set the order again in case it changed
43-
lookup2 =_set(s, lookup, order(newlookup))
41+
# Then set the order
42+
lookup2 =_set(s, lookup1, order(newlookup))
4443
# Then set the span
45-
lookup3 =_set(s, lookup, span(newlookup))
44+
lookup3 =_set(s, lookup2, span(newlookup))
4645
# Then set traits that dont affect each other
4746
sa =_set(s, sampling(lookup3), sampling(newlookup))
4847
md =_set(s, metadata(lookup3), metadata(newlookup))
4948
rebuild(lookup3; sampling=sa, metadata=md)
5049
end
51-
_set_lookup(s::Safety, lookup::Lookup, newlookup::AbstractCategorical) = begin
50+
_set_lookup(s::Unsafe, lookup::Lookup, newlookup::AbstractCategorical) = begin
51+
lookup =_set(s, lookup, parent(newlookup))
52+
o = _set(s, order(lookup), order(newlookup))
53+
md = _set(s, metadata(lookup), metadata(newlookup))
54+
rebuild(newlookup; data=parent(lookup), order=o, metadata=md)
55+
end
56+
_set_lookup(s::Safe, lookup::Lookup, newlookup::AbstractCategorical) = begin
5257
lookup =_set(Unsafe(), lookup, parent(newlookup))
53-
o =_set(s, order(lookup), order(newlookup))
54-
md =_set(s, metadata(lookup), metadata(newlookup))
58+
o = _format(order(newlookup), AnonDim, parent(newlookup))
59+
md = _set(s, metadata(lookup), metadata(newlookup))
5560
rebuild(newlookup; data=parent(lookup), order=o, metadata=md)
5661
end
5762
_set_lookup(s::Unsafe, lookup::Lookup, newlookup::AbstractSampled) =
5863
_set_lookup_parent(s, lookup, parent(newlookup))
59-
_set_lookup(s::Safety, lookup::Lookup, newlookup::AbstractSampled) = begin
64+
_set_lookup(s::Safe, lookup::Lookup, newlookup::AbstractSampled) = begin
6065
# Update each field separately. The old lookup may not have these fields, or may have
6166
# a subset with the rest being traits. The new lookup may have some auto fields.
62-
data =_set_lookup_parent(s, lookup, parent(newlookup))
63-
o =_set(s, order(lookup), order(newlookup))
64-
sp =_set(s, span(lookup), span(newlookup))
65-
sa =_set(s, sampling(lookup), sampling(newlookup))
66-
md =_set(s, metadata(lookup), metadata(newlookup))
67+
o = _format(order(newlookup), AnonDim, parent(newlookup))
68+
sp = _format(span(newlookup), AnonDim, parent(newlookup))
69+
sa = _set(s, sampling(lookup), sampling(newlookup))
70+
md = _set(s, metadata(lookup), metadata(newlookup))
6771
# Rebuild the new lookup with the merged fields
68-
rebuild(newlookup; data, order=o, span=sp, sampling=sa, metadata=md)
72+
rebuild(newlookup1; data, order=o, span=sp, sampling=sa, metadata=md)
6973
end
7074
_set_lookup(::Safety, lookup::Lookup, newlookup::NoLookup{<:AutoValues}) = NoLookup(axes(lookup, 1))
7175
_set_lookup(::Safety, lookup::Lookup, newlookup::AbstractNoLookup) = newlookup
@@ -100,8 +104,8 @@ _set_lookup_parent(s::Safe, lookup::AbstractSampled, values::AbstractVector) = b
100104
end
101105

102106
# Order
103-
_set_lookup_property(::Safe, lookup::Lookup, neworder::AutoOrder) = Lookup
104-
_set_lookup_property(::Unsafe, lookup::Lookup, neworder::AutoOrder) = Lookup
107+
_set_lookup_property(::Safe, lookup::Lookup, neworder::AutoOrder) = lookup
108+
_set_lookup_property(::Unsafe, lookup::Lookup, neworder::AutoOrder) = lookup
105109
_set_lookup_property(::Safe, lookup::AbstractNoLookup, neworder::AutoOrder) = lookup
106110
_set_lookup_property(::Unsafe, lookup::AbstractNoLookup, neworder::AutoOrder) = lookup
107111
_set_lookup_property(::Safe, lookup::AbstractNoLookup, neworder::Order) = lookup
@@ -110,8 +114,11 @@ _set_lookup_property(::Unsafe, lookup::AbstractNoLookup, neworder::Order) = look
110114
_set_lookup_property(s::Unsafe, lookup::Lookup, neworder::Order) =
111115
rebuild(lookup; order=_set(s, order(lookup), neworder))
112116
# Safe reorders them to match `neworder`
113-
_set_lookup_property(::Safe, lookup::Lookup, neworder::Order) =
114-
reorder(lookup, neworder)
117+
_set_lookup_property(::Safe, lookup::Lookup, neworder::Order) = begin
118+
re = reorder(lookup, neworder)
119+
@show "here" neworder order(lookup) order(re) span(re)
120+
re
121+
end
115122

116123
# Lookup Span
117124
_set_lookup_property(::Safety, lookup::AbstractSampled, ::Irregular{AutoBounds}) = begin
@@ -123,25 +130,75 @@ _set_lookup_property(::Safety, lookup::AbstractSampled, ::Irregular{AutoBounds})
123130
rebuild(lookup; span=Irregular(bnds))
124131
end
125132
_set_lookup_property(s::Safety, lookup::AbstractSampled, ::Regular{AutoStep}) = begin
126-
stp = if span(lookup) isa AutoSpan || step(lookup) isa AutoStep
127-
if parent(lookup) isa AbstractRange
128-
step(parent(lookup))
129-
else
130-
AutoStep()
131-
end
132-
else
133+
stp = if span(lookup) isa Regular
133134
step(lookup)
135+
else
136+
stp = _detect_span(parent(lookup))
137+
isnothing(stp) && throw(ArgumentError("Can't set an irregular lookup values to Regular"))
138+
stp
134139
end
135140
rebuild(lookup; span=Regular(stp))
136141
end
137-
# Lookup Span
138-
_set_lookup_property(::Safety, lookup::AbstractSampled, span::Span) = rebuild(lookup; span=span)
139-
_set_lookup_property(::Safety, lookup::AbstractSampled, span::AutoSpan) = lookup
142+
_set_lookup_property(::Safety, lookup::AbstractSampled, newspan::AutoSpan) = lookup
143+
_set_lookup_property(s::Safety, lookup::AbstractSampled, newspan::Span) =
144+
_set_lookup_property(s, lookup, span(lookup), newspan)
145+
function _set_lookup_property(
146+
s::Safe, lookup::AbstractSampled, ::Span, ::Explicit{<:AutoBounds}
147+
)
148+
# Generate a new bounds matrix
149+
span = Explicit(reinterpret(reshape, Float64, intervalbounds(lookup)))
150+
# Explicit has to be Intervals
151+
sampling = Intervals(locus(lookup))
152+
return rebuild(lookup; span, sampling)
153+
end
154+
_set_lookup_property(::Safe, lookup::AbstractSampled, ::Explicit, ::Explicit{<:AutoBounds}) =
155+
lookup
156+
function _set_lookup_property(::Safety, lookup::AbstractSampled, ::Span, span::Explicit)
157+
rebuild(lookup; span, sampling=Intervals(locus(lookup)))
158+
end
159+
function _set_lookup_property(
160+
::Safe, lookup::AbstractSampled, ::Span, ::Regular{<:AutoStep}
161+
)
162+
rebuild(lookup; sampling=Intervals(bounds(lookup)))
163+
end
164+
function _set_lookup_property(
165+
::Safe, lookup::AbstractSampled, ::Span, ::Irregular{<:AutoBounds}
166+
)
167+
rebuild(lookup; sampling=Intervals(bounds(lookup)))
168+
end
169+
_set_lookup_property(::Safety, lookup::AbstractSampled, ::Span, newspan::Span) =
170+
rebuild(lookup; span)
140171
# Lookup Sampling
141-
# TODO does this need to fix bounds?
142-
_set_lookup_property(s::Safety, lookup::AbstractSampled, newsampling::Sampling) =
143-
rebuild(lookup; sampling=_set(s, sampling(lookup), newsampling))
144-
_set_lookup_property(::Safety, lookup::AbstractSampled, sampling::AutoSampling) = lookup
172+
function _set_lookup_property(s::Safe, lookup::AbstractSampled, newsampling::Sampling)
173+
s = _set(s, sampling(lookup), newsampling)
174+
# If the locus is currently points, make it Center Intervals
175+
if sampling(lookup) isa Points
176+
if s isa Intervals # Points => Intervals
177+
span1 = if span(lookup) isa Irregular
178+
# We don't know the bounds
179+
Irregular(nothing, nothing)
180+
else
181+
span(lookup)
182+
end
183+
lookup1 = rebuild(lookup; sampling=Intervals(Center()))
184+
else # Points => Points, Nothing to do here
185+
return lookup
186+
end
187+
else # Intervals => Points
188+
span1 = if span(lookup) isa Union{Irregular,Explicit}
189+
# We don't need bounds for Points
190+
Irregular(nothing, nothing)
191+
else # Regular stays the same
192+
span(lookup)
193+
end
194+
lookup1 = lookup
195+
end
196+
# For Intervals this will shift the locus
197+
# For Points always convert all loci to Center()
198+
return rebuild(shiftlocus(locus(s), lookup1); sampling=s)
199+
end
200+
_set_lookup_property(s::Unsafe, lookup::AbstractSampled, sampling::Sampling) =
201+
rebuild(lookup; sampling=_set(s, sampling(lookup), sampling))
145202
# Lookup Locus
146203
_set_lookup_property(s::Unsafe, lookup::AbstractSampled, locus::Locus) =
147204
rebuild(lookup; sampling=_set(s, sampling(lookup), locus))
@@ -175,4 +232,13 @@ _set(::Safety, metadata::AllMetadata, newmetadata::AllMetadata) = newmetadata
175232
_set(::Safety, A, x) = _cantseterror(A, x)
176233

177234
@noinline _locuserror() = throw(ArgumentError("Can't set a locus for `Points` sampling other than `Center` - the lookup values are the exact points"))
178-
@noinline _cantseterror(a, b) = throw(ArgumentError("Can not set any fields of $(typeof(a)) to $(typeof(b))"))
235+
@noinline _cantseterror(a, b) = throw(ArgumentError("Can not set any fields of $(typeof(a)) to $(typeof(b))"))
236+
237+
_detect_step(A::AbstractRange) = step(A)
238+
function _detect_step(A::AbstractVector)
239+
step = first(A) - last(A) / (length(A) - 1)
240+
for i in eachindex(A)
241+
isapprox(A[i], first(A) + step * (i - 1)) || return nothing
242+
end
243+
return step
244+
end

src/Lookups/utils.jl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,16 @@ _reorder(lookup::Lookup, neworder::Order) =
128128
_reorder(lookup, order(lookup), neworder)
129129
# Same order, do nothing
130130
_reorder(lookup::Lookup, ::O, ::O) where {O<:Ordered} = lookup
131-
_reorder(lookup::Lookup, ::U, ::U) where {U<:Unordered} = lookup
131+
_reorder(lookup::Lookup, ::O, ::O) where {O<:Unordered} = lookup
132132
# We can always convert to `Unordered` without changing the lookup
133133
_reorder(lookup::Lookup, ::Ordered, neworder::Unordered) =
134134
rebuild(lookup; order=neworder)
135-
# To set with `Ordered` we need to sort
136-
_reorder(lookup::Lookup, ::Unordered, neworder::ForwardOrdered) =
137-
rebuild(lookup; data=sort(parent(lookup)), order=neworder)
138-
_reorder(lookup::Lookup, ::Unordered, neworder::ReverseOrdered) =
139-
rebuild(lookup; data=sort(parent(lookup); rev=true), order=neworder)
140135
# Different order, reverse the lookup
141-
function _reorder(lookup::Lookup, ::Ordered, neworder::Ordered)
142-
newdata = reverse(parent(lookup))
143-
rebuild(lookup; data=newdata, order=neworder)
136+
_reorder(lookup::Lookup, ::Ordered, neworder::Ordered) = reverse(lookup)
137+
# To set to `Ordered` we need to sort
138+
function _reorder(l::Lookup, ::Unordered, o::Ordered)
139+
# We use sortperm then index in case there is a bounds matrix
140+
# or similar, rather than just sort on lookup values
141+
idxs = sortperm(l; rev=isrev(o))
142+
return rebuild(l[idxs]; order=o)
144143
end

src/dimindices.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ metadata(A::DimExtensionArray) = metadata(A._data)
508508
newrealdims = dims(newdims, realdims)
509509
newdata = rebuild(A; data=newrealparent, dims=newrealdims)
510510
rebuild(de; _data=newdata, dims=newdims, refdims=newrefdims)
511-
endU
511+
end
512512
end
513513
@propagate_inbounds function rebuildsliced(
514514
f::Function, de::DimExtensionArray{<:Any,1}, I::Tuple{<:Union{Colon,AbstractRange}}

src/set.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ function _set(s::Safety, A::AbstractDimArray;
180180
end
181181

182182
end
183-
@show typeof(A1)
184183
# Just `rebuild` everything else, it's assumed to have no interactions.
185184
# Package developers note: if other fields do interact, implement this
186185
# method for your own `AbstractDimArray` type.
@@ -203,6 +202,8 @@ function _set(s::Safety, st::AbstractDimStack;
203202
end
204203

205204
# Dimensions and pairs are set for dimensions
205+
# Short circuit here to avoid multiple allocations
206+
# end
206207
function _set(
207208
s::Safety, A::AbstractDimArray, args::Union{Dimension,DimTuple,Pair}...
208209
)
@@ -222,7 +223,7 @@ function _set(
222223
# that match the dims of this layer
223224
map(val, dims(dim_updates, lds))
224225
end
225-
rebuild(_maybe_reorder(s, st, newdims); layerdims=lds)
226+
rebuild(_rebuild_maybe_reorder(s, st, newdims); layerdims=lds)
226227
end
227228
end
228229
# Single traits are set for all dimensions
@@ -272,7 +273,7 @@ function _rebuild_maybe_reorder(::Safe, A, newdims)
272273
if map(order, dims(A)) == map(order, newdims)
273274
rebuild(A; dims=newdims)
274275
else
275-
newdata = parent(reorder(A, map(rebuild, dims(A), order(newdims))))
276-
rebuild(A; data=newdata, dims=newdims)
276+
A1 = reorder(A, map(rebuild, dims(A), order(newdims)))
277+
rebuild(A; data=parent(A1), dims=newdims)
277278
end
278279
end

src/utils.jl

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ reorder(x::Reorderable, A::Union{AbstractDimArray,AbstractDimStack,AbstractDimIn
3939
reorder(x, dims(A))
4040
reorder(x::Reorderable, ::Nothing) = throw(ArgumentError("object has no dimensions"))
4141
reorder(x::Reorderable, p::Pair, ps::Pair...) = reorder(x, (p, ps...))
42-
reorder(x, ps::Tuple{Vararg{Pair}}) = reorder(x, Dimensions.pairs2dims(ps...))
42+
reorder(x::Reorderable, ps::Tuple{Vararg{Pair}}) = reorder(x, Dimensions.pairs2dims(ps...))
4343
reorder(x::Reorderable, ::Type{O}) where O<:Order = reorder(x, O())
4444
function reorder(x::Reorderable, o::Order)
4545
ds = dims(x)
@@ -64,10 +64,6 @@ reorder(ds::DimTuple, orderdims::Tuple{}) = ds
6464
reorder(x::Reorderable, orderdim::Dimension{<:Order}) = _reorder(x, dims(x, orderdim), val(orderdim))
6565
reorder(x::Reorderable, orderdim::Dimension{<:Lookup}) = _reorder(x, dims(x, orderdim), order(orderdim))
6666

67-
reorder(x::DimensionOrLookup, o::Order) = _reorder(x, o)
68-
reorder(x::DimensionOrLookup, l::Lookup) = _reorder(x, order(l))
69-
reorder(x::DimensionOrLookup, d::Dimension) = _reorder(x, order(d))
70-
7167
# Unordered: do nothing, just set the order to Unordered
7268
_reorder(x::Reorderable, dim::Dimension, o::Unordered) = unsafe_set(x, dim => o)
7369
# Ordered: leave, reverse or sort
@@ -77,25 +73,27 @@ _reorder(x::Reorderable, dim::Dimension, ::O, ::O) where O<:Ordered = x
7773
# dimensional reverse can handle this
7874
_reorder(x::Reorderable, dim::Dimension, ::Ordered, ::Ordered) =
7975
reverse(x; dims=basedims(dim))
80-
# We need to sort the data along this dimension
81-
function _reorder(x::Reorderable, dim::Dimension, ::Unordered, o::Ordered)
76+
function _reorder(x::AbstractDimIndices, dim::Dimension, o1::Unordered, o2::Ordered)
77+
newdim = _reorder(dims(x, dim), o1, o2)
78+
return unsafe_set(x, newdim)
8279
end
80+
# We need to sort the data along this dimension
8381
function _reorder(
8482
x::Union{AbstractDimArray,AbstractDimStack}, dim::Dimension, ::Unordered, o::Ordered
8583
)
8684
l = lookup(dim)
87-
# Make value => index pairs
88-
pairs = parent(l) .=> eachindex(l)
8985
# Sort forwards or reverse
90-
o isa ForwardOrdered ? sort!(pairs) : sort!(pairs; rev=true)
91-
# Get the indices
92-
idxs = last.(pairs)
86+
idxs = o isa ForwardOrdered ? sortperm(l) : sortperm(l; rev=true)
9387
# Reorder the values by indexing into dimension of dim
9488
output = x[rebuild(dim, idxs)]
9589
# Set the order
9690
return unsafe_set(output, dim => o)
9791
end
9892

93+
reorder(x::Dimension, o::Order) = rebuild(x, _reorder(lookup(x), o))
94+
reorder(x::Dimension, l::Lookup) = _reorder(x, order(l))
95+
reorder(x::Dimension, d::Dimension) = _reorder(x, order(d))
96+
9997
# Unordered: do nothing, just set the order to Unordered
10098
_reorder(x::DimensionOrLookup, o::Unordered) = unsafe_set(x, o)
10199
# Ordered: leave, reverse or sort
@@ -107,11 +105,6 @@ _reorder(x::DimensionOrLookup, ::Ordered, ::Ordered) = reverse(x)
107105
# We need to sort
108106
_reorder(dim::Dimension, ::Unordered, o::Ordered) =
109107
rebuild(dim, reorder(lookup(dim), o))
110-
function _reorder(l::Lookup, ::Unordered, o::Ordered)
111-
vals = collect(l)
112-
o isa ForwardOrdered ? sort!(vals) : sort!(vals; rev=true)
113-
return rebuild(l; data=vals, order=o)
114-
end
115108

116109
"""
117110
modify(f, A::AbstractDimArray) => AbstractDimArray
@@ -244,8 +237,7 @@ end
244237
function uniquekeys(das::Vector{<:AbstractDimArray})
245238
length(das) == 0 ? Symbol[] : uniquekeys(map(Symbol name, das))
246239
end
247-
function uniquekeys(keys::Vector{Symbol})
248-
map(enumerate(keys)) do (id, k)
240+
function uniquekeys(keys::Vector{Symbol}) map(enumerate(keys)) do (id, k)
249241
count(k1 -> k == k1, keys) > 1 ? Symbol(:layer, id) : k
250242
end
251243
end

0 commit comments

Comments
 (0)