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

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

Related

How to Convert Eigen Matrix to C/C++ Array

In Eigen C/C++ Library, how to converter the operation result (example below) from Eigen Matrix to C/C++ Array?
Example:
const Eigen::MatrixXf mat = Eigen::Map<Eigen::MatrixXf>( array_C_input , 3, 3);
const Eigen::MatrixSquareRootReturnValue<Eigen::MatrixXf> result = m.sqrt();
float* array_C_output = (float*) result; // Error: convert sqrt output to C array
If you want to compute the matrix root of a matrix passed as C-style array and handle the result like a C-style array, you can either store the result into a MatrixXf and use the data() member of that matrix:
Eigen::MatrixXf matrix_root = Eigen::MatrixXf::Map( array_C_input , 3, 3).sqrt();
float* array_C_output = matrix_root.data();
Alternatively, if you already have memory allocated for the result, you can map the output to that:
void foo(float* output_array, float const* input_array) {
Eigen::MatrixXf::Map( output_array , 3, 3) =
Eigen::MatrixXf::Map( input_array , 3, 3).sqrt();
}
Note that Matrix::sqrt computes the matrix-root, i.e., if S = A.sqrt(), then S*S == M. If you want an element-wise root, you need to use
Eigen::ArrayXXf::Map( input_array , 3, 3).sqrt()

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;
}

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).

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

How to initialize 3D array in C++

How do you initialize a 3d array in C++
int min[1][1][1] = {100, { 100, {100}}}; //this is not the way
The array in your question has only one element, so you only need one value to completely initialise it. You need three sets of braces, one for each dimension of the array.
int min[1][1][1] = {{{100}}};
A clearer example might be:
int arr[2][3][4] = { { {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} },
{ {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} } };
As you can see, there are two groups, each containing three groups of 4 numbers.
Instead of static multidimensional arrays you should probably use one-dimensional array and calculate the index by multiplication. E.g.
class Array3D {
size_t m_width, m_height;
std::vector<int> m_data;
public:
Array3D(size_t x, size_t y, size_t z, int init = 0):
m_width(x), m_height(y), m_data(x*y*z, init)
{}
int& operator()(size_t x, size_t y, size_t z) {
return m_data.at(x + y * m_width + z * m_width * m_height);
}
};
// Usage:
Array3D arr(10, 15, 20, 100); // 10x15x20 array initialized with value 100
arr(8, 12, 17) = 3;
std::vector allocates the storage dynamically, which is a good thing because the stack space is often very limited and 3D arrays easily use a lot of space. Wrapping it in a class like that also makes passing the array (by copy or by reference) to other functions trivial, while doing any passing of multidimensional static arrays is very problematic.
The above code is simply an example and it could be optimized and made more complete. There also certainly are existing implementations of this in various libraries, but I don't know of any.
Here's another way to dynamically allocate a 3D array in C++.
int dimX = 100; int dimY = 100; int dimZ = 100;
int*** array; // 3D array definition;
// begin memory allocation
array = new int**[dimX];
for(int x = 0; x < dimX; ++x) {
array[x] = new int*[dimY];
for(int y = 0; y < dimY; ++y) {
array[x][y] = new int[dimZ];
for(int z = 0; z < dimZ; ++z) { // initialize the values to whatever you want the default to be
array[x][y][z] = 0;
}
}
}
Everyone seems to forget std::valarray. It's the STL template for flat multidimensional arrays, and indexing and slicing them.
http://www.cplusplus.com/reference/std/valarray/
No static initialization, but is that really essential?