Matlab: determinant of a matrix of vectors - matlab

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.

Related

How do I plot relations in matlab?

I want to plot relations like y^2=x^2(x+3) in MATLAB without using ezplot or doing algebra to find each branch of the function.
Does anyone know how I can do this? I usually create a linspace and then create a function over the linspace. For example
x=linspace(-pi,pi,1001);
f=sin(x);
plot(x,f)
Can I do something similar for the relation I have provided?
What you could do is use solve and allow MATLAB's symbolic solver to symbolically solve for an expression of y in terms of x. Once you do this, you can use subs to substitute values of x into the expression found from solve and plot all of these together. Bear in mind that you will need to cast the result of subs with double because you want the numerical result of the substitution. Not doing this will still leave the answer in MATLAB's symbolic format, and it is incompatible for use when you want to plot the final points on your graph.
Also, what you'll need to do is that given equations like what you have posted above, you may have to loop over each solution, substitute your values of x into each, then add them to the plot.
Something like the following. Here, you also have control over the domain as you have desired:
syms x y;
eqn = solve('y^2 == x^2*(x+3)', 'y'); %// Solve for y, as an expression of x
xval = linspace(-1, 1, 1000);
%// Spawn a blank figure and remember stuff as we throw it in
figure;
hold on;
%// For as many solutions as we have...
for idx = 1 : numel(eqn)
%// Substitute our values of x into each solution
yval = double(subs(eqn(idx), xval));
%// Plot the points
plot(xval, yval);
end
%// Add a grid
grid;
Take special care of how I used solve. I specified y because I want to solve for y, which will give me an expression in terms of x. x is our independent variable, and so this is important. I then specify a grid of x points from -1 to 1 - exactly 1000 points actually. I spawn a blank figure, then for as many solutions to the equation that we have, we determine the output y values for each solution we have given the x values that I made earlier. I then plot these on a graph of these points. Note that I used hold on to add more points with each invocation to plot. If I didn't do this, the figure would refresh itself and only remember the most recent call to plot. You want to put all of the points on here generated from all of the solution. For some neatness, I threw a grid in.
This is what I get:
Ok I was about to write my answer and I just saw that #rayryeng proposed a similar idea (Good job Ray!) but here it goes. The idea is also to use solve to get an expression for y, then convert the symbolic function to an anonymous function and then plot it. The code is general for any number of solutions you get from solve:
clear
clc
close all
syms x y
FunXY = y^2 == x^2*(x+3);
%//Use solve to solve for y.
Y = solve(FunXY,y);
%// Create anonymous functions, stored in a cell array.
NumSol = numel(Y); %// Number of solutions.
G = cell(1,NumSol);
for k = 1:NumSol
G{k} = matlabFunction(Y(k))
end
%// Plot the functions...
figure
hold on
for PlotCounter = 1:NumSol
fplot(G{PlotCounter},[-pi,pi])
end
hold off
The result is the following:
n = 1000;
[x y] = meshgrid(linspace(-3,3,n),linspace(-3,3,n));
z = nan(n,n);
z = (y .^ 2 <= x .^2 .* (x + 3) + .1);
z = z & (y .^ 2 >= x .^2 .* (x + 3) - .1);
contour(x,y,z)
It's probably not what you want, but I it's pretty cool!

Evaluate all pairs of matrices

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.

Calculating the covariance of a 1000 5x5 matrices in matlab

