Eigen error when initializing dynamic matrix - c++

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.

Related

3D Vector - "No instance of overload function?"

Still relatively new to vectors in C++, the aim of this function is to take 4 arguments, 3 of which define the (x , y , z) position of the data being written, and the 4th being the value that is to be written.
as Requested, a picture of the errors is listed:
Picture of code listed above
The issue is under the "push_back" code. the "." after yy.push and xx.push is giving the error "no instance of overloaded function".
If somebody could explain what this means and how to fix it I would greatly appreciate it! :)
double datawrite(vector<unsigned int> xx, vector<unsigned int> yy,
vector<unsigned int> zz, double val) {
//Writes data to the 3d Vector
//finds coordinates for data
vector< vector< vector<unsigned int > > > xx;
vector< vector<unsigned int> > yy;
vector<unsigned int> zz;
//Writes value at proper position
zz.push_back(val);
yy.push_back(zz);
xx.push_back(yy);
//outputs value from vector
return val;
}
So you want a 3d matrix of doubles? First you need to create it:
#include <vector>
std::vector<vector<vector<double>>> matrix;
This creates a 3d matrix, but with 0 size. Next, when you add data to the matrix, you need to make sure the matrix is big enough:
// Co-ords are integers
double datawrite(int x, int y, int z, double val)
{
// Make sure vectors are large enough
if (matrix.size() < x+1) matrix.resize(x+1);
if (matrix[x].size() < y+1) matrix[x].resize(y+1);
if (matrix[x][y].size() < z+1) matrix[x][y].resize(z+1);
// Store the value
matrix[x][y][z] = val;
return val;
}
However, this is a bit messy and leaves the matrix in an incomplete state. For example, if you call datawrite(2, 3, 4, 9.9); this may appear that all indexes < 2,3,4 would be valid, but they are not. For example trying to read matrix[0][0][0] will give you an error.
You could work around this with a dataread function that checks the sizes of the vectors before trying to read from them.
If you know ahead of time how large the matrix is, you can create the entire matrix at once like this:
vector<vector<vector<double>>> matrix(10, vector<vector<double>>(10, vector<double>(10)));
This creates a complete 10x10x10 matrix. This ensures all indexes < 10 will be valid. I prefer this method. Then your function becomes:
double datawrite(int x, int y, int z, double val)
{
// Make sure indexes are valid
if (x >= matrix.size() || y >= matrix[x].size() || z >= matrix[x][y].size()) {
// Up to you what to do here.
// Throw an error or resize the matrix to fit the new data
}
// Store the value
matrix[x][y][z] = val;
return val;
}

Add a matrix of 2x2 into a vector in c++

I am trying to fill a vector with a matrix of values in c++. I'm not very self confident with this procedure (I don't know well about pointers and I don't know if I need it here) however I am trying this
int auxMat[gray.rows][gray.cols];
vector<int> collectionSum;
collectionSum.push_back(auxMat);
When I try to compile I receive an error which says
invalid arguments 'Candidates are: void push_back(const int &)
Can anyone tell me wether it's possible to do, how can I solve it?
I read something about erasing cache memory, changing my eclipse compiler, my c++ version, however I don't think the problem is so big.
You cannot push back a matrix into a vector. What you can do is preallocate memory for your vector (for speeding things up) then use the std::vector<>::assign member function to "copy" from the matrix into the vector:
vector<int> collectionSum(gray.rows * gray.cols); // reserve memory, faster
collectionSum.assign(*auxMat, *auxMat + gray.rows * gray.cols);
This should be pretty fast. Otherwise, you can push back each individual element in a loop.
EDIT
See May I treat a 2D array as a contiguous 1D array? for some technicalities regarding possible undefined behaviour (thanks #juanchopanza for the comment). I believe the code is safe, due to the fact that the storage of the matrix is contiguous.
Because the array auxMat is continuous in memory, you can just copy it directly from memory into your vector. Here, you are telling the vector constructor to copy from the start of auxMat until its end in memory using pointer arithmetic:
std::vector<int> collectionSum(auxMat, auxMat + (gray.rows * gray.cols));
EDIT:
Sorry, I read your question as being a 1D array (int*) rather than a 2D (int**) array. I honestly recommend switching over to a 1D array because often it is faster and easier to work with. Depending on whether your using row-first order or column-first order, you can access the element you want by:
elem = y * width + x; // for row-first order
elem = x * height + y; // for column-first order
For instance:
// Create a 3x3 matrix but represent it continuously as a 1D array
const int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
const unsigned width = 3;
const unsigned height = 3;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
printf("%d ", A[y * width + x]);
}
printf("\n");
}

Filter points inside of a sphere with Eigen

I have a set of 3D points, and I need to compute which ones are the nearest to a given point p. I am wondering which could be the correct way to do it in Eigen. So far, I have:
Matrix<double, Dynamic, 3> points; // The set of 3D points
Matrix<double, 1, 3> p;
// Populate the "points" matrix
...
// Fill a matrix with several copies of "p" in order to match the size
of "points"
Matrix<double, Dynamic, 3> pp(points.rows(), 3);
pp = Matrix<double, Dynamic, 1>::Ones(points.rows, 1) * p;
Matrix<double, Dynamic, 1> sq_distances = (points - pp).rowwise.squaredNorm();
Matrix<bool, Dynamic, 1> nearest_points = sq_distances < (dist_threshold * dist_threshold);
Can I then have some way of extracting the points in "points" that fullfill the "nearest_points" condition like in
Matrix<double, Dynamic, 3> nearest = points(nearest_points);
?
For the nearest I'd suggest:
int i;
double sqdist = (points.rowwise()-p).rowwise().squaredNorm().minCoeff(&i);
nearest = points.row(i);
For the ones in a given ball, you currently have to write one loop yourself:
ArrayXd sqdists = (points.rowwise()-p).rowwise().squaredNorm();
Matrix<double,Dynamic,3> nearests( (sqdists<sqradius).count(), 3 );
int count = 0;
for(int i=0; i<points.rows(); ++i)
if(sqdists(i)<sqradius)
nearests.row(count++) = points.row(i);

