| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| #include "main.h" |
| |
| using BoundedVector4d = Matrix<double, Dynamic, 1, ColMajor, 4, 1>; |
| using BoundedMatrix4d = Matrix<double, Dynamic, Dynamic, ColMajor, 4, 4>; |
| |
| EIGEN_DONT_INLINE MatrixXd bounded_transform(const MatrixXd& vertices, const BoundedMatrix4d& transform) { |
| MatrixXd transformed(vertices.rows(), vertices.cols()); |
| for (Index col = 0; col < vertices.cols(); ++col) { |
| BoundedVector4d homogeneous = BoundedVector4d::Ones(vertices.rows() + 1); |
| homogeneous.head(vertices.rows()) = vertices.col(col); |
| transformed.col(col) = (transform * homogeneous).head(vertices.rows()); |
| } |
| return transformed; |
| } |
| |
| struct BoundedFirst { |
| int operator()(int first, int) const { return first; } |
| }; |
| |
| template <int Order> |
| void mixed_bounded_products() { |
| using BoundedVector = Matrix<double, Dynamic, 1, ColMajor, 3, 1>; |
| using DynamicMatrix = Matrix<double, Dynamic, Dynamic, Order>; |
| for (Index size = 1; size <= 3; ++size) { |
| const DynamicMatrix matrix = DynamicMatrix::Random(size, size); |
| const BoundedVector vector = BoundedVector::Random(size); |
| const VectorXd dynamic = vector; |
| const auto left = dynamic.cwiseProduct(vector); |
| const auto right = vector.cwiseProduct(dynamic); |
| STATIC_CHECK(decltype(left)::MaxSizeAtCompileTime == Dynamic); |
| STATIC_CHECK(decltype(right)::MaxSizeAtCompileTime == 3); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(left)>>::Size == 3); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(right)>>::Size == 3); |
| VERIFY_IS_EQUAL(left.sum(), right.sum()); |
| const BoundedVector result = matrix * vector; |
| const auto reversed = (vector.transpose() * matrix.transpose()).eval(); |
| for (Index row = 0; row < size; ++row) { |
| double expected = 0; |
| for (Index col = 0; col < size; ++col) expected += matrix(row, col) * vector(col); |
| VERIFY(numext::abs(result(row) - expected) <= 8 * NumTraits<double>::epsilon()); |
| VERIFY(numext::abs(reversed(row) - expected) <= 8 * NumTraits<double>::epsilon()); |
| } |
| } |
| } |
| |
| template <int Order> |
| void heap_backed_expression_bounds() { |
| using RowsBounded = Matrix<double, Dynamic, Dynamic, Order, 200, Dynamic>; |
| using ColsBounded = Matrix<double, Dynamic, Dynamic, Order, Dynamic, 200>; |
| const RowsBounded a = RowsBounded::Ones(2, 2); |
| const ColsBounded b = ColsBounded::Ones(2, 2); |
| using Bounds = internal::redux_max_size<internal::remove_all_t<decltype(a + b)>>; |
| STATIC_CHECK(Bounds::Rows == 200); |
| STATIC_CHECK(Bounds::Cols == 200); |
| STATIC_CHECK(Bounds::Size == 40000); |
| const auto sum = (a + b).eval(); |
| const auto reversed = (b + a).eval(); |
| STATIC_CHECK((std::is_same<internal::remove_all_t<decltype(sum)>, RowsBounded>::value)); |
| STATIC_CHECK((std::is_same<internal::remove_all_t<decltype(reversed)>, ColsBounded>::value)); |
| VERIFY_IS_EQUAL(sum, RowsBounded::Constant(2, 2, 2)); |
| VERIFY_IS_EQUAL(reversed, ColsBounded::Constant(2, 2, 2)); |
| VERIFY_IS_EQUAL((a + b).sum(), 8); |
| } |
| |
| template <int Order> |
| void complementary_reduction_bounds() { |
| using RowsBounded = Matrix<int, Dynamic, Dynamic, Order, 4, Dynamic>; |
| using ColsBounded = Matrix<int, Dynamic, Dynamic, Order, Dynamic, 4>; |
| const RowsBounded a = RowsBounded::Constant(3, 4, 2); |
| const ColsBounded b = ColsBounded::Constant(3, 4, 3); |
| using Bounds = internal::redux_max_size<internal::remove_all_t<decltype(a + b)>>; |
| STATIC_CHECK(Bounds::Size == 16); |
| VERIFY_IS_EQUAL((a + b).sum(), 60); |
| VERIFY_IS_EQUAL((a + b).redux(BoundedFirst()), 5); |
| VERIFY_IS_EQUAL((b + a).redux(BoundedFirst()), 5); |
| |
| const auto wrapped_array = (a + b).array(); |
| const auto wrapped_matrix = (a.array() + b.array()).matrix(); |
| using ArrayBounds = internal::redux_max_size<internal::remove_all_t<decltype(wrapped_array)>>; |
| using MatrixBounds = internal::redux_max_size<internal::remove_all_t<decltype(wrapped_matrix)>>; |
| STATIC_CHECK(ArrayBounds::Rows == 4 && ArrayBounds::Cols == 4 && ArrayBounds::Size == 16); |
| STATIC_CHECK(MatrixBounds::Rows == 4 && MatrixBounds::Cols == 4 && MatrixBounds::Size == 16); |
| STATIC_CHECK(decltype(wrapped_array)::MaxSizeAtCompileTime == Dynamic); |
| STATIC_CHECK(decltype(wrapped_matrix)::MaxSizeAtCompileTime == Dynamic); |
| VERIFY_IS_EQUAL(wrapped_array.sum(), 60); |
| VERIFY_IS_EQUAL(wrapped_matrix.sum(), 60); |
| VERIFY_IS_EQUAL(wrapped_array.redux(BoundedFirst()), 5); |
| VERIFY_IS_EQUAL(wrapped_matrix.redux(BoundedFirst()), 5); |
| |
| const Matrix<bool, Dynamic, Dynamic, Order> condition = Matrix<bool, Dynamic, Dynamic, Order>::Constant(3, 4, true); |
| const auto selected = condition.select(a, b); |
| const auto reversed = condition.select(b, a); |
| using SelectedBounds = internal::redux_max_size<internal::remove_all_t<decltype(selected)>>; |
| using ReversedBounds = internal::redux_max_size<internal::remove_all_t<decltype(reversed)>>; |
| STATIC_CHECK(SelectedBounds::Rows == 4 && SelectedBounds::Cols == 4 && SelectedBounds::Size == 16); |
| STATIC_CHECK(ReversedBounds::Size == 16); |
| STATIC_CHECK(decltype(selected)::MaxSizeAtCompileTime == Dynamic); |
| VERIFY_IS_EQUAL(selected.sum(), 24); |
| VERIFY_IS_EQUAL(reversed.sum(), 36); |
| VERIFY_IS_EQUAL(selected.redux(BoundedFirst()), 2); |
| VERIFY_IS_EQUAL(reversed.redux(BoundedFirst()), 3); |
| |
| using Bounded = Matrix<int, Dynamic, Dynamic, Order, 4, 4>; |
| const Bounded bounded = Bounded::Constant(3, 4, 7); |
| const Matrix<int, Dynamic, Dynamic, Order> dynamic = bounded; |
| const auto bounded_second = condition.select(bounded, dynamic); |
| const auto bounded_third = condition.select(dynamic, bounded); |
| const auto bounded_first = (bounded.array() > 0).select(dynamic.array(), dynamic.array()); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(bounded_second)>>::Size == 16); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(bounded_third)>>::Size == 16); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(bounded_first)>>::Size == 16); |
| VERIFY_IS_EQUAL(bounded_second.sum(), 84); |
| VERIFY_IS_EQUAL(bounded_third.sum(), 84); |
| VERIFY_IS_EQUAL(bounded_first.sum(), 84); |
| |
| using HugeRows = Matrix<int, Dynamic, Dynamic, Order, 100000, Dynamic>; |
| using HugeCols = Matrix<int, Dynamic, Dynamic, Order, Dynamic, 100000>; |
| using HugeExpression = decltype(std::declval<HugeRows>() + std::declval<HugeCols>()); |
| STATIC_CHECK(internal::redux_max_size<HugeExpression>::Size == Dynamic); |
| } |
| |
| template <typename Scalar, int Capacity> |
| void mixed_packet_reductions() { |
| using Bounded = Matrix<Scalar, Dynamic, 1, ColMajor, Capacity, 1>; |
| using DynamicVector = Matrix<Scalar, Dynamic, 1>; |
| for (Index size = 0; size <= Capacity; ++size) { |
| Bounded bounded(size); |
| DynamicVector dynamic(size); |
| Scalar expected = 0; |
| for (Index i = 0; i < size; ++i) { |
| bounded(i) = Scalar(i % 5 - 2); |
| dynamic(i) = Scalar(i % 3 + 1); |
| expected += bounded(i) * dynamic(i); |
| } |
| const auto left = dynamic.cwiseProduct(bounded); |
| const auto right = bounded.cwiseProduct(dynamic); |
| STATIC_CHECK(decltype(left)::MaxSizeAtCompileTime == Dynamic); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(left)>>::Size == Capacity); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(right)>>::Size == Capacity); |
| VERIFY_IS_EQUAL(left.sum(), expected); |
| VERIFY_IS_EQUAL(right.sum(), expected); |
| const auto squared = left.cwiseAbs2(); |
| const auto negated = -squared; |
| STATIC_CHECK(decltype(squared)::MaxSizeAtCompileTime == Dynamic); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(squared)>>::Size == Capacity); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(negated)>>::Size == Capacity); |
| Scalar expectedSquared = 0; |
| for (Index i = 0; i < size; ++i) { |
| const Scalar value = bounded(i) * dynamic(i); |
| expectedSquared += value * value; |
| } |
| VERIFY_IS_EQUAL(squared.sum(), expectedSquared); |
| VERIFY_IS_EQUAL(negated.sum(), -expectedSquared); |
| VERIFY_IS_EQUAL(left.squaredNorm(), expectedSquared); |
| |
| const auto wrapped = left.array().square(); |
| auto array_product = dynamic.array() * bounded.array(); |
| const auto matrix = array_product.matrix(); |
| const auto nested = matrix.array().square().matrix(); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(wrapped)>>::Size == Capacity); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(matrix)>>::Size == Capacity); |
| STATIC_CHECK(internal::redux_max_size<internal::remove_all_t<decltype(nested)>>::Size == Capacity); |
| VERIFY_IS_EQUAL(wrapped.sum(), expectedSquared); |
| VERIFY_IS_EQUAL(matrix.sum(), expected); |
| VERIFY_IS_EQUAL(matrix.squaredNorm(), expectedSquared); |
| VERIFY_IS_EQUAL(nested.sum(), expectedSquared); |
| } |
| } |
| |
| template <int Order> |
| void bounded_reductions() { |
| for (Index size : {1, 4, 15, 16, 31, 32, 33, 64}) { |
| Matrix<int, Dynamic, Dynamic, Order, 64, 64> matrix(size, size); |
| for (Index row = 0; row < size; ++row) |
| for (Index col = 0; col < size; ++col) matrix(row, col) = int(row + col + 1); |
| VERIFY_IS_EQUAL(matrix.sum(), size * size * size); |
| VERIFY_IS_EQUAL(matrix.redux(BoundedFirst()), 1); |
| VERIFY_IS_EQUAL(matrix.topLeftCorner(size, size).sum(), size * size * size); |
| VERIFY_IS_EQUAL(matrix.topLeftCorner(size, size).redux(BoundedFirst()), 1); |
| } |
| } |
| |
| EIGEN_DECLARE_TEST(redux_bounded) { |
| mixed_packet_reductions<float, 3>(); |
| mixed_packet_reductions<float, 7>(); |
| mixed_packet_reductions<float, 15>(); |
| mixed_packet_reductions<float, 17>(); |
| mixed_packet_reductions<double, 3>(); |
| mixed_packet_reductions<double, 7>(); |
| mixed_packet_reductions<double, 15>(); |
| mixed_packet_reductions<double, 17>(); |
| for (Index size = 0; size <= 3; ++size) { |
| const MatrixXd vertices = MatrixXd::Random(size, 10); |
| const BoundedMatrix4d transform = BoundedMatrix4d::Random(size + 1, size + 1); |
| const MatrixXd result = bounded_transform(vertices, transform); |
| for (Index row = 0; row < size; ++row) { |
| for (Index col = 0; col < vertices.cols(); ++col) { |
| double expected = transform(row, size); |
| for (Index k = 0; k < size; ++k) expected += transform(row, k) * vertices(k, col); |
| VERIFY(numext::abs(result(row, col) - expected) <= 32 * NumTraits<double>::epsilon()); |
| } |
| } |
| } |
| bounded_reductions<ColMajor>(); |
| bounded_reductions<RowMajor>(); |
| mixed_bounded_products<ColMajor>(); |
| mixed_bounded_products<RowMajor>(); |
| heap_backed_expression_bounds<ColMajor>(); |
| heap_backed_expression_bounds<RowMajor>(); |
| complementary_reduction_bounds<ColMajor>(); |
| complementary_reduction_bounds<RowMajor>(); |
| } |