Iterating non-zero elements in MappedSparseMatrix eigen - c++

I am passing a small sparse matrix(for testing) to a C++ function from R. The matrix belongs to the class dgCMatrix as shown below:
5 x 5 sparse Matrix of class "dgCMatrix"
[1,] . . . . .
[2,] 1 1 . . .
[3,] . . . . .
[4,] . . 1 . .
[5,] . 1 . . .
I am iterating this matrix as mentioned in the documentation here.
My function prints out the value of the iterator and the row index, column index.
The c++ function is defined below:
#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]
using Eigen::MappedSparseMatrix;
using Eigen::SparseMatrix;
using Eigen::VectorXi;
using Eigen::Map;
using namespace Rcpp;
using namespace std;
// [[Rcpp::export]]
void createRec(RObject sparse_mat, IntegerVector sparse_vec) {
const MappedSparseMatrix<int> spmat(as<MappedSparseMatrix<int> >(sparse_mat));
long int nrow = spmat.rows();
long int ncol = spmat.cols();
NumericVector sim(nrow);
for(int k=0;k<spmat.outerSize();k++){
for(SparseMatrix<int,Eigen::ColMajor>::InnerIterator it(spmat,k);it;++it){
cout<<"k="<<k<<endl;
cout<<"value="<<it.value()<<endl;
cout<<"it.row="<<it.row()<<endl;
cout<<"it.col="<<it.col()<<endl;
cout<<"index="<<it.index()<<endl;
}
}
}
For the matrix given above the following results are printed:
k=0
value=156148016
it.row=66211520
it.col=0
index=66211520
k=1
value=0
it.row=0
it.col=1
index=0
k=1
value=1
it.row=4
it.col=1
index=4
k=2
value=1
it.row=3
it.col=2
index=3
1.) Any explanation for the values corresponding to k=0? Could these be due to passing the matrix in a wrong manner?
2.) k is iterating over outerSize, which is equal to 5, why is it not iterating for k=3,4? Considering it is a sparseMatrix, this behaviour was expected from the iterator.

