@@ -6,34 +6,31 @@ mutable struct RefArray{R}
6
6
end
7
7
8
8
"""
9
- ScaledArray{T,N,RA,S ,P} <: AbstractArray{T,N}
9
+ ScaledArray{T,R, N,RA,P} <: AbstractArray{T,N}
10
10
11
11
An array type that stores data as indices of a range.
12
12
13
13
# Fields
14
14
- `refs::RA<:AbstractArray{<:Any, N}`: an array of indices.
15
- - `start::T`: the starting value of the range.
16
- - `step::S`: the step size of the range.
17
- - `stop::T`: the stopping value of the range.
18
15
- `pool::P<:AbstractRange{T}`: a range that covers all possible values stored by the array.
16
+ - `invpool::Dict{T,R}`: a map from array elements to indices of `pool`.
19
17
"""
20
- mutable struct ScaledArray{T,N,RA,S ,P} <: AbstractArray{T,N}
18
+ mutable struct ScaledArray{T,R, N,RA,P} <: AbstractArray{T,N}
21
19
refs:: RA
22
- start:: T
23
- step:: S
24
- stop:: T
25
20
pool:: P
26
- ScaledArray {T,N,RA,S,P} (rs :: RefArray{RA} , start :: T , step :: S , stop :: T ,
27
- pool:: P = start : step : stop ) where
28
- {T, N, RA<: AbstractArray{<:Any , N} , S , P<: AbstractRange{T} } =
29
- new {T,N,RA,S, P} (rs. a, start, step, stop, pool )
21
+ invpool :: Dict{T,R}
22
+ ScaledArray {T,R,N,RA,P} (rs :: RefArray{RA} , pool:: P , invpool :: Dict{T,R} ) where
23
+ {T, R, N, RA<: AbstractArray{R , N} , P<: AbstractRange{T} } =
24
+ new {T,R, N,RA,P} (rs. a, pool, invpool )
30
25
end
31
26
32
- ScaledArray (rs:: RefArray{RA} , start :: T , step :: S , stop :: T , pool :: P = start : step : stop ) where
33
- {T,RA,S, P} = ScaledArray {T,ndims(RA),RA,S, P} (rs, start, step, stop, pool )
27
+ ScaledArray (rs:: RefArray{RA} , pool :: P , invpool :: Dict{T,R} ) where
28
+ {T,R,RA <: AbstractArray{R} , P} = ScaledArray {T,R, ndims(RA),RA,P} (rs, pool, invpool )
34
29
35
- const ScaledVector{T} = ScaledArray{T,1 }
36
- const ScaledMatrix{T} = ScaledArray{T,2 }
30
+ const ScaledVector{T,R} = ScaledArray{T,R,1 }
31
+ const ScaledMatrix{T,R} = ScaledArray{T,R,2 }
32
+
33
+ scale (sa:: ScaledArray ) = step (sa. pool)
37
34
38
35
function _validmin (min, xmin, isstart:: Bool )
39
36
if min === nothing
@@ -55,10 +52,11 @@ function _validmax(max, xmax, isstart::Bool)
55
52
return max
56
53
end
57
54
58
- function validstartstepstop (x:: AbstractArray , start, step, stop, usepool)
55
+ function validpool (x:: AbstractArray , T :: Type , start, step, stop, usepool:: Bool )
59
56
step === nothing && throw (ArgumentError (" step cannot be nothing" ))
60
57
pool = DataAPI. refpool (x)
61
- xmin, xmax = usepool && pool != = nothing ? extrema (pool) : extrema (x)
58
+ xs = skipmissing (usepool && pool != = nothing ? pool : x)
59
+ xmin, xmax = extrema (xs)
62
60
applicable (+ , xmin, step) || throw (ArgumentError (
63
61
" step of type $(typeof (step)) does not match array with element type $(eltype (x)) " ))
64
62
if xmin + step > xmin
@@ -70,47 +68,83 @@ function validstartstepstop(x::AbstractArray, start, step, stop, usepool)
70
68
else
71
69
throw (ArgumentError (" step cannot be zero" ))
72
70
end
73
- T = promote_type (eltype (x), eltype (start: step: stop))
74
- return convert (T, start), convert (T, stop)
71
+ start = convert (T, start)
72
+ stop = convert (T, stop)
73
+ return start: step: stop
75
74
end
76
75
77
- function _scaledlabel (x:: AbstractArray , step, reftype:: Type{<:Signed} = DEFAULT_REF_TYPE;
78
- start= nothing , stop= nothing , usepool:: Bool = true )
79
- start, stop = validstartstepstop (x, start, step, stop, usepool)
80
- pool = start: step: stop
81
- while typemax (reftype) < length (pool)
82
- reftype = widen (reftype)
76
+ function _scaledlabel! (labels:: AbstractArray , invpool:: Dict , xs:: AbstractArray , start, step)
77
+ z = zero (valtype (invpool))
78
+ @inbounds for i in eachindex (labels)
79
+ x = xs[i]
80
+ lbl = get (invpool, x, z)
81
+ if lbl != = z
82
+ labels[i] = lbl
83
+ elseif ismissing (x)
84
+ labels[i] = z
85
+ invpool[x] = z
86
+ else
87
+ r = start: step: x
88
+ lbl = length (r)
89
+ labels[i] = lbl
90
+ invpool[x] = lbl
91
+ end
83
92
end
84
- refs = similar (x, reftype)
85
- @inbounds for i in eachindex (refs)
86
- refs[i] = length (start: step: x[i])
93
+ end
94
+
95
+ function scaledlabel (xs:: AbstractArray , stepsize,
96
+ R:: Type = DEFAULT_REF_TYPE, T:: Type = eltype (xs);
97
+ start= nothing , stop= nothing , usepool:: Bool = true )
98
+ pool = validpool (xs, T, start, stepsize, stop, usepool)
99
+ T = Missing <: T ? Union{eltype (pool), Missing} : eltype (pool)
100
+ start = first (pool)
101
+ stepsize = step (pool)
102
+ if R <: Integer
103
+ while typemax (R) < length (pool)
104
+ R = widen (R)
105
+ end
87
106
end
88
- return refs, start, step, stop
107
+ labels = similar (xs, R)
108
+ invpool = Dict {T,R} ()
109
+ _scaledlabel! (labels, invpool, xs, start, stepsize)
110
+ return labels, pool, invpool
89
111
end
90
112
91
- function ScaledArray (x:: AbstractArray , reftype:: Type , start, step, stop, usepool:: Bool = true )
92
- refs, start, step, stop = _scaledlabel (x, step, reftype; start= start, stop= stop, usepool= usepool)
93
- return ScaledArray (RefArray (refs), start, step, stop )
113
+ function ScaledArray (x:: AbstractArray , reftype:: Type , xtype :: Type , start, step, stop, usepool:: Bool = true )
114
+ refs, pool, invpool = scaledlabel (x, step, reftype, xtype ; start= start, stop= stop, usepool= usepool)
115
+ return ScaledArray (RefArray (refs), pool, invpool )
94
116
end
95
117
96
- function ScaledArray (sa:: ScaledArray , reftype:: Type , start, step, stop, usepool:: Bool = true )
97
- if step != = nothing && step != sa . step
98
- refs, start, step, stop = _scaledlabel (sa, step, reftype; start= start, stop= stop, usepool= usepool)
99
- return ScaledArray (RefArray (refs), start, step, stop )
118
+ function ScaledArray (sa:: ScaledArray , reftype:: Type , xtype :: Type , start, step, stop, usepool:: Bool = true )
119
+ if step != = nothing && step != scale (sa)
120
+ refs, pool, invpool = scaledlabel (sa, step, reftype, xtype ; start= start, stop= stop, usepool= usepool)
121
+ return ScaledArray (RefArray (refs), pool, invpool )
100
122
else
101
- step = sa. step
102
- start, stop = validstartstepstop (sa, start, step, stop, usepool)
123
+ step = scale (sa)
124
+ pool = validpool (sa, xtype, start, step, stop, usepool)
125
+ T = Missing <: xtype ? Union{eltype (pool), Missing} : eltype (pool)
103
126
refs = similar (sa. refs, reftype)
104
- if start == sa. start
127
+ invpool = Dict {T, reftype} ()
128
+ start0 = first (sa. pool)
129
+ start = first (pool)
130
+ stop = last (pool)
131
+ if start == start0
105
132
copy! (refs, sa. refs)
106
- elseif start < sa. start && start < stop || start > sa. start && start > stop
107
- offset = length (start: step: sa. start) - 1
133
+ copy! (invpool, sa. invpool)
134
+ elseif start < start0 && start < stop || start > start0 && start > stop
135
+ offset = length (start: step: start0) - 1
108
136
refs .= sa. refs .+ offset
137
+ for (k, v) in sa. invpool
138
+ invpool[k] = v + offset
139
+ end
109
140
else
110
- offset = length (sa . start : step: start) - 1
141
+ offset = length (start0 : step: start) - 1
111
142
refs .= sa. refs .- offset
143
+ for (k, v) in sa. invpool
144
+ invpool[k] = v - offset
145
+ end
112
146
end
113
- return ScaledArray (RefArray (refs), start, step, stop )
147
+ return ScaledArray (RefArray (refs), pool, invpool )
114
148
end
115
149
end
116
150
@@ -126,39 +160,43 @@ If `start` or `stop` is not specified, it will be chosen based on the extrema of
126
160
- `usepool::Bool=true`: find extrema of `x` based on `DataAPI.refpool`.
127
161
"""
128
162
ScaledArray (x:: AbstractArray , start, step, stop= nothing ;
129
- reftype:: Type = DEFAULT_REF_TYPE, usepool:: Bool = true ) =
130
- ScaledArray (x, reftype, start, step, stop, usepool)
163
+ reftype:: Type = DEFAULT_REF_TYPE, xtype :: Type = eltype (x), usepool:: Bool = true ) =
164
+ ScaledArray (x, reftype, xtype, start, step, stop, usepool)
131
165
132
166
ScaledArray (sa:: ScaledArray , start, step, stop= nothing ;
133
- reftype:: Type = eltype (refarray (sa)), usepool:: Bool = true ) =
134
- ScaledArray (sa, reftype, start, step, stop, usepool)
167
+ reftype:: Type = eltype (refarray (sa)), xtype :: Type = eltype (sa), usepool:: Bool = true ) =
168
+ ScaledArray (sa, reftype, xtype, start, step, stop, usepool)
135
169
136
170
ScaledArray (x:: AbstractArray , step; reftype:: Type = DEFAULT_REF_TYPE,
137
- start= nothing , stop= nothing , usepool:: Bool = true ) =
138
- ScaledArray (x, reftype, start, step, stop, usepool)
171
+ start= nothing , stop= nothing , xtype :: Type = eltype (x), usepool:: Bool = true ) =
172
+ ScaledArray (x, reftype, xtype, start, step, stop, usepool)
139
173
140
174
ScaledArray (sa:: ScaledArray , step= nothing ; reftype:: Type = eltype (refarray (sa)),
141
- start= nothing , stop= nothing , usepool:: Bool = true ) =
142
- ScaledArray (sa, reftype, start, step, stop, usepool)
175
+ start= nothing , stop= nothing , xtype :: Type = eltype (sa), usepool:: Bool = true ) =
176
+ ScaledArray (sa, reftype, xtype, start, step, stop, usepool)
143
177
144
178
Base. size (sa:: ScaledArray ) = size (sa. refs)
145
- Base. IndexStyle (:: Type{<:ScaledArray{T,N,RA}} ) where {T,N,RA} = IndexStyle (RA)
179
+ Base. IndexStyle (:: Type{<:ScaledArray{T,R, N,RA}} ) where {T,R ,N,RA} = IndexStyle (RA)
146
180
147
181
DataAPI. refarray (sa:: ScaledArray ) = sa. refs
148
182
DataAPI. refvalue (sa:: ScaledArray , n:: Integer ) = getindex (DataAPI. refpool (sa), n)
149
183
DataAPI. refpool (sa:: ScaledArray ) = sa. pool
184
+ DataAPI. invrefpool (sa:: ScaledArray ) = sa. invpool
150
185
151
186
DataAPI. refarray (ssa:: SubArray{<:Any, <:Any, <:ScaledArray} ) =
152
187
view (parent (ssa). refs, ssa. indices... )
153
188
DataAPI. refvalue (ssa:: SubArray{<:Any, <:Any, <:ScaledArray} , n:: Integer ) =
154
189
DataAPI. refvalue (parent (ssa), n)
155
190
DataAPI. refpool (ssa:: SubArray{<:Any, <:Any, <:ScaledArray} ) =
156
191
DataAPI. refpool (parent (ssa))
192
+ DataAPI. invrefpool (ssa:: SubArray{<:Any, <:Any, <:ScaledArray} ) =
193
+ DataAPI. invrefpool (parent (ssa))
157
194
158
195
@inline function Base. getindex (sa:: ScaledArray , i:: Int )
159
196
refs = DataAPI. refarray (sa)
160
197
@boundscheck checkbounds (refs, i)
161
198
@inbounds n = refs[i]
199
+ iszero (n) && return missing
162
200
pool = DataAPI. refpool (sa)
163
201
@boundscheck checkbounds (pool, n)
164
202
return @inbounds pool[n]
@@ -169,13 +207,14 @@ end
169
207
@boundscheck checkbounds (refs, I... )
170
208
@inbounds ns = refs[I... ]
171
209
pool = DataAPI. refpool (sa)
172
- @boundscheck checkbounds (pool, ns)
210
+ N = length (pool)
211
+ @boundscheck checkindex (Bool, 0 : N, ns) || throw_boundserror (pool, ns)
173
212
return @inbounds pool[ns]
174
213
end
175
214
176
215
function Base.:(== )(x:: ScaledArray , y:: ScaledArray )
177
216
size (x) == size (y) || return false
178
- x . start == y . start && x . step == y . step && return x. refs == y. refs
217
+ first (x . pool) == first (y . pool) && step (x . pool) == step (y . pool) && return x. refs == y. refs
179
218
eq = true
180
219
for (p, q) in zip (x, y)
181
220
# missing could arise
0 commit comments