How to extract real and imaginary parts of complex Eigen tensor? - c++

I am fairly new with Eigen and I read about Eigen unsupported tensor, which I decided to give it a try. I am trying to copy the output of an array after taking the 3D FFT to a complex Eigen tensor and I am not sure how to do it correctly. Is this feature available for Eigen Tensor?
A simple working example:
static const int nx = 4;
static const int ny = 4;
static const int nz = 4;
double Lx = 2*EIGEN_PI;
double Ly = 2*EIGEN_PI;
double dx = Lx / nx;
double dy = Ly / ny;
Eigen::Tensor<double, 3> eXX(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> eYY(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> eZZ(nx,ny,nz);
eZZ.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
eXX(k,i,j) = i*dx;
eYY(j,i,k) = j*dy;
eZZ(j,i,k) = k*dz;
}
}
}
double A = (2 * EIGEN_PI)/Lx;
double B= (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> Fun(nx,ny,nz);
Fun.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Fun(k,i,j) = pow(eZZ(k,i,j),2.0) * sin(A * eXX(k,i,j)) * sin(B * eYY(k,i,j));
}
}
}
#define IMAG 1
#define REAL 0
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = Fun(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
I am trying to copy the output to a tensor with the definition:
Eigen::Tensor<std::complex<double>, 3> Test(nx,ny,nz);
Test.setZero();
My attempt:
Eigen::Tensor<double, 3> Re(nx,ny,nz);
Re.setZero();
Eigen::Tensor<std::complex<double>, 3> Im(nx,ny,nz);
Im.setZero();
for(int i=0; i < nx; ++i){
for(int j=0; j < ny; ++j) {
for(int k=0; k < nz; ++k) {
Re(k,i,j) = output_array[k + nz * (j + ny * i)][REAL];
Im(k,i,j) = output_array[k + nz * (j + ny * i)][IMAG];
}
}
}
Test.real() = Re;
Test.imag() = Im;
Unfortunately, this above attempt is not working. I get the error:
error: use of deleted function ‘Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >& Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >::operator=(Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >&&)’
370 | Test.imag() = Im;
error: non-static reference member ‘const Eigen::Tensor<std::complex<double>, 3>& Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >::m_xpr’, can’t use default assignment operator

No you can't assign the real or imaginary part of a Tensor using the real() or imag() operation. The unsupported Tensor interface does not perfectly match with the core Matrix or Array interface.(Unsupported modules are contribution from third party developers, not core developers.)
You can see the difference in the following sources, scrapped from the 3.4.0 version.
This is the implementation of the Matrix at Eigen/src/plugins/CommonCwiseUnaryOps.h.
typedef CwiseUnaryView<internal::scalar_imag_ref_op<Scalar>, Derived> NonConstImagReturnType;
...
NonConstImagReturnType
imag() { return NonConstImagReturnType(derived()); }
This is the implementation of Tensor at unsupported/Eigen/CXX11/src/Tensor/TensorBase.h.
... const TensorCwiseUnaryOp<internal::scalar_imag_op<Scalar>, const Derived>
imag() const { return unaryExpr(internal::scalar_imag_op<Scalar>()); }

Related

How to print an Eigen tensor into a text file?

I am trying to print out a 3D matrix into a text file that can be read by a MATLAB code. The example I have here prints the tensor in a text file but when I try to open it in MATLAB it reads something like 256 x 16 instead of 16x16x16.
Example:
static const int nx = 16;
static const int ny = 16;
static const int nz = 16;double Lx = 128;
double Ly = 128;
double LZ = 128;
double dx = Lx / nx;
double dy = Ly / ny;
double dz = Lz / nz;
double a = (2 * EIGEN_PI)/Lx;
double b = (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> X(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> Y(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> Z(nx,ny,nz);
eZZ.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
X(k,i,j) = i*dx;
Y(j,i,k) = j*dy;
Z(j,i,k) = k*dz;
}
}
}
Eigen::Tensor<double, 3> Out(nx,ny,nz);
Out.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Out(k,i,j) = sin(3. * a * Z(k,i,j)) * sin(a * X(k,i,j)) * cos(b * Y(k,i,j));
}
}
}
std::ofstream file("test.txt");
if (file.is_open())
{
file << Out << '\n';
}
I know I will probably have to write my own output routine instead os using the operator << since it treats a rank-3 tensor as a 2-d matrix for the purpose of output.

Error passing an Eigen tensor to function

