مانند هر زبان برنامه نویسی دیگر در گمز نیز حلقه ها انواع مختلفی دارند که بسته به کاربرد باید از یک یا ترکیبی از آنها استفاده نمود. در این تاپیک این حلقه ها به طور مختصر و مفید آموزش داده شده اند. در صورت وجود هر گونه سوالی در بخش نظرات همین تاپیک سوال خود را مطرح فرمایید.

حلقه Loop:

عمومی ترین حلقه در گمز loop است که در زیر ساختار کلی آن را مشاهده می کنید.


Loop( (sets),
statement or statements to execute
);

در کل بالا، sets اندیس یا اندیس هایی هستند کهرطبق آن ما می خواهیم که حلقه امان عمل کند. و statements هم شامل گذاره ها یا عملیاتیست که در هر لوپ مایلیم محاسبه یا انجام گیرند.

چند نکته:

گذاره ها در دستور Loop می توانند بیشتر از یک عدد باشند.

گذاره ها میتوانند شامل مواردی از قبیل if, put و display  و کاربردی تر از همه solve هم باشند. یعنی توسط لوپ می توان یک دستور solve را چندین بار ران گرفت و هر سری نتایج را ذخیره کرد. این عمل در مدلهای دینامیک، تجلیل پوششی، عدم قطعیت و… بسیار کاربرد دارد.

درون یک لوپ می توان یک نرم افزار دیگر را اجرا یا فراخوانی کرد. به عنوان مثال میتوان یک داده را از روی اکسل خواند و یا توسط آن دستور داد که یک نرم افزار دیگر اجرا شود و نتیجه آن به گمز بازگردد.

مهم، هیچ equationی نباید درون دستور loop قرار گیرد.

در سایز های بالا ترجیحا از دستور display در حلقه ها خودداری کنید. چرا که این عمل موجب افزایش حجم فایل lst می شود و ممکن است مشکلاتی را در پی داشته باشد. البته در صورت وجود چنین مشکلاتی می توانید از این تاپیک استفاده کنید.

 

چند مثال:


* Example 1
set t / 1985*1990 /
parameter pop(t) / 1985 3456 /
growth(t) / 1985 25.3, 1986 27.3, 1987 26.2
1988 27.1, 1989 26.6, 1990 26.6 /;

loop(t, pop(t+1) = pop(t) + growth(t) ) ;

* example 2
Loop (i,
problemdata=savparam(i);
Solve mymodel using lp maximizing profit;
Data(i)=profit.l;
) ;

* example 3
* Note that k is a set, not a parameter
loop(index,
k(index)=yes;
solve lptest using lp minimizing lam;
);

* Example 4
put / ’Type one’ / ;
loop(i,
put / ’- Mode : ’ @20 i.tl:1
/ ’- Date (mm/yy) : ’ @20 i.tl:5 @19 i.tl:3 @19 ’ ’ @22 ’/’
/ ’- Item Type : ’ @15 i.tl:7 @15 ’ : ’
/
);
put / ’Type two’ / ;
loop(i,
put / @20 i.tl:1 @1 ’- Mode : ’
/ @20 i.tl:5 @19 i.tl:3 @22 ’/’ @1 ’- Date (mm/yy) : ’
/ @15 i.tl:7 @1 ’- Item Type : ’
/
);

* example 5
loop(i$ ord(i)  gt  3,
if (x(i)  lt  y(i),
a=4;
);
);
* Example 6
set i/1*2/
parameter x/2/,z;
loop(i$x, z=3;);

در مثال آخر دقت کنید که شرط نوشته شده در دستور Loop متناظر با عبارت: حلقه را اعمال کن به شرطی که x مقداری مخالف صفر داشته باشد.

حلقه while:

این حلقه در دو حالت عمومی زیر نوشته می شود. که در آن عبارت logical condition یک شرط را نمایش می دهد. حلقه ی while تا وقتی اجرا می شود که شرط ارائه شده در قسمت logical condition رعایت شود.

---- first way
While (logical condition,
statements to be executed While condition is true;
);
---- second way
$Onend
While conditional do
statements ;
Endwhile;

فرق دو روش فوق بسیار واضح است. در روش اول از پرانتز و ویرگول استفاده می کنیم. در روش دوم از $onend و do و Endwhile استفاده می کنیم. چند مثال زیر را با دقت مرور کنید تا کلیات این دستور ملکه ذهنتان شود.


While(x lt 10,
x=x+0.01;
);
$Onend
While x lt 10 do
x=x+0.01;
Endwhile;

While(prod(I,q(i)), z=2;q(i)=q(i)-2);

