تقریباً همه کسانی که با GAMS کار میکنند، حداقل یک بار با این مشکل روبهرو شدهاند: مدل اجرا میشود، اما حل آن ساعتها طول میکشد.
بسیاری از کاربران تصور میکنند راهحل، خرید یک کامپیوتر قویتر یا تغییر Solver است. اما تجربه نشان میدهد در اغلب موارد، مشکل از سختافزار نیست؛ بلکه از نحوه مدلسازی است.
در پروژههای بزرگ مانند برنامهریزی ریزشبکه، بازار برق، سیستمهای انرژی یکپارچه و مسائل چنددورهای، تنها با چند تغییر در ساختار مدل میتوان زمان حل را از چند ساعت به چند دقیقه کاهش داد.
در این مقاله، ۱۰ تکنیک کاربردی را بررسی میکنیم که در پروژههای واقعی باعث افزایش چشمگیر سرعت مدلهای GAMS شدهاند.
۱. قبل از تغییر Solver، مدل را اصلاح کنید
بزرگترین اشتباه این است که ابتدا Solver را عوض کنید. اگر مدل بهدرستی نوشته نشده باشد، حتی بهترین Solverها نیز عملکرد مطلوبی نخواهند داشت. ابتدا این موارد را بررسی کنید:
- تعداد متغیرها
- تعداد قیود
- تراکم ماتریس
- متغیرهای صحیح
- ساختار روابط
۲. از Setهای کوچکتر استفاده کنید
گاهی مجموعهها بسیار بزرگ تعریف میشوند، در حالی که بخش زیادی از اعضای آنها هرگز استفاده نمیشوند.
مثلاً:
به جای اینکه کل سال را مدل کنید:
t /1*8760/
اگر فقط فصل تابستان موردنیاز است:
t /3000*5200/
کوچکتر شدن Setها مستقیماً تعداد معادلات را کاهش میدهد.
۳. شرطها را تا حد امکان از داخل معادلات خارج کنید
یکی از رایجترین اشتباهاتی که در مدلهای GAMS دیده میشود، استفاده بیش از حد از شرط ($) داخل توابع sum یا بدنه معادلات است. این کدها معمولاً از نظر منطقی کاملاً درست هستند و جواب صحیح تولید میکنند، اما از نظر کارایی همیشه بهترین انتخاب نیستند.
برای مثال بسیاری از کاربران چنین کدی مینویسند:
Balance(i,t)..
P(i,t)=e=
sum(j$(A(i,j)=1),Flow(i,j,t));
در نگاه اول هیچ مشکلی وجود ندارد. اما زمانی که مجموعههای i و j شامل هزاران عضو باشند، GAMS باید برای هر ترکیب ممکن از این دو مجموعه، شرط A(i,j)=1 را بررسی کند. این بررسی بارها و بارها در مرحله Model Generation تکرار میشود و میتواند زمان تولید مدل را بهطور محسوسی افزایش دهد.
راه بهتر این است که این شرط تنها یک بار بررسی شود و نتیجه آن بهصورت یک مجموعه جدید ذخیره شود.
به عنوان مثال:
Set Connected(i,j);
Connected(i,j)=yes$(A(i,j)=1);
سپس در معادله بنویسیم:
Balance(i,t)..
P(i,t)=e=
sum(Connected(i,j),Flow(i,j,t));
در این حالت، GAMS دیگر مجبور نیست در هر بار تولید معادله شرط منطقی را دوباره ارزیابی کند؛ بلکه مستقیماً روی اعضای مجموعه Connected پیمایش انجام میدهد.
این تفاوت شاید در مدلهای کوچک محسوس نباشد، اما در مدلهایی با میلیونها متغیر و معادله، زمان تولید مدل میتواند به شکل قابل توجهی کاهش پیدا کند.
یک قانون تجربی که ما در پروژههای بزرگ رعایت میکنیم این است:
این کار علاوه بر افزایش سرعت، خوانایی کد را نیز بسیار بهتر میکند و نگهداری مدل را در آینده آسانتر خواهد کرد.
۴. از تولید معادلات غیرضروری جلوگیری کنید
یکی از مهمترین قابلیتهای GAMS استفاده از عملگر $ هنگام تعریف معادله است.
به جای تولید هزاران معادله بلااستفاده:
Balance(i,t)$Active(i)..
فقط معادلات موردنیاز ساخته میشوند. در مدلهای بزرگ این کار گاهی تعداد معادلات را تا ۶۰ درصد کاهش میدهد.
۵. متغیرهای صحیح را به حداقل برسانید
بزرگترین عامل افزایش زمان حل، متغیرهای Integer و Binary هستند. هر متغیر باینری فضای جستجو را بهشدت بزرگتر میکند. قبل از اضافه کردن یک Binary Variable از خود بپرسید:
- آیا واقعاً لازم است؟
- آیا میتوان آن را با یک متغیر پیوسته جایگزین کرد؟
- آیا میتوان از قید دیگری استفاده کرد؟
۶. Bounds را مشخص کنید
یکی از رایجترین اشتباهات:
Positive Variable P;
اما هیچ Upper Bound تعریف نشده است. درحالیکه اگر بدانیم:
P.up=100;
Solver فضای جستجوی بسیار کوچکتری خواهد داشت.
۷. از Big-Mهای غیرواقعی استفاده نکنید
تقریباً هر کسی که مدلهای MILP یا MINLP نوشته باشد، حداقل یک بار از روش Big-M استفاده کرده است. اما انتخاب مقدار نامناسب برای این عدد، یکی از مهمترین دلایل کند شدن Solverها است.
متأسفانه بسیاری از کاربران بدون هیچ محاسبهای مینویسند:
M=1000000;
یا حتی
M=1e9;
در حالی که چنین مقادیری معمولاً هیچ توجیه فیزیکی ندارند.
زمانی که Big-M بسیار بزرگ انتخاب شود، ناحیه جستجوی Solver بیش از حد بزرگ میشود و فرآیند Branch and Bound گرههای بسیار بیشتری را بررسی میکند. نتیجه آن، افزایش شدید زمان حل و گاهی مشکلات عددی (Numerical Instability) است.
چگونه یک Big-M مناسب انتخاب کنیم؟
در عمل چند روش کاربردی وجود دارد.
۱. از محدودیتهای فیزیکی سیستم استفاده کنید
این بهترین روش است.
فرض کنید توان خروجی یک ژنراتور هرگز از ۵۰ مگاوات بیشتر نمیشود. پس هیچ دلیلی وجود ندارد که بنویسیم:
M=100000
در حالی که میتوان نوشت:
M=50
یا کمی بزرگتر، مثلاً ۵۵.
هرچه Big-M به مقدار واقعی نزدیکتر باشد، Solver سریعتر عمل خواهد کرد.
۲. از حدود متغیرها کمک بگیرید
فرض کنید داریم:
0 ≤ P ≤ 80
در این صورت مقدار M نیز نباید بسیار بزرگتر از ۸۰ باشد. گاهی تنها با استفاده از Upper Bound متغیرها میتوان مقدار مناسبی برای Big-M تعیین کرد.
۳. ابتدا مدل را بدون متغیرهای باینری حل کنید
این روش در پروژههای تحقیقاتی بسیار کاربرد دارد. ابتدا نسخه Relaxed مدل را اجرا کنید. بیشترین مقداری که متغیر موردنظر میتواند بگیرد، راهنمای بسیار خوبی برای انتخاب Big-M خواهد بود.
۴. برای هر قید، Big-M جداگانه تعریف کنید
یکی از اشتباهات رایج استفاده از یک مقدار ثابت برای کل مدل است. مثلاً:
M=1000
برای تمام قیود.
در حالی که ممکن است:
- در یک قید مقدار مناسب ۳۰ باشد.
- در قید دیگر ۱۵۰.
- در قید سوم ۷۰۰.
هرچه مقدار Big-M اختصاصیتر باشد، Solver سریعتر خواهد بود.
۵. اگر Solver از Indicator Constraints پشتیبانی میکند، از Big-M استفاده نکنید
در بسیاری از Solverهای مدرن مانند CPLEX و Gurobi، میتوان برخی روابط منطقی را بدون استفاده از Big-M مدلسازی کرد. این روش معمولاً هم از نظر پایداری عددی بهتر است و هم سرعت حل را افزایش میدهد. البته در GAMS بسته به Solver و نوع مدل، این قابلیت همیشه در دسترس یا بهصرفه نیست، اما اگر امکان استفاده وجود داشته باشد، ارزش بررسی دارد.
در تجربه ما، انتخاب یک Big-M واقعبینانه گاهی بهاندازه تغییر Solver روی زمان حل مدل اثر گذاشته است.
۸. دادهها را قبل از ورود به GAMS پردازش کنید
بسیاری از کاربران عملیات زیر را داخل مدل انجام میدهند:
- محاسبه میانگین
- نرمالسازی
- دستهبندی
- حذف دادههای تکراری
در حالی که این کارها بهتر است در Python یا MATLAB انجام شوند. هرچه مدل سبکتر باشد، سریعتر حل میشود.
۹. Solver مناسب انتخاب کنید
همه Solverها برای همه مسائل مناسب نیستند.
بهطور کلی:
| نوع مسئله | Solver پیشنهادی |
|---|---|
| LP | CPLEX، Gurobi |
| NLP | IPOPT، CONOPT |
| MINLP | BARON، DICOPT، SBB |
| MIP | Gurobi، CPLEX |
گاهی تغییر Solver میتواند زمان حل را چند برابر کاهش دهد، اما تنها زمانی که مدل ساختار مناسبی داشته باشد.
۱۰. از گزارش عملکرد GAMS استفاده کنید
بیشتر کاربران بعد از پایان حل، فایل Log را نمیخوانند.
در حالی که اطلاعات بسیار ارزشمندی در آن وجود دارد، از جمله:
- تعداد متغیرها
- تعداد قیود
- زمان تولید مدل
- زمان حل
- وضعیت Solver
- گرههای بررسیشده
- Gap نهایی
تحلیل این گزارش معمولاً اولین قدم برای بهینهسازی عملکرد مدل است.
مثال واقعی
شاید این جمله عجیب به نظر برسد، اما ما در یکی از پروژههای واقعی خود هنگام مدلسازی یک مسئله بهینهسازی سهسطحی، با مدلی مواجه شدیم که بیش از ۱۰ میلیون معادله تولید میکرد. در نگاه اول تصور میشد مشکل از سختافزار یا Solver است، اما پس از تحلیل ساختار مدل مشخص شد بخش بزرگی از این معادلات اساساً غیرضروری هستند. تنها با بازنویسی ساختار مجموعهها، حذف معادلات غیرفعال، اصلاح شرطها و بازنگری در نحوه تعریف متغیرها، تعداد معادلات به کمتر از ۲.۵ میلیون رسید و زمان حل مدل به کمتر از یکچهارم کاهش پیدا کرد. این تجربه بهخوبی نشان داد که در بسیاری از پروژههای بزرگ، سرعت حل بیش از آنکه به قدرت پردازنده وابسته باشد، به کیفیت مدلسازی وابسته است.
این تجربه برای ما یک نکته مهم را دوباره ثابت کرد: در بسیاری از پروژههای GAMS، بزرگترین فرصت برای افزایش سرعت، نه در تغییر Solver، بلکه در بهبود کیفیت مدلسازی نهفته است.
اشتباهات رایجی که سرعت مدل را کاهش میدهند
- استفاده بیرویه از متغیرهای Binary
- تعریف Setهای بزرگتر از نیاز
- استفاده از Big-Mهای غیرواقعی
- تولید معادلاتی که هرگز فعال نمیشوند
- تعریف نکردن حدود متغیرها
- انجام پردازش داده داخل GAMS
- انتخاب Solver نامناسب
- نادیده گرفتن فایل Log و گزارش Solver
جمعبندی
در بسیاری از پروژهها، افزایش سرعت مدل GAMS بیش از آنکه به قدرت سختافزار وابسته باشد، به کیفیت مدلسازی بستگی دارد. با اصلاح ساختار مجموعهها، کاهش تعداد متغیرهای صحیح، تعریف کرانهای مناسب، استفاده صحیح از شرطها و انتخاب Solver متناسب با نوع مسئله، میتوان زمان حل را بهطور قابلتوجهی کاهش داد.
اگر روی مسائل پیچیدهای مانند برنامهریزی ریزشبکه، سیستمهای انرژی یکپارچه، بازار برق یا بهینهسازی چندهدفه کار میکنید، این اصول میتوانند تفاوت بین مدلی با زمان حل چندساعته و مدلی با زمان حل چنددقیقهای را رقم بزنند.
دیدگاه خود را بنویسید