/* * 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 using namespace ::testing; using exec_aten::ArrayRef; using exec_aten::ScalarType; using exec_aten::Tensor; using torch::executor::testing::TensorFactory; class OpAmaxOutTest : public OperatorTest { protected: Tensor& op_amax_out( const Tensor& in, ArrayRef dim, bool keepdim, Tensor& out) { return torch::executor::aten::amax_outf(context_, in, dim, keepdim, out); } template void test_amax_out_invalid_dimensions() { TensorFactory tf; // clang-format off Tensor in = tf.make( {2, 3, 4}, { 0, 1, 2, 4, 4, 2, 1, 0, 1, 0, 4, 2, 4, 2, 1, 0, 0, 1, 2, 4, 1, 0, 4, 2, }); // clang-format on Tensor out = tf.zeros({2, 3, 1}); // out-of-bound dim in dim list int64_t dims_1[1] = {3}; ArrayRef dim_list{ArrayRef{dims_1, 1}}; ET_EXPECT_KERNEL_FAILURE( context_, op_amax_out(in, dim_list, /*keepdim=*/true, out)); // the same dim appears multiple times in list of dims int64_t dims_2[2] = {2, 2}; dim_list = ArrayRef{dims_2, 2}; ET_EXPECT_KERNEL_FAILURE( context_, op_amax_out(in, dim_list, /*keepdim=*/true, out)); } template void test_amax_out_invalid_shape() { TensorFactory tf; // clang-format off Tensor in = tf.make( {2, 3, 4}, { 0, 1, 2, 4, 4, 2, 1, 0, 1, 0, 4, 2, 4, 2, 1, 0, 0, 1, 2, 4, 1, 0, 4, 2, }); // clang-format on // dimension size mismatch when keepdim is true Tensor out = tf.zeros({2, 4}); int64_t dims_1[1] = {1}; ArrayRef dim_list{ArrayRef{dims_1, 1}}; ET_EXPECT_KERNEL_FAILURE( context_, op_amax_out(in, dim_list, /*keepdim=*/true, out)); // dimension size mismatch when keepdim is false out = tf.zeros({2, 1, 4}); ET_EXPECT_KERNEL_FAILURE( context_, op_amax_out(in, dim_list, /*keepdim=*/false, out)); } template void test_amax_out_dtype() { TensorFactory tf; // clang-format off Tensor in = tf.make( {2, 3, 4}, { 0, 1, 2, 4, 4, 2, 1, 0, 1, 5, 4, 2, 4, 2, 1, 0, 5, 1, 2, 4, 7, 5, 4, 2, }); // clang-format on // keepdim=true should work Tensor out = tf.zeros({2, 3, 1}); int64_t dims_1[1] = {2}; ArrayRef dim_list{ArrayRef{dims_1, 1}}; op_amax_out(in, dim_list, /*keepdim=*/true, out); // clang-format off EXPECT_TENSOR_CLOSE(out, tf.make( {2, 3, 1}, {4, 4, 5, 4, 5, 7})); // clang-format on // keepdim=false should work out = tf.zeros({2, 3}); op_amax_out(in, dim_list, /*keepdim=*/false, out); // clang-format off EXPECT_TENSOR_CLOSE(out, tf.make( {2, 3}, {4, 4, 5, 4, 5, 7})); // clang-format on // dim list with multiple dimensions should work out = tf.zeros({1, 1, 4}); int64_t dims_2[2] = {0, 1}; dim_list = ArrayRef{dims_2, 2}; op_amax_out(in, dim_list, /*keepdim=*/true, out); EXPECT_TENSOR_CLOSE(out, tf.make({1, 1, 4}, {7, 5, 4, 4})); out = tf.zeros({4}); op_amax_out(in, dim_list, /*keepdim=*/false, out); EXPECT_TENSOR_CLOSE(out, tf.make({4}, {7, 5, 4, 4})); // dim list with negative dimensions should work out = tf.zeros({2, 1, 4}); int64_t dims_3[1] = {-2}; dim_list = ArrayRef{dims_3, 1}; op_amax_out(in, dim_list, /*keepdim=*/true, out); // clang-format off EXPECT_TENSOR_CLOSE(out, tf.make( {2, 1, 4}, { 4, 5, 4, 4, 7, 5, 4, 4, })); // clang-format on // empty/null dim list should work // clang-format off in = tf.make( {2, 2, 4}, { 8, 7, 5, 4, 4, 3, 7, 9, 4, 2, 6, 8, 8, 7, 3, 4, }); // clang-format on out = tf.zeros({1, 1, 1}); ArrayRef null_dim_list; op_amax_out(in, null_dim_list, /*keepdim=*/true, out); EXPECT_TENSOR_CLOSE(out, tf.make({1, 1, 1}, {9})); ArrayRef empty_dim_list{ArrayRef{}}; op_amax_out(in, empty_dim_list, /*keepdim=*/true, out); EXPECT_TENSOR_CLOSE(out, tf.make({1, 1, 1}, {9})); out = tf.zeros({}); op_amax_out(in, null_dim_list, /*keepdim=*/false, out); EXPECT_TENSOR_CLOSE(out, tf.make({}, {9})); op_amax_out(in, empty_dim_list, /*keepdim=*/false, out); EXPECT_TENSOR_CLOSE(out, tf.make({}, {9})); } }; template <> void OpAmaxOutTest::test_amax_out_dtype() { TensorFactory tf_bool; // clang-format off Tensor in = tf_bool.make( {2, 3, 4}, { true, false, true, false, false, false, false, false, false, true, true, false, false, false, true, false, false, false, false, true, true, true, true, true, }); // clang-format on Tensor out = tf_bool.zeros({2, 3, 1}); // +/-inf and nan should work op_amax_out(in, /*dim=*/-1, /*keepdim=*/true, out); // clang-format off EXPECT_TENSOR_CLOSE( out, tf_bool.make( {2, 3, 1}, { true, false, true, true, true, true })); // clang-format on } TEST_F(OpAmaxOutTest, InvalidDimensionListDies) { if (torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "ATen kernel test fails"; } #define TEST_ENTRY(ctype, dtype) \ test_amax_out_invalid_dimensions(); ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); #undef TEST_ENTRY } TEST_F(OpAmaxOutTest, InvalidShapeDies) { if (torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "ATen kernel test fails"; } #define TEST_ENTRY(ctype, dtype) \ test_amax_out_invalid_shape(); ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); #undef TEST_ENTRY } TEST_F(OpAmaxOutTest, MismatchedDTypesDies) { if (torch::executor::testing::SupportedFeatures::get()->is_aten) { GTEST_SKIP() << "ATen kernel test fails"; } TensorFactory tf_float; TensorFactory tf_int; // clang-format off Tensor in = tf_int.make( {2, 3, 4}, { 0, 1, 2, 4, 4, 2, 1, 0, 1, 0, 4, 2, 4, 2, 1, 0, 0, 1, 2, 4, 1, 0, 4, 2, }); // clang-format on Tensor out = tf_float.zeros({2, 3, 1}); int64_t dims_1[1] = {2}; ArrayRef dim_list{ArrayRef{dims_1, 1}}; // out tensor should be of the same dtype with dtype when dtype is specified ET_EXPECT_KERNEL_FAILURE( context_, op_amax_out(in, dim_list, /*keepdim=*/true, out)); } TEST_F(OpAmaxOutTest, AllRealInputOutputPasses) { #define TEST_ENTRY(ctype, dtype) test_amax_out_dtype(); ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); #undef TEST_ENTRY } TEST_F(OpAmaxOutTest, InfinityAndNANTest) { TensorFactory tf_float; // clang-format off Tensor in = tf_float.make( {2, 3, 4}, { 0, 1, 2, INFINITY, INFINITY, -INFINITY, 1, 0, NAN, INFINITY, -INFINITY, 2, NAN, NAN, 1, 0, 0, INFINITY, NAN, 4, 1, NAN, 3.14, 2, }); // clang-format on Tensor out = tf_float.zeros({2, 3, 1}); int64_t dims[1] = {-1}; ArrayRef dim_list{ArrayRef{dims, 1}}; op_amax_out(in, dim_list, /*keepdim=*/true, out); // clang-format off EXPECT_TENSOR_CLOSE( out, tf_float.make({2, 3, 1}, {INFINITY, INFINITY, NAN, NAN, NAN, NAN})); // clang-format on }