GeneralizedEigenSolver not giving eigenvectors in Eigen library - c++

I am new to the Eigen library and trying to solve a generalized eigen value problem. As per the documentation of the GeneralizedEigenSolver template class in Eigen library here I am able to get the eigen values but not the eigen vectors. Seems like the eigenvectors() member function is not implemented. Is there any other way I can generate the eigen vectors once I know the eigen values.I am using Eigen 3.2.4.

It's strange that this isn't implemented, the docs suggest that it is. It's definitely worth asking on the Eigen mailing list or filing a ticket, maybe somebody is working on this and it's in the latest repository.
I have in the past used the GeneralizedSelfAdjointEigenSolver and it definitely produces eigenvectors. So if you know that both your matrices are symmetric, you can use that.
If your matrices are very small, as a quick fix you could apply the standard EigenSolver to M^{-1} A since
A x = lambda * M x <==> M^{-1} A x = lambda * x,
but obviously this requires you to compute the inverse of your right-hand side matrix which is very expensive, so this is really a last resort.
If all else fails, you could pull in a dedicated eigensolver library, say, FEAST, or use the LAPACK routines.

It doesn't appear to be implemented yet. At the end of the compute function there is:
m_eigenvectorsOk = false;//computeEigenvectors;
indicating that they're not actually calculated. Additionally, the eigenvectors() function is commented out and looks like (note the TODO):
//template<typename MatrixType>
//typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType GeneralizedEigenSolver<MatrixType>::eigenvectors() const
//{
// eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
// eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
// Index n = m_eivec.cols();
// EigenvectorsType matV(n,n);
// // TODO
// return matV;
//}
If you wanted eigenvalues from a single matrix you could use EigenSolver like this:
int main(int argc, char *argv[]) {
Eigen::EigenSolver<Eigen::MatrixXf> es;
Eigen::MatrixXf A = Eigen::MatrixXf::Random(4,4);
es.compute(A);
std::cout << es.eigenvectors() << std::endl;
return 0;
}

Related

Does C++ STL, Eigen or Boost have a inverse hyperbolic secant (asech) function?

I've been pouring over search results, but I can't seem to find anything on if this function exists in any of them. I'm pretty sure it does not exist in the C++ standard library.
However, for boost I saw references to nt2::asech but I can't tell if that's some third-party extension to Boost or deprecated or what.
I'm stuck with C++, Eigen and Boost, can't get another library in there for this.
As a sidenote, I thought that asech = 1/sech, and sech = 1/cosh. So therefore asech = cosh. However, that does not work in testing from MATLAB.
//in case of normal trigonometric functions
// the relation is reverse i.e., sin(x)=(1/cosec(x))
// but in case of inverse trigonometric functions
// the relation changes to asin(x)=acosec(1/x)
// now if we apply the same idea to hyperbolic functions as well
// then we find that asinh(x)=acosech(1/x) and asech(x)=acosh(1/x)
// also each hyperbolic functions have their own domain and ranges
// and in your case(asech(x)) the domain is (0,1] (all values between
// zero(0 not included) to 1(1 included)
// therefore your x inside acosh(1/x) should be between (0,1]
// and all the outputs are going to be positive [0,inf)
#include<boost/math/special_functions/acosh.hpp>
#include<iostream>
#include<vector>
int main()
{
std::vector<double> v={1,0.832,0.213,0.9,0.1};
for (auto x:v)
{
std::cout<<"The value of arc sec x for " << x<< "is "<<acosh(1/x)<<" "<<std::endl;
}
return 0;
}

Eigen LDLT Cholesky decomposition in-place

I am trying to get Eigen3 to solve a linear system A * X = B with an in-place Cholesky decomposition. I cannot afford to have any temporaries of the size of A pushed on the stack, but I am free to destroy A in the process.
Unfortunately,
A.llt().solveInPlace(B);
is out of question, since A.llt() implicitly pushes a temporary matrix of the size of A on the stack. For the LLT case, I could get access to the necessary functionality like so:
// solve A * X = B in-place for positive-definite A
template <typename AType, typename BType>
void AllInPlaceSolve(AType& A, BType& B)
{
typedef Eigen::internal::LLT_Traits<AType, Eigen::Upper> TraitsType;
TraitsType::inplace_decomposition(A);
TraitsType::getL(A).solveInPlace(B);
TraitsType::getU(A).solveInPlace(B);
}
This works fine, but I am worried that:
My matrices A might be positive semidefinite only, in which case a LDLT decomposition is required
The LLT decomposition calculates sqrt() unnecessarily for the solution of the system
I could not find a way to hook in Eigen's LDLT functionality similarly to the code above, since the code is structured very differently.
So my question is: Is there a way to use Eigen3 for solving a linear system using LDLT decompositions using no more scratch space than for the diagonal matrix D?
One option is to allocate a LDLT solver only once, and call the compute method:
LDLT<MatType> ldlt(size);
// ...
ldlt.compute(A);
x = ldlt.solve(b);
If that's also not an option, you can const cast the matrix stored by the ldlt object:
LDLT<MatType> ldlt(MatType::Identity(size,size));
MatType& A = const_cast<MatType&>(ldlt.matrixLDLT());
plays with A, and then:
ldlt.compute(A);
x = ldlt.solve(b);
This is ugly, but this should work as long as MatType is column major.

