Apply functions to all elements of an array of matrices - matlab

I have four 52-by-140 matrices in Matlab. Lets call them a, b, c, and d:
I want to apply the eigs function to a Hessian matrix [a,b;c,d] for every point in the original matrix like:
for i = 1:52
for j = 1:140
eigs([a(i,j),b(i,j);c(i,j),d(i,j)])
end
end
How can I do this in a simpler way, i.e., without for loops?

This can probably be done using arrayfun and defining the action you do in a single iteration using an anonymous function (untested)
result = arrayfun(#(a_ij, b_ij, c_ij, d_ij) eigs([a_ij, b_ij; c_ij, d_ij]), ...
a, b, c, d, 'uniformoutput', false);
Note that since eig returns a vector, the result can only be stored in a cell array.
You could name the parameters of the anonymous functions a, b, ... instead of a_ij, b_ij, ..., since they are only used inside the function, but I prefer to it this way to make it clear that inside the function you are using scalars, while the parameters to arrayfun are matrices. Personally, I often use upper/lower case to indicate the difference:
result = arrayfun(#(a, b, c, d) eigs([a, b; c, d]), A, B, C, D, 'uni', 0);
but then you would have to rename your variables.

Try this solution to get all of the matrixes teed up:
>> abcd = cat(3,a,b,c,d);
>> H = permute(reshape(permute(abcd,[3 1 2]),2,2,[]),[2 1 3]);
>> size(H)
ans =
2 2 7280
>> i=3;j=2;
>> [a(i,j),b(i,j);c(i,j),d(i,j)]
ans =
0.4984 0.7935
0.3524 0.2273
>> H(:,:,i+(j-1)*size(abcd,1))
ans =
0.4984 0.7935
0.3524 0.2273
>>
Then to run eigs on all 2D matrixes in H:
E=arrayfun(#(i)eigs(H(:,:,i)),1:size(H,3),'uni',false);

Related

Multiply each element of a vector by each element of another vector

I have two very big column vectors, A and B, of size ax1 and bx1, respectively. I want to construct a vector C of size (b*a)x1 by computing A(i)*B(j) for each i and j. To illustrate what I mean:
clear
a=10^3;
b=10^3;
A=randn(a,1);
B=randn(b,1);
Ctemp=zeros(a,b);
for i=1:a
for j=1:b
Ctemp(i,j)=A(i)*B(j);
end
end
C=reshape(Ctemp, a*b,1);
Question: is there a more efficient way to obtain C which avoid double looping? My actual a and b are bigger than 10^3.
This is a simple case of array multiplication that can benefit from implicit (or explicit) expansion:
% Implicit (R2016b and newer):
C = A(:) .* B(:).'; % optionally surround by reshape( ... , [], 1);
% "Explicit" (R2007a and newer):
C = bsxfun( #times, A(:), B(:).' );
From there it's just a matter of reshaping, as you're already doing (D = C(:) or D = C(:).').
You can also calculate the outer product of the vectors, resulting in a matrix of your required terms:
C = A*B'; % Assuming A,B are column vectors here
And reshape the output afterward as stated. Not sure if more efficient though.

Is there a version of bsxfun that works on structure arrays?

Why can I do this:
a = [1 2];
b = [3 4];
bsxfun(#(ai,bj) ai + bj, a, b')
% 4 5
% 5 6
But not this:
a = struct('x', {1 2});
b = struct('x', {3 4});
bsxfun(#(ai,bj) ai.x + bj.x, a, b');
% Error using bsxfun
% Operands must be numeric arrays.
And does a replacement function exist that works in both cases?
This may not be a general solution* but for your particular example it is easy to convert your structure array to a numerical array inside bsxfun, by using comma-separated-list generator syntax, and then using your original anonymous function, i.e.
>> bsxfun(#(ai, bj) ai+bj, [a.x], [b.x]')
ans =
4 5
5 6
and this should still leverage the computational efficiency conferred by bsxfun (as opposed to the much slower "repmat+arrayfun" approach, for instance).
*e.g. it might not work as intended if your field contains an array instead of a scalar, since the expansion to a comma-separated-list will be different
A hacky workaround:
function res = bsxfun_struct(f, A, B)
% best way to ensure our output size matches the behaviour of bsxfun is just to call it
dummy = bsxfun(#(ai, bj) ai+bj, zeros(size(A)), zeros(size(B)));
res_size = size(dummy);
% repeat the matrices as needed
Arep = repmat(A, res_size ./ size(A));
Brep = repmat(B, res_size ./ size(B));
% now we can just apply the function pairwise
res = arrayfun(f, Arep, Brep);
end

Apply a function to each sub-cell of a cell in Matlab?

I have a cell C in Matlab of dimension mx1, e.g. m=3
C={{1 2 3} {4 5 6} {7 8 9 10}}
Then I have a function g written in a separate m-file
function D=g(C{i},a,b)
...
end
that takes any sub-cell C{i} of C and using some other parameters a and b gives a vector D of dimension fx1.
I want to apply the function g to each sub-cell of C and assemble the obtained fx1 vectors in a matrix fxm without using loops. I have seen the command cellfun but I don't know how to make it working with a function written by myself. Any suggestion?
Simple. First make a handle to the function where the only input is the cell array:
h = #(x) D(x, a, b);
Here, x would be a cell from the cell array. Also, I'm going to assume that a and b are already defined in your workspace. After, just do this:
out = cellfun(h, C, 'uni', 0);
The first argument is a handle to the function, which we've already defined. The next parameter is the cell array you want to operate on and apply the function h to every cell in your array. You need to specify the uni=0 flag because the output is non-uniform. Because your function outputs a vector per cell, this is mandatory. If your function outputted a single value, then this declaration of uni=0 is not required.
Alternatively, you can do this in a loop... which is what cellfun ultimately performs:
out = cell(numel(C), 1);
for idx = 1 : numel(C)
out{idx} = D(C{idx}, a, b);
end
To me, the second option is more suitable for those who aren't used to using cellfun.

how to concatenate two images vertically in matlab?

>> a=imread ('Vasculature.tif');
>> b = imresize (a, [400,400]);
>> c=imread ('activation.tif');
>> d= imresize (c, [400,400]);
>> e=imadd (b,d);
the code I was able to work with was for horizontal concatenation pls do tell me concatenating the image vertically..
Get the images and make a matrix of them,
use for matrix a and matrix b,
c = vertcat(a,b)
Alternatively, you can use cat:
c = cat(1, a, b);
You can also use straight MATLAB matrix building:
c = [a; b];
This is assuming that the images have the same number of columns. Doing c = [a b] concatenates matrices column-wise. If you want to do it by row, use the semi-colon. Take a look at this basic tutorial on MATLAB operations here to get you started: http://www.mathworks.com/help/matlab/examples/basic-matrix-operations.html

Matlab code that outputs several matrices

I'm trying to write a Matlab code that, given a matrix, outputs 3 matrices (according to some rules). I'm having difficulty getting this to work though - I can't output a vector with matrices as entries. I get the error message:
??? In an assignment A(I) = B, the number of elements in B and I
must be the same.
How can I go about doing this?
You could write
function [A B C] = myFunction(X)
A = X;
B = 2 * X;
C = 3 * X;
end
and call it with
[a b c] = myFunction(ones(2))
If you won't want all of the outputs, just call it with
a = myFunction(ones(2))
or
[a b] = myFunction(ones(2))
to get just the first argument, or just the first two arguments.
You can also use cells:
A=cell(1,3); %% or A=cell(1,2); if you want to output only 2 matrices
A{1}=B;
A{2}=C;
A{3}=D;
If your matrices all have the same size you can also concatenate them:
A=zeros(m,n,3);
A(:,:,1)=B;
A(:,:,2)=C;
A(:,:,3)=D;
Function declaration:
function [A, B, C] = something (Input_mat)
%Do whatever needs to be done here, for example:
A= Input_mat;
B= Input_mat';
C= ones(18);
And then when you call it using:
[A,B,C] = something (Some_mat)
A, B and C are filled.