c++eigeneigen3elementwise-operations

Transform elements in an Eigen Vector to some constant to the power of the corresponding element


I am new to the Eigen library. I want to transform each element in a vector (or matrix) to some constant to the power of the corresponding element from the vector.

I want to do this operation efficiently because I may have a huge amount of elements. If possible, I would like to avoid a loop that traverses each element in the vector. There exist wise operations like .array().colwise().sum(). I was thinking about using some wise operation for doing this, if it exists.

Example:

int c = 3;
Vector<int, 3> v = { 1, 2, 3 }
v = pow(v, c);   // < pseudocode
std::cout << v;

Desired output:

 3  9 27

Explanation: {c^1, c^2, c^3} = {3^1, 3^2, 3^3} = {3, 9, 27}

Note that this question is not about raising each element to a constant (which is not complicated), but about raising a constant to the power of the corresponding element (which I find more complicated).


Solution

  • You mentioned that you would like to avoid traversing each element in the Vector.

    This is not really possible. In order to update each element you must traverse the Vector. Even the element-wise operations in Eigen itself hide an internal iteration.

    Since Eigen Vector (which is actually a type alias for Matrix of dim 1) support STL-like iterators, you can use a ranged-based loop to update the elements.

    This is demonstrated below:

    #include <iostream>
    #include <Eigen/Core>
    
    int ipow(int base, int exp) {
        int result = 1;
        for (;;) {
            if (exp & 1)
                result *= base;
            exp >>= 1;
            if (!exp)
                break;
            base *= base;
        }
    
        return result;
    }
    
    int main() {
        int c = 3;
        Eigen::Vector<int, 3> v = { 1, 2, 3 };
    
        for (auto & elem : v) {
            elem = ipow(c, elem);
        }   
    
        for (auto const & elem : v) {
            std::cout << elem << ",";
        }
    }
    

    Output:

    3,9,27,
    

    Live demo

    Note:
    Since you are dealing with int values, I did not use pow which is meant for floating point values. Instead I used an int based exponantiation function. This functions assumes the exponent is non-negative. You can use the standard pow if you actually have float or double values. Note that if your Vectors values can be negative int is not a proper type for it because after exponantiation is will require non-integer values.


    Update:
    Following the comment below by @Homer512, if you prefer to use only an Eigne expression in this case, you can use:

    v = Eigen::Array3i::Constant(c).binaryExpr(v.array(), &ipow);
    

    To aid inlining you can replace the ipow function pointer with a lambda expression. This approach has advantages (being able to combine with other Eigen expressions, one line initialization of an array), and disadvantages (readability, and isolation from other transformations you might wish to apply element-wise).