• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/runtime/core/exec_aten/util/scalar_type_util.h>
16 
17 #include <gtest/gtest.h>
18 
19 using namespace ::testing;
20 using exec_aten::ArrayRef;
21 using exec_aten::ScalarType;
22 using exec_aten::Tensor;
23 using exec_aten::TensorList;
24 using torch::executor::testing::TensorFactory;
25 using torch::executor::testing::TensorListFactory;
26 
27 class OpSplitCopyTensorOutTest : public OperatorTest {
28  protected:
op_split_copy_tensor_out(const Tensor & self,int64_t split_size,int64_t dim,TensorList out)29   void op_split_copy_tensor_out(
30       const Tensor& self,
31       int64_t split_size,
32       int64_t dim,
33       TensorList out) {
34     return torch::executor::aten::split_copy_outf(
35         context_, self, split_size, dim, out);
36   }
37 
38   template <ScalarType DTYPE>
make3x3x3(TensorFactory<DTYPE> & tf)39   Tensor make3x3x3(TensorFactory<DTYPE>& tf) {
40     // clang-format off
41     return tf.make(
42         /*sizes=*/{3, 3, 3},
43         /*data=*/
44         {
45              0,  1,  2, // tensor([[[ 0,  1,  2],
46              3,  4,  5, //          [ 3,  4,  5],
47              6,  7,  8, //          [ 6,  7,  8]],
48 
49              9, 10, 11, //         [[ 9, 10, 11],
50             12, 13, 14, //          [12, 13, 14],
51             15, 16, 17, //          [15, 16, 17]],
52 
53             18, 19, 20, //         [[18, 19, 20],
54             21, 22, 23, //          [21, 22, 23],
55             24, 25, 26, //          [24, 25, 26]]])
56         });
57     // clang-format on
58   }
59 
60   // A simple successful test case that will work for any real dtype and bool.
61   template <ScalarType DTYPE>
test_dtype()62   void test_dtype() {
63     TensorFactory<DTYPE> tf;
64     TensorListFactory<DTYPE> tlf;
65 
66     Tensor input = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 0, 0, 1});
67 
68     std::vector<Tensor> expected_out = {
69         tf.make(/*sizes=*/{1, 2}, /*data=*/{1, 0}),
70         tf.make(/*sizes=*/{1, 2}, /*data=*/{0, 1}),
71     };
72     TensorList out = tlf.zeros_like(expected_out);
73 
74     op_split_copy_tensor_out(input, /*split_size=*/1, /*dim=*/0, out);
75 
76     EXPECT_TENSOR_LISTS_EQ(out, expected_out);
77   }
78 
79   /* %python
80   import torch
81   torch.manual_seed(0)
82   x = torch.randint(10, (2, 9))
83   res = torch.split(x, 3, 1)
84   op = "op_split_copy_tensor_out"
85   opt_extra_params = "3, 1,"
86   out_args = [
87     "out_shape, dynamism",
88     "out_shape, dynamism",
89     "out_shape, dynamism"
90   ]
91   dtype = "ScalarType::Int"
92   check = "EXPECT_TENSOR_LISTS_EQ" */
93 
test_dynamic_shape(const std::vector<int32_t> & out_shape,enum torch::executor::TensorShapeDynamism dynamism)94   void test_dynamic_shape(
95       const std::vector<int32_t>& out_shape,
96       enum torch::executor::TensorShapeDynamism dynamism) {
97     /* %python
98     %rewrite(unary_op_tensor_list_out) */
99 
100     TensorFactory<ScalarType::Int> tf;
101 
102     Tensor x =
103         tf.make({2, 9}, {4, 9, 3, 0, 3, 9, 7, 3, 7, 3, 1, 6, 6, 9, 8, 6, 6, 8});
104     std::vector<Tensor> expectedv = {
105         tf.make({2, 3}, {4, 9, 3, 3, 1, 6}),
106         tf.make({2, 3}, {0, 3, 9, 6, 9, 8}),
107         tf.make({2, 3}, {7, 3, 7, 6, 6, 8})};
108     TensorList expected(expectedv.data(), expectedv.size());
109 
110     std::vector<Tensor> outv = {
111         tf.zeros(out_shape, dynamism),
112         tf.zeros(out_shape, dynamism),
113         tf.zeros(out_shape, dynamism)};
114     TensorList out(outv.data(), outv.size());
115     op_split_copy_tensor_out(x, 3, 1, out);
116     EXPECT_TENSOR_LISTS_EQ(out, expected);
117   }
118 };
119 
120 /**
121  * Returns a 3x3x3 contiguous tensor where the underlying data counts from 0 to
122  * 26.
123  */
TEST_F(OpSplitCopyTensorOutTest,Split3x3x3OnDim0)124 TEST_F(OpSplitCopyTensorOutTest, Split3x3x3OnDim0) {
125   TensorFactory<ScalarType::Int> tf;
126   TensorListFactory<ScalarType::Int> tlf;
127 
128   // Splitting on dim=N with split_size=2 will produce a list of tensors where
129   // the max dim[N] is 2, and the other dims are the same as the input.
130 
131   // clang-format off
132   std::vector<Tensor> expected_out = {
133       tf.make(
134           /*sizes=*/{2, 3, 3},
135           /*data=*/
136           {
137                0,  1,  2, // tensor([[[ 0,  1,  2],
138                3,  4,  5, //          [ 3,  4,  5],
139                6,  7,  8, //          [ 6,  7,  8]],
140 
141                9, 10, 11, //         [[ 9, 10, 11],
142               12, 13, 14, //          [12, 13, 14],
143               15, 16, 17, //          [15, 16, 17]]])
144           }),
145       tf.make(
146           /*sizes=*/{1, 3, 3},
147           /*data=*/
148           {
149               18, 19, 20, // tensor([[[18, 19, 20],
150               21, 22, 23, //          [21, 22, 23],
151               24, 25, 26, //          [24, 25, 26]]])
152           }),
153   };
154   // clang-format on
155 
156   Tensor input = make3x3x3(tf);
157 
158   // Output list with the same shapes/dtypes as the expected outputs.
159   TensorList out = tlf.zeros_like(expected_out);
160 
161   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/0, out);
162 
163   EXPECT_TENSOR_LISTS_EQ(expected_out, out);
164 
165   // Also show that python negative indexing works for this case.
166   TensorList out2 = tlf.zeros_like(expected_out);
167   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/-3, out2);
168   EXPECT_TENSOR_LISTS_EQ(expected_out, out2);
169 }
170 
TEST_F(OpSplitCopyTensorOutTest,Split3x3x3OnDim1)171 TEST_F(OpSplitCopyTensorOutTest, Split3x3x3OnDim1) {
172   TensorFactory<ScalarType::Int> tf;
173   TensorListFactory<ScalarType::Int> tlf;
174 
175   // Splitting on dim=N with split_size=2 will produce a list of tensors where
176   // the max dim[N] is 2, and the other dims are the same as the input.
177 
178   // clang-format off
179   std::vector<Tensor> expected_out = {
180       tf.make(
181           /*sizes=*/{3, 2, 3},
182           /*data=*/
183           {
184                0,  1,  2, // tensor([[[ 0,  1,  2],
185                3,  4,  5, //          [ 3,  4,  5]],
186 
187                9, 10, 11, //         [[ 9, 10, 11],
188               12, 13, 14, //          [12, 13, 14]],
189 
190               18, 19, 20, //         [[18, 19, 20],
191               21, 22, 23, //          [21, 22, 23]]]),
192           }),
193       tf.make(
194           /*sizes=*/{3, 1, 3},
195           /*data=*/
196           {
197                6,  7,  8, // tensor([[[ 6,  7,  8]],
198 
199               15, 16, 17, //         [[15, 16, 17]],
200 
201               24, 25, 26, //         [[24, 25, 26]]])
202           }),
203   };
204   // clang-format on
205 
206   Tensor input = make3x3x3(tf);
207 
208   // Output list with the same shapes/dtypes as the expected outputs.
209   TensorList out = tlf.zeros_like(expected_out);
210 
211   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/1, out);
212 
213   EXPECT_TENSOR_LISTS_EQ(expected_out, out);
214 
215   // Also show that python negative indexing works for this case.
216   TensorList out2 = tlf.zeros_like(expected_out);
217   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/-2, out2);
218   EXPECT_TENSOR_LISTS_EQ(expected_out, out2);
219 }
220 
TEST_F(OpSplitCopyTensorOutTest,Split3x3x3OnDim2)221 TEST_F(OpSplitCopyTensorOutTest, Split3x3x3OnDim2) {
222   TensorFactory<ScalarType::Int> tf;
223   TensorListFactory<ScalarType::Int> tlf;
224 
225   // Splitting on dim=N with split_size=2 will produce a list of tensors where
226   // the max dim[N] is 2, and the other dims are the same as the input.
227 
228   // clang-format off
229   std::vector<Tensor> expected_out = {
230       tf.make(
231           /*sizes=*/{3, 3, 2},
232           /*data=*/
233           {
234                0,  1, // tensor([[[ 0,  1],
235                3,  4, //          [ 3,  4],
236                6,  7, //          [ 6,  7]],
237 
238                9, 10, //         [[ 9, 10],
239               12, 13, //          [12, 13],
240               15, 16, //          [15, 16]],
241 
242               18, 19, //         [[18, 19],
243               21, 22, //          [21, 22],
244               24, 25, //          [24, 25]]])
245           }),
246       tf.make(
247           /*sizes=*/{3, 3, 1},
248           /*data=*/
249           {
250                2, // tensor([[[ 2],
251                5, //          [ 5],
252                8, //          [ 8]],
253 
254               11, //         [[11],
255               14, //          [14],
256               17, //          [17]],
257 
258               20, //         [[20],
259               23, //          [23],
260               26, //          [26]]])
261           }),
262   };
263   // clang-format on
264 
265   Tensor input = make3x3x3(tf);
266 
267   // Output list with the same shapes/dtypes as the expected outputs.
268   TensorList out = tlf.zeros_like(expected_out);
269 
270   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/2, out);
271 
272   EXPECT_TENSOR_LISTS_EQ(expected_out, out);
273 
274   // Also show that python negative indexing works for this case.
275   TensorList out2 = tlf.zeros_like(expected_out);
276   op_split_copy_tensor_out(input, /*split_size=*/2, /*dim=*/-1, out2);
277   EXPECT_TENSOR_LISTS_EQ(expected_out, out2);
278 }
279 
TEST_F(OpSplitCopyTensorOutTest,LargerSplitSizeDoesNothing)280 TEST_F(OpSplitCopyTensorOutTest, LargerSplitSizeDoesNothing) {
281   TensorFactory<ScalarType::Int> tf;
282   TensorListFactory<ScalarType::Int> tlf;
283 
284   Tensor input = make3x3x3(tf);
285 
286   // Since split_size will be >= the largest dimension, slicing along any
287   // dimension should return the unmodified input as the only output entry.
288   std::vector<Tensor> expected_out = {input};
289 
290   for (int64_t split_size = 3; split_size < 6; ++split_size) {
291     for (size_t dim = 0; dim < input.dim(); ++dim) {
292       TensorList out = tlf.zeros_like({input});
293       op_split_copy_tensor_out(input, split_size, dim, out);
294       EXPECT_TENSOR_LISTS_EQ(out, expected_out);
295     }
296   }
297 }
298 
TEST_F(OpSplitCopyTensorOutTest,AllDtypesSupported)299 TEST_F(OpSplitCopyTensorOutTest, AllDtypesSupported) {
300 #define TEST_ENTRY(ctype, dtype) test_dtype<ScalarType::dtype>();
301   ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
302 #undef TEST_ENTRY
303   // TODO: Also add tests for half, complex, quantized, and other types. Easiest
304   // way to do that would be to make TensorFactory support zeros() and ones()
305   // for those types.
306 }
307 
TEST_F(OpSplitCopyTensorOutTest,EmptyInputTensor)308 TEST_F(OpSplitCopyTensorOutTest, EmptyInputTensor) {
309   TensorFactory<ScalarType::Int> tf;
310   TensorListFactory<ScalarType::Int> tlf;
311 
312   Tensor input = tf.ones(/*sizes=*/{0});
313   EXPECT_EQ(input.numel(), 0);
314 
315   std::vector<Tensor> expected_out = {input};
316 
317   // Splitting a zero-size tensor succeeds, even for split_size zero.
318   TensorList out = tlf.zeros_like({input});
319   for (int64_t split_size = 0; split_size < 3; ++split_size) {
320     op_split_copy_tensor_out(input, split_size, /*dim=*/0, out);
321     EXPECT_TENSOR_LISTS_EQ(out, expected_out);
322   }
323 }
324 
TEST_F(OpSplitCopyTensorOutTest,ZeroDimensionalInputTensorDies)325 TEST_F(OpSplitCopyTensorOutTest, ZeroDimensionalInputTensorDies) {
326   TensorFactory<ScalarType::Int> tf;
327   TensorListFactory<ScalarType::Int> tlf;
328 
329   Tensor input = tf.ones(/*sizes=*/{});
330   // Arbitrary output shape since this input can't be split.
331   TensorList out = tlf.zeros_like({input});
332 
333   ET_EXPECT_KERNEL_FAILURE(
334       context_,
335       op_split_copy_tensor_out(input, /*split_size=*/1, /*dim=*/0, out));
336 }
337 
TEST_F(OpSplitCopyTensorOutTest,ZeroSplitSizeOnlyWorksForZeroSizeDims)338 TEST_F(OpSplitCopyTensorOutTest, ZeroSplitSizeOnlyWorksForZeroSizeDims) {
339   TensorFactory<ScalarType::Int> tf;
340   TensorListFactory<ScalarType::Int> tlf;
341 
342   Tensor input = tf.ones(/*sizes=*/{1, 0, 2});
343   EXPECT_EQ(input.numel(), 0);
344 
345   std::vector<Tensor> expected_out = {input};
346 
347   TensorList out = tlf.zeros_like({input});
348 
349   // Fails when trying to split with size zero on a dim with size > 0.
350   ET_EXPECT_KERNEL_FAILURE(
351       context_,
352       op_split_copy_tensor_out(input, /*split_size=*/0, /*dim=*/0, out));
353 
354   // Successfully splits with size zero on a dim with size == 0.
355   op_split_copy_tensor_out(input, /*split_size=*/0, /*dim=*/1, out);
356   EXPECT_TENSOR_LISTS_EQ(out, expected_out);
357 
358   // Fails again when trying to split with size zero on a dim with size > 0.
359   ET_EXPECT_KERNEL_FAILURE(
360       context_,
361       op_split_copy_tensor_out(input, /*split_size=*/0, /*dim=*/2, out));
362 }
363 
TEST_F(OpSplitCopyTensorOutTest,NegativeSplitSizeFails)364 TEST_F(OpSplitCopyTensorOutTest, NegativeSplitSizeFails) {
365   TensorFactory<ScalarType::Int> tf;
366   TensorListFactory<ScalarType::Int> tlf;
367 
368   Tensor input = tf.ones(/*sizes=*/{2, 2});
369   // Arbitrary output shape since there's no actual valid size.
370   TensorList out = tlf.zeros_like({input});
371 
372   ET_EXPECT_KERNEL_FAILURE(
373       context_,
374       op_split_copy_tensor_out(input, /*split_size=*/-1, /*dim=*/0, out));
375 }
376 
TEST_F(OpSplitCopyTensorOutTest,OutOfRangeDimsDie)377 TEST_F(OpSplitCopyTensorOutTest, OutOfRangeDimsDie) {
378   TensorFactory<ScalarType::Int> tf;
379   TensorListFactory<ScalarType::Int> tlf;
380 
381   Tensor input = tf.ones(/*sizes=*/{2, 2});
382 
383   std::vector<int64_t> good_dims = {-2, -1, 0, 1};
384   std::vector<int64_t> bad_dims = {-4, -3, 2, 3};
385 
386   // Since split_size is >= the largest dimension, slicing along any
387   // dimension should return the unmodified input as the only output entry.
388   constexpr int64_t split_size = 2;
389   std::vector<Tensor> expected_out = {input};
390 
391   for (auto dim : good_dims) {
392     TensorList out = tlf.zeros_like({input});
393     op_split_copy_tensor_out(input, split_size, dim, out);
394     EXPECT_TENSOR_LISTS_EQ(out, expected_out);
395   }
396 
397   for (auto dim : bad_dims) {
398     TensorList out = tlf.zeros_like({input});
399     ET_EXPECT_KERNEL_FAILURE(
400         context_, op_split_copy_tensor_out(input, split_size, dim, out));
401   }
402 }
403 
TEST_F(OpSplitCopyTensorOutTest,DtypeMismatchDies)404 TEST_F(OpSplitCopyTensorOutTest, DtypeMismatchDies) {
405   GTEST_SKIP() << "ATen kernel can handle dtype mismatch";
406   TensorFactory<ScalarType::Int> tf_int;
407   TensorListFactory<ScalarType::Int> tlf_int;
408   TensorListFactory<ScalarType::Float> tlf_float;
409 
410   Tensor input = tf_int.ones(/*sizes=*/{2, 2});
411 
412   // Use a split_size that produces a single output entry on success.
413   constexpr int64_t split_size = 2;
414   constexpr int64_t dim = 0;
415 
416   // Demonstrate that this setup works when the dtypes are the same.
417   {
418     TensorList out = tlf_int.zeros_like({input});
419     op_split_copy_tensor_out(input, split_size, dim, out);
420     EXPECT_TENSOR_LISTS_EQ(out, std::vector<Tensor>({input}));
421   }
422 
423   // Dies with the same setup but the output dtype is different.
424   {
425     TensorList out = tlf_float.zeros_like({input});
426     ET_EXPECT_KERNEL_FAILURE(
427         context_, op_split_copy_tensor_out(input, split_size, dim, out));
428   }
429 }
430 
TEST_F(OpSplitCopyTensorOutTest,WrongNumOutputEntriesDies)431 TEST_F(OpSplitCopyTensorOutTest, WrongNumOutputEntriesDies) {
432   TensorFactory<ScalarType::Int> tf;
433   TensorListFactory<ScalarType::Int> tlf;
434 
435   Tensor input = tf.ones(/*sizes=*/{3});
436 
437   // Use a split_size that produces two output entries on success.
438   constexpr int64_t split_size = 2;
439   constexpr int64_t dim = 0;
440 
441   // Demonstrate that splitting the input should produce two output entries.
442   {
443     std::vector<Tensor> expected_out = {
444         tf.ones(/*sizes=*/{2}),
445         tf.ones(/*sizes=*/{1}),
446     };
447     TensorList out = tlf.zeros_like(expected_out);
448     op_split_copy_tensor_out(input, split_size, dim, out);
449     EXPECT_TENSOR_LISTS_EQ(out, expected_out);
450   }
451 
452   // Dies with the same setup but the output has one fewer entry than it should.
453   {
454     std::vector<Tensor> incorrect_out = {
455         tf.ones(/*sizes=*/{2}),
456         // Missing second entry.
457     };
458     TensorList out = tlf.zeros_like(incorrect_out);
459     ET_EXPECT_KERNEL_FAILURE(
460         context_, op_split_copy_tensor_out(input, split_size, dim, out));
461   }
462 
463   // Dies with the same setup but the output has one more entry than it should.
464   {
465     std::vector<Tensor> incorrect_out = {
466         tf.ones(/*sizes=*/{2}),
467         tf.ones(/*sizes=*/{1}),
468         tf.ones(/*sizes=*/{1}), // Extra entry.
469     };
470     TensorList out = tlf.zeros_like(incorrect_out);
471     ET_EXPECT_KERNEL_FAILURE(
472         context_, op_split_copy_tensor_out(input, split_size, dim, out));
473   }
474 }
475 
TEST_F(OpSplitCopyTensorOutTest,WrongOutputShapeDies)476 TEST_F(OpSplitCopyTensorOutTest, WrongOutputShapeDies) {
477   if (torch::executor::testing::SupportedFeatures::get()->is_aten) {
478     GTEST_SKIP() << "ATen kernel can handle wrong out shape";
479   }
480   TensorFactory<ScalarType::Int> tf;
481   TensorListFactory<ScalarType::Int> tlf;
482 
483   Tensor input = tf.ones(/*sizes=*/{5, 3, 4});
484 
485   // Use a split_size that produces two output entries on success.
486   constexpr int64_t split_size = 2;
487   constexpr int64_t dim = 1;
488 
489   // Demonstrate the shapes that this split should produce.
490   {
491     std::vector<Tensor> expected_out = {
492         tf.ones(/*sizes=*/{5, 2, 4}),
493         tf.ones(/*sizes=*/{5, 1, 4}),
494     };
495     TensorList out = tlf.zeros_like(expected_out);
496     op_split_copy_tensor_out(input, split_size, dim, out);
497     EXPECT_TENSOR_LISTS_EQ(out, expected_out);
498   }
499 
500   // Make each of the dimensions of the final element incorrect.
501   {
502     std::vector<Tensor> incorrect_out = {
503         tf.ones(/*sizes=*/{5, 2, 4}),
504         tf.ones(/*sizes=*/{5 + 1, 1, 4}), // Wrong size for dim 0.
505     };
506     TensorList out = tlf.zeros_like(incorrect_out);
507     ET_EXPECT_KERNEL_FAILURE(
508         context_, op_split_copy_tensor_out(input, split_size, dim, out));
509   }
510   {
511     std::vector<Tensor> incorrect_out = {
512         tf.ones(/*sizes=*/{5, 2, 4}),
513         tf.ones(/*sizes=*/{5, 1 + 1, 4}), // Wrong size for dim 1 (split dim).
514     };
515     TensorList out = tlf.zeros_like(incorrect_out);
516     ET_EXPECT_KERNEL_FAILURE(
517         context_, op_split_copy_tensor_out(input, split_size, dim, out));
518   }
519   {
520     std::vector<Tensor> incorrect_out = {
521         tf.ones(/*sizes=*/{5, 2, 4}),
522         tf.ones(/*sizes=*/{5, 1, 4 + 1}), // Wrong size for dim 2.
523     };
524     TensorList out = tlf.zeros_like(incorrect_out);
525     ET_EXPECT_KERNEL_FAILURE(
526         context_, op_split_copy_tensor_out(input, split_size, dim, out));
527   }
528 
529   // Wrong size of the split dimension for the non-last output element.
530   {
531     std::vector<Tensor> incorrect_out = {
532         tf.ones(/*sizes=*/{5, 2 + 1, 4}), // Wrong size for dim 1 (split dim).
533         tf.ones(/*sizes=*/{5, 1, 4}),
534     };
535     TensorList out = tlf.zeros_like(incorrect_out);
536     ET_EXPECT_KERNEL_FAILURE(
537         context_, op_split_copy_tensor_out(input, split_size, dim, out));
538   }
539 
540   // Wrong number of output dimensions.
541   {
542     std::vector<Tensor> incorrect_out = {
543         tf.ones(/*sizes=*/{5, 2, 4}),
544         tf.ones(/*sizes=*/{5, 1, 4, 2}), // Extra dimension
545     };
546     TensorList out = tlf.zeros_like(incorrect_out);
547     ET_EXPECT_KERNEL_FAILURE(
548         context_, op_split_copy_tensor_out(input, split_size, dim, out));
549   }
550   {
551     std::vector<Tensor> incorrect_out = {
552         tf.ones(/*sizes=*/{5, 2, 4}),
553         tf.ones(/*sizes=*/{5, 1}), // Missing dimension
554     };
555     TensorList out = tlf.zeros_like(incorrect_out);
556     ET_EXPECT_KERNEL_FAILURE(
557         context_, op_split_copy_tensor_out(input, split_size, dim, out));
558   }
559 }
560 
TEST_F(OpSplitCopyTensorOutTest,DynamicShapeUpperBoundSameAsExpected)561 TEST_F(OpSplitCopyTensorOutTest, DynamicShapeUpperBoundSameAsExpected) {
562   test_dynamic_shape(
563       {2, 3}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
564 }
565 
TEST_F(OpSplitCopyTensorOutTest,DynamicShapeUpperBoundLargerThanExpected)566 TEST_F(OpSplitCopyTensorOutTest, DynamicShapeUpperBoundLargerThanExpected) {
567   GTEST_SKIP() << "Dynamic shape not supported";
568   test_dynamic_shape(
569       {10, 10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
570 }
571 
TEST_F(OpSplitCopyTensorOutTest,DynamicShapeUnbound)572 TEST_F(OpSplitCopyTensorOutTest, DynamicShapeUnbound) {
573   GTEST_SKIP() << "Dynamic shape not supported";
574   test_dynamic_shape(
575       {1, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND);
576 }
577