Files
openvino/ngraph/test/coordinate_range.cpp
2021-01-13 16:43:04 +03:00

471 lines
16 KiB
C++

//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// 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 <algorithm>
#include <numeric>
#include <utility>
#include "gtest/gtest.h"
#include <ngraph/coordinate_range.hpp>
using namespace ngraph;
using namespace ngraph::coordinates;
using Index = size_t;
using ExpectedOutput = std::vector<std::pair<Index, Coordinate>>;
///
///
/// SliceRange
///
///
TEST(coordinate_range, slice_range_shape0d)
{
const Shape s;
const Coordinate start_corner(s.size());
auto slice_range = slice(s, start_corner, s);
auto it = slice_range.begin();
EXPECT_EQ(it, begin(slice_range));
EXPECT_FALSE(it == slice_range.end());
auto v = *it; // if it is not end it has to be dereferencable;
(void)v;
EXPECT_TRUE(++it == slice_range.end());
}
TEST(coordinate_range, slice_range_shape1d)
{
const Shape s{3};
const Coordinate start_corner(s.size());
const ExpectedOutput expected{{0, {0}}, {1, {1}}, {2, {2}}};
ASSERT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto slice_range : slice(s, start_corner, s))
{
auto index = slice_range.begin_index;
for (size_t i = 0; i < slice_range.element_number; index += slice_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, slice_range_shape2d)
{
const Shape s{2, 3};
const Coordinate start_corner(s.size());
// clang-format off
const ExpectedOutput expected{
{0, {0, 0}}, {1, {0, 1}}, {2, {0, 2}},
{3, {1, 0}}, {4, {1, 1}}, {5, {1, 2}}};
// clang-format on
ASSERT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto slice_range : slice(s, start_corner, s))
{
auto index = slice_range.begin_index;
for (size_t i = 0; i < slice_range.element_number; index += slice_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, slice_range_shape3d)
{
const Shape s{2, 3, 4};
const Coordinate start_corner(s.size());
// clang-format off
const ExpectedOutput expected{
{0, {0, 0, 0}}, {1, {0, 0, 1}}, {2, {0, 0, 2}}, {3, {0, 0, 3}},
{4, {0, 1, 0}}, {5, {0, 1, 1}}, {6, {0, 1, 2}}, {7, {0, 1, 3}},
{8, {0, 2, 0}}, {9, {0, 2, 1}}, {10, {0, 2, 2}}, {11, {0, 2, 3}},
{12, {1, 0, 0}}, {13, {1, 0, 1}}, {14, {1, 0, 2}}, {15, {1, 0, 3}},
{16, {1, 1, 0}}, {17, {1, 1, 1}}, {18, {1, 1, 2}}, {19, {1, 1, 3}},
{20, {1, 2, 0}}, {21, {1, 2, 1}}, {22, {1, 2, 2}}, {23, {1, 2, 3}}};
// clang-format on
ASSERT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto slice_range : slice(s, start_corner, s))
{
auto index = slice_range.begin_index;
for (size_t i = 0; i < slice_range.element_number; index += slice_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected));
}
TEST(coordinate_range, slice_range_zero_sized_axis)
{
const Shape s{2, 0, 4};
const Coordinate start_corner(s.size());
auto slice_range = slice(s, start_corner, s);
auto it = slice_range.begin();
EXPECT_TRUE(it == slice_range.end()) << "Expect empyt range";
}
///
/// slice specyfic test
///
TEST(coordinate_range, slice_range_input_validataion)
{
const Shape s{10, 10, 10};
EXPECT_THROW(slice(s, {1}, {1}), std::domain_error);
EXPECT_THROW(slice(s, s, {1}), std::domain_error);
EXPECT_THROW(slice(s, {1}, s), std::domain_error);
EXPECT_THROW(slice(s, s, s, {}), std::domain_error);
}
namespace
{
Shape sliced_shape(const std::vector<size_t>& start_corner,
const std::vector<size_t>& end_corner)
{
Shape s;
std::transform(end_corner.begin(),
end_corner.end(),
start_corner.begin(),
std::back_inserter(s),
[](size_t e, size_t b) { return e - b; });
return s;
}
Shape sliced_shape(const std::vector<size_t>& start_corner,
const std::vector<size_t>& end_corner,
const std::vector<size_t>& strides)
{
Shape s = sliced_shape(start_corner, end_corner);
std::transform(s.begin(), s.end(), strides.begin(), s.begin(), [](size_t e, size_t s) {
return (e + s - 1) / s;
});
return s;
}
} // namespace
TEST(coordinate_range, slice_range_corner)
{
const Shape s{10, 10};
const Coordinate source_start_corner{3, 3};
const Coordinate source_end_corner{6, 6};
const ExpectedOutput expected{{33, {3, 3}},
{34, {3, 4}},
{35, {3, 5}},
{43, {4, 3}},
{44, {4, 4}},
{45, {4, 5}},
{53, {5, 3}},
{54, {5, 4}},
{55, {5, 5}}};
ASSERT_EQ(expected.size(), shape_size(sliced_shape(source_start_corner, source_end_corner)))
<< "check epxected data";
auto expected_val = begin(expected);
for (auto slice_range : slice(s, source_start_corner, source_end_corner))
{
auto index = slice_range.begin_index;
for (size_t i = 0; i < slice_range.element_number; index += slice_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, slice_range_strides)
{
const Shape s{10, 10};
const Coordinate source_start_corner{0, 0};
const Coordinate source_end_corner{s};
const Strides source_strides = Strides({2, 3});
// clang-format off
const ExpectedOutput expected{
{0, {0, 0}}, {3, {0, 3}}, {6, {0, 6}}, {9, {0, 9}},
{20, {2, 0}}, {23, {2, 3}}, {26, {2, 6}}, {29, {2, 9}},
{40, {4, 0}}, {43, {4, 3}}, {46, {4, 6}}, {49, {4, 9}},
{60, {6, 0}}, {63, {6, 3}}, {66, {6, 6}}, {69, {6, 9}},
{80, {8, 0}}, {83, {8, 3}}, {86, {8, 6}}, {89, {8, 9}}};
// clang-format on
ASSERT_EQ(expected.size(),
shape_size(sliced_shape(source_start_corner, source_end_corner, source_strides)))
<< "check epxected data";
auto expected_val = begin(expected);
for (auto slice_range : slice(s, source_start_corner, source_end_corner, source_strides))
{
auto index = slice_range.begin_index;
for (size_t i = 0; i < slice_range.element_number; index += slice_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
///
///
/// ReverseRange
///
///
TEST(coordinate_range, reverse_range_shape0d)
{
const Shape s;
const AxisSet reverset_axis{};
auto reverse_range = reverse(s, reverset_axis);
auto it = reverse_range.begin();
EXPECT_EQ(it, begin(reverse_range));
auto v = *it; // if it is not end it has to be dereferencable;
(void)v;
EXPECT_TRUE(++it == reverse_range.end());
}
TEST(coordinate_range, reverse_range_shape1d)
{
const Shape s{3};
const AxisSet reverset_axis{};
const ExpectedOutput expected{{0, {0}}, {1, {1}}, {2, {2}}};
EXPECT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::forward);
for (size_t i = 0; i < reverse_range.element_number; index += reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, reverse_range_shape2d)
{
const Shape s{2, 3};
const AxisSet reverset_axis{};
// clang-format off
const ExpectedOutput expected{
{0, {0, 0}}, {1, {0, 1}}, {2, {0, 2}},
{3, {1, 0}}, {4, {1, 1}}, {5, {1, 2}}};
// clang-format on
EXPECT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::forward);
for (size_t i = 0; i < reverse_range.element_number; index += reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, reverse_range_shape3d)
{
const Shape s{2, 3, 4};
const AxisSet reverset_axis{};
// clang-format off
const ExpectedOutput expected{
{0, {0, 0, 0}}, {1, {0, 0, 1}}, {2, {0, 0, 2}}, {3, {0, 0, 3}},
{4, {0, 1, 0}}, {5, {0, 1, 1}}, {6, {0, 1, 2}}, {7, {0, 1, 3}},
{8, {0, 2, 0}}, {9, {0, 2, 1}}, {10, {0, 2, 2}}, {11, {0, 2, 3}},
{12, {1, 0, 0}}, {13, {1, 0, 1}}, {14, {1, 0, 2}}, {15, {1, 0, 3}},
{16, {1, 1, 0}}, {17, {1, 1, 1}}, {18, {1, 1, 2}}, {19, {1, 1, 3}},
{20, {1, 2, 0}}, {21, {1, 2, 1}}, {22, {1, 2, 2}}, {23, {1, 2, 3}}};
// clang-format on
EXPECT_EQ(expected.size(), shape_size(s)) << "check epxected data";
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::forward);
for (size_t i = 0; i < reverse_range.element_number; index += reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, reverse_range_zero_sized_axis)
{
const Shape s{2, 0, 4};
auto reverse_range = reverse(s, {});
auto it = reverse_range.begin();
EXPECT_TRUE(it == reverse_range.end()) << "Expect empyt range";
}
///
/// reverse specyfic test
///
TEST(coordinate_range, reverse_range_input_validataion)
{
const Shape s{10, 10, 10};
EXPECT_THROW(reverse(s, {10}), std::domain_error);
}
TEST(coordinate_range, reverse_range_2d)
{
const Shape s{3, 10};
const AxisSet reverset_axis{1};
// clang-format off
const ExpectedOutput expected{
{9, {0, 9}}, {8, {0, 8}}, {7, {0, 7}}, {6, {0, 6}}, {5, {0, 5}}, {4, {0, 4}}, {3, {0, 3}}, {2, {0, 2}}, {1, {0, 1}}, {0, {0, 0}},
{19, {1, 9}}, {18, {1, 8}}, {17, {1, 7}}, {16, {1, 6}}, {15, {1, 5}}, {14, {1, 4}}, {13, {1, 3}}, {12, {1, 2}}, {11, {1, 1}}, {10, {1, 0}},
{29, {2, 9}}, {28, {2, 8}}, {27, {2, 7}}, {26, {2, 6}}, {25, {2, 5}}, {24, {2, 4}}, {23, {2, 3}}, {22, {2, 2}}, {21, {2, 1}}, {20, {2, 0}}};
// clang-format on
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::reverse);
for (size_t i = 0; i < reverse_range.element_number; index -= reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, reverse_1_range_3d)
{
const Shape s{3, 3, 3};
const AxisSet reverset_axis{1};
// clang-format off
const ExpectedOutput expected{
{6, {0, 2, 0}}, {7, {0, 2, 1}}, {8, {0, 2, 2}},
{3, {0, 1, 0}}, {4, {0, 1, 1}}, {5, {0, 1, 2}},
{0, {0, 0, 0}}, {1, {0, 0, 1}}, {2, {0, 0, 2}},
{15, {1, 2, 0}}, {16, {1, 2, 1}}, {17, {1, 2, 2}},
{12, {1, 1, 0}}, {13, {1, 1, 1}}, {14, {1, 1, 2}},
{9, {1, 0, 0}}, {10, {1, 0, 1}}, {11, {1, 0, 2}},
{24, {2, 2, 0}}, {25, {2, 2, 1}}, {26, {2, 2, 2}},
{21, {2, 1, 0}}, {22, {2, 1, 1}}, {23, {2, 1, 2}},
{18, {2, 0, 0}}, {19, {2, 0, 1}}, {20, {2, 0, 2}}};
// clang-format on
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::forward);
for (size_t i = 0; i < reverse_range.element_number; index += reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}
TEST(coordinate_range, reverse_2_range_3d)
{
const Shape s{3, 3, 3};
const AxisSet reverset_axis{1, 2};
// clang-format off
const ExpectedOutput expected{
{8, {0, 2, 2}}, {7, {0, 2, 1}}, {6, {0, 2, 0}},
{5, {0, 1, 2}}, {4, {0, 1, 1}}, {3, {0, 1, 0}},
{2, {0, 0, 2}}, {1, {0, 0, 1}}, {0, {0, 0, 0}},
{17, {1, 2, 2}}, {16, {1, 2, 1}}, {15, {1, 2, 0}},
{14, {1, 1, 2}}, {13, {1, 1, 1}}, {12, {1, 1, 0}},
{11, {1, 0, 2}}, {10, {1, 0, 1}}, {9, {1, 0, 0}},
{26, {2, 2, 2}}, {25, {2, 2, 1}}, {24, {2, 2, 0}},
{23, {2, 1, 2}}, {22, {2, 1, 1}}, {21, {2, 1, 0}},
{20, {2, 0, 2}}, {19, {2, 0, 1}}, {18, {2, 0, 0}}};
// clang-format on
auto expected_val = begin(expected);
for (auto reverse_range : reverse(s, reverset_axis))
{
auto index = reverse_range.begin_index;
ASSERT_EQ(reverse_range.direction, Direction::reverse);
for (size_t i = 0; i < reverse_range.element_number; index -= reverse_range.step, ++i)
{
EXPECT_EQ(index, expected_val->first);
++expected_val;
}
}
EXPECT_TRUE(expected_val == end(expected)) << "not all expected values return, ("
<< std::distance(expected_val, end(expected))
<< " is missing)";
}