How to vectorise the code below

2 views (last 30 days)
David Epstein
David Epstein on 21 Dec 2018
Edited: Stephen23 on 21 Dec 2018
I have asked about fsurf two or three times on this platform, and received two replies, neither of which extracted me from my difficulties. I have, however, made slow progress. I think I have found one bug in both execution and documentation of fsurf, and whether or not this is really a bug is still under consideration by Mathworks. I have finally succeeded in writing some code that actually outputs an image that seems to be related to what I am aiming at. The code is given the "green light" by the editor, but, when run produces many warnings. These all relate to the complaint that my code does not vectorize. Since the functions concerned are functions of two variables, I am not sure how fsurf would like me to change the code. Here is my code (called SE3):
close all; clear all; %#ok
R = 5; % centre of square is at r=R, z=0, where r is radial coord in (x,y)
%vertices of square in (x,z) plane.
A = [1,1,-1,-1,1;1,-1,-1,1,1];
figure; hold;
for x = 1:4
funx = @(ang,s) cos(ang)*(R + [cos(ang),sin(ang)]*(s*A(:,x)...
+ (1-s)*A(:,x+1)));
funy = @(ang,s) sin(ang)*(R + [cos(ang),sin(ang)]*(s*A(:,x)...
+ (1-s)*A(:,x+1)));
funz = @(ang,s)[-sin(ang),cos(ang)]*(s*A(:,x)+(1-s)*A(:,x+1));
fsurf(funx,funy,funz,[0,2*pi,0,1]);
end
hold off;
Here is the warning (only the first few lines of many warnings)
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize
your function to return an output with the same size and shape as the input arguments.
> In matlab.graphics.function.ParameterizedFunctionSurface>checkVectorization
In matlab.graphics.function.ParameterizedFunctionSurface/set.XFunction
In matlab.graphics.function.ParameterizedFunctionSurface
In fsurf>singleFsurf (line 263)
In fsurf>@(f1,f2,f3)singleFsurf(cax,{f1,f2,f3},extraOpts,args) (line 236)
In fsurf>vectorizeFsurf (line 236)
In fsurf (line 200)
In SE3 (line 12)
  8 Comments
David Epstein
David Epstein on 21 Dec 2018
@Stephen Cobeldick: Yes, I did ignore the instruction of have array inputs and outputs. I did this unconsciously, presumably because I couldn't make sense of the instruction. After this discussion, I do now understand what is required.
I had been ruling out the use of surf, because I was assuming it could only be used to display the graph of a real valued function of two variables. I looked again, after seeing your comment, and saw that one can use the syntax surf(X,Y,Z,C). This looks like a much better, and much simpler, approach than the one I was originally adopting, and on which you commented. And I can use matrices and matrix multiplication freely when defining X, Y and Z, which is a great relief.
@Rik Wisselink: Thanks for the further illumination. It's still a puzzle to me how I would use regular functions. (Anonymous functions are no good, because any natural code would require more than one executable.) In my code there are implicitly 12 distinct functions. A factor 4 for x=1:4 and a factor 3 for funx, funy and funz. As I understand Matlab (not very deeply) I cannot define regular functions in a loop. So this would be very ugly, very repetitive, and every improvement in the style of one function definition might be incorporated 12 times---which is very error prone.
I think I can now have a much more successful go at making this image. It has been a somewhat demoralizing experience trying and failing to get this to work, but I think that I finally know what I'm supposed to do.
Stephen23
Stephen23 on 21 Dec 2018
Edited: Stephen23 on 21 Dec 2018
@David Epstein: personally I have never found a use for fsurf and fplot and all those other magical plotting functions. I like to know what my data is doing, which means using meshgrid or ndgrid and generating the values myself. Don't feel demoralized, just chalk it up to experience.
" It's still a puzzle to me how I would use regular functions.... In my code there are implicitly 12 distinct functions. A factor 4 for x=1:4 ..."
One way would be to note that x (and possibly others) are also variables: you don't just have a function of two variables, but a function of three (or four or five) variables, so you can write a function that with those input arguments:
function out = funX(ang,S,x,...)
out = ...
end
and then within the code you can specify those values explicitly or use define a parametrized function, e.g. within your loop:
fx = @(a,s)funX(a,s,x);
...
fsurf(fx, ...)
Thus it would be easy to bring it down to two functions by specifying the X/Y functions and inputting a function handle to distinguish:
function out = funXY(ang,S,x,fun)
out = fun(ang) .* ...;
end
So then you can specify the first factor when the function is parameterized:
fx = @(a,s)funXY(a,s,x,@cos);
fy = @(a,s)funXY(a,s,x,@sin);
...
fsurf(fx, fy, ...)

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 21 Dec 2018
Here are some vectorized versions of your functions:
R = 5;
A = [1,1,-1,-1,1;1,-1,-1,1,1];
B = cat(3,A(1,:),A(2,:));
for x = 1:4
% Vectorized:
fz = @(ang,s) sum(cat(3,-sin(ang),+cos(ang)).*(s.*B(1,x,:)+(1-s).*B(1,x+1,:)),3);
fa = @(ang,s) sum(cat(3,+cos(ang),+sin(ang)).*(s.*B(1,x,:)+(1-s).*B(1,x+1,:)),3);
fx = @(ang,s) cos(ang).*(R + fa(ang,s));
fy = @(ang,s) sin(ang).*(R + fa(ang,s));
% Original:
funx = @(ang,s) cos(ang)*(R + [cos(ang),sin(ang)]*(s*A(:,x) + (1-s)*A(:,x+1)));
funy = @(ang,s) sin(ang)*(R + [cos(ang),sin(ang)]*(s*A(:,x) + (1-s)*A(:,x+1)));
funz = @(ang,s)[-sin(ang),cos(ang)]*(s*A(:,x)+(1-s)*A(:,x+1));
% Compare:
new = fx(G,S); % can be called by FSURF.
old = arrayfun(funx,G,S);
all(abs(new(:)-old(:))<1e-10)
end

More Answers (0)

Products


Release

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!