Matlab nested list data structure - matlab

I am thinking of recast a double for loop into something I can use with parallel computing. Specifically, I have
for i = 1 : N
x = x0+i*dx;
for j = 1 : N
y = y0+j*dy;
end
end
and the main program calls functions that require x and y as input arguments. In my problem the variables x and y are independent and so the two for loops should be able to recast into something simpler that can be run more efficiently taking advantage of matlab's matrix computations.
I'm thinking of creating a nested 2D array like (symbolically):
A = [{x0,y0},{x0,y1},{x0,y2},...,{x0,yN};
{x1,y0},{x1,y1},{x1,y2},...,{x1,yN};
...
{xN,y0},{xN,y1},{xN,y2},...,{xN,yN}]
i.e. each element in a 2D array is a 2-tuple {xi,yi} formed from the elements of the vectors x and y. Can I create such an object in matlab? If so, how can I call each individual element within each tuple? I need to have a way to call each element, e.g. x2 in {x2,y1}, in this array.
I am thinking of doing this so as to have the program run in parallel with input arguments given by each set of tuple {xi,yi} simultaneously, using the parallel processing toolbox on a GPU.
Many thanks in advance for your help.
James

I think what you are actually looking for is either meshgrid or ndgrid
>> [x y] = meshgrid( 1:N, 1:N )
For N=3 you'll get
>> [x y] = meshgrid( 1:3, 1:3 )
x =
1 2 3
1 2 3
1 2 3
y =
1 1 1
2 2 2
3 3 3
Now if you want to access a pair you can access its x and y coordinate for each matrix.
For example accessing the coordinates of ii=1, jj=2
>> ii=1; jj=2;
>> [x(ii,jj) y(ii,jj)]
Several comments
If you want both x and y to assume the same range of values (like in this example 1:N), you can skip the second arguemnt of meshgrid
>> [x y] = meshgrid( 1:N );
You can modify the inputs of meshgrid to capture the exact pattern you want for x and y, using dx and dy:
>> [x y] = meshgrid( x0 + (1:N)*dx, y0 + (1:N)*dy );
It is best not to use i and j as variable names in Matlab.

Related

Create arrays based on a different array

