简体   繁体   中英

Combination of matrix-vector multiplication with coefficient-wise product in eigen

I am trying to condense a bit of code using functions in Eigen, specifically the ones that allow you to do coefficient-wise products of arrays, but am perhaps using them incorrectly. The basic idea is contained in this expanded for loop:

  for (int dir = 0;  dir < NDIM; dir++)
  {
    for (int i = 0; i < nlocal; i++)
    {
      for (int qp = 0; qp < nVolQuad; qp++)
        qNewPtr[i] += 
          volQuad.weights(qp)*bigStoredVolMatrices[dir](i,qp)*alpha(dir,qp)*fAtQuad(qp);
    }
  }

which I am trying to condense to:

  for (int dir = 0;  dir < NDIM; dir++)
  {  
    resultVectorDir[dir].noalias() = bigStoredVolMatrices[dir]*
      (volQuad.weights.array()*fAtQuad.array()*alpha.row(dir).array()).matrix();  
  }

  for (int i = 0; i < nlocal; i++)
  {
    for (int dir = 0;  dir < NDIM; dir++)
      qNewPtr[i] += resultVectorDir[dir](i);
  }

or without switching between array and matrix, using something like:

  for (int dir = 0;  dir < NDIM; dir++)
  {  
    resultVectorDir[dir].noalias() = bigStoredVolMatrices[dir]*
      (volQuad.weights.cwiseProduct(fAtQuad.cwiseProduct(alpha.row(dir))));  
  }

  for (int i = 0; i < nlocal; i++)
  {
    for (int dir = 0;  dir < NDIM; dir++)
      qNewPtr[i] += resultVectorDir[dir](i);
  }

The strange thing to me is sometimes this works. The code sometimes produces the desired output, but then also sometimes produces NaNs. I thought I might need to explicitly zero out the resultVectorDir in the condensed version, but that didn't fix the issue. I figured there was maybe just something subtle about performing this order of operations? Any assistance which can be provided would be greatly appreciated.

As an addendum to this question, I have attacked this issue with good old fashioned print statements and have found that I must not be using the coefficient wise product of arrays function correctly. For example, in a situation where nVolQuad = 9, I ran this segment of code:

  for (int dir = 0;  dir < NDIM; dir++)
  {
    tempArray = volQuad.weights.cwiseProduct(fAtQuad.cwiseProduct(alpha.row(dir)));
    for (int qp = 0; qp < nVolQuad; qp++)
    {
      std::cout << std::endl;
      std::cout << tempArray(qp) << " "; 
      std::cout << volQuad.weights(qp)*alpha(dir,qp)*fAtQuad(qp) << " ";
      std::cout << std::endl;
    }
    std::cout << std::endl;
    std::cout << std::endl;
  }

A chunk of the output looks like this:

-2.23064e-05 -2.23064e-05

1.49458e-154 -3.56902e-05

6.94729e-310 -2.23064e-05

-2.68156e+154 -2.0672e-05

6.94729e-310 -3.30752e-05

6.94729e-310 -2.0672e-05

2.13645e-314 -2.99114e-06

6.94729e-310 -4.78582e-06

6.94729e-310 -2.99114e-06

Other segments of the output are similar. The first entry is correct, but the other 8 entries of the tempArray are nonsense. tempArray is initialized to 0.0 before the loop, so I am at a bit of a loss. I'll keep digging through the documentation of Eigen to make sure I am not doing something exceedingly stupid in my use of this function.

The key error is in the assumption that you can immediately go from the expanded loop to the coefficient wise product, when the expanded loop is accessing data that's different sizes. Here:

volQuad.weights.cwiseProduct(fAtQuad.cwiseProduct(alpha.row(dir)))

Since volQuad.weights and fAtQuad are initialized with Eigen::VectorXd, they are column vectors, but by using alpha.row(dir), that particular data structure is a row vector. Thus, the coefficient wise product doesn't make sense and you're only going to get the first entry correct. This can be fixed easily by changing the syntax to:

volQuad.weights.cwiseProduct(fAtQuad.cwiseProduct(alpha.row(dir).transpose()))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM