/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ #include #include #include #include #include #include #include #include #include "Eigen/Core" // from @eigen_archive // IWYU pragma: keep #include "tensorflow/lite/kernels/test_util.h" #include "tensorflow/lite/schema/schema_generated.h" #include "tensorflow/lite/types/half.h" namespace tflite { namespace { using ::testing::ElementsAreArray; using ::testing::IsEmpty; template class StridedSliceOpModel : public SingleOpModel { public: StridedSliceOpModel(std::initializer_list input_shape, std::initializer_list begin_shape, std::initializer_list end_shape, std::initializer_list strides_shape, const std::vector input_data, const std::vector begin_data, const std::vector end_data, const std::vector strides_data, int begin_mask, int end_mask, int ellipsis_mask, int new_axis_mask, int shrink_axis_mask, bool constant_tensors, bool offset = false) { if (constant_tensors) { input_ = AddConstInput(GetTensorType(), input_data, input_shape); begin_ = AddConstInput(TensorType_INT32, begin_data, begin_shape); end_ = AddConstInput(TensorType_INT32, end_data, end_shape); strides_ = AddConstInput(TensorType_INT32, strides_data, strides_shape); } else if (offset) { input_ = AddInput(GetTensorType()); begin_ = AddInput(TensorType_INT32); end_ = AddConstInput(TensorType_INT32, end_data, end_shape); strides_ = AddConstInput(TensorType_INT32, strides_data, strides_shape); } else { input_ = AddInput(GetTensorType()); begin_ = AddInput(TensorType_INT32); end_ = AddInput(TensorType_INT32); strides_ = AddInput(TensorType_INT32); } output_ = AddOutput(GetTensorType()); SetBuiltinOp( BuiltinOperator_STRIDED_SLICE, BuiltinOptions_StridedSliceOptions, CreateStridedSliceOptions(builder_, begin_mask, end_mask, ellipsis_mask, new_axis_mask, shrink_axis_mask, offset) .Union()); BuildInterpreter({input_shape, begin_shape, end_shape, strides_shape}); if (!constant_tensors) { if (!input_data.empty()) { SetInput(input_data, std::is_same()); } SetBegin(begin_data); SetEnd(end_data); SetStrides(strides_data); } else if (offset) { if (!input_data.empty()) { SetInput(input_data, std::is_same()); } SetBegin(begin_data); } } // Constant input, strides and end with offset. StridedSliceOpModel(std::initializer_list input_shape, std::initializer_list begin_shape, std::initializer_list end_shape, std::initializer_list strides_shape, const std::vector input_data, const std::vector begin_data, const std::vector end_data, const std::vector strides_data, int begin_mask, int end_mask, int ellipsis_mask, int new_axis_mask, int shrink_axis_mask) { input_ = AddConstInput(GetTensorType(), input_data, input_shape); begin_ = AddInput(TensorType_INT32); end_ = AddConstInput(TensorType_INT32, end_data, end_shape); strides_ = AddConstInput(TensorType_INT32, strides_data, strides_shape); output_ = AddOutput(GetTensorType()); SetBuiltinOp(BuiltinOperator_STRIDED_SLICE, BuiltinOptions_StridedSliceOptions, CreateStridedSliceOptions(builder_, begin_mask, end_mask, ellipsis_mask, new_axis_mask, shrink_axis_mask, /*offset=*/true) .Union()); BuildInterpreter({input_shape, begin_shape, end_shape, strides_shape}); SetBegin(begin_data); } template void SetInput(const std::vector data, std::false_type) { PopulateTensor(input_, data); } template void SetInput(const std::vector data, std::true_type) { PopulateStringTensor(input_, data); } void SetBegin(const std::vector data) { PopulateTensor(begin_, data); } void SetEnd(const std::vector data) { PopulateTensor(end_, data); } void SetStrides(const std::vector data) { PopulateTensor(strides_, data); } std::vector GetOutput() { return ExtractVector(output_); } std::vector GetStringOutput() { return ExtractVector(output_); } std::vector GetOutputShape() { return GetTensorShape(output_); } const TfLiteTensor* GetOutputTensor(int index) { return interpreter_->output_tensor(index); } private: int input_; int begin_; int end_; int strides_; int output_; }; template class StridedSliceOpTest : public ::testing::Test {}; using DataTypes = ::testing::Types; TYPED_TEST_SUITE(StridedSliceOpTest, DataTypes); template auto ElementsAreTypedArray(std::vector x) { if constexpr (std::is_floating_point_v) { return ElementsAreArray(ArrayFloatNear(std::move(x))); } else { return ElementsAreArray(std::move(x)); } } // Casts input vector to specified type, converting to string for std::string // type. template std::vector CastVector(const std::vector& input_data) { std::vector casted_input(input_data.size()); if constexpr (std::is_same_v) { std::transform(input_data.begin(), input_data.end(), casted_input.begin(), [](int x) { return std::to_string(x); }); } else if constexpr (std::is_same_v) { return input_data; } else { std::transform(input_data.begin(), input_data.end(), casted_input.begin(), [](int x) { return static_cast(x); }); } return casted_input; } TYPED_TEST(StridedSliceOpTest, In6D) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({0, 1, 2, 3, 4, 5}); StridedSliceOpModel m({2, 1, 1, 1, 1, 3}, {6}, {6}, {6}, input_data, {1, 0, 0, 0, 0, 1}, {2, 1, 1, 1, 1, 3}, {1, 1, 1, 1, 1, 1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 1, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({4, 5}))); } } TYPED_TEST(StridedSliceOpTest, In1DEmpty) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } StridedSliceOpModel m({0}, {1}, {1}, {1}, std::vector{}, {1}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0})); } } TYPED_TEST(StridedSliceOpTest, Offset) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); StridedSliceOpModel m({10}, {1}, {1}, {1}, input_data, {1}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3}))); if (m.GetNumberOfAppliedDelegates() == 0) { if (constant_tensors) { EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLitePersistentRo); } else { EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } } } } TYPED_TEST(StridedSliceOpTest, OffsetArray) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); StridedSliceOpModel m({3, 4}, {2}, {2}, {2}, input_data, {0, 1}, {2, 2}, {1, 1}, 0, 0, 0, 0, 0, constant_tensors, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 5, 6}))); if (m.GetNumberOfAppliedDelegates() == 0) { if (constant_tensors) { EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLitePersistentRo); } else { EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } } } } TYPED_TEST(StridedSliceOpTest, OffsetConstant) { const std::vector input_data = CastVector({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); StridedSliceOpModel m({3, 4}, {2}, {2}, {2}, input_data, {0, 1}, {2, 2}, {1, 1}, 0, 0, 0, 0, 0, /*constant_tensors*/ false, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 5, 6}))); EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } TYPED_TEST(StridedSliceOpTest, OffsetConstantStride) { const int height = 5; const int width = 6; std::vector input_data(height * width); std::iota(input_data.begin(), input_data.end(), 0); auto casted_input_data = CastVector(input_data); StridedSliceOpModel m({height, width}, {2}, {2}, {2}, casted_input_data, {0, 1}, {4, 3}, {2, 2}, 0, 0, 0, 0, 0, /*constant_tensors*/ false, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 13, 15}))); EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } TYPED_TEST(StridedSliceOpTest, OffsetConstantNegativeStride) { const int height = 5; const int width = 6; std::vector input_data(height * width); std::iota(input_data.begin(), input_data.end(), 0); auto casted_input_data = CastVector(input_data); StridedSliceOpModel m({height, width}, {2}, {2}, {2}, casted_input_data, {4, 4}, {-4, -3}, {-2, -2}, 0, 0, 0, 0, 0, /*constant_tensors*/ false, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({28, 26, 16, 14}))); EXPECT_THAT(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } TYPED_TEST(StridedSliceOpTest, In1D) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1DConst) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_Int32End) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } std::vector values(32768); for (int i = 0; i < 32768; ++i) { values[i] = static_cast(i); } StridedSliceOpModel m({32768}, {1}, {1}, {1}, values, {0}, {32768}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({32768})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(values)); } } TYPED_TEST(StridedSliceOpTest, In1D_EmptyOutput) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {10}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0})); } } TYPED_TEST(StridedSliceOpTest, In1D_NegativeBegin) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-3}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_OutOfRangeBegin) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-5}, {3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_NegativeEnd) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {-2}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({2}))); } } TYPED_TEST(StridedSliceOpTest, In1D_OutOfRangeEnd) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-3}, {5}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 3, 4}))); } } TYPED_TEST(StridedSliceOpTest, In1D_BeginMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {3}, {1}, 1, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_NegativeBeginNegativeStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-2}, {-3}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_OutOfRangeBeginNegativeStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {5}, {2}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({4}))); } } TYPED_TEST(StridedSliceOpTest, In1D_NegativeEndNegativeStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {2}, {-4}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({3, 2}))); } } TYPED_TEST(StridedSliceOpTest, In1D_OutOfRangeEndNegativeStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-3}, {-5}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 1}))); } } TYPED_TEST(StridedSliceOpTest, In1D_EndMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {3}, {1}, 0, 1, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({2, 3, 4}))); } } TYPED_TEST(StridedSliceOpTest, In1D_NegStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3}); StridedSliceOpModel m({3}, {1}, {1}, {1}, input_data, {-1}, {-4}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({3, 2, 1}))); } } TYPED_TEST(StridedSliceOpTest, In1D_EvenLenStride2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2}); StridedSliceOpModel m({2}, {1}, {1}, {1}, input_data, {0}, {2}, {2}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } } TYPED_TEST(StridedSliceOpTest, In1D_OddLenStride2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3}); StridedSliceOpModel m({3}, {1}, {1}, {1}, input_data, {0}, {3}, {2}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3}))); } } TYPED_TEST(StridedSliceOpTest, In2D_Identity) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, 0}, {2, 3}, {1, 1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In2D) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, 0}, {2, 2}, {1, 1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({4, 5}))); } } TYPED_TEST(StridedSliceOpTest, In2D_Stride2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, 0}, {2, 3}, {2, 2}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3}))); } } TYPED_TEST(StridedSliceOpTest, In2D_NegStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, -1}, {2, -4}, {2, -1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({6, 5, 4}))); } } TYPED_TEST(StridedSliceOpTest, In2D_BeginMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, 0}, {2, 2}, {1, 1}, 1, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 4, 5}))); } } TYPED_TEST(StridedSliceOpTest, In2D_EndMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, 0}, {2, 2}, {1, 1}, 0, 2, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In2D_NegStrideBeginMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, -2}, {2, -4}, {1, -1}, 2, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({6, 5, 4}))); } } TYPED_TEST(StridedSliceOpTest, In2D_NegStrideEndMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, -2}, {2, -3}, {1, -1}, 0, 2, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({5, 4}))); } } TYPED_TEST(StridedSliceOpTest, In3D_Identity) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {2, 3, 2}, {1, 1, 1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})); } } TYPED_TEST(StridedSliceOpTest, In3D_NegStride) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {-1, -1, -1}, {-3, -4, -3}, {-1, -1, -1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})); } } TYPED_TEST(StridedSliceOpTest, In3D_Strided2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {2, 3, 2}, {2, 2, 2}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 5}))); } } TYPED_TEST(StridedSliceOpTest, In1D_ShrinkAxisMask1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {2}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({2}))); } } TYPED_TEST(StridedSliceOpTest, In1D_ShrinkAxisMask1_NegativeSlice) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } // This is equivalent to tf.range(4)[-1]. const std::vector input_data = CastVector({0, 1, 2, 3}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-1}, {0}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({3}))); } } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxis3_NegativeSlice) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } // This is equivalent to tf.range(4)[:, tf.newaxis][-2, -1]. const std::vector input_data = CastVector({0, 1, 2, 3}); StridedSliceOpModel m({4, 1}, {2}, {2}, {2}, input_data, {-2, -1}, {-1, 0}, {1, 1}, 0, 0, 0, 0, 3, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({2}))); } } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxis2_BeginEndAxis1_NegativeSlice) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } // This is equivalent to tf.range(4)[:, tf.newaxis][:, -1]. const std::vector input_data = CastVector({0, 1, 2, 3}); StridedSliceOpModel m({4, 1}, {2}, {2}, {2}, input_data, {0, -1}, {0, 0}, {1, 1}, 1, 1, 0, 0, 2, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({0, 1, 2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In1D_BeginMaskShrinkAxisMask1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {1}, {1}, {1}, 1, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxisMask1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, 0}, {1, 3}, {1, 1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3}))); } } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, 0}, {2, 1}, {1, 1}, 0, 0, 0, 0, 2, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 4}))); } } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxisMask3) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, 0}, {1, 1}, {1, 1}, 0, 0, 0, 0, 3, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 2}, {1, 1, 1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {2, 1, 2}, {1, 1, 1}, 0, 0, 0, 0, 2, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 7, 8}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis3) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 1, 2}, {1, 1, 1}, 0, 0, 0, 0, 3, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis4) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {2, 3, 1}, {1, 1, 1}, 0, 0, 0, 0, 4, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5, 7, 9, 11}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis5) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 1}, {1, 1, 1}, 0, 0, 0, 0, 5, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis6) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {2, 1, 1}, {1, 1, 1}, 0, 0, 0, 0, 6, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 7}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis7) { for (bool constant_tensors : {true, false}) { const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 1, 1}, {1, 1, 1}, 0, 0, 0, 0, 7, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } // This tests catches a very subtle bug that was fixed by cl/188403234. } TYPED_TEST(StridedSliceOpTest, RunTwice) { const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {1, 0}, {2, 2}, {1, 1}, 1, 0, 0, 0, 0, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 4, 5}))); auto setup_inputs = [&m, &input_data]() { m.template SetInput(input_data, std::is_same()); m.SetBegin({1, 0}); m.SetEnd({2, 2}); m.SetStrides({1, 1}); }; setup_inputs(); ASSERT_EQ(m.Invoke(), kTfLiteOk); // Prior to cl/188403234 this was {4, 5}. EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 4, 5}))); } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis1Uint8) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 2}, {1, 1, 1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In3D_IdentityShrinkAxis1int8) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 2}, {1, 1, 1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In5D_Identity) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector( {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); StridedSliceOpModel m( {2, 2, 2, 1, 2}, {5}, {5}, {5}, input_data, {0, 0, 0, 0, 0}, {2, 1, 2, 1, 2}, {1, 1, 1, 1, 1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 2, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 9, 10, 11, 12}))); } } TYPED_TEST(StridedSliceOpTest, In5D_IdentityShrinkAxis1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector( {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); StridedSliceOpModel m( {2, 2, 2, 1, 2}, {5}, {5}, {5}, input_data, {0, 0, 0, 0, 0}, {2, 1, 2, 1, 2}, {1, 1, 1, 1, 1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4}))); } } TYPED_TEST(StridedSliceOpTest, In3D_SmallBegin) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {1}, {1}, {1}, input_data, {0}, {1}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In3D_SmallBeginWithhrinkAxis1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {1}, {1}, {1}, input_data, {0}, {1}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, In3D_BackwardSmallBeginEndMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2}); StridedSliceOpModel m({1, 1, 2}, {1}, {1}, {1}, input_data, {1}, {0}, {1}, 0, 1, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0, 1, 2})); } } TYPED_TEST(StridedSliceOpTest, In3D_BackwardSmallBegin) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2}); StridedSliceOpModel m({1, 1, 2}, {1}, {1}, {1}, input_data, {1}, {0}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0, 1, 2})); } } TYPED_TEST(StridedSliceOpTest, In3D_Backward) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2}); StridedSliceOpModel m({1, 1, 2}, {3}, {3}, {3}, input_data, {1, 0, 0}, {0, -1, -1}, {1, 1, 1}, 6, 7, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0, 1, 2})); } } TEST(StridedSliceOpTest, In1D_String_NegativeBegin) { std::vector input_data = CastVector( {1, 2, 3, 4}); // input_data = {"a", "b", "c", "d"} StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-3}, {3}, {1}, 0, 0, 0, 0, 0, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); std::vector output_data = CastVector({2, 3}); // output_data = {"b", "c"} EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetStringOutput(), ElementsAreArray(output_data)); } TEST(StridedSliceOpTest, In3D_String_BackwardSmallBegin) { std::vector input_data = CastVector({1, 2}); // input_data = {"a", "b"} StridedSliceOpModel m({1, 1, 2}, {1}, {1}, {1}, input_data, {1}, {0}, {1}, 0, 1, 0, 0, 0, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0, 1, 2})); } TEST(StridedSliceOpTest, In3D_String_SmallBeginWithhrinkAxis1) { std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {1}, {1}, {1}, input_data, {0}, {1}, {1}, 0, 0, 0, 0, 1, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetStringOutput(), ElementsAreArray({"1", "2", "3", "4", "5", "6"})); } TEST(StridedSliceOpTest, In5D_String_IdentityShrinkAxis1) { std::vector input_data = CastVector( {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); StridedSliceOpModel m({2, 2, 2, 1, 2}, {5}, {5}, {5}, input_data, {0, 0, 0, 0, 0}, {2, 1, 2, 1, 2}, {1, 1, 1, 1, 1}, 0, 0, 0, 0, 1, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 1, 2})); EXPECT_THAT(m.GetStringOutput(), ElementsAreArray({"1", "2", "3", "4"})); } TYPED_TEST(StridedSliceOpTest, In2D_ShrinkAxis_Endmask_AtSameAxis) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({0, 1, 2, 3}); StridedSliceOpModel m({2, 2}, {2}, {2}, {2}, input_data, {0, -1}, {0, 0}, {1, -1}, 1, 1, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask1_NewAxisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 1, 2, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 1, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5, 7, 9, 11}))); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask2_NewAxisMask1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 2, 1, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5, 7, 9, 11}))); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask2_NewAxisMask5) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 2, 5, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 3, 2, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask2_NewAxisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 2, 2, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5}))); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask4_NewAxisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 4, 2, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 3, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 3, 4, 5, 6}))); } } TYPED_TEST(StridedSliceOpTest, EllipsisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 2, 1}, {1, 1, 1}, 0, 0, 2, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 3, 5}))); } } TYPED_TEST(StridedSliceOpTest, NewAxisMask2) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 1}, {1, 1, 1}, 0, 0, 0, 2, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2}))); } } TYPED_TEST(StridedSliceOpTest, NewAxisMask1) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, input_data, {0, 0, 0}, {1, 3, 1}, {1, 1, 1}, 0, 0, 0, 1, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({1, 2, 7, 8}))); } } TYPED_TEST(StridedSliceOpTest, NoInfiniteLoop) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } StridedSliceOpModel m( {1, 1}, {6}, {6}, {6}, {}, {1, 1, 1, 1, 1, 1}, {3, 3, 3, 3, 3, 3}, {1, 1, 1, 1, 1, 1}, 1, 2, 1, 6, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); } } TYPED_TEST(StridedSliceOpTest, MinusThreeMinusFourMinusOne) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-3}, {-4}, {-1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({2}))); } } TYPED_TEST(StridedSliceOpTest, MinusFourMinusThreeOne) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4}); StridedSliceOpModel m({4}, {1}, {1}, {1}, input_data, {-4}, {-3}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({1}))); } } TYPED_TEST(StridedSliceOpTest, OneOneOne) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({2}); StridedSliceOpModel m({1}, {1}, {1}, {1}, input_data, {1}, {1}, {1}, 0, 0, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0})); } } TYPED_TEST(StridedSliceOpTest, OneOneOneShrinkAxis) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3}); StridedSliceOpModel m({3}, {1}, {1}, {1}, input_data, {1}, {1}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray(CastVector({2}))); } } TYPED_TEST(StridedSliceOpTest, OneOneOneShrinkAxisOOB) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({2}); StridedSliceOpModel m({1}, {1}, {1}, {1}, input_data, {1}, {1}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); } } TYPED_TEST(StridedSliceOpTest, OutOfBounds) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } StridedSliceOpModel m({1}, {1}, {1}, {1}, {}, {1}, {2}, {1}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); } } TYPED_TEST(StridedSliceOpTest, StrideOutOfBounds) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } StridedSliceOpModel m({1}, {1}, {1}, {1}, {}, {1}, {4}, {7}, 0, 0, 0, 0, 1, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); } } TYPED_TEST(StridedSliceOpTest, NegEndMask) { for (bool constant_tensors : {true, false}) { if (SingleOpModel::GetForceUseNnapi() && constant_tensors) { // NNAPI does not support graphs with all constant inputs. continue; } const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, -1}, {2, -3}, {1, -1}, 0, 0b10, 0, 0, 0, constant_tensors); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({3, 2, 1, 6, 5, 4}))); } } TYPED_TEST(StridedSliceOpTest, StrideOverflowAndEdgeCases) { if (SingleOpModel::GetForceUseNnapi()) { return; } { const std::vector input_data = CastVector({1}); StridedSliceOpModel m({1}, {1}, {1}, {1}, input_data, {0}, {2147483647}, {126322568}, 0, 0, 0, 0, 0, /*constant_tensors=*/false, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({17})); } { const std::vector input_data = CastVector({1}); StridedSliceOpModel m({1}, {1}, {1}, {1}, input_data, {0}, {-2147483648}, {-1000000000}, 0, 0, 0, 0, 0, /*constant_tensors=*/false, /*offset=*/true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); } } TYPED_TEST(StridedSliceOpTest, NoopOffset) { const std::vector input_data = CastVector({1, 2, 3, 4, 5, 6}); StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, input_data, {0, -1}, {2, -3}, {1, -1}, 0, 0b10, 0, 0, 0); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreTypedArray( CastVector({3, 2, 1, 6, 5, 4}))); } } // namespace } // namespace tflite