Smarter way to index loops in Matlab - matlab

I have written a function (call it F) that works "well" (i.e. gives me the result I want) and inside it I call the exact same function (call it G_i) four times (below one of them) except each time I change the way I index my loop to be able to cover all pairs of coefficients in a matrix. I think this method is poor and I would like to know if you have ideas to improve it please...
I do this to check sequentially conditions on the coefficients of a matrix (sometimes in the order (1,2) then (1,3) then (2,3). I go on checking in different orders).
function G_1=countbackward(a,,,)
n=a;
G_1=[];
N=1;
while N>0
for l=n:-1:1
for m=1:l
if some condition on generated matrices
...
elseif another condition on generated matrices
...
else
N=0 ;
end
G_1=[G_1,g_0] ;
end
end
end
(for n=3 I get with the above the entries: (3,1),(3,2),(2,1).)
Other indexing I use with the exact same body of the above function :
for l=n:-1:1
for m=(l-1):-1:1
Same for the following:
for l=1:n
for m=l+1:n
Same for the following:
for l=1:n
for m=n:-1:l
Thank you for your help.
APPENDIX:
below is a simplified example of my code:
function H=count2backward(a,g_0,s,e)
%matrix g_0 is the "start" matrix
%matrix g_K is the "end" matrix
n=a; % number of nodes in an undirected graph or size A
s=mypayoff(n,g_0);
e=mypayoff(n,g_K);
H=[];
N=1;
while N>0
for l=1:n
for m=n:-1:l
if l~=m && g_0(l,m)==0 && s(l)<=e(l) && s(m)<=e(m) && (s(l)<e(l) || s(m)<e(m) ) ;
g_0(l,m)=g_0(l,m)+1 ;
g_0(m,l)=g_0(m,l)+1 ;
g_0 ;
s=mypayoff(n,g_0);
elseif l~=m && g_0(l,m)==1 && (s(l)<e(l) || s(m)<e(m) ) ;
g_0(l,m)=g_0(l,m)-1 ;
g_0(m,l)=g_0(m,l)-1 ;
g_0 ;
s=mypayoff(n,g_0);
else
N=0;
end
H=[H,g_0] ;
end
end
end

You can generate the indexes and pass them as a parameter. That lets you abstract deciding how to loop into another function.
indexes = countbackwardpattern(a);
G_1=g_i(a, indexes);

Related

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

Logical AND in a for loop

I want to add an additional condition in the for loop.
for(i=1; (i<100)&&(something>0.001) ; i++)
{
//do something
}
How can I implement this in MATLAB?
The following isn't working:
for (y = 1:pI_present_y) && (max_sim_value > threshold)
% do something
end
In a for loop, the number of iterations and the values that the loop variable will have in those iterations are selected as soon as it is executed the first time.
Since you want to check the condition on every iteration, you cannot use a for loop without introducing an if condition inside the loop. This is what already suggested by souty.
However, it would be better to use break once the condition is not satisfied. In this way it will be a true replica of the C code. Otherwise the loop will keep executing till y equals pI_present_y. The result will be same but there will be unnecessary iterations and the value of the loop variable will be different at the end of the loop. i.e.
for y = 1:pI_present_y-1 %Subtracting 1 because you have i<100 in the C code, not i<=100
if max_sim_value <= threshold
break;
end
%do something
end
If you want to use that condition in the loop statement, it is only possible with a while loop.
y=1;
while(y<pI_present_y && max_sim_value>threshold)
% do something
y=y+1;
end
Logical conditions are expressed in if statements
for (y = 1:pI_present_y)
if (max_sim_value > threshold)
% do something
end
end
If one of max_sim_value and threshold is a vector of length pI_present_y, index it with y in the if statement, i.e. max_sim_value(y) or threshold(y).

While Loop and Logical Operators

