# How can I create a matrix with arrayfun

14 views (last 30 days)
Question Mr on 1 May 2021
Answered: Question Mr on 1 May 2021
i tried to swap the 2 FOR loops for arrayfun but i don't understand why it never wants to succeed.
TR = (2 * pi * M.theta) / 360;
PR = (2 * pi * M.phi) / 360;
[X,Y,Z] = sph2cart(TR,PR,1.0);
max = length(M.lab);
M(max,max) = 0;
MG = gpuArray(M);
for i = 1:max;
for j = 1:max;
M(i,j) = 1 - ( ( (X(i) - X(j))^2 + ...
(Y(i) - Y(j))^2 + (Z(i) - Z(j))^2 ) / 2 );
end;
end;
I have tried to implement these two for loops another function like this:
function M = gpuefg(X,Y,Z, maxiter)
M(maxiter,maxiter) = 0;
for i = 1:maxiter;
for j = 1:maxiter;
M(i,j) = 1 - ( ( (X(i) - X(j))^2 + ...
(Y(i) - Y(j))^2 + (Z(i) - Z(j))^2 ) / 2 );
end;
end;
end
and when I called its not worked. Wrong size.
I dont understand how can I swap these to for loops only for an arrayfun
Or how can I "create" a matrix with use arrayfun and use numerical calculations in the arrayfun?
I tried several ways but nothing
CG = arrayfun(@(X,Y,Z,max) gpuefg(X,Y,Z,max) );
CG = arrayfun(@gpuefg, M);
CG = arrayfun(@(X,Y,Z,max) gpuefg(X,Y,Z,max), M);
CG = arrayfun( @(X,Y,Z,max) gpuefg(M, X,Y,Z,max), X,Y,Z,max, 'UniformOutput', false );

Jan on 1 May 2021
The purpose of arrayfun is: "Apply function to each element of array".
This is not what you do in the nested for loops. This is a combination of different elements of different arrays. This means, that arrayfun is not a suitable apporach. Even if you get it to work, arrayfun is not necessarily faster than the clean and neat loops.
##### 2 CommentsShowHide 1 older comment
Jan on 1 May 2021
Edited: Jan on 1 May 2021
arrayfun provides the elements of the arrays elementwise to the function. Then the function gets X(i), Y(i), Z(i) only. The loop needs the complete arrays X,Y,Z also, so they have to be provided again as additional inputs. This is such indirect, that I would could assess this as "aggressive code obfuscation". Creating a matrix based on vectors using arrayfun is a really strange approach.
By the way, it makes it easier to write an asnwer if you provide running code. I have to guess, what M.theta, M.phi and M.lab is.
function speedTest
% Guessed test data:
n = 1e4;
TR = (2 * pi * linspace(0, pi, n)) / 360;
PR = (2 * pi * linspace(0, pi, n)) / 360;
[X,Y,Z] = sph2cart(TR,PR,1.0);
m = n;
% Original approach:
M(m,m) = 0;
tic
for i = 1:m
for j = 1:m
M(i, j) = 1 - ( ( (X(i) - X(j))^2 + ...
(Y(i) - Y(j))^2 + (Z(i) - Z(j))^2 ) / 2 );
end
end
toc
% Much faster with swapped loops (columnwise processing):
M2(m,m) = 0;
tic
for j = 1:m
for i = 1:m
M2(i, j) = 1 - ( ( (X(i) - X(j))^2 + ...
(Y(i) - Y(j))^2 + (Z(i) - Z(j))^2 ) / 2 );
end
end
toc
% Inner loop vectorized:
M3(m,m) = 0;
tic
for j = 1:m
M3(:, j) = 1 - 0.5 * ((X(:) - X(j)) .^ 2 + ...
(Y(:) - Y(j)) .^ 2 + (Z(:) - Z(j)) .^ 2) ;
end
toc
% Both loops vectorized:
tic;
M4 = 1 - 0.5 * ((X - X(:)) .^ 2 + (Y - Y(:)) .^ 2 + (Z - Z(:)) .^ 2);
toc
% Strange arrayfun approach:
tic
MC5 = arrayfun(@(x,y,z) fun(x,y,z, X,Y,Z, m), X, Y, Z, 'UniformOutput', false);
M5 = cat(1, MC5{:});
toc
% Do we get the same results?
isequal(M, M2, M3, M4, M5)
end
function M = fun(xi,yi,zi, X,Y,Z, m)
M(1, m) = 0;
for j = 1:m
M(j) = 1 - 0.5 * ((xi - X(j))^2 + (yi - Y(j))^2 + (zi - Z(j))^2);
end
end
% Core i7, Matlab R2018b:
% Elapsed time is 4.009399 seconds. Original
% Elapsed time is 0.390634 seconds. Swapped loops (10 times faster!)
% Elapsed time is 0.133837 seconds. Inner loop vectorized
% Elapsed time is 0.249436 seconds. Both loops vectorized
% Elapsed time is 2.565760 seconds. Strange arrayfun approach

Question Mr on 1 May 2021
Thank you it is working. And I got similar results like you. Can you explain the arrayfun part? How did you do and how is it working?