Evaluate all pairs of matrices - matlab

I have a function f which takes 2 matrices with the same number of rows and procudes a scalar value. A am now looking for a possibility to create a new function which takes two lists of matrices and calls f for all pairs.
I need a moore efficient implementation of this loop:
% X = cell of matrices
% Y = cell of matrices
for k=1:length(X)
for l=1:length(Y)
M(k,l) = f(X{k},Y{l});
end
end
(It is not a requirement that X and Y are cells)
For example f could be the mean of squared distances
f = #(X,Y) mean(mean(bsxfun(#plus,dot(X,X,1)',dot(Y,Y,1))-2*(X'*Y)));
but don't question f, it is just an example of a much more complicated problem.

Firstly you should be pre-allocating M. Then you can cut out one loop quite easily by using meshgrid to generate a list of all pairs of elements in X and Y:
[K, L] = meshgrid(1:length(X), 1:length(Y));
M = zeros(size(K)); %//This preallocation alone should give you a significant speed up
for ii = 1:numel(K)
M(ii) = f(X{K(ii)},Y{L(ii)});
end
However, if you can implement f so that it is properly vectorized, you might be able to pass it two 3D matrices, i.e. the entire list of X and Y pairs and do it without a loop at all. But this depends entirely on what it is that your f does.

On possible solution that works is using cellfun
fy = #(x,Y) cellfun(#(y) f(x,y), Y);
fx = #(X,Y) cellfun(#(x) fy(x,Y), X, 'UniformOutput', false);
newF = #(X,Y) cell2mat(fx(X,Y)')';
however I suppose there is a better way to do this.

Related

Matlab: how to run a For loop with multiple outputs?

So my question refers to the regress() function in matlab. Click here for the Matlab documentation
If I want to run multiple regressions using this function and output both the coefficients and the confidence intervals, what's the best way to do this in a For loop?
Matlab's own syntax for this is [b,bint] = regress(y,X). But when I try to implement this in a for loop it tells me that the dimension mismatch. My code is the following:
for i=1:6
[a, b]=regress(Dataset(:,i),capm_factors);
capm_coefs(i,:)=a;
capm_ci(i,:)=b;
end
Please help, thanks!
regress outputs a column vector of coefficients that minimize the least squared error between your input data (capm_factors) and your predicted values (Dataset(:,i)). However, in your for loop, you are assuming that a and b are row vectors.
Also, the first output of regress is the solution to your system, but the second output contains a matrix of confidence values where the first column denotes the lower end of the confidence interval for each variable and the second column denotes the upper end of the confidence interval.
Specifically, your input capm_factors should be a M x N matrix where M is the total number of input samples and N is the total number of features. In your code, a would thus give you a N x 1 vector and b would give you a N x 2 matrix.
If you'd like use a loop, make sure capm_coefs is a N x l matrix where l is the total number of times you want to loop and capm_ci should either be a N x 2 x l 3D matrix or perhaps a l element cell array. Either way is acceptable.... but I'll show you how to do both.
Something like this comes to mind:
Confidences as a 3D matrix
l = 6; %// Define # of trials
[M,N] = size(capm_factors); %// Get dimensions of data
capm_coefs = zeros(N, l);
capm_ci = zeros(N, 2, l);
for ii = 1 : l
[a,b] = regress(Dataset(:,i), capm_factors);
capm_coefs(:,ii) = a;
capm_ci(:,:,ii) = b;
end
You'd then access the coefficients for a trial via capm_coefs(:,ii) where ii is the iteration you want. Similarly, the confidence matrix can be accessed via capm_ci(:,:,ii)
Confidences as a cell array
l = 6; %// Define # of trials
[M,N] = size(capm_factors); %// Get dimensions of data
capm_coefs = zeros(N, l);
capm_ci = cell(l); %// Cell array declaration
for ii = 1 : l
[a,b] = regress(Dataset(:,i), capm_factors);
capm_coefs(:,ii) = a;
capm_ci{ii} = b; %// Assign confidences to cell array
end
Like above, you'd access the coefficients for a trial via capm_coefs(:,ii) where ii is the iteration you want. However, the confidence matrix can be accessed via capm_ci{ii} as we are now dealing with cell arrays.

Extract and then sum sub-matrices in Matlab [duplicate]

