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
]
Related
I have "oneMKL" integrated with Visual Studio 2022 and I would like to know how it performs for Matrix-vector multiplications, and compare it with a sequential implementation:
E.g. If I have this sequential matrix-vector multiplication in C++, how can I do the same for the same matrix-vector with MKL #include "mkl.h"?
#include <math.h>
#include <iostream>
using namespace std;
#define MAX 3
float matA[3][3]={{1.1,2.2,3.3},{4.4,5.5,6.6},{7.7,8.8,9.9}};
float matB[3]={1,2,3};
float matC[3];
float sequencial_multiplication(float matA[MAX][MAX],float matB[MAX]){
for (int i = 0; i < MAX; i++)
for (int j = 0; j < MAX; j++)
matC[i] += matA[i][j] * matB[j];
for(int i=0;i<MAX;i++)
cout<<matC[i]<<endl;
return 0;
}
int main()
{
sequencial_multiplication(matA,matB);
}
First, let me lower your expectations.
MKL is not a library to be used casually, it needs a lot of boilerplate in addition to what is required by using BLAS (the historic linear algebra interface).
Also, it is not the best option to operate small matrices, like 3x3, or 4x4, for that it might be better to write them manually if nothing else to avoid the non-inlined BLAS (or MKL) function. I hope your real application is to multiply big matrices.
If it looks complicated and convoluted is because it is.
There is a lot of history there, starting from the fact that the original BLAS was written in Fortran and still has to work with Fortran to this day.
There is no real BLAS or MKL for C++, the interface is defined for C.
Using C++, you can take advantage of the many BLAS wrappers written for BLAS, such as Boost.UBLAS or Multi. (See below for more).
But here I am giving you the recipe, without getting too much into the details to answer your question precisely.
This is the full program, I left your code for reference:
// my_gemv.cpp
#include <iostream>
extern "C" {
void sgemv_(const char& trans, int32_t const& nr, int32_t const& nc, float const& a, float const* A, int32_t const& lda, float const* X, int32_t const& incx, float const& beta, float* Y, int32_t const& incy);
}
#define MAX 3
void matrix_vector_multiplication_with_addition(float matA[MAX][MAX], float vecB[MAX], float vecC[MAX]) {
for(int i = 0; i != MAX; i++)
for(int j = 0; j != MAX; j++)
vecC[i] += matA[i][j] * vecB[j];
}
void blas_matrix_vector_multiplication_with_addition(float matA[MAX][MAX], float vecB[MAX], float vecC[MAX]) {
sgemv_('T', MAX, MAX, 1.0, &matA[0][0], MAX, &vecB[0], 1, 1.0, &vecC[0], 1);
}
int main() {
float matA[3][3] = {
{1.1, 2.2, 3.3},
{4.4, 5.5, 6.6},
{7.7, 8.8, 9.9},
};
float vecB[3] = {1.0, 2.0, 3.0};
float vecC[3] = {0.0, 0.0, 0.0};
matrix_vector_multiplication_with_addition(matA, vecB, vecC);
std::cout <<"vecC[] = {" << vecC[0] <<", "<< vecC[1] <<", "<< vecC[2] <<"}"<<std::endl;
float mkl_vecC[3] = {0.0, 0.0, 0.0};
blas_matrix_vector_multiplication_with_addition(matA, vecB, mkl_vecC);
std::cout <<"vecC[] = {" << mkl_vecC[0] <<", "<< mkl_vecC[1] <<", "<< mkl_vecC[2] <<"}"<<std::endl;
}
You might ask, where is MKL here?
It is not really there, I am using the fact that MKL uses a standard ABI interface for the linear algebra operators.
Why the extern "C"? Because you are using an interface defined for another language.
If you try to produce an executable it will not be able to "link" because someone needs to provide the sgemv_ "symbol".
Why the _? Because, well, Fortran. I am digressing.
The next steps may be different in Windows but maybe you can translate:
c++ my_gemv.cpp -L/opt/intel/oneapi/mkl/2023.0.0/lib/intel64 -lmkl_rt -o my_gemv
and you need to tell the executable where to find the library (again!)
export LD_LIBRARY_PATH=/opt/intel/oneapi/mkl/2023.0.0/lib/intel64
./my_gemv
or perhaps in Windows, you are better off linking a static version of MKL. I don't know.
If everything goes well, the program will print this (manual loop and MKL will give the same answer):
vecC[] = {15.4, 35.2, 55}
vecC[] = {15.4, 35.2, 55}
What's next? The answer I gave is really just the start, it will also free you from really needing MKL, and you can use other BLAS implementations.
You can use the header files from mkl, or from cblas, etc.
This can give you more convenience but it can lock you up on using MKL or extensions that are not open source, etc.
Don't like all the command line stuff? You will need a build system, for example, CMake https://cmake.org/cmake/help/latest/module/FindBLAS.html
Don't like the C syntax? Use a C++ BLAS wrapper, they usually can be a link to any implementation of BLAS, including MKL.
As I said above you can use a C++ wrapper to use BLAS (or BLAS in MKL) sanely, this is the example using my library Multi.
As you can see the library offers several modes, one is to "refer" to your c-arrays to use the library and another is to use the arrays from the library.
Compile it with:
c++ -Ipath_to_Multi my_gemv_multi.cpp -L/opt/intel/oneapi/mkl/2023.0.0/lib/intel64 -lmkl_rt
// my_gemv_multi.cpp
#include <multi/adaptors/blas/gemv.hpp>
#include <multi/array.hpp>
int main() {
float matA[3][3] = {
{1.1, 2.2, 3.3},
{4.4, 5.5, 6.6},
{7.7, 8.8, 9.9},
};
float vecB[3] = {1.0, 2.0, 3.0};
float vecC[3] = {0.0, 0.0, 0.0};
namespace multi = boost::multi;
{ // make references to c-arrays
multi::array_ref<float, 2> A{matA};
multi::array_ref<float, 1> B{vecB};
multi::array_ref<float, 1> C{vecC};
multi::blas::gemv(1.0, A, B, 0.0, C); // C is output
}
{ // make references to c-arrays
auto const& A = multi::ref(matA); // deduce element type and dimensionality
auto const& B = multi::ref(vecB);
auto&& Cref = multi::ref(vecC);
multi::blas::gemv(1.0, A, B, 0.0, Cref); // vecC holds the result
}
{ // one-liner
multi::blas::gemv(1.0, multi::ref(matA), multi::ref(vecB), 0.0, multi::ref(vecC)); // vecC holds the result
}
{ //one-liner with output assignment syntax
multi::ref(vecC) = multi::blas::gemv(1.0, multi::ref(matA), multi::ref(vecB));
}
{ // using the library, not references to c-arrays
multi::array<float, 2> A = {
{1.1, 2.2, 3.3},
{4.4, 5.5, 6.6},
{7.7, 8.8, 9.9},
};
multi::array<float, 1> B = {1.0, 2.0, 3.0};
multi::array<float, 1> C = multi::blas::gemv(1.0, A, B); // create (allocate) the result in C
}
{
multi::array<float, 2> A = {
{1.1, 2.2, 3.3},
{4.4, 5.5, 6.6},
{7.7, 8.8, 9.9},
};
multi::array<float, 1> B = {1.0, 2.0, 3.0};
auto C =+ multi::blas::gemv(1.0, A, B); // create (allocate) the result in C
}
}
I am trying to use SuiteSparse SPQR to solve a linear equation system x = A\b; my A matrix is sparse and it is a rectangular matrix so I chose SPQR to solve this.
I built SuiteSparse using MS Visual Studio 2012 on Windows 7 x64 using those provided by https://github.com/jlblancoc/suitesparse-metis-for-windows.
In order to test the function, I modified the spqr_example project to allocate tripets before converting to sparse matrix, instead of originally reading input from stdin to create a sparse matrix. I input a small A and b matrix for testing. The program compiled successfully. I debugged the program and found that my call to cholmod_allocate_triplet() has failed because in the declaration of this function it has this code below:
RETURN_IF_NULL_COMMON (NULL) ;
This always return false (even though my common starts successfully).
I don't want to explicitly make change to this line, as I might have make mistake somewhere or I forgot to do something I have to do because I am new to use the library.
Can anybody help give me some suggestion on how to make my program run properly? My code below is modified from the provided spqr_example. Thank you very much.
#include <iostream>
#include "SuiteSparseQR.hpp"
int main (int argc, char **argv)
{
cholmod_common Common, *cc ;
cholmod_sparse *A ;
cholmod_dense *X, *B, *Residual ;
double rnorm, one [2] = {1,0}, minusone [2] = {-1,0} ;
int mtype ;
// start CHOLMOD
cc = &Common ;
cholmod_l_start (cc) ;
// load A
//A = (cholmod_sparse *) cholmod_l_read_matrix (stdin, 1, &mtype, cc) ;
// A = [ 1 0 0 0;
// -1 1 0 0; ...
// 0 -1 1 0; ...
// 0 0 -1 1; ...
// 0 0 0 -1];
int row[] = {0, 1, 1, 2, 2, 3, 3, 4};
int col[] = {0, 0, 1, 1, 2, 2, 3, 3};
double val[] = {1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0};
int numEq = 5;
int numElement = 8;
int numSol = 4;
double b[] = {5.0, -5.0, 2.0, 1.0, 0.0};
cholmod_triplet* triplet = cholmod_allocate_triplet(5,4,5*4,0,CHOLMOD_REAL,cc);
int * triplet_i = (int *)(triplet->i);
int * triplet_j = (int *)(triplet->j);
double * triplet_x = (double *)(triplet->x);
for (int ne=0; ne<numElement; ne++)
{
triplet_i[triplet->nnz] = row[ne];
triplet_j[triplet->nnz] = col[ne];
triplet_x[triplet->nnz] = val[ne];
triplet->nnz++;
}
// Convert triplet to sparse matrix
A = cholmod_triplet_to_sparse(triplet, numElement, cc);
cholmod_free_triplet(&triplet, cc);
// B = ones (size (A,1),1)
//B = cholmod_l_ones (A->nrow, 1, A->xtype, cc) ;
B = cholmod_l_zeros(numEq, 1, CHOLMOD_REAL, cc);
for (int ne=0; ne<numEq; ne++)
{
((double *)(B->x))[ne] = val[ne];
}
// X = A\B
X = SuiteSparseQR<double>(A,B,cc);
//X = SuiteSparseQR <double> (A, B, cc) ;
// Print out the result
double *sol = static_cast<double *>(malloc(sizeof(X->x)));
sol = (double *)(X->x);
for (int r=0; r<numSol; r++)
{
std::cout << "x[" << r << "] = " << sol << std::endl;
sol++;
}
///// END HERE
// rnorm = norm (B-A*X)
Residual = cholmod_l_copy_dense (B, cc) ;
cholmod_l_sdmult (A, 0, minusone, one, X, Residual, cc) ;
rnorm = cholmod_l_norm_dense (Residual, 2, cc) ;
printf ("2-norm of residual: %8.1e\n", rnorm) ;
printf ("rank %ld\n", cc->SPQR_istat [4]) ;
// free everything and finish CHOLMOD
cholmod_l_free_dense (&Residual, 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) ;
}
I have finally find out why my program broke after the line below
cholmod_triplet* triplet = cholmod_allocate_triplet(5,4,5*4,0,CHOLMOD_REAL,cc);
as the result of the cholmod_allocate_triplet() internally calling RETURN_IF_NULL_COMMON (NULL), which return false.
The reason is that I start the process calling
cholmod_l_start (cc) ;
which is the long int version of cholmod_start().
To fix the problem, I have to call cholmod_l_allocate_triplet() instead of cholmod_allocate_triplet() as well as change all other functions to use cholmod_l instead of only calling cholmod_
I want to run the LP solver in GLPK in a parallel_for loop. The problems are all independent of each other so there shouldn't be any interference.
Here is an example code that fails, this is essentially the example code from the glpk wikibook but wrapped in a parallel_for loop. Any help will be appreciated
//#include <stdio.h> /* C input/output */
//#include <stdlib.h> /* C standard library */
#include <iostream>
#include <glpk.h> /* GNU GLPK linear/mixed integer solver */
#include <ppl.h>
using namespace concurrency;
using namespace std;
void main()
{
parallel_for(0, 10, [](int i){
/* declare variables */
glp_prob *lp;
int *ia = new int[4];
int *ja = new int[4];
double *ar = new double[4];
double z, x1, x2;
/* create problem */
lp = glp_create_prob();
glp_set_prob_name(lp, "minimax");
glp_set_obj_dir(lp, GLP_MAX);
/* fill problem */
glp_add_rows(lp, 2);
//glp_set_row_name(lp, 1, "p");
glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 1.0);
//glp_set_row_name(lp, 2, "q");
glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 2.0);
glp_add_cols(lp, 2);
//glp_set_col_name(lp, 1, "x1");
glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
glp_set_obj_coef(lp, 1, 0.6);
//glp_set_col_name(lp, 2, "x2");
glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
glp_set_obj_coef(lp, 2, 0.5);
ia[1] = 1, ja[1] = 1, ar[1] = 1.0; /* a[1,1] = 1 */
ia[2] = 1, ja[2] = 2, ar[2] = 2.0; /* a[1,2] = 2 */
ia[3] = 2, ja[3] = 1, ar[3] = 3.0; /* a[2,1] = 3 */
ia[4] = 2, ja[4] = 2, ar[4] = 1.0; /* a[2,2] = 1 */
glp_load_matrix(lp, 4, ia, ja, ar);
/* solve problem */
glp_simplex(lp, NULL);
/* recover and display results */
z = glp_get_obj_val(lp);
x1 = glp_get_col_prim(lp, 1);
x2 = glp_get_col_prim(lp, 2);
printf("z = %g; x1 = %g; x2 = %g\n", z, x1, x2);
/* housekeeping */
glp_delete_prob(lp);
glp_free_env();
});
system("pause");
}
You're calling glp_free_env from inside each thread, while the library is still actively doing work in other threads. That won't work well -- you're yanking the rug out from under threads working hard..
Instead call it only after all threads completed computation (join them). For this simple example, you can probably skip the cleanup step altogether.
I have found the problem. The issue is with the GLPK source code, there are a couple of routines that are not reenterable causing some big issues. This is documented here: http://en.wikibooks.org/wiki/GLPK/Using_the_GLPK_callable_library . There is also a fix in place but it requires rebuilding it. Note that this only works with version 4.50 of GLPK and older, newer versions have a slightly different layout.
While Ben was completely correct, making this change to the library solves all issues and lets you free the environment inside the loop.
Can anyone please give me a simple example of how to add elements to a triplet matrix using CHOLMOD.
I have tried something like this:
cholmod_triplet *A;
int k;
void add_A_entry(int r, int c, double x)
{
((int*)A->i)[k] = r;
((int*)A->j)[k] = c;
((double*)A->x)[k] = x;
k++;
}
int main()
{
k = 0;
cholmod_common com;
cholmod_start(&com);
A = cholmod_allocate_triplet(202, 202, 202*202, -1, CHOLMOD_REAL, &com);
add_A_entry(2, 2, 1.);
add_A_entry(4, 1, 2.);
add_A_entry(2, 10, -1.);
cholmod_print_triplet(A, "A", &com);
cholmod_finish(&com);
return 0;
}
However, this doesn't add any elements to the matrix. I simply get the output:
CHOLMOD triplet: A: 202-by-202, nz 0, lower. OK
Of course, I have tried to find the solution both by searching and in the CHOLMOD documentation, but I found no help.
cholmod_allocate_triplet() sets A->nzmax, which in your case is 202*202. That just defines the space available to add triplets. The actual number of triplets in the matrix is A->nnz, which gets set to zero by cholmod_allocate_triplet().
The A->nnz should be used instead of your variable k.
Tim Davis (CHOLMOD author)
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();