while(converge = 0 and iter lt lim,
root=(maxroot+minroot)/2;
iter=iter+1;
function_value=a-b*root+c*sqr(root);
if(abs(function_value) lt tolerance,
converge=1;
else
if(sign(function_value1)=sign(function_value),
minroot=root;
function_value1=function_value;
else
maxroot=root;
function_value2=function_value;);
);
* display iter,lim,root,minroot,maxroot,
* function_value,function_value1,function_value2;
);

حلقه ی for:
این حلقه نیز به دو صورت زیر تعریف می شود.

* first
for (i = start to|downto end [by incr],
statements;
);
* second
$Onend
For (i = start to|downto end [by incr] ) do
statements ;
endfor;

در کد بالا، start ابتدای بازه و end انتهای بازه و incr مقدار افزایش در هر گام حلقه بوده و همگی عدد می باشند (این اعداد می توانند منفی یا مثبت باشند) و همچنین i نباید یک set باشد. به عبارتی i یک پارامتر تعریف می شود. چند مثال زیر موضوع را روش می کند.

* Example 1
scalar i ;
scalar globmin ; globmin = inf ;
option bratio = 1 ;
for (i = 1 to 1000,
x.l(j) = uniform(0,1) ;
solve ml using nlp minimizing obj ;
if (obj.l le globmin,
globmin = obj.l ;
globinit(j) = x.l(j) ;
);) ;
* example 2
for(x=1 downto 12 by 2,
data(i)=x;
);
* Example 3
$Onend
for x=1 downto 12 by 2 do
data(i)=x;
endfor;

حلقه repeat:

برای حلقه ی while توضیح داده شد که statement تا زمانی اجرا می شود که شرط ارائه شده در logical condition نقض شود. در دستور repeat جای logical condition و statement عوض می شود. کد زیر را مشاهده کنید:


repeat ( statements to be executed;
until logical condition is true );

به عبارتی repeat تا وقتی اجرا می شود که logical condition رعایت نشود. در صورتی که logical صحیح باشد، گمز از ادامه ی repeat صرفه نظر می کند.

چند مثال:


** Example 1
repeat (
a=uniform(2,10);
solve mymodel using minlp max z;
display a,z.l;
until (z.l<=5) ;);
** 2 Example
repeat(
root=root+inc;
function_value2= a-b*root+c*sqr(root);
if((sign(function_value1) ne sign(function_value2)
and abs(function_value1) gt 0
and abs(function_value2) gt tolerance),
maxroot=root;
signswitch=1
else
if(abs(function_value2) gt tolerance,
function_value1=function_value2;
minroot=root;));
until (signswitch gt 0 or root  gt maxroot)) ;;
** example 3
repeat(
v=v+1;
break$(v-1=3);
%innerLoop%;
until v>3;

 

نکته: یک شرط توقف برای while, for و repeat استفاده از آپشن زیر است که تعداد تکرارهای هر کدام از دستورات ذکر شده را به تعداد number محدود می کند.

 option forlim=number; 

توجه: در حلقه ها تعاریف نمی توانند قرار گیرند. مثلا درون یک حلقه نمی توان یک مجموعه را تعریف کرد. یا یک پارامتر را تعریف کرد. همچنین در یک حلقه نمیتوان یک equation.. نوشت. دو مثال زیر که کاملا اشتباه است گواه این مدعاست.


for (s = 1 to 5 by 1,
eq.. sum(i,x(i)) =g= 2 ;
);
for (s=1 to 5 by 1,
scalar y ; y = 5 ;
);

توجه:! حلقه ها با سایز بالا در گمز سرعت پایینی نسبت به سایر زبان های برنامه نویسی دارند. از اینرو همیشه به یاد داشته باشید که در صورتی حلقه ی تعریف شده ی شما زمانبر است، از شرط ها، if و سایر دستورات کمکی استفاده کنید که سرعت حلقه بالاتر رود. در صورتی که این عمل نیز اثر نکرد از سایر زبان ها و نرم افزار ها مانند اکسل و متلب برای محاسبات عادی استفاده نموده و خروجی آنها را در گمز وارد کنید.

در کد تا جایی که برای شما امکان دارد به جای حلقه ها از عبارات معادل آنها استفاده کنید. به عنوان مثال در کد زیر رویه ی دومی که برای پارامتر u تعریف شده است سرعت عمل بیشتری نسبت به رویه اول دارد.


set I / 1 * 100000 /;
parameter u(I);
* bad!
loop { I,
u(I) = uniform(0,2);
};
* good
u(I) = uniform(0,2);

]