Fluorite | Level 6

## Do Until Loop

Hello everyone,

I would need your help about a do until loop. Here's my code :

if t=&t then stop;
do i = 1 to &p;
do z=1 to &g;
do j = 1 to &nbx;
do until ( x[j,i]-x[j,i-1] = 1e-7);

........

The aim of this loop is to calculate the difference between the array x[j,i] and the one of the previous iteration (I am not sure if this the right syntax for that : x[j,i-1]), and then to stop the loop when this difference is close to 0.

I also have another criteria : if the "do until criteria" isn't satisfied, then stop the loop when t=&t.

I have this error message :  Array subscript out of range at line 7459 column 35. (line 7459 is do until ( x[j,i]-x[j,i-1] = 1e-7);)

8 REPLIES 8
Diamond | Level 26

## Re: Do Until Loop

Can we see the whole PROC code or the whole DATA step code, instead of this small portion? What is &t? Where does it get assigned and changed? What are the other macro variables? Are they ever zero or negative or missing? Are they are ever non-integers?

Please post your code in a code text box, which is the little running man icon. Thanks.

--
Paige Miller
Fluorite | Level 6

## Re: Do Until Loop

``````if t=&t then stop;
do i = 1 to &p;
do z=1 to &g;
do j = 1 to &nbx;
do until ( x[j,i]-x[j,i-1] = 1e-7);

/* Compute new velocity and restrict it within minima and maxima */
v[j,i] = &chi*(&w*v[j,i] + &c1 * &r1 * (pbest[j,i] - x[j,i]) + &c2 * &r2 * (gbest[j] - x[j,i]));
v[j,i] = min(&vmax, max(-&vmax, v[j,i]));
/* Move particle to new position and restrict them to the UP and LB  */
x[j,i] = x[j,i]+ v[j,i];
x[j,i] = min(&UB, max(&LB, x[j,i]));``````

Here is a bigger part of the code, &t is a variable that I initialize in the first part with &let t=1000 for example. It's the iterations, the number of time I want my code to run.

Super User

## Re: Do Until Loop

We need to see the whole DATA step code, and we need to know the values of all macro variables used in the code. The log (which is equally important) will reveal the values of all variables at the moment of the crash.

Fluorite | Level 6

## Re: Do Until Loop

``````/*Before running this script, you should run the script "Test functions" to initialize the functions we'll be
working on*/

/*-------------------------------------------------------PSO code----------------------------------------------------*/

/*  PSO parameters */
%let nbx = 2; /* Number of variables */
%let p = 20; /* Number of particles */
%let g = 19 ;/* Number of relations between particles : we take p-1 for the global topology */
%let t = 1000; /* Number of iterations */
%let UB = 5; /* Upper bound on solution */
%let LB = -5; /* Lower bound on solution */
%let vmax =(&UB-&LB)/2; /* Maximum velocity */
%let c1 = 2.05; /* Weight on pull toward best particle position */
%let c2 = 2.05; /* Weight on pull toward best global position */
%let func=rosenbrock; /*The function to minimize*/
%let r1=uniform(0); /* Random variable */
%let r2=uniform(0); /* Random variable */
%let c = &c1 + &c2;/* Acceleration coefficient */
%let chi =2/((&c-2)+sqrt(&c**2-4*&c)); /* Constriction coefficient */
%let w=0.5*uniform(0)+0.5; /* Inertia weight */

/* PSO code */

data solution_canonical;

/* Define arrays for particle position(=x), velocity(=v), bests(pbest and gbest)
and one to store the pbests of the objective function */
array x[&nbx,&p];
array v[&nbx,&p];
array pbest[&nbx,&p];
array gbest[&nbx];
array fpbest[&p];
array n[&nbx,&g];
array nbest[&nbx,&g];
array fnbest[&g];

/* Initialize arrays with random particle locations and velocities */
do i = 1 to &p;
do z = 1 to &g;
do j = 1 to &nbx;
x[j,i] = &LB + (&UB - &LB)*&r1; /* Random particles locations */
n[j,z] = &LB + (&UB - &LB)*&r1; /* Random neighbors locations */
v[j,i] = -&vmax +(2*&vmax)*&r1; /* Random particles velocities */
pbest[j,i] = x[j,i];
nbest[j,z]= n[j,z];
fpbest[i] = %f(%str(pbest[:,i]), func=&func);
fnbest[z]= %f(%str(nbest[:,z]), func=&func);
end;
if i = 1 and z = 1 then do;
do j = 1 to &nbx;
gbest[j] = x[j,i];
end;

/* Store the value of the objective function at the global best */
fgnbest = fnbest[z];
fgbest = fpbest[i];
end;
else do;
if fnbest[z] < fgnbest then do;
do j = 1 to &nbx;
gbest[j] = n[j,z];
end;

