101
101
_mapreducedim (f, op, Size (a), a, Val{D}, v0)
102
102
end
103
103
104
- @generated function _mapreducedim (f, op, :: Size{S} , a:: StaticArray , :: Type{Val{D}} ) where {S, D}
104
+ @generated function _mapreducedim (f, op, :: Size{S} , a:: StaticArray , :: Type{Val{D}} ) where {S,D}
105
105
N = length (S)
106
106
Snew = ([n== D ? 1 : S[n] for n = 1 : N]. .. )
107
+ T0 = eltype (a)
108
+ T = :((T1 = Base. promote_op (f, $ T0); Base. promote_op (op, T1, T1)))
107
109
108
110
exprs = Array {Expr} (Snew)
109
111
itr = [1 : n for n ∈ Snew]
@@ -118,14 +120,13 @@ end
118
120
exprs[i... ] = expr
119
121
end
120
122
121
- # TODO element type might change
122
123
return quote
123
124
@_inline_meta
124
- @inbounds return similar_type (a, Size ($ Snew))(tuple ($ (exprs... )))
125
+ @inbounds return similar_type (a, $ T, Size ($ Snew))(tuple ($ (exprs... )))
125
126
end
126
127
end
127
128
128
- @generated function _mapreducedim (f, op, :: Size{S} , a:: StaticArray , :: Type{Val{D}} , v0) where {S, D }
129
+ @generated function _mapreducedim (f, op, :: Size{S} , a:: StaticArray , :: Type{Val{D}} , v0:: T ) where {S,D,T }
129
130
N = length (S)
130
131
Snew = ([n== D ? 1 : S[n] for n = 1 : N]. .. )
131
132
142
143
exprs[i... ] = expr
143
144
end
144
145
145
- # TODO element type might change
146
146
return quote
147
147
@_inline_meta
148
- @inbounds return similar_type (a, Size ($ Snew))(tuple ($ (exprs... )))
148
+ @inbounds return similar_type (a, T, Size ($ Snew))(tuple ($ (exprs... )))
149
149
end
150
150
end
151
151
@@ -160,33 +160,82 @@ end
160
160
# # reducedim ##
161
161
# ##############
162
162
163
- @inline reducedim (op, a:: StaticArray , :: Val{D} ) where {D} = mapreducedim (identity, op, a, Val{D})
164
- @inline reducedim (op, a:: StaticArray , :: Val{D} , v0) where {D} = mapreducedim (identity, op, a, Val{D}, v0)
163
+ @inline reducedim (op, a:: StaticArray , :: Type{ Val{D} } ) where {D} = mapreducedim (identity, op, a, Val{D})
164
+ @inline reducedim (op, a:: StaticArray , :: Type{ Val{D} } , v0) where {D} = mapreducedim (identity, op, a, Val{D}, v0)
165
165
166
166
# ######################
167
167
# # related functions ##
168
168
# ######################
169
169
170
170
# These are all similar in Base but not @inline'd
171
- @inline sum (a:: StaticArray{<:Any, T} ) where {T} = reduce (+ , zero (T), a)
172
- @inline sum (f:: Base.Callable , a:: StaticArray ) = mapreduce (f, + , a)
173
- @inline prod (a:: StaticArray{<:Any, T} ) where {T} = reduce (* , one (T), a)
174
- @inline count (a:: StaticArray{<:Any, Bool} ) = reduce (+ , 0 , a)
175
- @inline all (a:: StaticArray{<:Any, Bool} ) = reduce (& , true , a) # non-branching versions
176
- @inline any (a:: StaticArray{<:Any, Bool} ) = reduce (| , false , a) # (benchmarking needed)
171
+ #
172
+ # Implementation notes:
173
+ #
174
+ # 1. When providing an initial value v0, note that its location is different in reduce and
175
+ # reducedim: v0 comes earlier than collection in reduce, whereas it is the last argument in
176
+ # reducedim. The same difference exists between mapreduce and mapreducedim.
177
+ #
178
+ # 2. mapreduce and mapreducedim usually do not take initial value v0, because we don't
179
+ # always know the return type of an arbitrary mapping function f. (We usually want to use
180
+ # some initial value such as one(T) or zero(T) as v0, where T is the return type of f, but
181
+ # if users provide type-unstable f, its return type cannot be known.) Therefore, mapped
182
+ # versions of the functions implemented below usually require the collection to have at
183
+ # least two entries.
184
+ #
185
+ # 3. Exceptions are the ones that require Boolean mapping functions. For example, f in
186
+ # all and any must return Bool, so we know the appropriate v0 is true and false,
187
+ # respectively. Therefore, all(f, ...) and any(f, ...) are implemented by mapreduce(f, ...)
188
+ # with an initial value v0 = true and false.
189
+ @inline iszero (a:: StaticArray{<:Any,T} ) where {T} = reduce ((x,y) -> x && (y== zero (T)), true , a)
190
+
191
+ @inline sum (a:: StaticArray{<:Any,T} ) where {T} = reduce (+ , zero (T), a)
192
+ @inline sum (f:: Function , a:: StaticArray ) = mapreduce (f, + , a)
193
+ @inline sum (a:: StaticArray{<:Any,T} , :: Type{Val{D}} ) where {T,D} = reducedim (+ , a, Val{D}, zero (T))
194
+ @inline sum (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where D = mapreducedim (f, + , a, Val{D})
195
+
196
+ @inline prod (a:: StaticArray{<:Any,T} ) where {T} = reduce (* , one (T), a)
197
+ @inline prod (f:: Function , a:: StaticArray{<:Any,T} ) where {T} = mapreduce (f, * , a)
198
+ @inline prod (a:: StaticArray{<:Any,T} , :: Type{Val{D}} ) where {T,D} = reducedim (* , a, Val{D}, one (T))
199
+ @inline prod (f:: Function , a:: StaticArray{<:Any,T} , :: Type{Val{D}} ) where {T,D} = mapreducedim (f, * , a, Val{D})
200
+
201
+ @inline count (a:: StaticArray{<:Any,Bool} ) = reduce (+ , 0 , a)
202
+ @inline count (f:: Function , a:: StaticArray ) = mapreduce (x-> f (x):: Bool , + , 0 , a)
203
+ @inline count (a:: StaticArray{<:Any,Bool} , :: Type{Val{D}} ) where {D} = reducedim (+ , a, Val{D}, 0 )
204
+ @inline count (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = mapreducedim (x-> f (x):: Bool , + , a, Val{D}, 0 )
205
+
206
+ @inline all (a:: StaticArray{<:Any,Bool} ) = reduce (& , true , a) # non-branching versions
207
+ @inline all (f:: Function , a:: StaticArray ) = mapreduce (x-> f (x):: Bool , & , true , a)
208
+ @inline all (a:: StaticArray{<:Any,Bool} , :: Type{Val{D}} ) where {D} = reducedim (& , a, Val{D}, true )
209
+ @inline all (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = mapreducedim (x-> f (x):: Bool , & , a, Val{D}, true )
210
+
211
+ @inline any (a:: StaticArray{<:Any,Bool} ) = reduce (| , false , a) # (benchmarking needed)
212
+ @inline any (f:: Function , a:: StaticArray ) = mapreduce (x-> f (x):: Bool , | , false , a) # (benchmarking needed)
213
+ @inline any (a:: StaticArray{<:Any,Bool} , :: Type{Val{D}} ) where {D} = reducedim (| , a, Val{D}, false )
214
+ @inline any (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = mapreducedim (x-> f (x):: Bool , | , a, Val{D}, false )
215
+
177
216
@inline mean (a:: StaticArray ) = sum (a) / length (a)
217
+ @inline mean (f:: Function , a:: StaticArray ) = sum (f, a) / length (a)
218
+ @inline mean (a:: StaticArray , :: Type{Val{D}} ) where {D} = sum (a, Val{D}) / size (a, D)
219
+ @inline mean (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = sum (f, a, Val{D}) / size (a, D)
220
+
178
221
@inline minimum (a:: StaticArray ) = reduce (min, a) # base has mapreduce(idenity, scalarmin, a)
222
+ @inline minimum (f:: Function , a:: StaticArray ) = mapreduce (f, min, a)
223
+ @inline minimum (a:: StaticArray , :: Type{Val{D}} ) where {D} = reducedim (min, a, Val{D})
224
+ @inline minimum (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = mapreducedim (f, min, a, Val{D})
225
+
179
226
@inline maximum (a:: StaticArray ) = reduce (max, a) # base has mapreduce(idenity, scalarmax, a)
180
- @inline minimum (a:: StaticArray , dim:: Type{Val{D}} ) where {D} = reducedim (min, a, dim)
181
- @inline maximum (a:: StaticArray , dim:: Type{Val{D}} ) where {D} = reducedim (max, a, dim)
227
+ @inline maximum (f:: Function , a:: StaticArray ) = mapreduce (f, max, a)
228
+ @inline maximum (a:: StaticArray , :: Type{Val{D}} ) where {D} = reducedim (max, a, Val{D})
229
+ @inline maximum (f:: Function , a:: StaticArray , :: Type{Val{D}} ) where {D} = mapreducedim (f, max, a, Val{D})
182
230
183
231
# Diff is slightly different
184
232
@inline diff (a:: StaticArray ) = diff (a, Val{1 })
185
233
@inline diff (a:: StaticArray , :: Type{Val{D}} ) where {D} = _diff (Size (a), a, Val{D})
186
234
187
- @generated function _diff (:: Size{S} , a:: StaticArray , :: Type{Val{D}} ) where {S, D}
235
+ @generated function _diff (:: Size{S} , a:: StaticArray , :: Type{Val{D}} ) where {S,D}
188
236
N = length (S)
189
237
Snew = ([n== D ? S[n]- 1 : S[n] for n = 1 : N]. .. )
238
+ T = Base. promote_op (- , eltype (a), eltype (a))
190
239
191
240
exprs = Array {Expr} (Snew)
192
241
itr = [1 : n for n = Snew]
197
246
exprs[i1... ] = :(a[$ (i2... )] - a[$ (i1... )])
198
247
end
199
248
200
- # TODO element type might change
201
249
return quote
202
250
@_inline_meta
203
- @inbounds return similar_type (a, Size ($ Snew))(tuple ($ (exprs... )))
251
+ @inbounds return similar_type (a, $ T, Size ($ Snew))(tuple ($ (exprs... )))
204
252
end
205
253
end
0 commit comments