Re: [eigen] Eigenvalues of (lower) Hessenberg matrix |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: Re: [eigen] Eigenvalues of (lower) Hessenberg matrix
- From: Yixuan Qiu <yixuanq@xxxxxxxxx>
- Date: Tue, 4 Apr 2017 16:47:45 -0400
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cos-name.20150623.gappssmtp.com; s=20150623; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to; bh=uEXnpduzTlzvAm/KU9Vwgr39ttfjB7Y3ITzAUyadWpg=; b=BMAiIaUEEnP0tNkO+1BidkLJySvgphddPSYihjFxS8zTqLYX2yNxb25CfCDqhq4+Zr 78P4oaIsapZVuaf1Xis32smV6wKf9zaCm8b/U6w9xV8A86IYlj8vkDNgWRi/0Y7wAjMw a03ICosjkMi4Oh9VCn/V2eQolN8zxvXwDJvQ3pjbn4fkMd4miQASlwrJv6VQOT9bwAnn H9YWar/4tllTZ9clZxF3WMbP7NhmyEwSuU/4BOaIayErjjwHYd4bh6lQVApK2bRFSyEP DqK20Lw58WMFGBZq15VwXxxfpR+BJ8LcgKUnwKf+iVnJSixMNFgJ0sWtx5NCYlnrLtR7 0alw==
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to; bh=uEXnpduzTlzvAm/KU9Vwgr39ttfjB7Y3ITzAUyadWpg=; b=vIeFfm5SvYrF7XRvh1TJCfoik4XMMWkBBfqPz+hr61wAfp4p9bkWmU7Z/ASbT7aTKo 2cir+H6ag6O8/5qHrxUX6LiEi0oJVQSSq+PPLXMEPowDerORWNzzZRodDF4fEPzYT28x 6DKd9Sw/W4H32PSedazBh8xuCJmAekobvn5OVAxPikZOJqGGDZD9ub8cjiSMSf0iRpKj N53AHnS2IJOAUfxg8G4BzTUZ4alLpcVRUmYTDQe+Sf3cPyESvbn9HrUN5TTOZKVYBGnv ny0lh9KRi2TU8mL5GmAPFXdk2msN4XX0AK1YLllorq1TXS3rAywOxssvPuyFxaGO+vuQ 3+QA==
Hi Ian,
Given that your matrices are at very small scale, I don't expect my class will have visible improvement. Actually you found it to be slower, which I think may be due to several reasons:
1. My class does some basic scaling of matrix before factorization.
2. Did you select "computeEigenvectors = false" in EigenSolver? My class assumes computing eigenvectors, so some calculations are unneeded in your case. You can try the reduced version attached.
3. Did you randomize the order of execution? Did you have enough replications of experiment? Was the difference statistically significant relative to the standard error? Personally I don't fully trust benchmark results measured by elapsed time at the scale of microseconds. I would recommend Callgrind as the profiler for such tasks.
Hope this helps.
Best,
Yixuan
// The code was adapted from Eigen/src/Eigenvaleus/EigenSolver.h
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@xxxxxxxx>
// Copyright (C) 2010,2012 Jitse Niesen <jitse@xxxxxxxxxxxxxxxxx>
// Copyright (C) 2016-2017 Yixuan Qiu <yixuan.qiu@xxxxxxxx>
//
// 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/.
#ifndef UPPER_HESSENBERG_EIGEN_VAL_ONLY_H
#define UPPER_HESSENBERG_EIGEN_VAL_ONLY_H
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <stdexcept>
namespace Spectra {
template <typename Scalar = double>
class UpperHessenbergEigenValOnly
{
private:
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> Matrix;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Vector;
typedef typename Matrix::Index Index;
typedef Eigen::Ref<Matrix> GenericMatrix;
typedef const Eigen::Ref<const Matrix> ConstGenericMatrix;
typedef std::complex<Scalar> Complex;
typedef Eigen::Matrix<Complex, Eigen::Dynamic, Eigen::Dynamic> ComplexMatrix;
typedef Eigen::Matrix<Complex, Eigen::Dynamic, 1> ComplexVector;
Index m_n; // Size of the matrix
Eigen::RealSchur<Matrix> m_realSchur; // Schur decomposition solver
Matrix m_matT; // Schur T matrix
ComplexVector m_eivalues; // Eigenvalues
bool m_computed;
public:
UpperHessenbergEigenValOnly() :
m_n(0), m_computed(false)
{}
UpperHessenbergEigenValOnly(ConstGenericMatrix& mat) :
m_n(mat.rows()), m_computed(false)
{
compute(mat);
}
void compute(ConstGenericMatrix& mat)
{
using std::abs;
using std::sqrt;
if(mat.rows() != mat.cols())
throw std::invalid_argument("UpperHessenbergEigenValOnly: matrix must be square");
m_n = mat.rows();
// Scale matrix prior to the Schur decomposition
const Scalar scale = mat.cwiseAbs().maxCoeff();
// Reduce to real Schur form
Matrix Q = Matrix::Identity(m_n, m_n);
m_realSchur.computeFromHessenberg(mat / scale, Q, false);
if(m_realSchur.info() != Eigen::Success)
throw std::runtime_error("UpperHessenbergEigenValOnly: eigen decomposition failed");
m_matT = m_realSchur.matrixT();
// Compute eigenvalues from matT
m_eivalues.resize(m_n);
Index i = 0;
while(i < m_n)
{
// Real eigenvalue
if(i == m_n - 1 || m_matT.coeff(i+1, i) == Scalar(0))
{
m_eivalues.coeffRef(i) = m_matT.coeff(i, i);
++i;
}
else // Complex eigenvalues
{
Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1));
Scalar z;
// Compute z = sqrt(abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1)));
// without overflow
{
Scalar t0 = m_matT.coeff(i+1, i);
Scalar t1 = m_matT.coeff(i, i+1);
Scalar maxval = std::max(abs(p), std::max(abs(t0), abs(t1)));
t0 /= maxval;
t1 /= maxval;
Scalar p0 = p / maxval;
z = maxval * sqrt(abs(p0 * p0 + t0 * t1));
}
m_eivalues.coeffRef(i) = Complex(m_matT.coeff(i+1, i+1) + p, z);
m_eivalues.coeffRef(i+1) = Complex(m_matT.coeff(i+1, i+1) + p, -z);
i += 2;
}
}
// Scale eigenvalues back
m_eivalues *= scale;
m_computed = true;
}
ComplexVector eigenvalues()
{
if(!m_computed)
throw std::logic_error("UpperHessenbergEigenValOnly: need to call compute() first");
return m_eivalues;
}
};
} // namespace Spectra
#endif // UPPER_HESSENBERG_EIGEN_VAL_ONLY_H