'Multiplying' arrays in MATLAB - 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?

Related

Fitting Data with Linear Combination of Vectors in MATLAB with Constraints

Working in MATLAB. I have the following equation:
S = aW + bX + cY + dZ
where S,W,X,Y, and Z are all known n x 1 vectors. I am trying to fit the data of S with a linear combination of the basis vectors W,X,Y, and Z with the constraint of the constants (a,b,c,d) being greater than 0. I have managed to do this in Excel's solver, and have attempted to figure it out on MATLAB, being directed towards functions like fmincon, but I am not overly familiar with MATLAB and feel I am misunderstanding the use of fmincon.
I am looking for help with understanding fmincon's use towards my problem, or redirection towards a more efficient method for solving.
Currently I have:
initials = [0.2 0.2 0.2 0.2];
fun = #(x)x(1)*W + x(2)*X + x(3)*Y + x(4)*Z;
lb = [0,0,0,0];
soln = fmincon(fun,initials,data,b,Aeq,beq,lb,ub);
I am receiving an error stating "A must have 4 column(s)". Where A is referring to my variable data which corresponds to my S in the above equation. I do not understand why it is expecting 4 columns. Also to note the variables that are in my above snippet that are not explicitly defined are defined as [], serving as space holders.
Using fmincon is a huge overkill in this case. It's like using big heavy microscope to crack nuts... or martian rover to tow a pushcart or... anyway :) May be it's OK if you don't have to process large sets of vectors. If you need to fit hundreds of thousands of such vectors it can take hours. But this classic solution will be faster by several orders of magnitude.
%first make a n x 4 matrix of your vectors;
P=[W,X,Y,Z];
% now your equation looks like this S = P*m where m is 4 x 1 vectro
% containing your coefficients ( m = [a,b,c,d] )
% so solution will be simply
m_1 = inv(P'*P)*P'*S;
% or you can use this form
m_2 = (P'*P)\P'*S;
% or even simpler
m_3 = (S'/P')';
% all three solutions should give exactly same resul
% third solution is the neatest but may not work in every version of matlab
% Your modeled vector will be
Sm = P*m_3; %you can use any of m_1, m_2 or m_3;
% And your residual
R = S-Sm;
If you need to procees many vectors don't use for cycle. For cycles are very slow in Matlab and you should use matrices instead, if possible. S can also be nk matrix, where k is number vectors you want to process. In this case m will be 4k matrix.
What you are trying to do is similar to the answer I gave at is there a python (or matlab) function that achieves the minimum MSE between given set of output vector and calculated set of vector?.
The procedure is similar to what you are doing in EXCEL with solver. You create an objective function that takes (a, b, c, d) as the input parameters and output a measure of fit (mse) and then use fmincon or similar solver to get the best (a, b, c, d) that minimize this mse. See the code below (no MATLAB to test it but it should work).
function [a, b, c, d] = optimize_abcd(W, X, Y, Z)
%=========================================================
%Second argument is the starting point, second to the last argument is the lower bound
%to ensure the solutions are all positive
res = fmincon(#MSE, [0,0,0,0], [], [], [], [], [0,0,0,0], []);
a=res(1);
b=res(2);
c=res(3);
d=res(4);
function mse = MSE(x_)
a_=x_(1);
b_=x_(2);
c_=x_(3);
d_=x_(4);
S_ = a_*W + b_*X + c_*Y + d_*Z
mse = norm(S_-S);
end
end

Plot log(n over k)

I've never used Matlab before and I really don't know how to fix the code. I need to plot log(1000 over k) with k going from 1 to 1000.
y = #(x) log(nchoosek(1000,x));
fplot(y,[1 1000]);
Error:
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly
vectorize your function to return an output with the same size and shape as the input
arguments.
In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 241)
In fplot>#(f)singleFplot(cax,{f},limits,extraOpts,args) (line 196)
In fplot>vectorizeFplot (line 196)
In fplot (line 166)
In P1 (line 5)
There are several problems with the code:
nchoosek does not vectorize on the second input, that is, it does not accept an array as input. fplot works faster for vectorized functions. Otherwise it can be used, but it issues a warning.
The result of nchoosek is close to overflowing for such large values of the first input. For example, nchoosek(1000,500) gives 2.702882409454366e+299, and issues a warning.
nchoosek expects integer inputs. fplot uses in general non-integer values within the specified limits, and so nchoosek issues an error.
You can solve these three issues exploiting the relationship between the factorial and the gamma function and the fact that Matlab has gammaln, which directly computes the logarithm of the gamma function:
n = 1000;
y = #(x) gammaln(n+1)-gammaln(x+1)-gammaln(n-x+1);
fplot(y,[1 1000]);
Note that you get a plot with y values for all x in the specified range, but actually the binomial coefficient is only defined for non-negative integers.
OK, since you've gotten spoilers for your homework exercise anyway now, I'll post an answer that I think is easier to understand.
The multiplicative formula for the binomial coefficient says that
n over k = producti=1 to k( (n+1-i)/i )
(sorry, no way to write proper formulas on SO, see the Wikipedia link if that was not clear).
To compute the logarithm of a product, we can compute the sum of the logarithms:
log(product(xi)) = sum(log(xi))
Thus, we can compute the values of (n+1-i)/i for all i, take the logarithm, and then sum up the first k values to get the result for a given k.
This code accomplishes that using cumsum, the cumulative sum. Its output at array element k is the sum over all input array elements from 1 to k.
n = 1000;
i = 1:1000;
f = (n+1-i)./i;
f = cumsum(log(f));
plot(i,f)
Note also ./, the element-wise division. / performs a matrix division in MATLAB, and is not what you need here.
syms function type reproduces exactly what you want
syms x
y = log(nchoosek(1000,x));
fplot(y,[1 1000]);
This solution uses arrayfun to deal with the fact that nchoosek(n,k) requires k to be a scalar. This approach requires no toolboxes.
Also, this uses plot instead of fplot since this clever answer already addresses how to do with fplot.
% MATLAB R2017a
n = 1000;
fh=#(k) log(nchoosek(n,k));
K = 1:1000;
V = arrayfun(fh,K); % calls fh on each element of K and return all results in vector V
plot(K,V)
Note that for some values of k greater than or equal to 500, you will receive the warning
Warning: Result may not be exact. Coefficient is greater than 9.007199e+15 and is only accurate to 15 digits
because nchoosek(1000,500) = 2.7029e+299. As pointed out by #Luis Mendo, this is due to realmax = 1.7977e+308 which is the largest real floating-point supported. See here for more info.

Matlab: implementing sum of exponentials using function handles

I need to implement the following formula using function handles in Matlab
where t is the time vector and n is large. Also, Sk and fk are constant for each k. Any efficient way to implement this is appreciated.
Edit:
For the first harmonic, I could write
y=#(t) s(1)*exp(i*2*pi*f(1)*t);
However, I can not use this in a for loop to generate f(t). Is there a vector approach for doing this?
Assuming you have a data vector s, a frequency vector f of the same length, and a time vector t of a (potentially) different length, you can compute the given equation using
result = sum( s(:) .* exp( i*2*pi * f(:) .* t(:).' ), 1 );
What is happening here is s(:) forces s to be a column vector. We make f into a column vector in the same way. t(:).' is a row vector. MATLAB does implicit singleton expansion, so that f(:) .* t(:).' returns a 2D matrix. The other .* also does singleton expansion for s. Finally sum(.,1) sums over the fist dimension, which is over all values of f. The result is a row vector of the same length as t.
If you need a function handle that computes this, simply turn the one-liner into an anonymous function:
y = #(t) sum( s(:) .* exp( i*2*pi * f(:) .* t(:).' ), 1 );
This anonymous function will capture s and f as they exist when defining it. t can be supplied later:
result = y(t);
But do note that ifft does the same computation but much more efficiently.

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).

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.