c++vectoreigeneigen3

Eigen: subtract two vectors of unequal length, implicitly padding the shorter vector with zeros


I'm using Eigen 3.4. I'd like to subtract two vectors of unequal length, padding the shorter one with zeros along the bottom, while avoiding reallocation of memory. Rough example:

VectorXd A (4), B (2);
A << 1, 2, 3, 4;
B << 5, 6;
VectorXd C = paddedSubtract(A, B); // computes A - B but pads B with zeros to match A

The result should be

C = [-4, -4, 3, 4]

Note that I don't know beforehand which of the two vectors will be shorter.

  1. I could use conservativeResize to resize both vectors to the size of the larger of the two, and then manually set the padded values to zeros. However, this requires some checking of sizes, which is fine, but I'm wondering if there's a cleaner way.
  2. I could use conservativeResizeLike, passing in a vector of zeros with the size of the larger vector, but my concern is that a temporary zero vector will be allocated unnecessarily in the background; performance is important because this operation will be performed many times (but on small vectors).
  3. I could just use a loop, but I'd still have the unseemliness of (1).

My two questions are:

Thanks.


Solution

  • am I correct in thinking that there will be extra memory allocation of the zero vector

    Yes. You can make your own padding operator, however, it will likely defeat Eigen's explicit vectorization since it introduces a condition into the loop. It's the same reason why there is no concatenation operator. See Vector concatenation in Eigen returning an expression

    is there a cleaner / more Eigen-ey way than (1) or (3)?

    Keep it simple:

    Eigen::Index maxSize = std::max(A.size(), B.size());
    Eigen::Index minSize = std::min(A.size(), B.size());
    Eigen::Index tailSize = maxSize - minSize;
    Eigen::VectorXd C(maxSize);
    C.head(minSize) = A.head(minSize) - B.head(minSize);
    if(A.size() == maxSize)
        C.tail(tailSize) = A.tail(tailSize);
    else
        C.tail(tailSize) = -B.tail(tailSize);
    

    This would be optimized to avoid redundant memory operations. If you want fewer lines with slightly less efficiency:

    Eigen::VectorXd C = Eigen::VectorXd::Zero(std::max(A.size(), B.size());
    C.head(A.size()) = A;
    C.head(B.size()) -= B;
    

    You can also use the comma initializer

    Eigen::Index maxsize = std::max(A.size(), B.size());
    Eigen::Index minsize = std::min(A.size(), B.size());
    Eigen::VectorXd C(maxsize);
    C << (A.head(minsize) - B.head(minsize)),
         -B.tail(B.size() - minsize),
          A.tail(A.size() - minsize);