Storing the number of iterations of a nested loop in an array - matlab

I am relatively new to MATLAB and I am quite stuck in a specific problem.
I have an equation that I am trying to solve using a while loop. It works by guessing a certain parameter e_0 and filling it into the equation, until it converges. An example is found below, where the initial guessing value equals 100:
clear all
i=1;
e_0=100
e_1= e_0 + log(0.6) - log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
e_0=e_1;
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
end
i
Now I would like the exact same procedure but then for multiple values of e_0 at the same time, e.g. 101, 102, 103 and so on, and count how many more iterations those will take. I reckon that I therefore need to put a for-loop for that. I thought something like this:
clear all
i=1;
for e_0 = 100:105
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
e_0=e_1;
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
end
end
i
However, now all the iterations from the different guessing values are shown underneath each other, and I get a total of 1519 iterations. How can I for example store the number of iterations needed for every initial guessing value underneath each other into a variable?
I hope it is clear enough... Thank you!

How about this:
i = 0;
offset = 99;
for n = 1:6
e_0 = n + offset;
e_1 = e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
This part needs to change to prevent e_0 to be redefined inside the loop:
e_1= e_1+log(0.6)-log(exp(e_1)/(exp(e_1)+1))
end
iterations(n)=i;
end
Note: it is not recommended to use i as a loop increment, since it redefines i used in complex numbers.

Related

A conditional statement during a for loop in MATLAB

This is my attempt of a simple example (it seems pointless) but the idea is bigger than this simple code.
During a for loop, if something happens, I want to skip this step of the for loop and then add an extra step on the end.
I am trying to create a list of numbers, that do not include the number 8.
If the code creates an 8, this will mean that exitflag is equal to 1.
Can I adapt this program so that if the exitflag=1, the it will remove that result and add another loop.
The code:
for i = 1:1000
j = 1+round(rand*10)
if j == 8
exitflag = 1
else
exitflag = 0
end
storeexit(i)=exitflag;
storej(i)=j;
end
sum(storeexit)
I would ideally like a list of numbers, 1000 long which does not contain an 8.
If what you want to do is 1000 iterations of the loop, but repeat a loop iteration if you don't like its result, instead of tagging the repeat at the end, what you can do is loop inside the for loop until you do like the result of that iteration:
stores = zeros(1000,1); % Note that it is important to preallocate arrays, even in toy examples :)
for i = 1:1000
success = false; % MATLAB has no do..while loop, this is slightly more awkward....
while ~success
j = 1+round(rand*10);
success = j ~= 8;
end
storej(i) = j; % j guaranteed to not be 8
end
No.
With for loop, the number of loops is determined on the loop start and it is not dynamic.
For doing what you want, you need to use a while loop.

How to transfer excel formula to octave?

As you can see the image (excel file) I would like to use that formula in Octave to get the desired result. I also uploaded the octave codes picture and the workspace picture too. In workspace my result/values for storage variable should be the same values like that in excel (storage column). I have a doubt that in the code the last part using (if statement with i-1 is seems to be the error).
Can someone help me to figure it out? Let me know if any further clarifications required. Also I am posting my code below too:
BM_max = 1236;
virtual_feed_max = 64;
operation = dlmread ('2020Operation.csv');
BM = ones (size (operation, 1), 1);
for i=1:size(operation,1)
if operation(i,1)==1
BM(i,1)=BM_max;
else
BM(i,1)=0;
end
end
virtual_feed = ones(size(operation,1),1);
virtual_feed(:,1) = 64;
storage = ones(size(BM,1),1);
c = ones(size(BM,1),1);
for i=1:size(BM,1)
c=(BM(:,1)-virtual_feed(:,1));
end
for i=1:size(BM,1)
if ((i=1)&& c)<0
storage(:,1)=0;
elseif ((i=1)&& c)>0
storage(:,1)=c;
else
# Issue is below (Taking the value from subsequent row is the problem)
if (c+(storage(i-1,1)))<0
storage(:,1)=0;
elseif (c+(storage(i-1,1)))>0
storage(:,1)=(c+(storage(i-1,1)));
end
end
end
Workspace Excel
I think what you want is the following (as seen from your Excel screenshot)
BM_max = 1236;
virtual_feed_max = 64;
operation = [0; 1; 1; 1; 1; 1; 1; 1; 0; 0; 0; 0; 0];
BM = BM_max * operation;
virtual_feed = repmat (virtual_feed_max, size (operation));
storage = zeros (size (operation));
for i=2:numel (storage)
storage (i) = max (BM(i) - virtual_feed(i) + storage(i-1), 0);
endfor
storage
which outputs:
storage =
0
1172
2344
3516
4688
5860
7032
8204
8140
8076
8012
7948
7884
I leave the part of vectorization to make it faster for you. (hint: have a look at cumsum)
From this point on
for i=1:size(BM,1)
if ((i=1)&& c)<0
storage(:,1)=0;
elseif ((i=1)&& c)>0
storage(:,1)=c;
else
# Issue is below (Taking the value from subsequent row is the problem)
if (c+(storage(i-1,1)))<0
storage(:,1)=0;
elseif (c+(storage(i-1,1)))>0
storage(:,1)=(c+(storage(i-1,1)));
end
end
end
you are not changing a single value in storage but all the row/column, so each iteration, all the row/column is being changed instead of a single "cell".
You should use something like this:
storage(i,1) = 0;
BTW, a lot of those 'for' loops can be changed to vector operations. Example:
for i=1:size(BM,1)
c=(BM(:,1)-virtual_feed(:,1));
end
Can be changed for:
c = BM - virtual_feed;

MATLAB: Check for while loop divergence

