ESI 11 - Instytut Sterowania i Systemów Informatycznych

Transkrypt

ESI 11 - Instytut Sterowania i Systemów Informatycznych
Uniwersytet Zielonogórski
Wydział Elektrotechniki, Informatyki i
Telekomunikacji
Instytut Sterowania i Systemów Informatycznych
ELEMENTY SZTUCZNEJ INTELIGENCJI
Laboratorium nr 11
PRZESZUKIWANIE GRAFÓW Z WYKORZYSTANIEM METODY A*
Prowadzący: …………………………………………………..
Zakres ćwiczeń:
1. Idea metody przeszukiwania A*
2. Implementacja metody przeszukiwania A*
3. Złożoność obliczeniowa metody przeszukiwania A*
Wstęp teoretyczny
Zadaniem strategii A* podobnie jak w przypadku przeszukiwania wszerz i w głąb jest
wyznaczenie drogi do węzła docelowego. Aby przyspieszyć proces poszukiwań wykorzystuje
się pewną wiedzę heurystyczną specyficzną dla danego rozwiązywanego problemu, którą
wprowadza się do algorytmu w postaci funkcji oceniającej węzły. Funkcja oceniająca f(n) w
strategii A* jest sumą dwóch składników:
f(n)=h(n)+g(n)
Wyrażenie to oznacza, że dla danego węzła n jest wyznaczana najpierw w sposób
heurystyczny estymacja h(n) kosztu drogi łączącej węzeł n z węzłem celu. Następnie
wyznacza się dla węzła n dokładny koszt drogi łączącej węzeł początkowy p z węzłem n, co
reprezentuje składnik g(n). Biorąc pod uwagę powyższe fakty należy stwierdzić, że funkcja
oceniająca f(n) jest przybliżonym kosztem ścieżki od węzła początkowego do rozwiązania
poprzez aktualnie analizowany węzeł n. Algorytm A* pozwala znajdować optymalne ścieżki
prowadzące do rozwiązań jeżeli funkcja heurystyczna h(n) nie zawyża kosztu dotarcia do
celu w stosunku do rzeczywistego kosztu h’(n).
h’(n)≥ h(n)
Heurystykę, która spełnia powyższy warunek nazywamy heurystyką dopuszczalną. Niestety
jeżeli w grafie występują cykle, które są efektem powtarzających się stanów, algorytm A* nie
jest kompletny ponieważ może utkać w cyklach co nie pozwoli mu dotrzeć do celu.
Rozwiązaniem powyższego problemu jest sprawdzanie powtarzających się stanów i nie
rozwijanie węzłów, które wcześniej były już rozwijane. Prowadzi to jednak do utraty
właściwości optymalności. Problem ten można przezwyciężyć konstruując odpowiednio
funkcję heurystyczną tak aby wartość funkcji oceniającej była niemalejąca wzdłuż wszystkich
możliwych ścieżek. W takiej sytuacji algorytm A* nie utyka w cyklach (nie ma potrzeby
sprawdzania powtarzających się stanów) i jednocześnie pozwala znajdować optymalne
ścieżki do węzłów docelowych.
Kluczem do sukcesu w przypadku algorytmu A* jest zaprojektowanie odpowiedniej funkcji
heurystycznej h(n). Niestety nie istnieje szczegółowe rozwiązanie, pozwalające wyznaczać w
ten sam sposób funkcje heurystyczne dla różnych problemów. Każdy problem wymaga
indywidualnego podejścia co niewątpliwie utrudnia implementację niniejszego algorytmu.
Można jednakże sformułować ogólne podejście, które powinno być stosowane do
konstrukcji funkcji heurystycznej. Metoda ta polega na uproszczeniu zadania (łamane są
niektóre zasady, ograniczenia problemu, np. w przypadku układania puzzli dopuszcza się
wyjmowanie klocków i przenoszenie w inne miejsce) do tego stopnia, by w nowym
uproszczonym zadaniu koszt wyznaczenia rozwiązania był niewielki. Dzięki uproszczeniu
zadania jego rozwiązanie nie nastręcza problemu a koszt wykonania algorytmu dla takiego
zadania uproszczonego jest szukanym oszacowaniem heurystycznym dla zadania
oryginalnego. Im więcej zasad dotyczących oryginalnego problemu zostanie złamanych tym
łatwiej (z mniejszym kosztem obliczeniowym) dla każdego węzła będzie można wyznaczyć
wartość funkcji heurystycznej. Jednakże spowoduje to, że estymaty kosztów będą znacznie
różniły się od rzeczywistych kosztów jakie należy ponieść aby dotrzeć z bieżącego węzła do
węzła docelowego. Dlatego należy dążyć do pewnego kompromisu, w którym koszt
obliczeniowy wyznaczenia wartości funkcji heurystycznej dla pojedynczego węzła nie
powinien być zbyt duży a jednocześnie estymata kosztów nie powinna silnie różnić się od
rzeczywistych kosztów dotarcia do celu. Przykład konstruowania funkcji heurystycznej dla
problemu układania puzzli zaprezentowano w punkcie 3.
Implementacja strategii A* wymaga zdefiniowania dwóch list open oraz closed, na których
przechowywane są węzły drzewa. Na liście open przechowywane są węzły będące krawędzią
drzewa a na liście closed węzły, które były już wcześniej przeglądane, z każdym węzłem
skojarzona jest wartość funkcji oceniającej. W kolejnych krokach wybierany jest węzeł z listy
open, który charakteryzuje się najmniejszą wartością funkcji f(n) (lista open może być
posortowana względem wartości funkcji oceniającej). Dla wybranego węzła stosowna jest
ogólna procedura tzn. wybrany węzeł testowany jest czy przechowuje stan docelowy, jeśli
tak to koniec poszukiwań a jeśli nie to generowane są stany potomne, które są oceniane a
następnie dopisywane do listy open a węzeł macierzysty przenoszony jest na listę closed.
Prześledźmy zachowanie się algorytmu oraz zawartości list open oraz closed w kolejnych
krokach dla przykładowego drzewa (Rys. 1). Inicjalizacja algorytmu wymaga umieszczenia
węzła korzenia na liście open. Każdy węzeł przechowywany na listach powinien zawierać
dowiązanie do swojego rodzica tak aby po znalezieniu stanu docelowego możliwe było
odtworzyć ścieżkę będącą rozwiązaniem problemu.
Rys. 1. Przeszukiwanie A* (liczby wewnątrz węzłów określają kolejność przeglądania
węzłów a liczby ponad węzłami określają wartość funkcji oceniającej, węzeł G
przechowuje stan docelowy)
Kolejne stany list open i closed dla kolejnych kroków algorytmu (w nawiasach podawane są
węzły macierzyste, lista open i jest posortowana względem wartości funkcji oceniającej):
a) Inicjalizacja:
open=A(-)
closed= pusta
b) Rozwinięcie węzła A:
open=B(A),D(A),C(A)
closed=A(-)
c) Rozwinięcie węzła B:
open= E(B),D(A),C(A),F(B)
closed=A(-),B(A)
d) Rozwinięcie węzła E:
open= D(A),C(A),F(B)
closed=A(-),B(A),E(B)
e) Rozwinięcie węzła D:
open=C(A),J(D),F(B),I(D)
closed= A(-),B(A),E(B),D(A)
f) Rozwinięcie węzła C:
open= G(C),J(D),H(C),F(B),I(D)
closed= A(-),B(A),E(B),D(A),C(A)
g) Rozwinięcie węzła G (znaleziono cel):
open=J(D),H(C), F(B),I(D)
closed= A(-),B(A),E(B),D(A),C(A),G(C)
Po znalezieniu węzła docelowego następuje odtworzenie ścieżki, która doprowadziła do
rozwiązania na podstawie listy closed oraz informacji o rodzicach węzłów. Złożoność
czasowa jak również pamięciowa algorytmu A* jest wykładnicza, wszystkie przeglądane
węzły musza znajdować się w pamięci.
Przykładowe heurystyki dla 8-elementowych puzzli
Zadanie ułożenia puzzli sprowadza się do wykonywania dozwolonych ruchów za pomocą
poszczególnych elementów puzzli tak aby osiągnąć zadany stan docelowy (rys. 2b). Stan
początkowy może być generowany losowo (rys 2a).
Rys 2. Stan początkowy a) i stan docelowy b)
Zadanie wyznaczenia heurystyki sprowadza się do osłabienia zasad gry w puzzle. W tym
przypadku zasady można określić poprzez możliwe ruchu jakie można wykonać podczas
układania puzzli. Dozwolone ruchy to ruchy puzzli tylko przy użyciu pustej przestrzeni
pomiędzy puzzlami, nie wolno wyrywać puzzli i przenosić ich na inne pola oraz nie wolno
przesuwać puzzli ponad innymi puzzlami. Wyznaczmy jedną z możliwych heurystyk h1(n)
poprzez osłabienie ograniczeń gry w puzzle polegającą na umożliwieniu wyrywania puzzli i
przenoszeniu ich na dowolne pozycje w układance. W takiej sytuacji w bardzo prosty sposób
można ocenić ile ruchów należy wykonać z bieżącego stanu aby dotrzeć do stanu
docelowego, wystarczy policzyć ile puzzli nie znajduje się na swoich właściwych pozycjach.
Dla stanu przedstawionego na rys. 2a wartość funkcji heurystycznej h1(n)=7. Przykładem
funkcji heurystycznej w przypadku której złamano zasady gry w puzzle w mniejszym stopniu
może być funkcja h2(n) przy wyznaczaniu, której pozwolono jedynie na przesuwanie puzzli
ponad zajętymi polami ale nie pozwolono na wyrywanie puzzli. Wartość funkcji h2(n)
wyznacza się poprze zsumowanie liczby ruchów jakie należy wykonać aby puzzle znalazły się
na swoich miejscach h2(n)=2+0+3+1+0+1+3+4=14. Można stwierdzić, że heurystyka h2(n)
dominuje nad heurystyką h1(n) ( h2(n)≥ h1(n) ) ponieważ estymuje koszty dotarcia do celu
dokładniej. Jednakże należy zauważyć, że koszt obliczeniowy wyznaczenia heurystyki h2(n)
jest większy niż koszt obliczeniowy określenia heurystyki h1(n). Aby określić wartość funkcji
oceniającej f(n), konieczne jest również zdefiniowanie funkcji g(n), która określa koszt
dotarcia z węzła startowego do węzła bieżącego. Wartość tej funkcji można wyznaczyć
dokładnie a w przypadku puzzli określa się ją poprzez określenie poziomu drzewa, na którym
znajduje się badany węzeł.
Zadania:
1. Utwórz program do gry w puzzle gdzie decyzję o kolejnych ruchach będzie
podejmował komputer wykorzystując strategię przeszukiwania A*. Na wstępie
program powinien wylosować stan startowy a następnie po wyznaczeniu stanu
końcowego przedstawić sekwencje ruchów prowadzącą do stanu ułożenia.
2. Porównaj wyniki osiągnięte dla problemu układania puzli z wykorzystaniem strategii
wszerz, w głąb i A*.
Literatura:
1. Rutkowska D.,Piliński M., Rutkowski L.: Sieci neuronowe. Algorytmy genetyczne i
systemy rozmyte, PWN, Warszawa, 1997.
2. Mulawka J. J. Systemy ekspertowe, WNT, Warszawa 1996.
3. Brandys Cz, Fujarewicz K, Gałuszka A., Simek K., Świrniak K., Wojciechowski K. :
Metody sztucznej Inteligencji – Laboratorium, Wydawnictwo Politechniki Ślaskiej,
Gliwice 1998.
4. Rich E.: Artificial intelligence. McGraw-Hill, New York 1983.
5. http://aima.cs.berkeley.edu/