Matlab 2016b: looping with structures is much slower than with variables - matlab

I am computing a list of error statistics of a variable u. Whenever I put the structures in the loop, Matlab becomes superslow, while it is pretty fast with standard variables. I have heard that with Matlab 2016b one can either use loops or use vectorized notation, the speed should be the same. It looks like it does not work for structures. Do you know why? Best suggestion here? This is a minimal example ( I just used trivial "if" clauses, mine are more complex and that's the main reason why I don't vectorize):
n = 1000,
m = 1000;
uMODEL = rand(n,m);
uOBS = rand(n,m);
%
%
%
tic
ERRORS = struct('Emedio',0,'MAE',0,'sigma',0,'Emax',0,'Emin',0);
Nerr(1:max(n,1),1) = 0; %Nerr at most it contains n
fields = fieldnames(ERRORS);
for i = 1:numel(fields)
ERRORS.(fields{i}) = zeros(max(n,1),1);
end
for i=1:m
for j=1:n
if (1000>2 && 2000<343532)
diff = uMODEL(j,i)-uOBS(j,i);
ERRORS.Emedio(j) = ERRORS.Emedio(j) + diff;
ERRORS.MAE(j) = ERRORS.MAE(j) + abs(diff);
ERRORS.sigma(j) = ERRORS.sigma(j) + diff^2;
ERRORS.Emax(j) = max(ERRORS.Emax(j),diff);
ERRORS.Emin(j) = min(ERRORS.Emin(j),diff);
Nerr(n) = Nerr(n) + 1;
end
end
end
ERRORS.Emedio(:) = ERRORS.Emedio(:)./Nerr(:);
ERRORS.MAE(:) = ERRORS.MAE(:)./Nerr(:);
ERRORS.sigma(:) = sqrt(ERRORS.sigma(:)./(Nerr(:)-1));
toc
clear ERRORS
tic
%
% here instead I define variables, I fill them up and then I throw them in structures, cause loops with structures are strangely slow...
Emedio = zeros(max(n,1),1);
MAE = zeros(max(n,1),1);
sigma = zeros(max(n,1),1);
Nerr = zeros(max(n,1),1);
Emax = zeros(max(n,1),1);
Emin = zeros(max(n,1),1);
for i=1:m
for j=1:n
if (1000>2 && 2000<343532)
diff = uMODEL(j,i)-uOBS(j,i);
Emedio(j) = Emedio(j) + diff;
MAE(j) = MAE(j) + abs(diff);
sigma(j) = sigma(j) + diff^2;
Emax(j) = max(Emax(j),diff);
Emin(j) = min(Emin(j),diff);
Nerr(n) = Nerr(n) + 1;
end
end
end
Emedio(:) = Emedio(:)./Nerr(:);
MAE(:) = MAE(:)./Nerr(:);
sigma(:) = sqrt(sigma(:)./(Nerr(:)-1));
ERRORS.Emedio(:) = Emedio(:);
ERRORS.MAE(:) = MAE(:);
ERRORS.sigma(:) = sigma(:);
ERRORS.Emax(:) = Emax(:);
ERRORS.Emin(:) = Emin(:);
toc
the output is:
Elapsed time is 2.372765 seconds.
Elapsed time is 0.057719 seconds.

Related

MatLab - How to solve an indefinite integral and then define the limits?

