Compute weighted summation of matrix power (matrix polynomial) in Matlab - matlab

Given an nxn matrix A_k and a nx1 vector x, is there any smart way to compute
using Matlab? x_i are the elements of the vector x, therefore J is a sum of matrices. So far I have used a for loop, but I was wondering if there was a smarter way.

Short answer: you can use the builtin matlab function polyvalm for matrix polynomial evaluation as follows:
x = x(end:-1:1); % flip the order of the elements
x(end+1) = 0; % append 0
J = polyvalm(x, A);
Long answer: Matlab uses a loop internally. So, you didn't gain that much or you perform even worse if you optimise your own implementation (see my calcJ_loopOptimised function):
% construct random input
n = 100;
A = rand(n);
x = rand(n, 1);
% calculate the result using different methods
Jbuiltin = calcJ_builtin(A, x);
Jloop = calcJ_loop(A, x);
JloopOptimised = calcJ_loopOptimised(A, x);
% check if the functions are mathematically equivalent (should be in the order of `eps`)
relativeError1 = max(max(abs(Jbuiltin - Jloop)))/max(max(Jbuiltin))
relativeError2 = max(max(abs(Jloop - JloopOptimised)))/max(max(Jloop))
% measure the execution time
t_loopOptimised = timeit(#() calcJ_loopOptimised(A, x))
t_builtin = timeit(#() calcJ_builtin(A, x))
t_loop = timeit(#() calcJ_loop(A, x))
% check if builtin function is faster
builtinFaster = t_builtin < t_loopOptimised
% calculate J using Matlab builtin function
function J = calcJ_builtin(A, x)
x = x(end:-1:1);
x(end+1) = 0;
J = polyvalm(x, A);
end
% naive loop implementation
function J = calcJ_loop(A, x)
n = size(A, 1);
J = zeros(n,n);
for i=1:n
J = J + A^i * x(i);
end
end
% optimised loop implementation (cache result of matrix power)
function J = calcJ_loopOptimised(A, x)
n = size(A, 1);
J = zeros(n,n);
A_ = eye(n);
for i=1:n
A_ = A_*A;
J = J + A_ * x(i);
end
end
For n=100, I get the following:
t_loopOptimised = 0.0077
t_builtin = 0.0084
t_loop = 0.0295
For n=5, I get the following:
t_loopOptimised = 7.4425e-06
t_builtin = 4.7399e-05
t_loop = 1.0496e-04
Note that my timings fluctuates somewhat between different runs, but the optimised loop is almost always faster (up to 6x for small n) than the builtin function.

Related

Preventing using for loop in MATLAB

I have written the below MATLAB code. I want to know how can I optimize it without using for loop.
Any help will be very appreciated.
MATLAB code:
%Some parameters:
s = 50;
k = 50;
r = 0.1;
v = 0.2;
t = 2;
n=10000;
% Calculate CT by calling EurCall function
CT = EurCall(s, k, r, v, t, n);
%Function EurCall to be called
function C = EurCall(s, k, r, v, t, n)
X = zeros(n,1);
hh = zeros(n,1);
for ii = 1 : n
X(ii) = normrnd(0, 1);
SS = s*exp((r - v^2/2)*t + v*X(ii)*sqrt(t));
hh(ii) = exp(-r*t)*max(SS - k, 0);
end %end for loop
C = (1/n) * sum(hh);
end %end function
Vectorized Approach:
Here is a vectorized approach that I think replicates the same functionality as the original script. Instead of looping this example declares X as a vector of size n by 1. By using element-wise multiplication .* we can effectively calculate the remaining vectors SS and hh without need to loop through the indices. In this case SS and hh will also be vectors of size n by 1. I do agree with comment above that MATLAB's for-loops are no longer inherently slow.
%Some parameters:
s = 50;
k = 50;
r = 0.1;
v = 0.2;
t = 2;
n=10000;
% Calculate CT by calling EurCall function
[CT] = EurCall(s, k, r, v, t, n);
%Function EurCall to be called
function [C] = EurCall(s, k, r, v, t, n)
X = zeros(n,1);
hh = zeros(n,1);
mu = 0; sigma = 1;
%Creating a vector of normal random numbers of size (n by 1)%
X = normrnd(mu,sigma,[n 1]);
SS = s*exp((r - v^2/2)*t + v.*X.*sqrt(t));
hh = exp(-r*t)*max(SS - k, 0);
C = (1/n) * sum(hh);
end %end function
Ran using MATLAB R2019b

Is there a correlation ratio in MATLAB?

Is there any function in Matlab which calculates the correlation ratio?
Here is an implementation I tried to do, but the results are not right.
function cr = correlation_ratio(X, Y, L)
ni = zeros(1, L);
sigmai = ni;
for i = 0:(L-1)
Yn = Y(X == i);
ni(1, i+1) = numel(Yn);
m = (1/ni(1, i+1))*sum(Yn);
sigmai(1, i+1) = (1/ni(1, i+1))*sum((Yn - m).^2);
end
n = sum(ni);
prod = ni.*sigmai;
cr = (1-(1/n)*sum(prod))^0.5;
This is the equation on the Wikipedia page:
where:
η is the correlation ratio,
yx,i are the sample values (x is the class label, i the sample index),
yx (with the bar on top) is the mean of sample values for class x,
y (with the bar on top) is the mean for all samples across all classes, and
nx is the number of samples in class x.
This is how I interpreted it into code:
function eta = correlation_ratio(X, Y)
X = X(:); % make sure we've got column vectors, simplifies things below a bit
Y = Y(:);
L = max(X);
mYx = zeros(1, L+1); % we'll write mean per class here
nx = zeros(1, L+1); % we'll write number of samples per class here
for i = unique(X).'
Yn = Y(X == i);
if numel(Yn)>1
mYx(i+1) = mean(Yn);
nx(i+1) = numel(Yn);
end
end
mY = mean(Y); % mean across all samples
eta = sqrt(sum(nx .* (mYx - mY).^2) / sum((Y-mY).^2));
The loop could be replaced with accumarray.

Vectorize a regression map calculation

I compute the regression map of a time series A(t) on a field B(x,y,t) in the following way:
A=1:10; %time
B=rand(100,100,10); %x,y,time
rc=nan(size(B,1),size(B,2));
for ii=size(B,1)
for jj=1:size(B,2)
tmp = cov(A,squeeze(B(ii,jj,:))); %covariance matrix
rc(ii,jj) = tmp(1,2); %covariance A and B
end
end
rc = rc/var(A); %regression coefficient
Is there a way to vectorize/speed up code? Or maybe some built-in function that I did not know of to achieve the same result?
In order to vectorize this algorithm, you would have to "get your hands dirty" and compute the covariance yourself. If you take a look inside cov you'll see that it has many lines of input checking and very few lines of actual computation, to summarize the critical steps:
y = varargin{1};
x = x(:);
y = y(:);
x = [x y];
[m,~] = size(x);
denom = m - 1;
xc = x - sum(x,1)./m; % Remove mean
c = (xc' * xc) ./ denom;
To simplify the above somewhat:
x = [x(:) y(:)];
m = size(x,1);
xc = x - sum(x,1)./m;
c = (xc' * xc) ./ (m - 1);
Now this is something that is fairly straightforward to vectorize...
function q51466884
A = 1:10; %time
B = rand(200,200,10); %x,y,time
%% Test Equivalence:
assert( norm(sol1-sol2) < 1E-10);
%% Benchmark:
disp([timeit(#sol1), timeit(#sol2)]);
%%
function rc = sol1()
rc=nan(size(B,1),size(B,2));
for ii=1:size(B,1)
for jj=1:size(B,2)
tmp = cov(A,squeeze(B(ii,jj,:))); %covariance matrix
rc(ii,jj) = tmp(1,2); %covariance A and B
end
end
rc = rc/var(A); %regression coefficient
end
function rC = sol2()
m = numel(A);
rB = reshape(B,[],10).'; % reshape
% Center:
cA = A(:) - sum(A)./m;
cB = rB - sum(rB,1)./m;
% Multiply:
rC = reshape( (cA.' * cB) ./ (m-1), size(B(:,:,1)) ) ./ var(A);
end
end
I get these timings: [0.5381 0.0025] which means we saved two orders of magnitude in the runtime :)
Note that a big part of optimizing the algorithm is assuming you don't have any "strangeness" in your data, like NaN values etc. Take a look inside cov.m to see all the checks that we skipped.

Vectorization of Matrix Quadratics in MATLAB

I am trying to "vectorize" this loop in Matlab for computational efficiency
for t=1:T
j=1;
for m=1:M
for n=1:N
y(t,j) = v{m,n} + data(t,:)*b{m,n} + data(t,:)*f{m,n}*data(t,:)';
j=j+1;
end
end
end
Where v is a (M x N) cell of scalars. b is a (M x N) cell of (K x 1) vectors. f is a (M x N) cell of (K x K) matrices. data is a (T x K) array.
To give an example of what I mean the code I used to vectorize the same loop without the quadratic term is:
B = [reshape(cell2mat(v)',1,N*M);cell2mat(reshape(b'),1,M*N)];
X = [ones(T,1),data];
y = X*B;
Thanks!
For those interested here was the solution I found
f = f';
tMat = blkdiag(f{:})+(blkdiag(f{:}))';
y2BB = [reshape(cell2mat(v)',1,N*M);...
cell2mat(reshape(b',1,M*N));...
reshape(diag(blkdiag(f{:})),K,N*M);...
reshape(tMat((tril(tMat,-1)~=0)),sum(1:K-1),M*N)];
y2YBar = [ones(T,1),data,data.^2];
jj=1;
kk=1;
ll=1;
for k=1:sum(1:K-1)
y2YBar = [y2YBar,data(:,jj).*data(:,kk+jj)];
if kk<(K-ll)
kk=kk+1;
else
kk=1;
jj=jj+1;
ll=ll+1;
end
end
y = y2YBar*y2BB;
Here's the most vectorized form targeted for performance -
% Extract as multi-dim arrays
vA = reshape([v{:}],M,N);
bA = reshape([b{:}],K,M,N);
fA = reshape([f{:}],K,K,M,N);
% Perform : data(t,:)*f{m,n} for all iterations
data_f_mult = reshape(data*reshape(fA,K,[]),T,K,M,N);
% Now there are three parts :
% v{m,n}
% data(t,:)*b{m,n}
% data(t,:)*f{m,n}*data(t,:)';
% Compute those parts one by one
parte1 = vA(:).';
parte2 = data*reshape(bA,[],M*N);
parte3 = zeros(T,M*N);
for t = 1:T
parte3(t,:) = data(t,:)*reshape(data_f_mult(t,:,:),K,[]);
end
% Finally sum those up and to present in desired format permute dims
sums = bsxfun(#plus, parte1, parte2 + parte3);
out = reshape(permute(reshape(sums,T,M,N),[1,3,2]),[],M*N);

Jacobi method to solve linear systems in MATLAB

How would you code this in MATLAB?
This is what I've tried, but it doesn't work quite right.
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
for k = 1:tot_it
for j = 1:n
for i = 1:n
if (j ~= i)
x(i) = -((A(i,j)/A(i,i)) * x(j) + (b(i)/A(i,i)));
else
continue;
end
end
end
end
end
j is an iterator of a sum over each i, so you need to change their order. Also the formula has a sum and in your code you're not adding anything so that's another thing to consider. The last thing I see that you're omitting is that you should save the previous state of xbecause the right side of the formula needs it. You should try something like this:
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
s = 0; %Auxiliar var to store the sum.
xold = x
for k = 1:tot_it
for i = 1:n
for j = 1:n
if (j ~= i)
s = s + (A(i,j)/A(i,i)) * xold(j);
else
continue;
end
end
x(i) = -s + b(i)/A(i,i);
s = 0;
end
xold = x;
end
end