C++ Eigen - How to combine broadcasting and elementwise operations - c++

I have a MatrixXf variable and a VectorXf variable. I would like to perform a rowwise division using the Vector on my Matrix. Is it possible to do something like this?
#include <iostream>
#include "Eigen/Dense"
using namespace std;
using namespace Eigen;
int main() {
MatrixXf mat(3, 2);
mat << 1, 2,
3, 4,
5, 6;
VectorXf vec(2);
vec << 2, 3;
mat = mat.rowwise() / vec;
cout << mat << endl;
return 0;
}
I am expecting to get a matrix with value [0.5, 0.667; 1.5, 1.333; 2.5, 2].
Thank you very much!

You need to use the matrix and vector as arrays (and not linear algebra objects, see docs). To do so, you would rewrite the relevant line as:
mat = mat.array().rowwise() / vec.transpose().array();
cout << mat << endl; // Note that in the original this was vec
The transpose is needed as the VectorXf is a column vector by definition, and you wanted a row vector.

Related

How to get the rows based on condition in eigen?

I need to get the certain rows, when a element is a vector is one.
For an example:
std::vector<bool>index{}; //contains 6000 numbers of elements 0 and 1
Now I have a matrix mat of shape (6000,4)
How can I get the rows in a matrix mat, when the corresponding element is 1 in vector index.
mat = mat[index];
If I understand your question clearly, you may find good answer from this good reply:
Eigen3 select rows out based on column conditions
Using new feature (Eigen 3.4 or 3.3.90 development branch) and take the core code from the previous link:
#include <Eigen/Dense>
#include <iostream>
#include <vector>
using namespace Eigen;
int main() {
MatrixXd mat = MatrixXd::Random(10,5);
std::cout << "original:\n" << mat << std::endl;
std::vector<int> keep_rows;
for (int i = 0; i < mat.rows(); ++i) {
if (mat(i,mat.cols() - 1) > 0.3) {
keep_rows.push_back(i);
}
}
VectorXi keep_cols = VectorXi::LinSpaced(mat.cols(), 0,mat.cols());
MatrixXd mat_sel = mat(keep_rows, keep_cols);
std::cout << "selected:\n" << mat_sel << std::endl;
}
It uses the similar style of the Matlab:
MatrixXd mat_sel = mat(keep_rows, keep_cols);
But the columns and rows that should be kept are stored in an
Eigen::VectorXi
or in a
std::vector<int>

Eigen Assertion Error when Converting from MatrixXf to ArrayXf

I wrote a simple program that adds a scalar to a Random matrix.
#include <Eigen/Dense>
int main() {
Eigen::MatrixXf mat = Eigen::MatrixXf::Random(100, 100);
Eigen::ArrayXf arr = mat.array() + 1;
}
The program compiles without any errors. However, when executing this line:
Eigen::ArrayXf arr = mat.array() + 1;
I get the following error:
Assertion failed: (other.rows() == 1 || other.cols() == 1), function resizeLike, file /usr/local/Cellar/eigen/3.3.7/include/eigen3/Eigen/src/Core/PlainObjectBase.h, line 374.
I read the official documentation (https://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html) and I don't understand what I am doing wrong.
It's been a while since I did anything with Eigen, but I believe you can't mix Arrays and Matrices like that.
However, it seems like you're generating a 100x100 matrix with random numbers, and I'm not sure why it trips up. I don't have Eigen readily available at the moment, but changing it to use fixed size arrays seems to be working on Godbolt.
// Type your code here, or load an example.
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix<float, 100, 100> mat = Eigen::Matrix<float, 100, 100>::Random();
Eigen::Array<float, 100, 100> arr = mat.array() + 1;
std::cout << "Mat 0,0: " << mat(0,0) << "\nArr 0,0: " << arr(0,0) << "\n";
std::cout << "Mat 2,0: " << mat(2,0) << "\nArr 2,0: " << arr(2,0);
return 0;
}
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
Mat 0,0: 0.680375
Arr 0,0: 1.68038
Mat 2,0: 0.566198
Arr 2,0: 1.5662
https://godbolt.org/z/9xu5oW
Solved it. Apparently, I had to store the result of the addition in a MatrixXf, not in an ArrayXf.
#include <Eigen/Dense>
int main() {
Eigen::MatrixXf mat = Eigen::MatrixXf::Random(100, 100);
Eigen::MatrixXf arr = mat.array() + 1;
}
The corresponding Array object to MatrixXf (aka, Matrix<float, Dynamic, Dynamic>) would be ArrayXXf (aka, Array<float, Dynamic, Dynamic>). ArrayXf is a typedef for Array<float, Dynamic, 1>, similar to a VectorXf (aka, Matrix<float, Dynamic, 1>).
The following should work as expected:
#include <Eigen/Core>
int main() {
Eigen::MatrixXf mat = Eigen::MatrixXf::Random(100, 100);
Eigen::ArrayXXf arr = mat.array() + 1;
}