Whenever you see very large numbers like 156148016 or 66211520, chances are you either have an undefined behavior (UB) or a value was not appropriately initialized. In this case, it is the later. Specifically, the dgCMatrix class' underlying type is that of a double not an int.
The dgCMatrix class is a class of sparse numeric matrices in the compressed, sparse, column-oriented format. In this implementation the non-zero elements in the columns are sorted into increasing row order. dgCMatrix is the "standard" class for sparse numeric matrices in the Matrix package.
Thus, when you are trying to create a map to the memory location of the underlying RObject there is an additional step required to recreate the object anew in the requested different type. After adding the const term, I'm willing to bet the entries are then as expected since the compiler likely keeps in memory the intermediary object.
So, the changing following:
MappedSparseMatrix<int> spmat(as<MappedSparseMatrix<int> >(sparse_mat));
to:
MappedSparseMatrix<double> spmat(as<MappedSparseMatrix<double> >(sparse_mat));
should be sufficient.
The linked example uses a SparseMatrix matrix, here you are using a MappedSparseMatrix but do not setup an appropriate MappedSparseMatrix::InnerIterator for the second loop.
Thus, we have:
for(SparseMatrix<int,Eigen::ColMajor>::InnerIterator it(spmat,k);it;++it){
Going to:
for(MappedSparseMatrix<double>::InnerIterator it(spmat,k);it;++it){
Also, note that the use of Eigen::ColMajor within the SparseMatrix<int, Eigen::ColMajor>::InnerIterator is not needed as that is the default initialization. So, I've removed this statement.
Regarding your second question, on the iteration of k.
k does iterate over both k=3,4 but there are no elements within those columns. Therefore, the inner loop where k is output does not get called.
This is easy to see if we put two k declarative output statements in the outer and inner loops.
e.g.
for(int k = 0; k < spmat.outerSize(); ++k) {
Rcpp::Rcout << "Overall k = " << k << std::endl << std::endl;
for(MappedSparseMatrix<double>::InnerIterator it(spmat,k); it; ++it) {
Rcpp::Rcout << "Inner k = " << k << std::endl;
}
}
Avoid using namespace std;
Adding in namespace sometimes has unintended consequences, especially one as large as std.
Taking the points from above and slightly simplifying your example, we have the following bare bones working example:
#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]
using Eigen::MappedSparseMatrix;
using Eigen::SparseMatrix;
using Eigen::VectorXi;
using Eigen::Map;
// [[Rcpp::export]]
void createRec(Rcpp::RObject sparse_mat) {
MappedSparseMatrix<double> spmat(Rcpp::as<MappedSparseMatrix<double> >(sparse_mat));
long int nrow = spmat.rows();
Rcpp::NumericVector sim(nrow);
for(int k = 0; k < spmat.outerSize(); ++k) {
Rcpp::Rcout << "Overall k = " << k << std::endl << std::endl;
for(MappedSparseMatrix<double>::InnerIterator it(spmat,k); it; ++it) {
Rcpp::Rcout << "Inner k = " << k << std::endl
<< "value = " << it.value() << std::endl
<< "it.row = " << it.row() << std::endl
<< "it.col = " << it.col() << std::endl
<< "index = " << it.index() << std::endl;
}
}
}
/***R
# Setup values
id_row = c(2, 2, 4, 5)
id_col = c(1, 2, 3, 2)
vals = rep(1,4)
# Make the matrix
x = sparseMatrix(id_row, id_col, x = vals, dims = c(5, 5))
# Test the function
createRec(x)
*/
Output:
Overall k = 0
Inner k = 0
value = 1
it.row = 1
it.col = 0
index = 1
Overall k = 1
Inner k = 1
value = 1
it.row = 1
it.col = 1
index = 1
Inner k = 1
value = 1
it.row = 4
it.col = 1
index = 4
Overall k = 2
Inner k = 2
value = 1
it.row = 3
it.col = 2
index = 3
Overall k = 3
Overall k = 4
For more details on sparse matrices in Eigen and Rcpp, you may wish to read the Rcpp Gallery: Using iterators for sparse vectors and matrices by Soren Hojsgaard and Doug Bates.

Related

C++ - Nested for loop optimizations

Problem
I have some code that I need to optimize for work. Given two datasets, I need to compare every element in one dataset with every element in another. The elements in the datasets are string vectors. that look like this: {"AB", "BB", "AB", "AA", "AB", ...}, where there are 3 possible values: AB, BB, and AA. So for example, one dataset would be something like:
AB AA BB BB AA AB
AB AA AA AA BB AB
AA AA AB BB BB BB
while the other dataset might be
BB AB AB AA AB AB
AA AA BB BB BB BB
Note: The vector length will be the same within and between datasets. In this case, it's length 6.
So the first data set contains three vectors, and the second dataset contains two for a total of 6 comparisons
This example contained 3 vs 2 vectors. My real problem will have something like 1.3M vs 6,000
Reproducible Example
The following code will create the vectors to the datasets to the desired sizes similar to how they'll show up in my real code. The first part of the main function simply generates the datasets. This part doesn't need to be optimized because these will be read in from a file. I'm generating them here for the sake of this question. The part that needs to be optimized is the nested for loop in the latter part of the main function
#include <chrono>
#include <iostream>
#include <vector>
// Takes in a 2D string vector by reference, and fills it to the required size with AA, AB, or BB
void make_genotype_data(int numRows, int numCols, std::vector<std::vector<std::string>>& geno) {
std::string vals[3] = {"AA", "AB", "BB"};
for (int i = 0; i < numRows; i++) {
std::vector<std::string> markers;
for (int j = 0; j < numCols; j++) {
int randIndex = rand() % 3;
markers.push_back(vals[randIndex]);
}
geno.push_back(markers);
markers.clear();
}
}
int main(int argc, char **argv) {
// Timing Calculation
using timepoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
auto print_exec_time = [](timepoint start, timepoint stop) {
auto duration_us = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
auto duration_s = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
std::cout << duration_s.count() << " s\n";
};
// Create the data
auto start = std::chrono::high_resolution_clock::now();
int numMarkers = 100;
std::vector<std::vector<std::string>> old_genotypes;
std::vector<std::vector<std::string>> new_genotypes;
make_genotype_data(50, numMarkers, old_genotypes);
make_genotype_data(6000, numMarkers, new_genotypes);
auto stop = std::chrono::high_resolution_clock::now();
std::cout << "*****************" << std::endl;
std::cout << "Total time for creating data" << std::endl;
print_exec_time(start, stop);
std::cout << "*****************" << std::endl;
int nCols = old_genotypes[0].size();
float threshold = 0.8;
// Compare old_genotypes with new_genotypes
start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < old_genotypes.size()-1; i++) {
auto og = old_genotypes[i];
for (int j = 0; j < new_genotypes.size()-1; j++) {
auto ng = new_genotypes[j];
int numComparisons = 0;
int numMatches = 0;
for (int i = 1; i < nCols; i++) {
if (ng[i] != "--" && og[i] != "--") {
if (ng[i] == og[i]) {
numMatches++;
}
numComparisons++;
}
}
float similarity = (float) numMatches / numComparisons;
if (similarity >= threshold) {
std::cout << i << " from old_genotypes and " << j << " from new_genotypes have high similarity: " << similarity << std::endl;
}
}
}
stop = std::chrono::high_resolution_clock::now();
std::cout << "*****************" << std::endl;
std::cout << "Total time for comparison" << std::endl;
print_exec_time(start, stop);
std::cout << "*****************" << std::endl;
}
On 6,000 vs 5,000 it takes about 4 minutes. So for 6,000 vs 1.3M, it'll take about 17 hours.
It's quite slow. And I have no idea what I can do to improve the speed of the nested for loop. I'm a bit new to C++, so I don't know too many of the intricacies, but I can follow along with the jargon.
I'd really appreciate some pointers (pun intended :D) to help me optimize this. I am willing to try parallelization by breaking one of the datasets up into chunks and feeding each chunk to a core to compare against the second dataset (though don't know how to parallelize in C++). But I only want to explore parallelization after taking the serialized version as far as it can go (it'll help with the parallelized version anyway).
Comparing every element of the first list to every element of the second list does n^2 comparisons. You can get much faster (except on degenerate lists) by instead sorting the two lists (which should take n log n comparisons for each list), then walk a pair of counters down the lists comparing what is at the two counters -- if equal, you found a match, increment counters to the first different element in each list and record the set of matches you just found; if element from list 1 is less than element from list 2, then increment counter 1 (because they are sorted, this element of list one must be ; if element from list 1 is greater than the element from list 2, increment counter 2; as soon as one counter goes beyond the end of its list you are done. This does one compare and increments one counter each time, but can increment counters at most n times before it must hit the end of the lists, so is linear time except for the "record the set of matches you just found", which could be a large set if this is a degenerate pair of lists where most of both lists are the same. But even in that worst possible case, it's only failing back to the same n^2 behavior of your current algorithm.

Print the contents of a 2D vector using auto

I have the vector of vectors a, and I want to print out the contents of the first vector.
a = [ 1 5 3 ; 11 17 14 ]
knowing it's size/dimension, I could do that using the following:
for ( int k = 0; k <= a[0].size(); k++)
cout << a[0][k] << endl;
and the output, as I wanted it, is:
1 5 3
However, in another example where the vector changes its size during execution, I tried to use the following:
for ( auto k : a[0])
cout << a[0][k] << endl;
but the output is as the following:
5 0
How can I get the elements of the first vector using the auto keyword without knowing the dimensions of the vector?
When you use the auto keyword, k is being assigned to the value of each element in the vector, not the index of the element. Therefore, if you wanted to print out the contents of the array, print out just k:
for ( auto k : a[0] )
cout << k << endl;
EDIT: For clarity, the reason it works in the first for loop is because you are setting k to be every integer from 0 to the number of elements in a[0], and therefore the index of each element, rather than the value.

Eigen extracting submatrix from vector of indices

I have been googling for a while now, but cant find the answer to this simple question.
In matlab i can do this:
rows = [1 3 5 9];
A = rand(10);
B = A(rows, : );
How do i do this in eigen? It does not seem like it is possible. The closest thing i have found is
MatrixXd a(10,10);
a.row(1);
,but I want to get multiple rows/cols. Another user has also asked the question here: How to extract a subvector (of a Eigen::Vector) from a vector of indices in Eigen? , but I think there must some built in way of doing this because it is a really common operation I think.
Thanks.
While this was not possible at the time this question was asked, it has since been added in the development branch!
It's very straight forward:
Eigen::MatrixXf matrix;
Eigen::VectorXi columns;
Eigen::MatrixXf extracted_cols = matrix(Eigen::all, columns);
So I'm guessing this will be in the 3.3.5 3.4 stable release. Until then the development branch is the way to go.
Unfortunately, this is still not directly supported even in Eigen 3.3. There has been this feature request for a while:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=329
Gael linked to an example implementation in one of the comments there:
http://eigen.tuxfamily.org/dox-devel/TopicCustomizing_NullaryExpr.html#title1
Ok, say for example you have a 3x3 matrix:
m = [3 -1 1; 2.5 1.5 6; 4 7 1]
and say you want to extract following rows from m matrix:
[0 2], // row 0 and row 2
essentially giving out following matrix:
new_extracted_matrix = [3 -1 1; 4 7 1] // row 0 and row 2 of matrix m
Main thing here is, let's create a vector v having contents [0 2], means we would extract following row indices from matrix m.
Here is what i did:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main()
{
Matrix3f m;
m(0,0) = 3;
m(0,1) = -1;
m(0,2) = 1;
m(1,0) = 2.5;
m(1,1) = m(1,0) + m(0,1);
m(1,2) = 6;
m(2,0) = 4;
m(2,1) = 7;
m(2,2) = 1;
std::cout << "Here is the matrix m:\n" << m << std::endl; // Creating a random 3x3 matrix
VectorXf v(2);
v(0) = 0; // Extracting row 0
v(1) = 2; // Extracting row 2
MatrixXf r(1,v.size());
for (int i=0;i<v.size();i++)
{
r.col(i) << v(i); // Creating indice vector
}
cout << "The extracted row indicies of above matrix: " << endl << r << endl;
MatrixXf N = MatrixXf::Zero(r.size(),m.cols());
for (int z=0;z<r.size();z++)
{
N.row(z) = m.row(r(z));
}
cout << "Extracted rows of given matrix: " << endl << N << endl;
}
This would give us following output:
Here is the matrix m:
[3 -1 1; 2.5 1.5 6; 4 7 1]
The extracted row indicies of above matrix:
[0 2]
Extracted rows of given matrix:
[3 -1 1; 4 7 1]

Shorthand for for-loop - syntactic sugar in C++(11)

Actually these are two related questions.
I know there is a new syntax in C++11 for range-based for loops of the form:
//v is some container
for (auto &i: v){
// Do something with i
}
First question: how can I infer at which iteration I am in this loop? (Say I want to fill a vector with value j at position j).
Second question: I wanted to know if there also is some other way to write a loop of the form
for (int i=0; i<100; i++) { ... }
I find this way of writing it a bit cumbersome, and I do this so often and I would love to have a more concise syntax for it.
Something along the lines:
for(i in [0..99]){ ... }
would be great.
For both questions I would like to avoid having to use additional libraries.
First answer: you don't. You've used a simple construct for a simple purpose; you'll need something more complicated if you have more complicated needs.
Second answer: You could make an iterator type that yields consecutive integer values, and a "container" type that gives a range of those. Unless you have a good reason to do it yourself, Boost has such a thing:
#include <boost/range/irange.hpp>
for (int i : boost::irange(0,100)) {
// i goes from 0 to 99 inclusive
}
Use this:
size_t pos = 0;
for (auto& i : v) {
i = pos;
++pos;
}
(Boost is good, but it is not universally accepted.)
For the first question, the answer is pretty simple: if you need the iteration count, don't use the syntactic construct which abstracts away the iteration count. Just use a normal for loop and not the range-based one.
For the second question, I don't think there's anything currently in the standard library, but you could use a boost::irange for it:
for (int i : boost::irange(0, 100))
For the second question - if Boost is too heavy, you could always use this library:
cppitertools
for(auto i : range(10, 15)) { cout << i << '\n'; } will print 10 11 12 13 14
for(auto i : range(20, 30, 2)) { cout << i << '\n'; } will print 20 22 24 26 28
Doubles and other numeric types are supported too.
It has other pythonic iteration tools and is header-only.
You can do both of these things with Boost.Range: http://boost.org/libs/range
boost::adaptors::indexed: element value & index
boost::irange: integer range
For brevity (and to spice things up a little, since boost::irange has been already demonstrated in isolation), here's a sample code demonstrating these features working together:
// boost::adaptors::indexed
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
#include <boost/range/adaptor/indexed.hpp>
// boost::irange
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html
#include <boost/range/irange.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> input{11, 22, 33, 44, 55};
std::cout << "boost::adaptors::indexed" << '\n';
for (const auto & element : input | boost::adaptors::indexed())
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
endl(std::cout);
std::cout << "boost::irange" << '\n';
for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100))
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
return 0;
}
Sample output:
boost::adaptors::indexed
Value = 11 Index = 0
Value = 22 Index = 1
Value = 33 Index = 2
Value = 44 Index = 3
Value = 55 Index = 4
boost::irange
Value = 0 Index = 100
Value = 1 Index = 101
Value = 2 Index = 102
Value = 3 Index = 103
Value = 4 Index = 104
If v is a vector (or any std contiguous container), then
for(auto& x : v ) {
size_t i = &x-v.data();
x = i;
}
will set the ith entry to the value i.
An output iterator that counts is reasonably easy to write. Boost has one and has an easy-to-generate range of them called irange.
Extracting the indexes of a container is relatively easy. I have written a function called indexes that can take a container, or a range of integers, and produces random output iterators over the range in question.
That gives you:
for (size_t i : indexes(v) ) {
v[i] = i;
}
There probably is an equivalent container-to-index range function in Boost.
If you need both, and you don't want to do the work, you can write a zipper.
for( auto z : zip( v, indexes(v) ) ) {
auto& x = std::get<0>(z);
size_t i = std::get<1>(z);
x = i;
}
where zip takes two or more iterable ranges (or containers) and produces a range view over tuples of iterator_traits<It>::references to the elements.
Here is Boost zip iterator: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html -- odds are there is a Boost zip range that handles syntax like the above zip function.
For the 2nd question:
There is another way, but I would not use or recommend it. However, for quickly setting up a test you could write:
if you do not want to use a library and you are fine with only providing the top bound of the range you can write:
for (auto i:vector<bool>(10)) {
cout << "x";
}
This will create a boolean vector of size 10, with uninitialized values. Looping through these unitialized values using i (so do not use i) it will print 10 times "x".
For the second question, if you are using the latest Visual Studio versions, type 'if' then Tab, Tab, and Tab to fill in init value, step-up and so on.

