blob: 144937d7bd93dec7c3a8971ea40f208775266474 [file]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// 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 <Eigen/LU>
#include <Eigen/Cholesky>
#include <Eigen/QR>
#include <Eigen/Eigenvalues>
// This file test inplace decomposition through Ref<>, as supported by the Cholesky, LU, and QR decompositions, the
// Hessenberg, tridiagonal, Schur and QZ reductions, and the dense eigensolvers.
template <typename DecType, typename MatrixType>
void inplace(bool square = false, bool SPD = false) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RhsType;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ResType;
Index rows = MatrixType::RowsAtCompileTime == Dynamic ? internal::random<Index>(2, EIGEN_TEST_MAX_SIZE / 2)
: Index(MatrixType::RowsAtCompileTime);
Index cols = MatrixType::ColsAtCompileTime == Dynamic ? (square ? rows : internal::random<Index>(2, rows))
: Index(MatrixType::ColsAtCompileTime);
MatrixType A = MatrixType::Random(rows, cols);
RhsType b = RhsType::Random(rows);
ResType x(cols);
if (SPD) {
assert(square);
A.topRows(cols) = A.topRows(cols).adjoint() * A.topRows(cols);
A.diagonal().array() += 1e-3;
}
MatrixType A0 = A;
MatrixType A1 = A;
DecType dec(A);
// Check that the content of A has been modified
VERIFY_IS_NOT_APPROX(A, A0);
// Check that the decomposition is correct:
if (rows == cols) {
VERIFY_IS_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
// Check that modifying A breaks the current dec:
A.setRandom();
if (rows == cols) {
VERIFY_IS_NOT_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_NOT_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
// Check that calling compute(A1) does not modify A1:
A = A0;
dec.compute(A1);
VERIFY_IS_EQUAL(A0, A1);
VERIFY_IS_NOT_APPROX(A, A0);
if (rows == cols) {
VERIFY_IS_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
}
template <typename MatrixType>
void inplace_fullpivlu_subspaces() {
using RealScalar = typename MatrixType::RealScalar;
MatrixType input(3, 3);
input << 1, 0, 1, 0, 1, 1, 0, 0, 0;
MatrixType working = input;
FullPivLU<Ref<MatrixType>> lu(working);
Ref<MatrixType> original(input);
const auto kernel = lu.kernel().eval();
const auto image = lu.image(original).eval();
STATIC_CHECK((int(decltype(kernel)::IsRowMajor) == int(MatrixType::IsRowMajor)));
STATIC_CHECK((int(decltype(image)::IsRowMajor) == int(MatrixType::IsRowMajor)));
VERIFY_IS_EQUAL(kernel.cols(), 1);
VERIFY_IS_EQUAL(image.cols(), 2);
const RealScalar tolerance = RealScalar(128 * input.rows()) * NumTraits<RealScalar>::epsilon();
VERIFY((input * kernel).norm() <= tolerance * input.norm() * kernel.norm());
VERIFY_IS_EQUAL(kernel.fullPivLu().rank(), kernel.cols());
VERIFY_IS_EQUAL(image.fullPivLu().rank(), image.cols());
VERIFY((image * image.fullPivLu().solve(input) - input).norm() <= tolerance * input.norm());
}
template <typename MatrixType>
MatrixType random_selfadjoint(Index n) {
MatrixType a = MatrixType::Random(n, n);
return a + a.adjoint();
}
template <typename MatrixType, typename BasisType, typename FormType>
void verify_inplace_similarity(const MatrixType& input, const BasisType& basis, const FormType& form) {
using RealScalar = typename MatrixType::RealScalar;
const RealScalar tolerance = RealScalar(128 * input.rows()) * NumTraits<RealScalar>::epsilon();
VERIFY((input - basis * form * basis.adjoint()).norm() <= tolerance * input.norm());
VERIFY(basis.isUnitary(tolerance));
}
template <typename MatrixType, typename QZType>
void verify_inplace_qz(const MatrixType& a, const MatrixType& b, const QZType& qz) {
using RealScalar = typename MatrixType::RealScalar;
const RealScalar tolerance = RealScalar(128 * a.rows()) * NumTraits<RealScalar>::epsilon();
VERIFY_IS_EQUAL(qz.info(), Success);
VERIFY((a - qz.matrixQ() * qz.matrixS() * qz.matrixZ()).norm() <= tolerance * a.norm());
VERIFY((b - qz.matrixQ() * qz.matrixT() * qz.matrixZ()).norm() <= tolerance * b.norm());
VERIFY(qz.matrixQ().isUnitary(tolerance));
VERIFY(qz.matrixZ().isUnitary(tolerance));
}
template <typename MatrixType>
void inplace_reductions(Index size) {
using Scalar = typename MatrixType::Scalar;
{
MatrixType A = MatrixType::Random(size, size), A0 = A;
HessenbergDecomposition<Ref<MatrixType>> hess(A);
VERIFY(internal::is_same_dense(hess.packedMatrix(), A));
MatrixType Q = hess.matrixQ(), H = hess.matrixH();
verify_inplace_similarity(A0, Q, H);
MatrixType twiceH = Scalar(2) * hess.matrixH();
VERIFY_IS_EQUAL(twiceH, Scalar(2) * H);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): Snapshot verifies compute() preserves its input.
MatrixType A1 = MatrixType::Random(size, size), A1c = A1;
hess.compute(A1);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY(internal::is_same_dense(hess.packedMatrix(), A));
Q = hess.matrixQ();
H = hess.matrixH();
verify_inplace_similarity(A1, Q, H);
}
{
MatrixType A = random_selfadjoint<MatrixType>(size), A0 = A;
Tridiagonalization<Ref<MatrixType>> tri(A);
VERIFY(internal::is_same_dense(tri.packedMatrix(), A));
MatrixType Q = tri.matrixQ(), T = tri.matrixT().eval().template cast<Scalar>();
verify_inplace_similarity(A0, Q, T);
}
}
template <typename MatrixType, template <typename> class SchurType>
void inplace_schur(Index size) {
using RealScalar = typename MatrixType::RealScalar;
const RealScalar tolerance = RealScalar(128 * size) * NumTraits<RealScalar>::epsilon();
MatrixType A = MatrixType::Random(size, size), A0 = A;
SchurType<Ref<MatrixType>> schur(A);
VERIFY_IS_EQUAL(schur.info(), Success);
VERIFY(internal::is_same_dense(schur.matrixT(), A));
verify_inplace_similarity(A0, schur.matrixU(), schur.matrixT());
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): Snapshot verifies compute() preserves its input.
MatrixType A1 = MatrixType::Random(size, size), A1c = A1;
schur.compute(A1);
VERIFY_IS_EQUAL(schur.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY(internal::is_same_dense(schur.matrixT(), A));
verify_inplace_similarity(A1, schur.matrixU(), schur.matrixT());
MatrixType T = schur.matrixT();
schur.compute(A1, false);
VERIFY_IS_EQUAL(schur.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY((schur.matrixT() - T).norm() <= tolerance * A1.norm());
}
template <typename MatrixType>
void inplace_selfadjoint_eigensolver(Index size) {
using Scalar = typename MatrixType::Scalar;
using RealScalar = typename MatrixType::RealScalar;
const RealScalar tolerance = RealScalar(128 * size) * NumTraits<RealScalar>::epsilon();
MatrixType A = random_selfadjoint<MatrixType>(size), A0 = A;
A.template triangularView<StrictlyUpper>().setConstant(Scalar(std::numeric_limits<RealScalar>::quiet_NaN()));
SelfAdjointEigenSolver<Ref<MatrixType>> es(A);
VERIFY_IS_EQUAL(es.info(), Success);
VERIFY(internal::is_same_dense(es.eigenvectors(), A));
VERIFY((A0 * A - A * es.eigenvalues().asDiagonal()).norm() <= tolerance * A0.norm());
VERIFY(A.isUnitary(tolerance));
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): Snapshot verifies compute() preserves its input.
MatrixType A1 = random_selfadjoint<MatrixType>(size), A1c = A1;
es.compute(A1, EigenvaluesOnly);
VERIFY_IS_EQUAL(es.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
const auto values = es.eigenvalues().eval();
es.compute(A1);
VERIFY_IS_EQUAL(es.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY(internal::is_same_dense(es.eigenvectors(), A));
VERIFY((es.eigenvalues() - values).norm() <= tolerance * A1.norm());
VERIFY((A1 * A - A * es.eigenvalues().asDiagonal()).norm() <= tolerance * A1.norm());
VERIFY(A.isUnitary(tolerance));
if (MatrixType::RowsAtCompileTime == Dynamic) {
MatrixType big = MatrixType::Random(size + 3, size + 2);
Ref<MatrixType> B = big.block(2, 1, size, size);
B = random_selfadjoint<MatrixType>(size);
MatrixType Bin = B;
SelfAdjointEigenSolver<Ref<MatrixType>> esb(B);
VERIFY_IS_EQUAL(esb.info(), Success);
VERIFY(internal::is_same_dense(esb.eigenvectors(), B));
VERIFY((Bin * B - B * esb.eigenvalues().asDiagonal()).norm() <= tolerance * Bin.norm());
VERIFY(B.isUnitary(tolerance));
}
MatrixType Ag = random_selfadjoint<MatrixType>(size);
MatrixType Bg = MatrixType::Random(size, size);
Bg = Bg * Bg.adjoint() + RealScalar(size) * MatrixType::Identity(size, size);
for (int type : {int(Ax_lBx), int(ABx_lx), int(BAx_lx)}) {
MatrixType A2 = Ag, B2 = Bg;
GeneralizedSelfAdjointEigenSolver<Ref<MatrixType>> ges(A2, B2, ComputeEigenvectors | type);
VERIFY_IS_EQUAL(ges.info(), Success);
VERIFY(internal::is_same_dense(ges.eigenvectors(), A2));
const MatrixType& V = ges.eigenvectors();
MatrixType VD = V * ges.eigenvalues().asDiagonal();
if (type == Ax_lBx) {
VERIFY((Ag * V - Bg * VD).norm() <= tolerance * (Ag.norm() * V.norm() + Bg.norm() * VD.norm()));
} else if (type == ABx_lx) {
VERIFY((Ag * (Bg * V) - VD).norm() <= tolerance * (Ag.norm() * Bg.norm() * V.norm() + VD.norm()));
} else {
VERIFY((Bg * (Ag * V) - VD).norm() <= tolerance * (Ag.norm() * Bg.norm() * V.norm() + VD.norm()));
}
MatrixType metric;
if (type == BAx_lx) {
metric = V.adjoint() * Bg.llt().solve(V);
} else {
metric = V.adjoint() * Bg * V;
}
VERIFY((metric - MatrixType::Identity(size, size)).norm() <= tolerance * RealScalar(size));
MatrixType A3 = Ag, B3 = Bg;
GeneralizedSelfAdjointEigenSolver<Ref<MatrixType>> gesv(A3, B3, EigenvaluesOnly | type);
VERIFY_IS_EQUAL(gesv.info(), Success);
VERIFY((gesv.eigenvalues() - ges.eigenvalues()).norm() <= tolerance * ges.eigenvalues().norm());
}
}
template <typename MatrixType>
void inplace_special_values(Index size) {
using RealScalar = typename MatrixType::RealScalar;
for (Index kind = 0; kind <= 2 * size; ++kind) {
MatrixType A0 = MatrixType::Zero(size, size);
if (kind > 0) {
const Index index = (kind - 1) % size;
A0(index, index) =
kind <= size ? std::numeric_limits<RealScalar>::quiet_NaN() : std::numeric_limits<RealScalar>::infinity();
}
MatrixType A = A0;
RealSchur<Ref<MatrixType>> schur(A);
RealSchur<MatrixType> schur0(A0);
VERIFY_IS_EQUAL(schur.info(), schur0.info());
VERIFY_IS_EQUAL(schur.info(), kind == 0 ? Success : NoConvergence);
if (schur.info() == Success && kind == 0) verify_inplace_similarity(A0, schur.matrixU(), schur.matrixT());
MatrixType B = A0;
SelfAdjointEigenSolver<Ref<MatrixType>> saes(B);
SelfAdjointEigenSolver<MatrixType> saes0(A0);
VERIFY_IS_EQUAL(saes.info(), saes0.info());
VERIFY_IS_EQUAL(saes.info(), kind == 0 ? Success : NoConvergence);
if (saes.info() == Success && kind == 0) {
VERIFY_IS_EQUAL(saes.eigenvalues(), saes0.eigenvalues());
VERIFY(saes.eigenvectors().isUnitary(RealScalar(128 * size) * NumTraits<RealScalar>::epsilon()));
}
MatrixType C = A0;
EigenSolver<Ref<MatrixType>> es(C);
EigenSolver<MatrixType> es0(A0);
VERIFY_IS_EQUAL(es.info(), es0.info());
VERIFY_IS_EQUAL(es.info(), kind == 0 ? Success : NumericalIssue);
if (es.info() == Success && kind == 0) {
VERIFY_IS_EQUAL(es.eigenvalues(), es0.eigenvalues());
VERIFY((es.eigenvectors().colwise().norm().array() > RealScalar(0)).all());
}
}
}
template <typename MatrixType, template <typename> class SolverType>
void inplace_eigensolver(Index size) {
using RealScalar = typename MatrixType::RealScalar;
using ComplexScalar = std::complex<RealScalar>;
using ComplexMatrix = typename EigenSolver<MatrixType>::EigenvectorsType;
const RealScalar tolerance = RealScalar(128 * size) * NumTraits<RealScalar>::epsilon();
MatrixType A = MatrixType::Random(size, size), A0 = A;
SolverType<Ref<MatrixType>> es(A);
VERIFY_IS_EQUAL(es.info(), Success);
ComplexMatrix V = es.eigenvectors();
VERIFY((A0.template cast<ComplexScalar>() * V - V * es.eigenvalues().asDiagonal()).norm() <=
tolerance * A0.norm() * V.norm());
VERIFY((V.colwise().norm().array() - RealScalar(1)).abs().maxCoeff() <= tolerance);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): Snapshot verifies compute() preserves its input.
MatrixType A1 = MatrixType::Random(size, size), A1c = A1;
es.compute(A1);
VERIFY_IS_EQUAL(es.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
V = es.eigenvectors();
VERIFY((A1.template cast<ComplexScalar>() * V - V * es.eigenvalues().asDiagonal()).norm() <=
tolerance * A1.norm() * V.norm());
const auto values = es.eigenvalues().eval();
es.compute(A1, false);
VERIFY_IS_EQUAL(es.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY((es.eigenvalues() - values).norm() <= tolerance * A1.norm());
}
template <typename MatrixType, template <typename> class QZType>
void inplace_qz(Index size) {
MatrixType A = MatrixType::Random(size, size), B = MatrixType::Random(size, size), A0 = A, Bin = B;
QZType<Ref<MatrixType>> qz(A, B);
VERIFY(internal::is_same_dense(qz.matrixS(), A));
VERIFY(internal::is_same_dense(qz.matrixT(), B));
verify_inplace_qz(A0, Bin, qz);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): Snapshots verify compute() preserves both inputs.
MatrixType A1 = MatrixType::Random(size, size), B1 = MatrixType::Random(size, size), A1c = A1, B1c = B1;
qz.compute(A1, B1);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY_IS_EQUAL(B1, B1c);
VERIFY(internal::is_same_dense(qz.matrixS(), A));
VERIFY(internal::is_same_dense(qz.matrixT(), B));
verify_inplace_qz(A1, B1, qz);
const MatrixType S = qz.matrixS(), T = qz.matrixT();
qz.compute(A1, B1, false);
VERIFY_IS_EQUAL(qz.info(), Success);
VERIFY_IS_EQUAL(A1, A1c);
VERIFY_IS_EQUAL(B1, B1c);
using RealScalar = typename MatrixType::RealScalar;
const RealScalar tolerance = RealScalar(128 * size) * NumTraits<RealScalar>::epsilon();
VERIFY((qz.matrixS() - S).norm() <= tolerance * A1.norm());
VERIFY((qz.matrixT() - T).norm() <= tolerance * B1.norm());
}
template <typename MatrixType>
void inplace_generalized_eigensolver(Index size) {
using RealScalar = typename MatrixType::RealScalar;
using ComplexScalar = std::complex<RealScalar>;
using EigenvectorsType = typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType;
MatrixType A = MatrixType::Random(size, size), B = MatrixType::Random(size, size), A0 = A, Binput = B;
GeneralizedEigenSolver<Ref<MatrixType>> ges(A, B);
VERIFY_IS_EQUAL(ges.info(), Success);
EigenvectorsType V = ges.eigenvectors();
const EigenvectorsType lhs =
A0.template cast<ComplexScalar>() * V * ges.betas().template cast<ComplexScalar>().asDiagonal();
const EigenvectorsType rhs = Binput.template cast<ComplexScalar>() * V * ges.alphas().asDiagonal();
const RealScalar tolerance = RealScalar(128 * size) * NumTraits<RealScalar>::epsilon();
VERIFY((lhs - rhs).norm() <= tolerance * (lhs.norm() + rhs.norm()));
VERIFY((V.colwise().norm().array() - RealScalar(1)).abs().maxCoeff() <= tolerance);
}
template <typename Scalar, template <typename> class QZType, int Options>
void inplace_qz_inner_stride() {
using MatrixType = Matrix<Scalar, Dynamic, Dynamic, Options>;
using StridedRef = Ref<MatrixType, 0, Stride<Dynamic, Dynamic>>;
for (Index inner : {Index(1), Index(2)}) {
MatrixType storageA = MatrixType::Random(8, 5), storageB = MatrixType::Random(8, 5);
const Stride<Dynamic, Dynamic> stride(8, inner);
Map<MatrixType, 0, Stride<Dynamic, Dynamic>> a(storageA.data(), 4, 4, stride), b(storageB.data(), 4, 4, stride);
const MatrixType A0 = a, Binput = b;
const MatrixType savedA = storageA, savedB = storageB;
StridedRef ar(a), br(b);
QZType<StridedRef> qz(ar, br);
VERIFY(internal::is_same_dense(qz.matrixS(), a));
VERIFY(internal::is_same_dense(qz.matrixT(), b));
verify_inplace_qz(A0, Binput, qz);
// The Map's strides determine its footprint in either storage order.
for (Index offset = 0; offset < storageA.size(); ++offset) {
const Index outer = offset / stride.outer();
const Index innerOffset = offset % stride.outer();
if (outer < 4 && innerOffset % inner == 0 && innerOffset / inner < 4) continue;
VERIFY_IS_EQUAL(storageA.data()[offset], savedA.data()[offset]);
VERIFY_IS_EQUAL(storageB.data()[offset], savedB.data()[offset]);
}
}
}
struct InplaceLowerOnly {
double operator()(Index row, Index col) const {
VERIFY(row >= col);
return row == col ? 4.0 : 1.0;
}
};
template <typename = void>
void inplace_plain_lower_triangle() {
auto input = MatrixXd::NullaryExpr(3, 3, InplaceLowerOnly());
SelfAdjointEigenSolver<MatrixXd> mutableSolver(input);
const auto constInput = input;
SelfAdjointEigenSolver<MatrixXd> constSolver(constInput);
VERIFY_IS_EQUAL(mutableSolver.info(), Success);
VERIFY_IS_EQUAL(mutableSolver.eigenvalues(), constSolver.eigenvalues());
}
EIGEN_DECLARE_TEST(inplace_decomposition) {
CALL_SUBTEST_4((inplace_fullpivlu_subspaces<Matrix<double, Dynamic, Dynamic, ColMajor>>()));
CALL_SUBTEST_4((inplace_fullpivlu_subspaces<Matrix<double, Dynamic, Dynamic, RowMajor>>()));
CALL_SUBTEST_4((inplace_fullpivlu_subspaces<Matrix<double, 3, 3, RowMajor | DontAlign>>()));
CALL_SUBTEST_10((inplace_special_values<MatrixXd>(2)));
CALL_SUBTEST_10((inplace_special_values<MatrixXd>(1)));
CALL_SUBTEST_11(inplace_plain_lower_triangle<>());
CALL_SUBTEST_12((inplace_eigensolver<MatrixXd, EigenSolver>(128)));
CALL_SUBTEST_12((inplace_eigensolver<MatrixXd, EigenSolver>(129)));
CALL_SUBTEST_14((inplace_qz_inner_stride<double, RealQZ, ColMajor>()));
CALL_SUBTEST_14((inplace_qz_inner_stride<double, RealQZ, RowMajor>()));
CALL_SUBTEST_14((inplace_qz_inner_stride<std::complex<double>, ComplexQZ, ColMajor>()));
CALL_SUBTEST_14((inplace_qz_inner_stride<std::complex<double>, ComplexQZ, RowMajor>()));
EIGEN_UNUSED typedef Matrix<double, 4, 3> Matrix43d;
for (int i = 0; i < g_repeat; i++) {
EIGEN_UNUSED const Index size = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_1((inplace<LLT<Ref<MatrixXd> >, MatrixXd>(true, true)));
CALL_SUBTEST_1((inplace<LLT<Ref<Matrix4d> >, Matrix4d>(true, true)));
CALL_SUBTEST_2((inplace<LDLT<Ref<MatrixXd> >, MatrixXd>(true, true)));
CALL_SUBTEST_2((inplace<LDLT<Ref<Matrix4d> >, Matrix4d>(true, true)));
CALL_SUBTEST_3((inplace<PartialPivLU<Ref<MatrixXd> >, MatrixXd>(true, false)));
CALL_SUBTEST_3((inplace<PartialPivLU<Ref<Matrix4d> >, Matrix4d>(true, false)));
CALL_SUBTEST_4((inplace<FullPivLU<Ref<MatrixXd> >, MatrixXd>(true, false)));
CALL_SUBTEST_4((inplace<FullPivLU<Ref<Matrix4d> >, Matrix4d>(true, false)));
CALL_SUBTEST_5((inplace<HouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_5((inplace<HouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_6((inplace<ColPivHouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_6((inplace<ColPivHouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_7((inplace<FullPivHouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_7((inplace<FullPivHouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_8((inplace<CompleteOrthogonalDecomposition<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_8((inplace<CompleteOrthogonalDecomposition<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_2((inplace<BunchKaufman<Ref<MatrixXd>>, MatrixXd>(true, true)));
CALL_SUBTEST_2((inplace<BunchKaufman<Ref<Matrix4d>>, Matrix4d>(true, true)));
CALL_SUBTEST_9((inplace_reductions<MatrixXd>(size)));
CALL_SUBTEST_9((inplace_reductions<MatrixXcd>(size)));
CALL_SUBTEST_9((inplace_reductions<MatrixXd>(1)));
CALL_SUBTEST_9((inplace_reductions<Matrix4f>(4)));
CALL_SUBTEST_10((inplace_schur<MatrixXd, RealSchur>(size)));
CALL_SUBTEST_10((inplace_schur<MatrixXd, RealSchur>(1)));
CALL_SUBTEST_10((inplace_schur<Matrix4f, RealSchur>(4)));
CALL_SUBTEST_10((inplace_schur<MatrixXcd, ComplexSchur>(size)));
CALL_SUBTEST_10((inplace_schur<MatrixXcd, ComplexSchur>(1)));
CALL_SUBTEST_10((inplace_schur<Matrix4cf, ComplexSchur>(4)));
CALL_SUBTEST_10((inplace_special_values<MatrixXd>(size)));
CALL_SUBTEST_10((inplace_special_values<Matrix4f>(4)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<MatrixXd>(size)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<MatrixXcd>(size)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<MatrixXd>(1)));
// Fixed sizes whose columns are packet-aligned take the vectorized rotation kernel.
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix2d>(2)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix3d>(3)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix4f>(4)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix4d>(4)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix<float, Dynamic, Dynamic, RowMajor>>(size)));
// Large enough for the blocked tridiagonalization, on strided and row-major storage.
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<MatrixXd>(100)));
CALL_SUBTEST_11((inplace_selfadjoint_eigensolver<Matrix<float, Dynamic, Dynamic, RowMajor>>(100)));
CALL_SUBTEST_12((inplace_eigensolver<MatrixXd, EigenSolver>(size)));
CALL_SUBTEST_12((inplace_eigensolver<MatrixXd, EigenSolver>(1)));
CALL_SUBTEST_12((inplace_eigensolver<Matrix4f, EigenSolver>(4)));
CALL_SUBTEST_12((inplace_eigensolver<MatrixXcd, ComplexEigenSolver>(size)));
CALL_SUBTEST_12((inplace_eigensolver<MatrixXcd, ComplexEigenSolver>(1)));
CALL_SUBTEST_12((inplace_eigensolver<Matrix4cf, ComplexEigenSolver>(4)));
CALL_SUBTEST_13((inplace_qz<MatrixXd, RealQZ>(size)));
CALL_SUBTEST_13((inplace_generalized_eigensolver<MatrixXd>(size)));
CALL_SUBTEST_13((inplace_generalized_eigensolver<Matrix4d>(4)));
CALL_SUBTEST_13((inplace_qz<MatrixXd, RealQZ>(1)));
CALL_SUBTEST_13((inplace_qz<Matrix4d, RealQZ>(4)));
CALL_SUBTEST_13((inplace_qz<MatrixXcd, ComplexQZ>(size)));
CALL_SUBTEST_13((inplace_qz<MatrixXcd, ComplexQZ>(1)));
}
}