blob: 68a855c7ea1ed0112f6f0b1223a6731943245073 [file] [edit]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#if defined(EIGEN_TEST_PART_2)
#define EIGEN_NO_MALLOC
#else
#define EIGEN_RUNTIME_NO_MALLOC
#endif
#include "main.h"
#include <Eigen/Eigenvalues>
template <typename MatrixType>
void schur_no_malloc() {
using Scalar = typename MatrixType::Scalar;
using VectorType = typename RealSchur<MatrixType>::ColumnVectorType;
// These sizes would select padding if allocation and deallocation were allowed.
const Index n = 1024 / sizeof(Scalar);
MatrixType h = MatrixType::Random(n, n);
h.bottomLeftCorner(n - 2, n - 2).template triangularView<Lower>().setZero();
MatrixType q = MatrixType::Identity(n, n);
for (Index i = 0; i < n; i += 2) q(i, i) = Scalar(-1);
const MatrixType a = q.diagonal().asDiagonal() * h * q.diagonal().asDiagonal();
const Scalar bound = Scalar(64 * n) * NumTraits<Scalar>::epsilon();
MatrixType referenceT(n, n);
VectorType residual(n);
RealSchur<MatrixType> solver(n);
#ifdef EIGEN_RUNTIME_NO_MALLOC
for (int restriction : {1, 2, 3, 0}) {
internal::set_is_malloc_allowed((restriction & 1) == 0);
internal::set_is_free_allowed((restriction & 2) == 0);
#endif
solver.setMaxIterations(-1).compute(a, false);
VERIFY_IS_EQUAL(solver.info(), Success);
// An already Hessenberg input has no reflectors, so forming its initial Q must not allocate.
solver.compute(h, true);
#ifdef EIGEN_RUNTIME_NO_MALLOC
internal::set_is_malloc_allowed(true);
internal::set_is_free_allowed(true);
#endif
VERIFY_IS_EQUAL(solver.info(), Success);
Scalar hessenbergError(0);
for (Index j = 0; j < n; ++j) {
residual.noalias() = h * solver.matrixU().col(j);
residual.noalias() -= solver.matrixU() * solver.matrixT().col(j);
hessenbergError += residual.squaredNorm();
}
VERIFY(numext::sqrt(hessenbergError) <= bound * h.norm());
for (Index maxIters : {Index(-1), Index(1)}) {
solver.setMaxIterations(maxIters);
for (bool computeU : {true, false}) {
#ifdef EIGEN_RUNTIME_NO_MALLOC
internal::set_is_malloc_allowed((restriction & 1) == 0);
internal::set_is_free_allowed((restriction & 2) == 0);
#endif
solver.computeFromHessenberg(h, q, computeU);
#ifdef EIGEN_RUNTIME_NO_MALLOC
internal::set_is_malloc_allowed(true);
internal::set_is_free_allowed(true);
#endif
VERIFY_IS_EQUAL(solver.info(), maxIters == -1 ? Success : NoConvergence);
if (computeU) {
referenceT = solver.matrixT();
const MatrixType& u = solver.matrixU();
Scalar reconstructionError(0), orthogonalityError(0);
// Matrix-vector products also keep verification allocation-free in the compile-time no-malloc part.
for (Index j = 0; j < n; ++j) {
residual.noalias() = a * u.col(j);
residual.noalias() -= u * referenceT.col(j);
reconstructionError += residual.squaredNorm();
residual.noalias() = u.transpose() * u.col(j);
residual(j) -= Scalar(1);
orthogonalityError += residual.squaredNorm();
}
VERIFY(numext::sqrt(reconstructionError) <= bound * a.norm());
VERIFY(numext::sqrt(orthogonalityError) <= bound);
} else {
VERIFY_IS_EQUAL(solver.matrixT(), referenceT);
}
}
}
#ifdef EIGEN_RUNTIME_NO_MALLOC
}
#endif
}
EIGEN_DECLARE_TEST(schur_real_nomalloc) {
CALL_SUBTEST_1((schur_no_malloc<Matrix<float, Dynamic, Dynamic, ColMajor>>()));
CALL_SUBTEST_1((schur_no_malloc<Matrix<float, Dynamic, Dynamic, RowMajor>>()));
CALL_SUBTEST_1((schur_no_malloc<Matrix<double, Dynamic, Dynamic, ColMajor>>()));
CALL_SUBTEST_1((schur_no_malloc<Matrix<double, Dynamic, Dynamic, RowMajor>>()));
CALL_SUBTEST_2((schur_no_malloc<Matrix<double, 128, 128, ColMajor>>()));
CALL_SUBTEST_2((schur_no_malloc<Matrix<double, 128, 128, RowMajor>>()));
CALL_SUBTEST_2((schur_no_malloc<Matrix<double, Dynamic, Dynamic, ColMajor, 128, 128>>()));
CALL_SUBTEST_2((schur_no_malloc<Matrix<double, Dynamic, Dynamic, RowMajor, 128, 128>>()));
}