@@ -3,26 +3,21 @@ module EvaluateEquationModule
3
3
import LoopVectorization: @turbo , indices
4
4
import .. EquationModule: Node, string_tree
5
5
import .. OperatorEnumModule: OperatorEnum, GenericOperatorEnum
6
- import .. UtilsModule: @return_on_false , @maybe_turbo , is_bad_array
6
+ import .. UtilsModule: @return_on_false , @maybe_turbo , is_bad_array, fill_similar
7
7
import .. EquationUtilsModule: is_constant
8
8
9
- macro return_on_check (val, T, n)
10
- # This will generate the following code:
11
- # if !isfinite(val)
12
- # return (Array{T, 1}(undef, n), false)
13
- # end
14
-
9
+ macro return_on_check (val, X)
15
10
:(
16
11
if ! isfinite ($ (esc (val)))
17
- return (Array { $(esc(T )),1} (undef, $ (esc (n) )), false )
12
+ return (similar ( $ (esc (X )), axes ( $ (esc (X)), 2 )), false )
18
13
end
19
14
)
20
15
end
21
16
22
- macro return_on_nonfinite_array (array, T, n )
17
+ macro return_on_nonfinite_array (array)
23
18
:(
24
19
if is_bad_array ($ (esc (array)))
25
- return (Array { $(esc(T)),1} (undef, $ ( esc (n) )), false )
20
+ return ($ (esc (array )), false )
26
21
end
27
22
)
28
23
end
@@ -64,15 +59,14 @@ which speed up evaluation significantly.
64
59
function eval_tree_array (
65
60
tree:: Node{T} , cX:: AbstractMatrix{T} , operators:: OperatorEnum ; turbo:: Bool = false
66
61
):: Tuple{AbstractVector{T},Bool} where {T<: Number }
67
- n = size (cX, 2 )
68
62
if turbo
69
63
@assert T in (Float32, Float64)
70
64
end
71
65
result, finished = _eval_tree_array (
72
66
tree, cX, operators, (turbo ? Val (true ) : Val (false ))
73
67
)
74
68
@return_on_false finished result
75
- @return_on_nonfinite_array result T n
69
+ @return_on_nonfinite_array result
76
70
return result, finished
77
71
end
78
72
function eval_tree_array (
@@ -81,23 +75,22 @@ function eval_tree_array(
81
75
T = promote_type (T1, T2)
82
76
@warn " Warning: eval_tree_array received mixed types: tree=$(T1) and data=$(T2) ."
83
77
tree = convert (Node{T}, tree)
84
- cX = convert (AbstractMatrix{T}, cX)
78
+ cX = T .( cX)
85
79
return eval_tree_array (tree, cX, operators; turbo= turbo)
86
80
end
87
81
88
82
function _eval_tree_array (
89
83
tree:: Node{T} , cX:: AbstractMatrix{T} , operators:: OperatorEnum , :: Val{turbo}
90
84
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,turbo}
91
- n = size (cX, 2 )
92
85
# First, we see if there are only constants in the tree - meaning
93
86
# we can just return the constant result.
94
87
if tree. degree == 0
95
88
return deg0_eval (tree, cX)
96
89
elseif is_constant (tree)
97
90
# Speed hack for constant trees.
98
91
result, flag = _eval_constant_tree (tree, operators)
99
- ! flag && return Array {T,1} (undef, size (cX, 2 )), false
100
- return fill (result, size (cX, 2 )), true
92
+ ! flag && return similar (cX, axes (cX, 2 )), false
93
+ return fill_similar (result, cX, axes (cX, 2 )), true
101
94
elseif tree. degree == 1
102
95
op = operators. unaops[tree. op]
103
96
if tree. l. degree == 2 && tree. l. l. degree == 0 && tree. l. r. degree == 0
@@ -113,7 +106,7 @@ function _eval_tree_array(
113
106
# op(x), for any x.
114
107
(cumulator, complete) = _eval_tree_array (tree. l, cX, operators, Val (turbo))
115
108
@return_on_false complete cumulator
116
- @return_on_nonfinite_array cumulator T n
109
+ @return_on_nonfinite_array cumulator
117
110
return deg1_eval (cumulator, op, Val (turbo))
118
111
119
112
elseif tree. degree == 2
@@ -125,22 +118,22 @@ function _eval_tree_array(
125
118
elseif tree. r. degree == 0
126
119
(cumulator_l, complete) = _eval_tree_array (tree. l, cX, operators, Val (turbo))
127
120
@return_on_false complete cumulator_l
128
- @return_on_nonfinite_array cumulator_l T n
121
+ @return_on_nonfinite_array cumulator_l
129
122
# op(x, y), where y is a constant or variable but x is not.
130
123
return deg2_r0_eval (tree, cumulator_l, cX, op, Val (turbo))
131
124
elseif tree. l. degree == 0
132
125
(cumulator_r, complete) = _eval_tree_array (tree. r, cX, operators, Val (turbo))
133
126
@return_on_false complete cumulator_r
134
- @return_on_nonfinite_array cumulator_r T n
127
+ @return_on_nonfinite_array cumulator_r
135
128
# op(x, y), where x is a constant or variable but y is not.
136
129
return deg2_l0_eval (tree, cumulator_r, cX, op, Val (turbo))
137
130
end
138
131
(cumulator_l, complete) = _eval_tree_array (tree. l, cX, operators, Val (turbo))
139
132
@return_on_false complete cumulator_l
140
- @return_on_nonfinite_array cumulator_l T n
133
+ @return_on_nonfinite_array cumulator_l
141
134
(cumulator_r, complete) = _eval_tree_array (tree. r, cX, operators, Val (turbo))
142
135
@return_on_false complete cumulator_r
143
- @return_on_nonfinite_array cumulator_r T n
136
+ @return_on_nonfinite_array cumulator_r
144
137
# op(x, y), for any x or y
145
138
return deg2_eval (cumulator_l, cumulator_r, op, Val (turbo))
146
139
end
@@ -170,8 +163,7 @@ function deg0_eval(
170
163
tree:: Node{T} , cX:: AbstractMatrix{T}
171
164
):: Tuple{AbstractVector{T},Bool} where {T<: Number }
172
165
if tree. constant
173
- n = size (cX, 2 )
174
- return (fill (tree. val:: T , n), true )
166
+ return (fill_similar (tree. val:: T , cX, axes (cX, 2 )), true )
175
167
else
176
168
return (cX[tree. feature, :], true )
177
169
end
@@ -180,22 +172,21 @@ end
180
172
function deg1_l2_ll0_lr0_eval (
181
173
tree:: Node{T} , cX:: AbstractMatrix{T} , op:: F , op_l:: F2 , :: Val{turbo}
182
174
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,F,F2,turbo}
183
- n = size (cX, 2 )
184
175
if tree. l. l. constant && tree. l. r. constant
185
176
val_ll = tree. l. l. val:: T
186
177
val_lr = tree. l. r. val:: T
187
- @return_on_check val_ll T n
188
- @return_on_check val_lr T n
178
+ @return_on_check val_ll cX
179
+ @return_on_check val_lr cX
189
180
x_l = op_l (val_ll, val_lr):: T
190
- @return_on_check x_l T n
181
+ @return_on_check x_l cX
191
182
x = op (x_l):: T
192
- @return_on_check x T n
193
- return (fill (x, n ), true )
183
+ @return_on_check x cX
184
+ return (fill_similar (x, cX, axes (cX, 2 ) ), true )
194
185
elseif tree. l. l. constant
195
186
val_ll = tree. l. l. val:: T
196
- @return_on_check val_ll T n
187
+ @return_on_check val_ll cX
197
188
feature_lr = tree. l. r. feature
198
- cumulator = Array {T,1} (undef, n )
189
+ cumulator = similar (cX, axes (cX, 2 ) )
199
190
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
200
191
x_l = op_l (val_ll, cX[feature_lr, j]):: T
201
192
x = isfinite (x_l) ? op (x_l):: T : T (Inf )
@@ -205,8 +196,8 @@ function deg1_l2_ll0_lr0_eval(
205
196
elseif tree. l. r. constant
206
197
feature_ll = tree. l. l. feature
207
198
val_lr = tree. l. r. val:: T
208
- @return_on_check val_lr T n
209
- cumulator = Array {T,1} (undef, n )
199
+ @return_on_check val_lr cX
200
+ cumulator = similar (cX, axes (cX, 2 ) )
210
201
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
211
202
x_l = op_l (cX[feature_ll, j], val_lr):: T
212
203
x = isfinite (x_l) ? op (x_l):: T : T (Inf )
@@ -216,7 +207,7 @@ function deg1_l2_ll0_lr0_eval(
216
207
else
217
208
feature_ll = tree. l. l. feature
218
209
feature_lr = tree. l. r. feature
219
- cumulator = Array {T,1} (undef, n )
210
+ cumulator = similar (cX, axes (cX, 2 ) )
220
211
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
221
212
x_l = op_l (cX[feature_ll, j], cX[feature_lr, j]):: T
222
213
x = isfinite (x_l) ? op (x_l):: T : T (Inf )
@@ -230,18 +221,17 @@ end
230
221
function deg1_l1_ll0_eval (
231
222
tree:: Node{T} , cX:: AbstractMatrix{T} , op:: F , op_l:: F2 , :: Val{turbo}
232
223
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,F,F2,turbo}
233
- n = size (cX, 2 )
234
224
if tree. l. l. constant
235
225
val_ll = tree. l. l. val:: T
236
- @return_on_check val_ll T n
226
+ @return_on_check val_ll cX
237
227
x_l = op_l (val_ll):: T
238
- @return_on_check x_l T n
228
+ @return_on_check x_l cX
239
229
x = op (x_l):: T
240
- @return_on_check x T n
241
- return (fill (x, n ), true )
230
+ @return_on_check x cX
231
+ return (fill_similar (x, cX, axes (cX, 2 ) ), true )
242
232
else
243
233
feature_ll = tree. l. l. feature
244
- cumulator = Array {T,1} (undef, n )
234
+ cumulator = similar (cX, axes (cX, 2 ) )
245
235
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
246
236
x_l = op_l (cX[feature_ll, j]):: T
247
237
x = isfinite (x_l) ? op (x_l):: T : T (Inf )
@@ -255,35 +245,34 @@ end
255
245
function deg2_l0_r0_eval (
256
246
tree:: Node{T} , cX:: AbstractMatrix{T} , op:: F , :: Val{turbo}
257
247
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,F,turbo}
258
- n = size (cX, 2 )
259
248
if tree. l. constant && tree. r. constant
260
249
val_l = tree. l. val:: T
261
- @return_on_check val_l T n
250
+ @return_on_check val_l cX
262
251
val_r = tree. r. val:: T
263
- @return_on_check val_r T n
252
+ @return_on_check val_r cX
264
253
x = op (val_l, val_r):: T
265
- @return_on_check x T n
266
- return (fill (x, n ), true )
254
+ @return_on_check x cX
255
+ return (fill_similar (x, cX, axes (cX, 2 ) ), true )
267
256
elseif tree. l. constant
268
- cumulator = Array {T,1} (undef, n )
257
+ cumulator = similar (cX, axes (cX, 2 ) )
269
258
val_l = tree. l. val:: T
270
- @return_on_check val_l T n
259
+ @return_on_check val_l cX
271
260
feature_r = tree. r. feature
272
261
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
273
262
x = op (val_l, cX[feature_r, j]):: T
274
263
cumulator[j] = x
275
264
end
276
265
elseif tree. r. constant
277
- cumulator = Array {T,1} (undef, n )
266
+ cumulator = similar (cX, axes (cX, 2 ) )
278
267
feature_l = tree. l. feature
279
268
val_r = tree. r. val:: T
280
- @return_on_check val_r T n
269
+ @return_on_check val_r cX
281
270
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
282
271
x = op (cX[feature_l, j], val_r):: T
283
272
cumulator[j] = x
284
273
end
285
274
else
286
- cumulator = Array {T,1} (undef, n )
275
+ cumulator = similar (cX, axes (cX, 2 ) )
287
276
feature_l = tree. l. feature
288
277
feature_r = tree. r. feature
289
278
@maybe_turbo turbo for j in indices ((cX, cumulator), (2 , 1 ))
298
287
function deg2_l0_eval (
299
288
tree:: Node{T} , cumulator:: AbstractVector{T} , cX:: AbstractArray{T} , op:: F , :: Val{turbo}
300
289
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,F,turbo}
301
- n = size (cX, 2 )
302
290
if tree. l. constant
303
291
val = tree. l. val:: T
304
- @return_on_check val T n
292
+ @return_on_check val cX
305
293
@maybe_turbo turbo for j in indices (cumulator)
306
294
x = op (val, cumulator[j]):: T
307
295
cumulator[j] = x
320
308
function deg2_r0_eval (
321
309
tree:: Node{T} , cumulator:: AbstractVector{T} , cX:: AbstractArray{T} , op:: F , :: Val{turbo}
322
310
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,F,turbo}
323
- n = size (cX, 2 )
324
311
if tree. r. constant
325
312
val = tree. r. val:: T
326
- @return_on_check val T n
313
+ @return_on_check val cX
327
314
@maybe_turbo turbo for j in indices (cumulator)
328
315
x = op (cumulator[j], val):: T
329
316
cumulator[j] = x
@@ -389,10 +376,9 @@ Evaluate an expression tree in a way that can be auto-differentiated.
389
376
function differentiable_eval_tree_array (
390
377
tree:: Node{T1} , cX:: AbstractMatrix{T} , operators:: OperatorEnum
391
378
):: Tuple{AbstractVector{T},Bool} where {T<: Number ,T1}
392
- n = size (cX, 2 )
393
379
if tree. degree == 0
394
380
if tree. constant
395
- return (ones (T, n) .* convert (T, tree. val) , true )
381
+ return (fill_similar ( one (T), cX, axes (cX, 2 )) .* tree. val, true )
396
382
else
397
383
return (cX[tree. feature, :], true )
398
384
end
0 commit comments