I want to use an OR statement in my while loop so that the loop terminates whenever either of the two conditions aren't satisfied.
The conditions: (1) i must be less or equal to nmax, and (2) absolute value of R(i,i)-R(i-1,i-1) is less than specified delta
Here's my code (everything seems to work fine except for the while condition as the function executes until nmax is reached every time):
function [R] = romberg(f,a,b,delta,nmax)
R=zeros(nmax,nmax);
R(1,1)=(f(a)+f(b))*(b-a)/2;
i=2;
while i<nmax || abs(R(i,i)-R(i-1,i-1))<delta
m=2^(i-1);
R(i,1)=trapez(f,a,b,m);
for j=2:i
R(i,j)=R(i,j-1)+(R(i,j-1)-R(i-1,j-1))/(4^j-1);
end
i=i+1;
end
R
Try this. There were a few issues with the abs(R(i,i)-R(i-1,i-1)) condition for the while loop.
function [R] = romberg(f,a,b,delta,nmax)
R=zeros(nmax,nmax);
R(1,1)=(f(a)+f(b))*(b-a)/2;
i=2;
E=2*delta;
while i<nmax && E>delta
m=2^(i-1);
R(i,1)=trapez(f,a,b,m);
for j=2:i
R(i,j)=R(i,j-1)+(R(i,j-1)-R(i-1,j-1))/(4^j-1);
end
E=abs(R(i,i)-R(i-1,i-1));
i=i+1;
end

Code returns minimal m s.t P(X>m)=1/n^2 for binomial experiment

Assume we do an experiment where we throw n balls into n jars. X is an independent variable describes number of balls int the first jar. Build a function returns the smallest integer fulfills P(X>m)<1/n^2.
The distribution is binomial so I wrote the following matlab function:
function m = intpq3(n)
flag=0;
par=1/n^2;
m=0;
P=0;
%Since X is non-neative integer
if(n==1)
m=-1*Inf;
else
while(flag==0 && m<=n)
m=m+1;
P=P+nchoosek(n,m)*(1/n)^m*(1-1/n)^(n-m);
if(1-P<=par)
flag=1;
end
end
end
disp(m)
end
But for every 'n' I give it, it returns either error or n-1. What am I doing wrong?
The following version of your program seems to do what you want. The problem with your version as far as I can tell is that you did not include m=0 into your sum of P, thus 1-P was consistently too large. It's always a good idea to ask the program to spit out numbers and compare to paper-and-pencil calculations.
function [m,P] = intpq3(n,varargin);
if nargin==2
plt=varargin{1};
else
plt = 0;
end
flag=0;
par=1/n^2;
m=0;
P=0;
disp(['1/n^2 = ' num2str(par)]);
%Since X is non-neative integer
if(n==1)
m=-1*Inf;
else
while m<n & flag==0
P=P+nchoosek(n,m)*(1/n)^m*(1-1/n)^(n-m);
disp([' n= ' num2str(n) ' m= ' num2str(m) ' P(X>' num2str(m) ') ' num2str(1-P)])
if(1-P<=par)
flag=1;
end
m=m+1;
end
end
disp(['mselect = ' num2str(m-1)]);
end
The following also helped to diagnose the problem. It shows values of P(X>m) (colored dots) for different m at select values of n. Overlayed as a dashed line is 1/n^2.

multiple if conditions in matlab

while running the code below, the conditions (1) and (3) are not read in Matlab.
I tried my best but couldn't figure the mistake. Any help will be much appreciated.
% inputs are a_s, p, t, a
% a_s=single number
% p,t,a are column vectors
% output is P (also a column vector)
if a_s<a<=a_s-180
if p<=180-t %------(1)
P=p+t;
elseif p>180-t %------(2)
P=p+t-180;
end
elseif a<=a_s | a_s-180<a
if p>=t %------(3)
P=p-t;
elseif p<t %------(4)
P=p-t+180;
end
end
Try the following substitutions:
Substitute this:
if p<=180-t %------(1)
P=p+t;
elseif p>180-t %------(2)
P=p+t-180;
end
for this:
P = p+t;
P(P<=180) = P(P<=180)-180;
and this:
if p>=t %------(3)
P=p-t;
elseif p<t %------(4)
P=p-t+180;
end
for this:
P = p-t;
P(P<0) = P(P<0)+180;
as for the two ifs for a_s and a it's not clear if you want to execute the branch when any() condition is true or only if all of them are true (which is the default). Remember that a is a vector, so a<a_s is a boolean vector.