2017-11-04 5 views
2

私は、カーネルから行列を構築しようとしているので、A(i、j)= f(i、j)ここでi、jは両方のベクトルです(したがって、2つの行列x、y各行は点/ベクトルに対応する)。私の現在の機能は次のようになります。効率的な固有行列関数から

Eigen::MatrixXd get_kernel_matrix(const Eigen::MatrixXd& x, const Eigen::MatrixXd& y, double(&kernel)(const Eigen::VectorXd&)) { 
    Eigen::MatrixXd res (x.rows(), y.rows()); 
    for(int i = 0; i < res.rows() ; i++) { 
     for(int j = 0; j < res.cols(); j++) { 
      res(i, j) = kernel(x.row(i), y.row(j)); 
      } 
     } 
    } 
    return res; 
} 

(私の場合はそうはゼロによる除算を引き起こすことになる)対角線のためのいくつかのロジックと一緒に。

これを行うにはより効率的/イディオム的な方法がありますか?私のテストの中には、Matlabのコードが私のC++/Eigenの実装の速度を上回っているようです(私はベクトル化のために推測しています)。

私はかなりの量の文書(例えば、unaryExprの機能)を調べましたが、探しているものが見つからないようです。

ありがとうございました。そうしないと

#include <iostream> 
#include <Eigen/Dense> 
using namespace Eigen; 
using namespace std; 

double my_kernel(const MatrixXd::ConstRowXpr &x, const MatrixXd::ConstRowXpr &y) { 
    return x.dot(y); 
} 

template<typename Kernel> 
MatrixXd apply_kernel(const MatrixXd& x, const MatrixXd& y, Kernel kernel) { 
    return MatrixXd::NullaryExpr(x.rows(), y.rows(), 
       [&x,&y,&kernel](int i,int j) { return kernel(x.row(i), y.row(j)); }); 
} 

int main() 
{ 
    int n = 10; 
    MatrixXd X = MatrixXd::Random(n,n); 
    MatrixXd Y = MatrixXd::Random(n,n); 
    MatrixXd R = apply_kernel(X,Y,std::ptr_fun(my_kernel)); 
    std::cout << R << "\n\n"; 
    std::cout << X*Y.transpose() << "\n\n"; 
} 

ここ
MatrixXd res = MatrixXd::NullaryExpr(x.rows(), y.rows(), 
       [&x,&y,&kernel](int i,int j) { return kernel(x.row(i), y.row(j)); }); 

は行列積を再現する作業を自己完結型の例である:あなたはあなたのためのループを削除するには、適切なラムダとNullaryExprを使用することができます

答えて

1

apply_kernelをテンプレート関数にしたい場合は、std :: functionを使ってカーネルを渡すことができます。

+0

ありがとうございます!それは私がそれが欲しいものを行うべきであるように見えます。私はC++のラムダ式には新しく、カーネル関数を使うのに問題がありますが、修正ができたらうまくいきます。 –

+0

私は作業完了例を追加しました。 – ggael

+0

ありがとう、これは私の必要性を完全に満たしています。 –

関連する問題