2011-09-09 39 views
2

Iは二重和を有する1 =メートル上:MN = 1:座標ローと極点のためNPHIZベクトル化MATLAB関数

Double summ over m and n

私はそれのベクトル表記を書いています:

N = 10; 
M = 10; 
n = 1:N; 
m = 1:M; 

rho = 1; 
phi = 1; 
z = 1; 

summ = cos (n*z) * besselj(m'-1, n*rho) * cos(m*phi)'; 

今座標ローPHIZのベクトル(列)を受け入れるため、この機能を書き換える必要があります。私はarrayfun、cellfun、単純なループを試してみました - 彼らは私にとっては遅すぎます。私は "MATLAB配列の操作のヒントとテクニック"について知っていますが、MATLABの初心者としては、repmatやその他の関数を理解できません。

誰でもベクトル化された解を提案できますか?各行列の要素i,jを選択することにより、あなたはmnの両方のために必要なインデックスを取得するようにするには、二つの行列を作成する必要が

+0

缶あなたは各変数の次元を詳しく説明します。私。 'rho'は' 1xA'などで、出力に期待する次元は何ですか。まず、これは私たちがあなたを助けるのに役立ちます。そして、これは、MATLABを使用する際に最初に考慮すべき適切な寸法として、あなた自身を助けるのに役立ちます。 – Egon

答えて

1

私はあなたのコードは(nmのために)すでによくベクトル化だと思います。この関数がrho/phi/zの値の配列も受け入れるようにしたい場合は、for-loopの値を処理することをお勧めします。これ以上のベクトル化が大幅に改善されるとは思えません。 )。

以下のコードでは、BESSELJ関数とCOS関数を1回呼び出すことで、さまざまなコンポーネントを乗算する部分をベクトル化しようとしました(私は各行/行列/ 3次元の列)。彼らの乗算は(ARRAYFUNは正確には)まだdone in a loopです:

%# parameters 
N = 10; M = 10; 
n = 1:N; m = 1:M; 

num = 50; 
rho = 1:num; phi = 1:num; z = 1:num; 

%# straightforward FOR-loop 
tic 
result1 = zeros(1,num); 
for i=1:num 
    result1(i) = cos(n*z(i)) * besselj(m'-1, n*rho(i)) * cos(m*phi(i))'; 
end 
toc 

%# vectorized computation of the components 
tic 
a = cos(bsxfun(@times, n, permute(z(:),[3 2 1]))); 
b = besselj(m'-1, reshape(bsxfun(@times,n,rho(:))',[],1)');    %' 
b = permute(reshape(b',[length(m) length(n) length(rho)]), [2 1 3]); %' 
c = cos(bsxfun(@times, m, permute(phi(:),[3 2 1]))); 
result2 = arrayfun(@(i) a(:,:,i)*b(:,:,i)*c(:,:,i)', 1:num);   %' 
toc 

%# make sure the two results are the same 
assert(isequal(result1,result2)) 

私はTIMEIT機能(より公平タイミングを与える)を使用して、別のベンチマークテストを行いました。その結果、以前と一致する:あなたが入力ベクトルのサイズを大きくすると、2つの方法が同様のタイミングを持って開始すること

0.0062407 # elapsed time (seconds) for the my solution 
0.015677  # elapsed time (seconds) for the FOR-loop solution 

注意(FORループは、さらにいくつかの場面で勝利)

+0

ありがとうございます。あなたのコードは超高速で動作します。このコードスニペットを 'bsxfun'と' permute'の例として残しておきます。 forループでarrayfunを置き換えようとしましたが、2〜10倍高速のコードが追加されました。 'arrayfun'と' cellfun'は通常のfor-loopよりも遅いようです。 – N0rbert

0

は、m_n_を言います。

ほとんどのMATLAB関数は、行列とベクトルを受け入れ、その結果を要素ごとに計算します。したがって、二重合計を生成するには、合計のすべての要素を並列にf(m_, n_)で計算し、合計します。あなたのケースでは

.*オペレータは行列の要素ごとの乗算を実行することに注意してください)

N = 10; 
M = 10; 
n = 1:N; 
m = 1:M; 

rho = 1; 
phi = 1; 
z = 1; 

% N rows x M columns for each matrix 
% n_ - all columns are identical 
% m_ - all rows are identical 
n_ = repmat(n', 1, M); 
m_ = repmat(m , N, 1); 

element_nm = cos (n_*z) .* besselj(m_-1, n_*rho) .* cos(m_*phi); 
sum_all = sum(element_nm(:)); 
+0

こんにちは、nimrodm!あなたの答えをありがとう。しかし、それは私が意味するものではありません。つまり、rho *、* phi *、* z *はベクトル、すなわちrho = 0:4、phi = 0:4、z = 0:4となります。あなたのコードはこれらの変数のベクトルを受け入れません。私のコード(* rho *、* phi *、* z *のスカラー値)と同じ結果が得られますが、私より620倍遅く実行されます。私の変種は{行N} * {行列N * M} * {列M} = {スカラー}を意味します。そのため、要素ごとの演算子(。*など)は使用しませんでした。 – N0rbert