how to implement this procedure

I have implemented the first part of this problem but failed to achieve the second part. What I'm trying to do is that I have two vectors
std::vector<double> A = {1,1,2,2};
std::vector<double> B = {3,3,4,4,5,5};
I have to go through two loops and make subtraction of two math vectors. For example,
For the first iteration:
C = [1;1] (Note: the first two elements of A vector)
Because C is 2x1, I have to construct from B three math vectors of the same size, therefore the output for the first iteration is
1 - 3
1 - 3
------
1 - 4
1 - 4
------
1 - 5
1 - 5
For the second iteration, the C matrix is expanded by two elements per iteration , therefore the new C matrix is C = [1;1;2;2]. Now we need to make the subtraction again, the output for the second iteration is
1 - 3
1 - 3
2 - 4
2 - 4
------
1 - 4
1 - 4
2 - 5
2 - 5
------
1 - 5
1 - 5
2 - 3
2 - 3
As you can see, the second math vector is shifted by two elements where the first math vector remains as it is.
A and B matrices have this assumption size % 2 = 0 where 2 is the size of C matrix.
Replicating your ouput, for first iteration you would have:
std::vector<double> A = {1,1,2,2};
std::vector<double> B = {3,3,4,4,5,5};
std::vector<double> C (A.begin(), A.begin()+2);
// bg - index of group of 2 elements in B
for (int bg = 0; bg < 3; ++bg) {
for (int ci = 0; ci < int(C.size()); ++ci) {
// bi - index of element in B
int bi = (2*bg + ci) % int(B.size());
std::cout << C[ci] << " - " << B[bi] << std::endl;
}
std::cout << "------" << std::endl;
}
For second iteration you would have to change one line:
// line changed...
std::vector<double> C (a.begin(), a.begin()+4);
Edit: OK, here's more general form that outputs both cases you specified for the change of iteration counter it. Hope it works when you extend the vectors.
for (int it = 1; it <= int(A.size())/2; ++it) {
std::vector<double> C (A.begin(), A.begin()+it*2);
// bg - index of group of 2 elements in B
for (int bg = 0; bg < int(B.size())/2; ++bg) {
for (int ci = 0; ci < int(C.size()); ++ci) {
// bi - index of element in B
int bi = (2*bg + ci) % int(B.size());
std::cout << C[ci] << " - " << B[bi] << std::endl;
}
std::cout << "------" << std::endl;
}
std::cout << std::endl;
}

Categories