Eigen: modify sparse matrix' triplet list, instead of using coeffRef - c++

I am facing the problem of assembling an Eigen::SparseMatrix. In reality it concerns a finite element system matrix, assembled by looping over elements and integration points. Below I have made the problem more abstract.
I initialize the matrix by first constructing a list of triplets (as suggested in the Eigen documentation). I then perform the assembly in concurrent loops using coeffRef (see example below). The question concerns the fact that coeffRef "performs a binary search", while I know exactly where each item is in the list of triplets (T below). More specifically:
Is it more efficient to modify the list of triplets to avoid coeffRef, at the cost of having to reinitialize the sparse matrix?
If one wants to modify a value in the list of triplets, is there something more elegant than
T[i] = Trip(T[i].row(),T[i].col(),T[i].value()+X);
I realize that the answer may largely depend on the bandwidth of the matrix (i.e. how costly the search is), but there might be generic things to say about this.
Example
#include <iostream>
#include <Eigen/Sparse>
typedef Eigen::SparseMatrix<double> SpMat;
typedef Eigen::Triplet <double> Trip;
int main(void)
{
size_t N = 100;
SpMat A(N,N);
std::vector<Trip> T;
T.reserve(3*N);
for ( size_t i=0; i<N; ++i )
{
if ( i==0 ) T.push_back(Trip(i,i ,-1.0));
else T.push_back(Trip(i,i-1,-1.0));
T.push_back(Trip(i,i,+2.0));
if ( i==N-1 ) T.push_back(Trip(i,0 ,-1.0));
else T.push_back(Trip(i,i+1,-1.0));
}
A.setFromTriplets(T.begin(),T.end());
for ( size_t i=0; i<N; ++i )
A.coeffRef(i,i) += static_cast<double>(i);
return 0;
}
Compiled using e.g.:
clang++ -I/usr/local/include/eigen3 test.cpp

My guess is that as long as the coefficients accessed by coeffRef already exist in the matrix, then calling coeffRef should be faster than reconstructing the matrix from the triplet list.
You might also outsmart the binary search performed by coeffRef by directly accessing the underlying data structure with A.valuePtr()[A.outerIndexPtr()[i]+some_offset] += ..., assuming you can directly compute some_offset taking advantage of the known structure.
Finally, if you need to update all entries, you can also sequentially iterate over them using an InnerIterator it and update the entries with it.valueRef() += ....

Related

Submatrix view from indices in Eigen

Is it possible in Eigen to do the equivalent of the following operation in Matlab?
A=rand(10,10);
indices = [2,5,6,8,9];
B=A(indices,indices)
I want to have a submatrix as a view on the original matrix with given, non consecutive indices.
The best option would be to have a shared memory view of the original matrix, is this possible?
I've figured out a method that works but is not very fast, since it involves non vectorized for loops:
MatrixXi slice(const MatrixXi &A, const std::set<int> &indices)
{
int n = indices.size();
Eigen::MatrixXi B;
B.setZero(n,n);
std::set<int>::const_iterator iInd1 = indices.begin();
for (int i=0; i<n;++i)
{
std::set<int>::const_iterator iInd2=indices.begin();
for (int j=0; j<n;++j)
{
B(i,j) = A.coeffRef(*iInd1,*iInd2);
++iInd2;
}
++iInd1;
}
return B;
}
How can this be made faster?
Make your matrix traversal col-major (which is default in Eigen) http://eigen.tuxfamily.org/dox-devel/group__TopicStorageOrders.html
Disable debug asserts, EIGEN_NO_DEBUG, see http://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html, as the comment by Deepfreeze suggested.
It is very non-trivial to implement vectorized version since elements are not contiguous in general. If you are up to it, take a look at AVX2 gather instructions (provided you have CPU with AVX2 support)
To implement matrix view (you called it shared-memory) you'd need to implement an Eigen expression, which is not too hard if you are well versed in C++ and know Eigen codebase. I can help you to get started if you so want.

Is it possible to combine GSL vectors into a single vector?

