How to get the rows based on condition in eigen? - c++

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>

Related

How to fill a sparse matrix efficiently?

I use the eigen library to perform the sparse matrix operations, particularly, to fill a sparse matirx. But the rows and cols are very large in our case, which results in a long time for filling the sparse matrix. Is there any efficient way to do this (maybe by the other libraries)?
Below is the my code:
SparseMatrix mat(rows,cols);
mat.reserve(VectorXi::Constant(cols,6));
for each i,j such that v_ij != 0
mat.insert(i,j) = v_ij;
mat.makeCompressed();
The order in which a SparseMatrix is filled can make an enormous difference in computation time. To fill a SparseMatrix matrix quickly, the elements should be addressed in a sequence that corresponds to the storage order of the SparseMatrix. By default, the storage order in Eigen's SparseMatrix is column major, but it is easy to change this.
The following code demonstrates the time difference between a rowwise filling of two sparse matrices with different storage order. The square sparse matrices are relatively small and nominally identical. While the RowMajor matrix is almost instantly filled, it takes a much longer time (about 30 seconds on my desktop computer) in the case of ColMajor storage format.
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/SparseCore>
#include <random>
using namespace Eigen;
typedef SparseMatrix<double, RowMajor> SpMat_RM;
typedef SparseMatrix<double, ColMajor> SpMat_CM;
// compile with -std=c++11 -O3
int main() {
const int n = 1e4;
const int nnzpr = 50;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> randInt(0, n-1);
SpMat_RM m_RM(n,n);
m_RM.reserve(n);
SpMat_CM m_CM(n,n);
m_CM.reserve(n);
std::cout << "Row-wise filling of [" << n << " x " << n << "] sparse matrix (RowMajor) ..." << std::flush;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < nnzpr; ++j) {
int col = randInt(gen);
double val = 1. ; // v_ij
m_RM.coeffRef(i,col) = val ;
}
}
m_RM.makeCompressed();
std::cout << "done." << std::endl;
std::cout << "Row-wise filling of [" << n << " x " << n << "] sparse matrix (ColMajor) ..." << std::flush;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < nnzpr; ++j) {
int col = randInt(gen);
double val = 1.; // v_ij
m_CM.coeffRef(i,col) = val ;
}
}
m_CM.makeCompressed();
std::cout << "done." << std::endl;
}

merging a collection of `Eigen::VectorXd`s into one large `Eigen::VectorXd`

If you go to this Eigen page, you'll see you can initialize VectorXd objects with the << operator. You can also dump a few vector objects into one big VectorXd object (e.g. look at the third example in the section called "The comma initializer").
I want to dump a few vectors into a big vector, but I'm having a hard time writing code that will work for an arbitrarily sized collection of vectors. The following doesn't work, and I'm having a hard time writing it in a way that does (that isn't a double for loop). Any suggestions?
#include <iostream>
#include <Eigen/Dense>
#include <vector>
int main(int argc, char **argv)
{
// make some random VectorXds
std::vector<Eigen::VectorXd> vOfV;
Eigen::VectorXd first(3);
Eigen::VectorXd second(4);
first << 1,2,3;
second << 4,5,6,7;
vOfV.push_back(first);
vOfV.push_back(second);
// here is the problem
Eigen::VectorXd flattened(7);
for(int i = 0; i < vOfV.size(); ++i)
flattened << vOfV[i];
//shows that this doesn't work
for(int i = 0; i < 7; ++i)
std::cout << flattened(i) << "\n";
return 0;
}
The comma initializer does not work like that. You have to fully initialize the matrix from that. Instead, allocate a large enough vector and iterate and assign the blocks.
#include <iostream>
#include <vector>
#include <Eigen/Dense>
// http://eigen.tuxfamily.org/dox/group__TopicStlContainers.html
#include <Eigen/StdVector>
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::VectorXd)
int main()
{
// make some random VectorXds
std::vector<Eigen::VectorXd> vOfV;
Eigen::VectorXd first(3);
Eigen::VectorXd second(4);
first << 1,2,3;
second << 4,5,6,7;
vOfV.push_back(first);
vOfV.push_back(second);
int len = 0;
for (auto const &v : vOfV)
len += v.size();
Eigen::VectorXd flattened(len);
int offset = 0;
for (auto const &v : vOfV)
{
flattened.middleRows(offset,v.size()) = v;
offset += v.size();
}
std::cout << flattened << "\n";
}

