Eigen  5.0.1
 
Loading...
Searching...
No Matches
Writing custom functors

Several Eigen extension points accept a user-provided function object, or functor. This is often the lightest way to customize an expression without defining a new expression type.

Where functors are used

Common entry points include:

Scalar interface

At minimum, a functor provides an operator() matching the expression kind:

struct clamp {
double lo, hi;
double operator()(double x) const { return x < lo ? lo : (hi < x ? hi : x); }
};
struct add_scaled {
double scale;
double operator()(double a, double b) const { return a + scale * b; }
};
struct checkerboard {
double operator()(Eigen::Index i, Eigen::Index j) const { return ((i + j) % 2) ? -1.0 : 1.0; }
};

The result type is deduced from operator() and may differ from the input scalar type. Binary functors can rely on Eigen's scalar binary-op traits when the return type follows the usual scalar rules; custom mixed-scalar operations may need a ScalarBinaryOpTraits specialization.

Functors used with redux() must implement an associative binary operation and return the same scalar type as the expression, because Eigen may combine coefficients in an order chosen by the evaluator.

Cost and vectorization traits

Eigen assigns conservative defaults to unknown functors:

template <typename T>
struct functor_traits {
enum { Cost = 10, PacketAccess = false, IsRepeatable = false };
};

For performance-sensitive functors, specialize Eigen::internal::functor_traits for your functor:

namespace Eigen {
namespace internal {
template <>
struct functor_traits<clamp> {
enum { Cost = 3 * NumTraits<double>::AddCost, PacketAccess = false };
};
} // namespace internal
} // namespace Eigen

Cost is an approximate scalar cost used by Eigen's expression evaluators. PacketAccess may be set to true only when the functor also provides packet overloads compatible with the packet types used by the relevant scalar type. Unary and binary packetized functors usually provide a packetOp() member; reduction functors that support packet reductions also provide predux().

Most user functors should start with scalar-only code and leave PacketAccess set to false. That keeps the functor portable and lets Eigen use the scalar path for that operation while preserving vectorization opportunities elsewhere in the expression.

Capturing state

Functor objects are copied into expression objects and may be evaluated later. Store any captured data so that it outlives the expression evaluation. For example, a nullary functor producing a view into another matrix should either store a safe reference to an object owned by the caller or require the caller to evaluate the expression before the referenced object goes out of scope.

When a functor is not enough

If the expression needs a new shape, a custom nested expression type, or evaluator-specific behavior that cannot be expressed coefficient by coefficient, see Adding a new expression type. For many procedural matrices and indexed views, Matrix manipulation via nullary-expressions is simpler than a new expression type.