Biologicznie motywowane metody sztucznej inteligencji Problem marszrutyzacji Paweł Rychlik Jacek Gąsiorowski Informatyka, SSI, sem. 7 Grupa GKiO1 Prowadzący: dr inż. Grzegorz Baron
1. Wstęp Problem marszrutyzacji - problem decyzyjny polegający na wyznaczeniu optymalnych tras przewozowych dla pewnej ściśle określonej ilości środków transportu, której zadaniem jest obsłużenie zbioru klientów znajdujących się w różnych punktach przy zachowaniu ograniczeń. Kryterium optymalizacji jest całkowity koszt transportu (wyrażony odległościowo, cenowo lub czasowo). Istnieją również rozwinięcia problemu uwzględniające więcej, niż jedno kryterium optymalizacji. Problem marszrutyzacji należy do podstawowej problematyki zarządzania operacyjnego flotą środków transportu (rzadziej zarządzania na wyższym szczeblu). Poniższy rysunek jest graficznym przedstawieniem rozwiązaniem problemu: 2. Problem i analiza Naszym zadaniem będzie wykonanie oprogramowania potrafiącego wyszukać możliwie najlepszego rozwiązania problemu marszrutyzacji. Danymi wejściowymi będzie zbiór punktów (miast) wraz z zaznaczonym punktem powrotu (magazynu) oraz liczba K, która odpowiada za maksymalną długość(w sensie ilości miast odwiedzanych) dla pojedynczej trasy. Ważną informacją jest, że graf złożony z miast jest grafem pełnym, czyli takim który pozwala nam połączyć każdy wierzchołek (miasto) z każdym innym. Do rozwiązania tego problemu potrzebne jest wykorzystanie metod heurystycznych dlatego zdecydowaliśmy się na wykorzystanie algorytmu genetycznego, którego poddaliśmy pewnym modyfikacjom w celu zoptymalizowania czasu wyszukiwania rozwiązania.
3. Poszczególne kroki algorytmu 3.1 Losowanie pierwszej generacji Ponieważ pierwsze próby uruchomienia algorytmu przy losowaniu populacji z całego zbioru miast dawały bardzo słabe wyniki w kryterium czasu wyszukiwania rozwiązania, postanowiliśmy zastosować optymalizację dzielenia grafu na wiele niezależnych podgrafów, w których dopiero dokonywaliśmy losowania cech poszczególnych osobników. Po przemyśleniu sposobu dzielenia grafu zdecydowaliśmy się go dzielić na grupy zawierające K wierzchołków, gdzie ostatnia grupa może posiadać mniej niż K wierzchołków. Sposób dzielenia grafu ukazuje poniższy rysunek Gdzie: Czerwony punkt magazyn Ilość miast 16 K 4 Jak łatwo zauważyć nie jest to jedyny sposób dokonania podziału na podgrafy. Dlatego postanowiliśmy równolegle dokonywać obliczeń przy zastosowaniu innych podziałów. 3.2 Selekcja Przed każdym krzyżowaniem osobników w populacji musimy dokonać wyboru, które osobniki powinny mieć największą szansę zostania rodzicem, by cechy określające największą jakość były przekazywane następnym pokoleniom. Operacja ta nazywana jest selekcją. W naszym projekcie postanowiliśmy skorzystać z metody ruletkowej przy doborze rodziców. Polega ona na wypełnieniu koła ruletki ocenami jakości wszystkich chromosomów w danej populacji. Każdy chromosom w ten sposób zajmuje część koła, która odpowiada jego jakości. Mając tak wypełnione koło ruletki dokonując losowania łatwo można zauważyć, że chromosom 1 ma największą jakość, a co za tym idzie ma największą szansę zostania rodzicem. Ponieważ w naszym przypadku jakość osobnika jednoznacznie określana jest przez długość trasy, gdzie lepszym wynikiem jest trasa krótsza byliśmy zmuszeni funkcję oceny zmodyfikować. Modyfikacja polega na wstępnym posortowaniu rosnąco populacji według długości ich tras po czym nadaniu im ocen od 1 do N, gdzie ocena 1 nadawana jest osobnikowi ostatniemu, a ocena N (równa liczebności populacji) osobnikowi pierwszemu najlepszemu. Tak nadane oceny mogą być użyte w celu dokonywania selekcji.
3.3 Krzyżowanie Zdawać by się mogło, że algorytm krzyżowania sprowadza się do przedzielenia dwóch równolicznych ścieżek w tym samym losowym kroku i zamienienia miejscami odciętych części ścieżek: Przed krzyżowaniem: Po skrzyżowaniu: A B C D E F D F A B E C ^ Losowa oś krzyżowania A B A B E C D F C D E F Jednak widać, że uzyskane w ten sposób ścieżki są niepoprawne ścieżka #1 dwukrotnie zawiera miasta A i B, tak samo ścieżka #2 zawiera podwójne miasta D i F. W związku z tym należało nieco zmodyfikować proces krzyżowania. W naszym algorytmie krzyżowane ze sobą chromosomy (ścieżki) zawsze będą miały tę samą ilość alleli (miast) dla przykładu przyjmijmy ilość P. 1. W pierwszym kroku generujemy liczbę pseudolosową R z zakresu <1, P-1>, czyli tak, aby wyeliminować krańcowe wartości - będzie to nasza oś krzyżowania. 2. Następnie bierzemy (R+1)-wsze miasto M1 ze ścieżki pierwszej oraz (R+1)-wsze miasto M2 ze ścieżki drugiej. Przechodzimy przez wszystkie miasta ścieżki pierwszej zamieniając wszystkie wystąpienia miasta M1 miastem M2, a wystąpienia miasta M2 zamieniając na M1. Analogicznie przechodzimy przez wszystkie miasta ścieżki drugiej w identyczny sposób podmieniając miasta. Przykładowo: P=6; R=2; M1=C; M2=A; (Kolor fioletowy oznacza zamienione miasta) Przed krzyżowaniem: Po zamianie M1 z M2 dla miasta R+1: A B C D E F D F A B E C ^ Oś krzyżowania R C B A D E F D F C B E A 3. Powtarzamy poprzedni krok rozpatrując następne w kolejności miasto (R+2)-gie, (R+3)-cie, dochodząc do miasta (P-1)-wszego włącznie. Teraz M1=D; M2=B; Po zamianie M1 z M2 dla miasta R+2: C D A B E F B F C D E A Teraz M1=E; M2=E; Po zamianie M1 z M2 dla miasta R+3: C D A B E F B F C D E A Teraz M1=F; M2=A; Po zamianie M1 z M2 dla miasta R+4: C D F B E A B A C D E F
W ten sposób uzyskujemy dwa poprawnie skrzyżowane ze sobą osobniki. Porównując wynik pierwszej zaproponowanej wersji krzyżowania (niepoprawnej) z powyższym wynikiem można zauważyć czasem spore rozbieżności (część wspólna zaznaczona na zielono): Krzyżowanie niepoprawne: Krzyżowanie poprawne: A B A B E C D F C D E F C D F B E A B A C D E F Jednak nasz algorytm krzyżowania gwarantuje poprawność uzyskanych chromosomów, jednocześnie jest dość prosty do zaimplementowania i szybki w działaniu. Zaimplementowaliśmy też nieco bardziej złożoną wersję krzyżowania z dwoma osiami krzyżowania. Wówczas zamianie podlegały jedynie miasta, które znalazły się pomiędzy wyznaczonymi dwoma osiami. Zazwyczaj wychodzi na to, że im proces jest prostszy, tym jest bardziej skuteczny. W tym przypadku jednak zastosowanie dwóch osi krzyżowania nieznacznie polepsza wyniki algorytmu (są to wartości rzędu kilku procent). Tak więc pozostaliśmy przy efektywniejszej implementacji z dwoma osiami krzyżowania. 3.4 Mutacja Ponieważ po wylosowaniu pierwszej generacji osobników algorytm genetyczny poprzez selekcję i krzyżowanie będzie starał się ulepszać rozwiązanie na bazie dostarczonych mu na początku osobników, może zdarzyć się sytuacja, w której algorytm utknie w lokalnym ekstremum funkcji, co zdecydowanie nie zapewnia nam otrzymania rozwiązania zbliżonego do optymalnego. Dlatego stosowana jest operacja mutacji, która ma na celu zmodyfikowanie chromosomu w sposób losowy. Wprowadzone zakłócenie pozwala na otrzymanie osobników różniących się od pozostałych, przez co algorytm będzie poszukiwał najlepszego rozwiązania w różnych obszarach funkcji. Mutacja przeprowadzana na naszych osobnikach polega na losowej zamianie miejscami alleli w obrębie jednego chromosomu. W celu optymalizacji tego procesu zdecydowaliśmy się na zezwalanie jedynie na mutacje, które poprawiają jakość rozwiązania. Jeśli dokonana mutacja pogarsza jakość osobnika, wycofujemy zmiany, których dokonała. W naszej aplikacji możemy ustalić procentowy poziom mutacji, które będą zachodzić podczas poszukiwań najlepszego rozwiązania. Jednak z racji tego, że uznajemy jedynie mutacje poprawiające rozwiązanie, efektywny procent mutacji zawsze będzie dużo niższy niż wejściowy parametr. 4. Specyfikacja zewnętrzna Program VRP Solver składa się z jednego głównego okienka podzielonego na dwie sekcje. Z lewej strony widnieje biały kwadrat, na którym graficznie przedstawiane jest położenie magazynu (czerwona kropka) i miast (czarne kropki). Panel ten pozwala dodawać nowe miasta (lewy przycisk myszy), usuwać istniejące miasta (prawy przycisk myszy; magazynu nie da się usunąć). Współrzędne poszczególnych kropek miast można odczytać przy pomocy balonika z podpowiedzią, ukazującym się ponad wskazanym miastem, jak również w dolnej belce statusu tam wyświetlane są współrzędne punktu na mapie, w jakim znajduje się kursor. Po uruchomieniu obliczeń na tym samym panelu rysowane będzie najlepsze dotychczasowe rozwiązanie problemu (Rys. 3). Panel po prawej stronie umożliwia podglądanie, jak i ustawianie parametrów pracy programu.
W pierwszej grupie kontrolek mamy informację nt. aktualnej ilości miast na mapie (magazyn też liczony jest jako miasto), tutaj też możemy ustalić parametr K, czyli długość (ilość miast, a nie maksymalna sumaryczna odległość) pojedynczej ścieżki. Program umożliwia wczytywanie listy miast z odpowiednio spreparowanego pliku przycisk Load Map, oraz wyczyszczenie całej mapy przycisk Reset. Drugi zestaw kontrolek pozwala dostosować parametry związane z funkcjonowaniem algorytmu genetycznego, tj. możemy ustalić wielkość populacji oraz procent mutacji. Opcje zaawansowane umożliwiają nam określić ilość niezależnych od siebie wątków, w których uruchamiane będą obliczenia (maksymalnie 6). Na końcu mamy ramkę z trzema polami tekstowymi, w których to zapisywane będą kolejno: długość najkrótszej znalezionej ścieżki, numer utworzonej generacji oraz czas, który upłynął od uruchomienia obliczeń. Warto podkreślić, że te trzy pola tekstowe odświeżane są jedynie, jeżeli program znalazł rozwiązanie lepsze od aktualnie najlepszego. Największy przycisk okienka Start uruchamia obliczenia. Po uruchomieniu, przycisk ten zmienia się w Stop, którym to możemy w każdej chwili zatrzymać obliczenia. Rys. 1. Wyczyszczone okno programu
Przykładowe parametry ustalone na rysunku nr 2: ilość miast N=100 (odczytane z pliku) długość ścieżki K=17 (odczytane z pliku) wielkość jednej populacji: 16 osobników procent mutacji (nieefektywny): 30% ilość wątków liczących: 1 Rys. 2. Wygląd okna po wczytaniu listy miast z pliku dyskowego.
Rys. 3. Chwilowe najlepsze rozwiązanie problemu dla N=100, K=17, osiągnięte w 41-wszej sekundzie po uruchomieniu, dokładnie w 55568 pokoleniu. Osiągnięta najkrótsza sumaryczna długość ścieżki to 5992, 822 jednostki.
Rys. 4. Proponowane rozwiązanie problemu dostawy dla 400 miast, z ograniczeniem długości ścieżki do 25 miast, odnalezione po 690 sekundach obliczeń. Jak widać na rysunku, program został uruchomiony w 6-ciu osobnych wątkach. Na mapie zawsze widzimy najlepsze znalezione rozwiązanie spośród rozwiązań generowanych przez wszystkie wątki. 5. Wnioski Napisana przez nas aplikacja pozwoliła nam poznać działanie i ideę algorytmów genetycznych. Ponieważ podczas implementacji napotykaliśmy na pewne problemy z samym działaniem algorytmu, nieocenioną pomocą okazała się graficzna reprezentacja postępów pracy algorytmu. Dało nam to możliwość określenia czy kolejne generacje dokonują optymalizacji i co najważniejsze byliśmy w stanie ocenić czy algorytm faktycznie dąży do wyników optymalnych. Przy pomocy naszego projektu niestety nie byliśmy w stanie ocenić wydajności samego algorytmu, przy takim typie zadań, poprzez porównania go z innymi metodami optymalizacyjnymi. Zauważalną cechą jest zdecydowanie fakt, jak wiele modyfikacji można dokonać w samym algorytmie w celach optymalizacyjnych bardzo zależało nam na zoptymalizowaniu algorytmu pod względem czasowym. Uważamy, że uzyskany efekt w postaci stosunku szybkości do otrzymanych wyników jest bardzo zadowalający. Źródła: Wikipedia.org Eioba.pl Obitko.com