Using Eigen and C++ to do a colsum of massive matrix product

I am trying to compute colsum(N * P), where N is a sparse, 1M by 2500 matrix, and P is a dense 2500 by 1.5M matrix. I am using the Eigen C++ library with Intel's MKL library. The issue is that the matrix N*P can't actually exist in memory, it's way too big (~10 TB). My question is whether Eigen will be able to handle this computation through some combination of lazy evaluation and parallelism? It says here that Eigen won't make temporary matrices unnecessarily: http://eigen.tuxfamily.org/dox-devel/TopicLazyEvaluation.html
But does Eigen know to compute N * P in piecewise chunks that will actually fit in memory? IE: it will have to do something like colsum(N * P_1) ++ colsum(N * P_2) ++ .. ++ colsum(N * P_n), where P is split into n different submatrices column-wise and "++" is concatenation.
I am working with 128 GB RAM.
I gave it a try but ended up with a bad malloc (I'm only running on 8GB on Win8). I set up my main() and used a not inline colsum function I wrote.
int main(int argc, char *argv[])
{
Eigen::MatrixXd dense = Eigen::MatrixXd::Random(1000, 100000);
Eigen::SparseMatrix<double> sparse(100000, 1000);
typedef Triplet<int> Trip;
std::vector<Trip> trps(dense.rows());
for(int i = 0; i < dense.rows(); i++)
{
trps[i] = Trip(20*i, i, 2);
}
sparse.setFromTriplets(trps.begin(), trps.end());
VectorXd res = colsum(sparse, dense);
std::cout << res;
std::cin >> argc;
return 0;
}
The attempt was simply:
__declspec(noinline) VectorXd
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
return (sparse * dense).colwise().sum();
}
That had a bad malloc. Sol it looks like you have to split it up manually on your own (unless someone else has a better solution).
EDIT
I improved the function a bit, but the get the same bad malloc:
__declspec(noinline) VectorXd
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
return (sparse * dense).topRows(4).colwise().sum();
}
EDIT 2
Another option would be to make the sparse matrix dense and force a lazy evaluation. I don't think that it would work with a sparse matrix (oh well).
__declspec(noinline) VectorXd
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
Eigen::MatrixXd denseSparse(sparse);
return denseSparse.lazyProduct(dense).colwise().sum();
}
This doesn't give me the bad malloc, but computes a lot of pointless 0*x_i expressions.
To answer your question: Especially, when products are involved, Eigen often evaluates parts of expressions into temporaries. In some situations this could be optimized but is not implemented yet, in some cases this is essentially the most efficient way to implement it.
However, in your case you could simply calculate the colsum of N (a 1 x 2500 vector) and multiply that by P.
Maybe future versions of Eigen will be able to make this kind of optimization themselves, but most of the time it is a good idea to make problem-specific optimizations oneself before letting the computer do the rest of the work.
Btw: I'm afraid sparse.colwise() is not implemented yet, so you must compute that manually. If you are lazy, you can instead compute Eigen::RowVectorXd Nsum = Eigen::RowVectorXd::Ones(N.rows())*P; (I have not checked it, but this might actually get optimized to near optimal code, with the most recent versions of Eigen).

Matrix of matrices in Eigen C++