C++ How to change value of 2Dvector using reference to particular element?

When I try to change the vector I reach same values. Please explain me how to solve this problem?
#include <iostream>
#include <vector>
using namespace std;
int &Give2DVectorRef(int i, int j, vector<vector<int>> &matrix) {
return matrix.at(i).at(j);
}
int main() {
vector<vector<int>> matrix{
{1, 1, 1, 1, 1}, {2, 2, 2, 2, 2}, {3, 3, 3, 3, 3}};
int ref;
ref = Give2DVectorRef(1, 3, matrix);
ref = 55;
cout << matrix.at(1).at(3) << endl; // print 2, but I expect 55
return 0;
}
The short answer is to change from
int ref;
ref = Give2DVectorRef(1, 3, matrix);
to
int &ref = Give2DVectorRef(1, 3, matrix);
(as #user1810087 already commented)
Here are some more comments on your code
References to vector items can be dangerous.
Image
int & ref = Give2DVectorRef(1, 3, matrix);
matrix[1].erase(matrix[1].begin()+2); //deletes the third item
ref = 55; // Reference is no longer meaningful
This situation might also accour, if you insert an item before the location of the item referenced to.
A matrix should not be stored as a vector of vectors. If you are using this construct in heavy numerical calculation you will face severe performance problems. A single vector of length (N*M) will be faster. Even better is the usage of a library such as Eigen.
If you are concerned about performance, the operator .at is slow in comparison to the operator [].
Avoid using using namespace std;

Passing values of vectors to Eigen library format [duplicate]

This question already has an answer here:
Eigen and std::vector
(1 answer)
Closed 5 years ago.
I am trying to solve a linear equation Ax=b using Eigen's abilities for the A as a square 2D vector. I have the A and b as C++ based 2D vector and 1D vector respectively. However, I could not find a way to pass the values of them to the Eigen format matrix and vectors. Would you please let me how to copy the variable in Eigen format?
Moreover, what should include in the beginning to be able to use the Map class as a possible solvent?!
Here is the code:
#include <iostream>
#include <vector>
#include "Eigen/Dense"
using namespace std;
using namespace Eigen;
int main()
{
// Let's consider that the A and b are following CPP based vectors:
vector<vector<double>> mainA= { { 10.,11.,12. },{ 13.,14.,15. },{ 16.,17.,18. } };
vector<double> mainB = { 2.,5.,8. };
// ??? Here I need to do something to pass the values to the following Eigen
//format matrix and vector
MatrixXf A;
VectorXf b;
cout << "Here is the matrix A:\n" << A << endl;
cout << "Here is the vector b:\n" << b << endl;
Vector3f x = A.colPivHouseholderQr().solve(b);
cout << "The solution is:\n" << x << endl;
}
As mentioned in the comments, Eigen::Map<> should do the trick.
Usually you'll get away without using the Unaligned, but for correctness/stability, it's best to use it:
auto A = Eigen::Map<Eigen::MatrixXd, Eigen::Unaligned>(mainA.data(), mainA.size(), mainA[0].size())
auto b = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(mainB.data(), mainB.size());
Vector3d x = A.colPivHouseholderQr().solve(b);
To answer the question below about robustness: This can be done using helper functions:
template <typename T, int Align>
Eigen::Map<Eigen::Matrix<T, -1, -1>, Align> CreateMatrix(const std::vector<std::vector<T>>& x)
{
int R = x.size();
assert(!x.empty());
int C = x[0].size();
#ifndef NDEBUG
for(int r=1; r < R; r++)
assert(x[r].size() == x[0].size());
#endif
return auto A = Eigen::Map<Eigen::Matrix<T,-1,-1>, Align>(x.data(), R, C);
}
Although it looks verbose, it does a lot of sanity checks where you then can rely upon in all code for which you have a unit test.

Extract a block from a sparse matrix as another sparse matric

How to extract a block from a Eigen::SparseMatrix<double>. It seems there aren't the methods I used for the dense ones.
‘class Eigen::SparseMatrix<double>’ has no member named ‘topLeftCorner’
‘class Eigen::SparseMatrix<double>’ has no member named ‘block’
There is a way to extract a block as a Eigen::SparseMatrix<double> ?
I made this function to extract blocks from a Eigen::SparseMatrix<double,ColMaior>
typedef Triplet<double> Tri;
SparseMatrix<double> sparseBlock(SparseMatrix<double,ColMajor> M,
int ibegin, int jbegin, int icount, int jcount){
//only for ColMajor Sparse Matrix
assert(ibegin+icount <= M.rows());
assert(jbegin+jcount <= M.cols());
int Mj,Mi,i,j,currOuterIndex,nextOuterIndex;
vector<Tri> tripletList;
tripletList.reserve(M.nonZeros());
for(j=0; j<jcount; j++){
Mj=j+jbegin;
currOuterIndex = M.outerIndexPtr()[Mj];
nextOuterIndex = M.outerIndexPtr()[Mj+1];
for(int a = currOuterIndex; a<nextOuterIndex; a++){
Mi=M.innerIndexPtr()[a];
if(Mi < ibegin) continue;
if(Mi >= ibegin + icount) break;
i=Mi-ibegin;
tripletList.push_back(Tri(i,j,M.valuePtr()[a]));
}
}
SparseMatrix<double> matS(icount,jcount);
matS.setFromTriplets(tripletList.begin(), tripletList.end());
return matS;
}
And these if the sub-matrix is in one of the four corners:
SparseMatrix<double> sparseTopLeftBlock(SparseMatrix<double> M,
int icount, int jcount){
return sparseBlock(M,0,0,icount,jcount);
}
SparseMatrix<double> sparseTopRightBlock(SparseMatrix<double> M,
int icount, int jcount){
return sparseBlock(M,0,M.cols()-jcount,icount,jcount);
}
SparseMatrix<double> sparseBottomLeftBlock(SparseMatrix<double> M,
int icount, int jcount){
return sparseBlock(M,M.rows()-icount,0,icount,jcount);
}
SparseMatrix<double> sparseBottomRightBlock(SparseMatrix<double> M,
int icount, int jcount){
return sparseBlock(M,M.rows()-icount,M.cols()-jcount,icount,jcount);
}
This is now supported in Eigen 3.2.2 Docs (though maybe earlier versions support it too).
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Sparse>
using namespace Eigen;
int main()
{
MatrixXd silly(6, 3);
silly << 0, 1, 2,
0, 3, 0,
2, 0, 0,
3, 2, 1,
0, 1, 0,
2, 0, 0;
SparseMatrix<double, RowMajor> sparse_silly = silly.sparseView();
std::cout <<"Whole Matrix" << std::endl;
std::cout << sparse_silly << std::endl;
std::cout << "block of matrix" << std::endl;
std::cout << sparse_silly.block(1,1,3,2) << std::endl;
return 0;
}
There is very sparse support (sorry, no pun intended) for submatrices in sparse matrices. Effectively you can only access a continuous set of rows for row-major, and columns for column major. The reason for that is not that the matrices could be empty, but rather that the indexing scheme is somewhat more complicated than with dense matrices. With dense matrices you only need an additional stride number in order to support sub-matrix support.