-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Krylov-Schur EigenSolver for (real) non-Hermitian matrices #132
base: master
Are you sure you want to change the base?
Conversation
The targets file links to the Eigen3::Eigen target so we must include here instead of the client side
Applies Krylov Schur algorithm for non-Hermitian matrices. Computes eigenvalues and eigenvectors for the generalized eigen problem.
include/Spectra/LinAlg/KrylovSchur.h
Outdated
Vector m_fac_v; // current v vector (residual) | ||
Scalar m_beta; // ||f||, B-norm of f | ||
|
||
bool robust_reorthogonalize(MapConstMat& Vjj, Vector& f, Scalar& fnorm, const Index jj, const Index seed, Vector& wIn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you add more documentation of what this does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in respect to the reference:
G. W. Stewart; Matrix algorithms. Volume 1, Basic decompositions; 1998; page 287, Algorithm 4.1.13
include/Spectra/LinAlg/KrylovSchur.h
Outdated
for (int reorth = 1; reorth <= 5; reorth++) | ||
{ | ||
// Check orthogonality | ||
Vector VMf(jj + 1); | ||
VMf.noalias() = Vjj.transpose() * f; | ||
fMf = f.norm(); | ||
|
||
Scalar ortho_err = VMf.cwiseAbs().maxCoeff(); | ||
if (abs(fMf - 1) <= 1e-10 && ortho_err <= 1e-10) | ||
{ | ||
stopAlgorithm = false; | ||
break; | ||
} | ||
|
||
// Re-orthogonalize | ||
f.noalias() -= Vjj * VMf; | ||
f.normalize(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you reuse the code from above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in my opinion difficult because of the stopAlgorithm part
using Matrix = Eigen::MatrixXd; | ||
using Vector = Eigen::VectorXd; | ||
using SpMatrix = Eigen::SparseMatrix<double>; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a test for non-symmetric matrices and also one where the cholesky factorisation is not used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really nice contribution. I do not know the algorithm of matlab, just gave some thoughts.
Thanks, really nice.
Thanks for your comments and hints! i will correct and comment the code in the coming days. Thank you. |
@yixuan is the one with the keys. :) |
Thank you David. I'm sorry that I'm a bit busy recently, so it would be nice if you allow me some time reviewing the code. One quick impression is that much of the code is copied from existing classes, so you may consider if there is some better way reusing the code. Thanks. |
- derived KrylovSchurSolverBase from SymEigsBase to reuse existing code - derived KrylovSchur from Arnoldi to reuse existing code - deleted SparseRegularInverseLU - extended SparseRegularInverse to make all solvers in Eigen available to use - KrylovSchur test minimalized to use system matrices out of a regular Finite Element beam model (matrix_A and matrix_B file) - added more documentation
Thank you @yixuan and @JensWehner for the hints so far.
The extension of the SparseRegularInverse class can be very helpful if one wants to use other Eigen sparsematrix solvers. The helper class "Solver" here solves the polymorphism problem with the Eigen library solvers. They are indeed derived from Eigen::SparseSolverBase but the template parameter makes it difficult to implement any polymorphism in the "SparseRegularInverse" class. So i simply declared all available solvers in the helper class. With the enum SparseRegularInverse ::SolverType the solver type can be switched. This method shouldnt make any problems in respect of memory usage compared to the original SparseRegularInverse class. This extension is also fully compatible with existing syntax and examples/tests. The default solver is still the CG solver. Best Regards |
@@ -64,7 +220,7 @@ class SparseRegularInverse | |||
/// `Eigen::Map<Eigen::SparseMatrix<Scalar, ...> >`. | |||
/// | |||
template <typename Derived> | |||
SparseRegularInverse(const Eigen::SparseMatrixBase<Derived>& mat) : | |||
SparseRegularInverse(const Eigen::SparseMatrixBase<Derived>& mat, SolverType type = SolverType::ConjugateGradient) : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this works, instead we could also just have a template argumement which takes any type which provides a solve interface. Sort of like the preconditioners in Eigen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so basically compile time polymorphism vs runtime. @yixuan what do you prefer?
some minor review corrections
CMake: include Eigen targets
uses marketmatrix file import instead of binary sparse matrix import
Hi @dotnotlock, I'm really really interested in this new branch; I was looking exactly for this kind of solvers (probably because we are working on the same topic/applications). Matlab can solve damped FE systems with no issues at all (cannot tell the performance though) while IR-Arnoldi is really really struggling in retrieving consistent results, even using ARPACK directly. I see that you are having problems with Eigen::SparseLU; I had a lot of problems myself and I realized they were caused by AVX2 instruction sets (see projectchrono/chrono#290 and https://gitlab.com/libeigen/eigen/-/issues/2126 for reference). For example, the same issues didn't show up in Debug mode. And I think that the same problem affects also Eigen::SparseQR. |
@yixuan could you enable the CI for this PR? |
compatible with Eigen < 3.4
…nto krylovschur
- SparseRegularInverse::Solver::compute function corrected - KrylovSchur test file path correction
finally passed all workflow checks (dotnotlock#1) |
When everything went good with this PR, i can extend the Krylov-Schur Solver for Hermitian matrices. |
I hope I can finish this soon. Just a quick question: for Hermitian matrices, Krylov-Schur is equivalent to the implicitly restarted Lanczos algorithm, it that correct? Because Schur decomposition on a Hermitian matrix is basically an eigen decomposition. |
Codecov Report
@@ Coverage Diff @@
## master #132 +/- ##
========================================
- Coverage 92.1% 88.9% -3.2%
========================================
Files 45 48 +3
Lines 2140 2436 +296
========================================
+ Hits 1971 2167 +196
- Misses 169 269 +100
Continue to review full report at Codecov.
|
@yixuan Schur vs Eigendecomposition of hermitian matrices, that is also my understanding. |
Yes you are right, the Schur decomposition is not needed for hermitian matrices. Its indeed equal with implicitly restarted Lanczos algorithm |
I just want to leave another comment to say sorry that I'm a bit tied up recently. I put this PR in a high priority, so once I get some free time I will come back here. Thanks for your understanding. |
Dear @dotnotlock et al., I am testing the Krylov Schur solver and it works fine.
where K may be singular too (ex. when I need to extract the six rigid body modes at zero frequency in a free-free structure), so using shift-and-invert with a small sigma shift works perfectly in all cases. What I did is to inherit a specialized Krylov-Schur class, inspired to
then I can use it as:
It works perfectly but the issue here is that the
Are you planning to support the "shift and invert" scheme later in a new push to develop, or did I miss something? |
A second comment: the Krylov-Schur in Matlab works also with non-symmetric matrices, for complex eigenpairs.
Note that I need to solve this with a shift-and-invert, because alternative approaches requiring only the inversion will fail some special cases. Thanks and compliments for the great library. |
@tasora thanks for the comment. Nice to hear that it works well so far.
Thank you :) |
@tasora can you just submit a second PR, so we can have a look? |
Hello,
yes you can send a sample for the systemmatrices. You can send me this also
in Matlab MAT file format, so i can create some input for c++ test file.
Thank you :)
Best Regards
David
|
Today I spent some time reading the whole implementation, and got a quick question to ask: from the title of this PR and our previous discussions it seems that you designed the solver for non-Hermitian matrices. However, looking at the class member functions, I only see real-valued eigenvalues and eigenvectors. Did I miss anything? |
Yes exactly, unfortunatly i had implemented and tested only for real values and RealSchur function. But it should be no problem to expand the algorithm for complex values. |
Oh, I mean, the A and B matrices can be both real-valued, but if A is not symmetric, then the eigenvalues and eigenvectors are supposed to be complex-valued, right? But I only see |
Dear Yixuan Qiu
i am interested in the case of the complex-value
eigenvalues/eigenvectors in fact. My problems involve sparse real-valued
but /not symmetric/ A and B, with shift-and-invert, and that's the case
that I cannot solve efficiently with the current version of Spectra.
I tried to modify the experimental Krylov Schur solver some weeks ago
but I gave up because it took too many hacks from my side and it did not
work as expected, so I preferred to wait until someone from the official
Spectra team can do an "official" implementation of Krylov Schur for
non-symmetric matrices.
I hope that the Krylov Schur solver could support this case because
there are not so many c++ alternatives for doing this...
best regards
Alessandro Tasora
…On 29/03/2022 02:55, Yixuan Qiu wrote:
Oh, I mean, the A and B matrices can be both real-valued, but if A is
not symmetric, then the eigenvalues and eigenvectors are supposed to
be complex-valued, right? But I only see |eigenvalues()| with a return
type of real vector.
—
Reply to this email directly, view it on GitHub
<https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fyixuan%2Fspectra%2Fpull%2F132%23issuecomment-1081291676&data=04%7C01%7Calessandro.tasora%40unipr.it%7C9158009108e54574d61608da111ecf1a%7Cbb064bc5b7a841ecbabed7beb3faeb1c%7C0%7C0%7C637841121279273440%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=ymoTEuSkXFVYs8penvKx98H93x6KiA4GfyyFURWVH8A%3D&reserved=0>,
or unsubscribe
<https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FABHTOBFRYKLGAKBNY3WXDELVCJIHXANCNFSM5FTPX2EQ&data=04%7C01%7Calessandro.tasora%40unipr.it%7C9158009108e54574d61608da111ecf1a%7Cbb064bc5b7a841ecbabed7beb3faeb1c%7C0%7C0%7C637841121279273440%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=otft4CLx4dboDCVU9d8LFi5DzZMjXnhqsJOnx4Llmok%3D&reserved=0>.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I think i could expand this to complex values. Eigen offers the ComplexEigenSolver which return complex values. Also ComplexSchur is available in Eigen. So from this point its possible. I just have to find some time for this, then i will update the PR and offer some Test example for the complex case. |
Any news? This PR can merge as it is? |
Dear authors and contributers of Spectra,
I have implemented a Krylov Schur algorithm for non-Hermitian matrices which computes eigenvalues and eigenvectors for the generalized Eigenproblem. I have created this type of solver, because the existing solvers in Spectra doesnt worked for my problems well. I'm dealing with system, in which some eigenvalue gaps can be near 0 (equal eigenvalues). The system matrices are generated in a typical Finite Element procedure. The SymGEigsSolver doesnt handled these system good. Thatswhy i decided to implement another algorithm. The structure of the code is based on SymGEigsBase and SymGEigsSolver.
The code itsself is based on MATLAB's "eigs" function. I have tested the solver with matrix size of A and B up to 300k×300k entries. The solver only needs some seconds to find correctly the first 6 eigenvalues (LargestMagn or for the inverse problem SmallestMagn).
It works stable and very fast with large sparse Eigenproblems. It uses all tweaks which MATLAB also using. For that reason i also replaced the original Arnoldi iterations with the one from MATLAB (class KrylovSchur [Spectra\LinAlg\KrylovSchur.h]). Its a little bit different from the existing Anroldi iterations, but very stable because of a robust reorthogonalization algorithm (see Matlabs "eigs" code).
Currently only real input Matrices A and B are allowed, but the algorithm whould also work on Matrices with complex scalars. The Schur decomposition is also available for complex matrices (Eigen::ComplexSchur), as well as the eigensolver "Eigen::ComplexEigenSolver". From this point of view it should be possible with some minor changes on the current code.
For some reasons i also have implemented the Regular Inverse Algorithm using "Eigen::SparseLU" alogirthm. Sometimes the CG-Solver doesnt converge or is much slower than a classical LU decomposition. Maybe you can also use it with the other solvers. It would be also worth to consider a new enum in GEigsMode for the Regular Inverse LU operator.
Tell me what are you thinking. I know the code is currently not perfect now, but its a good start.
I can also create some more significant test cases.
It would be a pleasure for me and a good reference to contribute something useful to the Spectra project.
Best Regards
David