I am trying to turn the following code to a function:
Update: added full working example to test and run. Thanks.
static const int nx = 4;
static const int ny = 4;
static const int nz = 4;
double Lx = 2*EIGEN_PI;
double Ly = 2*EIGEN_PI;
double A = (2 * EIGEN_PI)/Lx;
double A1 = (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> eXX(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> eYY(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> eZZ(nx,ny,nz);
eZZ.setZero();
double dx = Lx / nx;
double dy = Ly / ny;
double dz = Lz / nz;
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
eXX(k,i,j) = i*dx;
eYY(j,i,k) = j*dy;
eZZ(j,i,k) = k*dz;
}
}
}
Eigen::Tensor<double, 3> uFun(nx,ny,nz);
uFun.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
uFun(k,i,j) = sin(3. * A * eZZ(k,i,j)) * sin(A * eXX(k,i,j)) * cos(A1 * eYY(k,i,j));
}
}
}
//Turn this to function
#define IMAG 1
#define REAL 0
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = uFun(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
My attempt:
void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr){
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = rArr(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
//this is correct 3D fft of uFun = fftn(uFun) in MATLAB
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
}
But I get all these errors:
error: variable or field ‘r2cfft3d’ declared void
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
| ^~~~~~
spectralFunctions3D.h:27:22: error: ‘Tensor’ is not a member of ‘Eigen’
spectralFunctions3D.h:27:29: error: expected primary-expression before ‘double’
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
error: ‘rArr’ was not declared in this scope
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
error: ‘cArr’ was not declared in this scope
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
| ^~~~
I don't understand these errors, espically that the code works fine before trying to turn it into a function. I am more familiar with passing Eigen matrices to function but not Eigen tensors. Thanks
I managed to compile this fine by including all the relevant headers (especially #include <unsupported/Eigen/CXX11/Tensor>).
Since you are using const sizes for the Eigen Tensors you could define them as fixed size with
Eigen::TensorFixedSize<double, Eigen::Sizes<nx, ny, nz>>
Also take a look at this: https://www.fftw.org/fftw3_doc/Column_002dmajor-Format.html , maybe you can avoid the conversion from column-major to row-major and pass directly the pointer to the Eigen Tensor.

How to convert for loop matrix multiplication using Eigen C++: incorrect results

I have the following for loop that works:
static const int ny = 10;
std::vector<double> ygl(ny+1);
double *dVGL;
dVGL = (double*) fftw_malloc(((ny+1)*(ny+1))*sizeof(double));
memset(dVGL, 42, ((ny+1)*(ny+1))* sizeof(double));
double *dummy1;
dummy1 = (double*) fftw_malloc(((ny+1)*(ny+1))*sizeof(double));
memset(dummy1, 42, ((ny+1)*(ny+1))* sizeof(double));
double *dummy2;
dummy2 = (double*) fftw_malloc(((ny+1)*(ny+1))*sizeof(double));
memset(dummy2, 42, ((ny+1)*(ny+1))* sizeof(double));
for (int i = 0; i < ny+1; i++){
for (int j = 0; j < ny+1; j++){
ygl[j] = -1. * cos(((j) * EIGEN_PI )/ny);
dummy1[j + ny*i] = 1./(sqrt(1-pow(ygl[j],2)));
dummy2[j + ny*i] = 1. * (i);
dVGL[j + ny*i] = dummy1[j + ny*i] * sin(acos(ygl[j]) * (i)) * dummy2[j + ny*i];
}
}
The above works fine, now I convert to Eigen and I am getting off results:
Eigen::Matrix< double, 1, ny+1> v1;
v1.setZero();
std::iota(v1.begin(), v1.end(), 0);
Eigen::Matrix< double, ny+1, ny+1> dummy1;
dummy1.setZero();
Eigen::Matrix< double, ny+1, ny+1> dummy2;
dummy2.setZero();
for (int j = 0; j < ny+1; j++){
v[j] = 1./(sqrt(1-pow(ygl[j],2)));
}
dummy1 = v.array().matrix().asDiagonal(); //this is correct
dummy2 = v1.array().matrix().asDiagonal(); //this is correct
Eigen::Matrix< double, ny+1, ny+1> dVGL;
dVGL.setZero();
for (int i = 0; i < ny+1; i++){
for (int j = 0; j < ny+1; j++){
ygl[j] = -1. * cos(((j) * EIGEN_PI )/ny);
dVGL(j + ny*i) = sin(acos(ygl[j]) * (i)); //this is correct
}
}
//##################################
dv1 = (dummy1) * (dVGL) * (dummy2); //this is incorrect, dVGL outside for loop is different from inside for loop!!
I have been wracking my brain for a week now over this I cannot seem to fix it. why is dVGL out side the for loop is different?? (off as if my rows and columns have length ny+1, but When I flatten my array I am using just ny.) why is that?
I feel like this should be a simple issue.
Thanks to #chtz in the comments, I was able to fix this problem simply by changing my indexing:
dVGL(j + (ny+1)*i) = sin(acos(ygl[j]) * (i));
dv1 = (dummy1) * (dVGL) * (dummy2); //Then this is correct

Error using Eigen: Perform element-wise multiplication between a vector and matrix

I am trying to perform an element-wise multiplication of a row vector with matrix. In MATLAB this would be simply done by the "dot" operator or:
deriv = 1i * k .* fk;
where k is row vector and fk is a matrix.
Now in C++ I have this code:
static const int nx = 10;
static const int ny = 10;
static const int nyk = ny/2 + 1;
static const int nxk = nx/2 + 1;
static const int ncomp = 2;
Matrix <double, 1, nx> eK;
eK.setZero();
for(int i = 0; i < nx; i++){
eK[i] = //some expression
}
fftw_complex *UOut;
UOut= (fftw_complex*) fftw_malloc((((nx)*(ny+1))*nyk)* sizeof(fftw_complex));
for (int i = 0; i < nx; i++){
for (int j = 0; j < ny+1; j++){
for (int k = 0; k < ncomp; k++){
UOut[i*(ny+1)+j][k] = //FFT of some expression
}
}
}
Eigen::Map<Eigen::MatrixXcd, Eigen::Unaligned> U(reinterpret_cast<std::complex<double>*>(UOut),(ny+1),nx);
Now, I am trying to take the product of eK which is a row vector of 1 x 10 and the matrix U of a 11 x 10. I tried few things, none of which seem to work really:
U = 1i * eKX.array() * euhX.array() ; //ERROR
static assertion failed: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES
( \
| ~~~
176 | (int(Eigen::internal::size_of_xpr_at_compile_time<TYPE0>::ret)==0 && int(Eigen::internal::size_of_xpr_at_compile_time<TYPE1>::ret)==0) \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
177 | || (\
| ^~~~~
178 | (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
Eigen doesn't do broadcasting the same way Matlab or Numpy do unless you explicitely ask for it, for example with matrix.array().rowwise() * vector.array()
The IMHO clearer form is to interpret the vector as a diagonal matrix.
Eigen::VectorXd eK = ...;
Eigen::Map<Eigen::MatrixXcd, Eigen::Unaligned> U = ...;
Eigen::MatrixXcd result = U * (eK * 1i).asDiagonal();

FFTW forward and back ward yield in different results why?

I am trying to FFT an image using the library from http://www.fftw.org/. basically i want to do a forward transform and then the backward transform to get the input image i have chosen. Then I would like to get my input back with the backward FFT, but it doesn't work. Here is my code :
double n[w][h][2];
double im[w][h][2];
const int Lx = w;
const int Lt = h;
int var_x;
int var_t;
fftw_complex *in, *out, *result;
fftw_plan p;
fftw_plan inv_p;
in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
result = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *Lx *Lt);
p = fftw_plan_dft_2d(Lx, Lt, in, out, FFTW_FORWARD, FFTW_MEASURE);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
in[t + Lt*x][0] = n[x][t][0];
in[t + Lt*x][1] = 0;
}
}
fftw_execute(p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
n[x][t][0] = out[t + Lt*x][0];
n[x][t][1] = out[t + Lt*x][1];
}
}
inv_p = fftw_plan_dft_2d(Lx, Lt, out, result, FFTW_BACKWARD, FFTW_MEASURE);
fftw_execute(inv_p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
im[x][t][0] = result[t + Lt*x][0];
im[x][t][1] = result[t + Lt*x][1];
std::cout<<im[x][t][0]<<std::endl;
}
}
fftw_destroy_plan(p);
fftw_free(in);
fftw_free(out);
As you can see, I just try to perform a normal FFT, then to reverse it. The problem is that my output 'im' is just full of 0, instead of 1 and 0...
So what's wrong with my code ?
Thank you :)
Your original image and transform matrices are declared as int. Try defining them as double:
double n[w][h][2];
double im[w][h][2];
The line below, for example, is destroying data because result[i][j] is of type double (as of fftw_complex definition). So that if result[i][j] == 0.99, it'll be converted to 0.
im[x][t][0] = result[t + Lt*x][0]; //A value of 0.99 may be converted to 0
This is the corrected version of the code which is now working - thank you to everybody who helped me to fix all the problems.
double n[w][h][2];
double im[w][h][2];
const int Lx = w;
const int Lt = h;
int var_x;
int var_t;
fftw_complex *in, *out, *result;
fftw_plan p;
fftw_plan inv_p;
in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
result = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *Lx *Lt);
p = fftw_plan_dft_2d(Lx, Lt, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
in[t + Lt*x][0] = n[x][t][0];
in[t + Lt*x][1] = 0;
}
}
fftw_execute(p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
n[x][t][0] = out[t + Lt*x][0];
n[x][t][1] = out[t + Lt*x][1];
}
}
inv_p = fftw_plan_dft_2d(Lx, Lt, out, result, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(inv_p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
im[x][t][0] = result[t + Lt*x][0];
im[x][t][1] = result[t + Lt*x][1];
std::cout<<im[x][t][0]<<std::endl;
}
}
fftw_destroy_plan(p);
fftw_destroy_plan(inv_p);
fftw_free(in);
fftw_free(out);
fftw_free(result);