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 using namespace ::testing;
19 using exec_aten::IntArrayRef;
20 using exec_aten::Scalar;
21 using exec_aten::ScalarType;
22 using exec_aten::Tensor;
23 using torch::executor::testing::SupportedFeatures;
24 using torch::executor::testing::TensorFactory;
25
26 class OpConstantPadNDOutTest : public OperatorTest {
27 protected:
op_constant_pad_nd_out(const Tensor & self,const IntArrayRef padding,const Scalar & value,Tensor & out)28 Tensor& op_constant_pad_nd_out(
29 const Tensor& self,
30 const IntArrayRef padding,
31 const Scalar& value,
32 Tensor& out) {
33 return torch::executor::aten::constant_pad_nd_outf(
34 context_, self, padding, value, out);
35 }
36
37 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim2()38 void test_constant_pad_nd_out_dim2() {
39 TensorFactory<DTYPE> tf;
40
41 const std::vector<int32_t> sizes = {2, 4, 4};
42 const std::vector<int32_t> sizes_out = {2, 4, 6};
43 const std::vector<int64_t> padding = {1, 1};
44
45 // clang-format off
46 Tensor self = tf.make(
47 sizes,
48 {
49 1, 2, 3, 4,
50 5, 6, 7, 8,
51 1, 2, 3, 4,
52 5, 6, 7, 8,
53
54 1, 2, 3, 4,
55 5, 6, 7, 8,
56 1, 2, 3, 4,
57 5, 6, 7, 8,
58 });
59 // clang-format on
60
61 // clang-format off
62 Tensor expected = tf.make(
63 sizes_out,
64 {
65 7, 1, 2, 3, 4, 7,
66 7, 5, 6, 7, 8, 7,
67 7, 1, 2, 3, 4, 7,
68 7, 5, 6, 7, 8, 7,
69
70 7, 1, 2, 3, 4, 7,
71 7, 5, 6, 7, 8, 7,
72 7, 1, 2, 3, 4, 7,
73 7, 5, 6, 7, 8, 7,
74 });
75 // clang-format on
76
77 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
78 Tensor out = tf.zeros(sizes_out);
79
80 // Valid input should give the expected output
81 op_constant_pad_nd_out(self, padding_ref, 7, out);
82 EXPECT_TENSOR_CLOSE(out, expected);
83 }
84
85 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim1()86 void test_constant_pad_nd_out_dim1() {
87 TensorFactory<DTYPE> tf;
88
89 const std::vector<int32_t> sizes = {2, 4, 4};
90 const std::vector<int32_t> sizes_out = {2, 6, 4};
91 const std::vector<int64_t> padding = {0, 0, 2, 0};
92
93 // clang-format off
94 Tensor self = tf.make(
95 sizes,
96 {
97 1, 2, 3, 4,
98 5, 6, 7, 8,
99 1, 2, 3, 4,
100 5, 6, 7, 8,
101
102 1, 2, 3, 4,
103 5, 6, 7, 8,
104 1, 2, 3, 4,
105 5, 6, 7, 8,
106 });
107 // clang-format on
108
109 // clang-format off
110 Tensor expected = tf.make(
111 sizes_out,
112 {
113 7, 7, 7, 7,
114 7, 7, 7, 7,
115 1, 2, 3, 4,
116 5, 6, 7, 8,
117 1, 2, 3, 4,
118 5, 6, 7, 8,
119
120 7, 7, 7, 7,
121 7, 7, 7, 7,
122 1, 2, 3, 4,
123 5, 6, 7, 8,
124 1, 2, 3, 4,
125 5, 6, 7, 8,
126 });
127 // clang-format on
128
129 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
130 Tensor out = tf.zeros(sizes_out);
131
132 // Valid input should give the expected output
133 op_constant_pad_nd_out(self, padding_ref, 7, out);
134 EXPECT_TENSOR_CLOSE(out, expected);
135 }
136
137 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim0()138 void test_constant_pad_nd_out_dim0() {
139 TensorFactory<DTYPE> tf;
140
141 const std::vector<int32_t> sizes = {2, 4, 4};
142 const std::vector<int32_t> sizes_out = {3, 4, 4};
143 const std::vector<int64_t> padding = {0, 0, 0, 0, 1, 0};
144
145 // clang-format off
146 Tensor self = tf.make(
147 sizes,
148 {
149 1, 2, 3, 4,
150 5, 6, 7, 8,
151 1, 2, 3, 4,
152 5, 6, 7, 8,
153
154 1, 2, 3, 4,
155 5, 6, 7, 8,
156 1, 2, 3, 4,
157 5, 6, 7, 8,
158 });
159 // clang-format on
160
161 // clang-format off
162 Tensor expected = tf.make(
163 sizes_out,
164 {
165 7, 7, 7, 7,
166 7, 7, 7, 7,
167 7, 7, 7, 7,
168 7, 7, 7, 7,
169
170 1, 2, 3, 4,
171 5, 6, 7, 8,
172 1, 2, 3, 4,
173 5, 6, 7, 8,
174
175 1, 2, 3, 4,
176 5, 6, 7, 8,
177 1, 2, 3, 4,
178 5, 6, 7, 8,
179 });
180 // clang-format on
181
182 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
183 Tensor out = tf.zeros(sizes_out);
184
185 // Valid input should give the expected output
186 op_constant_pad_nd_out(self, padding_ref, 7, out);
187 EXPECT_TENSOR_CLOSE(out, expected);
188 }
189
190 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim12()191 void test_constant_pad_nd_out_dim12() {
192 TensorFactory<DTYPE> tf;
193
194 const std::vector<int32_t> sizes = {2, 4, 4};
195 const std::vector<int32_t> sizes_out = {2, 6, 7};
196 const std::vector<int64_t> padding = {2, 1, 0, 2};
197
198 // clang-format off
199 Tensor self = tf.make(
200 sizes,
201 {
202 1, 2, 3, 4,
203 5, 6, 7, 8,
204 1, 2, 3, 4,
205 5, 6, 7, 8,
206
207 1, 2, 3, 4,
208 5, 6, 7, 8,
209 1, 2, 3, 4,
210 5, 6, 7, 8,
211 });
212 // clang-format on
213
214 // clang-format off
215 Tensor expected = tf.make(
216 sizes_out,
217 {
218 7, 7, 1, 2, 3, 4, 7,
219 7, 7, 5, 6, 7, 8, 7,
220 7, 7, 1, 2, 3, 4, 7,
221 7, 7, 5, 6, 7, 8, 7,
222 7, 7, 7, 7, 7, 7, 7,
223 7, 7, 7, 7, 7, 7, 7,
224
225 7, 7, 1, 2, 3, 4, 7,
226 7, 7, 5, 6, 7, 8, 7,
227 7, 7, 1, 2, 3, 4, 7,
228 7, 7, 5, 6, 7, 8, 7,
229 7, 7, 7, 7, 7, 7, 7,
230 7, 7, 7, 7, 7, 7, 7,
231 });
232 // clang-format on
233
234 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
235 Tensor out = tf.zeros(sizes_out);
236
237 // Valid input should give the expected output
238 op_constant_pad_nd_out(self, padding_ref, 7, out);
239 EXPECT_TENSOR_CLOSE(out, expected);
240 }
241
242 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim02()243 void test_constant_pad_nd_out_dim02() {
244 TensorFactory<DTYPE> tf;
245
246 const std::vector<int32_t> sizes = {2, 4, 4};
247 const std::vector<int32_t> sizes_out = {3, 4, 7};
248 const std::vector<int64_t> padding = {2, 1, 0, 0, 0, 1};
249
250 // clang-format off
251 Tensor self = tf.make(
252 sizes,
253 {
254 1, 2, 3, 4,
255 5, 6, 7, 8,
256 1, 2, 3, 4,
257 5, 6, 7, 8,
258
259 1, 2, 3, 4,
260 5, 6, 7, 8,
261 1, 2, 3, 4,
262 5, 6, 7, 8,
263 });
264 // clang-format on
265
266 // clang-format off
267 Tensor expected = tf.make(
268 sizes_out,
269 {
270 7, 7, 1, 2, 3, 4, 7,
271 7, 7, 5, 6, 7, 8, 7,
272 7, 7, 1, 2, 3, 4, 7,
273 7, 7, 5, 6, 7, 8, 7,
274
275 7, 7, 1, 2, 3, 4, 7,
276 7, 7, 5, 6, 7, 8, 7,
277 7, 7, 1, 2, 3, 4, 7,
278 7, 7, 5, 6, 7, 8, 7,
279
280 7, 7, 7, 7, 7, 7, 7,
281 7, 7, 7, 7, 7, 7, 7,
282 7, 7, 7, 7, 7, 7, 7,
283 7, 7, 7, 7, 7, 7, 7,
284 });
285 // clang-format on
286
287 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
288 Tensor out = tf.zeros(sizes_out);
289
290 // Valid input should give the expected output
291 op_constant_pad_nd_out(self, padding_ref, 7, out);
292 EXPECT_TENSOR_CLOSE(out, expected);
293 }
294
295 template <ScalarType DTYPE>
test_constant_pad_nd_out_dim012()296 void test_constant_pad_nd_out_dim012() {
297 TensorFactory<DTYPE> tf;
298
299 const std::vector<int32_t> sizes = {2, 4, 4};
300 const std::vector<int32_t> sizes_out = {3, 5, 7};
301 const std::vector<int64_t> padding = {2, 1, 1, 0, 0, 1};
302
303 // clang-format off
304 Tensor self = tf.make(
305 sizes,
306 {
307 1, 2, 3, 4,
308 5, 6, 7, 8,
309 1, 2, 3, 4,
310 5, 6, 7, 8,
311
312 1, 2, 3, 4,
313 5, 6, 7, 8,
314 1, 2, 3, 4,
315 5, 6, 7, 8,
316 });
317 // clang-format on
318
319 // clang-format off
320 Tensor expected = tf.make(
321 sizes_out,
322 {
323 7, 7, 7, 7, 7, 7, 7,
324 7, 7, 1, 2, 3, 4, 7,
325 7, 7, 5, 6, 7, 8, 7,
326 7, 7, 1, 2, 3, 4, 7,
327 7, 7, 5, 6, 7, 8, 7,
328
329 7, 7, 7, 7, 7, 7, 7,
330 7, 7, 1, 2, 3, 4, 7,
331 7, 7, 5, 6, 7, 8, 7,
332 7, 7, 1, 2, 3, 4, 7,
333 7, 7, 5, 6, 7, 8, 7,
334
335 7, 7, 7, 7, 7, 7, 7,
336 7, 7, 7, 7, 7, 7, 7,
337 7, 7, 7, 7, 7, 7, 7,
338 7, 7, 7, 7, 7, 7, 7,
339 7, 7, 7, 7, 7, 7, 7,
340 });
341 // clang-format on
342
343 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
344 Tensor out = tf.zeros(sizes_out);
345
346 // Valid input should give the expected output
347 op_constant_pad_nd_out(self, padding_ref, 7, out);
348 EXPECT_TENSOR_CLOSE(out, expected);
349 }
350 };
351
TEST_F(OpConstantPadNDOutTest,TestPadDim2)352 TEST_F(OpConstantPadNDOutTest, TestPadDim2) {
353 #define TEST_ENTRY(ctype, dtype) \
354 test_constant_pad_nd_out_dim2<ScalarType::dtype>();
355
356 ET_FORALL_REAL_TYPES(TEST_ENTRY);
357 #undef TEST_ENTRY
358 }
359
TEST_F(OpConstantPadNDOutTest,TestPadDim1)360 TEST_F(OpConstantPadNDOutTest, TestPadDim1) {
361 #define TEST_ENTRY(ctype, dtype) \
362 test_constant_pad_nd_out_dim1<ScalarType::dtype>();
363
364 ET_FORALL_REAL_TYPES(TEST_ENTRY);
365 #undef TEST_ENTRY
366 }
367
TEST_F(OpConstantPadNDOutTest,TestPadDim0)368 TEST_F(OpConstantPadNDOutTest, TestPadDim0) {
369 #define TEST_ENTRY(ctype, dtype) \
370 test_constant_pad_nd_out_dim0<ScalarType::dtype>();
371
372 ET_FORALL_REAL_TYPES(TEST_ENTRY);
373 #undef TEST_ENTRY
374 }
375
TEST_F(OpConstantPadNDOutTest,TestPadDim1And2)376 TEST_F(OpConstantPadNDOutTest, TestPadDim1And2) {
377 #define TEST_ENTRY(ctype, dtype) \
378 test_constant_pad_nd_out_dim12<ScalarType::dtype>();
379
380 ET_FORALL_REAL_TYPES(TEST_ENTRY);
381 #undef TEST_ENTRY
382 }
383
TEST_F(OpConstantPadNDOutTest,TestPadDim0And2)384 TEST_F(OpConstantPadNDOutTest, TestPadDim0And2) {
385 #define TEST_ENTRY(ctype, dtype) \
386 test_constant_pad_nd_out_dim02<ScalarType::dtype>();
387
388 ET_FORALL_REAL_TYPES(TEST_ENTRY);
389 #undef TEST_ENTRY
390 }
391
TEST_F(OpConstantPadNDOutTest,TestPadDim0And1And2)392 TEST_F(OpConstantPadNDOutTest, TestPadDim0And1And2) {
393 #define TEST_ENTRY(ctype, dtype) \
394 test_constant_pad_nd_out_dim012<ScalarType::dtype>();
395
396 ET_FORALL_REAL_TYPES(TEST_ENTRY);
397 #undef TEST_ENTRY
398 }
399
TEST_F(OpConstantPadNDOutTest,DifferentInputOutputTypesFail)400 TEST_F(OpConstantPadNDOutTest, DifferentInputOutputTypesFail) {
401 TensorFactory<ScalarType::Float> tf;
402 TensorFactory<ScalarType::Double> tf_out;
403
404 const std::vector<int32_t> sizes = {1, 4, 4};
405 const std::vector<int32_t> sizes_out = {1, 4, 6};
406 const std::vector<int64_t> padding = {1, 1};
407
408 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
409
410 Tensor self = tf.ones(sizes);
411 Tensor out = tf_out.zeros(sizes_out);
412
413 ET_EXPECT_KERNEL_FAILURE(
414 context_, op_constant_pad_nd_out(self, padding_ref, 0, out));
415 }
416
TEST_F(OpConstantPadNDOutTest,OddNumberOfPaddingElementsFail)417 TEST_F(OpConstantPadNDOutTest, OddNumberOfPaddingElementsFail) {
418 TensorFactory<ScalarType::Float> tf;
419
420 const std::vector<int32_t> sizes = {1, 4, 4};
421 const std::vector<int32_t> sizes_out = {1, 4, 4};
422 const std::vector<int64_t> padding = {1, 1, 0};
423
424 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
425
426 Tensor self = tf.ones(sizes);
427 Tensor out = tf.zeros(sizes_out);
428
429 ET_EXPECT_KERNEL_FAILURE(
430 context_, op_constant_pad_nd_out(self, padding_ref, 0, out));
431 }
432
TEST_F(OpConstantPadNDOutTest,TooManyPaddingElementsFail)433 TEST_F(OpConstantPadNDOutTest, TooManyPaddingElementsFail) {
434 TensorFactory<ScalarType::Float> tf;
435
436 const std::vector<int32_t> sizes = {1, 4, 4};
437 const std::vector<int32_t> sizes_out = {1, 4, 4};
438 const std::vector<int64_t> padding = {3, 2, 1, 1, 2, 1, 1, 0};
439
440 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
441
442 Tensor self = tf.ones(sizes);
443 Tensor out = tf.zeros(sizes_out);
444
445 ET_EXPECT_KERNEL_FAILURE(
446 context_, op_constant_pad_nd_out(self, padding_ref, 0, out));
447 }
448
TEST_F(OpConstantPadNDOutTest,IncorrectOutputShapeFail)449 TEST_F(OpConstantPadNDOutTest, IncorrectOutputShapeFail) {
450 if (SupportedFeatures::get()->is_aten) {
451 GTEST_SKIP() << "ATen kernel can handle reshape output";
452 }
453
454 TensorFactory<ScalarType::Float> tf;
455
456 const std::vector<int32_t> sizes = {1, 4, 4};
457 const std::vector<int32_t> sizes_out = {1, 4, 4};
458 const std::vector<int64_t> padding = {1, 1};
459
460 IntArrayRef padding_ref = IntArrayRef(padding.data(), padding.size());
461
462 Tensor self = tf.ones(sizes);
463 Tensor out = tf.zeros(sizes_out);
464
465 ET_EXPECT_KERNEL_FAILURE(
466 context_, op_constant_pad_nd_out(self, padding_ref, 0, out));
467 }
468