Add Matrix and DiagonalMatrix in Eigen3 - c++

I want to add elements to the diagonal of a Eigen::MatrixXd object with the Eigen3 library (version 3.3.2).
Both for optimisation and being able to use constness, I want to do this by adding a diagonal matrix to the original, like this
const MatrixXd a(2,2); a << 1, 2, 3, 4;
const VectorXd v(2); v << 10, 20;
const MatrixXd b = a + v.asDiagonal();
But this doesn't work: I get a compiler error about there being no operator+. Adding two MatrixXd does work, so I would expect it to behave for the diagonal specialisation.
Removing the constness doesn't help. Using statically sized matrices makes no difference, so it's not a dynamic-sizing thing. And explicitly constructing a DiagonalMatrix rather than using the DiagonalWrapper returned by asDiagonal() also gives the same error.
Multiplication is well-formed for these types: MatrixXd c = a * v.asDiagonal(); compiles and runs just fine. Am I doing something wrong, or is operator+(Matrix,DiagonalMatrix) just missing from the library?

Thanks to #CoryKramer for linking to an equivalent question being asked and answered on the KDE/Eigen forum: https://forum.kde.org/viewtopic.php?f=74&t=136617 Here's a summary for posterity:
"Normal" addition of an Eigen Matrix and either a DiagonalMatrix or DiagonalWrapper isn't a supported operation, while multiplication or compound += addition are fine. += isn't an option if trying to work with const objects, but constructing an explicit Matrix2d from the asDiagonal() call -- why didn't I think of trying that?! -- works nicely:
MatrixXd b = a + Matrix2d(v.asDiagonal());
I guess there are potential performance penalties, which is why this isn't supported without the type construction. But they're unlikely to be worse than the dirty alternative of manually looping over diagonal indices.

Related

Rationale for Eigen API for Matrix with Scalar operations

Consider the following code:
#include <Eigen/Core>
using Matrix = Eigen::Matrix<float, 2, 2>;
Matrix func1(const Matrix& mat) { return mat + 0.5; }
Matrix func2(const Matrix& mat) { return mat / 0.5; }
func1() does not compile; you need to replace mat with mat.array() in the function body to fix it ([1]). However, func2() does compile as-is.
My question has to do with why the API is designed this way. Why is addition-with-scalar and division-by-scalar treated differently? What problems would arise if the following method is added to the Matrix class, and why haven't those problems arisen already for the operator/ method?:
auto operator+(Scalar s) const { return this->array() + s; }
From a mathematics perspective, a scalar added to a matrix "should" be the same as adding the scalar only to the diagonal. That is, a math text would usually use M + 0.5 to mean M + 0.5I, for I the identity matrix. There are many ways to justify this. For example, you can appeal to the analogy I = 1, or you can appeal to the desire to say Mx + 0.5x = (M + 0.5)x whenever x is a vector, etc.
Alternatively, you could take M + 0.5 to add 0.5 to every element. This is what you think is right if you don't think of matrices from a "linear algebra mindset" and treat them as just collections (arrays) of numbers, where it is natural to just "broadcast" scalar operations.
Since there are multiple "obvious" ways to handle + between a scalar and a matrix, where someone expecting one may be blindsided by the other, it is a good idea to do as Eigen does and ban such expressions. You are then forced to signify what you want in a less ambiguous way.
The natural definition of / from an algebra perspective coincides with the array perspective, so no reason to ban it.

Does Eigen Library in C++ have a dynamic vector or matrix

Is there a way to set a dynamic vector or matrix in Eigen library? If not, is there a way to still use the Eigen library in conjunction with another class like vector?
For example let's say I have n*1 matrix called MatrixXd S(n,1); Now for simplicity let n=3 and S = 4 2 6. Pretend that the elements in S are future stock prices and let K = 2 which will be the strike price. Don't worry you won't need to understand the terminology of an option. Now say I want to know at what positions of S will we have S - K > 0 and say I want to store these positions in a vector call b.
Clearly, depending on the elements of S the vector b will be of a different size. Thus, I need to have b being of a dynamic variable. The only class I am familiar with that allows this is the vector class i.e., #include <vector>.
My question is as follows: Is it okay to use the Eigen library and the #include <vector> class together? Note that I will be performing operations of b with the Eigen library vectors and matrices I have created.
If I am not making sense, or if my question is unclear please let me know and I will clarify as much as possible.
Yes, it does. It's presented in the "A simple first program" of Getting started:
#include <iostream>
#include <Eigen/Dense>
using Eigen::MatrixXd;
int main()
{
MatrixXd m(2,2);
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);
std::cout << m << std::endl;
}
You do need to pass the size to the constructor, but it's works like a vector. You can resize it later on too.
MatrixXd is a convenient typedef to a Matrix template which uses Dynamic as a template value for Rows, and Cols. It's basically Matrix<double, Dynamic, Dynamic>.
So you can have not only dynamic sized vectors and matrices, but also arbitrarily large fixed-size ones. Eigen does pretty nifty optimizations for small matrices, so using a fixed size there might be beneficial.

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).

