Slicing Eigen tensor: Error accessing matrices from tensors - c++

I am new to tensor in Eigen and just trying to run simple examples here. This is the code I have it's to access the first matrix in a tensor. Let's say I have a tensor with size ((nz+1),ny,nx), where each matrix in this tensor should have the shape or size of (nz+1)-by-ny. The thing is I can only extract a matrix that returns size ny-by-nz.
The code:
static const int nx = 10;
static const int ny = 10;
static const int nz = 10;
Eigen::Tensor<double, 3> epsilon((nz+1),ny,nx);
epsilon.setZero();
//slicing test: access first matrix in tensor
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {1,ny,nx}; //Finish point
std::array<long,2> shape2 = {(ny),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape2) << std::endl;
The answer is a matrix with a 10-by-10 size. How can I change this to extract slice and reshape it into a 11x10 matrix instead (11 rows and 10 columns). I tried changing last line to std::array<long,2> shape2 = {(nz+1),(nx)}; but this returns the error:
Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::TensorEvaluator(const XprType&, const Device&) [with NewDimensions = const std::array<long int, 2>; ArgType = Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> >; Device = Eigen::DefaultDevice; Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::XprType = Eigen::TensorReshapingOp<const std::array<long int, 2>, Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> > >]: Assertion `internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions())' failed.
Aborted
How can I change the number of rows in this matrix? Thanks

I was able to fix:
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {(nz+1),nx,1}; //Finish point:(row,column,matrix)
std::array<long,2> shape = {(nz+1),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape) << std::endl;

Related

Initializing segments of an Eigen VectorXd

I'd like to efficiently initialize segments of an VectorXd object from the Eigen library. This vector is large (~1e6) so I would like to do this efficiently. Below is an example showing what I was thinking.
size_t N = 1e6;
std::vector<double> F(1., 2., 3., 4.);
Eigen::VectorXd ln_f_origin( F.size() * num_B );
for (size_t i=0; i<F.size(); i++) {
ln_f_origin.segment(i*num_B, num_B) = log(F[i]/num_B);
}
This doesn't seem to be working. I'm getting the following error:
error: no match for 'operator=' (operand types are 'Eigen::DenseBase<Eigen::Matrix<double, -1, 1> >::FixedSegmentReturnType<-1>::Type' {aka 'Eigen::VectorBlock<Eigen::Matrix<double, -1, 1>, -1>'} and 'double')

why I cannot multiply an op result by the constant eigen tensor array

Why it's not legal to do multiplication of the tensor op(sqrt()) and the linear.constant()
Eigen::Tensor<float, 1> linear(2);
linear.setValues({3,4});
auto linear_square = linear * linear;
auto linear_square_sum = linear_square.sum().sqrt();
std::cout<<linear_square_sum<<std::endl; // 5
auto new_linear = linear_square_sum * linear.constant(5); //no compiling error but aborted when executing
error info
tensor2matrix:
/usr/local/include/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h:380:
Eigen::TensorEvaluator, Device>::TensorEvaluator(const XprType&,
const Device&) [with BinaryOp =
Eigen::internal::scalar_product_op; LeftArgType = const
Eigen::TensorCwiseUnaryOp,
const Eigen::TensorReductionOp,
const Eigen::DimensionList, const
Eigen::TensorCwiseBinaryOp, const Eigen::Tensor, const Eigen::Tensor
, Eigen::MakePointer> >; RightArgType = const Eigen::TensorCwiseNullaryOp,
const Eigen::Tensor >; Device = Eigen::DefaultDevice;
Eigen::TensorEvaluator, Device>::XprType =
Eigen::TensorCwiseBinaryOp, const
Eigen::TensorCwiseUnaryOp,
const Eigen::TensorReductionOp,
const Eigen::DimensionList, const
Eigen::TensorCwiseBinaryOp, const Eigen::Tensor, const Eigen::Tensor
, Eigen::MakePointer> >, const Eigen::TensorCwiseNullaryOp,
const Eigen::Tensor > >]: Assertion
`dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions())'
failed. Aborted
I'm pretty sure people already linked to you the documentation saying that using auto with expression templates is not a good idea. Evaluating one expression template multiple times seems like an even worse idea.
If you don't want/can't explicitly mention the types you can base them on the original values you put in.
Eigen::Tensor<float, 1> linear(2);
linear.setValues({ 3,4 });
decltype(linear) linear_square = linear * linear;
Eigen::Tensor<decltype(linear)::Scalar, 0> linear_square_sum = linear_square.sum().sqrt();
std::cout << linear_square_sum << std::endl; // 5
// Don't forget to convert to an actual scalar
// |
// v
decltype(linear) new_linear = linear_square_sum() * linear.constant(5);
std::cout << new_linear;
return 0;

simple multiplication or operator issue

