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).
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,
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 Vector
s 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).