I am using the Gnu Scientific Library (GSL), where I have initialized different vectors.
Now I want to combine these vectors into a single vector in order to iterate over the full vector. Does anyone know of a method, where it is possible to do this?
This question discusses the same problem in a more general fashion, but I wanted to know if anyone knew a way to do this directly using GSL (I am to use the sort function implemented in GSL afterwards).
Thank you,
Rasmus
If you want to stick to GSL, but not set all vector coordinates individually you can use gsl_vector_view obtained from gsl_vector_subvector.
To this end, allocate the output gsl_vector large enough to hold the concatenation of all your different vectors. Then for each of these use gsl_vector_subvector to obtain a gsl_vector_view to the portion of the output vector. You can then gsl_vector_memcpy from each of your input vectors to that corresponding portion. Note that a gsl_vector_view is a struct which contains a gsl_vector called vector:
#include <stdio.h>
#include <gsl/gsl_vector.h>
#define length1 4
#define length2 6
int main () {
/* allocate all vectors */
gsl_vector
*vectorIn1 = gsl_vector_alloc( length1 ),
*vectorIn2 = gsl_vector_alloc( length2 ),
*vectorOut = gsl_vector_alloc( length1+length2 );
/* fill input vectors with some test data */
for ( size_t index = 0; index < length1; ++index ) {
gsl_vector_set( vectorIn1, index, -(double)index );
}
for ( size_t index = 0; index < length2; ++index ) {
gsl_vector_set( vectorIn2, index, (double)index );
}
/* perform the copy to portions of the output */
{
gsl_vector_view
viewOut1 = gsl_vector_subvector( vectorOut, 0, length1 ),
viewOut2 = gsl_vector_subvector( vectorOut, length1, length2 );
gsl_vector_memcpy( &viewOut1.vector, vectorIn1 );
gsl_vector_memcpy( &viewOut2.vector, vectorIn2 );
}
/* display the result to see it is correct */
for ( size_t index = 0; index < length1 + length2; ++index ) {
printf( "%3.1f\n", gsl_vector_get( vectorOut, index ) );
}
/* be nice and tidy: release resources after use */
gsl_vector_free( vectorOut );
gsl_vector_free( vectorIn2 );
gsl_vector_free( vectorIn1 );
}
If by " initialized different vectors " you meant initialized different std::vectors, then the answer of your question is here use std::assign.
EDIT 1: In this case, std::assign is the best answer (and not std::copy as many places would suggest) because std::copy will insert the new elements one by one (instead of inserting the whole array at once) and that can cause multiple reallocation (meaning: when you try to insert a new element to a vector where its current size (given by std::vector::size) is equal to its current capacity (given by std::vector::capacity), a reallocation is made that doubles vector capacity. Depending of the size of your vector, this can happen multiple times and it is a very (very!) expensive operation. With std::assign this will only happen once.
If not (meaning you have a collection of gsl_vectors), then in principle it is possible to use STL algorithms with C arrays see here (gsl_vectors holds a C array called data). However it is quite dangerous because the way the memory is aligned inside gsl_vectors is tricky. In this case, you need to convert them manually to std::vector or merge then manually to a bigger gsl_vector)
But, unless you need to implement matrices or need very fast BLAS operations with vectors (see here) I would always work with std::vector (and use std::vector::data to pass the C pointers to GSL functions). For these two exceptions, you should use Armadillo Linear Algebra Package or Blaze if you want to work in C++ (otherwise you would need to write a wrapper or code like C).

Slow performance of sparse matrix using std::vector