I have piece of code with a while loop. This loop will diverge in certain conditions and thus will yield a infinite loop.
I want to check whether the loop is diverging and break the loop in an elegant and efficient procedure.
A solution to this is to check every output of the loop, save it, and compare it to the previously calculated loop output.
This is the code:
ai = 0;
ai_old = 100;
iteration = 0;
CDeff = 0;
while abs(ai - ai_old)>2*10^-1 % Get induced angle of attack
iteration = iteration +1;
ai_old = ai;
Cleff = (Clp * cosd(ai)^2 + CDeff * sind(ai) )/cosd(ai);
Veff = Vp/cosd(ai);
Re_eff = Reinf * Veff/Vinf * cp/c;
Meff = Mp/cosd(ai);
if iteration ==1
AFdata(:,2) = AFdata(:,2)/cosd(SweepQC);
end
[~,a_eff,CDeff] = obj.ConstantVortex(AFdata,[],Cleff,Meff);
ai = -a_eff + (AOA + Twists(zz))/cosd(SweepQC);
end
Here, ai is calculated with the function obj.ConstantVortex and compared with the previous calculated ai. The while loop is terminated when the difference is small enough.
However, it can occur that the difference between the initial ai and calculated ai is increasing with every iteration.
How can I check this? and break the loop accordingly?
Thank you
A typical solution for this situation is to store more previous values, and monitor the behaviour over time. So instead of ai_old, you would use:
ai = 0;
num_prev = 5; % how many previous results to check
ai_prev = zeros(1,num_prev);
iteration = 0;
while abs(ai - ai_prev(end))>2*10^-1
iteration = iteration+1;
% your loop code goes here
% now update the array of previous values
ai_prev = circshift(ai_prev,[0 -1]);
ai_prev(end) = ai;
if iteration > num_prev && all(sign(diff(ai_prev)))
% the slope of the previous five results is positive, so exit
break
end
end
You can change the number of previous results and use whatever function is appropriate to check for a break condition on the data in ai_prev for your computation. For example you might want to do some averaging on the previous results, or use a different function than diff().
One solution is to keep last differences or min differences and compare the current difference with that. For example you can have variable ai_older and use it. You can add
ai_older = 1000;
before your while loop and then have
ai_older = ai_old;
ai_old = ai;
and change while condition to
while abs(ai - ai_old)>2*10^-1 && abs(ai - ai_old) < abs(ai_old - ai_older)
Now you can avoid divergence. However, I'm not completely aware of your problem and not sure using abs is required or not.
As I previously mentioned, depending to your problem you may want to keep minimum difference till now and compare current one against that.

Matlab symbols used to terminate the loop

I am new to matlab and I have couple of questions about it. First one, "Your function should terminate the sequence when either the value of ... or..." I use || in the code but it does not work as expected while && gives me the correct answer. Second question, how could the code be to display only the final answer?
Problem: calculate X which is represented by the sequence below
X = 1 - 1/2^2 + 1/3^2 - 1/4^2 +....
Requirement: Your function should terminate the sequence when either the value of 1/k^2 is less than 0.0001 or k is equal to k_max.
input k
Initialize x = 0
for loop i from 1 to k
if 1/i^2<0.0001 && i >= 100
break
end
Calculate X = (-1)^(i+1)./i^2 + X
end
You can use the break function as follows, where END_CONDITION is the condition you want to end your loop in.
if END_CONDITION
disp(X);
break;
end
To display the final answer, you can use the disp function. Eg. if your variable you want to print is called A then you use the following code.
disp(A)
Collectively this is your code. Since k_max terminates at the end of the for loop, we don't have to add any conditions to break out of the loop.
X = 0;
for i = 1:k
if 1/i^2<0.0001 || i==100
break;
end
X = (-1)^(i+1)./i^2 + X;
end
disp(X);

faster sparse matric indexing in matlab

I had a question before but it was not as complete as this one! Actually, what I meant was that I have a nested if-for loop which I did not make it very clear before.
So, I have a very long code which is full of the following "if"s and matlab editor gives me a suggestion as follow:
this sparse indexing expression is likely to be slow
Is there any way by which I can make the code faster and do the matlab's suggestion? (The code may not run, because I just picked a few lines and tried to show the issue)
In my previous question, I did not explain that I need to use the i,j as index, so the answer was not convincing. But, as you can see here, I need to use the i and j as index which make the problem a little different from the previous post.
template = rand(200,200);
grid = rand(200,200);
T = size(template);
rws = size(grid,1);
cols = size(grid,2);
ind = "it is a matrix";
A = sparse(rws*cols,rws*cols);
T = sparse(rws*cols,2);
border_grid = 0;
border_template = 0;
template_comp = 0;
grid_comp = 0;
for i = 1:cols
for j = 1:rws
if(ind(j,i)==255)
Asr=grid(j,i,1);
Bsr=template(((j-posy)+1),((i-posx)+1),1);
Snorm= ((Asr-Bsr)^2)^(1/2);
if (( (j+1) > 0) && ((j+1) <= rws))
if ( ind(j+1,i)==0)
T((i-1)*rws+j,1)=100000;
border_grid=border_grid+1;
end
if ( ind(j+1,i)==128)
border_template=border_template+1;
T((i-1)*rws+j,2)=100000;
end
if( (ind(j+1,i)==255))
Atr=grid(j+1,i,1);
Btr=template(((j+1)-posy)+1,(i-posx)+1,1);
Tnorm= ((Atr-Btr)^2)^(1/2);
A((i-1)*rws+j,(i-1)*rws+(j+1))=Snorm+Tnorm;
end
end
end;
**+ some other similar if-loops**
end
end