在 Matlab 中,既有 repmat 也有 repelem。对于大小为[d, n1]
和[d, n2]
的矩阵x1
和x2
,您可以在 Matlab 中执行此操作:
n1 = size(x1, 2);
n2 = size(x2, 2);
M = repmat(x1, 1, n2) - repelem(x2, 1, n1);
什么是等效的特征码?以下是我不太满意的四种变体。我想知道它是否可以制作成更快的单行本?
TL;DR:变体 2 是最好的,但它取决于编译器和其他东西。
int d = x1.rows();
int n1 = x1.cols();
int n2 = x2.cols();
Eigen::MatrixXd M(d, n1*n2);
// Variant 1:
int idx = 0;
for (int c = 0; c != n2; c++) {
for (int r = 0; r != n1; r++) {
M.col(idx) = x1.col(r) - x2.col(c);
idx += 1;
}
}
// Variant 2:
for (int c = 0, idx = 0; c != n2; c += 1, idx += n1)
M.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
// Variant 3:
M = - x2.replicate(n1, 1);
M.resize(d, n1*n2);
M += x1.replicate(1, n2);
// Variant 5:
M = x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
以下是我目前的时间安排,有关完整代码,请参见下文。Matlab 时序适用于多线程和单线程 Matlab R2017b。 C++使用标志-O3 -DNDEBUG -march=native -mtune=native
编译的版本。所有这些都在i5-6500
上运行,所以我有AVX
。
时间(秒( 代码 gcc-7 gcc-8 叮当-6 ----------------------------------- 马特拉布 mt 51 Matlab st 84 V. 1 38 37 57 V. 2 36 34 23 V. 3 598 599 187 V. 5 94 172 107
矩阵代码:
ds = 1:10;
n1s = 5:5:500;
n2s = 5:5:500;
z1 = randn(max(ds), max(n1s));
z2 = randn(max(ds), max(n2s));
tic;
s = 0;
for idx = 1:numel(ds)
for jdx = 1:numel(n1s)
for kdx = 1:numel(n2s)
K = MFdiff(z1(1:ds(idx), 1:n1s(jdx)),...
z2(1:ds(idx), 1:n2s(kdx)));
s = s + K(1,1);
end
end
end
toc
C++代码:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
template <typename Derived1, typename Derived2>
MatrixXd MFdiff1(
DenseBase<Derived1> const & x1,
DenseBase<Derived2> const & x2)
{
int d = x1.rows();
int n1 = x1.cols();
int n2 = x2.cols();
MatrixXd out(d, n1*n2);
int idx = 0;
for (int c = 0; c != n2; c++) {
for (int r = 0; r != n1; r++) {
out.col(idx) = x1.col(r) - x2.col(c);
idx += 1;
}
}
return out;
}
template <typename Derived1, typename Derived2>
MatrixXd MFdiff2(
DenseBase<Derived1> const & x1,
DenseBase<Derived2> const & x2)
{
int d = x1.rows();
int n1 = x1.cols();
int n2 = x2.cols();
MatrixXd out(d, n1*n2);
for (int c = 0, idx = 0; c != n2; c+=1, idx += n1)
out.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
return out;
}
template <typename Derived1, typename Derived2>
MatrixXd MFdiff3(
DenseBase<Derived1> const & x1,
DenseBase<Derived2> const & x2)
{
int d = x1.rows();
int n1 = x1.cols();
int n2 = x2.cols();
MatrixXd out;
out = - x2.replicate(n1, 1);
out.resize(d, n1*n2);
out += x1.replicate(1, n2);
return out;
}
template <typename Derived1, typename Derived2>
MatrixXd MFdiff5(
DenseBase<Derived1> const & x1,
DenseBase<Derived2> const & x2)
{
int n1 = x1.cols();
int n2 = x2.cols();
return x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
}
double test(VectorXi const & ds,
VectorXi const & n1s,
VectorXi const & n2s)
{
MatrixXd z1 = MatrixXd::Random(ds.maxCoeff(), n1s.maxCoeff());
MatrixXd z2 = MatrixXd::Random(ds.maxCoeff(), n2s.maxCoeff());
double s = 0;
for (int idx = 0; idx!=ds.rows(); idx++) {
for (int jdx = 0; jdx!=n1s.rows(); jdx++) {
for (int kdx = 0; kdx!=n2s.rows(); kdx++) {
MatrixXd K = MFdiff5(z1.block(0, 0, ds(idx), n1s(jdx)),
z2.block(0, 0, ds(idx), n2s(kdx)));
s += K(0,0);
}
}
}
return s;
}
int main() {
VectorXi ds = VectorXi::LinSpaced(10, 1, 10);
VectorXi n1s = VectorXi::LinSpaced(100, 5, 500);
VectorXi n2s = VectorXi::LinSpaced(100, 5, 500);
std::cout << test(ds, n1s, n2s) << 'n';
}
用本征的头你可以写:
M = x1.rowwise().replicate(n2) - x2(Eigen::all,VectorXi::LinSpaced(n1*n2,0,n2-1));
速度与变体 2 相同。
自包含基准测试(BenchTimer.h
需要存储库的克隆(,使用 gcc 7 和 clang 6 进行了-O3 -DNDEBUG
测试:
#include <iostream>
#include <Eigen/Dense>
#include <bench/BenchTimer.h>
using namespace Eigen;
using namespace std;
EIGEN_DONT_INLINE
void foo1(const MatrixXd& x1, const MatrixXd& x2, MatrixXd& M)
{
int d = x1.rows();
int n1 = x1.cols();
int n2 = x2.cols();
int idx = 0;
for (int c = 0; c != n2; c++) {
M.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
idx += n1;
}
}
EIGEN_DONT_INLINE
void foo2(const MatrixXd& x1, const MatrixXd& x2, MatrixXd& M)
{
int n1 = x1.cols();
int n2 = x2.cols();
M = x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
}
int main()
{
int tries = 2;
int rep = 1;
int d = 100;
int n1 = 100;
int n2 = 100;
MatrixXd x1(d,n1); x1.setRandom();
MatrixXd x2(d,n2); x2.setRandom();
MatrixXd M(d, n1*n2);
BenchTimer t;
BENCH(t, tries, rep, foo1(x1, x2, M));
std::cout << "Time: " << t.best() << "s" << std::endl;
BENCH(t, tries, rep, foo2(x1, x2, M));
std::cout << "Time: " << t.best() << "s" << std::endl;
}