%% Lesson 3a: Meshes & Broadcasting

%% Meshgrid
% Meshgrid is quite hard to understand. Think of it as a way to replicate
% arrays, like the following example:
a = 1:3;
b = 1:5;
[A,B] = meshgrid(a,b);

%% Using meshgrid for functions of multiple variables
% You have created two arrays A and B, note that in A, the vector a is copied
% row-wise, while the vector b is transposed and copied column-wise.  This is
% useful, because when you lay one above the other, you essentially create a
% CARTESIAN PRODUCT, and it is useful when we need to plot a 3D graph.
% 
% Here is a more complicated example to show you when meshgrid is useful
a1 = -2:0.25:2;
b1 = a1;
[A1,B1] = meshgrid(a1);

% Here we plot the surface of f(x) = x*exp^(x.^2+y.^2)
F = A1.*exp(-A1.^2-B1.^2);
surf(A1, B1, F);

%% Broadcasting: an alternative to meshgrid
% Broadcasting, like meshgrid, can be used as a way to write functions of
% multiple variables, without generating the intermediate matrices A and B.
% The way this works is that operations performed on a set of N orthogonal
% vectors will automatically generate an N-dimensional result.
% 
% See the following example, which recreates the above example. Note that b1 is
% transposed.
F2 = a1.*exp(-a1.^2-(b1.').^2);
surf(A1, B1, F2);

% Check that this matches the previous result.
error = rms(F - F2, 'all');

% Note: broadcasting doesn't generate the domains A1 and B1, so meshgrid() is
% more useful when we need to supply the domain to a function like mesh() or
% surf(). But when we only need the result, broadcasting is somewhat simpler.
%
% For homework assignments that require functions of multiple variables, use
% whichever method is more intuitive to you.