I'm trying to implement the functionality of MATLAB function sparse.
Insert a value in sparse matrix at a specific index such that:
If a value with same index is already present in the matrix, then the new and old values are added.
Else the new value is appended to the matrix.
The function addNode performs correctly but the problem is that it is extremely slow. I call this function in a loop about 100000 times and the program takes more than 3 minutes to run. While MATLAB accomplishes this task in a matter of seconds. Is there any way to optimize the code or use stl algorithms instead of my own function to achieve what I want?
Code:
struct SparseMatNode
{
int x;
int y;
float value;
};
std::vector<SparseMatNode> SparseMatrix;
void addNode(int x, int y, float val)
{
SparseMatNode n;
n.x = x;
n.y = y;
n.value = val;
bool alreadyPresent = false;
int i = 0;
for(i=0; i<SparseMatrix.size(); i++)
{
if((SparseMatrix[i].x == x) && (SparseMatrix[i].y == y))
{
alreadyPresent = true;
break;
}
}
if(alreadyPresent)
{
SparseMatrix[i].value += val;
if(SparseMatrix[i].value == 0.0f)
SparseMatrix.erase(SparseMatrix.begin + i);
}
else
SparseMatrix.push_back(n);
}
Sparse matrices aren't typically stored as a vector of triplets as you are attempting.
MATLAB (as well as many other libraries) uses a Compressed Sparse Column (CSC) data structure, which is very efficient for static matrices. The MATLAB function sparse also does not build the matrix one entry at a time (as you are attempting) - it takes an array of triplet entries and packs the whole sequence into a CSC matrix. If you are attempting to build a static sparse matrix this is the way to go.
If you want a dynamic sparse matrix object, that supports efficient insertion and deletion of entries, you could look at different structures - possibly a std::map of triplets, or an array of column lists - see here for more information on data formats.
Also, there are many good libraries. If you're wanting to do sparse matrix operations/factorisations etc - SuiteSparse is a good option, otherwise Eigen also has good sparse support.
Sparse matrices are usually stored in compressed sparse row (CSR) or compressed sparse column (CSC, also called Harwell-Boeing) format. MATLAB by default uses CSC, IIRC, while most sparse matrix packages tend to use CSR.
Anyway, if this is for production usage rather than a learning exercise, I'd recommend using a matrix package with support for sparse matrices. In the C++ world, my favourite is Eigen.
The first thinks that stands out is that you are implementing your own functionality for finding an element: that's what std::find is for. So, instead of:
bool alreadyPresent = false;
int i = 0;
for(i=0; i<SparseMatrix.size(); i++)
{
if((SparseMatrix[i].x == x) && (SparseMatrix[i].y == y))
{
alreadyPresent = true;
break;
}
}
You should write:
auto it = std::find(SparseMatrix.begin(), SparseMatrix().end(), Comparer);
where Comparer is a function that compares two SparseMatNode objects.
But the main improvement will come from using the appropriate container. Instead of std::vector, you will be much better off using an associative container. This way, finding an element will have just a O(logN) complexity instead of O(N). You may slighly modify your SparseMatNode class as follows:
typedef std::pair<int, int> Coords;
typedef std::pair<const Coords, float> SparseMatNode;
You may cover this typedefs inside a class to provide a better interface, of course.
And then:
std::unordered_map<Coords, float> SparseMatrix;
This way you can use:
auto it = SparseMatrix.find(std::make_pair(x, y));
to find elements much more efficiently.
Have you tried sorting your vector of sparse nodes? Performing a linear search becomes costly every time you add a node. You could Insert In Place and always perform Binary Search.
Because sparse matrix may be huge and need to be compressed, you may use std::unordered_map. I assume matrix indexes (x and y) are always positive.
#include <unordered_map>
const size_t MAX_X = 1000*1000*1000;
std::unordered_map <size_t, float> matrix;
void addNode (size_t x, size_t y, float val)
{
size_t index = x + y*MAX_X;
matrix[index] += val; //this function can be still faster
if (matrix[index] == 0) //using find() / insert() methods
matrix.erase(index);
}
If std::unordered_map is not available on your system, you may try std::tr1::unordered_map or stdext::hash_map...
If you can use more memory, then use double instead of float, this will improve a bit your processing speed.

Is it possible to use boost accumulators with vectors?

I wanted to use boost accumulators to calculate statistics of a variable that is a vector. Is there a simple way to do this. I think it's not possible to use the dumbest thing:
using namespace boost::accumulators;
//stuff...
accumulator_set<vector<double>, stats<tag::mean> > acc;
vector<double> some_vetor;
//stuff
some_vector = doStuff();
acc(some_vector);
maybe this is obvious, but I tried anyway. :P
What I wanted was to have an accumulator that would calculate a vector which is the mean of the components of many vectors. Is there an easy way out?
EDIT:
I don't know if I was thoroughly clear. I don't want this:
for_each(vec.begin(), vec.end(),acc);
This would calculate the mean of the entries of a given vector. What I need is different. I have a function that will spit vectors:
vector<double> doSomething();
// this is a monte carlo simulation;
And I need to run this many times and calculate the vectorial mean of those vectors:
for(int i = 0; i < numberOfMCSteps; i++){
vec = doSomething();
acc(vec);
}
cout << mean(acc);
And I want mean(acc) to be a vector itself, whose entry [i] would be the means of the entries [i] of the accumulated vectors.
Theres a hint about this in the docs of Boost, but nothing explicit. And I'm a bit dumb. :P
I've looked into your question a bit, and it seems to me that Boost.Accumulators already provides support for std::vector. Here is what I could find in a section of the user's guide :
Another example where the Numeric
Operators Sub-Library is useful is
when a type does not define the
operator overloads required to use it
for some statistical calculations.
For instance, std::vector<> does not overload any arithmetic operators, yet
it may be useful to use std::vector<>
as a sample or variate type. The
Numeric Operators Sub-Library defines
the necessary operator overloads in
the boost::numeric::operators
namespace, which is brought into scope
by the Accumulators Framework with a
using directive.
Indeed, after verification, the file boost/accumulators/numeric/functional/vector.hpp does contain the necessary operators for the 'naive' solution to work.
I believe you should try :
Including either
boost/accumulators/numeric/functional/vector.hpp before any other accumulators header
boost/accumulators/numeric/functional.hpp while defining BOOST_NUMERIC_FUNCTIONAL_STD_VECTOR_SUPPORT
Bringing the operators into scope with a using namespace boost::numeric::operators;.
There's only one last detail left : execution will break at runtime because the initial accumulated value is default-constructed, and an assertion will occur when trying to add a vector of size n to an empty vector. For this, it seems you should initialize the accumulator with (where n is the number of elements in your vector) :
accumulator_set<std::vector<double>, stats<tag::mean> > acc(std::vector<double>(n));
I tried the following code, mean gives me a std::vector of size 2 :
int main()
{
accumulator_set<std::vector<double>, stats<tag::mean> > acc(std::vector<double>(2));
const std::vector<double> v1 = boost::assign::list_of(1.)(2.);
const std::vector<double> v2 = boost::assign::list_of(2.)(3.);
const std::vector<double> v3 = boost::assign::list_of(3.)(4.);
acc(v1);
acc(v2);
acc(v3);
const std::vector<double> &meanVector = mean(acc);
}
I believe this is what you wanted ?
I don't have it set up to try right now, but if all boost::accumulators need is properly defined mathematical operators, then you might be able to get away with a different vector type: http://www.boost.org/doc/libs/1_37_0/libs/numeric/ublas/doc/vector.htm
And what about the documentation?
// The data for which we wish to calculate statistical properties:
std::vector< double > data( /* stuff */ );
// The accumulator set which will calculate the properties for us:
accumulator_set< double, features< tag::min, tag::mean > > acc;
// Use std::for_each to accumulate the statistical properties:
acc = std::for_each( data.begin(), data.end(), acc );

