Issue with comma initialisation in Eigen c++ - c++

I have a problem where the comma initialisation indicated in the Eigen tutorial here doesn't seem to be working.
I have a system where I have a main section where a vector is initialised:
Main:
VectorXd v;
and a function:
double useVector(VectorXd &v) {
dataI = model_.find();
v << model_[dataI].v[0], model_[dataI].v[1], model_[dataI].v[2], 1;
return dataI;
}
Note: the function is used like this:
double distance = useVector(v);
Now the model_[dataI].v is a double[3] and it is definitely working. My understanding is that this is the same as this:
VectorXd v;
v << 1, 2, 3,
4, 5, 6,
7, 8, 9;
but it is not working, the code is seg-faulting at the comma initialization phase in function.
Note that this works:
v.resize(4)
v[0] = model_[dataI].v[0];
v[1] = model_[dataI].v[1];
v[2] = model_[dataI].v[2];
v[3] = 1;
as long as v is initialised, like this:
VectorXd v(4);
which immediately makes me wonder about the point of the resize (but if I take it away then it seg-faults again).
Does anyone know why this is happening?

Yes, the vector v must be resized to the appropriate size before using the comma initializer.

Related

Copying from one dimensional vector vector<int> starts to first element of two dimensional vector pair vector<pair<int,int>>matrix

I have multiple 3 one dimensional vectors (vector<int> starts, vector<int> ends, vector<int> points). Each having specific number of elements.
I want to create a two dimensional vector vector<pair<int,int>>matrix in such a sequence :
from beginning of matrix to size of start first element of matrix is elements of vector<int> starts and second element is "-1"
Append now the elements of vector<int> ends to matrix such that first element of matrix is elements of vector<int> ends and second element is "-2"
Append now the elements of vector<int> points to matrix such that first element of matrix is elements of vector<int> points and second element is Index of points.
Visual Representation :-
Input:
starts: {1, 2, 3}
ends: {4, 5, 6}
points: (7, 8, 9}
Output:
matrix: { {1, -1}, {2, -1}, {3, -1}, {4, -2}, {5, -2}, {6, -2}, {7, 0}, {8, 1}, {9, 2} }
Currently I am using a push_back with for-loop function which works perfectly fine but when the input size is big code is very slow.
Code I am using is as follows:
vector<pair<int,int>> fast_count_segments(
vector<int> starts,
vector<int> ends,
vector<int> points)
{
int i = 0;
vector<pair<int,int>>matrix;
for(i; i<starts.size(); i++) {
matrix.push_back(make_pair(starts[i],-1));
}
for(i; i<starts.size()+ends.size(); i++) {
matrix.push_back(make_pair(ends[i-starts.size()],-2));
}
for(i; i<starts.size()+ends.size()+points.size(); i++) {
matrix.push_back(make_pair(
points[i-starts.size()-ends.size()],
i-(starts.size()+ends.size())
));
}
return matrix;
}
Can you please help on how to fill the 2D vector quickly with these requirements without iterating through each element. I am using C++11. Thanks in Advance !!
Preliminary concern: As #datenwolf and others note - Your resulting data structure is not a 2D matrix (unless you mean a boolean matrix in sparse representation). Are you sure that's what you want to be populating?
Regardless, here are a few ideas to possibly improve speed:
Don't take the input vectors by value! That's useless copying... take their .data(), or their .cbegin() iterator, or take a span<int> parameter.
Use the reserve() method on the target vector to avoid multiple re-allocations.
Use .emplace_back() instead of .push_back() to construct the points in place, rather than constructing-then-moving every point. Although, to be honest, the compiler will probably optimize those constructions away, anyway.
Put the .size() values of the input vectors in local variables. This will only help if, for some reason, the compiler suspects that size will not be constant throughout the execution of the function.
Make sure you're passing optimization switches to the compiler (e.g. -O2 or -O3 to GCC and clang). This might seem obvious to you but sometimes it's so obvious you forget to check it's actually been done.
Some aesthetic comments:
No need to use the same counter for all vectors. for(int i = 0; i < whatever; i++) can be used multiple times.
No need for raw for loops, you can use for(const auto& my_element : my_vector) for the first two loops. The third loop is trickier, since you want the index. You can use std::difference() working with iterators, or go with Python-style enumeration described here.
You might consider using std::transform() with a back_emplacer output iterators instead of all three loops. No-loop code! That would mean using std::difference() in the transformer lambda instead of the third loop.
This incorporates the suggestions from #einpoklum's answer, but also cleans up the code.
std::vector<std::pair<int,int>> fast_count_segments(
std::vector<int> const & starts,
std::vector<int> const & ends,
std::vector<int> const & points)
{
std::vector<std::pair<int,int>> matrix(starts.size() + ends.size() + points.size());
auto out = std::transform(starts.cbegin(), starts.cend(),
matrix.begin(),
[](int i) { return std::pair<int,int>{i, -1}; });
out = std::transform(ends.cbegin(), ends.cend(),
out,
[](int i) { return std::pair<int,int>{i, -2}; });
int c = 0;
std::transform(points.cbegin(), points.cend(),
out,
[&c](int i) { return std::pair<int,int>{i, c++}; });
return matrix;
}
You could even write all the transforms as a single expression. Whether this is easier to read is highly subjective, so I'm not recommending it per se. (Try reading it like you would nested function calls.)
std::vector<std::pair<int,int>> fast_count_segments(
std::vector<int> const & starts,
std::vector<int> const & ends,
std::vector<int> const & points)
{
std::vector<std::pair<int,int>> matrix(starts.size() + ends.size() + points.size());
int c = 0;
std::transform(points.cbegin(), points.cend(),
std::transform(ends.cbegin(), ends.cend(),
std::transform(starts.cbegin(), starts.cend(),
matrix.begin(),
[](int i) { return std::pair<int,int>{i, -1}; }),
[](int i) { return std::pair<int,int>{i, -2}; }),
[&c](int i) { return std::pair<int,int>{i, c++}; });
return matrix;
}

