For 1D resizing, the Eigen documentation suggests I use the following method to resize an array:
using Eigen;
MatrixXf X(2,2) << 1,2,3,4;
Map<RowVectorXf> v1(X.data(), X.size());
Except I have a templated vector, and can't use RowVectorXf
using Eigen;
template<class num>
void my_func(){
Matrix<num,Dynamic,Dynamic> X(2,2) << 1,2,3,4;
Map<Matrix<num,Dynamic,Dynamic>> unraveled(X.data(),X.size());
}
The example above fails with the following message:
error: static assertion faild: YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX
How do I obtain a flat view of an eigen matrix in a templated function?
The issue is that the Map is 2D and not 1D as you really want:
Map<Matrix<num,Dynamic,1>> unraveled(X.data(),X.size());
Then now it's a vector operation on your original X matrix.
Related
I am very new to Eigen, and have the following minimal example of my issue.
#include <iostream>
#include <Eigen/Dense>
template <typename T>
struct arr_holder
{
explicit arr_holder(Eigen::ArrayBase<T> const &loc)
: local_arr {decltype(local_arr)::Zero(loc.rows(), loc.cols())}
{
do_calc(loc);
}
auto do_calc(Eigen::ArrayBase<T> const &data) -> void
{
auto &&data_col = data.col(0);
auto &&local_col = local_arr.col(0);
std::cout << data_col - local_col << '\n';
}
private:
Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic> local_arr;
};
int main() {
Eigen::Array<double, 3, 3> data;
data << 1.0, 2.0, 3.0, 2.0, 5.0, 7.0, 2.0, 5.0, 7.0;
auto arr = arr_holder(data);
}
This code fails to compile with Eigen 3.3.4 and Clang 5.0.1, with the error
eigen/Eigen/src/Core/AssignEvaluator.h:833:3: error: static_assert failed "YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES"
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src)
stemming from the line in do_calc where I am attempting to subtract the columns.
My question is, why doesn't this work? My (naive) understanding would lead me to believe that I can perform an element-wise subtraction of columns between the locally zeroed 2D-array and the data array, since the columns appear to have the same shape (checked by printing out the number of rows and columns of data_col and local_col), and the type is the same.
What am I misunderstanding here, and what is the correct way to perform such column-wise operations between a class-owned 2D array and a 2D array passed as an argument? My suspicion is that I am misusing Dynamic arrays?
You are subtracting an array of double and a array of 3x3 arrays, which is not allowed. Perhaps you meant to write:
Eigen::Array<typename T::Scalar, Eigen::Dynamic, Eigen::Dynamic> local_arr;
The Eigen documentation is filled with examples illustrating how one should write a general function accepting a matrix:
template <typename Derived>
void print_cond(const MatrixBase<Derived>& a)
The reason to use MatrixBase as opposed to Matrix is that all dense Eigen matrix expressions derive from MatrixBase. So, for instance, if I pass a block of a matrix
print_cond ( A.block(...));
Then using the signature const MatrixBase<Derived>& a avoids creating a temporary. Conversely, if we had declared the function with the signature
template <typename T, int rows, int cols>
void print_cond(const Matrix<T,rows,cols>& a)
then Eigen would have to convert the block type to a matrix before passing it to the function, meaning that an unnecessary temporary would have to be created.
Please correct me if this understanding is incorrect...
With that in mind, one of the benefits of the second approach is that we can get compile time checks on the dimensions of the matrix (assuming they are fixed, not dynamic).
What I can't find in the documentation is an example with the generality of the first approach (which helps avoid temporary creation), but which has complie time checks on the type and dimensions of the matrix. Could somebody please tell me how to do that?
Just for completeness, Marc and ggael are suggesting something like this
#include <iostream>
#include "Eigen/Dense"
using namespace Eigen;
using T = double;
const int rows = 5;
const int cols = 3;
template<typename Derived>
void print_cond(const MatrixBase <Derived> &a) {
/* We want to enforce the shape of the input at compile-time */
static_assert(rows == Derived::RowsAtCompileTime);
static_assert(cols == Derived::ColsAtCompileTime);
/* Now that we are guaranteed that we have the
* correct dimensions, we can do something... */
std::cout << a;
}
int main() {
print_cond(Matrix<T, rows, cols>::Ones());
/* These will not compile */
// print_cond(Matrix<T, rows + 1, cols>::Ones());
// print_cond(Matrix<T, rows, cols + 1>::Ones());
// print_cond(Matrix<T, rows + 1, cols + 1>::Ones());
return 0;
}
I am trying to compute the element-wise natural logarithm of a vector using the Eigen library, here's my code:
#include <Eigen/Core>
#include <Eigen/Dense>
void function(VectorXd p, VectorXd q) {
VectorXd kld = p.cwiseQuotient(q);
kld = kld.log();
std::cout << kld << std::endl;
}
However when compiling with
g++ -I eigen_lib -std=c++11 -march=native test_eigen.cpp -o test_eigen
I get
test_eigen.cpp:15:23: error: invalid use of incomplete type ‘const class Eigen::MatrixLogarithmReturnValue<Eigen::Matrix<double, -1, 1> >’ kld = kld.log();
What is it that I'm missing?
VectorXd::log() is MatrixBase<...>::log() which computes the matrix logarithm of a square matrix. If you want the element-wise logarithm you need to use the array functionality:
kld = kld.array().log();
// or:
kld = log(kld.array());
If all your operations are element-wise, consider using ArrayXd instead of VectorXd:
void function(const Eigen::ArrayXd& p, const Eigen::ArrayXd& q) {
Eigen::ArrayXd kld = log(p/q);
std::cout << kld << std::endl;
}
To do element-wise operations on Eigen objects (Matrix or Vector), you need to specify that. This is done by by adding .array() to the Matrix/Vector object like so:
kld = kld.array().log();
See this tutorial.
P.S. MatrixLogarithmReturnValue is part of the unsupported modules for matrix functions.
I am using a library where a function takes array references and updates them:
void foo(ArrayXXd A&)
However, in my code I want to use
Matrix<double,Dynamic,Dynamic>
How can I call the function foo with a matrix? Can I map the matrix to an array somehow?
This is the compiler error:
error: invalid initialization of reference of type ‘Mat& {aka Eigen::Array<double, -1, -1>&}’ from expression of type ‘Eigen::Matrix<double, -1, -1>’
I did the following that seems to work, but I don't know if it is a general solution (different memory layouts and so on).
//X_IN is a Matrix<double,Dynamic,Dynamic> &
//Map Matrix to pointer
X_pntr = X_IN.data();
//Map pointer to Array
ArrayXXd X_array = Map<ArrayXXd>(X_pntr,X_IN.rows(),X_IN.cols());
foo(X_array);
Most objects in Eigen are expressions (more specifically, objects derived from MatrixBase). If you want to write a function that works for any type of Matrix/Array etc. and not be restricted only to e.g. Array, you need to write it in the following form:
template<typename T>
void foo(Eigen::MatrixBase<T>& A)
{
// do something here with A
}
Now you can invoke foo with any kind of object, for example foo(A*A), where A is a MatrixXd, or MatrixXf or ArrayXd, you get the idea. See the official documentation for more details:
http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
After reading your comment I can just come up with this solution:
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> m(2,2);
m << 1,2,3,4;
Eigen::ArrayXXd tmp = m; // convert into array (via copy)
foo(tmp); // modify tmp
m = tmp; // copy back into m
cout << m; // now m is modified
When Eigen will support move semantics, then you will be able to use std::move instead of making 2 copies.
How can I initialize a SparseVector in Eigen ? The following code:
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Sparse>
using namespace Eigen;
SparseVector<float> vec(3);
main()
{
vec(0)=1.0;
}
gives me the following error
error: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
vec(0)=1.0;
by the way, vec[0]=1.0 doesn't work either.
Looking at the documentation I noticed Scalar& coeffRef(Index i), and it says:
Returns a reference to the coefficient value at given index i. This operation involes a log(rho*size) binary search. If the coefficient does not exist yet, then a sorted insertion into a sequential buffer is performed. (This insertion might be very costly if the number of nonzeros above i is large.)
So the following should work:
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Sparse>
using namespace Eigen;
SparseVector<float> vec(3);
main()
{
vec.coeffRef(0)=1.0;
}
Not sure why they did it that way instead of using array overloading. Perhaps when it becomes IS_STABLE then they'll do it in a more typical C++ way?