The Eigen library can map existing memory into Eigen matrices.
float array[3];
Map<Vector3f>(array, 3).fill(10);
int data[4] = 1, 2, 3, 4;
Matrix2i mat2x2(data);
MatrixXi mat2x2 = Map<Matrix2i>(data);
MatrixXi mat2x2 = Map<MatrixXi>(data, 2, 2);
My question is, how can we get c array (e.g. float[] a) from eigen matrix (e.g. Matrix3f m)? What it the real layout of eigen matrix? Is the real data stored as in normal c array?
You can use the data() member function of the Eigen Matrix class. The layout by default is column-major, not row-major as a multidimensional C array (the layout can be chosen when creating a Matrix object). For sparse matrices the preceding sentence obviously doesn't apply.
Example:
ArrayXf v = ArrayXf::LinSpaced(11, 0.f, 10.f);
// vc is the corresponding C array. Here's how you can use it yourself:
float *vc = v.data();
cout << vc[3] << endl; // 3.0
// Or you can give it to some C api call that takes a C array:
some_c_api_call(vc, v.size());
// Be careful not to use this pointer after v goes out of scope! If
// you still need the data after this point, you must copy vc. This can
// be done using in the usual C manner, or with Eigen's Map<> class.
To convert normal data type to eigen matrix type
double *X; // non-NULL pointer to some data
You can create an nRows x nCols size double matrix using the Map functionality like this:
MatrixXd eigenX = Map<MatrixXd>( X, nRows, nCols );
To convert eigen matrix type into normal data type
MatrixXd resultEigen; // Eigen matrix with some result (non NULL!)
double *resultC; // NULL pointer <-- WRONG INFO from the site. resultC must be preallocated!
Map<MatrixXd>( resultC, resultEigen.rows(), resultEigen.cols() ) = resultEigen;
In this way you can get in and out from eigen matrix. Full credits goes to http://dovgalecs.com/blog/eigen-how-to-get-in-and-out-data-from-eigen-matrix/
If the array is two-dimensional, one needs to pay attention to the storage order. By default, Eigen stores matrices in column-major order. However, a row-major order is needed for the direct conversion of an array into an Eigen matrix. If such conversions are performed frequently in the code, it might be helpful to use a corresponding typedef.
using namespace Eigen;
typedef Matrix<int, Dynamic, Dynamic, RowMajor> RowMatrixXi;
With such a definition one can obtain an Eigen matrix from an array in a simple and compact way, while preserving the order of the original array.
From C array to Eigen::Matrix
int nrow = 2, ncol = 3;
int arr[nrow][ncol] = { {1 ,2, 3}, {4, 5, 6} };
Map<RowMatrixXi> eig(&arr[0][0], nrow, ncol);
std::cout << "Eigen matrix:\n" << eig << std::endl;
// Eigen matrix:
// 1 2 3
// 4 5 6
In the opposite direction, the elements of an Eigen matrix can be transferred directly to a C-style array by using Map.
From Eigen::Matrix to C array
int arr2[nrow][ncol];
Map<RowMatrixXi>(&arr2[0][0], nrow, ncol) = eig;
std::cout << "C array:\n";
for (int i = 0; i < nrow; ++i) {
for (int j = 0; j < ncol; ++j) {
std::cout << arr2[i][j] << " ";
}
std::cout << "\n";
}
// C array:
// 1 2 3
// 4 5 6
Note that in this case the original matrix eig does not need to be stored in row-major layout. It is sufficient to specify the row-major order in Map.
You need to use the Map function again. Please see the example here:
http://forum.kde.org/viewtopic.php?f=74&t=95457
The solution with Map above segfaults when I try it (see comment above).
Instead, here's a solution that works for me, copying the data into a std::vector from an Eigen::Matrix. I pre-allocate space in the vector to store the result of the Map/copy.
Eigen::MatrixXf m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = 0;
cout << m << "\n";
// Output:
// 3 -1
// 2.5 0
// Segfaults with this code:
//
// float* p = nullptr;
// Eigen::Map<Eigen::MatrixXf>(p, m.rows(), m.cols()) = m;
// Better code, which also copies into a std::vector:
// Note that I initialize vec with the matrix size to begin with:
std::vector<float> vec(m.size());
Eigen::Map<Eigen::MatrixXf>(vec.data(), m.rows(), m.cols()) = m;
for (const auto& x : vec)
cout << x << ", ";
cout << "\n";
// Output: 3, 2.5, -1, 0
I tried this : passing the address of the element at (0,0) and iterating forward.
Eigen::Matrix<double, 3, 8> coordinates3d;
coordinates3d << 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0;
double *p = &coordinates3d(0,0);
std::vector<double> x2y2;
x2y2.assign(p, p + coordinates3d.size());
for(int i=0;i < coordinates3d.size(); i++) {
std::cout <<x2y2[i];
}
This is the output : 001011111101000010110100
The data is stored row-major it seems
ComplexEigenSolver < MyMatrix > es;
complex<double> *eseig;
es.compute(H);
es.eigenvalues().transpose();
eseig=(complex<double> *)es.eigenvalues().data();
Related
I am looking for a builtin way with the eigen library to perform coordinate transformations by normal vectors in 2D space.
Mathematically, it's not difficult: Let v = (v_x, v_y) be a 2D column vector and n = (n_x, n_y) be a normal vector, then the transformation I am looking for is one by rotational matrix:
v_T = N * v, with v_T being the transformed vector and N being the rotational matrix, which is
| nx, ny |
| -ny, nx |
In my case, the data I need to transform is stored in an Array2Xd and the normal vectors are stored in a Matrix2Xd, with each column holding x- and y-component. I need to transform each column in the array by the corresponding normal vector in the matrix.
Currently, I'm doing it like this:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
/* transform a single vector, just for illustration */
Array2d transform_s( const Ref<const Array2d>& v, const Ref<const Vector2d>& n ){
return {
n.dot( v.matrix() ),
-n.y() * v.x() + n.x() * v.y()
};
}
/* transform multiple columns */
Array2Xd transform_m( const Ref<const Array2Xd>& v, const Ref<const Array2Xd>& n ){
Array2Xd transformed ( 2, v.cols() );
/* colwise dot product for first row */
transformed.row(0) = (n * v).colwise().sum();
/* even less elegant calculation for the second row */
transformed.row(1) = n.row(0) * v.row(1) - n.row(1) * v.row(0);
return transformed;
}
int main(){
Array2Xd vals (2, 3);
vals <<
2, 0,-1,
0, 3, 2;
Matrix2Xd n;
n.resizeLike(vals);
n <<
0, 0, 1,
1,-1, 1;
n.colwise().normalize();
std::cout
<< "single column:\n" << transform_s( vals.col(0), n.col(0) )
<< "\nall columns:\n" << transform_m( vals, n.array() )
<< "\n";
return 0;
}
I'm aware of Eigen::Rotation2D, but it appears to either require an angle or a rotational matrix. I am specifically looking for a way to only provide the normal vectors. Otherwise I need to build the rotational matrices from the normal vectors myself, which doesn't really reduce the complexity on my end.
If there's no way to do this with eigen, I'll accept that as an answer. In that case, I'd be very happy about a more efficient implementation of what I wrote above.
What you are doing is essentially a complex multiplication with conj(n).
There is no elegant way to reinterpret a Vector2d/Array2Xd to a complex<double>/ArrayXcd, but you can hack something together using Maps:
Array2Xd transform_complex( const Ref<const Array2Xd>& v, const Ref<const Array2Xd>& n ){
Array2Xd transformed(2, v.cols());
ArrayXcd::Map(reinterpret_cast<std::complex<double>*>(transformed.data()), v.cols())
= ArrayXcd::Map(reinterpret_cast<std::complex<double> const*>(v.data()), v.cols())
* ArrayXcd::Map(reinterpret_cast<std::complex<double> const*>(n.data()), n.cols()).conjugate();
return transformed;
}
You could write yourself a helper function which takes a const Ref<const Array2Xd>& and returns a Map<ArrayXcd> with the same content.
I am trying to populate an Eigen matrix (dyinamic rows, 2 columns, of doubles) from a vector containing some simple structure of cartesian points, however, I am getting an error when using operator <<.
Minimum failing example (using MSVC 2017):
#include <Eigen/Dense>
#include <vector>
struct point {
double x, y;
};
int main() {
std::vector<point> points = {
point{0.0, 0.0},
point{0.5, 0.0},
point{0.0, 1.0},
point{0.5, 1.0},
};
typedef Eigen::Matrix<double, Eigen::Dynamic, 2> CoordMatrix;
CoordMatrix X;
for (auto& p : points)
X << p.x, p.y;
return 0;
}
When running this, I get an error in the line X << point.x, point.y; saying: "No operator << matches these operands" (this also throws when trying to pass X << 0.0, 0.0; while in debug mode).
From what I understand, you are trying to initialize the X matrix with values in each row containing coordinates of one of the points from the earlier vector. You can't do it that way, see here:
Eigen offers a comma initializer syntax which allows the user to easily set all the coefficients of a matrix, vector or array. Simply list the coefficients, starting at the top-left corner and moving from left to right and from the top to the bottom. The size of the object needs to be specified beforehand. If you list too few or too many coefficients, Eigen will complain.
The above clearly states that you the right hand side needs to match dimensions to the left hand side. In your case you would probably need to copy the vector element by element. Something like:
CoordMatrix X(points.size(), 2); // reserving rigth storage for the matrix
for (auto i = 0u; i < points.size(); ++i) {
X(i, 0) = points[i].x;
X(i, 1) = points[i].y;
}
If you like to use the << initialization, you can do that one row at a time (and as #paler123 already said, you need to allocate X before storing values into it):
typedef Eigen::Matrix<double, Eigen::Dynamic, 2> CoordMatrix;
CoordMatrix X(points.size(), 2); // allocate space for matrix
Eigen::Index r=0; // or use `r` as counter in the loop
for (auto& p : points)
X.row(r++) << p.x, p.y; // fill matrix one row per iteration
You can also map the memory of points to an Eigen::Map directly -- in that case you must make sure that the storage order agrees and that points does not get modified if you still use X, but X will require no extra memory (except for a pointer and an Index).
typedef Eigen::Matrix<double, Eigen::Dynamic, 2, Eigen::RowMajor> CoordMatrix;
auto X = CoordMatrix::Map(&points[0].x, points.size(), 2); // no copy happens
// X gets invalid if `points` are destructed or re-allocated.
MatrixXf A = MatrixXf::Random(3, 3);
MatrixXf B = A.row(1);
std::vector<float> vec;
I want to built the vector "vec" with elements from the row Eigen matrix "B". Something like this "vec=B.data()"
In addition to the obvious answer (manual push_backs or pre-allocation + index-by-index assignment), you can initialize it directly using the base pointer returned by ::data():
Eigen::MatrixXf A = Eigen::MatrixXf::Random(3, 3);
Eigen::MatrixXf B = A.row(1);
std::vector<float> vec(B.data(), B.data() + B.size());
Just be careful that Eigen may use memory alignment to take advantage of SSE-family instructions, so it may not work correctly with higher dimensions.
Just use a loop:
MatrixXf A = MatrixXf::Random(3, 3);
MatrixXf B = A.row(1);
std::vector<float> vec(B.size());
for(size_t row=0; row < vec.size(); row++) {
vec[row] = B[row];
}
I am using the Xtensor library for C++.
I have a xt::zeros({n, n, 3}) array and I would like to assign the its i, j, element an xt::xarray{ , , } so that it would store a 3D dimensional vector at each (i, j). However the documentation does not mention assigning values - I am in general unable to figure out from the documentation how arrays with multiple coodinates works.
What I have been trying is this
xt::xarray<double> force(Body body1, Body body2){
// Function to calulate the vector force on body2 from
// body 1
xt::xarray<double> pos1 = body1.get_position();
xt::xarray<double> pos2 = body2.get_position();
// If the positions are equal return the zero-vector
if(xt::all(xt::equal(pos1, pos2))) {
return xt::zeros<double>({1, 3});
}
xt::xarray<double> r12 = pos2 - pos1;
double dist = xt::linalg::norm(r12);
return -6.67259e-11 * body1.get_mass() * body2.get_mass()/pow(dist, 3) * r12;
}
xt::xarray <double> force_matrix(){
// Initialize the matrix that will hold the force vectors
xt::xarray <double> forces = xt::zeros({self_n, self_n, 3});
// Enter the values into the force matrix
for (int i = 0; i < self_n; ++i) {
for (int j = 0; j < self_n; ++j)
forces({i, j}) = force(self_bodies[i], self_bodies[j]);
}
}
Where I'm trying to assign the output of the force function as the ij'th coordinate in the forces array, but that does not seem to work.
In xtensor, assigning and indexing into multidimensional arrays is quite simple. There are two main ways:
Either index with round brackets:
xarray<double> a = xt::zeros({3, 3, 5});
a(0, 1, 3) = 10;
a(1, 1, 0) = -100; ...
or by using the xindex type (which is a std::vector at the moment), and the square brackets:
xindex idx = {0, 1, 3};
a[idx] = 10;
idx[0] = 1;
a[idx] = -100; ...
Hope that helps.
You can also use view to achieve that.
In the inner loop, you could do:
xt::view(forces, i, j, xt::all()) = a_xarray_with_proper_size;
In SparseSuiteQR, all of the examples I can find use stdin or a file read to create a sparse matrix. Could someone provide a simple example of how to create one directly in C++?
Even better, in the CHOLMOD documentation, there is mention of a sparse2 function available in matlab, which behaves the same as the sparse. Can this be used in C++?
The data structures used by SuiteSparseQR (e.g. cholmod_sparse) are defined in the CHOLMOD library. You can find more information about it on the CHOLMOD documentation, which is much larger than the one from SuiteSparseQR.
I am assuming that you try to solve a linear system, see the CSparse package from Tim Davies, or boost matrix libraries which also have numeric bindings which interface umfpack and some lapack functions AFAIK...
CHOLMOD is a pretty awesome project - thanks Tim Davis :)
There is surprisingly a lot of code on GitHub that makes use of CHOLMOD, but you have to be logged into GitHub and know what you're looking for!
So, after crawling through CHOLMOD documentation and source code and then searching through GitHub for source code that uses CHOLMOD you would find out what to do.
But for most developers who want/need a quick example, here it is below.
*Note that your mileage might vary depending on how you compiled SuiteSparse.
(You might need to use the cholmod_ variant (without the l), i.e. not cholmod_l_; and use int for indexing, not long int).
// example.cpp
#include "SuiteSparseQR.hpp"
#include "SuiteSparse_config.h"
int main (int argc, char **argv)
{
cholmod_common Common, *cc;
cholmod_sparse *A;
cholmod_dense *X, *B;
// start CHOLMOD
cc = &Common;
cholmod_l_start (cc);
/* A =
[
1.1, 0.0, -0.5, 0.7
0.0, -2.0, 0.0, 0.0
0.0, 0.0, 0.9, 0.0
0.0, 0.0, 0.0, 0.6
]
*/
int m = 4; // num rows in A
int n = 4; // num cols in A
int nnz = 6; // num non-zero elements in A
int unsymmetric = 0; // A is non-symmetric: see cholmod.h > search for `stype` for more details
// In coordinate form (COO) a.k.a. triplet form (zero-based indexing)
int i[nnz] = {0, 1, 0, 2, 0, 3}; // row indices
int j[nnz] = {0, 1, 2, 2, 3, 3}; // col indices
double x[nnz] = {1.1, -2.0, -0.5, 0.9, 0.7, 0.6}; // values
// Set up the cholmod matrix in COO/triplet form
cholmod_triplet *T = cholmod_l_allocate_triplet(m, n, nnz, unsymmetric, CHOLMOD_REAL, cc);
T->nnz = nnz;
for (int ind = 0; ind < nnz; ind++)
{
((long int *) T->i)[ind] = i[ind]; // Notes:
((long int *) T->j)[ind] = j[ind]; // (1) casting necessary because these are void* (see cholmod.h)
((double *) T->x)[ind] = x[ind]; // (2) direct assignment will cause memory corruption
} // (3) long int for index pointers corresponds to usage of cholmod_l_* functions
// convert COO/triplet to CSC (compressed sparse column) format
A = (cholmod_sparse *) cholmod_l_triplet_to_sparse(T, nnz, cc);
// note: if you already know CSC format you can skip the triplet allocation and instead use cholmod_allocate_sparse
// and assign the member variables: see cholmod.h > cholmod_sparse_struct definition
// B = ones (size (A,1),1)
B = cholmod_l_ones (A->nrow, 1, A->xtype, cc);
// X = A\B
X = SuiteSparseQR <double> (A, B, cc);
// Print contents of X
printf("X = [\n");
for (int ind = 0; ind < n; ind++)
{
printf("%f\n", ((double *) X->x)[ind]);
}
printf("]\n");
fflush(stdout);
// free everything and finish CHOLMOD
cholmod_l_free_triplet (&T, cc);
cholmod_l_free_sparse (&A, cc);
cholmod_l_free_dense (&X, cc);
cholmod_l_free_dense (&B, cc);
cholmod_l_finish (cc);
return 0;
}
Supposing you have compiled SuiteSparse successfully and you have saved example.cpp in the base directory, then the following should work (on Linux):
gcc example.cpp -I./include -L./lib -lcholmod -lspqr -lsuitesparseconfig -o example
#Add SuiteSpare libraries to your `ld` search path if necessary
LD_LIBRARY_PATH=$(pwd)/lib
export LD_LIBRARY_PATH
./example
Output:
X = [
0.353535
-0.500000
1.111111
1.666667
]