c++c++20eigenreinterpret-cast

Can we `reinterpret_cast` a `Eigen::Vector<T, D + 1>& x` to `Eigen::Vector<T, D>&` to extract the first `D` components from `x`?


I need to compute the function value and gradient of a D-dimensional function and add those values together. I thought it would be computational beneficial to simply store the gradient part in the first D-components and the value of the function in the last component of a D+1-dimensional vector.

However, how can I extract the first D-components (i.e. the gradient part) from that D+1-dimensional vector? I know that there is the option of slicing, but I don't want to add any senseless overhead here. So, I've tried to simply do a reinterpret_cast<Eigen::Vector<T, D>&> on my Eigen::Vector<T, D + 1> and it worked; but is that really guaranteed to work (and safe)?


Solution

  • You don't want the slicing operations, you want the block operations. Most (all?) of them come with template versions. To get the first D elements of a vector if D is a runtime variable, call vector.head(D). If it is a compile-time constant, use vector.head<D>().

    The returned block expression object is similar to an Eigen Map in that it is effectively a zero-overhead reference and does exactly what you want.

    // act like reference
    auto first_d = vector.head<D>();
    // copy into new vector
    auto copy = first_d.eval();
    // or
    Eigen::Vector<double, D> copy2 = first_d;
    

    The usual warnings about using auto in Eigen apply, but this use is okay. If you want to be safe, spell the type out or don't keep it around as a variable, only use it as part of expressions.

    If you compile without -DNDEBUG there will be a range-check unless the compiler can optimize it away (likely the case for template parameter used on fixed-size vector).

    And just to return to the original question: No, it would not be safe. Even if you trust that Eigen never changes the internal layout of fixed size types (reasonable assumption), smaller vectors may have bigger alignment. alignof(Vector3d) < alignof(Vector2d). This will result in Eigen creating machine instructions that assume that higher alignment (such as movapd vs. movupd on x86), which will fail at runtime.