Pierwotnie rozwiązywałem w ten sposób problem obliczania minimum funkcji, ale wychodziły tam strasznie duże wartości liczbowe, które trudno się debugowało, gdyż za wiele nie mówiły o rozwiązaniu. Przeszedłem więc na rzecz bardziej teoretyczną: generujemy populację losowych ciągów znaków i za pomocą ewolucji próbujemy doprowadzić je do jakiegoś konkretnego słowa. Rzecz miła i przyjemna dla oka.
Na tym problemie przetestowałem jakość kombinacji różnych metod selekcji i krzyżowania. Zdecydowanie najgorzej wypada selekcja metodą ruletki, mająca poważne problemy z wyprodukowaniem nawet przybliżonego rozwiązania. Selekcja rankingowa sprawdza się znacznie lepiej, generując rozwiązanie bardzo bliskie prawdy (z 14 nie zgadzała się średnio jedna, dwie litery). Wtedy jednak, ze względu na wybór przez cały czas wyłącznie najlepszych globalnie osobników, algorytm przedwcześnie osiąga zbieżność, a populacja traci różnorodność genetyczną. Wtedy nadzieja pozostaje w mutacjach. Selekcja turniejowa, która dzieli populację na grupy i do rozrodu wybiera najlepszego osobnika z każdej grupy, niweluje tę wadę. Chociaż do zbioru rozwiązań mogą dostać się osobniki globalnie słabe, ogólnie rzecz biorąc, jakość populacji cały czas się polepsza (bezwzględnie najgorsze sztuki odpadają w turnieju), nie zatracając w aż takim stopniu różnorodności. Wtedy bez trudu już po 13 pokoleniach algorytm dochodzi do właściwego wyniku.
Szczegółowy opis algorytmu ewolucyjnego (wraz z pełnym kodem źródłowym w C++) znajdzie się na Zyxist.com za tydzień. Będzie on rozwinięciem skryptu do wykładu przygotowywanego na warsztaty, o których niedawno pisałem. W przypisach podałem tymczasem kilka przydatnych adresów w polskim Internecie traktujących o zagadnieniu.