I have an model to evaluate a thermodinamical process, it is made with Mathcad and I need it in MatLab.
It is a big equation that uses an integral thousand of times, each temperature uses an definite integral.
If I solve each time, the result is the same as Mathcad, but it takes hours, if I solve only once, it takes less than a second, but the result is wrong.
I split the equation and found that the error is in the part that is in the code.
How should I write my code to solve only one time the and get the right result?
clc
clear
FrCrist = FCrystFastWrong();
FrCrist = FCrystSlowRight();
function [Fvpa] = FCrystSlowRight()
tic;
syms T;
Part4 = (10^(-4.27+(3961/(T-751))));
i = 0;
for TempN = 996:1100
i = i+1;
TC(i) = TempN;
FintDef = int(Part4,T,[1000 TempN]);
Fvpa(i) = double(vpa(FintDef));
end
toc
plot(TC,Fvpa)
end
function [Fvpa] = FCrystFastWrong()
tic;
syms T;
Part4 = (10^(-4.27+(3961/(T-751))));
Fint = int(Part4,T);
qc = arrayfun(#char, Fint, 'uniform', 0);
qc = erase(qc,"int");
qc = erase(qc,", T");
qc = str2sym(qc);
f = inline(qc,'T');
i = 0;
for TempN = 996:1667
i = i+1;
TC(i) = TempN;
Solve(i) = f(TempN)-f(1000);
Fvpa(i) = Solve(i);
end
toc
plot(TC,Fvpa)
end

How to correct grid search?

Trying to find the optimal hyperparameters for my svm model using a grid search, but it simply returns 1 for the hyperparameters.
function evaluations = inner_kfold_trainer(C,q,k,features_xy,labels)
features_xy_flds = kdivide(features_xy, k);
labels_flds = kdivide(labels, k);
evaluations = zeros(k,3);
for i = 1:k
fprintf('Fold %i of %i\n',i,k);
train_data = cell2mat(features_xy_flds(1:end ~= i));
train_labels = cell2mat(labels_flds(1:end ~= i));
test_data = cell2mat(features_xy_flds(i));
test_labels = cell2mat(labels_flds(i));
%AU1
train_labels = train_labels(:,1);
test_labels = test_labels(:,1);
[k,~] = size(test_labels);
%train
sv = fitcsvm(train_data,train_labels, 'KernelFunction','polynomial', 'PolynomialOrder',q,'BoxConstraint',C);
sv.predict(test_data);
%Calculate evaluative measures
%svm_outputs = zeros(k,1);
sv_predictions = sv.predict(test_data);
[precision,recall,F1] = evaluation(sv_predictions,test_labels);
evaluations(i,1) = precision;
evaluations(i,2) = recall;
evaluations(i,3) = F1;
end
save('eval.mat', 'evaluations');
end
an inner-fold cross validation function
and below the grid function where something seems to be going wrong
function [q,C] = grid_search(features_xy,labels,k)
% n x n grid
n = 3;
q_grid = linspace(1,19,n);
C_grid = linspace(1,59,n);
tic
evals = zeros(n,n,3);
for i = 1:n
for j = 1:n
fprintf('## i=%i, j=%i ##\n', i, j);
svm_results = inner_kfold_trainer(C_grid(i), q_grid(j),k,features_xy,labels);
evals(i,j,:) = mean(svm_results(:,:));
% precision only
%evals(i,j,:) = max(svm_results(:,1));
toc
end
end
f = evals;
% retrieving the best value of the hyper parameters, to use in the outer
% fold
[M1,I1] = max(f);
[~,I2] = max(M1(1,1,:));
index = I1(:,:,I2);
C = C_grid(index(1))
q = q_grid(index(2))
end
When I run grid_search(features_xy,labels,8) for example, I get C=1 and q=1, for any k(the no. of folds) value. Also features_xy is a 500*98 matrix.

How can I speed up this MATLAB code with a whileloop?

I'm using a code that calculates expectation value of probabilities. This code contains a while-loop that finds all possible combinations and adds up products of probability combinations. However, when the number of elements becomes large(over 40) it takes too much time, and I want to make the code faster.
The code is as follow-
function pcs = combsum(N,K,prbv)
nprbv=1-prbv; %prbv: probability vector
WV = 1:K; % Working vector.
lim = K; % Sets the limit for working index.
inc = 0; % Controls which element of WV is being worked on.
pcs = 0;
stopp=0;
while stopp==0
if logical((inc+lim)-N)
stp = inc; % This is where the for loop below stops.
flg = 0; % Used for resetting inc.
else
stp = 1;
flg = 1;
end
for jj = 1:stp
WV(K + jj - inc) = lim + jj; % Faster than a vector assignment.
end
PV=nprbv;
PV(WV)=prbv(WV);
pcs=prod(PV)+pcs;
inc = inc*flg + 1; % Increment the counter.
lim = WV(K - inc + 1 ); % lim for next run.
if (inc==K)&&(lim==N-K)
stopp=1;
WV = (N-K+1):N;
PV=nprbv;
PV(WV)=prbv(WV);
pcs=prod(PV)+pcs;
end
end
Is there a way to reduce calculation time? I wonder if parallel computing using GPU would help.
I tried to remove dependent variables in a loop for parallel computing, and I made a matrix of possible combinations using 'combnk' function. This worked faster.
nprbv=1-prbv; %prbv : a probability vector
N = 40;
K = 4;
n_combnk = size(combnk(1:N,K),1);
PV_mat = repmat(nprbv,n_combnk,1);
cnt = 0;
tic;
for i = 1:N-K+1
for j = i+1:N-K+2
for k = j+1:N-K+3
for l = k+1:N-K+4
cnt = cnt+1;
PV_mat(cnt,i) = prbv(i);
PV_mat(cnt,j) = prbv(j);
PV_mat(cnt,k) = prbv(k);
PV_mat(cnt,l) = prbv(l);
end
end
end
end
toc;
tic;
pcs_rr = sum(prod(PV_mat,2));
toc;
However, when K value gets larger, an out-of-memory problem happens in building a combination matrix(PV_mat). How can I break up the big matrix into small ones to avoid memory problem?

What is the fastest way of appending an element to an array?

This is a follow-up question to How to append an element to an array in MATLAB? That question addressed how to append an element to an array. Two approaches are discussed there:
A = [A elem] % for a row array
A = [A; elem] % for a column array
and
A(end+1) = elem;
The second approach has the obvious advantage of being compatible with both row and column arrays.
However, this question is: which of the two approaches is fastest? My intuition tells me that the second one is, but I'd like some evidence for or against that. Any idea?
The second approach (A(end+1) = elem) is faster
According to the benchmarks below (run with the timeit benchmarking function from File Exchange), the second approach (A(end+1) = elem) is faster and should therefore be preferred.
Interestingly, though, the performance gap between the two approaches is much narrower in older versions of MATLAB than it is in more recent versions.
R2008a
R2013a
Benchmark code
function benchmark
n = logspace(2, 5, 40);
% n = logspace(2, 4, 40);
tf = zeros(size(n));
tg = tf;
for k = 1 : numel(n)
x = rand(round(n(k)), 1);
f = #() append(x);
tf(k) = timeit(f);
g = #() addtoend(x);
tg(k) = timeit(g);
end
figure
hold on
plot(n, tf, 'bo')
plot(n, tg, 'ro')
hold off
xlabel('input size')
ylabel('time (s)')
leg = legend('y = [y, x(k)]', 'y(end + 1) = x(k)');
set(leg, 'Location', 'NorthWest');
end
% Approach 1: y = [y, x(k)];
function y = append(x)
y = [];
for k = 1 : numel(x);
y = [y, x(k)];
end
end
% Approach 2: y(end + 1) = x(k);
function y = addtoend(x)
y = [];
for k = 1 : numel(x);
y(end + 1) = x(k);
end
end
How about this?
function somescript
RStime = timeit(#RowSlow)
CStime = timeit(#ColSlow)
RFtime = timeit(#RowFast)
CFtime = timeit(#ColFast)
function RowSlow
rng(1)
A = zeros(1,2);
for i = 1:1e5
A = [A rand(1,1)];
end
end
function ColSlow
rng(1)
A = zeros(2,1);
for i = 1:1e5
A = [A; rand(1,1)];
end
end
function RowFast
rng(1)
A = zeros(1,2);
for i = 1:1e5
A(end+1) = rand(1,1);
end
end
function ColFast
rng(1)
A = zeros(2,1);
for i = 1:1e5
A(end+1) = rand(1,1);
end
end
end
For my machine, this yields the following timings:
RStime =
30.4064
CStime =
29.1075
RFtime =
0.3318
CFtime =
0.3351
The orientation of the vector does not seem to matter that much, but the second approach is about a factor 100 faster on my machine.
In addition to the fast growing method pointing out above (i.e., A(k+1)), you can also get a speed increase from increasing the array size by some multiple, so that allocations become less as the size increases.
On my laptop using R2014b, a conditional doubling of size results in about a factor of 6 speed increase:
>> SO
GATime =
0.0288
DWNTime =
0.0048
In a real application, the size of A would needed to be limited to the needed size or the unfilled results filtered out in some way.
The Code for the SO function is below. I note that I switched to cos(k) since, for some unknown reason, there is a large difference in performance between rand() and rand(1,1) on my machine. But I don't think this affects the outcome too much.
function [] = SO()
GATime = timeit(#GrowAlways)
DWNTime = timeit(#DoubleWhenNeeded)
end
function [] = DoubleWhenNeeded()
A = 0;
sizeA = 1;
for k = 1:1E5
if ((k+1) > sizeA)
A(2*sizeA) = 0;
sizeA = 2*sizeA;
end
A(k+1) = cos(k);
end
end
function [] = GrowAlways()
A = 0;
for k = 1:1E5
A(k+1) = cos(k);
end
end

Deleting matrix elements by = [] vs reassigning matrix

Is there any difference between these two methods for deleting elements in Matlab:
ElementsToDelete = [0 0 1 0 1 0 0 1 1 0]
A = 1:10
A(ElementsToDelete) = []
%Versus
A = 1:10
A = A(~ElementsToDelete)
Are there times when one method is more appropriate than the other? Is there a difference in efficiency? Or are they completely interchangeable?
Try this:
A = rand(1e3, 1);
b = A<0.5;
tic;
for ii = 1:1e5
a = A;
a(b) = [];
end
toc
tic;
for ii = 1:1e5
a = A;
a = a(~b);
end
toc
Results:
Elapsed time is 1.654146 seconds
Elapsed time is 1.126325 seconds
So the difference is a speed factor of 1.5 in favour of re-assigning. This however, is worse:
A = rand(1e4, 1);
stop = 0;
for jj = 1:10
a = A;
start = tic;
for ii = 1:1e5
a(a < rand) = [];
end
stop = stop + toc(start);
end
avg1 = stop/10
stop = 0;
for jj = 1:10
a = A;
start = tic;
for ii = 1:1e5
a = a(a > rand);
end
stop = stop + toc(start);
end
avg2 = stop/10
avg1/avg2
Results:
avg1 = 1.1740235 seconds
avg2 = 0.1850463 seconds
avg1/avg2 = 6.344485136963019
So, the factor's increased to well over 6.
My guess is that deletion (i.e., assigning with []) re-writes the entire array on each and every occurrence of a true in the internal loop through the logical indices. This is hopelessly inefficient, as becomes apparent when testing it like this. Re-assigning on the other hand can determine the size of the new array beforehand and initialize it accordingly; no re-writes needed.
Why the JIT does not compile the one into the other is a mystery to me, because deletion is a far more intuitive notation IMHO. But, as you see, it is inefficient compared to alternatives, and should thus be used sparingly. Never use it inside loops!