1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <executorch/kernels/portable/NativeFunctions.h> // Declares the operator
10 #include <executorch/kernels/test/TestUtil.h>
11 #include <executorch/runtime/core/exec_aten/exec_aten.h>
12 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
13 #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h>
14 #include <executorch/test/utils/DeathTest.h>
15
16 #include <gtest/gtest.h>
17 #include <cmath>
18
19 using namespace ::testing;
20 using exec_aten::ScalarType;
21 using exec_aten::Tensor;
22 using torch::executor::native::allclose_out;
23 using torch::executor::testing::IsCloseTo;
24 using torch::executor::testing::TensorFactory;
25
26 const double default_atol{1e-08};
27 const double default_rtol{1e-05};
28
TEST(OpAllCloseTest,IdenticalFloatTensors)29 TEST(OpAllCloseTest, IdenticalFloatTensors) {
30 TensorFactory<ScalarType::Float> tf_float;
31 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
32 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
33 TensorFactory<ScalarType::Bool> tf_bool;
34 Tensor out = tf_bool.zeros(/*sizes=*/{1});
35
36 allclose_out(
37 a,
38 b,
39 default_rtol,
40 default_atol,
41 /*equal_nan=*/false,
42 /*dummy_param=*/false,
43 out);
44
45 auto out_data = out.data_ptr<bool>();
46 EXPECT_EQ(out_data[0], true);
47 }
48
TEST(OpAllCloseTest,IdenticalDoubleTensors)49 TEST(OpAllCloseTest, IdenticalDoubleTensors) {
50 TensorFactory<ScalarType::Double> tf_double;
51 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
52 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
53 TensorFactory<ScalarType::Bool> tf_bool;
54 Tensor out = tf_bool.zeros(/*sizes=*/{1});
55
56 allclose_out(
57 a,
58 b,
59 default_rtol,
60 default_atol,
61 /*equal_nan=*/false,
62 /*dummy_param=*/false,
63 out);
64
65 auto out_data = out.data_ptr<bool>();
66 EXPECT_EQ(out_data[0], true);
67 }
68
TEST(OpAllCloseTest,NonEqualFloatTensors)69 TEST(OpAllCloseTest, NonEqualFloatTensors) {
70 TensorFactory<ScalarType::Float> tf_float;
71 Tensor a = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.});
72 Tensor b = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.});
73 TensorFactory<ScalarType::Bool> tf_bool;
74 Tensor out = tf_bool.zeros(/*sizes=*/{1});
75
76 allclose_out(
77 a,
78 b,
79 default_rtol,
80 default_atol,
81 /*equal_nan=*/false,
82 /*dummy_param=*/false,
83 out);
84
85 auto out_data = out.data_ptr<bool>();
86 EXPECT_EQ(out_data[0], false);
87 }
88
TEST(OpAllCloseTest,NonEqualDoubleTensors)89 TEST(OpAllCloseTest, NonEqualDoubleTensors) {
90 TensorFactory<ScalarType::Double> tf_double;
91 Tensor a = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.});
92 Tensor b = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.});
93 TensorFactory<ScalarType::Bool> tf_bool;
94 Tensor out = tf_bool.zeros(/*sizes=*/{1});
95
96 allclose_out(
97 a,
98 b,
99 default_rtol,
100 default_atol,
101 /*equal_nan=*/false,
102 /*dummy_param=*/false,
103 out);
104
105 auto out_data = out.data_ptr<bool>();
106 EXPECT_EQ(out_data[0], false);
107 }
108
TEST(OpAllCloseTest,IdenticalIntTensors)109 TEST(OpAllCloseTest, IdenticalIntTensors) {
110 TensorFactory<ScalarType::Int> tf_int;
111 Tensor a = tf_int.ones(/*sizes=*/{2, 2});
112 Tensor b = tf_int.ones(/*sizes=*/{2, 2});
113 TensorFactory<ScalarType::Bool> tf_bool;
114 Tensor out = tf_bool.zeros(/*sizes=*/{1});
115 allclose_out(
116 a,
117 b,
118 default_rtol,
119 default_atol,
120 /*equal_nan=*/false,
121 /*dummy_param=*/false,
122 out);
123
124 auto out_data = out.data_ptr<bool>();
125 EXPECT_EQ(out_data[0], true);
126 }
127
TEST(OpAllCloseTest,NonEqualIntTensors)128 TEST(OpAllCloseTest, NonEqualIntTensors) {
129 TensorFactory<ScalarType::Int> tf_int;
130 Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4});
131 Tensor b = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{5, 6, 7, 8});
132 TensorFactory<ScalarType::Bool> tf_bool;
133 Tensor out = tf_bool.zeros(/*sizes=*/{1});
134 allclose_out(
135 a,
136 b,
137 default_rtol,
138 default_atol,
139 /*equal_nan=*/false,
140 /*dummy_param=*/false,
141 out);
142
143 auto out_data = out.data_ptr<bool>();
144 EXPECT_EQ(out_data[0], false);
145 }
146
TEST(OpAllCloseTest,IdenticalBoolTensors)147 TEST(OpAllCloseTest, IdenticalBoolTensors) {
148 TensorFactory<ScalarType::Bool> tf_bool;
149 Tensor a = tf_bool.ones(/*sizes=*/{2, 2});
150 Tensor b = tf_bool.ones(/*sizes=*/{2, 2});
151 Tensor out = tf_bool.zeros(/*sizes=*/{1});
152
153 allclose_out(
154 a,
155 b,
156 default_rtol,
157 default_atol,
158 /*equal_nan=*/false,
159 /*dummy_param=*/false,
160 out);
161 auto out_data = out.data_ptr<bool>();
162 EXPECT_EQ(out_data[0], true);
163 }
164
TEST(OpAllCloseTest,NonEqualBoolTensors)165 TEST(OpAllCloseTest, NonEqualBoolTensors) {
166 TensorFactory<ScalarType::Bool> tf_bool;
167 Tensor a = tf_bool.ones(/*sizes=*/{2, 2});
168 Tensor b = tf_bool.ones(/*sizes=*/{2, 2});
169 auto b_data = b.data_ptr<bool>();
170 b_data[0] = false;
171 Tensor out = tf_bool.zeros(/*sizes=*/{1});
172
173 allclose_out(
174 a,
175 b,
176 default_rtol,
177 default_atol,
178 /*equal_nan=*/false,
179 /*dummy_param=*/false,
180 out);
181 auto out_data = out.data_ptr<bool>();
182 EXPECT_EQ(out_data[0], false);
183 }
184
TEST(OpAllCloseTest,MismatchedInputShapesDeath)185 TEST(OpAllCloseTest, MismatchedInputShapesDeath) {
186 TensorFactory<ScalarType::Int> tf_int;
187 Tensor a = tf_int.ones(/*sizes=*/{2, 1});
188 Tensor b = tf_int.ones(/*sizes=*/{2, 2});
189 TensorFactory<ScalarType::Bool> tf_bool;
190 Tensor out = tf_bool.zeros(/*sizes=*/{1});
191
192 ET_EXPECT_DEATH(
193 allclose_out(
194 a,
195 b,
196 default_rtol,
197 default_atol,
198 /*equal_nan=*/false,
199 /*dummy_param=*/false,
200 out),
201 "");
202 }
203
TEST(OpAllCloseTest,MismatchedInputDtypesDeath)204 TEST(OpAllCloseTest, MismatchedInputDtypesDeath) {
205 TensorFactory<ScalarType::Float> tf_float;
206 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
207
208 TensorFactory<ScalarType::Int> tf_int;
209 Tensor b = tf_int.ones(/*sizes=*/{2, 2});
210
211 TensorFactory<ScalarType::Bool> tf_bool;
212 Tensor out = tf_bool.zeros(/*sizes=*/{1});
213
214 ET_EXPECT_DEATH(
215 allclose_out(
216 a,
217 b,
218 default_rtol,
219 default_atol,
220 /*equal_nan=*/false,
221 /*dummy_param=*/false,
222 out),
223 "");
224 }
225
TEST(OpAllCloseTest,IncorrectOutputDtypeDeath)226 TEST(OpAllCloseTest, IncorrectOutputDtypeDeath) {
227 TensorFactory<ScalarType::Float> tf_float;
228 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
229 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
230 Tensor out = tf_float.zeros(/*sizes=*/{1});
231
232 ET_EXPECT_DEATH(
233 allclose_out(
234 a,
235 b,
236 default_rtol,
237 default_atol,
238 /*equal_nan=*/false,
239 /*dummy_param=*/false,
240 out),
241 "");
242 }
243
TEST(OpAllCloseTest,IncorrectOutputShapeDeath)244 TEST(OpAllCloseTest, IncorrectOutputShapeDeath) {
245 TensorFactory<ScalarType::Float> tf_float;
246 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
247 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
248 TensorFactory<ScalarType::Bool> tf_bool;
249 Tensor out = tf_bool.zeros(/*sizes=*/{2, 2});
250
251 ET_EXPECT_DEATH(
252 allclose_out(
253 a,
254 b,
255 default_rtol,
256 default_atol,
257 /*equal_nan=*/false,
258 /*dummy_param=*/false,
259 out),
260 "");
261 }
262
TEST(OpAllCloseTest,FloatTensorsVaryWithinRelativeTolerance)263 TEST(OpAllCloseTest, FloatTensorsVaryWithinRelativeTolerance) {
264 const double rtol = 1e-05;
265 const double rdiff = 1e-06;
266
267 TensorFactory<ScalarType::Float> tf_float;
268 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
269 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
270
271 auto a_data = a.data_ptr<float>();
272 auto b_data = b.data_ptr<float>();
273 b_data[0] = a_data[0] * (1. + rdiff);
274
275 TensorFactory<ScalarType::Bool> tf_bool;
276 Tensor out = tf_bool.zeros(/*sizes=*/{1});
277
278 allclose_out(
279 a, b, rtol, /*atol=*/0., /*equal_nan=*/false, /*dummy_param=*/false, out);
280
281 auto out_data = out.data_ptr<bool>();
282 EXPECT_EQ(out_data[0], true);
283 }
284
TEST(OpAllCloseTest,DoubleTensorsVaryWithinRelativeTolerance)285 TEST(OpAllCloseTest, DoubleTensorsVaryWithinRelativeTolerance) {
286 const double rtol = 1e-05;
287 const double rdiff = 1e-06;
288
289 TensorFactory<ScalarType::Double> tf_double;
290 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
291 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
292
293 auto a_data = a.data_ptr<double>();
294 auto b_data = b.data_ptr<double>();
295 b_data[0] = a_data[0] * (1. + rdiff);
296 TensorFactory<ScalarType::Bool> tf_bool;
297 Tensor out = tf_bool.zeros(/*sizes=*/{1});
298
299 allclose_out(
300 a, b, rtol, /*atol=*/0., /*equal_nan=*/false, /*dummy_param=*/false, out);
301
302 auto out_data = out.data_ptr<bool>();
303 EXPECT_EQ(out_data[0], true);
304 }
305
TEST(OpAllCloseTest,FloatTensorsVaryOutsideRelativeTolerance)306 TEST(OpAllCloseTest, FloatTensorsVaryOutsideRelativeTolerance) {
307 const double rtol = 1e-05;
308 const double rdiff = 1e-04;
309
310 TensorFactory<ScalarType::Float> tf_float;
311 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
312 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
313
314 auto a_data = a.data_ptr<float>();
315 auto b_data = b.data_ptr<float>();
316 b_data[0] = a_data[0] * (1. + rdiff);
317 TensorFactory<ScalarType::Bool> tf_bool;
318 Tensor out = tf_bool.zeros(/*sizes=*/{1});
319
320 allclose_out(
321 a, b, rtol, /*atol=*/0., /*equal_nan=*/false, /*dummy_param=*/false, out);
322
323 auto out_data = out.data_ptr<bool>();
324 EXPECT_EQ(out_data[0], false);
325 }
326
TEST(OpAllCloseTest,DoubleTensorsVaryOutsideRelativeTolerance)327 TEST(OpAllCloseTest, DoubleTensorsVaryOutsideRelativeTolerance) {
328 const double rtol = 1e-05;
329 const double rdiff = 1e-04;
330
331 TensorFactory<ScalarType::Double> tf_double;
332 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
333 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
334
335 auto a_data = a.data_ptr<double>();
336 auto b_data = b.data_ptr<double>();
337 b_data[0] = a_data[0] * (1. + rdiff);
338 TensorFactory<ScalarType::Bool> tf_bool;
339 Tensor out = tf_bool.zeros(/*sizes=*/{1});
340
341 allclose_out(
342 a, b, rtol, /*atol=*/0., /*equal_nan=*/false, /*dummy_param=*/false, out);
343
344 auto out_data = out.data_ptr<bool>();
345 EXPECT_EQ(out_data[0], false);
346 }
347
TEST(OpAllCloseTest,FloatTensorsVaryWithinAbsoluteTolerance)348 TEST(OpAllCloseTest, FloatTensorsVaryWithinAbsoluteTolerance) {
349 const double atol = 1e-08;
350 const double adiff = 1e-09;
351
352 TensorFactory<ScalarType::Float> tf_float;
353 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
354 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
355
356 auto a_data = a.data_ptr<float>();
357 auto b_data = b.data_ptr<float>();
358 b_data[0] = a_data[0] + adiff;
359 TensorFactory<ScalarType::Bool> tf_bool;
360 Tensor out = tf_bool.zeros(/*sizes=*/{1});
361
362 allclose_out(
363 a, b, /*rtol=*/0., atol, /*equal_nan=*/false, /*dummy_param=*/false, out);
364
365 auto out_data = out.data_ptr<bool>();
366 EXPECT_EQ(out_data[0], true);
367 }
368
TEST(OpAllCloseTest,DoubleTensorsVaryWithinAbsoluteTolerance)369 TEST(OpAllCloseTest, DoubleTensorsVaryWithinAbsoluteTolerance) {
370 const double atol = 1e-08;
371 const double adiff = 1e-09;
372
373 TensorFactory<ScalarType::Double> tf_double;
374 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
375 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
376
377 auto a_data = a.data_ptr<double>();
378 auto b_data = b.data_ptr<double>();
379 b_data[0] = a_data[0] + adiff;
380 TensorFactory<ScalarType::Bool> tf_bool;
381 Tensor out = tf_bool.zeros(/*sizes=*/{1});
382
383 allclose_out(
384 a, b, /*rtol=*/0., atol, /*equal_nan=*/false, /*dummy_param=*/false, out);
385
386 auto out_data = out.data_ptr<bool>();
387 EXPECT_EQ(out_data[0], true);
388 }
389
TEST(OpAllCloseTest,FloatTensorsVaryOutsideAbsoluteTolerance)390 TEST(OpAllCloseTest, FloatTensorsVaryOutsideAbsoluteTolerance) {
391 const double atol = 1e-08;
392 const double adiff = 1e-07;
393
394 TensorFactory<ScalarType::Float> tf_float;
395 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
396 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
397
398 auto a_data = a.data_ptr<float>();
399 auto b_data = b.data_ptr<float>();
400 b_data[0] = a_data[0] + adiff;
401 TensorFactory<ScalarType::Bool> tf_bool;
402 Tensor out = tf_bool.zeros(/*sizes=*/{1});
403
404 allclose_out(
405 a, b, /*rtol=*/0., atol, /*equal_nan=*/false, /*dummy_param=*/false, out);
406
407 auto out_data = out.data_ptr<bool>();
408 EXPECT_EQ(out_data[0], false);
409 }
410
TEST(OpAllCloseTest,DoubleTensorsVaryOutsideAbsoluteTolerance)411 TEST(OpAllCloseTest, DoubleTensorsVaryOutsideAbsoluteTolerance) {
412 const double atol = 1e-08;
413 const double adiff = 1e-07;
414
415 TensorFactory<ScalarType::Float> tf_double;
416 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
417 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
418
419 auto a_data = a.data_ptr<double>();
420 auto b_data = b.data_ptr<double>();
421 b_data[0] = a_data[0] + adiff;
422 TensorFactory<ScalarType::Bool> tf_bool;
423 Tensor out = tf_bool.zeros(/*sizes=*/{1});
424
425 allclose_out(
426 a, b, /*rtol=*/0., atol, /*equal_nan=*/false, /*dummy_param=*/false, out);
427
428 auto out_data = out.data_ptr<bool>();
429 EXPECT_EQ(out_data[0], false);
430 }
431
TEST(OpAllCloseTest,FloatTensorsVaryWithZeroTolerance)432 TEST(OpAllCloseTest, FloatTensorsVaryWithZeroTolerance) {
433 TensorFactory<ScalarType::Float> tf_float;
434 Tensor a = tf_float.ones(/*sizes=*/{2, 2});
435 Tensor b = tf_float.ones(/*sizes=*/{2, 2});
436
437 auto a_data = a.data_ptr<float>();
438 auto b_data = b.data_ptr<float>();
439 b_data[0] = a_data[0] + 1e-07;
440 TensorFactory<ScalarType::Bool> tf_bool;
441 Tensor out = tf_bool.zeros(/*sizes=*/{1});
442
443 allclose_out(
444 a,
445 b,
446 /*rtol=*/0.,
447 /*atol=*/0,
448 /*equal_nan=*/false,
449 /*dummy_param=*/false,
450 out);
451
452 auto out_data = out.data_ptr<bool>();
453 EXPECT_EQ(out_data[0], false);
454 }
455
TEST(OpAllCloseTest,DoubleTensorsVaryWithZeroTolerance)456 TEST(OpAllCloseTest, DoubleTensorsVaryWithZeroTolerance) {
457 TensorFactory<ScalarType::Double> tf_double;
458 Tensor a = tf_double.ones(/*sizes=*/{2, 2});
459 Tensor b = tf_double.ones(/*sizes=*/{2, 2});
460
461 auto a_data = a.data_ptr<double>();
462 auto b_data = b.data_ptr<double>();
463 b_data[0] = a_data[0] + 1e-09;
464 TensorFactory<ScalarType::Bool> tf_bool;
465 Tensor out = tf_bool.zeros(/*sizes=*/{1});
466
467 allclose_out(
468 a,
469 b,
470 /*rtol=*/0.,
471 /*atol=*/0.,
472 /*equal_nan=*/false,
473 /*dummy_param=*/false,
474 out);
475
476 auto out_data = out.data_ptr<bool>();
477 EXPECT_EQ(out_data[0], false);
478 }
479