blob: 7facccd6433551f784bd123c8463d3f1354a26e3 [file]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
#include "main.h"
#include "MovableScalar.h"
template <typename Scalar>
struct ReductionIdentity {
ReductionIdentity(double initialValue, int& lvalueCount, int& rvalueCount)
: value(initialValue), lvalueConversions(lvalueCount), rvalueConversions(rvalueCount) {}
ReductionIdentity(const ReductionIdentity&) = delete;
ReductionIdentity(ReductionIdentity&&) = delete;
explicit operator Scalar() const& {
++lvalueConversions;
return Scalar(value);
}
explicit operator Scalar() && {
++rvalueConversions;
return Scalar(value);
}
double value;
int& lvalueConversions;
int& rvalueConversions;
};
template <typename Scalar>
void reductionIdentityArguments() {
const internal::scalar_sum_op<Scalar, Scalar> sum;
const Matrix<Scalar, 0, 1> fixedEmpty;
const Matrix<Scalar, Dynamic, 1, 0, 0, 1> zeroCapacity(0);
Matrix<Scalar, Dynamic, 1> dynamic(0);
const double runtimeIdentity = 0.25;
VERIFY_IS_EQUAL(double(internal::redux_with_identity(fixedEmpty, sum, runtimeIdentity)), runtimeIdentity);
VERIFY_IS_EQUAL(double(internal::redux_with_identity(dynamic, sum, runtimeIdentity)), runtimeIdentity);
int lvalueConversions = 0, rvalueConversions = 0;
ReductionIdentity<Scalar> identity(runtimeIdentity, lvalueConversions, rvalueConversions);
const auto& constIdentity = identity;
VERIFY_IS_EQUAL(double(internal::redux_with_identity(fixedEmpty, sum, identity)), runtimeIdentity);
VERIFY_IS_EQUAL(double(internal::redux_with_identity(zeroCapacity, sum, identity)), runtimeIdentity);
VERIFY_IS_EQUAL(double(internal::redux_with_identity(dynamic, sum, constIdentity)), runtimeIdentity);
VERIFY_IS_EQUAL(lvalueConversions, 3);
VERIFY_IS_EQUAL(rvalueConversions, 0);
Matrix<Scalar, 2, 1> fixed;
fixed << Scalar(2), Scalar(3);
dynamic = fixed;
VERIFY_IS_EQUAL(double(internal::redux_with_identity(fixed, sum, identity)), 5.0);
VERIFY_IS_EQUAL(double(internal::redux_with_identity(
dynamic, sum, ReductionIdentity<Scalar>(runtimeIdentity, lvalueConversions, rvalueConversions))),
5.0);
VERIFY_IS_EQUAL(lvalueConversions, 3);
VERIFY_IS_EQUAL(rvalueConversions, 0);
dynamic.resize(0);
VERIFY_IS_EQUAL(double(internal::redux_with_identity(dynamic, sum, std::move(identity))), runtimeIdentity);
VERIFY_IS_EQUAL(
double(internal::redux_with_identity(
fixedEmpty, sum, ReductionIdentity<Scalar>(runtimeIdentity, lvalueConversions, rvalueConversions))),
runtimeIdentity);
VERIFY_IS_EQUAL(lvalueConversions, 3);
VERIFY_IS_EQUAL(rvalueConversions, 2);
}
template <typename MatrixType>
void zeroReduction(const MatrixType& m) {
// Reductions that must hold for zero sized objects
VERIFY(m.all());
VERIFY(!m.any());
VERIFY(m.prod() == 1);
VERIFY(m.sum() == 0);
VERIFY(m.norm() == 0);
VERIFY(m.squaredNorm() == 0);
EIGEN_IF_CONSTEXPR (!NumTraits<typename MatrixType::Scalar>::IsInteger) {
VERIFY(m.template lpNorm<Infinity>() == 0);
VERIFY(m.hypotNorm() == 0);
VERIFY(m.stableNorm() == 0);
}
VERIFY(m.count() == 0);
VERIFY(m.allFinite());
VERIFY(!m.hasNaN());
VERIFY_RAISES_ASSERT(m.minCoeff());
VERIFY_RAISES_ASSERT(m.maxCoeff());
Index i, j;
EIGEN_UNUSED_VARIABLE(i); // Only used if exceptions are enabled.
EIGEN_UNUSED_VARIABLE(j);
VERIFY_RAISES_ASSERT(m.minCoeff(&i, &j));
VERIFY_RAISES_ASSERT(m.maxCoeff(&i, &j));
VERIFY_RAISES_ASSERT(m.reshaped().minCoeff(&i));
VERIFY_RAISES_ASSERT(m.reshaped().maxCoeff(&i));
}
template <typename MatrixType>
void zeroSizedMatrix() {
MatrixType t1;
typedef typename MatrixType::Scalar Scalar;
if (MatrixType::SizeAtCompileTime == Dynamic || MatrixType::SizeAtCompileTime == 0) {
zeroReduction(t1);
if (MatrixType::RowsAtCompileTime == Dynamic) VERIFY(t1.rows() == 0);
if (MatrixType::ColsAtCompileTime == Dynamic) VERIFY(t1.cols() == 0);
MatrixType reversed = t1;
reversed.reverseInPlace();
VERIFY(reversed == t1.reverse());
if (t1.rows() == t1.cols()) {
MatrixType transposed = t1;
transposed.transposeInPlace();
VERIFY(transposed == t1.transpose());
}
if (MatrixType::RowsAtCompileTime == Dynamic && MatrixType::ColsAtCompileTime == Dynamic) {
MatrixType t2(0, 0);
VERIFY(t2.rows() == 0);
VERIFY(t2.cols() == 0);
zeroReduction(t2);
VERIFY(t1 == t2);
}
}
if (MatrixType::MaxColsAtCompileTime != 0 && MatrixType::MaxRowsAtCompileTime != 0) {
Index rows = MatrixType::RowsAtCompileTime == Dynamic ? internal::random<Index>(1, 10)
: Index(MatrixType::RowsAtCompileTime);
Index cols = MatrixType::ColsAtCompileTime == Dynamic ? internal::random<Index>(1, 10)
: Index(MatrixType::ColsAtCompileTime);
MatrixType m(rows, cols);
zeroReduction(m.template block<0, MatrixType::ColsAtCompileTime>(0, 0, 0, cols));
zeroReduction(m.template block<MatrixType::RowsAtCompileTime, 0>(0, 0, rows, 0));
zeroReduction(m.template block<0, 1>(0, 0));
zeroReduction(m.template block<1, 0>(0, 0));
Matrix<Scalar, Dynamic, Dynamic> prod = m.template block<MatrixType::RowsAtCompileTime, 0>(0, 0, rows, 0) *
m.template block<0, MatrixType::ColsAtCompileTime>(0, 0, 0, cols);
VERIFY(prod.rows() == rows && prod.cols() == cols);
VERIFY(prod.isZero());
prod = m.template block<1, 0>(0, 0) * m.template block<0, 1>(0, 0);
VERIFY(prod.size() == 1);
VERIFY(prod.isZero());
}
}
// Complex extrema are unordered; check only reductions with defined empty identities.
template <typename MatrixType>
void zeroComplexReduction(const MatrixType& m) {
using Scalar = typename MatrixType::Scalar;
VERIFY_IS_EQUAL(m.sum(), Scalar(0));
VERIFY_IS_EQUAL(m.prod(), Scalar(1));
VERIFY_IS_EQUAL(m.template lpNorm<Infinity>(), 0.0);
VERIFY_IS_EQUAL(m.hypotNorm(), 0.0);
VERIFY_IS_EQUAL(m.stableNorm(), 0.0);
}
template <typename VectorType>
void zeroSizedVector() {
VectorType t1;
if (VectorType::SizeAtCompileTime == Dynamic || VectorType::SizeAtCompileTime == 0) {
zeroReduction(t1);
VERIFY(t1.size() == 0);
VectorType t2(DenseIndex(0)); // Select the size constructor.
VERIFY(t2.size() == 0);
zeroReduction(t2);
VERIFY(t1 == t2);
}
}
EIGEN_DECLARE_TEST(zerosized) {
reductionIdentityArguments<double>();
reductionIdentityArguments<MovableScalar<double>>();
zeroSizedMatrix<Matrix2d>();
zeroSizedMatrix<Matrix3i>();
zeroSizedMatrix<Matrix<float, 2, Dynamic> >();
zeroSizedMatrix<MatrixXf>();
zeroSizedMatrix<Matrix<float, 0, 0> >();
zeroSizedMatrix<Matrix<float, Dynamic, 0, 0, 0, 0> >();
zeroSizedMatrix<Matrix<float, 0, Dynamic, 0, 0, 0> >();
zeroSizedMatrix<Matrix<float, Dynamic, Dynamic, 0, 0, 0> >();
zeroSizedMatrix<Matrix<float, 0, 4> >();
zeroSizedMatrix<Matrix<float, 4, 0> >();
zeroSizedVector<Vector2d>();
zeroSizedVector<Vector3i>();
zeroSizedVector<VectorXf>();
zeroSizedVector<Matrix<float, 0, 1> >();
zeroSizedVector<Matrix<float, 1, 0> >();
zeroComplexReduction(MatrixXcd(0, 3));
zeroComplexReduction(MatrixXcd(3, 0));
zeroComplexReduction(Matrix<std::complex<double>, 0, 0>());
zeroComplexReduction(Matrix<std::complex<double>, 0, 3>());
zeroComplexReduction(Matrix<std::complex<double>, 3, 0>());
}