How to convert an std::vector to a matrix in Eigen?

I am somewhat new to Stack Overflow and C++ so feel free to correct any errors in my code and the formatting of this question.
I am trying to make a linear regression calculator using the normal equation which involved the transposing of matrices and multiplication of vectors (and their inverses). The program is supposed to read from a csv file and pass the information from that file into a matrix and calculate the regression line. To make the job easier, I decided to use a library called Eigen for matrix-matrix multiplication.
The problem that I have run into is that the Map function can only take in an array as opposed to a std::vector.
This is what I have so far:
float feature_data[] = { 1, 1, 1, 1, 1, 1,
2, 4.5, 3, 1,4, 5};
float labels[] = { 1, 4, 3, 2, 5, 7 };
//maps the array to a matrix called "feature_data"
MatrixXf mFeatures = Map< Matrix<float, 6, 2> >(feature_data);
MatrixXf mLabels = Map< Matrix<float, 6, 1> >(labels);
//use the toArray function
std::vector<float> test_vector = { 2,1,3 };
float* test_array = toArray(test_vector);
calcLinReg(mFeatures, mLabels);
const int n = 2;
int arr[n];
system("pause");
For context, the toArray function is my unsuccessful attempt to make an array from a vector (in all honesty, it works but it returns a pointer which you can't pass into the Map function in Eigen.) calcLinReg does exactly what it sounds like: calculates the linear regression line parameters.
Is there anyway I can convert a vector to an array or convert a vector to a matrix in Eigen?
How about trying to use the vectors data() method, which gives you access to the memory array used internally by the vector, like this:
std::vector<float> test_vector = { 2,1,3 };
float* test_array = test_vector.data();
Eigen::MatrixXf test = Eigen::Map<Eigen::Matrix<float, 3, 1> >(test_array);
Or shorter:
std::vector<float> test_vector = { 2,1,3 };
Eigen::MatrixXf test = Eigen::Map<Eigen::Matrix<float, 3, 1> >(test_vector.data());
Beware The asignment actually copies the data, therefore this is safe. However, you can also directly use the data of the vector like this
std::vector<float> test_vector(3,2);
Eigen::Map<Eigen::Matrix<float, 3, 1> > dangerousVec (test_vector.data());
If vector goes out of scope the memory is deallocated and dangerousVec's data is dangeling.
Someone in a comment is asking for the case of dynamic numbers of rows and columns. This is possible, as follows:
typedef Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> MyMatrix;
size_t nrow = ...;
size_t ncol = ...;
MyMatrix M = Eigen::Map<MyMatrix>(test_vector.data(), nrow, ncol);

c++, boost, store objects in multidimensional array without default constructor

I want to store thousands of interpolation functions in a multidimensional array, preferable the one from boost. The main problem is that the interpolation function I use is a class that does not have a default constructor. This prohibits me to initialize the multidimensional array.
What I wish I could do:
double func(const double& x1, const double& x2, const double& x3)
{
return x1 + x2 + x3;
};
int main()
{
std::vector<double> x1 {0, 1, 2, 3};
std::vector<double> x2 {1.1, 1.2, 1.3, 1.4, 1.5};
std::vector<double> x3 {0, 10, 20, 30, 40};
std::vector<double> y(20, std::vector<double>(5));
boost::multi_array<Linear_interp, 2> Storage(boost::extents[4][5]);
typedef std::vector<double>::size_type vd_sz;
int n = 0;
for (vd_sz i_x1 = 0; i_x1 < x1.size(); ++i_x1) {
for (vd_sz i_x2 = 0; i_x2 < x2.size(); ++i_x2) {
for( vd_sz i_x3 = 0; i_x3 < x3.size(); ++i_x3) {
y[n][i_x3] = func(x1[i_x1], x2[i_x2], x3[i_x3]);
}
Linear_interp myInterp(x3, y);
Storage[i_x1][i_x2] = myInterp;
++n;
}
}
// Sample usage
double z = Storage[3][2].interp(23);
return 0;
}
The problem is that the class Linear_interp has no default constructor (the class is similar to this class 1), therefore boost::multi_array can not initialize the array.
Note that I initialize all interpolations inside a loop and therefore, I need to store these objects. A simple pointer to the object will not work, since the object will be overwritten in each loop.
In reality, I will have much more dimensions (atm I have 10), and multi_array is a nice container to handle these. Additionally, Interpolations in later loops, will take interpolations from previous loops (i.e. I have a recursive problem).
EDIT 1: Minor code correction.
EDIT 2: code correction: in the previous version, i did not save the "y"s which lead to unwanted results.
Well pointer WILL work. If you will declare your array as:
multi_array<Linear_interp*, 2>
to store pointers to the the objects instead of objects themselves.
Then in the loop you could allocate new object each time it would be necessary and put it to the appropriate place in the array. Just use new keyword to create new Linear_interp object inside the loop. Here is code to use inside the loop:
Storage[i_x1][i_x2] = new Linear_interp(x3, y);
I'm not a boost expert, but I'm sure there is an equivalent solution. You could do the following steps:
Make sure to build a complete "matrix" with empty innermost arrays. Something like the following (using std::vector) works for 3 dimensions:
std::vector<std::vector<std::vector<Linear_interp>>> Storage;
Storage.resize(x1.size());
for (vd_sz i_x1 = 0; i_x1 < x1.size(); i_x1++) {
Storage[i_x1].resize(x2.size());
}
At this point, Storage[i][j] is an existing, but empty std::vector<Linear_interp>. So now you can use std::vector::emplace_back or (::push_back with C++11) to fill your Storage. Going back to two dimensions and your original code, something like this will do the job:
typedef std::vector<double>::size_type vd_sz;
for (vd_sz i_x1 = 0; i_x1 < x1.size(); i_x1++) {
for (vd_sz i_x2 = 0; i_x2 < x2.size(); i_x2++) {
for( vd_sz i_x3 = 0; i_x3 < x3.size(); i_x3++) {
y[i_x3] = func(x1[i_x1], x2[i_x2], x3[i_x3]);
}
Storage[i_x1][i_x2].emplace_back(x3, y);
// or: Storage[i_x1][i_x2].push_back(Linear_interp(x3, y));
}
}
Using push_back or similar methods, will only call a copy c'tor and hence work for your non-default-constructible type Linear_interp.

Store pointer to Eigen Vector 'segment' without copy?

I have an Eigen Vector that I would like to refer to a segment at a later time (e.g. pass between functions) instead of modifying immediately.
Eigen::Matrix<float, Eigen::Dynamic, 1> vec(10);
// initialize
vec << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
I would like to create a pointer to a segment that I can refer to later. The following works but it creates a copy so any changes made to the segment are not reflected in the original vector.
const int start = 2;
const int end = 8
Eigen::Matrix<float, Eigen::Dynamic, 1> *block = new Eigen::Matrix<float, Eigen::Dynamic, 1>(end - start + 1, 1);
*block = vec.segment(start-1,end-1);
How can I keep a reference to the segment without copying?
You can use an Eigen::Map to wrap an existing segment of memory without copying. I'm not sure why you're allocating the *block object and not just using block. Using a Map it would look like
Eigen::Map<Eigen::VectorXf> block(&vec(start - 1), end - start + 1);
You then use the Map as you would a normal VectorXd, sans resizing and stuff. Simpler yet (at least according to #ggael), you can use an Eigen:Ref to refer to part of an Eigen object without inducing a copy. For example:
void times2(Eigen::Ref< Eigen::VectorXf> rf)
{
rf *= 2.f;
}
int main()
{
Eigen::Matrix<float, Eigen::Dynamic, 1> vec(10);
// initialize
vec << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
const int start = 2;
const int end = 8;
// This would work as well
//Eigen::Map<Eigen::VectorXf> block(&vec(start - 1), end - start + 1);
Eigen::Ref<Eigen::VectorXf> block = vec.segment(start, end - start + 1);
std::cout << block << "\n\n";
times2(block);
std::cout << vec << "\n";
return 0;
}
P.S. I think you're misusing the segment function. It takes a beginning position an the number of elements, i.e. (start, end-start+1).

C++ Eigen: How to concatenate matrices dynamically (pointer issue?)

I have the following problem:
I have several partial (eigen) MatrixXds I want to concatenate to another, larger, MatrixXd variable I only have as a pointer. However, both the size of the smaller matrices and their number are dynamic, so I cannot use the << operator easily.
So I'm trying the following (the smaller matrices are stored in list_subdiagrams, obviously, and basis->cols() defines the number of matrices), using Eigen's MatrixXd block funtionality:
// sd[] contains the smaller matrices to be concatenated; all are of the same size
// col defines the total number of smaller matrices
MatrixXd* ret = new MatrixXd(sd[0]->rows(), col*sd[0]->cols());
for (int i=0; i<col; ++i){
ret->block(0, i*sd[0]->cols(), sd[0]->rows(), sd[0]->cols()) = *(sd[i]);
}
This, unfortunately, appears to somehow overwrite some part of the *ret variable - for before the assignment via the block, the size is (in my test-case) correctly shown as being 2x1. After the assignment it becomes 140736006011136x140736006011376 ...
Thank you for your help!
What do you mean you don't know the size? You can use the member functions cols()/rows() to get the size. Also, I assume by concatenation you mean direct sum? In that case, you can do something like
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::MatrixXd *A = new Eigen::MatrixXd(2, 2);
Eigen::MatrixXd *B = new Eigen::MatrixXd(3, 3);
*A << 1, 2, 3, 4;
*B << 5, 6, 7, 8, 9, 10, 11, 12, 13;
Eigen::MatrixXd *result = new Eigen::MatrixXd(A->rows() + B->rows(), A->cols() + B->cols());
result->Zero(A->rows() + B->rows(), A->cols() + B->cols());
result->block(0, 0, A->rows(), A->cols()) = *A;
result->block(A->rows(), A->cols(), B->rows(), B->cols()) = *B;
std::cout << *result << std::endl;
delete A;
delete B;
delete result;
}
So first make sure it works for 2 matrices, test it, then extend it to N.