xref: /aosp_15_r20/external/executorch/kernels/test/op_add_test.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
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/test/FunctionHeaderWrapper.h> // Declares the operator
10 #include <executorch/kernels/test/TestUtil.h>
11 #include <executorch/kernels/test/supported_features.h>
12 #include <executorch/runtime/core/exec_aten/exec_aten.h>
13 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
14 #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h>
15 
16 #include <gtest/gtest.h>
17 
18 #include <iostream>
19 
20 using namespace ::testing;
21 using executorch::aten::Scalar;
22 using executorch::aten::ScalarType;
23 using executorch::aten::Tensor;
24 using executorch::runtime::testing::TensorFactory;
25 using torch::executor::testing::SupportedFeatures;
26 namespace etrt = executorch::runtime;
27 
28 class OpAddOutKernelTest : public OperatorTest {
29  protected:
op_add_out(const Tensor & self,const Tensor & other,const Scalar & alpha,Tensor & out)30   Tensor& op_add_out(
31       const Tensor& self,
32       const Tensor& other,
33       const Scalar& alpha,
34       Tensor& out) {
35     return torch::executor::aten::add_outf(context_, self, other, alpha, out);
36   }
37 
38   template <ScalarType DTYPE_A, ScalarType DTYPE_B, ScalarType DTYPE_OUT>
test_add()39   void test_add() {
40     TensorFactory<DTYPE_A> tf_a;
41     TensorFactory<DTYPE_B> tf_b;
42     TensorFactory<DTYPE_OUT> tf_out;
43 
44     const std::vector<int32_t> sizes = {2, 2};
45 
46     // Destination for the sum.
47     Tensor out = tf_out.zeros(sizes);
48 
49     // Add two tensors.
50     op_add_out(
51         tf_a.make(sizes, /*data=*/{1, 2, 4, 8}),
52         tf_b.ones(sizes),
53         /*alpha=*/1,
54         out);
55 
56     // Check that it matches the expected output.
57     EXPECT_TENSOR_EQ(out, tf_out.make(sizes, /*data=*/{2, 3, 5, 9}));
58   }
59 
60   template <ScalarType DTYPE_A, ScalarType DTYPE_B>
test_add_enumerate_out_types()61   void test_add_enumerate_out_types() {
62     test_add<DTYPE_A, DTYPE_B, ScalarType::BFloat16>();
63     test_add<DTYPE_A, DTYPE_B, ScalarType::Half>();
64     test_add<DTYPE_A, DTYPE_B, ScalarType::Float>();
65     test_add<DTYPE_A, DTYPE_B, ScalarType::Double>();
66     // Integral out type is only allowed if both inputs are integral types
67     if (etrt::isIntegralType(DTYPE_A, false) &&
68         etrt::isIntegralType(DTYPE_B, false)) {
69       test_add<DTYPE_A, DTYPE_B, ScalarType::Int>();
70       test_add<DTYPE_A, DTYPE_B, ScalarType::Long>();
71     }
72   }
73 
74   template <ScalarType DTYPE_A>
test_add_enumerate_b_types()75   void test_add_enumerate_b_types() {
76 #define ENUMERATE_TEST_ENTRY(ctype, dtype) \
77   test_add_enumerate_out_types<DTYPE_A, ScalarType::dtype>();
78 
79     ET_FORALL_REALHBF16_TYPES(ENUMERATE_TEST_ENTRY)
80 
81 #undef ENUMERATE_TEST_ENTRY
82   }
83 
test_add_enumerate_a_types()84   void test_add_enumerate_a_types() {
85 #define ENUMERATE_TEST_ENTRY(ctype, dtype) \
86   test_add_enumerate_b_types<ScalarType::dtype>();
87 
88     ET_FORALL_REALHBF16_TYPES(ENUMERATE_TEST_ENTRY)
89 
90 #undef ENUMERATE_TEST_ENTRY
91   }
92 
93   // Common testing for adding two floating point Tensors.
94   template <ScalarType DTYPE>
test_floating_point_add_out()95   void test_floating_point_add_out() {
96     TensorFactory<DTYPE> tf;
97 
98     const std::vector<int32_t> sizes = {2, 2};
99 
100     // Destination for the sum.
101     Tensor out = tf.zeros(sizes);
102 
103     // Add two tensors.
104     op_add_out(
105         tf.make(sizes, /*data=*/{1.25, 2.25, 4.5, 8.875}),
106         tf.ones(sizes),
107         /*alpha=*/1.25,
108         out);
109 
110     // Check that it matches the expected output. Values selected to
111     // be exactly representable to avoid throwing off half/bfloat16
112     // tests.
113     EXPECT_TENSOR_CLOSE(out, tf.make(sizes, /*data=*/{2.5, 3.5, 5.75, 10.125}));
114   }
115 };
116 
117 class OpAddScalarOutKernelTest : public OperatorTest {
118  protected:
op_add_scalar_out(const Tensor & self,const Scalar & other,const Scalar & alpha,Tensor & out)119   Tensor& op_add_scalar_out(
120       const Tensor& self,
121       const Scalar& other,
122       const Scalar& alpha,
123       Tensor& out) {
124     return torch::executor::aten::add_outf(context_, self, other, alpha, out);
125   }
126 };
127 
128 /**
129  * Uses the function templates above to test all valid combinations of inputs
130  * and output dtypes
131  */
TEST_F(OpAddOutKernelTest,AllRealDtypesSupported)132 TEST_F(OpAddOutKernelTest, AllRealDtypesSupported) {
133   test_add_enumerate_a_types();
134 }
135 
TEST_F(OpAddOutKernelTest,FloatTensors)136 TEST_F(OpAddOutKernelTest, FloatTensors) {
137   test_floating_point_add_out<ScalarType::Float>();
138 }
139 
TEST_F(OpAddOutKernelTest,DoubleTensors)140 TEST_F(OpAddOutKernelTest, DoubleTensors) {
141   test_floating_point_add_out<ScalarType::Double>();
142 }
143 
TEST_F(OpAddOutKernelTest,HalfTensors)144 TEST_F(OpAddOutKernelTest, HalfTensors) {
145   test_floating_point_add_out<ScalarType::Half>();
146 }
147 
TEST_F(OpAddOutKernelTest,BFloat16Tensors)148 TEST_F(OpAddOutKernelTest, BFloat16Tensors) {
149   test_floating_point_add_out<ScalarType::BFloat16>();
150 }
151 
TEST_F(OpAddOutKernelTest,BoolAndIntInputTensor)152 TEST_F(OpAddOutKernelTest, BoolAndIntInputTensor) {
153   TensorFactory<ScalarType::Bool> tf;
154   TensorFactory<ScalarType::Int> tfi;
155 
156   const std::vector<int32_t> sizes = {2, 2};
157 
158   Tensor a = tf.make(sizes, /*data=*/{false, true, false, true});
159   Tensor b = tfi.make(sizes, /*data=*/{2, 4, 3, 3});
160 
161   Tensor out = tfi.zeros(sizes);
162 
163   op_add_out(a, b, /*alpha=*/1, out);
164   EXPECT_TENSOR_EQ(out, tfi.make(sizes, {2, 5, 3, 4}));
165 }
166 
TEST_F(OpAddOutKernelTest,BoolAndBoolInputTensor)167 TEST_F(OpAddOutKernelTest, BoolAndBoolInputTensor) {
168   et_pal_init();
169   TensorFactory<ScalarType::Bool> tf;
170 
171   const std::vector<int32_t> sizes = {2, 2};
172 
173   Tensor a = tf.make(sizes, /*data=*/{false, true, false, true});
174   Tensor b = tf.make(sizes, /*data=*/{false, true, true, true});
175 
176   Tensor out = tf.zeros(sizes);
177 
178   op_add_out(a, b, /*alpha=*/1, out);
179   EXPECT_TENSOR_EQ(out, tf.make(sizes, {false, true, true, true}));
180 }
181 
TEST_F(OpAddOutKernelTest,BroadcastDimSizeIsOneAB)182 TEST_F(OpAddOutKernelTest, BroadcastDimSizeIsOneAB) {
183   TensorFactory<ScalarType::Float> tf;
184 
185   Tensor x = tf.make(
186       {3, 2},
187       {0.5721208453178406,
188        0.9629082083702087,
189        0.19517338275909424,
190        0.4107270836830139,
191        0.945562481880188,
192        0.8788509368896484});
193   Tensor y = tf.make({1, 2}, {0.7453382015228271, 0.3131374716758728});
194   Tensor expected_result = tf.make(
195       {3, 2},
196       {1.3174591064453125,
197        1.2760456800460815,
198        0.9405115842819214,
199        0.7238645553588867,
200        1.6909006834030151,
201        1.191988468170166});
202 
203   Tensor out = tf.zeros({3, 2});
204   Tensor ret = op_add_out(x, y, 1, out);
205   EXPECT_TENSOR_CLOSE(out, expected_result);
206 }
207 
TEST_F(OpAddOutKernelTest,BroadcastDimSizeMissingAB)208 TEST_F(OpAddOutKernelTest, BroadcastDimSizeMissingAB) {
209   TensorFactory<ScalarType::Float> tf;
210 
211   Tensor x = tf.make(
212       {3, 2},
213       {0.5721208453178406,
214        0.9629082083702087,
215        0.19517338275909424,
216        0.4107270836830139,
217        0.945562481880188,
218        0.8788509368896484});
219   Tensor y = tf.make({2}, {0.7453382015228271, 0.3131374716758728});
220   Tensor expected_result = tf.make(
221       {3, 2},
222       {1.3174591064453125,
223        1.2760456800460815,
224        0.9405115842819214,
225        0.7238645553588867,
226        1.6909006834030151,
227        1.191988468170166});
228 
229   Tensor out = tf.zeros({3, 2});
230   Tensor ret = op_add_out(x, y, 1, out);
231   EXPECT_TENSOR_CLOSE(out, expected_result);
232 }
233 
TEST_F(OpAddOutKernelTest,BroadcastDimSizeIsOneBA)234 TEST_F(OpAddOutKernelTest, BroadcastDimSizeIsOneBA) {
235   TensorFactory<ScalarType::Float> tf;
236 
237   Tensor x = tf.make({1, 2}, {0.7453382015228271, 0.3131374716758728});
238   Tensor y = tf.make(
239       {3, 2},
240       {0.5721208453178406,
241        0.9629082083702087,
242        0.19517338275909424,
243        0.4107270836830139,
244        0.945562481880188,
245        0.8788509368896484});
246   Tensor expected_result = tf.make(
247       {3, 2},
248       {1.3174591064453125,
249        1.2760456800460815,
250        0.9405115842819214,
251        0.7238645553588867,
252        1.6909006834030151,
253        1.191988468170166});
254 
255   Tensor out = tf.zeros({3, 2});
256   Tensor ret = op_add_out(x, y, 1, out);
257   EXPECT_TENSOR_CLOSE(out, expected_result);
258 }
259 
TEST_F(OpAddOutKernelTest,BroadcastDimSizeMissingBA)260 TEST_F(OpAddOutKernelTest, BroadcastDimSizeMissingBA) {
261   TensorFactory<ScalarType::Float> tf;
262 
263   Tensor x = tf.make({1, 2}, {0.7453382015228271, 0.3131374716758728});
264   Tensor y = tf.make(
265       {3, 2},
266       {0.5721208453178406,
267        0.9629082083702087,
268        0.19517338275909424,
269        0.4107270836830139,
270        0.945562481880188,
271        0.8788509368896484});
272   Tensor expected_result = tf.make(
273       {3, 2},
274       {1.3174591064453125,
275        1.2760456800460815,
276        0.9405115842819214,
277        0.7238645553588867,
278        1.6909006834030151,
279        1.191988468170166});
280 
281   Tensor out = tf.zeros({3, 2});
282   Tensor ret = op_add_out(x, y, 1, out);
283   EXPECT_TENSOR_CLOSE(out, expected_result);
284 }
285 
TEST_F(OpAddOutKernelTest,BroadcastSupported)286 TEST_F(OpAddOutKernelTest, BroadcastSupported) {
287   TensorFactory<ScalarType::Float> tf;
288 
289   const std::vector<int32_t> sizes = {2, 2};
290 
291   Tensor a = tf.zeros({5, 1, 3, 1});
292   Tensor b = tf.ones({2, 1, 4});
293 
294   // Destination for the broadcasting sum. Follow the broadcasting rules in
295   // https://fburl.com/n9wl4d0o
296   Tensor out = tf.zeros({5, 2, 3, 4});
297 
298   Tensor ret = op_add_out(a, b, 1, out);
299 
300   EXPECT_TENSOR_EQ(out, ret);
301   EXPECT_TENSOR_EQ(out, tf.ones({5, 2, 3, 4}));
302 }
303 
TEST_F(OpAddOutKernelTest,BroadcastOneElementTensor)304 TEST_F(OpAddOutKernelTest, BroadcastOneElementTensor) {
305   TensorFactory<ScalarType::Float> tf;
306   Tensor x = tf.make({1}, {1.75});
307   Tensor y = tf.make({3, 2}, {-1.5, -1, -0.5, 0, 0.5, 1.5});
308 
309   Tensor out = tf.zeros({3, 2});
310 
311   Tensor ret = op_add_out(x, y, 1, out);
312 
313   Tensor expected = tf.make(
314       {3, 2},
315       {
316           0.25,
317           0.75,
318           1.25,
319           1.75,
320           2.25,
321           3.25,
322       });
323 
324   EXPECT_TENSOR_EQ(out, expected);
325 
326   out = op_add_out(y, x, 1, out);
327   EXPECT_TENSOR_EQ(out, expected);
328 }
329 
TEST_F(OpAddOutKernelTest,BroadcastOneElementTensorTypePromotion)330 TEST_F(OpAddOutKernelTest, BroadcastOneElementTensorTypePromotion) {
331   TensorFactory<ScalarType::Float> tf;
332   TensorFactory<ScalarType::Double> tfDouble;
333   Tensor x = tfDouble.make({1}, {1.75});
334   Tensor y = tf.make({3, 2}, {-1.5, -1, -0.5, 0, 0.5, 1.5});
335 
336   Tensor out = tfDouble.zeros({3, 2});
337 
338   Tensor ret = op_add_out(x, y, 1, out);
339 
340   Tensor expected = tfDouble.make(
341       {3, 2},
342       {
343           0.25,
344           0.75,
345           1.25,
346           1.75,
347           2.25,
348           3.25,
349       });
350 
351   EXPECT_TENSOR_EQ(out, expected);
352 
353   out = op_add_out(y, x, 1, out);
354   EXPECT_TENSOR_EQ(out, expected);
355 }
356 
TEST_F(OpAddOutKernelTest,BroadcastOneElementRank0Tensor)357 TEST_F(OpAddOutKernelTest, BroadcastOneElementRank0Tensor) {
358   TensorFactory<ScalarType::Float> tf;
359 
360   Tensor a = tf.make({1}, {5});
361   Tensor b = tf.make({}, {2});
362 
363   Tensor out = tf.zeros({1});
364 
365   op_add_out(a, b, 1, out);
366 
367   Tensor ret = tf.make({1}, {7});
368   EXPECT_TENSOR_EQ(out, ret);
369 
370   op_add_out(b, a, 1, out);
371   EXPECT_TENSOR_EQ(out, ret);
372 }
373 
374 //
375 // Death Tests
376 //
377 
TEST_F(OpAddOutKernelTest,IntInputsFloatAlphaDies)378 TEST_F(OpAddOutKernelTest, IntInputsFloatAlphaDies) {
379   // op_add_out() doesn't handle floating alpha for intergal inputs
380   TensorFactory<ScalarType::Int> tf;
381 
382   const std::vector<int32_t> sizes = {2, 2};
383 
384   // Destination for the op.
385   Tensor out = tf.zeros(sizes);
386 
387   // Elementwise add operation on two integral tensor with floating alpha
388   // should cause an assertion and kill the test process.
389   ET_EXPECT_KERNEL_FAILURE(
390       context_, op_add_out(tf.ones(sizes), tf.ones(sizes), /*alpha=*/.7, out));
391 }
392 
TEST_F(OpAddOutKernelTest,BoolInputsFloatAlphaDies)393 TEST_F(OpAddOutKernelTest, BoolInputsFloatAlphaDies) {
394   // op_add_out() doesn't handle floating alpha for intergal inputs
395   TensorFactory<ScalarType::Bool> tf;
396 
397   const std::vector<int32_t> sizes = {2, 2};
398 
399   // Destination for the op.
400   Tensor out = tf.zeros(sizes);
401 
402   // Elementwise add operation on two integral tensor with floating alpha
403   // should cause an assertion and kill the test process.
404   ET_EXPECT_KERNEL_FAILURE(
405       context_, op_add_out(tf.ones(sizes), tf.ones(sizes), /*alpha=*/.7, out));
406 }
407 
TEST_F(OpAddOutKernelTest,IntOutputWithFloatInputDies)408 TEST_F(OpAddOutKernelTest, IntOutputWithFloatInputDies) {
409   TensorFactory<ScalarType::Int> tfi;
410   TensorFactory<ScalarType::Float> tff;
411 
412   const std::vector<int32_t> sizes = {2, 2};
413 
414   // Addends.
415   Tensor a = tfi.make(sizes, /*data=*/{2, 4, 3, 3});
416   Tensor b = tff.make(sizes, /*data=*/{2, 4, 3, 3});
417 
418   // Destination for the sum.
419   Tensor out = tfi.zeros(sizes);
420 
421   ET_EXPECT_KERNEL_FAILURE(context_, op_add_out(a, b, /*alpha=*/1, out));
422 }
423 
TEST_F(OpAddOutKernelTest,BoolOutputWithIntegralInput)424 TEST_F(OpAddOutKernelTest, BoolOutputWithIntegralInput) {
425   // op_add_out() doesn't handle Bool.
426   TensorFactory<ScalarType::Bool> tf;
427   TensorFactory<ScalarType::Int> tfi;
428 
429   const std::vector<int32_t> sizes = {2, 2};
430 
431   // Addends.
432   Tensor a = tfi.make(sizes, /*data=*/{false, true, true, false});
433   Tensor b = tfi.make(sizes, /*data=*/{2, 3, 4, 3});
434 
435   // Destination for the sum.
436   Tensor out = tf.zeros(sizes);
437 
438   ET_EXPECT_KERNEL_FAILURE(context_, op_add_out(a, b, /*alpha=*/1, out));
439 }
440 
TEST_F(OpAddOutKernelTest,MismatchedNonBroadcastableInputShapesDies)441 TEST_F(OpAddOutKernelTest, MismatchedNonBroadcastableInputShapesDies) {
442   TensorFactory<ScalarType::Int> tf;
443 
444   // Addends with different shapes.
445   Tensor a = tf.ones(/*sizes=*/{4, 2});
446   Tensor b = tf.ones(/*sizes=*/{2, 2});
447 
448   // Destination for the sum; matches the shape of one of the inputs.
449   Tensor out = tf.zeros(/*sizes=*/{8});
450 
451   // Adding the two mismatched tensors should cause an assertion and kill the
452   // test process.
453   ET_EXPECT_KERNEL_FAILURE(context_, op_add_out(a, b, /*unused=*/0, out));
454 }
455 
TEST_F(OpAddOutKernelTest,MismatchedOutputShapesDies)456 TEST_F(OpAddOutKernelTest, MismatchedOutputShapesDies) {
457   if (SupportedFeatures::get()->output_resize) {
458     GTEST_SKIP()
459         << "The current kernel supports implicitly resizing output tensor";
460   }
461 
462   TensorFactory<ScalarType::Int> tf;
463 
464   const std::vector<int32_t> sizes = {2, 2};
465 
466   // Addends with the same shapes.
467   Tensor a = tf.ones(sizes);
468   Tensor b = tf.ones(sizes);
469 
470   // Destination with a different shape.
471   Tensor out = tf.zeros(/*sizes=*/{4});
472 
473   // Adding the tensors into a mismatched output should cause an assertion and
474   // kill the test process.
475   ET_EXPECT_KERNEL_FAILURE(context_, op_add_out(a, b, /*unused=*/0, out));
476 }
477 
TEST_F(OpAddOutKernelTest,SimpleGeneratedCase)478 TEST_F(OpAddOutKernelTest, SimpleGeneratedCase) {
479   et_pal_init();
480 
481   TensorFactory<ScalarType::Float> tf;
482 
483   Tensor x = tf.make(
484       {10, 10},
485       {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
486        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
487        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
488        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
489        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
490        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
491        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
492        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
493   Tensor y = tf.make(
494       {10, 10},
495       {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
496        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
497        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
498        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
499        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
500        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
501        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
502        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
503   Tensor expected_result = tf.make(
504       {10, 10},
505       {2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
506        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
507        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
508        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
509        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
510        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
511        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
512        2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0});
513 
514   Tensor out = tf.zeros({10, 10});
515   Tensor ret = op_add_out(x, y, 1, out);
516   EXPECT_TENSOR_CLOSE(out, expected_result);
517 }
518 
TEST_F(OpAddOutKernelTest,DynamicShapeUpperBoundSameAsExpected)519 TEST_F(OpAddOutKernelTest, DynamicShapeUpperBoundSameAsExpected) {
520   TensorFactory<ScalarType::Float> tf;
521 
522   Tensor x = tf.make(
523       {3, 2},
524       {0.04024535417556763,
525        0.6475827097892761,
526        0.9623860716819763,
527        0.6206040978431702,
528        0.47623592615127563,
529        0.4509747624397278});
530   Tensor y = tf.make(
531       {3, 2},
532       {0.7232733964920044,
533        0.3614498972892761,
534        0.15757757425308228,
535        0.9975225925445557,
536        0.09227871894836426,
537        0.3320664167404175});
538   Tensor expected_result = tf.make(
539       {3, 2},
540       {0.763518750667572,
541        1.0090326070785522,
542        1.1199636459350586,
543        1.618126630783081,
544        0.5685146450996399,
545        0.7830411791801453});
546 
547   Tensor out =
548       tf.zeros({3, 2}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
549   Tensor ret = op_add_out(x, y, 1, out);
550   EXPECT_TENSOR_CLOSE(out, expected_result);
551 }
552 
TEST_F(OpAddOutKernelTest,DynamicShapeUpperBoundLargerThanExpected)553 TEST_F(OpAddOutKernelTest, DynamicShapeUpperBoundLargerThanExpected) {
554   TensorFactory<ScalarType::Float> tf;
555 
556   Tensor x = tf.make(
557       {3, 2},
558       {0.04024535417556763,
559        0.6475827097892761,
560        0.9623860716819763,
561        0.6206040978431702,
562        0.47623592615127563,
563        0.4509747624397278});
564   Tensor y = tf.make(
565       {3, 2},
566       {0.7232733964920044,
567        0.3614498972892761,
568        0.15757757425308228,
569        0.9975225925445557,
570        0.09227871894836426,
571        0.3320664167404175});
572   Tensor expected_result = tf.make(
573       {3, 2},
574       {0.763518750667572,
575        1.0090326070785522,
576        1.1199636459350586,
577        1.618126630783081,
578        0.5685146450996399,
579        0.7830411791801453});
580 
581   Tensor out =
582       tf.zeros({10, 10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
583   Tensor ret = op_add_out(x, y, 1, out);
584   EXPECT_TENSOR_CLOSE(out, expected_result);
585 }
586 
TEST_F(OpAddOutKernelTest,DynamicShapeUnbound)587 TEST_F(OpAddOutKernelTest, DynamicShapeUnbound) {
588   GTEST_SKIP() << "Dynamic shape not supported";
589   TensorFactory<ScalarType::Float> tf;
590 
591   Tensor x = tf.make(
592       {3, 2},
593       {0.04024535417556763,
594        0.6475827097892761,
595        0.9623860716819763,
596        0.6206040978431702,
597        0.47623592615127563,
598        0.4509747624397278});
599   Tensor y = tf.make(
600       {3, 2},
601       {0.7232733964920044,
602        0.3614498972892761,
603        0.15757757425308228,
604        0.9975225925445557,
605        0.09227871894836426,
606        0.3320664167404175});
607   Tensor expected_result = tf.make(
608       {3, 2},
609       {0.763518750667572,
610        1.0090326070785522,
611        1.1199636459350586,
612        1.618126630783081,
613        0.5685146450996399,
614        0.7830411791801453});
615 
616   Tensor out =
617       tf.zeros({1, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND);
618   Tensor ret = op_add_out(x, y, 1, out);
619   EXPECT_TENSOR_CLOSE(out, expected_result);
620 }
621 
TEST_F(OpAddScalarOutKernelTest,SanityCheck)622 TEST_F(OpAddScalarOutKernelTest, SanityCheck) {
623   TensorFactory<ScalarType::Int> tf;
624 
625   const std::vector<int32_t> sizes = {2, 2};
626 
627   Tensor out = tf.zeros(sizes);
628 
629   op_add_scalar_out(tf.make(sizes, {1, 2, 4, 8}), true, /*alpha=*/2, out);
630 
631   // Check that it matches the expected output.
632   EXPECT_TENSOR_EQ(out, tf.make(sizes, {3, 4, 6, 10}));
633 }
634 
TEST_F(OpAddScalarOutKernelTest,OptimizedSanityCheck)635 TEST_F(OpAddScalarOutKernelTest, OptimizedSanityCheck) {
636   TensorFactory<ScalarType::Float> tf;
637 
638   const std::vector<int32_t> sizes = {2, 2};
639 
640   Tensor out = tf.zeros(sizes);
641 
642   op_add_scalar_out(
643       tf.make(sizes, {1.3, 2.1, 4.6, 8.2}), 1.9, /*alpha=*/2.8, out);
644 
645   // Check that it matches the expected output.
646   EXPECT_TENSOR_CLOSE(out, tf.make(sizes, {6.62, 7.42, 9.92, 13.52}));
647 }
648 
TEST_F(OpAddScalarOutKernelTest,DtypeTest_float16_bool_int_float16)649 TEST_F(OpAddScalarOutKernelTest, DtypeTest_float16_bool_int_float16) {
650   torch::executor::testing::TensorFactory<exec_aten::ScalarType::Half> tfHalf;
651 
652   exec_aten::Tensor self = tfHalf.ones({2, 2});
653   exec_aten::Scalar other = exec_aten::Scalar(true);
654   exec_aten::Scalar alpha = exec_aten::Scalar(1);
655   exec_aten::Tensor out = tfHalf.zeros({2, 2});
656   exec_aten::Tensor out_expected = tfHalf.full({2, 2}, 2.0);
657   op_add_scalar_out(self, other, alpha, out);
658   EXPECT_TENSOR_CLOSE(out, out_expected);
659 }
660