output iteration results from a loop in Matlab - matlab

I am trying to use a for loop to make some calculations in a cell array but at the end only the results for the last loop are displayed. I would like Matlab to display the results for all loops. Here there is the code:
slope=[];
time=[];
position= [];
for p=1:max(L) % max L gives the number of result{n}. so if max(L)=6 we have from result{1} to result{6} and therefore 6 final values that i want to get%
a=result{n}(:,1);
b=result{n}(:,2);
end
B = [ones(length(a),1) a] \ b % this is to obtain the slope and intercept of a lin. regresion
slope = B(2)
time = result{n}(end,1)-result{n}(1:1)
position = (slope.*result{n}(end,1)+intercept)-(slope.*result{n}(1:1)+intercept)
At the moment in the output that is what i get:
slope =
4.4089
time =
0.5794
position =
2.5546
This result is correct. However, these values are the ones obtained with result{6} and i need the values previous to this one.
Any help is much appreciated !
Thanks in advance!

You are making a mess with the indexes… It is a bit hard to understand what you did on your code, but it may be something like this (pseudocode since the code you gave does not have the result declared):
slope=zeros(1,max(L)); % Pre allocate zeros, one index for each interation
time=zeros(1,max(L));
position=zeros(1,max(L));
a=zeros(1,max(L));
b=zeros(1,max(L));
for p=1:max(L) % max L gives the number of result{n}. so if max(L)=6 we have from result{1} to result{6} and therefore 6 final values that i want to get%
a(p)=result{p}(:,1);
b(p)=result{p}(:,2);
B = [ones(length(a( p ),1) a( p )] \ b( p) % this is to obtain the slope and intercept of a lin. regresion
slope( p) = B(2)
time( p) = result{p}(end,1)-result{p}(1:1)
position( p) = (slope( p ).*result{p}(end,1)+intercept)-(slope ( p) .*result{p}(1)+intercept)
end
position(6) will get your value, position(5) the previous value.

The easiest way to do this is to remove the ";" for lines that you want printed to the command window. This will display all loop values you need.
for p=1:max(L)
a=result{n}(:,1)
b=result{n}(:,2)
end

Can you do all calculations inside the loop and don't block with ";" instead. If you get a result after coming out of a loop, you will only get the last one.

Related

Matlab: for loop and sprintf combination

I have the following data:
no_gridpoints = 640 % amount of columns in considered
surfaceelevation % a 1x640 array with surface elevation
Terskol1752, Terskol1753, ... Terskol2017 % 365x1 arrays with daily mean temperatures for 1 year of which the fifth colomn contains the temperature data
I want to create temp_glacier files with the corresponding year in the file name. This with a loop over all the years (1752-2017) by using the sprintf command in the loop:
for k = 1752:2017
for m = 1:no_gridpoints
sprintf('temp_glacier%d(m)',k) = sprintf('Terskol%d(:,5)',k) + surfaceelevation
end
end
However, I always get the error 'Subscripted assignment dimension mismatch.'. Can anyone tell me what I am doing wrong?
Thanks
As stated in my comment: it looks like you're mistaking sprintf for eval. The expression within sprintf is not evaluated, so your assignment is stating "make this string = this other string added to an array" - it makes no sense.
To correct your code as-is, you could do the following
for k = 1752:2017
for m = 1:no_gridpoints
eval(sprintf('temp_glacier%d(m) = Terskol%d(:,5) + surfaceelevation', k, k))
end
end
This is a bad idea
It would be far better practise for you to store your yearly data in a single cell array (or because it's numerical and the same size, just a standard matrix) rather than 266 individually named variables. I say better practise because if you to mean to use eval, you should know it should be avoided!
This method would look like the following:
Terskol = [ ... ] % your data here, in a 266*365 matrix where each row is a year
for k = (1752:2017) - 1751 % We actually want to loop through rows 1 to 266
for m = 1:no_gridpoints
% Your arrays were 1D, so you were originally getting a scalar temp val
% We can do that here like so...
temp_glacier(m) = Terskol(k, 5) + surfaceelevation;
% Now do something with temp_glacier, or there was no point in this loop!
% ...
end
end
Vectorising the inner loop:
for k = (1752:2017) - 1751 % We actually want to loop through rows 1 to 266
temp_glacier = repmat( Terskol(k, 5) + surfaceelevation, 1, no_gridpoints );
% Do something with temp_glacier...
end

MATLAB: Using a for loop within another function

I am trying to concatenate several structs. What I take from each struct depends on a function that requires a for loop. Here is my simplified array:
t = 1;
for t = 1:5 %this isn't the for loop I am asking about
a(t).data = t^2; %it just creates a simple struct with 5 data entries
end
Here I am doing concatenation manually:
A = [a(1:2).data a(1:3).data a(1:4).data a(1:5).data] %concatenation function
As you can see, the range (1:2), (1:3), (1:4), and (1:5) can be looped, which I attempt to do like this:
t = 2;
A = [for t = 2:5
a(1:t).data
end]
This results in an error "Illegal use of reserved keyword "for"."
How can I do a for loop within the concatenate function? Can I do loops within other functions in Matlab? Is there another way to do it, other than copy/pasting the line and changing 1 number manually?
You were close to getting it right! This will do what you want.
A = []; %% note: no need to initialize t, the for-loop takes care of that
for t = 2:5
A = [A a(1:t).data]
end
This seems strange though...you are concatenating the same elements over and over...in this example, you get the result:
A =
1 4 1 4 9 1 4 9 16 1 4 9 16 25
If what you really need is just the .data elements concatenated into a single array, then that is very simple:
A = [a.data]
A couple of notes about this: why are the brackets necessary? Because the expressions
a.data, a(1:t).data
don't return all the numbers in a single array, like many functions do. They return a separate answer for each element of the structure array. You can test this like so:
>> [b,c,d,e,f] = a.data
b =
1
c =
4
d =
9
e =
16
f =
25
Five different answers there. But MATLAB gives you a cheat -- the square brackets! Put an expression like a.data inside square brackets, and all of a sudden those separate answers are compressed into a single array. It's magic!
Another note: for very large arrays, the for-loop version here will be very slow. It would be better to allocate the memory for A ahead of time. In the for-loop here, MATLAB is dynamically resizing the array each time through, and that can be very slow if your for-loop has 1 million iterations. If it's less than 1000 or so, you won't notice it at all.
Finally, the reason that HBHB could not run your struct creating code at the top is that it doesn't work unless a is already defined in your workspace. If you initialize a like this:
%% t = 1; %% by the way, you don't need this, the t value is overwritten by the loop below
a = []; %% always initialize!
for t = 1:5 %this isn't the for loop I am asking about
a(t).data = t^2; %it just creates a simple struct with 5 data entries
end
then it runs for anyone the first time.
As an appendix to gariepy's answer:
The matrix concatenation
A = [A k];
as a way of appending to it is actually pretty slow. You end up reassigning N elements every time you concatenate to an N size vector. If all you're doing is adding elements to the end of it, it is better to use the following syntax
A(end+1) = k;
In MATLAB this is optimized such that on average you only need to reassign about 80% of the elements in a matrix. This might not seam much, but for 10k elements this adds up to ~ an order of magnitude of difference in time (at least for me).
Bare in mind that this works only in MATLAB 2012b and higher as described in this thead: Octave/Matlab: Adding new elements to a vector
This is the code I used. tic/toc syntax is not the most accurate method for profiling in MATLAB, but it illustrates the point.
close all; clear all; clc;
t_cnc = []; t_app = [];
N = 1000;
for n = 1:N;
% Concatenate
tic;
A = [];
for k = 1:n;
A = [A k];
end
t_cnc(end+1) = toc;
% Append
tic;
A = [];
for k = 1:n;
A(end+1) = k;
end
t_app(end+1) = toc;
end
t_cnc = t_cnc*1000; t_app = t_app*1000; % Convert to ms
% Fit a straight line on a log scale
P1 = polyfit(log(1:N),log(t_cnc),1); P_cnc = #(x) exp(P1(2)).*x.^P1(1);
P2 = polyfit(log(1:N),log(t_app),1); P_app = #(x) exp(P2(2)).*x.^P2(1);
% Plot and save
loglog(1:N,t_cnc,'.',1:N,P_cnc(1:N),'k--',...
1:N,t_app,'.',1:N,P_app(1:N),'k--');
grid on;
xlabel('log(N)');
ylabel('log(Elapsed time / ms)');
title('Concatenate vs. Append in MATLAB 2014b');
legend('A = [A k]',['O(N^{',num2str(P1(1)),'})'],...
'A(end+1) = k',['O(N^{',num2str(P2(1)),'})'],...
'Location','northwest');
saveas(gcf,'Cnc_vs_App_test.png');

Preallocating in MATLAB when a loop has the "Union" function

Assume there is a loop which should be preallocated. It can be done either by "zeros", "eye" or "NAN" matrices. The problem is when one of these 3 matrices are being used, after using union function, an extra line of zeros (or one or NAN) will be remain which should delete at the end.
For example:
Q=[0 0];
for i=1:10
q= [rand(1) 2*rand(1)];
Q= union(Q,q,'rows');
end
Consequently, there is a [0 0] array remain at the beginning of our matrix which should be deleted.
Q(1,:)=[];
I was wondering if you could help with a code which can do reallocating without needing erasing the first line.
P.S. just image there is a reason for keep the union and loop.
Thanks
Don't ask for a union that you don't want:
Q = [];
for i=1:10
q = [rand(1) 2*rand(1)];
if(isempty(Q))
Q = q;
else
Q = union(Q,q,'rows');
end
end
Or, instead of initializing Q with values that you don't want, initialize it with a value you DO want:
Q = [rand(1) 2*rand(1)];
for i=1:9
q = [rand(1) 2*rand(1)];
Q = union(Q,q,'rows');
end
This really has nothing to do with preallocation. The way union works forces it to return a new value for Q each time, which means you overwrite the previous value. preallocation is when you insert data into the correct location of an appropriately-sized output matrix, in order to avoid extra memory allocations due to resizing your output.

MATLAB: subtracting each element in a large vector from each element in another large vector in the fastest way possible

here is the code I have, its not simple subtraction. We want subtract each value in one vector from each value in the other vector, within certain bounds tmin and tmax. time_a and time_b are the very long vectors with times (in ps). binsize is just for grouping times in a similar range for plotting. The longest way possible would be to loop through each element and subtract each element in the other vector, but this would take forever and we are talking about vectors with hundreds of megabytes up to gb.
function [c, dt, dtEdges] = coincidence4(time_a,time_b,tmin,tmax,binsize)
% round tmin, tmax to a intiger multiple of binsize:
if mod(tmin,binsize)~=0
tmin=tmin-mod(tmin,binsize)+binsize;
end
if mod(tmax,binsize)~=0
tmax=tmax-mod(tmax,binsize);
end
dt = tmin:binsize:tmax;
dtEdges = [dt(1)-binsize/2,dt+binsize/2];
% dtEdges = linspace((tmin-binsize/2),(tmax+binsize/2),length(dt));
c = zeros(1,length(dt));
Na = length(time_a);
Nb = length(time_b);
tic1=tic;
% tic2=tic1;
% bbMax=Nb;
bbMin=1;
for aa = 1:Na
ta = time_a(aa);
bb = bbMin;
% tic
while (bb<=Nb)
tb = time_b(bb);
d = tb - ta;
if d < tmin
bbMin = bb;
bb = bb+1;
elseif d > tmax
bb = Nb+1;
else
% tic
% [dum, dum2] = histc(d,dtEdges);
index = floor((d-dtEdges(1))/(dtEdges(end)-dtEdges(1))*(length(dtEdges)-1)+1);
% toc
% dt(dum2)
c(index)=c(index)+1;
bb = bb+1;
end
end
% if mod(aa, 200) == 0
% toc(tic2)
% tic2=tic;
% end
end
% c=c(1:end-1);
toc(tic1)
end
Well, not a final answer but a few clue to simplify and accelerate your system:
First, use cached values. For example, in your line:
index = floor((d-dtEdges(1))/(dtEdges(end)-dtEdges(1))*(length(dtEdges)-1)+1);
your loop repeat the same computations every iteration. You can calculate the value before starting the loop, cache it then reuse the stored result:
cached_dt_constant = (dtEdges(end)-dtEdges(1))*(length(dtEdges)-1) ;
Then in your loop simply use:
index = floor( (d-dtEdges(1)) / cached_dt_constant +1 ) ;
if you have so many loop iteration you'll save valuable time this way.
Second, I am not entirely sure of what the computations are trying to achieve, but you can save time again by using the indexing power of matlab. By replacing the lower part of your code like this, I get an execution time 2 to 3 time faster (and the same results obviously).
Na = length(time_a);
Nb = length(time_b);
tic1=tic;
dtEdge_span = (dtEdges(end)-dtEdges(1)) ;
cached_dt_constant = dtEdge_span * (length(dtEdges)-1) ;
for aa = 1:Na
ta = time_a(aa);
d = time_b - ta ;
iok = (d>=tmin) & (d<=tmax) ;
index = floor( (d(iok)-dtEdges(1)) ./ cached_dt_constant +1 ) ;
c(index) = c(index) +1 ;
end
toc(tic1)
end
Now there is only one loop to go through, the inner loop has been removed and replaced by vectorized calculation. By scratching the head a bit further there might be a way to do even without the top loop and use only vectorized computations. Although this will require to have enough memory to handle quite big arrays in one go.
If the precision of each value is not critical (I see you round and floor values often), try converting your initial vectors to 'single' type instead of the default matlab 'double'. that would almost double the size of array your memory will be able to handle in one go.

MATLAB setting matrix values in an array

I'm trying to write some code to calculate a cumulative distribution function in matlab. When I try to actually put my results into an array it yells at me.
tempnum = ordered1(1);
k=2;
while(k<538)
count = 1;
while(ordered1(k)==tempnum)
count = count + 1;
k = k + 1;
end
if(ordered1(k)~=tempnum)
output = [output;[(count/537),tempnum]];
k = k + 1;
tempnum = ordered1(k);
end
end
The errors I'm getting look like this
??? Error using ==> vertcat
CAT arguments dimensions are not consistent.
Error in ==> lab8 at 1164
output = [output;[(count/537),tempnum]];
The line to add to the output matrice was given to me by my TA. He didn't teach us much syntax throughout the year so I'm not really sure what I'm doing wrong. Any help is greatly appreciated.
If you're building the matrix output from scratch, you should make sure it hasn't already been initialized to anything. To do this, you can set it to the empty matrix at the beginning of your code:
output = [];
Also, if you know how large output is going to be, your code will run more efficiently if you preallocate the array output and index into the array to assign values instead of appending values to it. In your case, output should have the same number of rows as there are unique values in the array ordered1, so you could use the function UNIQUE to preallocate output:
nRows = numel(unique(ordered1)); %# Get the number of unique values
output = zeros(nRows,2); %# Initialize output
You would then have to keep a separate counter (say r) to track which index into output you will be adding to next:
...
output(r,:) = [count/537 tempnum]; %# Overwrite a row in output
r = r+1; %# Increment the row index
...
Some additional advice...
Even if you solve the error you are getting, you're going to run into more with the code you have above:
I believe you are actually computing a probability density function (or PDF) with your code. In order to get the cumulative distribution function (or CDF), you have to perform a cumulative sum over the final values in the first column of output. You can do this with the function CUMSUM:
output(:,1) = cumsum(output(:,1));
Your loop will throw an error when it reaches the last element of ordered1. The value of k can become 538 in your inner while loop, which will then cause an error to be thrown when you try to access ordered1(k) anywhere. To get around this, you will have to add checks to the value of k at a number of points in your code. One such point is your inner while loop, which can be rewritten as:
while (k <= 537) && (ordered1(k) == tempnum)
count = count + 1;
k = k + 1;
end
This solution uses the short-circuit AND operator &&, which will first check if (k <= 537) is true or false. If it is false (i.e. k > 537), the second logical check is skipped since its result doesn't matter, and you avoid the error that would result from evaluating ordered1(k).
Bonus MATLAB coolness...
MATLAB has a lot of cool functions that can do a lot of the work for you. One such function is ACCUMARRAY. Your TA may want you to do things using loops like you have above, but you can actually reduce your whole code to just a few lines like so:
nValues = numel(ordered1); %# Get the number of values
p = accumarray(ordered1,ones(size(ordered1)))./nValues; %# Create a PDF
output = [cumsum(p) unique(ordered1)]; %# Create the CDF output