% create variable x with array of all necessary values
x=linspace(0.1,13,50);
for i=x
% create equation to determine y
y=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Using Matlab and im trying to use values from my x array to create two arrays, y and z, im pretty new to matlab and im struggling, thanks.
The problem in you code is that you did not use for loop properly. You can run through the index of x, then assign x(i) to a new variable k in each iteration, i.e.,
x=linspace(0.1,13,50);
for k = 1:length(x)
i = x(k);
% create equation to determine y
y(k) =(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(k) =log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Since MATLAB is able to vectorize the operations, so you are recommended to do it like below to speed up (for loop in MATLAB is expensive)
x = linspace(0.1,13,50);
y = (sqrt(2*x).*4.*x.^3)./(4*x+7^(x/10));
z = log10(2*x+5)+(4*x+exp(x))./(2/3 + 4*x.^2);
Remarks: you should be careful about the difference between .* and *, or ./ and /, where * and / are not element-wise operations.
Method 1:
you can initialize y and z into empty arrays and just append the corresponding result at the end:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
y=[];
z=[];
for i=x
% create equation to determine y
y(end+1)=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(end+1)=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
This approach can prove to be poor in terms of efficiency, since the size of y and z changes dynamically.
Method 2:
If you still want to use a for loop, it is better to preallocate memory for y and z and iterate the indices of x, something like:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
% Memory allocation
y = zeros(1, length(x));
z = zeros(1, length(x));
for i = 1 : length(x)
% create equation to determine y
y(i)=(sqrt(2.*x(i)*4*x(i).^3)/(4.*x(i)+7.^(x(i)/10));
%create equation to determine z
z(i)=log10(2.*x(i)+5)+(4.*x(i)+exp(x(i)))/(2./3+4.*x(i).^2);
end
Method 3 (preferred one):
It is generally more efficient to vectorize your implementations. In your case you could use something like:
x = linspace(0.1,13,50);
y = (sqrt(2.*x)*4*.*x.^3) ./ (4*x + 7.^(x./10));
z = log10(2*x+5) + (4*x + exp(x)) ./ (2/3 + 4*x.^2);

Using meshgrid in MATLAB when the function has matrix operations

I need to plot level surfaces of a 3 variable function. The variables are in a column vector X = [x, y, z]^t. The function is f(X) = X^t * A * X. Where ^t means transpose and A is a 3x3 constant matrix. I know for a fact that A is symmetric and therefore diagonalizable, i.e. A = V * D * V^t. Just in case it turns out to be useful.
I intend to use isosurface to get the points of the function where it equals a certain level and then use patch to plot.
However I can't figure out how to compute the value of the function for every point in the grid. Ideally I'd like to do
x = linspace(-1, 1,10); y=x; z = x;
[XX,YY,ZZ]=meshgrid(x,y,z);
f = [XX YY ZZ]'*A*[XX YY ZZ];
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue');
but this won't work obviously because of the sizes of XX and A. What I've done so far is do the math myself to obtain the function as a polynomial of XX, YY and ZZ but it's incredibly ugly and not practical.
Anybody knows how to do this? Thanks!
If I understand correctly, this does that you want. In the following explanation I will use 10x10x10 points as given in your example (although the code works for any number of points). Also, I define a random 3x3 matrix A.
Once XX, YY and ZZ have been generated as 10x10x10 arrays (step 1), the key is to build a 1000x3 matrix in which the first column is x coordinate, the second is y and the third is z. This is variable XYZ in the code below (step 2).
Since XYZ is a matrix, not a vector, the function f can't be computed using matrix multiplication. But it can be obtained efficiently with bsxfun. First compute an intermediate 1000x3x3 variable (XYZ2) with all 3x3 products of coordinates for each of the 1000 points (step 3). Then reshape it into a 1000x9 matrix and multiply by the 9x1 vector obtained from linearizing A (step 4).
The f thus obtained has size 1000x1. You need to reshape it into a 10x10x10 array to match XX, YY and ZZ (step 5). Then you can use isosurface as per your code (step 6).
A = rand(3);
x = linspace(-1, 1,10); y = x; z = x;
[XX,YY,ZZ] = meshgrid(x,y,z); %// step 1
XYZ = [XX(:) YY(:) ZZ(:)]; %// step 2
XYZ2 = bsxfun(#times, XYZ, permute(XYZ, [1 3 2])); %// step 3
f = reshape(XYZ2,[],numel(A))*A(:); %// step 4
f = reshape(f, size(XX)); %// step 5
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue'); %// step 6
I suspect that you could explicitly define your function as
ffun = #(x,y,z) [x y z]*A*[x; y; z];
then use arrayfun to apply this function to each element of your coordinate vectors:
f = arrayfun(ffun,XX,YY,ZZ);
This will return f(i)=ffun(XX(i),YY(i),ZZ(i)) for each i in 1:numel(XX), which I think is what you are after. The output f will have the same shape as your input arrays, which seems perfectly fine to use with isosurface later.

Matlab: work with 2NxN matrix

I have a matrix 2NxN.
And I want get some parametrs by this matrix. For example it:
How, I can do it?
You may want to break your 12x6 matrix, into two 6x6 matrix; let's say: Z and Zb (last one for z bar). Odd rows are Z and evens are Zb.
Considering M to be the combined matrices:
Z = M(1:2:end,:)
Zb = M(2:2:end,:)
read about the colon(:) operator and end to see what 1:2:end means.
Hope it helps.
From what I understand here are the first three:
% Random Matrix
% Needs to be defined before the functions since the functions look for
% the m variable
m = rand(12,6);
% Function 1
p = #(i,j) sign(m(i,j)+m(i+1,j)) * max(abs(m(i,j)),abs(m(i+1,j)));
p(2,2)
% Function 2 - Avg of row
pavg = #(i) mean(m(i,:));
pavg(2)
% Function 3
c = #(i,j) abs(m(i,j)+m(i+1,j)) / (abs(m(i,j)) + abs(m(i+1,j)));
c(2,2)

Getting the N-dimensional product of vectors

I am trying to write code to get the 'N-dimensional product' of vectors. So for example, if I have 2 vectors of length L, x & y, then the '2-dimensional product' is simply the regular vector product, R=x*y', so that each entry of R, R(i,j) is the product of the i'th element of x and the j'th element of y, aka R(i,j)=x(i)*y(j).
The problem is how to elegantly generalize this in matlab for arbitrary dimensions. This is I had 3 vectors, x,y,z, I want the 3 dimensional array, R, such that R(i,j,k)=x(i)*y(j)*z(k).
Same thing for 4 vectors, x1,x2,x3,x4: R(i1,i2,i3,i4)=x1(i1)*x2(i2)*x3(i3)*x4(i4), etc...
Also, I do NOT know the number of dimensions beforehand. The code must be able to handle an arbitrary number of input vectors, and the number of input vectors corresponds to the dimensionality of the final answer.
Is there any easy matlab trick to do this and avoid going through each element of R specifically?
Thanks!
I think by "regular vector product" you mean outer product.
In any case, you can use the ndgrid function. I like this more than using bsxfun as it's a little more straightforward.
% make some vectors
w = 1:10;
x = w+1;
y = x+1;
z = y+1;
vecs = {w,x,y,z};
nvecs = length(vecs);
[grids{1:nvecs}] = ndgrid(vecs{:});
R = grids{1};
for i=2:nvecs
R = R .* grids{i};
end;
% Check results
for i=1:10
for j=1:10
for k=1:10
for l=1:10
V(i,j,k,l) = R(i,j,k,l) == w(i)*x(j)*y(k)*z(l);
end;
end;
end;
end;
all(V(:))
ans = 1
The built-in function bsxfun is a fast utility that should be able to help. It is designed to perform 2 input functions on a per-element basis for two inputs with mismatching dimensions. Singletons dimensions are expanded, and non-singleton dimensions need to match. (It sounds confusing, but once grok'd it useful in many ways.)
As I understand your problem, you can adjust the dimension shape of each vector to define the dimension that it should be defined across. Then use nested bsxfun calls to perform the multiplication.
Example code follows:
%Some inputs, N-by-1 vectors
x = [1; 3; 9];
y = [1; 2; 4];
z = [1; 5];
%The computation you describe, using nested BSXFUN calls
bsxfun(#times, bsxfun(#times, ... %Nested BSX fun calls, 1 per dimension
x, ... % First argument, in dimension 1
permute(y,2:-1:1) ) , ... % Second argument, permuited to dimension 2
permute(z,3:-1:1) ) % Third argument, permuted to dimension 3
%Result
% ans(:,:,1) =
% 1 2 4
% 3 6 12
% 9 18 36
% ans(:,:,2) =
% 5 10 20
% 15 30 60
% 45 90 180
To handle an arbitrary number of dimensions, this can be expanded using a recursive or loop construct. The loop would look something like this:
allInputs = {[1; 3; 9], [1; 2; 4], [1; 5]};
accumulatedResult = allInputs {1};
for ix = 2:length(allInputs)
accumulatedResult = bsxfun(#times, ...
accumulatedResult, ...
permute(allInputs{ix},ix:-1:1));
end

How to generate a function of two variables without using any loop?

Suppose I have a function y(t,x) = exp(-t)*sin(x)
In Matlab, I define
t = [0: 0.5: 5];
x = [0: 0.1: 10*2*pi];
y = zeros(length(t), length(x)); % empty matrix init
Now, how do I define matrix y without using any loop, such that each element y(i,j) contains the value of desired function y at (t(i), x(j))? Below is how I did it using a for loop.
for i = 1:length(t)
y(i,:) = exp(-t(i)) .* sin(x);
end
Your input vectors x is 1xN and t is 1xM, output matrix y is MxN. To vectorize the code both x and t must have the same dimension as y.
[x_,t_] = meshgrid(x,t);
y_ = exp(-t_) .* sin(x_);
Your example is a simple 2D case. Function meshgrid() works also 3D. Sometimes you can not avoid the loop, in such cases, when your loop can go either 1:N or 1:M, choose the shortest one. Another function I use to prepare vector for vectorized equation (vector x matrix multiplication) is diag().
there is no need for meshgrid; simply use:
y = exp(-t(:)) * sin(x(:)'); %multiplies a column vector times a row vector.
Those might be helpful:
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/meshgrid.html
http://www.mathworks.com/company/newsletters/digest/sept00/meshgrid.html
Good Luck.