Convert Eigen Matrix to C array

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();

A function to populate an array with maps

I'm pretty new to C++ so I'm not sure I'm going about this problem in the right way. I'm dealing with a 3D array of voxel data and I would like to create a parallel data structure to store isosurface normal vectors. Memory efficiency is an issue so I thought to use a 2D array of maps, which are indexed by an integer and contain a 3D vector.
The idea being the 2D array indexes every x and y coordinate and the maps index only the z coordinates containing a value (typically between 0 and 3 values dispersed along each row of the z axis).
Question 1: how do I create a 2D array of maps like std::map<int, Vector3f> surfaceNormals; ?
Question 2: My idea is declare the 2D array global then to populate it with a function which deals with it by pointer and creates a map for each array cell, is the code below on the right track? the ?????'s indicate where i'm not sure what to put given my uncertainty about Question 1.
In particular am I managing pointers/references/values correctly such as to actually end up storing all the data I need?
????? isoSurfaces1 [256][100];
????? *extractIS(float Threshold, ????? *pointy){
????? *surfacePointer = pointy;
for loop over x and y {
std::map<int, Vector3f> surfaceNormals;
for loop over z {
[ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfaceNormals[zi] = newNormalVector;
}
surfacePointer[x][y] = surfaceNormals;
}
return surfacePointer;
}
extractIS(0.45, isoSurfaces1);
If i understood you correctly, you want to use the coordinate as a std::map key?
You could just create 1 dimensional std::map, and convert the XYZ coordinates into 1 dimensional coordinate system:
int pos1d = z*max_x*max_y+y*max_x+x;
and then just put that to the map key.
Edit: or you could just use a struct with x,y,z as integers as Space_C0wb0y showed, but that will of course take 3x more memory per std::map key, also note that the example i showed will have the maximum cube size: 1625x1625x1625 (if unsigned int), so if you need longer coordinates then use a struct, but note that with structs you have to write comparisor function for the std::map key datatype.
Edit3:
I think this is what you are looking for, as i noticed you used max 256 coordinate value, here is what i came up with:
// NOTE: max 256x256x256 cube coordinates with this struct. change unsigned char to short or int etc if you need larger values.
// also note that if you change to something else than unsigned char, you cant use nor compare the union: v1.Pos > v2.Pos anymore.
// (unless you use unsigned short for each coordinate, and unsigned __int64 for the union Pos value)
union PosXYZ {
struct {
unsigned char x, y, z, padding; // use full 32bits for better performance
};
unsigned __int32 Pos; // assure its 32bit even on 64bit machines
PosXYZ(unsigned char x, unsigned char y, unsigned char z) : x(x), y(y), z(z), padding(0) {} // initializer list, also set padding to zero so Pos can be compared correctly.
};
inline bool operator>(const PosXYZ &v1, const PosXYZ &v2){
return v1.Pos > v2.Pos;
}
typedef map<PosXYZ, Vector3f, greater<PosXYZ> > MyMap;
void extractIS(float Threshold, MyMap &surfacePointer){
for loop over x and y {
for loop over z {
// [ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfacePointer[PosXYZ(x,y,z)] = newNormalVector;
}
}
}
MyMap isoSurfaces1;
extractIS(0.45, isoSurfaces1);
Another way to do this std::map key struct is to just use plain integer value, which you would generate via your own function similar to: ((x << 16) | (y << 8) | z), this will simplify things a little since you dont need the comparisor function for std::map anymore.
#define PosXYZ(x,y,z) (((x) << 16) | ((y) << 8) | (z)) // generates the std::map key for 256x256x256 max cube coords.
typedef map<unsigned __int32, Vector3f, greater<unsigned __int32> > MyMap;
void extractIS(float Threshold, MyMap &surfacePointer){
for loop over x and y {
for loop over z {
// [ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfacePointer[PosXYZ(x,y,z)] = newNormalVector;
}
}
}
MyMap isoSurfaces1;
extractIS(0.45, isoSurfaces1);
First off, a map has a higher memory overhead than a vector. This brings up the question, how many elements are there? Is it feasible to have vectors that are partly empty? Consider the following implementation:
struct 3dvec {
3dvec(int x, int y, int z) : x(x), y(y), z(z) {}
int x;
int y;
int z;
};
std::vector<3dvec> empty_z_vector(4, 3dvec(0, 0, 0));
std::vector< std::vector<3dvec> > data(width*height, empty_z_vector);
You simply keep all values in memory, based on the assumption that only a few of them will be empty, and there will never be more than 4 z-values. You can access the 3dvec at position X, Y, Z like this:
data[X + Y*width][Z]
This is making a lot of assumptions, but in the end, you will have to compare possible solution, because the feasibility depends on the data.