Eigen - 计算 2 组向量之间的距离矩阵
Eigen - Calculate the Distance Matrix between 2 Sets of Vectors
我需要创建一个特征数组,其中包含每个源和记录器位置之间的所有距离。
我有三个 Eigen::Array sx、sy 和 sz 表示源位置,三个 Eigen::Array rx、ry 和 rz 表示记录器位置。源和记录位置数组的长度不必相同。
使用for循环我可以计算距离矩阵如下
Eigen::ArrayXf sx, sy, sz;
Eigen::ArrayXf rx, ry, rz;
Eigen::ArrayXXf dist;
for (int s=0; s<nrSources; s++ ) {
for (int r=0; r<nrReceivers; r++) {
dist(h,g) = sqrt(pow(rx(h)-sx(g),2.)+
pow(ry(h)-sy(g),2.)+
pow(sz(h)-sz(g),2.));
}
}
我需要为实验计算 dist 数组 500 x 1000 次。使用 for 循环显然可行,但它可能不是最有效的方法,因为它不使用矢量化。
将 sx、sx、sz 和 hx、hy 和 hz 重写为 sxyz 和 hxyz 数组应该是可能的。
有没有可能更有效地写出方程式!?
您可能想要放弃内部循环以支持表达式。通过这样做,我们允许将计算集中在一起,并有望实现矢量化。假设 r
和 s
变量被声明为 Eigen::ArrayX3f sxyz(nrSources,3), rxyz(nrReceivers,3);
,那么您可以将外部循环写成:
for (int s = 0; s < nrSources; s++)
{
dist.col(s) =
(rxyz.rowwise() - sxyz.row(s)).matrix().rowwise().norm();
}
这里我们使用rxyz.rowwise() - sxyz.row(s)
从所有r
中减去第s个s
。需要 matrix()
才能访问 norm()
。
基准测试并与您的实施进行比较。
你可以看看我的项目Calculate Distance Matrix。
我实现了各种方法来计算 2 个任意向量集之间的距离矩阵。
实际上,Eigen 执行此操作的速度非常快(比使用 MSVC 的普通 C 实现慢得多)。
总之,上面的另一个方法是:
void CalcDistanceMatrixEigen(float* mD, float* mA, float* mB, int vecDim, int numRowsA, int numRowsB)
{
EigenMatExt meA(mA, vecDim, numRowsA);
EigenMatExt meB(mB, vecDim, numRowsB);
EigenMatExt meD(mD, numRowsA, numRowsB);
// meD = meA.colwise().squaredNorm().transpose() - (2 * meA.transpose() * meB) + meB.colwise().squaredNorm();
// Not even close to be as fast as MATLAB (Intel MKL???)
meD = ((-2 * meA.transpose() * meB).colwise() + meA.colwise().squaredNorm().transpose()).rowwise() + meB.colwise().squaredNorm();
}
看看文件就知道了。
您会看到我在 @AviGinsburg 和上述方法中比较了 Eigen,看起来我的速度更快(尽管再次使用 Vanilla C 比 Eigen 快得多)。
我需要创建一个特征数组,其中包含每个源和记录器位置之间的所有距离。
我有三个 Eigen::Array sx、sy 和 sz 表示源位置,三个 Eigen::Array rx、ry 和 rz 表示记录器位置。源和记录位置数组的长度不必相同。
使用for循环我可以计算距离矩阵如下
Eigen::ArrayXf sx, sy, sz;
Eigen::ArrayXf rx, ry, rz;
Eigen::ArrayXXf dist;
for (int s=0; s<nrSources; s++ ) {
for (int r=0; r<nrReceivers; r++) {
dist(h,g) = sqrt(pow(rx(h)-sx(g),2.)+
pow(ry(h)-sy(g),2.)+
pow(sz(h)-sz(g),2.));
}
}
我需要为实验计算 dist 数组 500 x 1000 次。使用 for 循环显然可行,但它可能不是最有效的方法,因为它不使用矢量化。
将 sx、sx、sz 和 hx、hy 和 hz 重写为 sxyz 和 hxyz 数组应该是可能的。
有没有可能更有效地写出方程式!?
您可能想要放弃内部循环以支持表达式。通过这样做,我们允许将计算集中在一起,并有望实现矢量化。假设 r
和 s
变量被声明为 Eigen::ArrayX3f sxyz(nrSources,3), rxyz(nrReceivers,3);
,那么您可以将外部循环写成:
for (int s = 0; s < nrSources; s++)
{
dist.col(s) =
(rxyz.rowwise() - sxyz.row(s)).matrix().rowwise().norm();
}
这里我们使用rxyz.rowwise() - sxyz.row(s)
从所有r
中减去第s个s
。需要 matrix()
才能访问 norm()
。
基准测试并与您的实施进行比较。
你可以看看我的项目Calculate Distance Matrix。
我实现了各种方法来计算 2 个任意向量集之间的距离矩阵。
实际上,Eigen 执行此操作的速度非常快(比使用 MSVC 的普通 C 实现慢得多)。
总之,上面的另一个方法是:
void CalcDistanceMatrixEigen(float* mD, float* mA, float* mB, int vecDim, int numRowsA, int numRowsB)
{
EigenMatExt meA(mA, vecDim, numRowsA);
EigenMatExt meB(mB, vecDim, numRowsB);
EigenMatExt meD(mD, numRowsA, numRowsB);
// meD = meA.colwise().squaredNorm().transpose() - (2 * meA.transpose() * meB) + meB.colwise().squaredNorm();
// Not even close to be as fast as MATLAB (Intel MKL???)
meD = ((-2 * meA.transpose() * meB).colwise() + meA.colwise().squaredNorm().transpose()).rowwise() + meB.colwise().squaredNorm();
}
看看文件就知道了。
您会看到我在 @AviGinsburg 和上述方法中比较了 Eigen,看起来我的速度更快(尽管再次使用 Vanilla C 比 Eigen 快得多)。