编写新的 Eigen 表达式
Writing new Eigen expression
我正在尝试根据最新文档 https://eigen.tuxfamily.org/dox-devel/TopicNewExpressionType.html 编写新的 Eigen 表达式。基本上,我想要的是 Eigen 中仍然缺少的重塑功能的一部分。所以 chop_expr(此处为特征向量表达式)应将输入向量重塑为 n 次矩阵。
不幸的是,我实现的不适用于分配在堆上的表达式,例如下面的代码不起作用,但将 MAXV 更改为 10 后,一切都变得完美。
另一个问题是关于
enum {Flags = EvalBeforeNestingBit}
我发现我需要它,否则,当我切割矩阵乘法时,Eigen 不会创建临时变量,但我想这样我也强制 chop_expr 为任何其他表达式创建临时变量。所以问题是我应该如何正确地做呢?
namespace Eigen {
template <int chunk, typename Derived> struct ChoppedExpression;
namespace internal {
template <int chunk, typename Derived>
struct traits<ChoppedExpression<chunk, Derived>> : traits<Derived> {
enum {Flags = EvalBeforeNestingBit};
enum {IsRowMajor = 0};
enum { RowsAtCompileTime = chunk};
enum {MaxRowsAtCompileTime = chunk};
enum {ColsAtCompileTime = (Derived::RowsAtCompileTime == Eigen::Dynamic
? Eigen::Dynamic : Derived::RowsAtCompileTime / chunk)};
enum {MaxColsAtCompileTime = (Derived::MaxRowsAtCompileTime == Eigen::Dynamic
? Eigen::Dynamic : (Derived::MaxRowsAtCompileTime + chunk - 1) / chunk)};
};
} // namespace internal
template <int chunk, class Derived> struct ChoppedExpression
: public MatrixBase<ChoppedExpression<chunk, Derived>> {
ChoppedExpression(const Derived& arg) : m_arg(arg) {
EIGEN_STATIC_ASSERT(Derived::ColsAtCompileTime == 1,
YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX);
EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime % chunk == 0
|| Derived::RowsAtCompileTime == Eigen::Dynamic,
VECTOR_SHOULD_HAVE_INTEGER_NUMBER_OF_CHUNKS_FOR_CHOPPING);
}
typedef Index Index;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return chunk; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_arg.size() / chunk; }
typedef typename internal::ref_selector<ChoppedExpression>::type Nested;
typedef typename internal::ref_selector<Derived>::type DerivedTypeNested;
DerivedTypeNested m_arg;
};
namespace internal {
template<int chunk, typename Derived>
struct evaluator<ChoppedExpression<chunk, Derived>>
: public evaluator_base<ChoppedExpression<chunk, Derived>> {
typedef ChoppedExpression<chunk, Derived> XprType;
typedef typename nested_eval<Derived, XprType::ColsAtCompileTime>::type DerivedNested;
typedef typename remove_all<DerivedNested>::type DerivedNestedCleaned;
typedef typename XprType::CoeffReturnType CoeffReturnType;
enum {
CoeffReadCost = evaluator<DerivedNestedCleaned>::CoeffReadCost,
Flags = traits<XprType>::Flags, IsRowMajor = 0
};
evaluator(const XprType& xpr) : m_argImpl(xpr.m_arg) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const
{ return m_argImpl.coeff(col * chunk + row); }
evaluator<DerivedNestedCleaned> m_argImpl;
};
} // namespace internal
} // namespace Eigen
template<int chunk, typename Derived> EIGEN_ALWAYS_INLINE
EIGEN_DEVICE_FUNC static Eigen::ChoppedExpression<chunk, Derived>
chop_expr(const Eigen::MatrixBase<Derived> &expr)
{ return Eigen::ChoppedExpression<chunk, Derived>(expr.derived()); }
#define MAXV -1
Eigen::Matrix<double, -1, 1, 0, std::max(3*MAXV, -1)> _blendshapes(2, 1);
int main() {
for (int i = 0; i < 2; ++i) _blendshapes[i] = double(i + 10);
std::cout << chop_expr<2>(_blendshapes + Eigen::Matrix<double, 2, 1>(1, 1)) << std::endl;
}
更新
终于,我找到了让它工作的方法。解决方案是删除 DerivedNested 和 DerivedNestedCleaned typedef(我的表达式中显然不需要它们,因为它只是重塑,但是,我无法解释为什么它会导致不正确的结果)。因此剩下的唯一问题是我应该如何处理 EvalBeforeNestingBit?
您不需要 EvalBeforeNestingBit
,但在计算器中传播标志时必须小心。为了安全起见,写:
Flags = traits<XprType>::Flags&HereditaryBits
我正在尝试根据最新文档 https://eigen.tuxfamily.org/dox-devel/TopicNewExpressionType.html 编写新的 Eigen 表达式。基本上,我想要的是 Eigen 中仍然缺少的重塑功能的一部分。所以 chop_expr(此处为特征向量表达式)应将输入向量重塑为 n 次矩阵。
不幸的是,我实现的不适用于分配在堆上的表达式,例如下面的代码不起作用,但将 MAXV 更改为 10 后,一切都变得完美。
另一个问题是关于
enum {Flags = EvalBeforeNestingBit}
我发现我需要它,否则,当我切割矩阵乘法时,Eigen 不会创建临时变量,但我想这样我也强制 chop_expr 为任何其他表达式创建临时变量。所以问题是我应该如何正确地做呢?
namespace Eigen {
template <int chunk, typename Derived> struct ChoppedExpression;
namespace internal {
template <int chunk, typename Derived>
struct traits<ChoppedExpression<chunk, Derived>> : traits<Derived> {
enum {Flags = EvalBeforeNestingBit};
enum {IsRowMajor = 0};
enum { RowsAtCompileTime = chunk};
enum {MaxRowsAtCompileTime = chunk};
enum {ColsAtCompileTime = (Derived::RowsAtCompileTime == Eigen::Dynamic
? Eigen::Dynamic : Derived::RowsAtCompileTime / chunk)};
enum {MaxColsAtCompileTime = (Derived::MaxRowsAtCompileTime == Eigen::Dynamic
? Eigen::Dynamic : (Derived::MaxRowsAtCompileTime + chunk - 1) / chunk)};
};
} // namespace internal
template <int chunk, class Derived> struct ChoppedExpression
: public MatrixBase<ChoppedExpression<chunk, Derived>> {
ChoppedExpression(const Derived& arg) : m_arg(arg) {
EIGEN_STATIC_ASSERT(Derived::ColsAtCompileTime == 1,
YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX);
EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime % chunk == 0
|| Derived::RowsAtCompileTime == Eigen::Dynamic,
VECTOR_SHOULD_HAVE_INTEGER_NUMBER_OF_CHUNKS_FOR_CHOPPING);
}
typedef Index Index;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return chunk; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_arg.size() / chunk; }
typedef typename internal::ref_selector<ChoppedExpression>::type Nested;
typedef typename internal::ref_selector<Derived>::type DerivedTypeNested;
DerivedTypeNested m_arg;
};
namespace internal {
template<int chunk, typename Derived>
struct evaluator<ChoppedExpression<chunk, Derived>>
: public evaluator_base<ChoppedExpression<chunk, Derived>> {
typedef ChoppedExpression<chunk, Derived> XprType;
typedef typename nested_eval<Derived, XprType::ColsAtCompileTime>::type DerivedNested;
typedef typename remove_all<DerivedNested>::type DerivedNestedCleaned;
typedef typename XprType::CoeffReturnType CoeffReturnType;
enum {
CoeffReadCost = evaluator<DerivedNestedCleaned>::CoeffReadCost,
Flags = traits<XprType>::Flags, IsRowMajor = 0
};
evaluator(const XprType& xpr) : m_argImpl(xpr.m_arg) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const
{ return m_argImpl.coeff(col * chunk + row); }
evaluator<DerivedNestedCleaned> m_argImpl;
};
} // namespace internal
} // namespace Eigen
template<int chunk, typename Derived> EIGEN_ALWAYS_INLINE
EIGEN_DEVICE_FUNC static Eigen::ChoppedExpression<chunk, Derived>
chop_expr(const Eigen::MatrixBase<Derived> &expr)
{ return Eigen::ChoppedExpression<chunk, Derived>(expr.derived()); }
#define MAXV -1
Eigen::Matrix<double, -1, 1, 0, std::max(3*MAXV, -1)> _blendshapes(2, 1);
int main() {
for (int i = 0; i < 2; ++i) _blendshapes[i] = double(i + 10);
std::cout << chop_expr<2>(_blendshapes + Eigen::Matrix<double, 2, 1>(1, 1)) << std::endl;
}
更新
终于,我找到了让它工作的方法。解决方案是删除 DerivedNested 和 DerivedNestedCleaned typedef(我的表达式中显然不需要它们,因为它只是重塑,但是,我无法解释为什么它会导致不正确的结果)。因此剩下的唯一问题是我应该如何处理 EvalBeforeNestingBit?
您不需要 EvalBeforeNestingBit
,但在计算器中传播标志时必须小心。为了安全起见,写:
Flags = traits<XprType>::Flags&HereditaryBits