| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2026 Rasmus Munk Larsen <rmlarsen@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 |
| |
| // Enable Eigen's runtime malloc tracking so bunchkaufman_no_malloc() can assert that compute() |
| // performs no heap allocation when the workspace is pre-allocated. (Malloc stays allowed by default; |
| // only that one subtest toggles it off.) Must be defined before any Eigen header is included. |
| #define EIGEN_RUNTIME_NO_MALLOC |
| |
| #include "main.h" |
| #include <Eigen/Cholesky> |
| #include <Eigen/QR> |
| #include <Eigen/Eigenvalues> |
| #include "solverbase.h" |
| |
| template <typename MatrixType, int UpLo> |
| typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) { |
| if (m.cols() == 0) return typename MatrixType::RealScalar(0); |
| MatrixType symm = m.template selfadjointView<UpLo>(); |
| return symm.cwiseAbs().colwise().sum().maxCoeff(); |
| } |
| |
| // Reconstruct the block-diagonal D from vectorD() / subDiagonal() and check that |
| // P^T L D L^* P == A and that matrixL()/matrixU() are consistent. |
| template <typename MatrixType, typename BKType> |
| void verify_factorization(const MatrixType& A, const BKType& bk) { |
| typedef typename MatrixType::Scalar Scalar; |
| const Index n = A.rows(); |
| |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| |
| // Build D explicitly from vectorD() and subDiagonal() and reconstruct manually. |
| MatrixType D = MatrixType::Zero(n, n); |
| D.diagonal() = bk.vectorD(); |
| for (Index k = 0; k + 1 < n; ++k) { |
| Scalar s = bk.subDiagonal()(k); |
| if (!numext::is_exactly_zero(s)) { |
| D(k + 1, k) = s; |
| D(k, k + 1) = numext::conj(s); |
| } |
| } |
| // matrixU() should be the adjoint of matrixL(). |
| MatrixType L = bk.matrixL(); |
| MatrixType U = bk.matrixU(); |
| VERIFY_IS_APPROX(L.adjoint(), U); |
| |
| // P^T L D L^* P |
| MatrixType PtL = bk.transpositionsP().transpose() * L; |
| MatrixType recon = PtL * D * PtL.adjoint(); |
| VERIFY_IS_APPROX(A, recon); |
| } |
| |
| // Core test on a Hermitian indefinite matrix `symm` (full, self-adjoint). |
| template <typename MatrixType> |
| void bunchkaufman_solve_and_reconstruct(const MatrixType& symm) { |
| typedef typename MatrixType::Scalar Scalar; |
| typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType; |
| typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; |
| |
| const Index rows = symm.rows(); |
| const Index cols = symm.cols(); |
| |
| SquareMatrixType symmLo = symm.template triangularView<Lower>(); |
| SquareMatrixType symmUp = symm.template triangularView<Upper>(); |
| |
| BunchKaufman<SquareMatrixType, Lower> bk_lo(symmLo); |
| VERIFY(bk_lo.info() == Success); |
| verify_factorization(SquareMatrixType(symm), bk_lo); |
| check_solverbase<VectorType, VectorType>(symm, bk_lo, rows, rows, 1); |
| check_solverbase<MatrixType, MatrixType>(symm, bk_lo, rows, cols, rows); |
| |
| BunchKaufman<SquareMatrixType, Upper> bk_up(symmUp); |
| VERIFY(bk_up.info() == Success); |
| verify_factorization(SquareMatrixType(symm), bk_up); |
| check_solverbase<VectorType, VectorType>(symm, bk_up, rows, rows, 1); |
| |
| // MatrixBase / SelfAdjointView entry points. |
| verify_factorization(SquareMatrixType(symm), SquareMatrixType(symm).bunchKaufman()); |
| verify_factorization(SquareMatrixType(symm), symm.template selfadjointView<Lower>().bunchKaufman()); |
| verify_factorization(SquareMatrixType(symm), symm.template selfadjointView<Upper>().bunchKaufman()); |
| |
| // rcond() within a factor of 10 of the true reciprocal 1-norm condition number. |
| if (rows > 0) { |
| const SquareMatrixType inv = bk_lo.solve(SquareMatrixType::Identity(rows, rows)); |
| using RealScalar = typename MatrixType::RealScalar; |
| RealScalar rcond = (RealScalar(1) / matrix_l1_norm<SquareMatrixType, Lower>(symmLo)) / |
| matrix_l1_norm<SquareMatrixType, Lower>(inv); |
| RealScalar rcond_est = bk_lo.rcond(); |
| VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10); |
| } |
| } |
| |
| // Build a Hermitian matrix with a prescribed (real) eigenvalue spectrum and check inertia + stability. |
| template <typename MatrixType> |
| void bunchkaufman_inertia_and_conditioning(Index n) { |
| typedef typename MatrixType::Scalar Scalar; |
| typedef typename MatrixType::RealScalar RealScalar; |
| typedef Matrix<RealScalar, Dynamic, 1> RealVectorType; |
| |
| // Random orthonormal/unitary U via QR. |
| MatrixType R = MatrixType::Random(n, n); |
| HouseholderQR<MatrixType> qr(R); |
| MatrixType U = qr.householderQ(); |
| |
| // Eigenvalues spanning a wide magnitude range, with mixed signs (indefinite). |
| const RealScalar s = (std::min)(RealScalar(6), RealScalar(std::numeric_limits<RealScalar>::max_exponent10) / 8); |
| RealVectorType d(n); |
| Index expect_pos = 0, expect_neg = 0; |
| for (Index k = 0; k < n; ++k) { |
| RealScalar mag = pow(RealScalar(10), internal::random<RealScalar>(-s, s)); |
| RealScalar sign = internal::random<bool>() ? RealScalar(1) : RealScalar(-1); |
| d(k) = sign * mag; |
| if (d(k) > 0) |
| ++expect_pos; |
| else |
| ++expect_neg; |
| } |
| MatrixType A = U * d.asDiagonal() * U.adjoint(); |
| // Force exact Hermitian symmetry (kill round-off asymmetry). |
| A = (A + A.adjoint()).eval() * Scalar(RealScalar(0.5)); |
| |
| BunchKaufman<MatrixType, Lower> bk(A); |
| VERIFY(bk.info() == Success); |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| |
| // isPositive()/isNegative() agree with the true inertia. |
| VERIFY(bk.isPositive() == (expect_neg == 0)); |
| VERIFY(bk.isNegative() == (expect_pos == 0)); |
| |
| // Backward-stable solve: relative residual is small even for ill-conditioned A. |
| Matrix<Scalar, Dynamic, 1> b = Matrix<Scalar, Dynamic, 1>::Random(n); |
| Matrix<Scalar, Dynamic, 1> x = bk.solve(b); |
| RealScalar res = (A * x - b).norm() / b.norm(); |
| RealScalar tol = sqrt(test_precision<RealScalar>()); |
| VERIFY(res <= tol); |
| } |
| |
| // Definiteness / 2x2-pivot regression cases. |
| template <typename Scalar> |
| void bunchkaufman_small_cases() { |
| typedef Matrix<Scalar, 2, 2> Mat2; |
| typedef Matrix<Scalar, 2, 1> Vec2; |
| |
| // Indefinite with zero diagonal -> requires a 2x2 pivot. |
| { |
| Mat2 A; |
| A << Scalar(0), Scalar(1), Scalar(1), Scalar(0); |
| BunchKaufman<Mat2> bk(A); |
| VERIFY(bk.info() == Success); |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| VERIFY(!bk.isPositive()); |
| VERIFY(!bk.isNegative()); |
| Vec2 b(Scalar(3), Scalar(5)); |
| Vec2 x = bk.solve(b); |
| VERIFY_IS_APPROX(A * x, b); |
| } |
| // Diagonal indefinite [[1,0],[0,-1]]. |
| { |
| Mat2 A; |
| A << Scalar(1), Scalar(0), Scalar(0), Scalar(-1); |
| BunchKaufman<Mat2> bk(A); |
| VERIFY(bk.info() == Success); |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| VERIFY(!bk.isPositive()); |
| VERIFY(!bk.isNegative()); |
| } |
| // 1x1. |
| { |
| Matrix<Scalar, 1, 1> A; |
| A << Scalar(-3); |
| BunchKaufman<Matrix<Scalar, 1, 1> > bk(A); |
| VERIFY(bk.info() == Success); |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| VERIFY(!bk.isPositive()); |
| VERIFY(bk.isNegative()); |
| } |
| } |
| |
| // Exactly-singular matrix: factorization succeeds structurally but reports NumericalIssue, |
| // while still reconstructing the input exactly. Exercised at a small size (unblocked kernel) and a |
| // size larger than the panel width (blocked kernel, where the zero pivot lands inside a panel). |
| template <typename Scalar> |
| void bunchkaufman_singular(Index n) { |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| // A zero column/row makes the matrix exactly singular with an exact zero pivot. Place it in the |
| // interior so that, for n > blocksize, it falls inside a panel of the blocked algorithm. |
| const Index z = n / 2; |
| MatrixType M = MatrixType::Random(n, n); |
| MatrixType A = M + M.adjoint(); |
| A.col(z).setZero(); |
| A.row(z).setZero(); |
| BunchKaufman<MatrixType, Lower> lo(A); |
| VERIFY(lo.info() == NumericalIssue); |
| VERIFY_IS_APPROX(A, lo.reconstructedMatrix()); |
| // matrixL() must be a well-formed unit lower triangular factor even on the singular column. |
| VERIFY((lo.matrixL().toDenseMatrix().diagonal().array() == Scalar(1)).all()); |
| BunchKaufman<MatrixType, Upper> up(A); |
| VERIFY(up.info() == NumericalIssue); |
| VERIFY_IS_APPROX(A, up.reconstructedMatrix()); |
| } |
| |
| // A matrix containing a NaN must be reported as a numerical failure (matching LAPACK's DISNAN guard), |
| // not silently accepted. |
| template <typename Scalar> |
| void bunchkaufman_nan() { |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| for (Index n : {5, 100}) { |
| MatrixType M = MatrixType::Random(n, n); |
| MatrixType A = M + M.adjoint(); |
| A(n / 2, n / 2) = std::numeric_limits<typename NumTraits<Scalar>::Real>::quiet_NaN(); |
| BunchKaufman<MatrixType> bk(A); |
| VERIFY(bk.info() == NumericalIssue); |
| } |
| } |
| |
| // Rank-deficient PSD: A = a a^* with a of rank r < n. Reconstruct must match. |
| template <typename Scalar> |
| void bunchkaufman_rank_deficient() { |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| const Index n = 16; |
| const Index r = internal::random<Index>(1, n - 1); |
| MatrixType a = MatrixType::Random(n, r); |
| MatrixType A = a * a.adjoint(); |
| BunchKaufman<MatrixType> bk(A); |
| VERIFY_IS_APPROX(A, bk.reconstructedMatrix()); |
| VERIFY(!bk.isNegative()); // PSD -> no negative eigenvalues |
| } |
| |
| // Blocking and 2x2-panel-boundary stress across sizes that straddle the panel width. |
| template <typename Scalar> |
| void bunchkaufman_blocking_boundary() { |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| typedef typename NumTraits<Scalar>::Real RealScalar; |
| const Index PS = internal::packet_traits<Scalar>::size; |
| const Index sizes[] = {1, 2, 3, PS - 1, PS, PS + 1, 2 * PS, 31, 32, 33, |
| 63, 64, 65, 96, 127, 128, 129, 192, 2 * 64 + 3, 200}; |
| for (Index n : sizes) { |
| if (n <= 0) continue; |
| MatrixType M = MatrixType::Random(n, n); |
| MatrixType A = M + M.adjoint(); |
| // Force several 2x2 pivots by shrinking the diagonal. |
| A.diagonal() *= Scalar(RealScalar(1e-2)); |
| |
| BunchKaufman<MatrixType, Lower> lo(A); |
| VERIFY(lo.info() == Success); |
| VERIFY_IS_APPROX(A, lo.reconstructedMatrix()); |
| |
| BunchKaufman<MatrixType, Upper> up(A); |
| VERIFY(up.info() == Success); |
| VERIFY_IS_APPROX(A, up.reconstructedMatrix()); |
| |
| // Lower and Upper must yield the same (Hermitian) decomposition of A. |
| VERIFY_IS_APPROX(lo.reconstructedMatrix(), up.reconstructedMatrix()); |
| |
| Matrix<Scalar, Dynamic, 1> b = Matrix<Scalar, Dynamic, 1>::Random(n); |
| VERIFY_IS_APPROX(A * lo.solve(b).eval(), b); |
| } |
| } |
| |
| template <typename MatrixType> |
| void bunchkaufman_verify_assert() { |
| MatrixType tmp; |
| BunchKaufman<MatrixType> bk; |
| VERIFY_RAISES_ASSERT(bk.matrixL()) |
| VERIFY_RAISES_ASSERT(bk.matrixU()) |
| VERIFY_RAISES_ASSERT(bk.vectorD()) |
| VERIFY_RAISES_ASSERT(bk.subDiagonal()) |
| VERIFY_RAISES_ASSERT(bk.transpositionsP()) |
| VERIFY_RAISES_ASSERT(bk.isPositive()) |
| VERIFY_RAISES_ASSERT(bk.isNegative()) |
| VERIFY_RAISES_ASSERT(bk.matrixLDLT()) |
| VERIFY_RAISES_ASSERT(bk.reconstructedMatrix()) |
| VERIFY_RAISES_ASSERT(bk.solve(tmp)) |
| } |
| |
| // Build a random Hermitian (real symmetric) indefinite matrix of the same type/size as `m`. |
| template <typename MatrixType> |
| MatrixType make_hermitian_indefinite(const MatrixType& m) { |
| MatrixType a = MatrixType::Random(m.rows(), m.cols()); |
| return MatrixType(a + a.adjoint()); |
| } |
| |
| template <typename MatrixType> |
| void bunchkaufman(const MatrixType& m) { |
| // General Hermitian indefinite. |
| bunchkaufman_solve_and_reconstruct(make_hermitian_indefinite(m)); |
| // Zero-diagonal Hermitian -> forces 2x2 pivots throughout (needs n >= 2 to stay non-singular). |
| if (m.rows() >= 2) { |
| MatrixType A = make_hermitian_indefinite(m); |
| A.diagonal().setZero(); |
| bunchkaufman_solve_and_reconstruct(A); |
| } |
| } |
| |
| // Extreme-scale 2x2 pivot: an off-diagonal-only Hermitian 2x2 forces a single 2x2 pivot whose |
| // determinant is det = -|off|^2. The scaled (det-free) 2x2 formulas must stay finite and correct when |
| // |off| is huge or tiny. Regression for forming det = d11*d22 - |d21|^2 directly, which overflows to |
| // +-inf for off=1e200 (solve then returns 0, residual 1) and underflows to 0 for off=1e-200 (solve |
| // returns NaN/inf), and which also misclassifies the inertia. Requires a type that can hold 1e+-200, |
| // so this is exercised for double / complex<double> only. |
| template <typename Scalar> |
| void bunchkaufman_extreme_scale() { |
| typedef typename NumTraits<Scalar>::Real RealScalar; |
| typedef Matrix<Scalar, 2, 2> Mat2; |
| typedef Matrix<Scalar, 2, 1> Vec2; |
| const RealScalar tol = sqrt(test_precision<RealScalar>()); |
| for (RealScalar mag : {pow(RealScalar(10), RealScalar(200)), pow(RealScalar(10), RealScalar(-200))}) { |
| const Scalar off = Scalar(mag); |
| Mat2 A; |
| A << Scalar(0), numext::conj(off), off, Scalar(0); |
| BunchKaufman<Mat2> bk(A); |
| VERIFY(bk.info() == Success); |
| VERIFY(!bk.isPositive()); // det < 0 => one positive and one negative eigenvalue |
| VERIFY(!bk.isNegative()); |
| // Use the max-abs (infinity) relative norm throughout: the Frobenius norm (.norm()) squares the |
| // ~1e200 entries and would overflow/underflow even for a correct factorization. |
| VERIFY((A - bk.reconstructedMatrix()).cwiseAbs().maxCoeff() <= tol * A.cwiseAbs().maxCoeff()); |
| // A x = b with b = [1,1]; the product A*x stays O(1), so its residual is safe to measure. |
| const Vec2 b(Scalar(1), Scalar(1)); |
| const Vec2 x = bk.solve(b); |
| VERIFY((A * x - b).cwiseAbs().maxCoeff() <= tol); |
| } |
| } |
| |
| // Extreme-scale factorization at the matrix level: a zero-diagonal Hermitian matrix (2x2 pivots |
| // throughout, exercising both the unblocked and -- for n > blocksize -- the blocked trailing update) |
| // scaled to an extreme magnitude. The factorization is scale-equivariant and must remain overflow-free; |
| // the solve must stay backward stable. double / complex<double> only (1e+-175 overflows float). |
| template <typename Scalar> |
| void bunchkaufman_extreme_scale_large(Index n) { |
| typedef typename NumTraits<Scalar>::Real RealScalar; |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| typedef Matrix<Scalar, Dynamic, 1> VectorType; |
| const RealScalar tol = sqrt(test_precision<RealScalar>()); |
| MatrixType M = MatrixType::Random(n, n); |
| MatrixType A = M + M.adjoint(); |
| A.diagonal().setZero(); |
| // 1e+-175 is past the squaring threshold (|entry|^2 over/underflows double), so the pre-fix code |
| // (which forms det = d11*d22 - |d21|^2) produces NaN/Inf here, while the scaled formulas stay exact. |
| for (RealScalar sigma : {pow(RealScalar(10), RealScalar(175)), pow(RealScalar(10), RealScalar(-175))}) { |
| const MatrixType As = A * Scalar(sigma); |
| BunchKaufman<MatrixType, Lower> bk(As); |
| VERIFY(bk.info() == Success); |
| // Max-abs relative reconstruction error (avoid .norm(), whose squaring overflows the ~1e175 entries). |
| VERIFY((As - bk.reconstructedMatrix()).cwiseAbs().maxCoeff() <= tol * As.cwiseAbs().maxCoeff()); |
| // As*x stays O(1) for a unit-scale rhs, so its residual norm is safe to form. |
| const VectorType b = VectorType::Random(n); |
| const VectorType x = bk.solve(b); |
| VERIFY((As * x - b).norm() <= tol * b.norm()); |
| } |
| } |
| |
| // Regression: the size constructor must pre-allocate the panel workspace so that a subsequent compute() |
| // on a problem of that size performs no heap allocation. n is chosen above the panel width so the |
| // blocked path (the one that uses the workspace) runs. (Uses the default stack-allocation limit so the |
| // trailing-update GEMM's small blocking buffers stay on the stack rather than the heap.) |
| template <typename Scalar> |
| void bunchkaufman_no_malloc() { |
| typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType; |
| const Index n = internal::bunch_kaufman_blocksize<Scalar>() + 36; |
| const MatrixType M = MatrixType::Random(n, n); |
| const MatrixType A = M + M.adjoint(); |
| BunchKaufman<MatrixType> bk(n); // pre-allocates m_matrix, m_transpositions, m_subdiag, m_workspace |
| internal::set_is_malloc_allowed(false); |
| bk.compute(A); |
| internal::set_is_malloc_allowed(true); |
| VERIFY(bk.info() == Success); |
| } |
| |
| EIGEN_DECLARE_TEST(bunchkaufman) { |
| for (int i = 0; i < g_repeat; i++) { |
| CALL_SUBTEST_1(bunchkaufman(Matrix<double, 1, 1>())); |
| CALL_SUBTEST_2(bunchkaufman(Matrix2d())); |
| CALL_SUBTEST_3(bunchkaufman(Matrix3f())); |
| CALL_SUBTEST_4(bunchkaufman(Matrix4d())); |
| |
| int s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE); |
| CALL_SUBTEST_5(bunchkaufman(MatrixXd(s, s))); |
| TEST_SET_BUT_UNUSED_VARIABLE(s); |
| |
| s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2); |
| CALL_SUBTEST_6(bunchkaufman(MatrixXcd(s, s))); |
| TEST_SET_BUT_UNUSED_VARIABLE(s); |
| |
| s = internal::random<int>(2, EIGEN_TEST_MAX_SIZE); |
| CALL_SUBTEST_5(bunchkaufman_inertia_and_conditioning<MatrixXd>(s)); |
| s = internal::random<int>(2, EIGEN_TEST_MAX_SIZE / 2); |
| CALL_SUBTEST_6(bunchkaufman_inertia_and_conditioning<MatrixXcd>(s)); |
| |
| CALL_SUBTEST_7(bunchkaufman_small_cases<double>()); |
| CALL_SUBTEST_7(bunchkaufman_small_cases<std::complex<double> >()); |
| // Singular matrices in both the unblocked (n=8) and blocked (n=100 > blocksize) regimes. |
| CALL_SUBTEST_5(bunchkaufman_singular<double>(8)); |
| CALL_SUBTEST_5(bunchkaufman_singular<double>(100)); |
| CALL_SUBTEST_6(bunchkaufman_singular<std::complex<double> >(8)); |
| CALL_SUBTEST_6(bunchkaufman_singular<std::complex<double> >(100)); |
| CALL_SUBTEST_5(bunchkaufman_nan<double>()); |
| CALL_SUBTEST_6(bunchkaufman_nan<std::complex<double> >()); |
| CALL_SUBTEST_5(bunchkaufman_rank_deficient<double>()); |
| CALL_SUBTEST_6(bunchkaufman_rank_deficient<std::complex<double> >()); |
| } |
| |
| // Empty-matrix edge case. |
| CALL_SUBTEST_5(bunchkaufman(MatrixXd(0, 0))); |
| |
| // Problem-size constructors. |
| CALL_SUBTEST_8(BunchKaufman<MatrixXf>(10)); |
| CALL_SUBTEST_8(BunchKaufman<MatrixXcd>(10)); |
| |
| // Assertion checks on an uninitialized decomposition. |
| CALL_SUBTEST_3(bunchkaufman_verify_assert<Matrix3f>()); |
| CALL_SUBTEST_5(bunchkaufman_verify_assert<MatrixXd>()); |
| CALL_SUBTEST_6(bunchkaufman_verify_assert<MatrixXcd>()); |
| |
| // Deterministic blocking / panel-boundary tests (outside g_repeat). |
| CALL_SUBTEST_8(bunchkaufman_blocking_boundary<double>()); |
| CALL_SUBTEST_8(bunchkaufman_blocking_boundary<float>()); |
| CALL_SUBTEST_8(bunchkaufman_blocking_boundary<std::complex<double> >()); |
| |
| // Extreme-scale 2x2 pivots: the scaled (det-free) 2x2 formulas must not over/underflow. |
| CALL_SUBTEST_7(bunchkaufman_extreme_scale<double>()); |
| CALL_SUBTEST_7(bunchkaufman_extreme_scale<std::complex<double> >()); |
| CALL_SUBTEST_5(bunchkaufman_extreme_scale_large<double>(8)); |
| CALL_SUBTEST_5(bunchkaufman_extreme_scale_large<double>(100)); |
| CALL_SUBTEST_6(bunchkaufman_extreme_scale_large<std::complex<double> >(8)); |
| CALL_SUBTEST_6(bunchkaufman_extreme_scale_large<std::complex<double> >(100)); |
| |
| // No-malloc regression: the size constructor pre-allocates the panel workspace. |
| CALL_SUBTEST_8(bunchkaufman_no_malloc<double>()); |
| CALL_SUBTEST_8(bunchkaufman_no_malloc<std::complex<double> >()); |
| } |