if fpbest[i] < fnbest[z] then do;
do j = 1 to &nbx;
gbest[j] = x[j,i];
end;
if fpbest[i] < fgbest then do;
do j = 1 to &nbx;
gbest[j] = x[j,i];
end;
end;
fgbest = fpbest[i];
end;

end;
end;
end;

/* Here is the fun part : Update particle locations and velocities to let them wander*/
/* For each iteration, particle and variable */
if t=&t then stop;
do i = 1 to &p;
do z=1 to &g;
do j = 1 to &nbx;
do until ( x[j,i]-x[j,i-1] = 1e-7);

/* Compute new velocity and restrict it within minima and maxima */
v[j,i] = &chi*(&w*v[j,i] + &c1 * &r1 * (pbest[j,i] - x[j,i]) + &c2 * &r2 * (gbest[j] - x[j,i]));
v[j,i] = min(&vmax, max(-&vmax, v[j,i]));
/* Move particle to new position and restrict them to the UP and LB  */
x[j,i] = x[j,i]+ v[j,i];
x[j,i] = min(&UB, max(&LB, x[j,i]));

end;
end;

/* Calculate the best particle in each neighborhood and THEN update particle and global best positions (if new best found) */

fx= %f(%str(x[:,i]), func=&func);
if fx < fnbest[z] then do;
do j = 1 to &nbx;
nbest[j,z] = n[j,z];
fpbest[i] = fnbest[z];
end;
if fx < fpbest[i] then do;
do j = 1 to &nbx;
pbest[j,i] = x[j,i];
fpbest[i] = fx;
end;
if fx < fgbest then do;
do j = 1 to &nbx;
gbest[j] = x[j,i];
end;
fgbest = fx;

end;
end;
*end;
end;
end;

end;
end;

/* Record the iterations and global best position as the output solution */
/*do j = 1 to &nbx;
do i = 1 to &p;
var_iteration_indice = "x"  || strip(i) || strip(j) ;
iteration_solution = pbest[j,i];
output;
end;
end;
keep  var_iteration_indice  iteration_solution;*/

do j = 1 to &nbx;
var_indice = "x"  || strip(j) ;
global_solution = gbest[j];
output solution_canonical;
end;
keep var_indice  global_solution  ;

run;

proc transpose data=Solution_canonical  out=newt;
var global_solution;
run;

data newt;
set newt;
rename COL1=x1 col2=x2;
run;

data params(type=est);
set newt;
_TYPE_='PARMS';
run;

proc nlp tech=NEWRAP  gradcheck=detail gconv2=1e-21 inest=params;
min f;
parms x1, x2;
f = rosenbrock(x1,x2);
run;``````

Here's the whole code!

Super User

## Re: Do Until Loop

``do until ( x[j,i]-x[j,i-1] = 1e-7);``

In the outermost loop, i starts with 1, so i-1 resolves to zero, while the array starts at 1.

Super User

## Re: Do Until Loop

``````				do until ( x[j,i]-x[j,i-1] = 1e-7);
``````

Whenever the outer loop of i=1 to whatever executes and i=1f then you have

x[j,i-1] referencing x[j,0]

so if x isn't defined in a way to allow an index of 0 in that second position then "i-1" is out of range.

Save yourself some work and copy an entire proc or data step section from the log with the error message and paste into a text box opened on the forum with the </> icon.

Sometimes the actual cause of your error can be quite separate from the statement(s) that SAS is reporting the error for. So the entire step is usually needed.

Fluorite | Level 6

## Re: Do Until Loop

Thank you for your response! How can I correct this do you think? I tried to replace my i=1 to i=2 in all the code but it doesn't seem to work..

## Re: Do Until Loop

Hello @sarrabeny,

@sarrabeny wrote:

do until ( x[j,i]-x[j,i-1] = 1e-7);

........

The aim ... is ... to stop the loop when this difference is close to 0.

Apart from the issue with the array subscripts: Shouldn't the check for the difference being "close to 0" rather use "... < 1e-7" or "... <= 1e-7" than exact equality? And also possibly an absolute value: 0 <= abs(...-...) < 1e-7, unless negative differences can be ruled out? Even if exact equality was the intended criterion, it would often fail due to numeric representation errors.

Example (log from Windows SAS 9.4M5):

```124   data _null_;
125   x=0.1234561;
126   y=0.123456;
127   if round(x-y,1e-10)=1e-7 then put 'equal';
128   if x-y=1e-7 then put 'exactly equal';
129   d=x-y-1e-7;
130   put d=;
131   run;

equal
d=2.875571E-18```
Discussion stats
• 8 replies
• 752 views
• 5 likes
• 5 in conversation