3

ポインタとして与えられた次元 dim*dim のスパース行列 P があります

double* P

/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(dim,dim,mxREAL);

/* get a pointer to the real data in the output matrix*/
P = mxGetPr(plhs[0]);

Pを埋めるために多くのforループが必要であり、c ++はそのためのmatlabよりもはるかに高速であるため、これをmexファイルで行います。

現時点では、dim=22500 で、C++ が P を埋めるのに約 2 秒かかり (matlab では、このタスクに 50 秒かかりました)、matlab で行列を正規化するのに約 100 秒、matlab のすべてのゼロ列を消去するのに再び 100 秒かかります。これは、matlab で次のコードを使用して行います。

for i=1:size(P,1)
    if sum(P(i,:)) > 0
        sum(P(i,:))
        P(i,:)=(1/sum(P(i,:))).*P(i,:);
    end
end

% clear empty rows and colunms
P(~any(P,2),:)=[];
P(:,~any(P))=[];

私の質問は今です:これをC ++でも行うことができますか? 次の方法で C++ で P を正規化しようとしました。

int i;
int j;
int sum;
int get_idx(int x, int y, int rows) {
   return x +y * rows;   
}
/* NORMALIZE */
for(i = 0; i <dim; i++)  {
    sum=0;
    for(j=0; j<dim;j++) {   
        sum = sum + P[get_idx(i,j,dim)];
    }
    if(sum > 0) {
         for(j=0; j<dim;j++) {   
           P[get_idx(i,j,p_rows)]=P[get_idx(i,j,dim)]*(1/sum);
        }
    }
}

しかし、何らかの理由でこのコードは P を変更していないようです。また、これには c++ で約 85 秒かかります。また機能するより高速な方法はありますか?また、空の行と列をクリアすることは可能ですか?

4

1 に答える 1

5

なぜ C++ なのか?

正規化の前に空の行/列をクリアします。空のエントリを正規化する必要はありません。

正規化をベクトル化します。

s = sum(P, 2);
valid = s > 0;
P( valid,: ) = bsxfun(@rdivide, P(valid,:), s(valid) );

タダ!

はとても楽しいです!


更新:行/列の削減について。
簡単な調査の後、得るべき速度係数が ~x3 あると思います。

次の 3 つのオプションを検討してください。

  1. P( ~any(P,2), :) = []; P( :, ~any(P,1) ) = [];
  2. P( :, ~any(P,1) ) = []; P( ~any(P,2), :) = [];
  3. P = P( any(P,2), any(P,1) );

これら 3 つの代替案をテストすると、3 番目のものは ~x3 速く、最初のものは 2 番目のものよりわずかに (しかし一貫して) 遅いことがわかります。

なんで?
思い出してください、Matlab はマティックスを列優先でメモリに格納するため、行の前に列を削除すると、メモリのコピーと再割り当てを節約できます。

しかし、1 番目と 2 番目の方法では、メモリのコピーと再割り当てが2回行われます。つまり、行に対して 1 回、列に対して 1 回です。

于 2013-10-24T14:14:42.947 に答える