I am very new in Matlab. I just try to implement sum of series 1+x+x^2/2!+x^3/3!..... . But I could not find out how to do it. So far I did just sum of numbers. Help please.
for ii = 1:length(a)
sum_a = sum_a + a(ii)
sum_a
end
n = 0 : 10; % elements of the series
x = 2; % value of x
s = sum(x .^ n ./ factorial(n)); % sum
The second part of your answer is:
n = 0:input('variable?')
Cheery's approach is perfectly valid when the number of terms of the series is small. For large values, a faster approach is as follows. This is more efficient because it avoids repeating multiplications:
m = 10;
x = 2;
result = 1+sum(cumprod(x./[1:m]));
Example running time for m = 1000; x = 1;
tic
for k = 1:1e4
result = 1+sum(cumprod(x./[1:m]));
end
toc
tic
for k = 1:1e4
result = sum(x.^(0:m)./factorial(0:m));
end
toc
gives
Elapsed time is 1.572464 seconds.
Elapsed time is 2.999566 seconds.
Related
I'm trying to generate a new matrix, based on index values stored in another matrix.
This is trivial to do with a for loop, but this is currently the slowest line in some code I'm trying to optimise, and so I'm looking for a way to do it without the loop, and pulling my hair out.
I'm sure this has been answered before, and that I just don't know the right search terms.
n1 = 10;
n2 = 100;
a = randi(n2,[1,n1]);
b = randi(n2,[4,n1]);
c = rand(100,100);
for i = 1:n1
d(:,i) = c(a(i),b(:,i));
end
I'm assuming the value of n1 in your code is way bigger than in the example you provide, which would explain why it is "slow".
In order to do this without a loop, you can use Linear indexing:
n1 = 1e6;
n2 = 100;
a = randi(n2,[1,n1]);
b = randi(n2,[4,n1]);
c = rand(n2,n2);
% With a loop
d = zeros(4,n1);
tic
for i = 1:n1
d(:,i) = c(a(i),b(:,i));
end
toc
% A faster way for big values of `n1`
d2 = zeros(4,n1);
tic
a_rep = repmat(a,4,1); % Repeat row indexes to match the elements in b
idx_Lin = sub2ind([n2,n2],a_rep(:),b(:)); % Get linear indexes
d2(:) = c(idx_Lin); % Fill
toc
isequal(d,d2)
Elapsed time is 1.309654 seconds.
Elapsed time is 0.062549 seconds.
ans =
logical
1
Try This:
n1 = 10;
n2 = 100;
a = randi(n2,[1,n1]);
b = randi(n2,[4,n1]);
c = rand(100,100);
idx = (1:n1);
tic
d1=(c(a(idx),b(:,idx)))';
[idx,idy]=meshgrid(0:44:400,1:4);
d1=d1(idy+idx);
toc
this is the timeing:
Elapsed time is 0.000517 seconds.
In MatLab I have to call the cdf of the t distribution (tcdf) iteratively (since the next input value depends on the previous output of tcdf), which unfortunately slows down my code massively.
tic
z = NaN(1e5,1);
z(1) = 1;
x = 2;
for ii = 2:1e5
x = tcdf(z(ii-1),x);
z(ii) = z(ii-1)*x;
end
toc
Elapsed time is 4.717087 seconds.
Is there a way to speed this up somehow?
For comparison:
tic
z = randn(1e5,1);
tcdf(z,5);
toc
Elapsed time is 0.091353 seconds.
Move the random number generation outside the loop as suggested below
numVal = 1e5
z = randn(numVal,1);
for ii = 2:numVal
z(ii) = z(ii-1) + z(ii);
end
tcdf(z,5);
I have developed a function to reduce the size of an initial vector X = [x,y]. But for an X of 500,000 points and points_limit = 10000, Matlab needs 16sec to complete this function.
Are there any ways to optimize this, maybe by removing the loop using matrix operations (vectorisation)?
function X = reduce_vector_size(X,points_limit)
while length(X) > points_limit
k = 1;
X2 = zeros(round(length(X(:,1))/2),2);
X = sortrows(X);
for i=1:2:length(X(:,1))-1
X2(k,1) = mean([X(i,1) ,X(i+1,1) ]);
X2(k,2) = mean([X(i,2) ,X(i+1,2) ]);
k = k + 1;
end
X = X2;
end
An other best idea is to have a new approach :
Ratio = ceil(length(X(:,1))/points_limit);
X = ceil(X);
X = sortrows(X,1);
X = sortrows(X,2);
X1=[];
for i=1:points_limit - 1
X1 = [X1; mean(X(i*Ratio:(i+1)*Ratio,1)), mean(X(i*Ratio:(i+1)*Ratio,2))];
end
X = X1;
The objective is to reduce the number of points in a vector: a form of compression function for a 2D vectors.
Do you know if I can do this new method with loop ?
What do you think about my algorithm of compression ?
you can easily vectorize the inner for loop:
k = 1;
X = rand(5e5,2);
X2 = zeros(round(length(X(:,1))/2),2);
tic
for i=1:2:length(X(:,1))-1
X2(k,1) = mean([X(i,1) ,X(i+1,1) ]);
X2(k,2) = mean([X(i,2) ,X(i+1,2) ]);
k = k + 1;
end
toc % Elapsed time is 1.988739 seconds.
tic
X3 = (X(1:2:length(X(:,1))-1,:) + X(2:2:length(X(:,1)),:))/2;
toc % Elapsed time is 0.014575 seconds.
isequal(X2,X3) % true
I have the following lines of code
y = zeros(n, 1);
for i=1:n
b = L * [u(i:-1:max(1,i-M+1));zeros((-i+M)*(i-M<0),1)];
y(i) = b' * gamma;
end
u is nx1, gamma is Mx1 and L is MxM
n takes very large values, so are there any ideas on how to vectorize the for loop?
Discussion and solution code
Initial approach
Matrix-multiplications based approach -
u_pad = [zeros(M-1,1) ; u]; %// Pad u with zeros
idx = bsxfun(#plus,[M:-1:1]',0:n-1);%//'# Calculate sliding indices for u
u_pad_indexed = u_pad(idx); %// Index into padded u
y_vectzed = gamma.'*L*u_pad_indexed;%//'# Matrix-multiplications for final o/p
Modified approach
Now, you have huge datasizes to work with. So, to optimize for such a case, the data could be broken into smaller pieces that are runnable and the operations could be done iteratively. Then, each iteration would calculate a part of the output array.
With this new strategy, the intial setting up could be done once and reused within each iteration. The modified approach would look something like this -
div_factor = [...] %// Make sure it is a divisor of n
nrows = n/div_factor;
start_idx = bsxfun(#plus,[M:-1:1]',0:nrows-1); %//'
u_pad = [zeros(M-1,1) ; u];
y_vectorized = zeros(div_factor,n/div_factor);
for iter = 1:div_factor
u_pad_indexed = u_pad((iter-1)*nrows + start_idx);
y_vectorized(iter,:) = gamma.'*L*u_pad_indexed; %//'
end
y_vectorized = reshape(y_vectorized.',[],1);
Benchmarking
%// Size parameters and input arrays
n = 4000000;
M = 1000;
u = rand(n,1);
gamma = rand(M,1);
L = rand(M,M);
%// Warm up tic/toc.
for k = 1:50000
tic(); elapsed = toc();
end
disp('----------- With Original loopy code');
tic
y = zeros(n, 1);
for i=1:n
b = L * [u(i:-1:max(1,i-M+1));zeros((-i+M)*(i-M<0),1)];
y(i) = b' * gamma; %//'
end
toc
clear b y
disp('----------- With Proposed solution code');
tic
..... Proposed Modified Code with div_factor = 200
toc
Runtimes
----------- With Original loopy code
Elapsed time is 498.563049 seconds.
----------- With Proposed solution code
Elapsed time is 44.273299 seconds.
Edit: I am redoing the solution because I found out that Matlab does not handle anonymous functions well. So I changed the call from an anonymous function to a normal function. Making this change:
Test 1
Comparison(40E3, 3E3)
Elapsed time is 21.731176 seconds.
Elapsed time is 251.327347 seconds.
|y2-y1| = 3.1519e-06
Test 2
Comparison(40E3, 1E3)
Elapsed time is 6.407259 seconds.
Elapsed time is 25.551116 seconds.
|y2-y1| = 2.8402e-07
Test 3
Comparison(20E3, 3E3)
Elapsed time is 10.484422 seconds.
Elapsed time is 125.033313 seconds.
|y2-y1| = 1.5462e-06
Test 4
Comparison(20E3, 1E3)
Elapsed time is 3.153404 seconds.
Elapsed time is 13.200649 seconds.
|y2-y1| = 1.5627e-07
The function is:
function Comparison(n, M)
u = rand(n, 1);
L = rand(M);
gamma = rand(M, 1);
tic
y1 = vectorized(u, L, gamma);
toc
tic
y2 = looped(u, L, gamma);
toc
disp(['|y2-y1| = ', num2str(norm(y2 - y1, 1))])
end
function y = vectorized(u, l, gamma)
global a Column
M = length(gamma);
Column = l' * gamma;
x = bsxfun(#plus, -(1:M)', (1:length(u)) + 1);
x(x < 1) = 1;
a = u(x);
a(1:M, 1:M) = a(1:M, 1:M) .* triu(ones(M));
a = a';
m = 1:size(a,1);
y = arrayfun(#VectorY , m)';
end
function yi = VectorY(j)
global a Column
yi = a(j,:) * Column;
end
function y = looped(U, l, gamma)
n = length(U);
M = length(gamma);
u = U';
L = l';
y = zeros(n, 1);
for i=1:n
y(i) = [u(i:-1:max(1,i-M+1)), zeros(1,(-i+M)*(i-M<0))] * L * gamma;
end
end
I am trying to derive a function for calculating a moving/rolling correlation for two vectors and speed is a high priority, since I need to apply this function in an array function. What I have (which is too slow) is this:
Data1 = rand(3000,1);
Data2 = rand(3000,1);
function y = MovCorr(Data1,Data2)
[N,~] = size(Data1);
correlationTS = nan(N, 1);
for t = 20+1:N
correlationTS(t, :) = corr(Data1(t-20:t, 1),Data2(t-20:t,1),'rows','complete');
end
y = correlationTS;
end
I am thinking that the for loop could be done more efficiently if I knew how to generate the roling window indices and then applying accumarray. Any suggestions?
Following the advice from #knedlsepp, and using filter as in the movingstd, I found the following solution, which is quite fast:
function Cor = MovCorr1(Data1,Data2,k)
y = zscore(Data2);
n = size(y,1);
if (n<k)
Cor = NaN(n,1);
else
x = zscore(Data1);
x2 = x.^2;
y2 = y.^2;
xy = x .* y;
A=1;
B = ones(1,k);
Stdx = sqrt((filter(B,A,x2) - (filter(B,A,x).^2)*(1/k))/(k-1));
Stdy = sqrt((filter(B,A,y2) - (filter(B,A,y).^2)*(1/k))/(k-1));
Cor = (filter(B,A,xy) - filter(B,A,x).*filter(B,A,y)/k)./((k-1)*Stdx.*Stdy);
Cor(1:(k-1)) = NaN;
end
end
Comparing with my original solution the execution times are:
tic
MovCorr(Data1,Data2);
toc
Elapsed time is 1.017552 seconds.
tic
MovCorr1(Data1,Data2,21);
toc
Elapsed time is 0.019400 seconds.