Eigen and C++11 type inference fails for Cholesky of matrix product

I am trying to take the cholesky decomposition of the product of a matrix with its transpose, using Eigen and C++11 "auto" type. The problem comes when I try to do
auto c = a * b
auto cTc = c.tranpose() * c;
auto chol = cTc.llt();
I am using XCode 6.1, Eigen 3.2.2. The type error I get is here.
This minimal example shows the problem on my machine. Change the type of c from auto to MatrixXd to see it work.
#include <iostream>
#include <Eigen/Eigen>
using namespace std;
using namespace Eigen;
int main(int argc, const char * argv[]) {
MatrixXd a = MatrixXd::Random(100, 3);
MatrixXd b = MatrixXd::Random(3, 100);
auto c = a * b;
auto cTc = c.transpose() * c;
auto chol = cTc.llt();
return 0;
}
Is there a way to make this work while still using auto?
As a side question, is there a performance reason to not assert the matrix is a MatrixXd at each stage? Using auto would allow Eigen to keep the answer as whatever weird template expression it fancies. I'm not sure if typing it as MatrixXd would cause problems or not.
The problem is that the first multiplication returns a Eigen::GeneralProduct instead of a MatrixXd and auto is picking up the return type. You can implicitly create a MatrixXd from a Eigen::GeneralProduct so when you explicitly declare the type it works correctly. See http://eigen.tuxfamily.org/dox/classEigen_1_1GeneralProduct.html
EDIT: I'm not an expert on the Eigen product or performance characteristics of doing the casting. I just surmised the answer from the error message and confirmed from the online documentation. Profiling is always your best bet for checking the performance of different parts of your code.
Let me summarize what's is going on and why it's wrong. First of all, let's instantiate the auto keywords with the types they are taking:
typedef GeneralProduct<MatrixXd,MatrixXd> Prod;
Prod c = a * b;
GeneralProduct<Transpose<Prod>,Prod> cTc = c.transpose() * c;
Note that Eigen is an expression template library. Here, GeneralProduct<> is an abstract type representing the product. No computation are performed. Therefore, if you copy cTc to a MatrixXdas:
MatrixXd d = cTc;
which is equivalent to:
MatrixXd d = c.transpose() * c;
then the product a*b will be carried out twice! So in any case it is much preferable to evaluate a*b within an explicit temporary, and same for c^T*c:
MatrixXd c = a * b;
MatrixXd cTc = c.transpose() * c;
The last line:
auto chol = cTc.llt();
is also rather wrong. If cTc is an abstract product type, then it tries to instantiate a Cholesky factorization working on a an abstract product type which is not possible. Now, if cTc is a MatrixXd, then your code should work but this still not the preferred way as the method llt() is rather to implement one-liner expression like:
VectorXd b = ...;
VectorXd x = cTc.llt().solve(b);
If you want a named Cholesky object, then rather use its constructor:
LLT<MatrixXd> chol(cTc);
or even:
LLT chol(c.transpose() * c);
which is equivalent unless you have to use c.transpose() * c in other computations.
Finally, depending of the sizes of a and b, it might be preferable to compute cTc as:
MatrixXd cTc = b.transpose() * (a.transpose() * a) * b;
In the future (i.e., Eigen 3.3), Eigen will be able to see:
auto c = a * b;
MatrixXd cTc = c.transpose() * c;
as a product of four matrices m0.transpose() * m1.transpose() * m2 * m3 and put the parenthesis at the right place. However, it cannot know that m0==m3 and m1==m2, and therefore if the preferred way is to evaluate a*b in a temporary, then you will still have to do it yourself.
I'm not an expert at Eigen, but libraries like this often return proxy objects from operations and then use implicit conversion or constructors to force the actual work. (Expression Templates are an extreme example of this.) This avoids unnecessary copying of the full matrix of data in many situations. Unfortunately, auto is quite happy to just create an object of the proxy type, which normally users of the library would never explicitly declare. Since you need to ultimately have the numbers calculated, there is not a performance hit per se from casting to a MatrixXd. (Scott Meyers, in "Effective Modern C++", gives the related example of using auto with vector<bool>, where operator[](size_t i) returns a proxy.)
DO NOT use auto with Eigen expressions. I bumped into even more "dramatic" issues with this before, see
eigen auto type deduction in general product
and was advised by one of the Eigen creators (Gael) not to use auto with Eigen expressions.
The cast from an expression to a specific type like MatrixXd should be extremely fast, unless you want lazy evaluation (since when doing the cast the result is evaluated).