Given a square matrix of say size 400x400, how would I go about splitting this into constituent sub-matrices of 20x20 using a for-loop? I can't even think where to begin!
I imagine I want something like :
[x,y] = size(matrix)
for i = 1:20:x
for j = 1:20:y
but I'm unsure how I would proceed. Thoughts?
Well, I know that the poster explicitly asked for a for loop, and Jeff Mather's answer provided exactly that.
But still I got curious whether it is possible to decompose a matrix into tiles (sub-matrices) of a given size without a loop. In case someone else is curious, too, here's what I have come up with:
T = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3])
transforms a two-dimensional array A into a three-dimensional array T, where each 2d slice T(:, :, i) is one of the tiles of size m x n. The third index enumerates the tiles in standard Matlab linearized order, tile rows first.
The variant
T = permute(reshape(A, size(A, 1), n, []), [2 1 3]);
T = permute(reshape(T, n, m, [], size(T, 3)), [2 1 3 4]);
makes T a four-dimensional array where T(:, :, i, j) gives the 2d slice with tile indices i, j.
Coming up with these expressions feels a bit like solving a sliding puzzle. ;-)
I'm sorry that my answer does not use a for loop either, but this would also do the trick:
cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)
You can then access the individual cells like:
cellOf20x20matrices{i,j}(a,b)
where i,j is the submatrix to fetch (and a,b is the indexing into that matrix if needed)
Regards
You seem really close. Just using the problem as you described it (400-by-400, divided into 20-by-20 chunks), wouldn't this do what you want?
[x,y] = size(M);
for i = 1:20:x
for j = 1:20:y
tmp = M(i:(i+19), j:(j+19));
% Do something interesting with "tmp" here.
end
end
Even though the question is basically for 2D matrices, inspired by A. Donda's answer I would like to expand his answer to 3D matrices so that this technique could be used in cropping True Color images (3D)
A = imread('peppers.png'); %// size(384x512x3)
nCol = 4; %// number of Col blocks
nRow = 2; %// number of Row blocks
m = size(A,1)/nRow; %// Sub-matrix row size (Should be an integer)
n = size(A,2)/nCol; %// Sub-matrix column size (Should be an integer)
imshow(A); %// show original image
out1 = reshape(permute(A,[2 1 4 3]),size(A,2),m,[],size(A,3));
out2 = permute(reshape(permute(out1,[2 1 3 4]),m,n,[],size(A,3)),[1 2 4 3]);
figure;
for i = 1:nCol*nRow
subplot(nRow,nCol,i); imshow(out2(:,:,:,i));
end
The basic idea is to make the 3rd Dimension unaffected while reshaping so that the image isn't distorted. To achieve this, additional permuting was done to swap 3rd and 4th dimensions. Once the process is done, the dimensions are restored as it was, by permuting back.
Results:
Original Image
Subplots (Partitions / Sub Matrices)
Advantage of this method is, it works good on 2D images as well.
Here is an example of a Gray Scale image (2D). Example used here is MatLab in-built image 'cameraman.tif'
With some many upvotes for the answer that makes use nested calls to permute, I thought of timing it and comparing to the other answer that makes use of mat2cell.
It is true that they don't return the exact same thing but:
the cell can be easily converted into a matrix like the other (I timed this, see further down);
when this problem arises, it is preferable (in my experience) to have the data in a cell since later on one will often want to put the original back together;
Anyway, I have compared them both with the following script. The code was run in Octave (version 3.9.1) with JIT disabled.
function T = split_by_reshape_permute (A, m, n)
T = permute (reshape (permute (reshape (A, size (A, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
endfunction
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1));
endfunction
function t = time_it (f, varargin)
t = cputime ();
for i = 1:100
f(varargin{:});
endfor
t = cputime () - t;
endfunction
Asizes = [30 50 80 100 300 500 800 1000 3000 5000 8000 10000];
Tsides = [2 5 10];
As = arrayfun (#rand, Asizes, "UniformOutput", false);
for d = Tsides
figure ();
t1 = t2 = [];
for A = As
A = A{1};
s = rows (A) /d;
t1(end+1) = time_it (#split_by_reshape_permute, A, s, s);
t2(end+1) = time_it (#split_by_mat2cell, A, s, s);
endfor
semilogy (Asizes, [t1(:) t2(:)]);
title (sprintf ("Splitting in %i", d));
legend ("reshape-permute", "mat2cell");
xlabel ("Length of matrix side (all squares)");
ylabel ("log (CPU time)");
endfor
Note that the Y axis is in log scale
Performance
Performance wise, using the nested permute will only be faster for smaller matrices where big changes in relative performance are actually very small changes in time. Note that the Y axis is in log scale, so the difference between the two functions for a 100x100 matrix is 0.02 seconds while for a 10000x10000 matrix is 100 seconds.
I have also tested the following which will convert the cell into a matrix so that the return values of the two functions are the same:
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1), 1);
T = reshape (cell2mat (T(:)'), [m n numel(T)]);
endfunction
This does slow it down a bit but not enough to consider (the lines will cross at 600x600 instead of 400x400).
Readability
It is so much more difficult to get your head around the use of the nested permute and reshape. It's mad to use it. It will increase maintenance time by a lot (but hey, this is Matlab language, it's not supposed to be elegant and reusable).
Future
The nested calls to permute does not expand nicely at all into N dimensions. I guess it would require a for loop by dimension (which would not help at all the already quite cryptic code). On the other hand, making use of mat2cell:
function T = split_by_mat2cell (A, lengths)
dl = arrayfun (#(l, s) repmat (l, s, 1), lengths, size (A) ./ lengths, "UniformOutput", false);
T = mat2cell (A, dl{:});
endfunction
Edit (and tested in Matlab too)
The amount of upvotes on the answer suggesting to use permute and reshape got me so curious that I decided to get this tested in Matlab (R2010b). The results there were pretty much the same, i.e., it's performance is really poor. So unless this operation will be done a lot of times, in matrices that will always be small (less than 300x300), and there will always be a Matlab guru around to explain what it does, don't use it.
If you want to use a for loop you can do this:
[x,y] = size(matrix)
k=1; % counter
for i = 1:20:x
for j = 1:20:y
subMatrix=Matrix(i:i+19, j:j+19);
subMatrixCell{k}=subMatrix; % if you want to save all the
% submatrices into a cell array
k=k+1;
end
end

Sum over blocks in a 3D matrix - MATLAB

For a 3N by 3N by 3N matrix A, I would like to derive a N by N by N matrix B whose entries come from summation over blocks in A.
For example, B(1,1,1) = sum of all elements of A(1:3,1:3,1:3).
Basically, A is kind of a high resolution matrix and B is a low resolution matrix from summing over entries in A.
If memory is not a concern, you can use a "labelling" approach: build a 3-component label to group the elements of A, and use that label as the first input argument to accumarray to do the sum. The label uses integers from 1 to N, so the result of accumarray already has the desired shape (NxNxN).
N = 5;
F = 3; %// block size per dimension
A = rand(15,15,15); %// example data. Size FN x FN x FN
[ii jj kk] = ind2sub(size(A), 1:numel(A));
label = ceil([ii.' jj.' kk.']/F);
result = accumarray(label, A(:));
reshape + sum based approach and as such has to be pretty efficient -
sumrows = sum(reshape(A,3,[]),1); %// Sum along rows
sumcols = sum(reshape(sumrows,N,3,[]),2); %// Sum along cols
B = reshape(sum(reshape(sumcols,N*N,3,[]),2),N,N,N); %// Sum along 3rd dim
If you are crazy about one-liners, here's that combining all steps into one -
B = reshape(sum(reshape(sum(reshape(sum(reshape(A,3,[]),1),N,3,[]),2),N*N,3,[]),2),N,N,N);
For a 2D matrix, this would work:
B = reshape(sum(im2col(A, [3 3], 'distinct')), [N N]);
NB: You need the image processing toolbox.
But for 3D matrices, I don't know of any built-in function equivalent to im2col. You might have to use a loop. Left as an exercise to the reader ;)

Can someone explain how to graph this sum in MATLAB using contourf?

I'm going to start off by stating that, yes, this is homework (my first homework question on stackoverflow!). But I don't want you to solve it for me, I just want some guidance!
The equation in question is this:
I'm told to take N = 50, phi1 = 300, phi2 = 400, 0<=x<=1, and 0<=y<=1, and to let x and y be vectors of 100 equally spaced points, including the end points.
So the first thing I did was set those variables, and used x = linspace(0,1) and y = linspace(0,1) to make the correct vectors.
The question is Write a MATLAB script file called potential.m which calculates phi(x,y) and makes a filled contour plot versus x and y using the built-in function contourf (see the help command in MATLAB for examples). Make sure the figure is labeled properly. (Hint: the top and bottom portions of your domain should be hotter at about 400 degrees versus the left and right sides which should be at 300 degrees).
However, previously, I've calculated phi using either x or y as a constant. How am I supposed to calculate it where both are variables? Do I hold x steady, while running through every number in the vector of y, assigning that to a matrix, incrementing x to the next number in its vector after running through every value of y again and again? And then doing the same process, but slowly incrementing y instead?
If so, I've been using a loop that increments to the next row every time it loops through all 100 values. If I did it that way, I would end up with a massive matrix that has 200 rows and 100 columns. How would I use that in the linspace function?
If that's correct, this is how I'm finding my matrix:
clear
clc
format compact
x = linspace(0,1);
y = linspace(0,1);
N = 50;
phi1 = 300;
phi2 = 400;
phi = 0;
sum = 0;
for j = 1:100
for i = 1:100
for n = 1:N
sum = sum + ((2/(n*pi))*(((phi2-phi1)*(cos(n*pi)-1))/((exp(n*pi))-(exp(-n*pi))))*((1-(exp(-n*pi)))*(exp(n*pi*y(i)))+((exp(n*pi))-1)*(exp(-n*pi*y(i))))*sin(n*pi*x(j)));
end
phi(j,i) = phi1 - sum;
end
end
for j = 1:100
for i = 1:100
for n = 1:N
sum = sum + ((2/(n*pi))*(((phi2-phi1)*(cos(n*pi)-1))/((exp(n*pi))-(exp(-n*pi))))*((1-(exp(-n*pi)))*(exp(n*pi*y(j)))+((exp(n*pi))-1)*(exp(-n*pi*y(j))))*sin(n*pi*x(i)));
end
phi(j+100,i) = phi1 - sum;
end
end
This is the definition of contourf. I think I have to use contourf(X,Y,Z):
contourf(X,Y,Z), contourf(X,Y,Z,n), and contourf(X,Y,Z,v) draw filled contour plots of Z using X and Y to determine the x- and y-axis limits. When X and Y are matrices, they must be the same size as Z and must be monotonically increasing.
Here is the new code:
N = 50;
phi1 = 300;
phi2 = 400;
[x, y, n] = meshgrid(linspace(0,1),linspace(0,1),1:N)
f = phi1-((2./(n.*pi)).*(((phi2-phi1).*(cos(n.*pi)-1))./((exp(n.*pi))-(exp(-n.*pi)))).*((1-(exp(-1.*n.*pi))).*(exp(n.*pi.*y))+((exp(n.*pi))-1).*(exp(-1.*n.*pi.*y))).*sin(n.*pi.*x));
g = sum(f,3);
[x1,y1] = meshgrid(linspace(0,1),linspace(0,1));
contourf(x1,y1,g)
Vectorize the code. For example you can write f(x,y,n) with:
[x y n] = meshgrid(-1:0.1:1,-1:0.1:1,1:10);
f=exp(x.^2-y.^2).*n ;
f is a 3D matrix now just sum over the right dimension...
g=sum(f,3);
in order to use contourf, we'll take only the 2D part of x,y:
[x1 y1] = meshgrid(-1:0.1:1,-1:0.1:1);
contourf(x1,y1,g)
The reason your code takes so long to calculate the phi matrix is that you didn't pre-allocate the array. The error about size happens because phi is not 100x100. But instead of fixing those things, there's an even better way...
MATLAB is a MATrix LABoratory so this type of equation is pretty easy to compute using matrix operations. Hints:
Instead of looping over the values, rows, or columns of x and y, construct matrices to represent all the possible input combinations. Check out meshgrid for this.
You're still going to need a loop to sum over n = 1:N. But for each value of n, you can evaluate your equation for all x's and y's at once (using the matrices from hint 1). The key to making this work is using element-by-element operators, such as .* and ./.
Using matrix operations like this is The Matlab Way. Learn it and love it. (And get frustrated when using most other languages that don't have them.)
Good luck with your homework!

Matlab: determinant of a matrix of vectors

I have a 2x2 matrix, each element of which is a 1x5 vector. something like this:
x = 1:5;
A = [ x x.^2; x.^2 x];
Now I want to find the determinant, but this happens
B = det(A);
Error using det
Matrix must be square.
Now I can see why this happens, MATLAB sees A as a 2x10 matrix of doubles. I want to be able to treat x as an element, not a vector. What I'd like is det(A) = x^2 - x^4, then get B = det(A) as a 1x5 vector.
How do I achieve this?
While Matlab has symbolic facilities, they aren't great. Instead, you really want to vectorize your operation. This can be done in a loop, or you can use ARRAYFUN for the job. It sounds like ARRAYFUN would probably be easier for your problem.
The ARRAYFUN approach:
x = 1:5;
detFunc = #(x) det([ x x^2 ; x^2 x ]);
xDet = arrayfun(detFunc, x)
Which produces:
>> xDet = arrayfun(detFunc, x)
xDet =
0 -12 -72 -240 -600
For a more complex determinant, like your 4x4 case, I would create a separate M-file for the actual function (instead of an anonymous function as I did above), and pass it to ARRAYFUN using a function handle:
xDet = arrayfun(#mFileFunc, x);
Well mathematically a Determinant is only defined for a square matrix. So unless you can provide a square matrix you're not going to be able to use the determinant.
Note I know wikipedia isn't the end all resource. I'm simply providing it as I can't readily provide a print out from my college calculus book.
Update: Possible solution?
x = zeros(2,2,5);
x(1,1,:) = 1:5;
x(1,2,:) = 5:-1:1;
x(2,1,:) = 5:-1:1;
x(2,2,:) = 1:5;
for(n=1:5)
B(n) = det(x(:,:,n));
end
Would something like that work, or are you looking to account for each vector at the same time? This method treats each 'layer' as it's own, but I have a sneaky suspiscion that you're wanting to get a single value as a result.