mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
81 lines
3.2 KiB
C++
81 lines
3.2 KiB
C++
// This file is part of Eigen, a lightweight C++ template library
|
|
// for linear algebra.
|
|
//
|
|
// Copyright (C) 2009-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
|
|
//
|
|
// 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/.
|
|
|
|
#include "main.h"
|
|
#include <unsupported/Eigen/MatrixFunctions>
|
|
|
|
// For complex matrices, any matrix is fine.
|
|
template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
|
struct processTriangularMatrix {
|
|
static void run(MatrixType&, MatrixType&, const MatrixType&) {}
|
|
};
|
|
|
|
// For real matrices, ensure all eigenvalues have positive real parts
|
|
// (needed for matrix log) and cap the condition number.
|
|
template <typename MatrixType>
|
|
struct processTriangularMatrix<MatrixType, 0> {
|
|
typedef typename MatrixType::Scalar Scalar;
|
|
static void run(MatrixType& m, MatrixType& T, const MatrixType& U) {
|
|
using std::abs;
|
|
const Index size = m.cols();
|
|
Scalar maxDiag(0);
|
|
|
|
for (Index i = 0; i < size; ++i) {
|
|
if (i == size - 1 || numext::is_exactly_zero(T.coeff(i + 1, i))) {
|
|
// 1x1 block (real eigenvalue): make positive.
|
|
T.coeffRef(i, i) = abs(T.coeff(i, i));
|
|
} else {
|
|
// 2x2 block (complex conjugate pair): eigenvalues are T(i,i) ± bi.
|
|
// Negate the block if the real part is negative so that the matrix
|
|
// log is well-defined (avoids the branch cut on the negative real axis).
|
|
if (T.coeff(i, i) < Scalar(0)) {
|
|
T.coeffRef(i, i) = -T.coeff(i, i);
|
|
T.coeffRef(i + 1, i + 1) = -T.coeff(i + 1, i + 1);
|
|
T.coeffRef(i, i + 1) = -T.coeff(i, i + 1);
|
|
T.coeffRef(i + 1, i) = -T.coeff(i + 1, i);
|
|
}
|
|
++i;
|
|
}
|
|
maxDiag = (std::max)(maxDiag, abs(T.coeff(i, i)));
|
|
}
|
|
// Clamp small eigenvalues to limit condition number. Matrix power and
|
|
// matrix function tests lose too many digits on ill-conditioned matrices.
|
|
if (maxDiag > Scalar(0)) {
|
|
Scalar minAllowed = maxDiag / Scalar(100);
|
|
for (Index i = 0; i < size; ++i) {
|
|
if (abs(T.coeff(i, i)) < minAllowed) T.coeffRef(i, i) = minAllowed;
|
|
}
|
|
}
|
|
m = U * T * U.transpose();
|
|
}
|
|
};
|
|
|
|
template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
|
struct generateTestMatrix;
|
|
|
|
template <typename MatrixType>
|
|
struct generateTestMatrix<MatrixType, 0> {
|
|
static void run(MatrixType& result, typename MatrixType::Index size) {
|
|
result = MatrixType::Random(size, size);
|
|
RealSchur<MatrixType> schur(result);
|
|
MatrixType T = schur.matrixT();
|
|
processTriangularMatrix<MatrixType>::run(result, T, schur.matrixU());
|
|
}
|
|
};
|
|
|
|
template <typename MatrixType>
|
|
struct generateTestMatrix<MatrixType, 1> {
|
|
static void run(MatrixType& result, typename MatrixType::Index size) { result = MatrixType::Random(size, size); }
|
|
};
|
|
|
|
template <typename Derived, typename OtherDerived>
|
|
typename Derived::RealScalar relerr(const MatrixBase<Derived>& A, const MatrixBase<OtherDerived>& B) {
|
|
return std::sqrt((A - B).cwiseAbs2().sum() / (std::min)(A.cwiseAbs2().sum(), B.cwiseAbs2().sum()));
|
|
}
|