I am trying to run this simple code. But I am missing something. I tried to look at operator overloading. Could someone explain what I am missing here.
#include <iostream>
#include <vector>
#include <cstdlib>
int main(){
std::vector < std::vector<double> > tm;
std::vector<int> dfg;
// Creating a simple matrix
double ta1[]={0.5,0.5,0};
std::vector <double> tv1 (ta1, ta1+3);
tm.push_back(tv1);
double ta2[]={0.5,0,0};
std::vector <double> tv2 (ta2, ta2+3);
tm.push_back(tv2);
double ta3[]={0,0.5,0};
std::vector <double> tv3 (ta3, ta3+3);
tm.push_back(tv3);
double d_load =0.5;
// doing some simple calculations
for (int destinationID = 1; destinationID <= tm.size(); destinationID++){
float randomNum = ((double) rand())/((double) RAND_MAX);
if (randomNum <= d_load * tm[destinationID - 1])
dfg.push_back(destinationID);
}
return 0;
}
I get the following error.
error: no match for ‘operator*’ in ‘d_load * tm.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::vector<double>, _Alloc = std::allocator<std::vector<double> >, std::vector<_Tp, _Alloc>::reference = std::vector<double>&, std::vector<_Tp, _Alloc>::size_type = long unsigned int](((long unsigned int)(destinationID + -0x00000000000000001)))’
The tm is a std::vector<std::vector<double>>, thus effectively it is a 2-dimensional dynamic array of double. This means that to access the individual double elements in tm, you would use something like this:
double value = tm[destinationID - 1][theValueIndex];
It is the [theValueIndex] part of the loop that you're missing.
Since we don't know your exact intentions on how you want to traverse the array, I leave it to you to fill in this gap.
The following line is invalid:
d_load * tm[destinationID - 1]
Since tm is a std::vector<std::vector<double>>, The elements of tm are std::vector<double>, not double. If you want to multiply each number or check that each number matches the condition, you have to iterate the element you're getting out of tm[]

no match for 'operator =' for 3d vector

I am trying to convert a vector of coordinates std::vector surface into a 3D array, setting all entries of the 3d array that are contained in surface to 0;
however I am getting a no match for operator array.
I looked up the error several times but did not find my case....
std::vector<coordinates> surface is global.
the coordiantes simply look like
struct coords{
int xvalue;
int yvalue;
int zvalue;
coords(int x1, int y1, int z1) : xvalue(x1),yvalue(y1),zvalue(z1){}
~coords(){}
};
typedef struct coords coordinates;
and my method is:
(doubleBox is a typedef for a 3D double vector)
doubleBox levelset::putIntoBox( vector<coordinates> surface){
int xMaxs, yMaxs,zMaxs;
for (vector<coordinates>::iterator it = surface.begin() ; it != surface.end(); ++it){
if (it->xvalue > xMaxs)
xMaxs = it->xvalue;
if (it->yvalue > yMaxs)
yMaxs = it->yvalue;
if (it->zvalue > zMaxs)
zMaxs = it->zvalue;
//check invalid surface
if (it->xvalue < 0 || it->yvalue <0 || it->zvalue<0)
cout << "invalid surface with point coordinates below 0 !" << endl;
}
doubleBox surfaceBox[xMaxs+1][yMaxs+1][zMaxs+1];
int max = std::ceil(sqrt(xMaxs*xMaxs + yMaxs*yMaxs + zMaxs*zMaxs));
std::fill(&surfaceBox[0][0][0],&surfaceBox[0][0][0] + sizeof(surfaceBox)*sizeof(surfaceBox[0])/ sizeof(surfaceBox[0][0]) / sizeof(surfaceBox[0][0]), max);
for (vector<coordinates>::iterator it = surface.begin() ; it != surface.end(); it++){
surfaceBox[it->xvalue][it->yvalue][it->zvalue] = 0.0;
}
return surfaceBox;
}
the output is (declaring that the error lies in the second for-loop)
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\vector.tcc:160:5: note: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = std::vector<std::vector<double> >; _Alloc = std::allocator<std::vector<std::vector<double> > >]
vector<_Tp, _Alloc>::
^
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\vector.tcc:160:5: note: no known conversion for argument 1 from 'const int' to 'const std::vector<std::vector<std::vector<double> > >&'
..\src\Levelset.cpp: In member function 'doubleBox levelset::putIntoBox(std::vector<coords>)':
..\src\Levelset.cpp:295:1: warning: control reaches end of non-void function [-Wreturn-type]
Maybe this problem is caused by the fact that std::fill is used inappropriately??
Since doubleBox is defined as std::vector<std::vector<std::vector<double>, why do you define doubleBox surfaceBox[xMaxs+1][yMaxs+1][zMaxs+1]; in this way?
What you defined is a 3 dimensional array whose element type is doubleBox, which means that every element is of type std::vector<std::vector<std::vector<double>, which is not what you want.
You may need something like doubleBox surfaceBox(xMaxs + 1, std::vector<std::vector<double>>(yMaxs + 1, std::vector<double>(zMaxs + 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);