Ускорьте циклы `for` или векторизуйте их - PullRequest
0 голосов
/ 17 апреля 2011

Я написал некоторый код, но моя программа работает слишком медленно.Проблема в следующем:

Я построю Матрицу "A", чтобы решить проблему Ax = b

У меня есть сфера (это может быть любая форма), которая показана какой-то точкой,

Я назначил вектор координат [xyz] для каждой точки.

N - количество точек.

Пожалуйста, сначала загрузите (a)

clc 
[rv,N,d0]=geometrySphere(5e-9,10);         %#  Nx3 matrix [x1 y1 z1;x2 y2 z2;... ].

%# geometrySphere is a function for replacicg the sphere with points.
 L=(301:500)*1e-9;  K=2*pi./L;                   %# 1x200 array 
 %some constants ==================
 I=eye(3);
 e0=1;
 V=N*d0^3; aeq=(3*V/(4*pi))^(1/3);
 E0y=ones(N,1);
 E0z=E0y;
 Cext=zeros(1,200);
 Qext=zeros(1,200);
 A=zeros(3,3,N^2);
 %=================================
for i=1:N
    r(i)=sqrt(rv(i,1)^2+rv(i,2)^2+rv(i,3)^2);    %# r is the size of each vector 
end
for i=1:N
    for j=1:N
        dx(i,j)=rv(i,1)-rv(j,1); %# The x component of distance between each 2 point
        dy(i,j)=rv(i,2)-rv(j,2);
        dz(i,j)=rv(i,3)-rv(j,3);
    end
end
d=cat(3,dx,dy,dz);  %# d is the distance between each 2 point (a 3D matrix)
nd=sqrt(dx.^2+dy.^2+dz.^2);                     %# Norm of rv vector
nx=d(:,:,1)./nd; ny=d(:,:,2)./nd; nz=d(:,:,3)./nd;
n=cat(3,nx,ny,nz);                              %# Unit vectors for points that construct my sphere


 for s=1:length(L)
    E0x=exp(1i*K(s)*rv(:,1))';                   
    % 1x200 array  in direction of x(in Cartesian coordinate system)
    % Main Loop    =================================================
    p=1;                                                        
    for ii=1:N                                                  
        for jj=1:N                                              
            if ii==jj                                           
                A(:,:,p)=a(s)*eye(3);           %# 3x3 , a is a 1x200 constant array                        
                p=p+1;                          %# p is only a counter              
            else                                                
            A(:,:,p)=-exp(1i*K(s)*nd(ii,jj))/nd(ii,jj)*(-K(s)^2*([nx(ii,jj);ny(ii,jj);nz(ii,jj)]... 
                *[nx(ii,jj) ny(ii,jj) nz(ii,jj)]-I)+(1/nd(ii,jj)^2-1i*K(s)/nd(ii,jj))...             
                *(3*[nx(ii,jj);ny(ii,jj);nz(ii,jj)]*[nx(ii,jj) ny(ii,jj) nz(ii,jj)]-I));             
            p=p+1;          
            end                                             
        end                                                 
    end                                                     

%===============================================================
B = reshape(permute(reshape(A,3,3*N,[]),[2 1 3]),3*N,[]).';
%# concatenation of N^2 3x3 matrixes into a 3Nx3N matrix
    for i=1:N
        E00(:,i)=[E0x(i) E0y(i) E0z(i)]';
    end
    b=reshape(E00,3*N,1);
    P=inv(B)*b;
    Cext(s)=(4*pi*K(s))*imag(b'*P);
    Qext(s)=Cext(s)/(pi*aeq^2);
 end

Qmax=max(Qext); Qext=Qext/Qmax;
L=L*1e9;
plot(L,Qext,'--');figure(gcf)

Я не знаю, могу ли я объяснить ясно?

Есть ли у вас какие-либо предложения?Заранее благодарим за любые предложения.

geometrySphere Matrix A Где I - это единичная матрица 3x3, а nij nij обозначает двоичное произведение.n_ij n_ij

(a) после запуска функции: массив 1x200

1 Ответ

2 голосов
/ 17 апреля 2011

Первые два цикла могут быть легко заменены следующими векторными операциями (я не проверял это):

r=sqrt(sum(rv,2).^2);
[npoints,ndims]=size(rv);
pairs=combnk(1:npoints,2);
npairs=size(pairs,1);

index=repmat(pairs(:),ndims,1)+npoints*reshape(repmat(0:ndims-1,npairs*2,1),npairs*2*ndims,1);
d=reshape(reshape(rv(index),npairs*ndims,2)*[1 -1]',npairs,ndims);           %'
n=bsxfun(@rdivide,d,sqrt(sum(d.^2,2))); 

Обратите внимание, что в вашем случае dx, dy и dz будут кососимметричными матрицами с нулевыми диагоналями и, следовательно, только N(N-1)/2 независимыми элементами. Это соединение может быть достигнуто с помощью combnk, что дает все возможные пары из n предметов. Следовательно, d здесь представляет собой массив элементов N(N-1)/2x3, тогда как ваш d является массивом NxNx3, но содержит ту же информацию.

Теперь основной цикл также выглядит так, как будто его можно векторизовать, однако он слишком длинный, и я не хочу тратить время на просмотр всех индексов. Но вот несколько советов:

  1. Вы можете выполнять поэлементные операции в MATLAB, используя префикс . перед оператором. Поэтому, если у вас есть два равномерных массива / вектора, например, A=[a b c] и B=[d e f] (предположим, что они действительные), скалярное произведение двух векторов будет просто A.*B, что дает [ad be cf]. Подобные правила для разделения и возведения его в силу. Вы можете прочитать больше об этом здесь .
  2. Матричные умножения можно выполнять с помощью оператора * (здесь нет точек), и внутренние размеры должны совпадать. Таким образом, в приведенном выше примере внутренний продукт просто равен A*B', что дает вам ad+be+cf, а внешний продукт (двоичный продукт) равен A'*B, что дает вам матрицу 3x3: [ad ae af;bd be bf;cd ce cf]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...