/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include // Declares the operator #include #include #include #include #include #include #include #include #include #include using namespace ::testing; using exec_aten::ArrayRef; using exec_aten::Scalar; using exec_aten::ScalarType; using exec_aten::Tensor; using torch::executor::testing::TensorFactory; class OpArangeOutTest : public OperatorTest { protected: Tensor& op_arange_out(const Scalar& end, Tensor& out) { return torch::executor::aten::arange_outf(context_, end, out); } template void test_arange_dtype() { TensorFactory tf; Scalar end = Scalar(static_cast(10)); Tensor out = tf.zeros({10}); Tensor ret = op_arange_out(end, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, filled with 0, 1, ..., 9 Tensor expected = tf.make({10}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); EXPECT_TENSOR_EQ(out, expected); } }; class OpArangeStartOutTest : public OperatorTest { protected: Tensor& op_arange_start_out( const Scalar& start, const Scalar& end, const Scalar& step, Tensor& out) { return torch::executor::aten::arange_outf(context_, start, end, step, out); } template void test_arange_start_dtype() { TensorFactory tf; Scalar start = Scalar(static_cast(0)); Scalar end = Scalar(static_cast(10)); Scalar step = Scalar(static_cast(1)); Tensor out = tf.zeros({10}); Tensor ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, filled with 0, 1, ..., 9 Tensor expected = tf.make({10}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); EXPECT_TENSOR_EQ(out, expected); } }; /// A generic smoke test that works for any dtype that supports zeros(). TEST_F(OpArangeOutTest, AllRealDtypesSupported) { #define TEST_ENTRY(ctype, dtype) test_arange_dtype(); ET_FORALL_REAL_TYPES(TEST_ENTRY); #undef TEST_ENTRY } TEST_F(OpArangeOutTest, FloatNumberNotEqualIntSupport) { TensorFactory tf; // end = any floating point number between [a, a+1) where a is an arbitrary // integer should have same result as end = a. So here arage(end = 5.5) == // arange(5) Scalar end = Scalar(5.5); Tensor out = tf.zeros({6}); Tensor ret = op_arange_out(end, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal Tensor expected = tf.make({6}, {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}); EXPECT_TENSOR_EQ(out, expected); } TEST_F(OpArangeOutTest, OutDimUnsupportedDie) { if (torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "ATen kernel can handle mismatched out dim"; } TensorFactory tf; Scalar end = Scalar(5); Tensor out = tf.zeros({5, 1}); // out.dim() should be 1, not 2 ET_EXPECT_KERNEL_FAILURE(context_, op_arange_out(end, out)); } TEST_F(OpArangeOutTest, DynamicShapeUpperBoundSameAsExpected) { TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({5}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_arange_out(Scalar(5), out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpArangeOutTest, DynamicShapeUpperBoundLargerThanExpected) { TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_arange_out(Scalar(5), out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpArangeOutTest, DynamicShapeUnbound) { if (!torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "Dynamic Unbound not supported"; } TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND); Tensor ret = op_arange_out(Scalar(5), out); EXPECT_TENSOR_CLOSE(out, expected_result); } /// A generic smoke test that works for any dtype that supports zeros(). TEST_F(OpArangeStartOutTest, AllRealDtypesSupported) { #define TEST_ENTRY(ctype, dtype) \ test_arange_start_dtype(); ET_FORALL_REAL_TYPES(TEST_ENTRY); #undef TEST_ENTRY } TEST_F(OpArangeStartOutTest, FloatNumberNotEqualIntSupport) { TensorFactory tf; // Tested in bento: // import torch // torch.arange(5.5) // >> tensor([0., 1., 2., 3., 4., 5.]) Scalar start = Scalar(0); Scalar end = Scalar(5.5); Scalar step = Scalar(1); Tensor out = tf.zeros({6}); Tensor ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal Tensor expected = tf.make({6}, {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}); EXPECT_TENSOR_EQ(out, expected); } TEST_F(OpArangeStartOutTest, OutDimUnsupportedDie) { if (torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "ATen kernel can handle mismatched out dim"; } TensorFactory tf; Scalar start = Scalar(0); Scalar end = Scalar(5); Scalar step = Scalar(1); Tensor out = tf.zeros({5, 1}); // out.dim() should be 1, not 2 ET_EXPECT_KERNEL_FAILURE( context_, op_arange_start_out(start, end, step, out)); } TEST_F(OpArangeStartOutTest, DynamicShapeUpperBoundSameAsExpected) { TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({5}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_arange_start_out(Scalar(0), Scalar(5), Scalar(1), out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpArangeStartOutTest, DynamicShapeUpperBoundLargerThanExpected) { TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_arange_start_out(Scalar(0), Scalar(5), Scalar(1), out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpArangeStartOutTest, DynamicShapeUnbound) { if (!torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "Dynamic Unbound not supported"; } TensorFactory tf; Tensor expected_result = tf.make({5}, {0, 1, 2, 3, 4}); Tensor out = tf.zeros({1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND); Tensor ret = op_arange_start_out(Scalar(0), Scalar(5), Scalar(1), out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpArangeStartOutTest, StartOut) { TensorFactory tf; Scalar start = Scalar(1.1); Scalar end = Scalar(5.5); Scalar step = Scalar(1.1); Tensor out = tf.zeros({4}); Tensor ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal Tensor expected = tf.make({4}, {1.1, 2.2, 3.3, 4.4}); EXPECT_TENSOR_EQ(out, expected); end = Scalar(5.51); out = tf.zeros({5}); ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal expected = tf.make({5}, {1.1, 2.2, 3.3, 4.4, 5.5}); EXPECT_TENSOR_EQ(out, expected); } TEST_F(OpArangeStartOutTest, StartOutNegativeStep) { TensorFactory tf; Scalar start = Scalar(5.5); Scalar end = Scalar(1.1); Scalar step = Scalar(-1.1); Tensor out = tf.zeros({4}); Tensor ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal Tensor expected = tf.make({4}, {5.5, 4.4, 3.3, 2.2}); EXPECT_TENSOR_EQ(out, expected); end = Scalar(1.09); out = tf.zeros({5}); ret = op_arange_start_out(start, end, step, out); // Should always return the provided out Tensor. EXPECT_TENSOR_EQ(ret, out); // Expected tensor, equal expected = tf.make({5}, {5.5, 4.4, 3.3, 2.2, 1.1}); EXPECT_TENSOR_EQ(out, expected); }