HW3.pdf

‫به نام یگانه هستی بخش‬
‫هوش مصنوعی‬
‫مدرس ‪ :‬سلیمانی‬
‫تمرین ‪3‬‬
‫دانشکده مهندسی کامپیوتر‬
‫موعد تحویل تمرین تئوری‪ 23 :‬اسفند قبل از کالس درس‬
‫موعد تحویل تمرین عملی‪ 28 :‬اسفند ساعت ‪24‬‬
‫تمرین تئوری‬
‫سوال ‪ 6( - 1‬نمره)‬
‫در صورتی که الگوریتم ‪ Simulated Annealing‬برای یافتن کمینهی مطلق با هرکدام از شرایط زیر روبهرو‬
‫شود‪ ،‬باید چه تغییری را در ‪ Cooling Schedule‬انجام داد؟‬
‫‪ )a‬الگوریتم معموالً در کمینهی موضعی گیر میکند‪.‬‬
‫‪ )b‬الگوریتم زمان بسیار زیادی را صرف پیدا کردن جواب میکند‪.‬‬
‫‪ )c‬میدانیم که تابع هزینه‪ ،‬محدب (‪ )convex‬است و میخواهیم جواب را در زمان کمتری پیدا کنیم‪.‬‬
‫سوال ‪ 14( - 2‬نمره)‬
‫میخواهیم با استفاده از الگوریتمهای ‪ Simulated Annealing‬و ‪ Genetic Algorithm‬برای مسائل زیر‬
‫جواب مناسبی بیابیم‪ .‬عملگرهای این دو الگوریتم را (برای ‪ :SA‬نمایش حالتها‪ ،‬تابع هزینه و یافتن همسایهها و‬
‫برای ‪ :GA‬نمایش کروموزومها‪ ،‬تابع هزینه‪ ،‬تولید مثل و جهش) برای هر مسئله توضیح دهید‪.‬‬
‫‪ )a‬مسئلهی رنگآمیزی گراف‪ :‬میخواهیم رأسهای یک گراف را با حداقل تعداد رنگ‪ ،‬رنگآمیزی کنیم به‬
‫طوری که هیچ دو رأس مجاوری همرنگ نباشند‪ .‬مطلوب است رنگ هر رأس‪.‬‬
‫‪ )b‬مسئلهی فروشندهی دورهگرد‪ :‬تعدادی شهر داریم و هزینه رفتن مستقیم از هر شهر به دیگری را میدانیم‪.‬‬
‫مطلوب است کمهزینهترین مسیری که از یک شهر شروع شود و از تمامی شهرها دقیقاٌ یکبار عبور کند‬
‫و به شهر شروع بازگردد‪.‬‬
‫سوال ‪ 10( - 3‬نمره)‬
‫روباتی در یک جدول ‪ 3x3‬به شکل زیر است‪ .‬روبات در هر لحظه یک ‪ Perception‬دارد که او را از رنگ خانهی‬
‫فعلی مطلع میسازد‪ B( .‬برای رنگ آبی و ‪ R‬برای رنگ قرمز) سپس یک ‪ – Action‬که حرکت به یکی از جهات‬
‫باال پایین‪ ،‬چپ و یا راست است – را انجام میدهد‪ .‬دورِ جدول دیوار کشیده شده است‪ .‬در صورتی که روبات در‬
‫خانههای کناری باشد و بخواهد به سمت دیوار حرکت کند‪ ،‬حرکتش بیاثر خواهد بود و در همان خانه میماند‪.‬‬
‫مکان اولیهی روبات نامعلوم است و فقط میدانیم نتیجهی اولین ‪ B ،Perception‬است‪.‬‬
‫‪ )a‬یک گراف ‪ And-Or‬رسم کنید و با استفاده از آن‪ ،‬پس از حداکثر ‪ 3‬حرکت‪ ،‬مکان اولیهی روبات را‬
‫بیابید‪( .‬نیازی نیست که پس از یافتنِ مکانِ اولیه‪ ،‬به آن بازگردید)‬
‫‪ )b‬آیا این گراف دور دارد؟‬
‫‪ )c‬آیا میتوان با تعداد حرکت کمتری مکان اولیه را یافت؟ اگر راهی هست‪ ،‬گرافِ آن را رسم کنید و در غیر‬
‫این صورت دلیل آن را بیان کنید‪.‬‬
‫سوال ‪ 10( - 4‬نمره)‬
‫فرض کنید روباتی در جدولی ‪ 3x3‬قرار دارد‪ .‬دور جدول کامالً دیوار کشیده شده است‪ .‬عالوه بر این بین بعضی‬
‫از خانههای جدول هم دیوار وجود دارد‪ .‬مثالً جدولِ زیر چهار دیوار داخلی دارد‪:‬‬
‫فرض کنید وضعیت دیوارهای داخلی در ابتدا مشخص نیست‪ .‬در هر لحظه‪ ،‬روبات یک حرکت به یکی از چهار‬
‫جهت انجام میدهد و پس از آن از دیوارهای داخلیِ چهار طرفِ خود مطلع میشود‪ .‬مکان اولیهی روبات و هدف‬
‫مشخص است‪ .‬اگر از الگوریتم ‪ online DFS‬استفاده شود و شمارهگذاری وضعیتها به صورت زیر باشد‪ ،‬مشخص‬
‫کنید که وضعیتها با چه ترتیبی در طول این الگوریتم مالقات میشوند (در شرایط یکسان بین کنشها ترتیب‬
‫باال‪ ،‬پایین‪ ،‬چپ و راست را برای اعمال شدن در نظر بگیرید)‪.‬‬
‫تمرین عملی (‪ 20 + 60‬نمره)‬
‫معرفی مسئله‬
‫بازی لولهکشی – که در لینوکس ‪ KPlumber‬و در ویندوز ‪ Linkz‬نامیده میشود – یک پازل جدولی است‪ .‬هر‬
‫خانه از جدول دارای صفر الی چهار لوله است که در چهار طرف آن قرار دارند و در وسط خانه یکدیگر را قطع‬
‫میکنند‪ .‬به یک لوله در صورتی «باز» گفته میشود که در خانهی مجاور به هیچ لولهای متصل نباشد‪ .‬برای آشنایی‬
‫بیشتر عکسهای زیر را ببینید‪:‬‬
‫شکل ‪ 1‬یک جدول ‪ 5‬در ‪ - 5‬شیری که روی یکی از خانه ها نصب شده تنها جنبه ی تزیینی دارد و نقشی در بازی ندارد!‬
‫شکل ‪ 2‬لولههای باز با دایرهی قرمز مشخص شده اند‪.‬‬
‫بازیکن میتواند در هر حرکت‪ ،‬یک خانه را ‪ 90‬درجه در جهت حرکت عقربههای ساعت بچرخاند‪ .‬هدف بازی‬
‫چرخاندن خانههای جدول به صورتی است که در نهایت هیچ لولهای باز نباشد‪.‬‬
‫شکل ‪ 3‬حالت نهاییِ شکل ‪.1‬‬
‫ثابت شده است که این بازی در حالت کلی (در صورت امکانِ وجودِ همهی انواع خانهها) ‪ NP-Complete‬است‪.‬‬
‫‪1‬‬
‫از طرفی تعداد حالتها هم در بدترین شرایط زیاد است‪ 4n( .‬که ‪ n‬تعداد خانههای جدول است‪ ).‬بنابراین در این‬
‫تمرین قصد داریم این مسئله را با الگوریتم ژنتیک و ‪ Simulated Annealing‬حل کنیم‪.‬‬
‫توضیحات کد‬
‫بخشهایی از کد که مربوط به تعریف مسئله‪ ،‬ساختن جدول و استفاده از الگوریتمهای شما برای حل مسئله است‪،‬‬
‫قبالً نوشته شده و پیادهسازی الگوریتمهای ژنتیک و ‪ SA‬برعهدهی شما گذاشته شده است‪.‬‬
‫کالسهایی که باید شما تغییر دهید‪ ،‬کالسهای ‪ Chromosome‬و ‪ GASolver‬برای الگوریتم ژنتیک و کالس‪-‬‬
‫های ‪ State‬و ‪ SASolver‬برای الگوریتم ‪ SA‬هستند‪.‬‬
‫مستندِ کد در زیر آمده است‪:‬‬
‫کالس ‪Tile‬‬
‫این کالس برای نمایش یک خانه از جدول به کار میرود‪ .‬در سازندهی کالس به صورت زیر‪:‬‬
‫)‪public Tile(boolean top, boolean bottom, boolean left, boolean right‬‬
‫هر کدام از پارامترها مشخص میکنند که در جهت گفته شده لولهای وجود دارد یا خیر‪.‬‬
‫)‪public Tile(Tile other‬‬
‫این سازنده‪ ،‬یک خانهی جدید مشابه خانهی داده شده درست میکند‪.‬‬
‫)(‪public boolean hasTop‬‬
‫)(‪public boolean hasBottom‬‬
‫)(‪public boolean hasLeft‬‬
‫)(‪public boolean hasRight‬‬
‫‪http://www.sciencedirect.com/science/article/pii/S0304397503005954‬‬
‫‪1‬‬
‫این توابع بودن یا نبودنِ لوله در جهت مشخص شده را برمیگردانند‪.‬‬
‫)(‪public void rotateClockwise‬‬
‫این تابع خانه را ‪ 90‬درجه در جهت حرکت عقربههای ساعت میچرخاند‪ .‬دقت کنید که این تابع همان ‪ Tile‬را‬
‫تغییر میدهد و شی جدیدی برنمیگرداند‪( .‬کالس ‪ Immutable ،Tile‬نیست‪).‬‬
‫)‪public int cntRotates(Tile other‬‬
‫مشخص میکند که این خانه چند بار باید با تابع قبلی بچرخد تا به وضعیت ‪ other‬برسد‪ .‬در صورتی که با‬
‫چرخیدن نتوان از این خانه به وضعیت ‪ other‬رسید‪ ،‬مقدار ‪ 4‬برگردانده میشود‪ .‬در غیر اینصورت مقادیر ‪ 0‬الی‬
‫‪ 3‬برگردانده میشوند‪( .‬این تابع‪ ،‬خانه را تغییر نمی دهد و فقط تعداد چرخشها را محاسبه میکند‪).‬‬
‫)‪public boolean isEqual(Tile other‬‬
‫یکی بودنِ این خانه با خانهی داده شده را بررسی میکند‪ .‬به جای عملگر == یا تابع ‪ equals‬از این تابع استفاده‬
‫کنید‪.‬‬
‫کالس ‪ProblemGenerator‬‬
‫این کالس برای ساختن مسئله استفاده میشود‪ .‬برای تست کردن کدتان میتوانید با استفاده از این کالس‪ ،‬مسئله‬
‫طراحی کنید‪.‬‬
‫)‪public static Tile[][] generate(int rowCnt, int colCnt‬‬
‫این تابع یک جدول تصادفیِ قابلِ حلشدن با تعداد سطر و ستون دادهشده میسازد‪.‬‬
‫)(‪public static Tile[][] myProblem‬‬
‫با تغییر این تابع میتوانید خودتان به صورت ‪ hard-code‬یک مسئله مشخص کنید‪ .‬خانههای جدول را مانند‬
‫مثال مشخص شده در کد‪ ،‬تعریف کنید‪ rowCnt .‬تعداد سطرها و ‪ colCnt‬تعداد ستونها را مشخص میکند‪.‬‬
‫در ]‪ rows[i‬خانههای سطر ‪i‬ام را مشخص کنید‪ .‬هر خانه با ‪ 0‬الی ‪ 4‬حرف از حروف ‪ t ،l ،r‬و ‪ b‬مشخص میشود‬
‫که هر کدام نشان میدهند در یک طرفِ خانه‪ ،‬لولهای وجود دارد‪ .‬به جای خانهی خالی (خانهای که لولهای ندارد)‬
‫یک حرف ‪ x‬بگذارید و خانههای هر سطر را با ‪ ,‬از یکدیگر جدا کنید‪.‬‬
‫کالس ‪Main‬‬
‫در این کالس یک نمونه تابع ‪ main‬نوشته شده که الگوریتم ‪ GA‬یا ‪ SA‬را اجرا میکند و نتیجه را چاپ میکند‪.‬‬
‫برای تغییر الگوریتم استفاده شده‪ method ،‬را در خط دوم تابع تغییر دهید‪.‬‬
‫;‪private final static int rowCount = 4‬‬
‫;‪private final static int colCount = 4‬‬
‫این دو مقدار‪ ،‬تعدادِ سطر و ستون را برای تولید مسئلهی تصادفی در ‪ ProblemGenerator‬مشخص میکنند‪.‬‬
‫;‪private final static int maxTries = 1‬‬
‫در هنگام تست میتوانید این مقدار را افزایش دهید تا در صورتی که الگوریتم به جواب نرسید‪ ،‬چند بار دیگر هم‬
‫روی مسئله اجرا شود‪.‬‬
‫)‪public static void printTable(Tile[][] table‬‬
‫این تابع جدول داده شده را چاپ میکند‪ .‬هر خانهی جدول با چهار حرفِ ‪ T ،R ،L‬و ‪ B‬مشخص میشود که هر‬
‫کدام نشان میدهند در یک طرفِ خانه‪ ،‬لولهای وجود دارد‪.‬‬
‫)‪public static void printRes(Tile[][] result, Tile[][] problem‬‬
‫این تابع‪ ،‬جدولِ ‪ problem‬و جدولِ ‪ result‬را چاپ میکند‪ .‬همچنین نشان میدهد که هر کدام از خانههای‬
‫جدولِ ‪ problem‬باید چند بار بچرخند تا به حالتِ خود در جدولِ ‪ result‬برسند‪ .‬در حالت عادی تعداد چرخشها‬
‫عددی از ‪ 0‬تا ‪ 3‬است و در صورتی که نتوان از یک خانهی ‪ problem‬به خانهی متناظر در ‪ result‬رسید‪ ،‬عدد‬
‫‪ 4‬برای آن خانه چاپ میشود‪ .‬وجود عدد ‪ 4‬نشان میدهد که در ساختنِ جدولِ ‪ result‬اشتباهی رخ داده است‪.‬‬
‫کالس ‪Chromosome‬‬
‫این کالس – که نشاندهندهی یک کروموزوم در الگوریتم ژنتیک است – را باید شما طراحی کنید و از آن در‬
‫کالسِ ‪ GASolver‬استفاده کنید‪.‬‬
‫کالس ‪State‬‬
‫این کالس – که نشاندهندهی یک حالت در ‪ Simulated Annealing‬است – را باید شما طراحی کنید و از‬
‫آن در کالسِ ‪ SASolver‬استفاده کنید‪.‬‬
‫کالس ‪GASolver‬‬
‫در این کالس قرار است الگوریتمِ ژنتیک پیادهسازی شود و در تابع ‪ main‬از آن استفاده شود‪ .‬توابع داده شده باید‬
‫طراحی شوند‪ .‬عالوه بر آنها میتوانید خودتان هم توابع و فیلدهایی در این کالس تعریف و از آنها استفاده کنید‪.‬‬
‫)‪public GASolver(Tile[][] problem‬‬
‫این تابع سازندهی کالس است و یک جدول به عنوان ورودی میگیرد‪.‬‬
‫)(‪public void runAlgorithm‬‬
‫این تابع‪ ،‬الگوریتمِ ژنتیک را روی مسالهی داده شده اجرا میکند و جدول جواب را در جایی ذخیره میکند‪.‬‬
‫)(‪public Tile[][] getResult‬‬
‫این تابع‪ ،‬در صورتی که قبالً تابع ‪ runAlgorithm‬فراخوانی شده باشد‪ ،‬حاصل آن را برمیگرداند‪.‬‬
‫)(‪public boolean isSuccessful‬‬
‫این تابع‪ ،‬در صورتی که قبالً تابع ‪ runAlgorithm‬فراخوانی شده باشد‪ ،‬نشان میدهد که آیا الگوریتم موفق به‬
‫حل مسئله شده است یا خیر‪.‬‬
‫)(‪public void initialize‬‬
‫این تابع باید طراحی شود و در ابتدای الگوریتم فراخوانی شود تا یک جمعیت اولیه ایجاد کند‪.‬‬
‫)(‪public Chromosome[] selectParents‬‬
‫کروموزومهای ‪ Parent‬را از میان جمعیت انتخاب میکند تا تولیدمثل کنند‪.‬‬
‫)‪public Chromosome reproduce(Chromosome[] parents‬‬
‫کروموزومهای ‪ Parent‬را میگیرد و فرزند (نتیجهی تولیدمثل) را برمیگرداند‪.‬‬
‫)‪public Chromosome mutate(Chromosome chrom‬‬
‫یک کروموزوم میگیرد و نسخهی جهشیافتهی آن را برمیگرداند‪.‬‬
‫کالس ‪SASolver‬‬
‫در این کالس قرار است الگوریتمِ ‪ Simulated Annealing‬پیادهسازی شود و در تابع ‪ main‬از آن استفاده‬
‫شود‪ .‬توابع داده شده باید طراحی شوند‪ .‬عالوه بر آنها میتوانید خودتان هم توابع و فیلدهایی در این کالس تعریف‬
‫و از آنها استفاده کنید‪.‬‬
‫)‪public SASolver(Tile[][] problem‬‬
‫این تابع سازندهی کالس است و یک جدول به عنوان ورودی میگیرد‪.‬‬
‫)(‪public void runAlgorithm‬‬
‫این تابع‪ ،‬الگوریتمِ ژنتیک را روی مسالهی داده شده اجرا میکند و جدول جواب را در جایی ذخیره میکند‪.‬‬
‫)(‪public Tile[][] getResult‬‬
‫این تابع‪ ،‬در صورتی که قبالً تابع ‪ runAlgorithm‬فراخوانی شده باشد‪ ،‬حاصل آن را برمیگرداند‪.‬‬
‫)(‪public boolean isSuccessful‬‬
‫این تابع‪ ،‬در صورتی که قبالً تابع ‪ runAlgorithm‬فراخوانی شده باشد‪ ،‬نشان میدهد که آیا الگوریتم موفق به‬
‫حل مسئله شده است یا خیر‪.‬‬
‫)(‪public double getTemperature‬‬
‫دمای فعلی را برمیگرداند‪.‬‬
‫)(‪public void cool‬‬
‫پس از هر ‪ iteration‬فراخوانی میشود و دما را کاهش میدهد‪ .‬به عبارتی دیگر‪ ،‬این تابع ‪Cooling Schedule‬‬
‫را مشخص میکند‪.‬‬
‫)‪public State getRandomSuccessor(State s‬‬
‫یک حالت میگیرد و یکی از حاالت مجاورش را به صورت تصادفی برمیگرداند‪.‬‬
‫نکات‬
‫‪ ‬در هنگام نمرهدهی‪ ،‬تنها فایلهای ‪ State ،GASolver ،Chromosome‬و ‪ SASolver‬از کد‬
‫شما استفاده میشوند و فایلهای دیگر مشابهِ کدِ آماده خواهند بود‪ .‬بنابراین برای پیادهسازی الگوریتمِ‬
‫خود فایلهای دیگر را تغییر ندهید‪ .‬همچنین در صورتی که برای تست‪ ،‬فایل دیگری را تغییر دادید‪،‬‬
‫در نهایت باید الگوریتم شما با فایل اولیه قابل اجرا باشد‪.‬‬
‫‪ ‬مستندی شامل توابعی که تعریف کردهاید یا تغییر دادهاید و همچنین روشِ پیادهسازی الگوریتمها و‬
‫شیوههای اتخاذ شده‪ ،‬به همراه کد بفرستید‪.‬‬
‫‪ ‬این بخش در کل‪ 20+60‬نمره دارد که ‪ 35‬نمره از آن مربوط به مستند و کدِ الگوریتم ژنتیک‪25 ،‬‬
‫نمره مربوط به مستند و کدِ الگوریتمِ ‪ Simulated Annealing‬و ‪ 20‬نمرهی دیگر مربوط به حاصلِ‬
‫اجرای کد روی مسائلِ نمونه است‪.‬‬
‫‪ ‬هرگونه سوال دربارهی تمرین را به آدرس ‪ [email protected]‬ارسال نمایید‪.‬‬
‫در صورت مشاهده هر گونه تقلب نمره تقلب کننده و گیرنده ‪ 0‬منظور شده و به استاد معرفی می شوند‪.‬‬
‫موفق باشید‬