3
3
# # Functions to compute the reduced shape
4
4
5
5
# for reductions that expand 0 dims to 1
6
- reduced_index (i:: OneTo ) = OneTo (1 )
7
- reduced_index (i:: Slice ) = Slice (first (i): first (i))
8
- reduced_index (i:: AbstractUnitRange ) =
9
- throw (ArgumentError (
10
- """
11
- No method is implemented for reducing index range of type $typeof (i). Please implement
12
- reduced_index for this index type or report this as an issue.
13
- """
14
- ))
15
6
reduced_indices (a:: AbstractArray , region) = reduced_indices (axes (a), region)
16
7
17
8
# for reductions that keep 0 dims as 0
18
9
reduced_indices0 (a:: AbstractArray , region) = reduced_indices0 (axes (a), region)
19
10
20
- function reduced_indices (inds:: Indices{N} , d:: Int ) where N
11
+ function reduced_indices (inds:: Indices{N} , d:: Int , rd :: AbstractUnitRange ) where N
21
12
d < 1 && throw (ArgumentError (" dimension must be ≥ 1, got $d " ))
22
13
if d == 1
23
- return (reduced_index (inds[1 ]), tail (inds)... )
14
+ return (oftype (inds[1 ], rd ), tail (inds)... )
24
15
elseif 1 < d <= N
25
- return tuple (inds[1 : d- 1 ]. .. , oftype (inds[d], reduced_index (inds[d]) ), inds[d+ 1 : N]. .. ):: typeof (inds)
16
+ return tuple (inds[1 : d- 1 ]. .. , oftype (inds[d], rd ), inds[d+ 1 : N]. .. ):: typeof (inds)
26
17
else
27
18
return inds
28
19
end
29
20
end
21
+ reduced_indices (inds:: Indices , d:: Int ) = reduced_indices (inds, d, OneTo (1 ))
30
22
31
23
function reduced_indices0 (inds:: Indices{N} , d:: Int ) where N
32
24
d < 1 && throw (ArgumentError (" dimension must be ≥ 1, got $d " ))
33
25
if d <= N
34
26
ind = inds[d]
35
- rd = isempty (ind) ? ind : reduced_index (inds[d])
36
- if d == 1
37
- return (rd, tail (inds)... )
38
- else
39
- return tuple (inds[1 : d- 1 ]. .. , oftype (inds[d], rd), inds[d+ 1 : N]. .. ):: typeof (inds)
40
- end
27
+ return reduced_indices (inds, d, (isempty (ind) ? ind : OneTo (1 )))
41
28
else
42
29
return inds
43
30
end
@@ -51,7 +38,7 @@ function reduced_indices(inds::Indices{N}, region) where N
51
38
if d < 1
52
39
throw (ArgumentError (" region dimension(s) must be ≥ 1, got $d " ))
53
40
elseif d <= N
54
- rinds[d] = reduced_index (rinds[d])
41
+ rinds[d] = oftype (rinds[d], OneTo ( 1 ) )
55
42
end
56
43
end
57
44
tuple (rinds... ):: typeof (inds)
@@ -66,7 +53,7 @@ function reduced_indices0(inds::Indices{N}, region) where N
66
53
throw (ArgumentError (" region dimension(s) must be ≥ 1, got $d " ))
67
54
elseif d <= N
68
55
rind = rinds[d]
69
- rinds[d] = isempty (rind) ? rind : reduced_index (rind )
56
+ rinds[d] = oftype (rind, ( isempty (rind) ? rind : OneTo ( 1 )) )
70
57
end
71
58
end
72
59
tuple (rinds... ):: typeof (inds)
92
79
reducedim_initarray (A:: AbstractArray , region, init, :: Type{R} ) where {R} = fill! (similar (A,R,reduced_indices (A,region)), init)
93
80
reducedim_initarray (A:: AbstractArray , region, init:: T ) where {T} = reducedim_initarray (A, region, init, T)
94
81
82
+ function reducedim_initarray0 (A:: AbstractArray{T} , region, f, ops) where T
83
+ ri = reduced_indices0 (A, region)
84
+ if isempty (A)
85
+ if prod (length, reduced_indices (A, region)) != 0
86
+ reducedim_initarray0_empty (A, region, f, ops) # ops over empty slice of A
87
+ else
88
+ R = f == identity ? T : Core. Compiler. return_type (f, (T,))
89
+ similar (A, R, ri)
90
+ end
91
+ else
92
+ R = f == identity ? T : typeof (f (first (A)))
93
+ si = similar (A, R, ri)
94
+ mapfirst! (f, si, A)
95
+ end
96
+ end
97
+
98
+ reducedim_initarray0_empty (A:: AbstractArray , region, f, ops) = mapslices (x-> ops (f .(x)), A, dims = region)
99
+ reducedim_initarray0_empty (A:: AbstractArray , region,:: typeof (identity), ops) = mapslices (ops, A, dims = region)
100
+
95
101
# TODO : better way to handle reducedim initialization
96
102
#
97
103
# The current scheme is basically following Steven G. Johnson's original implementation
@@ -118,33 +124,8 @@ function _reducedim_init(f, op, fv, fop, A, region)
118
124
return reducedim_initarray (A, region, z, Tr)
119
125
end
120
126
121
- # initialization when computing minima and maxima requires a little care
122
- for (f1, f2, initval) in ((:min , :max , :Inf ), (:max , :min , :(- Inf )))
123
- @eval function reducedim_init (f, op:: typeof ($ f1), A:: AbstractArray , region)
124
- # First compute the reduce indices. This will throw an ArgumentError
125
- # if any region is invalid
126
- ri = reduced_indices (A, region)
127
-
128
- # Next, throw if reduction is over a region with length zero
129
- any (i -> isempty (axes (A, i)), region) && _empty_reduce_error ()
130
-
131
- # Make a view of the first slice of the region
132
- A1 = view (A, ri... )
133
-
134
- if isempty (A1)
135
- # If the slice is empty just return non-view version as the initial array
136
- return copy (A1)
137
- else
138
- # otherwise use the min/max of the first slice as initial value
139
- v0 = mapreduce (f, $ f2, A1)
140
-
141
- # but NaNs need to be avoided as intial values
142
- v0 = v0 != v0 ? typeof (v0)($ initval) : v0
143
-
144
- return reducedim_initarray (A, region, v0)
145
- end
146
- end
147
- end
127
+ reducedim_init (f, op:: typeof (max), A:: AbstractArray{T} , region) where {T} = reducedim_initarray0 (A, region, f, maximum)
128
+ reducedim_init (f, op:: typeof (min), A:: AbstractArray{T} , region) where {T} = reducedim_initarray0 (A, region, f, minimum)
148
129
reducedim_init (f:: Union{typeof(abs),typeof(abs2)} , op:: typeof (max), A:: AbstractArray{T} , region) where {T} =
149
130
reducedim_initarray (A, region, zero (f (zero (T))))
150
131
0 commit comments