I have a 1000 5x5 matrices (Xm) like this:
Each $(x_ij)m$ is a point estimate drawn from a distribution. I'd like to calculate the covariance cov of each $x{ij}$, where i=1..n, and j=1..n in the direction of the red arrow.
For example the variance of $X_m$ is `var(X,0,3) which gives a 5x5 matrix of variances. Can I calculate the covariance in the same way?
Attempt at answer
So far I've done this:
for m=1:1000
Xm_new(m,:)=reshape(Xm(:,:,m)',25,1);
end
cov(Xm_new)
spy(Xm_new) gives me this unusual looking sparse matrix:
If you look at cov (edit cov in the command window) you might see why it doesn't support multi-dimensional arrays. It perform a transpose and a matrix multiplication of the input matrices: xc' * xc. Both operations don't support multi-dimensional arrays and I guess whoever wrote the function decided not to do the work to generalize it (it still might be good to contact the Mathworks however and make a feature request).
In your case, if we take the basic code from cov and make a few assumptions, we can write a covariance function M-file the supports 3-D arrays:
function x = cov3d(x)
% Based on Matlab's cov, version 5.16.4.10
[m,n,p] = size(x);
if m == 1
x = zeros(n,n,p,class(x));
else
x = bsxfun(#minus,x,sum(x,1)/m);
for i = 1:p
xi = x(:,:,i);
x(:,:,i) = xi'*xi;
end
x = x/(m-1);
end
Note that this simple code assumes that x is a series of 2-D matrices stacked up along the third dimension. And the normalization flag is 0, the default in cov. It could be exapnded to multiple dimensions like var with a bit of work. In my timings, it's over 10 times faster than a function that calls cov(x(:,:,i)) in a for loop.
Yes, I used a for loop. There may or may not be faster ways to do this, but in this case for loops are going to be faster than most schemes, especially when the size of your array is not known a priori.
The answer below also works for a rectangular matrix xi=x(:,:,i)
function xy = cov3d(x)
[m,n,p] = size(x);
if m == 1
x = zeros(n,n,p,class(x));
else
xc = bsxfun(#minus,x,sum(x,1)/m);
for i = 1:p
xci = xc(:,:,i);
xy(:,:,i) = xci'*xci;
end
xy = xy/(m-1);
end
My answer is very similar to horchler, however horchler's code does not work with rectangular matrices xi (whose dimensions are different from xi'*xi dimensions).

How to plot this function in MATLAB?

I have a simple function below (I omitted the allocations, etc. for brevity) that I have been tryig to plot against it's x value for specific values of N and T but I keep getting a dimensions error. I think that when I try to plot this I am defining an array for x and then plotting Psum(N', x, T') for certain N' and T' against these x, however MATLAB doesn't seem to like this. Can someone give me some direction please.
function U = Psum(N, X, T)
for m = 1:N
A(1,m) = (1/(m*pi))*sin(m*pi*X)*T*exp(-(m^2)*(pi^2)*T);
% array terms of partial sum
end
M = -sum(A); % evaluate Nth partial sum
U = T*(1-X) + M; % output U(X,T) = T(1-X) + V(X,T)
end
I'm getting a similar error when I try to plot the following, I think there must be something wrong with my general approach
syms x;
f = #(x)((x/(100*pi))*(exp(-(100^2)*(pi^2)*x)));
x = 0:0.1:10000;
plot(x,f(x),'r')
title('PartialSum convergence');
xlabel('T');
ylabel('a_n');
the error I get here reads:
Error using *
Inner matrix dimensions must agree.
Here's the analysis of why you're getting a dimension mismatch error. From this line:
A(1,m) = (1/(m*pi))*sin(m*pi*X)*T*exp(-(m^2)*(pi^2)*T)
The element A(1, m) is supposed to be a scalar value in a two-dimensional matrix. Now let's see what are the dimensions of each of the multiplicands:
(1/(m*pi)) is a scalar (that is, a 1×1 matrix).
sin(m*pi*X) has the same dimensions as X. Let's assume its dimensions are q×n.
exp(-(m^2)*(pi^2)*T) has the same dimensions as T, and is multiplied by T.
Therefore T must be a square matrix, so let's assume its dimensions are p×p.
What we get is a q×n matrix multiplied by a square p×p matrix, and the result must be a scalar (that is, 1×1 matrix). This forces q=1 and n=p.
Now let's look at this line:
U = T*(1-X) + M
We are forced to conclude that p=1, otherwise T cannot be multiplied by X from the right.
This means that your code forces T and X to be scalar! No wonder you're getting a error :)
The remedy is simple: revise the computation in Psum so that it can produce correct results for both a scalar X and a vector X. A possible fix would be adding another loop to iterate over all values of X:
function U = Psum(N, X, T)
U = zeros(size(X));
for k = 1:numel(X) %// Iterate over all values of X
for m = 1:N
A(1,m) = (1/(m*pi))*sin(m*pi*X(k))*T*exp(-(m^2)*(pi^2)*T);
%// array terms of partial sum
end
M = -sum(A); % evaluate Nth partial sum
U(k) = T*(1-X(k)) + M; % output U(X,T) = T(1-X) + V(X,T)
end
end
The output of this function has the same dimensions as X.
By the way, did you verify that Psum produces that correct result for scalar inputs?
I don't fully understand what you are trying to accomplish, but just an observation for you: if your input X is a vector, line 3 can not be computed correctly
A(1,m) = (1/(m*pi))*sin(m*pi*X)*T*exp(-(m^2)*(pi^2)*T);
because the right hand side of the equation give you a vector, but the right hand side A(1,m) is one element, not vector. so you have dimension mismatch.
Hope this helps!

'Multiplying' arrays in MATLAB

First off, I didn't know what to put as title, since the question is not easy to formulate shortly.
I need to convolve a matrix-valued function (k) with a vector-valued function (X), each of which is defined on R^3. I need to to this in MATLAB, so naturally I will do the discretized version. I plan on representing k and X by 5- and 4-dimensional arrays, respectively. This seems a bit heavy though. Do you know if there are any better ways to do it?
Instead of doing the convolution directly, I will go to Fourier space by fft'ing both k and X, pad with zeros, multiply them and then use ifft. That should produce the same result and run much, much faster.
My question here is whether there is any way to multiply these arrays/matrices easily? I.e. is there any way to do k(i,j,k,:,:)*X(i,j,k,:) for all i,j,k, without using three nested loops?
Do you need to discretize? Matlab is perfectly capable of taking functions as input and output. For examples, you could define a convolution function:
>> convolve = #(fm,fv) #(x) fm(x) * fv(x); %fm matrix valued, fv vector valued
and define some matrix-valued and vector-valued functions (this assumes the input is a column vector)
>> f = #(x) [x x x];
>> g = #(x) cos(x);
now their convolution:
>> h = convolve(f,g);
and try applying it to a vector:
>> h([1;2;3])
ans =
-0.8658
-1.7317
-2.5975
You get the same answer as if you did the operation manually:
>> f([1;2;3]) * g([1;2;3])
ans =
-0.8658
-1.7317
-2.5975
You perform element-by-element operation by using . together with the operator of choice. For example:
Element-by-element multiplication: .*
Element-by-element division: ./
and so on... is that what you mean?