Sorting eigenvectors by their eigenvalues (associated sorting)

I have an unsorted vector of eigenvalues and a related matrix of eigenvectors. I'd like to sort the columns of the matrix with respect to the sorted set of eigenvalues. (e.g., if eigenvalue[3] moves to eigenvalue[2], I want column 3 of the eigenvector matrix to move over to column 2.)
I know I can sort the eigenvalues in O(N log N) via std::sort. Without rolling my own sorting algorithm, how do I make sure the matrix's columns (the associated eigenvectors) follow along with their eigenvalues as the latter are sorted?
Typically just create a structure something like this:
struct eigen {
int value;
double *vector;
bool operator<(eigen const &other) const {
return value < other.value;
}
};
Alternatively, just put the eigenvalue/eigenvector into an std::pair -- though I'd prefer eigen.value and eigen.vector over something.first and something.second.
I've done this a number of times in different situations. Rather than sorting the array, just create a new array that has the sorted indices in it.
For example, you have a length n array (vector) evals, and a 2d nxn array evects. Create a new array index that has contains the values [0, n-1].
Then rather than accessing evals as evals[i], you access it as evals[index[i]] and instead of evects[i][j], you access it evects[index[i]][j].
Now you write your sort routine to sort the index array rather than the evals array, so instead of index looking like {0, 1, 2, ... , n-1}, the value in the index array will be in increasing order of the values in the evals array.
So after sorting, if you do this:
for (int i=0;i<n;++i)
{
cout << evals[index[i]] << endl;
}
you'll get a sorted list of evals.
this way you can sort anything that's associated with that evals array without actually moving memory around. This is important when n gets large, you don't want to be moving around the columns of the evects matrix.
basically the i'th smallest eval will be located at index[i] and that corresponds to the index[i]th evect.
Edited to add. Here's a sort function that I've written to work with std::sort to do what I just said:
template <class DataType, class IndexType>
class SortIndicesInc
{
protected:
DataType* mData;
public:
SortIndicesInc(DataType* Data) : mData(Data) {}
Bool operator()(const IndexType& i, const IndexType& j) const
{
return mData[i]<mData[j];
}
};
The solution purely relies on the way you store your eigenvector matrix.
The best performance while sorting will be achieved if you can implement swap(evector1, evector2) so that it only rebinds the pointers and the real data is left unchanged.
This could be done using something like double* or probably something more complicated, depends on your matrix implementation.
If done this way, swap(...) wouldn't affect your sorting operation performance.
The idea of conglomerating your vector and matrix is probably the best way to do it in C++. I am thinking about how I would do it in R and seeing if that can be translated to C++. In R it's very easy, simply evec<-evec[,order(eval)]. Unfortunately, I don't know of any built in way to perform the order() operation in C++. Perhaps someone else does, in which case this could be done in a similar way.