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.
Related
I'm looking for a clean way to shed non-contiguous indices in using the Armadillo linear algebra library for C++. I have some code included below, but it seems like there is probably a better way to do it. Any advice appreciated.
The following code works for removing indexes in ind from (column) vector a, but feels clunky.
for(uword k = ind.n_elem; k>0; k--){
a.shed_row(ind(k-1));
}
Any thoughts?
Here is one way using a templated function for dropping rows based on a (sorted) uvec of indexes to exclude. You get the missing indexes from std::set_difference and then go from there.
#define ARMA_USE_CXX11
#include <armadillo>
#include <iostream>
template <class T>
T drop_rows(T a, arma::uvec exclude) {
arma::uvec full_range = arma::regspace<arma::uvec>(0, a.n_rows - 1);
std::vector<int> diff;
std::set_difference(full_range.begin(), full_range.end(),
exclude.begin(), exclude.end(),
std::inserter(diff, diff.begin()));
T b = a.rows(arma::conv_to<arma::uvec>::from(diff));
return b;
}
int main() {
arma::uvec exclude = {0, 1, 4};
arma::vec a = arma::linspace<arma::vec>(100, 500, 5);
arma::vec b = drop_rows(a, exclude);
std::cout << b << std::endl;
arma::mat A = arma::mat(5, 5, arma::fill::eye);
arma::mat B = drop_rows(A, exclude);
std::cout << B << std::endl;
return 0;
}
I'd like to do radius search to find all valid neighbors, but it seems to give me wrong results. Here is my code
#include "opencv/cv.hpp"
#include <iostream>
#include <vector>
int main () {
// create a group of points
std::vector<cv::Point2f> points;
points.emplace_back(438.6, 268.8);
points.emplace_back(439.1, 268.6);
points.emplace_back(438.2, 268.1);
points.emplace_back(498.3, 285.9);
points.emplace_back(312.9, 245.9);
points.emplace_back(313.4, 245.7);
points.emplace_back(313.1, 245.5);
points.emplace_back(312.5, 245.4);
points.emplace_back(297.6, 388.1);
points.emplace_back(291.7, 309.8);
points.emplace_back(194.1, 369.8);
points.emplace_back(439.9, 314.9);
points.emplace_back(312.8, 246.0);
// create features array
cv::Mat_<float> features(0, 2);
for (auto && point : points) {
//Fill matrix
cv::Mat row = (cv::Mat_<float>(1, 2) << point.x, point.y);
features.push_back(row);
}
std::cout << features << std::endl;
cv::flann::Index flann_index(features, cv::flann::KDTreeIndexParams());
std::vector<float> query{ 300.6f, 268.8f };
std::vector<int> ind;
std::vector<float> d;
unsigned int max_neighbours = 10;
// Here I deliberately increase the radius to contain all the points
double radius = 500.0;
flann_index.radiusSearch(query, ind, d, radius, max_neighbours,
cv::flann::SearchParams());
}
Output of ind is [0,0,0,0,0,0,0,0,0,0], all zeros, which is unexpected.
Anyone knows why?
=-=-=-=-=-=-=-=-=-=-= Update
int main() {
// create a group of points
std::vector<cv::Point2f> points;
points.emplace_back(438.6, 268.8);
points.emplace_back(439.1, 268.6);
points.emplace_back(438.2, 268.1);
points.emplace_back(498.3, 285.9);
points.emplace_back(312.9, 245.9);
points.emplace_back(313.4, 245.7);
points.emplace_back(313.1, 245.5);
points.emplace_back(312.5, 245.4);
points.emplace_back(297.6, 388.1);
points.emplace_back(291.7, 309.8);
points.emplace_back(194.1, 369.8);
points.emplace_back(439.9, 314.9);
points.emplace_back(312.8, 246.0);
// create features array
cv::Mat_<float> features(0, 2);
for (auto && point : points) {
//Fill matrix
cv::Mat row = (cv::Mat_<float>(1, 2) << point.x, point.y);
features.push_back(row);
}
std::cout << features << std::endl;
cv::flann::GenericIndex<cvflann::L2<float> > index(features, cvflann::KDTreeIndexParams());
std::vector<float> query(438.6f, 268.8f);
std::vector<int> ind;
std::vector<float> d;
index.radiusSearch(query, ind, d, 45.f, cvflann::SearchParams());
// I can print std::vector by some method, the reader may not, so I comment this line
//std::cout << d << std::endl;
}
As cv::flann::Index is deprecated, I change to new API, but this time, the program just doesn't work anymore.
If you check the example of the plain FLANN I had used here, you would see that they call buildIndex(), which you don't. Could that be?
Try:
cv::flann::Index flann_index(features, cv::flann::KDTreeIndexParams());
flann_index.buildIndex();
You have to set the size of ind and d.
I encountered this issue, and the solution is that radius must be specified as radius squared (^2). And the length of ind and d will be set by max_neighbors, but the return of radiusSearch must be checked to find out which is less, num_found or max_neighbours;
double radius = 500.0;
int num_found = flann_index.radiusSearch(query, ind, d, radius*radius, max_neighbours, cv::flann::SearchParams());
num_found = min(num_found,(int)ind.size()); // check correct size
for(int i=0; i<num_found; i++) { ... ind[i] ... d[i] ... }
in my case, i also had to adjust the index and search parameters to return correct results:
flann::KDTreeIndexParams indexParams(128);
flann::SearchParams searchParams(1024,0.0,true);
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.
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;
}
If I have a 2D vector represented like this:
#include <vector>
typedef vector<vector<double>> Matrix;
Matrix A = {
{ 0, 2, 0, -2, 2.5},
{ 2, 0, 1, 0, 1.6},
{ 0, 1, 0, 1, 0},
{ -2, 0, 1, 0, 0},
{2.5, 1.6, 0, 0, 0}
};
If A.size() returns the rows, does it count each sub-vector as 1 row? Why does A[0].size() mean the number of columns?
It depends on what library you use. If you use Boost uBLAS, you can refer to a documentation here. If not, there are many other matrix libraries you can use. You can check out here for more detail of each library.
C++ doesn't have a std::matrix but it does support multi-dimensional arrays as well as vectors inside of vectors.
For example std::vector<std::vector>> can act as a double matrix, but care must be taken to properly access the underlying variables. In essense, this doubly-layered vector is merely a vector inside of a vector; therefore, doing a dobule [x][y] will not work without some special overloading of operator[].
For a vector inside of a vector, A.size() will return the amount of elements in the 1st dimension, and A[0].size() will return the amount of elements in the vector at the 0th index in the 1st dimension. Note that it is not required for each vector inside of the 1st-dimensional vector to be of uniform length.
It's possible to create a scalable X-dimensional matrix, but it's a bit messy and may be beyond the scope of this question.
Here is a basic example of how to create a "2d vector" within C++:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix;
for (int i = 0; i < 10; ++i) {
matrix.push_back(std::vector<int>());
for (int j = 0; j < 10; ++j) {
matrix[i].push_back(i*10 + j);
}
}
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
std::cout << matrix[i].at(j) << std::endl;
}
}
return 0;
}
Coliru for 3d-matrix: http://coliru.stacked-crooked.com/a/b949266621fb45fb
First, you should know how the Matrix initialized.
Let's insert the float numbers into the Matrix as below.
Matrix A;
vector<double> a1, a2, a3, a4;
a1.push_back(0);
a1.push_back(2);
a1.push_back(0);
a1.push_back(-2);
a1.push_back(2.5);
a2.push_back(2);
a2.push_back(0);
a2.push_back(1);
a2.push_back(0);
a2.push_back(1.6);
a3.push_back(-2);
a3.push_back(0);
a3.push_back(1);
a3.push_back(0);
a3.push_back(0);
a4.push_back(2.5);
a4.push_back(1.6);
a4.push_back(0);
a4.push_back(0);
a4.push_back(0);
A.push_back(a1);
A.push_back(a2);
A.push_back(a3);
A.push_back(a4);
Now, 4 vectors(a1, a2, a3, a4) have been inserted into the Matrix. So the A.size() is 4.
And a1.size() is 5. A[0] is a1, so A[0].size() is 5.