| // 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>>())); | |
| } |