Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
KERESŐALGORITMUSOK OBJEKTUMORIENTÁLT IMPLEMENTÁCIÓJA A MESTERSÉGES INTELLIGENCIA TÁRGY GYAKORLATI KURZUSAIN OBJECT-ORIENTED IMPLEMENTATION OF SEARCH ALGORITHMS AT THE INTRODUCTORY COURSE OF ARTIFICIAL INTELLIGENCE
Kósa Márk, Pánovics János Debreceni Egyetem, Informatikai Kar, Információ Technológia Tanszék Összefoglaló Az elmúlt években a hallgatói létszám gyors emelkedésének következtében szükségessé vált az egyetemünkön 1989 óta oktatott Mesterséges intelligencia bevezető kurzushoz kapcsolódó gyakorlatok tematikájának, követelmény¬rendszerének és számonkérési módjának az áttekintése, újragondolása. Az elmúlt öt év során sikerült kialakítani egy hatékony, a tényleges gyakorlati feladatmegoldáson alapuló számonkérési rendszert, melynek során a problémák számítógéppel támogatott dokumentálását és megoldását kérjük hallgatóinktól. Igazodva a korszerű informatika által támasztott követelményekhez, a hallgatóktól ma már valamilyen objektumorientált programozási nyelven várjuk ezeket a megoldásokat. Előadásunkban ismertetjük a kurzus gyakorlatainak oktatásával kapcsolatos tapasztalatainkat, és bemutatunk egy olyan Java osztályhierarchiát, amely megkönnyíti a tárgy előadásain ismeretett algoritmusok működésének megértését, és segíti hallgatóink vizsgára történő felkészülését. Az osztályhierarchia két fő részből áll: az állapottér-reprezentáció komponenseinek absztrakt elemeiből, valamint a reprezentációs gráfok csúcsainak reprezentációjából és a keresőalgoritmusok vezérlőinek implementációjából.
Kulcsszavak Mesterséges intelligencia, programozás, osztálydiagram.
állapottér-reprezentáció,
keresőalgoritmusok,
objektumorientált
Abstract Due to an increase in the number of students of the last few years, it became necessary to review the topics, requirements and the way of examination in the practical lessons of the introductory course of Artificial Intelligence at the University of Debrecen. In the last five years, we managed to create an efficient examination system that is based on actual practical problem solving, i.e. documenting and solving problems using computers. In accordance with the demands of modern informatics, we require students to make these solutions using an object-oriented programming language. In this paper we present a possible object-oriented approach to implement search algorithms discussed at the seminars of the Artificial Intelligence course. It is about a Java class hierarchy which makes it easier to understand the operation of the algorithms described at the lectures of this subject, and helps our students prepare for their exams. This class hierarchy consists of two main parts: the abstract elements of the state space representation components, and the representation of nodes in the representation graphs together with the implementation of search strategies of the different algorithms.
Keywords Artificial intelligence, state space representation, search algorithms, object-oriented programming, class diagram.
1
Informatika a felsőoktatásban 2008
1.
Debrecen, 2008. augusztus 27-29.
Bevezetés
Az elmúlt években a hallgatói létszám gyors emelkedésének következtében szükségessé vált az egyetemünkön 1989 óta oktatott Mesterséges intelligencia bevezető kurzushoz kapcsolódó gyakorlatok tematikájának, követelmény¬rendszerének és számonkérési módjának az áttekintése, újragondolása. Előadásunkban ismertetjük a kurzus gyakorlatainak oktatásával kapcsolatos tapasztalatainkat. Az elmúlt öt év során sikerült kialakítani egy hatékony, a tényleges gyakorlati feladatmegoldáson alapuló számonkérési rendszert, melynek során a problémák számítógéppel támogatott dokumentálását és megoldását kérjük hallgatóinktól. Igazodva a korszerű informatika által támasztott követelményekhez, a hallgatóktól ma már valamilyen objektumorientált programozási nyelven várjuk ezeket a megoldásokat. A Mesterséges intelligencia bevezető kurzusa egyetemünkön három nagyobb témakört ölel föl:
problémák állapottér-reprezentációja, megoldáskeresés állapottérgráfokban,
problémaredukciós reprezentációs technika, megoldáskeresés hipergráfokban,
kétszemélyes, zérusösszegű, véges, determinisztikus, teljes információjú játékok elmélete.
A gyakorlati kurzusokon e témakörökhöz kapcsolódóan a hallgatóknak 4–5 Java nyelven elkészített programot kell bemutatniuk a félév során. 1.1.
A gyakorlati foglalkozások
A szorgalmi időszak 14 gyakorlati foglalkozásából általában 10–11 alkalommal a problémák állapottér-reprezentációjával és az állapottérgráfokban történő megoldáskereséssel foglalkozunk. Ezeken a gyakorlatokon egy konkrét problémát elemzünk, és azon keresztül mutatjuk be a különböző megoldáskeresési stratégiákat. Első lépésként reprezentáljuk, azaz valamilyen matematikai modellben (általában elsőrendű logikai nyelv segítségével) formalizáljuk a problémát. Ezután egymás után implementáljuk az előadáson tárgyalt megoldáskereső algoritmusokat, így a nem módosítható keresőket, a visszalépéses keresőalgoritmusok különböző fajtáit, valamint a keresőgráffal kereső szisztematikus (szélességi, mélységi, optimális) és heurisztikus (best-first, A-algoritmuscsalád) algoritmusokat. Az elkészített programok mindegyikét teszteljük is, a konkrét problémán szemléltetve működésüket. Hallgatóinknak a félév során egy önállóan választott feladatot kell állapottérreprezentálniuk és megoldaniuk az ismertetett algoritmusokkal. A gyakorlati aláírás feltétele, hogy az elkészült reprezentációt és programokat a gyakorlatvezetőknek bemutassák, és a felmerülő kérdésekre válaszoljanak. A gyakorlatot sikeresen teljesítő hallgatók csak akkor vizsgázhatnak a tárgyból, ha a házi feladatként beadott programokon túl ellenőrzött körülmények között számítógépes laborjainkban megadott idő alatt elkészítenek egy adott állapottér-reprezentációhoz tartozó valamilyen (előre meghatározott) megoldáskereső programot.
2
Informatika a felsőoktatásban 2008
2.
Debrecen, 2008. augusztus 27-29.
Az osztályhierarchiák
Az állapottérgráfokban történő megoldáskereséshez az elmúlt időszakban kifejlesztettünk két olyan Java csomagot, amelyek ügyesen felparaméterezve lehetőséget biztosítanak tetszőleges probléma bármely kívánt algoritmussal történő megoldására. A házi feladatként és a vizsga előfeltételeként megírandó programok elkészítése ezek után nem jelent mást, mint a gyakorlatokon ismertetett algoritmusok otthoni implementálását, és alkalmazásukat a választott problémára. A következőkben bemutatjuk a gyakorlatainkon használt osztályhierarchiát. Az általunk javasolt két Java csomag egyike az állapottér-reprezentációval, a másik pedig a megoldáskereső algoritmusokkal kapcsolatos osztályokat tartalmazza (1. ábra).
1. ábra – A csomagstruktúra
2.1.
Az állapottér-reprezentáció csomagja
Ebben a csomagban két osztályt találunk (2. ábra). Az Operator osztály az egyes problémákhoz tartozó operátorok, míg az Allapot osztály a problémákhoz tartozó állapotok absztrakt ősosztálya. Mivel egy állapot jellemzői mindig a konkrét problémától függnek, ezért ez utóbbi osztályban csak egyetlen adattagot definiáltunk, amely nem más, mint a probléma állapotaira alkalmazható összes operátor halmaza. Természetesen – függetlenül a problémától – minden állapotnak meg kell tudnia mondani magáról, hogy célállapot-e, hogy alkalmazhatóe rá egy adott operátor, illetve hogy egy operátor alkalmazásával milyen új állapot jön létre belőle. A heurisztikus keresők olyan állapotokat használnak, amelyek a fentebb felsorolt jellemzőkön kívül még egy heurisztikaértéket is tartalmaznak. Ehhez nyújt segítséget a HeurisztikusAllapot interfész azáltal, hogy az ezt megvalósító állapotok rendelkezni fognak egy heurisztikus értéket szolgáltató módszerrel. Ehhez hasonlóan a KoltsegesOperator
3
Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
interfészt azok az operátorok fogják implementálni, amelyeket az operátorok költségét figyelembe vevő keresőalgoritmusok használnak.
2. ábra – Az állapottér-reprezentáció osztálydiagramja
2.2.
A megoldáskereső algoritmusok csomagja
A megoldáskereső algoritmusok csomagjában lévő osztályok két különálló hierarchiába rendeződnek. Az egyik (3. ábra) az állapottérgráfok csúcsainak, a másik (4. ábra) a különböző keresőalgoritmusoknak a modellezésére szolgál.
3. ábra – Az állapottérgráf-csúcsok osztálydiagramja
A csúcsokra vonatkozó csaknem minden információ a különböző csúcstípusok közös ősosztályában, a Csucs osztályban található. Itt tároljuk a csúcs által szemléltetett állapotot, a csúcsnak a startcsúcstól mért távolságát (mélységét), a szülő csúcsát, illetve azt az operátort, amellyel a szülőjében tárolt állapotból az adott csúcsban tárolt állapotot előállítottuk. A Csucs
4
Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
osztály leszármazottai ezeken az attribútumokon túl a konkrét keresőalgoritmusok által igényelt további adattagokat tartalmaznak.
4. ábra – A keresőalgoritmusok osztálydiagramja
A keresőalgoritmusok ősosztálya az absztrakt Kereso osztály, amely éppen a legfontosabb metódusát nem implementálja, nevezetesen azt, hogy milyen stratégiával kell működnie a megoldáskeresés vezérlőjének. Ennek a metódusnak a kódját a leszármazott osztályok tartalmazzák majd. Ugyanakkor lehetőséget biztosít arra, hogy tároljuk a terminális csúcsokat, kiírjuk a megoldásokat, illetve hogy beállítsuk az egyes keresők algoritmustól független jellemzőit. A BacktrackKereso osztály új jellemzői között találjuk az aktuális utat, valamint a körfigyelés és az úthosszkorlát opcionális lehetőségét. Az AgEsKorlatKereso osztály annyiban tér el ettől, hogy az úthosszkorlát helyett költségkorláttal dolgozik, amely itt nem opció, hanem az algoritmus szerves részét képezi. A KeresografosKereso osztály a kereső adatbázisában tárolt csúcsok nyilvántartásához két listát használ. Ezen osztály leszármazottai (a konkrét gráfkereső algoritmusok) egyrészt a keresési stratégiában, másrészt pedig az adatbázisukban tárolt csúcsok osztályában térnek el egymástól. 2.3.
Egy konkrét példa: Hanoi tornyai
Lássuk ezek után, hogy hogyan lehet felhasználni a bemutatott csomagokat konkrét feladatok megoldására. Megoldandó feladatnak válasszuk a mindenki által jól ismert „Hanoi tornyai” problémát. Az alábbiakban definiáljuk a feladatot, és megadjuk az állapottér-
5
Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
reprezentációjának leglényegesebb elemeit. Megjegyezzük azonban, hogy a megoldáskeresés szempontjából a feladat ismerete másodlagos, mivel a kódok elkészítéséhez elegendő a feladat állapottér-reprezentációja. A legenda szerint egy szerzetesek lakta távol-keleti kolostor udvarán áll három rúd, amelyeken 64 különböző átmérőjű aranykorong található. Eredetileg mind a 64 korong egyetlen rúdra volt rárakva úgy, hogy minden korong alatt egy nála nagyobb volt. A szerzeteseknek az a céljuk, hogy mind a 64 korongot áthelyezzék az első rúdról a harmadik rúdra, naponta mindig csak egy korongot mozgatva úgy, hogy sohase rakjanak egy korongot nála kisebbre. Amint az összes korongot átpakolják a harmadik rúdra, eljön majd az általuk várva várt világvége. Leegyszerűsített állapottér-reprezentációnkban legyen N = 3 a korongok száma, jelöljük a három rudat sorrendben A, B és C betűkkel, a korongokat pedig számozzuk 1-től N-ig, átmérőik szerint növekvő sorrendben. Tekintsük a probléma jellemző tulajdonságának azt, hogy melyik korong melyik rúdon található. Mivel minden korong elvileg előfordulhat bármely rúdon, ezért a korongok mindegyikéhez azonos alaphalmazokat rendelhetünk: H 1 = H 2 = … = H N = {A, B, C} A probléma világának állapotai elemei ezen alaphalmazok Descartes-szorzatának elemei lesznek: A = H1 H2 … HN Mivel a kiinduló helyzetben minden korong az első, A-val jelölt rúdon található, a problémának a kezdő = (A, A, A) A állapot lesz a feladatban meghatározott kezdállapota. A célállapotok halmazát egyetlen elem alkotja: az, amely azt a helyzetet írja le, amikor az összes korong a harmadik, C-vel jelölt rúdon található: C = {(C, C, C)} A Operátorunk a Mozgat(mit, hova) kétparaméteres operátor lesz, ahol a mit egy korongot, a hova pedig egy rudat jelöl. A mozgatás akkor hajtható végre, ha
a mit korong nincs a hova rúdon;
a mit korong a legkisebb a saját rúdján;
a hova rúd vagy üres, vagy nincs rajta a mit korongnál kisebb korong.
Az operátor alkalmazásának hatására a mit korong pozíciója megváltozik: a hova rúdra kerül. A feladat implementációját az operátor leprogramozásával érdemes kezdeni. Ehhez származtatunk az absztrakt Operator osztályból egy HanoiMozgat nevű konkrét osztályt, amelynek két adattagja a Mozgat(mit, hova) operátor két paramétere lesz. Ha olyan keresőt szeretnénk használni, amelyben az operátorok alkalmazása nem konstans költségű, akkor a HanoiMozgat osztálynak implementálnia kell a KoltsegesOperator interfészt, azaz meg kell adnunk a koltseg() metódus törzsét is. Ezután rátérhetünk az állapotteret leíró osztály elkészítésére. Ebben az osztályban először is az állapotok komponenseinek megfelelő adattagokat kell megadnunk. Jelen esetben ez az N értéket és a korong nevű N elemű tömböt jelenti. A korong tömb elemei az A, B vagy C karakterek lehetnek. Ezeket felhasználva már csak az Allapot osztályból örökölt absztrakt metódusokat kell implementálnunk a reprezentációnak megfelelően. A kezdőállapotot a
6
Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
HanoiAllapot osztály paraméter nélküli konstruktorával hozzuk létre. Ha olyan keresőt szeretnénk használni, amely valamilyen reprezentáción kívüli plusz információt, heurisztikát használ a megoldás kereséséhez, akkor a HanoiAllapot osztálynak implementálnia kell a HeurisztikusAllapot interfészt, azaz meg kell adnunk a heurisztika() metódus törzsét is. Ezeknek a kódoknak az elkészítése minimális programozói ismeretekkel is gyorsan megoldható, mindössze a reprezentációban megfogalmazott formulákat kell átültetni Java nyelvű kódra. A probléma osztálydiagramja az 5. ábrán látható.
5. ábra – A Hanoi tornyai probléma osztálydiagramja
package hanoi; import kereso.*; import kereso.keresografos.szisztematikus.MelysegiKereso; public class HanoiMain { public static void main( String[] args ) { Kereso kereso = new MelysegiKereso( new HanoiAllapot(), MelysegiKereso.OSSZES_MEGOLDAS ); System.out.println( kereso ); kereso.keres(); for ( Csucs cs : kereso.getTerminalisok() ) { System.out.println( "Egy megoldás:" ); kereso.kiirMegoldas( cs ); } System.out.println( "Megoldások száma: " + kereso.getTerminalisok().size() ); } }
6. ábra – A főprogram egy lehetséges megvalósítása
Utolsó teendőnk a keresőalgoritmus kiválasztása és a főprogram megírása. A főprogramban példányosítanunk kell a megfelelő keresőalgoritmus osztályát, amelynek paraméterként átadjuk a megoldandó probléma kezdőállapotát és a keresés jellemzőit, majd
7
Informatika a felsőoktatásban 2008
Debrecen, 2008. augusztus 27-29.
meg kell hívnunk a keresés vezérlését megvalósító keres() metódust. A keresés befejeződése után megjeleníthetők a megoldások. A 6. ábrán látható a HanoiMain osztály kódja, amely a Hanoi tornyai problémát mélységi keresővel oldja meg. Hasonlóan egyszerű a többi keresőalgoritmus használata is: a MelysegiKereso helyett a kívánt keresőalgoritmus osztályát kell példányosítani. 3.
Oktatási tapasztalatok
Az elmúlt félévek során A mesterséges intelligencia alapjai című tárgy keretében hallgatóinknak különböző problémák állapottér-reprezentációját kellett elkészíteniük, majd az itt bemutatott osztályhierarchiákat és kódokat felhasználva implementálni azt. Tapasztalataink alapján elondhatjuk, hogy az itt bemutatott csomagok, osztályok és forráskódok nagy segítséget nyújtottak egyrészt az órák tervezésében, másrészt a tárgy előadásain ismertetett algoritmusok elsajátításában, legfőképpen azon hallgatók számára, akik rendelkeztek a szükséges elméleti háttérrel (logikai és programozási alapismeretekkel). Ezek a hallgatók önállóan is sokat kísérleteztek a kódok bővítésével és javításával, eredményeiket felhasználva a jövőben tovább tudjuk emelni a gyakorlati foglalkozásaink színvonalát.
8