Submatrix with stride in Eigen Library

I'm new to Eigen and I would like to create 10 mxn matrices.
For some reasons I do it with the following method:
Matrix<double, m, n*10>
Which It seems that the memory allocation will be similar to the following:
_______________________________________________________________
|M1(1,1)|M2(1,1)|...|M10(1,1)|.....|M1(1,n)|M2(1,n)|...|M10(1,n)|
| . . |
| . |
Now how it possible to create a reference matrix (means by reference and without copying data) to each of this 10 matrices?
I would recommend using the dynamically allocated matrix, as m and n might be large. Also, it appears that you assume the matrix memory is row major, when the default is column major. In the example below, I've explicitly made them row major.
You can use a series Eigen::Map<MatrixXd>s like so:
#include <Eigen/Core>
#include <iostream>
using namespace Eigen;
int main(void)
{
int m = 3;
int n = 4;
int x = 6;
typedef Matrix < double, Dynamic, Dynamic, RowMajor > ourMat;
ourMat M1(m, n * x);
M1.setConstant(9.9);
for (int i = 0; i < x; i++)
{
Eigen::Map<ourMat, 0, Stride<Dynamic, Dynamic>> m_i(M1.data() + i,
m, n,
Stride<Dynamic, Dynamic>(n*x,x));
m_i.setConstant(double(i));
std::cout << m_i << std::endl;
std::cout << M1 << "\n" << std::endl;
}
Eigen::Map<VectorXd> m_i(M1.data(), m * n * x);
std::cout << m_i.transpose() << std::endl;
return 0;
}

How to count duplicate entries of a vector in C++

I'm using Armadillo to do linear algebra calculation in C++.
For example, there is a
vector a = (1,1,2,2,0,2,1,0)
I wish return a matrix
(0, 2) //means 0 shows 2 times in the vector
(1, 3) //1 shows 3 times
(2, 3) //2 shows 3 times
Is there any function can fulfill such job?
As mentioned in comments you could use a std::map to collect the results. Then you can convert to a matrix as you see fit. You could skip the map step and use a matrix directly if it's already pre-initialised with the rows you're after.
As for a function to do this, you can use std::for_each from <algorithm> along with a lambda expression, although it seems overkill when a loop would be fine.
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
vector<int> v{1,1,2,2,0,2,1,0};
map<int,int> dup;
for_each( v.begin(), v.end(), [&dup]( int val ){ dup[val]++; } );
for( auto p : dup ) {
cout << p.first << ' ' << p.second << endl;
}
return 0;
}
Here's another solution, using only Armadillo functions, and a C++11 compiler:
vec a = {1,1,2,2,0,2,1,0}; // vec holds elements of type 'double'
vec b = unique(a);
uvec c = hist(a,b); // uvec holds unsigned integers
mat X(b.n_rows, 2);
X.col(0) = b;
X.col(1) = conv_to<vec>::from(c);
X.print("X:");
Explanation:
vec b = unique(a) creates a vector containing the unique elements of a, sorted in ascending order
uvec c = hist(a,b) creates a histogram of counts of elements in a, using b as the bin centers
conv_to<vec>::from(c) converts c (vector with unsigned integers) to the same vector type as a

How do I sum all elements in a ublas matrix?

According to this page there should be a sum function provided in ublas, but I can't get the following to compile:
boost::numeric::ublas::matrix<double> mymatrix;
std::cout << boost::numeric::ublas::sum(mymatrix);
error is:
testcpp:146:144: error: no matching function for call to
‘sum(boost::numeric::ublas::matrix&)’
I'm #includeing:
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
Am I missing an include, or did I misunderstand the docs? How would I achieve this (I'm trying to sum up all elements of a matrix and produce a single double)?
As pointed out in comments, sum only applies to vectors (see documentation)
You could certainly get at m.data() and sum the values that way, but you are using a linear algebra library! Multiply a row vector of 1's by your matrix, and sum the result:
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
namespace bls = boost::numeric::ublas;
int main()
{
bls::matrix<double> m(3, 3);
for (unsigned i = 0; i < m.size1(); ++i)
for (unsigned j = 0; j < m.size2(); ++j)
m(i, j) = 3 * i + j;
std::cout << "Sum of all elements of " << m << " is "
<< sum(prod(bls::scalar_vector<double>(m.size1()), m)) << '\n';
}
A more reusable approach would be to define a sum that takes a matrix_expression, as the shark library did.