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 #include <executorch/test/utils/DeathTest.h>
16
17 #include <gtest/gtest.h>
18
19 using namespace ::testing;
20 using exec_aten::MemoryFormat;
21 using exec_aten::optional;
22 using exec_aten::Scalar;
23 using exec_aten::ScalarType;
24 using exec_aten::Tensor;
25 using torch::executor::testing::TensorFactory;
26
27 class OpFullLikeTest : public OperatorTest {
28 protected:
op_full_like_out(const Tensor & self,const Scalar & fill_value,optional<MemoryFormat> memory_format,Tensor & out)29 Tensor& op_full_like_out(
30 const Tensor& self,
31 const Scalar& fill_value,
32 optional<MemoryFormat> memory_format,
33 Tensor& out) {
34 return torch::executor::aten::full_like_outf(
35 context_, self, fill_value, memory_format, out);
36 }
37
38 template <ScalarType DTYPE>
test_full_like_out()39 void test_full_like_out() {
40 TensorFactory<DTYPE> tf;
41 const std::vector<int32_t> sizes = {2, 2};
42 Tensor in = tf.zeros(sizes);
43 Tensor out = tf.zeros(sizes);
44 Scalar value = 42;
45 MemoryFormat memory_format = MemoryFormat::Contiguous;
46
47 // Check that it matches the expected output.
48 op_full_like_out(in, value, memory_format, out);
49 EXPECT_TENSOR_EQ(out, tf.make(sizes, /*data=*/{42, 42, 42, 42}));
50
51 value = 1;
52 op_full_like_out(in, value, memory_format, out);
53 EXPECT_TENSOR_EQ(out, tf.ones(sizes));
54 }
55
56 template <ScalarType DTYPE>
test_full_like_out_mismatched_shape()57 void test_full_like_out_mismatched_shape() {
58 TensorFactory<DTYPE> tf;
59 const std::vector<int32_t> sizes = {2, 2};
60 Tensor in = tf.zeros(/*sizes=*/{2, 2});
61 Tensor out = tf.zeros(/*sizes=*/{4, 2});
62 Scalar value = 42;
63 MemoryFormat memory_format;
64
65 ET_EXPECT_KERNEL_FAILURE(
66 context_, op_full_like_out(in, value, memory_format, out));
67 }
68 };
69
70 template <>
test_full_like_out()71 void OpFullLikeTest::test_full_like_out<ScalarType::Bool>() {
72 TensorFactory<ScalarType::Bool> tf;
73 const std::vector<int32_t> sizes = {2, 2};
74 Tensor in = tf.zeros(sizes);
75 Tensor out = tf.zeros(sizes);
76 Scalar value = true;
77 MemoryFormat memory_format = MemoryFormat::Contiguous;
78
79 // Check that it matches the expected output.
80 op_full_like_out(in, value, memory_format, out);
81 EXPECT_TENSOR_EQ(out, tf.make(sizes, /*data=*/{true, true, true, true}));
82
83 value = false;
84 op_full_like_out(in, value, memory_format, out);
85 EXPECT_TENSOR_EQ(out, tf.zeros(sizes));
86 }
87
TEST_F(OpFullLikeTest,AllRealOutputPasses)88 TEST_F(OpFullLikeTest, AllRealOutputPasses) {
89 #define TEST_ENTRY(ctype, dtype) test_full_like_out<ScalarType::dtype>();
90 ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
91 #undef TEST_ENTRY
92 }
93
TEST_F(OpFullLikeTest,MismatchedShapeDies)94 TEST_F(OpFullLikeTest, MismatchedShapeDies) {
95 if (torch::executor::testing::SupportedFeatures::get()->is_aten) {
96 GTEST_SKIP() << "ATen kernel can handle mismatched shapes";
97 }
98 #define TEST_ENTRY(ctype, dtype) \
99 test_full_like_out_mismatched_shape<ScalarType::dtype>();
100 ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
101 #undef TEST_ENTRY
102 }
103
TEST_F(OpFullLikeTest,SimpleGeneratedCase)104 TEST_F(OpFullLikeTest, SimpleGeneratedCase) {
105 TensorFactory<ScalarType::Float> tf;
106
107 Tensor x = tf.make(
108 {10, 10},
109 {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,
110 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,
111 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,
112 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,
113 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,
114 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,
115 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,
116 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
117 Tensor expected_result = tf.make(
118 {10, 10},
119 {3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
120 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
121 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
122 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
123 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
124 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
125 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0,
126 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0});
127
128 Tensor out = tf.zeros({10, 10});
129 Tensor ret = op_full_like_out(x, Scalar(3.0), MemoryFormat::Contiguous, out);
130 EXPECT_TENSOR_CLOSE(out, expected_result);
131 }
132
TEST_F(OpFullLikeTest,DynamicShapeUpperBoundSameAsExpected)133 TEST_F(OpFullLikeTest, DynamicShapeUpperBoundSameAsExpected) {
134 TensorFactory<ScalarType::Float> tf;
135
136 Tensor x = tf.make(
137 {3, 2},
138 {0.04876953363418579,
139 0.816348671913147,
140 0.44230276346206665,
141 0.2767965793609619,
142 0.8998266458511353,
143 0.09595239162445068});
144 Tensor expected_result = tf.make({3, 2}, {3.0, 3.0, 3.0, 3.0, 3.0, 3.0});
145
146 Tensor out =
147 tf.zeros({3, 2}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
148 Tensor ret = op_full_like_out(x, Scalar(3.0), MemoryFormat::Contiguous, out);
149 EXPECT_TENSOR_CLOSE(out, expected_result);
150 }
151
TEST_F(OpFullLikeTest,DynamicShapeUpperBoundLargerThanExpected)152 TEST_F(OpFullLikeTest, DynamicShapeUpperBoundLargerThanExpected) {
153 TensorFactory<ScalarType::Float> tf;
154
155 Tensor x = tf.make(
156 {3, 2},
157 {0.04876953363418579,
158 0.816348671913147,
159 0.44230276346206665,
160 0.2767965793609619,
161 0.8998266458511353,
162 0.09595239162445068});
163 Tensor expected_result = tf.make({3, 2}, {3.0, 3.0, 3.0, 3.0, 3.0, 3.0});
164
165 Tensor out =
166 tf.zeros({10, 10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
167 Tensor ret = op_full_like_out(x, Scalar(3.0), MemoryFormat::Contiguous, out);
168 EXPECT_TENSOR_CLOSE(out, expected_result);
169 }
170
TEST_F(OpFullLikeTest,DynamicShapeUnbound)171 TEST_F(OpFullLikeTest, DynamicShapeUnbound) {
172 GTEST_SKIP() << "Dynamic shape unbound not supported";
173 TensorFactory<ScalarType::Float> tf;
174
175 Tensor x = tf.make(
176 {3, 2},
177 {0.04876953363418579,
178 0.816348671913147,
179 0.44230276346206665,
180 0.2767965793609619,
181 0.8998266458511353,
182 0.09595239162445068});
183 Tensor expected_result = tf.make({3, 2}, {3.0, 3.0, 3.0, 3.0, 3.0, 3.0});
184
185 Tensor out =
186 tf.zeros({1, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND);
187 Tensor ret = op_full_like_out(x, Scalar(3.0), MemoryFormat::Contiguous, out);
188 EXPECT_TENSOR_CLOSE(out, expected_result);
189 }
190
TEST_F(OpFullLikeTest,HalfSupport)191 TEST_F(OpFullLikeTest, HalfSupport) {
192 TensorFactory<ScalarType::Half> tf;
193 optional<MemoryFormat> memory_format;
194 Tensor in = tf.ones({2, 3});
195 Tensor out = tf.zeros({2, 3});
196
197 op_full_like_out(in, false, memory_format, out);
198 EXPECT_TENSOR_CLOSE(out, tf.full({2, 3}, 0));
199
200 op_full_like_out(in, true, memory_format, out);
201 EXPECT_TENSOR_CLOSE(out, tf.full({2, 3}, 1));
202
203 op_full_like_out(in, 7, memory_format, out);
204 EXPECT_TENSOR_CLOSE(out, tf.full({2, 3}, 7));
205
206 op_full_like_out(in, 2.5, memory_format, out);
207 EXPECT_TENSOR_CLOSE(out, tf.full({2, 3}, 2.5));
208
209 op_full_like_out(in, INFINITY, memory_format, out);
210 EXPECT_TENSOR_CLOSE(out, tf.full({2, 3}, INFINITY));
211 }
212