假设我有两个定义为的特征数组
Array<float, 10, 1> a;
Array<float, 4, 1> b;
现在,我想得到一个Array<bool, 10, 4> result;
的数组,为a
的10个条目中的每一个读取true
,其中它比b
的四个条目中每一个都大。实现这一目标的一种方法是:
Array<float, 10, 1> a;
Array<float, 4, 1> b;
// ... fill the arrays
Array<bool, 10, 4> result = a.replicate(1 , 4) > (b.transpose()).replicate(10, 1);
实际上,矩阵的尺寸要大得多。这种方法有效,但我有两个问题。
首先:如果我用auto result = ...
替换Array<bool, 10, 4> result = ...
,由于某种原因,使用result
要慢得多(我在之后使用它来根据布尔的结果进行一些计算(。
第二:虽然这是有效的,但我想知道这是否是最有效的方法,因为我不知道复制是否需要复制。我可以考虑在二维中的一个上迭代
Array<float, 10, 1> a;
Array<float, 4, 1> b;
// ... fill the arrays
Array<bool, 10, 4> result;
for(int i = 0; i < 4; i++){
result.col(i) = a > b(i, 0);
}
这将消除以增加迭代为代价使用CCD_ 8的必要性。
非常感谢您的帮助!
编辑:以下是感兴趣的代码块。它经常被调用,因此加速是非常令人担忧的。现在,这占用了整个执行时间的90%。它是数千条线的相交检测的一部分。我的方法是在矩阵表达式中写入所有检查,以避免在所有行对上迭代。为此,我构建了一个矩阵,其中n
行用于所有n
行,m
列用于其他n
行可能发生冲突的所有行。然后,线交点公式可以系数化地应用于大矩阵上,我希望这能加快速度。
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x1 = rays.col(0).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x2 = (rays.col(2) + rays.col(0)).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y1 = rays.col(1).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y2 = (rays.col(3) + rays.col(1)).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x3 = obstacles.col(0).transpose().replicate(num_rays*num_ships, 1);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x4 = obstacles.col(2).transpose().replicate(num_rays*num_ships, 1);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y3 = obstacles.col(1).transpose().replicate(num_rays*num_ships, 1);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y4 = obstacles.col(3).transpose().replicate(num_rays*num_ships, 1);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> t_den = (x1-x2)*(y3-y4) -(y1-y2)*(x3-x4);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> t = (x1-x3)*(y3-y4) -(y1-y3)*(x3-x4)/t_den;
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> u = ((x1-x3)*(y1-y2) - (y1-y3)*(x1-x2));
Eigen::Array<bool, Eigen::Dynamic, Eigen::Dynamic> col_r = 0 <= t && 0 <= u && u <= t_den;
t_rays = col_r.select(t, 1000).rowwise().minCoeff();
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x1_ = ship_b_boxs.col(0).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x2_ = (ship_b_boxs.col(2)).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y1_ = ship_b_boxs.col(1).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y2_ = (ship_b_boxs.col(3)).replicate(1, 4*obs.size());
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x3_ = x3(Eigen::seq(0, 4*num_ships-1), Eigen::all);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> x4_ = x4(Eigen::seq(0, 4*num_ships-1), Eigen::all);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y3_ = y3(Eigen::seq(0, 4*num_ships-1), Eigen::all);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> y4_ = y4(Eigen::seq(0, 4*num_ships-1), Eigen::all);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> t_den_ = (x1_-x2_)*(y3_-y4_) -(y1_-y2_)*(x3_-x4_);
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> t_ = (x1_-x3_)*(y3_-y4_) -(y1_-y3_)*(x3_-x4_)/t_den_;
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> u_ = ((x1_-x3_)*(y1_-y2_) - (y1_-y3_)*(x1_-x2_));
Eigen::Array<bool, Eigen::Dynamic, Eigen::Dynamic> col_s = (0 <= t_ && t_ <= 1 && 0 <= u_ && u_ <= t_den_).rowwise().maxCoeff();
CCD_ 13占85%。我可以看到,现在可能所有的临时数组构造都需要花费大量时间。然而,存储这些临时变量是有益的,因为它们被多次使用。有什么办法加快速度吗?
第一:如果我替换Array<布尔,10,4>结果=。。。按自动结果=…,由于某些原因,使用结果要慢得多(我在根据bool的结果进行一些计算(。
@Homer512在评论中提到,不要在特征表达式中使用auto
第二:虽然这很有效,但我想知道这是否是最有效的方法,因为我不知道复制是否需要复制
否,如果在表达式中使用replicate
,并且不主动将其存储在某个中间变量中,或者以其他方式强制计算表达式,则不涉及复制。在典型的Eigen风格replicate
中,只返回复制的表达式,请参阅文档,只有在绝对必要时,才会创建包含完整复制的实际对象。
简而言之,这个涉及副本:
Array<bool, 10, 4> a4r = a.replicate(1 , 4);
Array<bool, 10, 4> b4r = b.transpose().replicate(10, 1);
Array<bool, 10, 4> result = a4r > b4r;
而你的表达没有:
Array<bool, 10, 4> result = a.replicate(1 , 4) > b.transpose().replicate(10, 1);
所以我真的认为这是最有效的方法,或者接近它
这魔法怎么可能?这在文档中解释得很好。
旁注:
- 如果你的矩阵很大,你应该考虑切换到动态大小,请参阅Eigen自己的建议"固定与动态大小">
- 另一方面,如果您确实知道编译时的大小,则可以考虑复制的临时版本:
a.replicate<1,4>() > b.transpose().replicate<10,1>();
如果您仍然不相信不涉及复制,您可以检查源代码,从版本3.4.0 开始
Eigen/src/Core/Replicate.h
template<typename MatrixType,int RowFactor,int ColFactor> class Replicate
: public internal::dense_xpr_base< Replicate<MatrixType,RowFactor,ColFactor> >::type
{
[...]
template<typename OriginalMatrixType>
EIGEN_DEVICE_FUNC
inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor)
: m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor)
{
EIGEN_STATIC_ASSERT((internal::is_same<typename internal::remove_const<MatrixType>::type,OriginalMatrixType>::value),
THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE)
}
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); }
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); }
EIGEN_DEVICE_FUNC
const _MatrixTypeNested& nestedExpression() const
{
return m_matrix;
}
protected:
MatrixTypeNested m_matrix;
const internal::variable_if_dynamic<Index, RowFactor> m_rowFactor;
const internal::variable_if_dynamic<Index, ColFactor> m_colFactor;
};
Eigen/src/Core/DenseBase.h
const Replicate<Derived, Dynamic, Dynamic> replicate(Index rowFactor, Index colFactor) const
{
return Replicate<Derived, Dynamic, Dynamic>(derived(), rowFactor, colFactor);
}
Eigen/src/Core/CoreEvaluators.h
template<typename ArgType, int RowFactor, int ColFactor>
struct unary_evaluator<Replicate<ArgType, RowFactor, ColFactor> >
: evaluator_base<Replicate<ArgType, RowFactor, ColFactor> >
{
[...]
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
explicit unary_evaluator(const XprType& replicate)
: m_arg(replicate.nestedExpression()),
m_argImpl(m_arg),
m_rows(replicate.nestedExpression().rows()),
m_cols(replicate.nestedExpression().cols())
{}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
CoeffReturnType coeff(Index row, Index col) const
{
// try to avoid using modulo; this is a pure optimization strategy
const Index actual_row = internal::traits<XprType>::RowsAtCompileTime==1 ? 0
: RowFactor==1 ? row
: row % m_rows.value();
const Index actual_col = internal::traits<XprType>::ColsAtCompileTime==1 ? 0
: ColFactor==1 ? col
: col % m_cols.value();
return m_argImpl.coeff(actual_row, actual_col);
}
[...]
protected:
const ArgTypeNested m_arg;
evaluator<ArgTypeNestedCleaned> m_argImpl;
const variable_if_dynamic<Index, ArgType::RowsAtCompileTime> m_rows;
const variable_if_dynamic<Index, ArgType::ColsAtCompileTime> m_cols;
};
我知道,如果你不熟悉这种机制,代码会很重,很难解释,这就是为什么我删除了除最相关部分之外的所有部分。您需要保留的是:replicate
只创建一个类型为Replicate
的表达式,它只存储对原始对象的引用、行副本的数量和列副本的数量;然后,当您想要从表达式中检索系数时,计算器使用modulo在原始矩阵中计算适当的索引,并返回相应的元素。