I'm creating a circuit analysis library in C++ (also to learn C++, so I'm very new to it).
After getting familiar with Eigen, I'd like to have a matrix where each cell hosts a 3x3 complex matrix.
So far I've tried this very simple prove of principle:
typedef Eigen::MatrixXcd cx_mat;
typedef Eigen::SparseMatrix<cx_mat> sp_mat_mat;
void test(cx_mat Z1){
sp_mat_mat Y(2, 2);
Y(0, 0) = Z1;
Y(2, 2) = Z1;
cout << "\n\nY:\n" << Y << endl;
}
Testing this simple example fails as a probable consequence of Eigen expecting a number instead of a structure.
As a matter of fact the matrix of matrices is prompt to be sparse, hence the sparse matrix structure.
Is there any way to make this work?
Any help is appreciated.
I don't believe Eigen will give you a way to make this work. I you think about the other functions which are connected to Matrix or Sparse matrix, like:
inverse()
norm()
m.row()*m.col()
what should Eigen do when a matrix element number is replaced by a matrix?
What I can understand is that you want to have a data structure that stores your Eigen::MatrixXcd in an memory efficient way.
You could also realize this using the map container:
#include <map>
typedef Eigen::MatrixXcd cx_mat;
cx_mat Z1;
std::map<int,Eigen::MatrixXcd> sp_mat_mat;
int cols = 2;
sp_mat_mat[0*cols+0]=Z1;
sp_mat_mat[2*cols+2]=Z1;
Less memory efficient, but perhaps easier to access would be using the vector container:
#include <vector>
std::vector<std::vector<Eigen::MatrixXcd>> mat_mat;
Have you found a way to create a matrix of matrices?
I see that we can use a 2-D array to create a matrix of matrices.
For example,
#include <Eigen/Dense>
MatrixXd A;
MatrixXd B;
A = MatrixXd::Random(3, 3);
B = MatrixXd::Random(3, 4);
C = MatrixXd::Random(4, 4);
MatrixXd D[2][2];
D[0][0] = A;
D[0][1] = B; D[1][0] = B.transpose();
D[1][1] = C;
I don't know if this way is memory-efficient or not. Let's check it out.
You asked "sparse matrix structure. Is there any way to make this work?" I would say no, because it is not easy to translate a circuit design into a "matrix of matrices" in the first place.. if you want to simulate something, you choose a representation close to it,. In case of an electronic circuit diagram, the schema in memory should IMHO be a directed graph, with linked-list items. At each node/junction, there is a matrix representing the behaviour of a particular component input to output transfer (eg resistor, capacitor, transistor) and you propagate the signal through the matrices assigned to each component. The transformed signal eventually arrives at an output, through the connections in your connected graph. In software, it should work similarly.. Suggested further reading: https://core.ac.uk/download/pdf/53745212.pdf

Use Eigen library to perform sparseLU and display L & U?

I'm a new to Eigen and I'm working with sparse LU problem.
I found that if I create a vector b(n), Eigen could compute the x(n) for the Ax=b equation.
Questions:
How to display the L & U, which is the factorization result of the original matrix A?
How to insert non-zeros in Eigen? Right now I just test with some small sparse matrix so I insert non-zeros one by one, but if I have a large-scale matrix, how can I input the matrix in my program?
I realize that this question was asked a long time ago. Apparently, referring to Eigen documentation:
an expression of the matrix L, internally stored as supernodes The only operation available with this expression is the triangular solve
So there is no way to actually convert this to an actual sparse matrix to display it. Eigen::FullPivLU performs dense decomposition and is of no use to us here. Using it on a large sparse matrix, we would quickly run out of memory while trying to convert it to dense, and the time required to compute the factorization would increase several orders of magnitude.
An alternative solution is using the CSparse library from the Suite Sparse as:
extern "C" { // we are in C++ now, since you are using Eigen
#include <csparse/cs.h>
}
const cs *p_matrix = ...; // perhaps possible to use Eigen::internal::viewAsCholmod()
css *p_symbolic_decomposition;
csn *p_factor;
p_symbolic_decomposition = cs_sqr(2, p_matrix, 0); // 1 = ordering A + AT, 2 = ATA
p_factor = cs_lu(p_matrix, m_p_symbolic_decomposition, 1.0); // tol = 1.0 for ATA ordering, or use A + AT with a small tol if the matrix has amostly symmetric nonzero pattern and large enough entries on its diagonal
// calculate ordering, symbolic decomposition and numerical decomposition
cs *L = p_factor->L, *U = p_factor->U;
// there they are (perhaps can use Eigen::internal::viewAsEigen())
cs_sfree(p_symbolic_decomposition); cs_nfree(p_factor);
// clean up (deletes the L and U matrices)
Note that although this does not use expliit vectorization as some Eigen functions do, it is still fairly fast. CSparse is also very compact, it is just a single header and about thirty .c files with no external dependencies. Easy to incorporate in any C++ project. There is no need to actually include all of Suite Sparse.
If you'll use Eigen::FullPivLU::matrixLU() to the original matrix, you'll receive LU decomposition matrix. To display L and U separately, you can use method triangularView<mode>. In Eigen wiki you can find good example of it. Inserting nonzeros into matrices depends on numbers, which you wan't to put. Eigen has convenient syntax, so you can easily insert values in loop:
for(int i=0;i<size;i++)
{
for(int j=size;j>someNumber;j--)
{
matrix(i,j)=yourClass.getNextNumber();
}
}