5
5
# ##### Generic (map)reduce functions ######
6
6
7
7
if Int === Int32
8
- const SmallSigned = Union{Int8,Int16}
9
- const SmallUnsigned = Union{UInt8,UInt16}
8
+ const SmallSigned = Union{Int8,Int16}
9
+ const SmallUnsigned = Union{UInt8,UInt16}
10
10
else
11
- const SmallSigned = Union{Int8,Int16,Int32}
12
- const SmallUnsigned = Union{UInt8,UInt16,UInt32}
11
+ const SmallSigned = Union{Int8,Int16,Int32}
12
+ const SmallUnsigned = Union{UInt8,UInt16,UInt32}
13
13
end
14
14
15
- const CommonReduceResult = Union{UInt64,UInt128,Int64,Int128,Float16,Float32,Float64}
16
- const WidenReduceResult = Union{SmallSigned, SmallUnsigned}
17
-
18
- promote_sys_size {T} (:: Type{T} ) = T
19
- promote_sys_size {T<:SmallSigned} (:: Type{T} ) = Int
20
- promote_sys_size {T<:SmallUnsigned} (:: Type{T} ) = UInt
21
- # r_promote_type: promote T to the type of reduce(op, ::Array{T})
22
- # (some "extra" methods are required here to avoid ambiguity warnings)
23
- r_promote_type (op, :: Type{T} ) where {T} = T
24
- r_promote_type (op, :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
25
- r_promote_type (:: typeof (+ ), :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
26
- r_promote_type (:: typeof (* ), :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
27
- r_promote_type (:: typeof (+ ), :: Type{T} ) where {T<: Number } = typeof (zero (T)+ zero (T))
28
- r_promote_type (:: typeof (* ), :: Type{T} ) where {T<: Number } = typeof (one (T)* one (T))
29
- r_promote_type (:: typeof (scalarmax), :: Type{T} ) where {T<: WidenReduceResult } = T
30
- r_promote_type (:: typeof (scalarmin), :: Type{T} ) where {T<: WidenReduceResult } = T
31
- r_promote_type (:: typeof (max), :: Type{T} ) where {T<: WidenReduceResult } = T
32
- r_promote_type (:: typeof (min), :: Type{T} ) where {T<: WidenReduceResult } = T
33
-
34
- # r_promote: promote x to the type of reduce(op, [x])
35
- r_promote (op, x:: T ) where {T} = convert (r_promote_type (op, T), x)
15
+ # Certain reductions like sum and prod may wish to promote the items being
16
+ # reduced over to an appropriate size.
17
+ promote_sys_size (x) = x
18
+ promote_sys_size (x:: SmallSigned ) = Int (x)
19
+ promote_sys_size (x:: SmallUnsigned ) = UInt (x)
36
20
37
21
# # foldl && mapfoldl
38
22
39
23
@noinline function mapfoldl_impl (f, op, v0, itr, i)
40
24
# Unroll the while loop once; if v0 is known, the call to op may
41
25
# be evaluated at compile time
42
26
if done (itr, i)
43
- return r_promote (op, v0)
27
+ return v0
44
28
else
45
29
(x, i) = next (itr, i)
46
- v = op (r_promote (op, v0) , f (x))
30
+ v = op (v0 , f (x))
47
31
while ! done (itr, i)
48
32
@inbounds (x, i) = next (itr, i)
49
33
v = op (v, f (x))
@@ -108,10 +92,10 @@ function mapfoldr_impl(f, op, v0, itr, i::Integer)
108
92
# Unroll the while loop once; if v0 is known, the call to op may
109
93
# be evaluated at compile time
110
94
if isempty (itr) || i == 0
111
- return r_promote (op, v0)
95
+ return v0
112
96
else
113
97
x = itr[i]
114
- v = op (f (x), r_promote (op, v0) )
98
+ v = op (f (x), v0 )
115
99
while i > 1
116
100
x = itr[i -= 1 ]
117
101
v = op (f (x), v)
@@ -180,12 +164,12 @@ foldr(op, itr) = mapfoldr(identity, op, itr)
180
164
@noinline function mapreduce_impl (f, op, A:: AbstractArray , ifirst:: Integer , ilast:: Integer , blksize:: Int )
181
165
if ifirst == ilast
182
166
@inbounds a1 = A[ifirst]
183
- return r_promote (op, f (a1) )
167
+ return f (a1)
184
168
elseif ifirst + blksize > ilast
185
169
# sequential portion
186
170
@inbounds a1 = A[ifirst]
187
171
@inbounds a2 = A[ifirst+ 1 ]
188
- v = op (r_promote (op, f (a1)), r_promote (op, f (a2) ))
172
+ v = op (f (a1), f (a2))
189
173
@simd for i = ifirst + 2 : ilast
190
174
@inbounds ai = A[i]
191
175
v = op (v, f (ai))
@@ -245,17 +229,24 @@ pairwise_blocksize(::typeof(abs2), ::typeof(+)) = 4096
245
229
# handling empty arrays
246
230
_empty_reduce_error () = throw (ArgumentError (" reducing over an empty collection is not allowed" ))
247
231
mr_empty (f, op, T) = _empty_reduce_error ()
248
- # use zero(T)::T to improve type information when zero(T) is not defined
249
- mr_empty (:: typeof (identity), op:: typeof (+ ), T) = r_promote (op, zero (T):: T )
250
- mr_empty (:: typeof (abs), op:: typeof (+ ), T) = r_promote (op, abs (zero (T):: T ))
251
- mr_empty (:: typeof (abs2), op:: typeof (+ ), T) = r_promote (op, abs2 (zero (T):: T ))
252
- mr_empty (:: typeof (identity), op:: typeof (* ), T) = r_promote (op, one (T):: T )
253
- mr_empty (:: typeof (abs), op:: typeof (scalarmax), T) = abs (zero (T):: T )
254
- mr_empty (:: typeof (abs2), op:: typeof (scalarmax), T) = abs2 (zero (T):: T )
232
+ mr_empty (:: typeof (identity), op:: typeof (+ ), T) = zero (T)
233
+ mr_empty (:: typeof (abs), op:: typeof (+ ), T) = abs (zero (T))
234
+ mr_empty (:: typeof (abs2), op:: typeof (+ ), T) = abs2 (zero (T))
235
+ mr_empty (:: typeof (identity), op:: typeof (* ), T) = one (T)
236
+ mr_empty (:: typeof (promote_sys_size), op, T) =
237
+ promote_sys_size (mr_empty (identity, op, T))
238
+ mr_empty (:: typeof (abs), op:: typeof (scalarmax), T) = abs (zero (T))
239
+ mr_empty (:: typeof (abs2), op:: typeof (scalarmax), T) = abs2 (zero (T))
255
240
mr_empty (:: typeof (abs), op:: typeof (max), T) = mr_empty (abs, scalarmax, T)
256
241
mr_empty (:: typeof (abs2), op:: typeof (max), T) = mr_empty (abs2, scalarmax, T)
257
- mr_empty (f, op:: typeof (& ), T) = true
258
- mr_empty (f, op:: typeof (| ), T) = false
242
+ mr_empty (:: typeof (identity), op:: typeof (& ), :: Type{Bool} ) = true
243
+ mr_empty (:: typeof (identity), op:: typeof (| ), :: Type{Bool} ) = false
244
+
245
+ # Allow mr_empty to “see through” promote_sys_size
246
+ let ComposedFunction = typename (typeof (identity ∘ identity)). wrapper
247
+ global mr_empty (f:: ComposedFunction{typeof(promote_sys_size)} , op, T) =
248
+ promote_sys_size (mr_empty (f. g, op, T))
249
+ end
259
250
260
251
mr_empty_iter (f, op, itr, :: HasEltype ) = mr_empty (f, op, eltype (itr))
261
252
mr_empty_iter (f, op:: typeof (& ), itr, :: EltypeUnknown ) = true
@@ -271,12 +262,12 @@ function _mapreduce(f, op, ::IndexLinear, A::AbstractArray{T}) where T
271
262
return mr_empty (f, op, T)
272
263
elseif n == 1
273
264
@inbounds a1 = A[inds[1 ]]
274
- return r_promote (op, f (a1) )
265
+ return f (a1)
275
266
elseif n < 16 # process short array here, avoid mapreduce_impl() compilation
276
267
@inbounds i = inds[1 ]
277
268
@inbounds a1 = A[i]
278
269
@inbounds a2 = A[i+= 1 ]
279
- s = op (r_promote (op, f (a1)), r_promote (op, f (a2) ))
270
+ s = op (f (a1), f (a2))
280
271
while i < last (inds)
281
272
@inbounds Ai = A[i+= 1 ]
282
273
s = op (s, f (Ai))
@@ -352,7 +343,7 @@ julia> sum(abs2, [2; 3; 4])
352
343
29
353
344
```
354
345
"""
355
- sum (f:: Callable , a) = mapreduce (f, + , a)
346
+ sum (f:: Callable , a) = mapreduce (promote_sys_size ∘ f, + , a)
356
347
357
348
"""
358
349
sum(itr)
@@ -364,7 +355,7 @@ julia> sum(1:20)
364
355
210
365
356
```
366
357
"""
367
- sum (a) = mapreduce (identity , + , a)
358
+ sum (a) = mapreduce (promote_sys_size , + , a)
368
359
sum (a:: AbstractArray{Bool} ) = count (a)
369
360
370
361
@@ -379,7 +370,7 @@ summation algorithm for additional accuracy.
379
370
"""
380
371
function sum_kbn (A)
381
372
T = _default_eltype (typeof (A))
382
- c = r_promote ( + , zero (T):: T )
373
+ c = promote_sys_size ( zero (T):: T )
383
374
i = start (A)
384
375
if done (A, i)
385
376
return c
@@ -410,7 +401,7 @@ julia> prod(abs2, [2; 3; 4])
410
401
576
411
402
```
412
403
"""
413
- prod (f:: Callable , a) = mapreduce (f, * , a)
404
+ prod (f:: Callable , a) = mapreduce (promote_sys_size ∘ f, * , a)
414
405
415
406
"""
416
407
prod(itr)
@@ -422,7 +413,7 @@ julia> prod(1:20)
422
413
2432902008176640000
423
414
```
424
415
"""
425
- prod (a) = mapreduce (identity , * , a)
416
+ prod (a) = mapreduce (promote_sys_size , * , a)
426
417
427
418
# # maximum & minimum
428
419
0 commit comments