- Hill Climbing With Random Restarts (Shotgun hill climbing)
- Local Search (own modification)
- Tabu Seach
- tabu list
- Simulated Annealing
- temperature
- accept worse
- Particle Swarm
- velocity vector
- does not select parents
- Genetic Alghorithm
- selection
- mutation
- crossover
- reproduction
- generation improvement
- Losowane jest inicjalne rozwiązanie z hiperkostki n^4 na przedziale (-5,5)
- Dopóki mamy czas global_time:
- Losujemy przedział czasowy ( mniejszy niż odgórne t) local_time:
- Dopóki mamy czas local_time:
- Generujemy sąsiada zaburzując wektor x o zmienną losową z przedziału (-1,1)^4
- Badamy jakość sąsiada jęsli jest lepsza to przechodzimy do niego, jeśli nie zostajemy przy S.
- Porównujemy besta z lokalnym wynikiem i losujemy zupełnie nowy start ( random restart)
- Losowane jest inicjalne rozwiązanie z hiperkostki n^4 na przedziale (-5,5)
- Dopóki mamy czas t:
- generujemy n sąsiadów bieżącego rozwiązania zaburzując wektor x o zmienną losową z przedziału (-1,1)^4 n razy
- wybieramy minimalnego pod względem quality function sąsiada i do niego przechodzimy.
- jeśli utknęliśmy w lokalnym optimum- random restart
- Znajdź rozwiązanie inicjalne - algorytm zachłanny :
- wchodzi w kolejne miasta biorąc minimalne dystanse
- Dopóki jest czas:
- sprawdź długość Tabu, jeśli jest zbyt duże pozbądź się najstarszych ścieżek.
- Wybierz sąsiada R - transpozycja dowolnych dwóch miast
- Tweak n razy:
- wybierz sąsiada W rozwiązania R - transpozycja.
- Wybierz najlepszego z n x W u R
- Dołącz najlepszego z nich do Tabu List.
- Porównaj besty.
- Jeśli dopusczone są resety to co m- iterację wróć do najlepsego miasta.
- Jeśli dopusczone są teleportację co k- iterację zacznij poszukiwania od nowo wylosowanego miasta.
- Znajdź rozwiązanie inicjalne - algorytm zachłanny :
- wchodzi w kolejne miasta biorąc minimalne dystanse
- Dopóki jest czas:
- Stwórz wszystkie kombinacje ścieżek bazujące tylko na transpozycjach.
- Wybierz z nich najlepszego
- Dodaj najlepszego do tabu
- Porównaj z bestem.
- Generujemy rozwiązanie początkowe:
- agent dochodzi do górnej ściany, a później podąża za ścianą dopóki nie napotka wyjścia.
- Dopóki jest czas:
- Sprawdzaj rozmiar tabu list i wyrzucaj najstrasze ścieżki
- Wybierz losową transpozycję R rozwiązania S i usuwamy punkty stałe
- Tweak n razy:
- Wybierz najlepszego z wszystkich tweaków W( transpozycje na R) i usuwamy punkty stałe
- jeśli rozwiązanie nowe W nie jest w tabu i jest lepsze od R to przechodzimy do niego
- jeśli rozwiązanie nie jest w tabu to dołączamy go
- sprawdzamy poprawność rozwiązania.
- Generujemy rozwiązanie początkowe:
- agent dochodzi do górnej ściany, a później podąża za ścianą dopóki nie napotka wyjścia.
- Dopóki jest czas:
- Losujemy wszystkie transpzycje scieżki i usuwamy punkty stałe
- prawdzamy poprawność ścieżki i wybieramy minimalną z nich
- Porównujemy z bestem
- Dołączamy do Tabu
- Temperatura początkowa zostaje zainicjowana na wysoką wartość np.: 100, 1000, 10000
- Program działa w pętli dopóki nie przekroczy limitu czasowego, lub T osiąggnie wartość 0.
- Wyliczamy wartość funkcji Salomon'a ( quality function) na podstawie rozwiązania początkowego i zapisujemy do "historii best'ów".
- Generujemy sąsiada neighbour aktualnego rozwiązania x.( możemy zaburzać względem wiekości wektora np x_i = x_i*(1+random.uniform(-e,e)) lub statycznie x_i = x_i + random.uniform(k,k)) ( w moim przypadku robię to naprzemiennie, wtedy wiem, że ze przy skalowaniu nie utknę w 0^4)
- Wyznaczamy wartości funkcji Salomon'a dla neighbour oraz x, wyznaczamy deltę( róznicę między tymi wartościami.)
- Losujemy liczbę zmiennoprzecinkową z przedziału (0,1)
- Obliczamy probability z wzoru podanego na wykładzie p=e^{\frac{-delta}{T}}
- Jeśli wylosowana wartość(0,1) jest mniejsza od wyliczonej probability to przechodzimy do sąsiada tzn, ustalamy x = neighbour.
- Zmniejszamy T( temperaturę ) w określony sposób ( jeden z wykładów np T_{i+1}= T_i/log(i))
- Sprawdzamy czy aktualna wartość jest lepsza od najlepszej dotychczas znalezionej best, jeśli tak dodajemy do historii.
- Wracamy do 3.
-
Funkcja Kosztu: Funkcja Salamon'a.
-
Sąsiedztwo: Naprzemienne zaburzenia wektora V^4 względem jego samego(losowe odchylenia) lub skalowanie.
W programie została zaimplementowana również możliwość reset'ów. Tzn jeśli wpadniemy w lokalne minimum lub wpadniemy po prostu na "złą trasę" to restartujemy, tzn cofnięcia się do naszego dotychczas najlepszego rozwiązania i wylosowanie nowego sąsiada, wtedy być może pójdźiemy w innym kierunku niż ostatnio i uciekniemy w taki sposób z minimum lokalnego. Ewentualnie można też zrobić losowy spawn na określonym przedziale np(-10,10)(chyba), ale wydaje się to mniej ciekawe. Została też zaimplementowana możliwość rysowania wykresów funkcji kosztu , czy nawet zmian samych współrzędnych wektora.( graphs = True w mainie aby wyświetlić)
- Określamy czas zakończenia.
- Nakładamy abstrakcyjną siatkę, tworząc po tym rozwiązanie inicjalne.
- Dzielimy taką siatką macierz na bloki k+1 x k+1 elementowe, lub większe.
- Czemu nie kxk? Bo wtedy mamy większą swobodę ruchu, lepszy wybór sąsiada, bardziej swobodny.
- Inicjujemy nasze najlepsze wyniki jako w listach.
- Dopóki temperatura jest większa od zera i nie skończył się czas.
- Wylosuj sąsiada. W jaki sposób jest losowany?
- Zmieniamy kolor losowego bloku na losowy.
- Losowo wyznaczmy blok, który będziemy poszerzać kosztem innego sąsiedniego do niego(Zachowany warunek min blok kxk)
- Tworzymy nowy board na podstawie nowych zmienonych współrzędnych(zawsze zwiększamy jeden o 1 kolumnę/wiersz inny zmniejszając).
- Sprawdzamy Koszt.
- Niestety nieraz możemy rozszeerzyć blok składający się z wartości 32 kosztem bloku o tej samej wartości lub po prostu żaden z sąsiadów bloku nie ma odpowiednich wymiarów lub nie jest w odpowiednich kolumnach , wtedy globalnie nic się nie zmieniło i koszt jest zerem więc musimy wybrać inne rozszerzanie ( wracamy do i.)
- Sprawdzamy acceptance_probability jeśli uda się przejść warunek > random.uniform(0,1) to updateujemy wartości " przechodzimy do wygenerowanego sąsiada "
- Jeśli wynik jest lepszy od ostatniego najlepszego zapisujemy.
i wtedy będzie wykres kolejnych wartości przez, które rzeczywiście przeszliśmy.
-
Funkcja Kosztu: compute_distance() (zadana w poleceniu zadania)
-
Sąsiedztwo: Zmiana wartości( koloru) losowego bloku i/lub rozszerzenia losowego bloku kosztem innego bloku lub/i swap wartości losowych bloków. Tzn jeśli mamy np maksymalnie prawy górny blok wiekości (założmy Wysokość x Szerokość) k+1 x k+1 i jego sąsiadów lewego L i dolnego D, to sprawdzamy, czy dane bloki mają odpowiednie wymiary, tj czy po ucięciu kolumny czy też wiersza będą nadal większe niz k x k. Losujemy np Lewego Sprawdzamy, czy lewy leży na tej samej wysokości, i potem czy po zjedzeniu kolumny jego wymiar szerokość będzie większa niż k.
Została również zaimplementowana możliwość rysowania wykresu funkcji kosztu, naturalnie jest zaimplementowana dla niepowtarzających się kosztów ( w celu zachowania przyjemnego wyglądu SA).
Generalnie udało mi się zaimplementować na 4 różne sąsiedztwa, z czego 2 były chyba zbyt losowe(bardzo wolne), dlatego ich nie publikuję. Po wpisaniu make będziemy korzystać z tego opartego na preffixach.( w mainie można przestawić na transpozycje)
Algorytm został zaimplementowany na dwa sposoby wyboru sąsiedztwa pierwszy na zasadzie transpozycji, a drugi na podstawie usuwania losowego suffixu. Chciałbym od razu podkreślić, że wydaje mi się, że ten pierwszy bazujący na transpozycjach może nie być do końca SA, bo w teorii nie mogę znaleźć przez transpozycję sąsiada o długości większej czyli o gorszej jakości, chyba że rozwiązanie o tej samej długości można uznać za gorsze( a tak chyba można założyć?). Dlatego własnie pushuje na dwa sposoby.
- Wyznaczenie czasu zakończenia.
- Ustalenie temperatury początkowej.
- Znalezienie pozycji startowej.
- Wyznaczenie rozwiązania inicjalnego.
- Jak wyznaczone jest rowiązanie intuicyjne?
- Losujemy path długości 2*(m+n-1)
- Idziemy wzdłuż dopóki nie napotkamy ściany lub wyjścia.
- Jeśli napotkamy ścianę losujemy nowy path z miejsca, w którym ostatnio się zatrzymaliśmy.
- Powtarzamy dopóki nie znajdziemy wyjścia.
- Losujemy sąsiada.
- Losujemy losowy index. Ten do którego prefix ma zostać zachowany.
- Do prefixu dołączamy, losowy path.
- Jeśli przez dany path napotkamy ściąnę, losujemy kolejnego sąsiada.(powrót do 5.1)
- Jeśli uda nam się przejść acceptance_prob przechodzimy do sąsiada. Current = neighbour.
- Zapisujemy wynik do bestów, jeśli je``st lepszy od ostatniego besta.
- Wracamy do 5.
- Funkcja Kosztu: Długość ścieżki.
- Sąsiedztwo: Transpozycje danej ścieżki. np LLU , neigh = LUL itd.
Różni się w zasadzie tylko losowaniem sąsiada, reszta jak wyżej. 5. Losujemy sąsiada. 1. Wyznaczamy sąsiada zamieniając miejscami 2 elementy z initial_path( Transpozycja) 2. Usuwamy punkty stałe, tzn UD LR RL DU z pathu. 3. Jeśli przez dany path napotkamy ściąnę, losujemy kolejnego sąsiada.(powrót do 5.1)
- Funkcja Kosztu: Długość ścieżki.
- Sąsiedztwo: Ścieżki o wspólnym prefixie.
Została zaimplementowana również możliwość stworzenia wykresu, gdzie możemy zaoobserwować zaimplementowane wyżarzanie. Wystarczy ustawic graph= na True w mainie.
:param x0: - start vector
:param t: time limitation
:param func: quality function
:param swarm_size: quantity of swarms
:param alpha: velocity retained
:param beta: personal best retained
:param gamma: best of informants' retained
:param delta: global best retained
:param epsilon: size of jumps
:param plot: graphs
- Iniciujemy populacje losowymi rozwiązaniami, i tworzymy losowe wektory prędkości dla każdego z nich.
- Rejestrujemy listę personalnych bestów.
- Wybieramy globalnego besta.
- Wybieramy besta z bieżących rojów ( informowanych )
- Zaburzamy każdy z wektorów zgodnie z współczynnikami i wzorem
population[i][1][j] = alpha * vi[j] + b * (fittest_personal[j] - xi[j]) + c * ( fittest_informants[j] - xi[j]) + d * (fittest_all[j] - xi[j])
- Zmieniamy prędkości zgodnie z epsilon i zaburzamy współrzędne wykraczające poza dziedzinę.
genetic_algorithm scrabble - (scrabble game) creating words from characters-multiset in accordance with given dictionary
:param t: time limitation
:param correct_words: set of correct words
:param initial_words: initial correct words
:param multiset: dictionary of letter and frequencies (Acceptable freq)
:param gen_times: quantity of children to be generated
- Wczytujemy zbiór liter z wartościami - multiset.
- Budujemy frequency table ( dopuszczalna ) restrykuje możliwe słowa do multisetu.
- Budujemy słownik możliwych liter z wagami.
- Wczytujemy słownik.txt i okrajamy nasz zbiór do słów prawidłowych dla frequency table.
- Wybieramy rodziców licząć prawdopodobieństwa( f(x_i)/sum(quality(X))) w każdej iteracji szufladkując listę.
- Krzyżujemy wybranych rodziców ( tworzymy zbiór liter z p1,p2 i próbujemy ułożyć słowo z poprawnych słów)
- Mutujemy dziecko zachowując jego prefix lub suffix ( szukamy innego w słowniku o tym samym suffixie/prefixie)
- Podmieniamy starą populację na nową generację
:param t: time limitation
:param n: board height
:param m: board width
:param s: quantity of initial solutions
:param p: population quantity
:param paths: initial solutions
:param board: maze
:param mutation: decide with function use to mixed_mutation
:param selection: decide with function use to select parents
- Wybieramy besta z ścieżek inicjalnych.
- Wybieramy rodziców z populacji do skrzyżowania w sposób
- tournament selection
- licząć prawdopodobieństwa( f(x_i)/sum(quality(X))) w każdej iteracji szufladkując listę
- Krzyżyujemy rodziców (two point crossover) wybierając losowe indexy i1,j1 ; i2,j2 i podmieniamy "środki" lub boki tworząc dzieci
- Mutujemy dzieci na sposób:
- losowo podmieniamy dwa elementy ścieżki ( transpozycja )
- wybieramy losowy preffix i losujemy losowej długości suffix
- Inicjujemy losową populację początkową random shuffles + kilka rozwiązań utworzonych przy użyciu pseudo- zachłannego algorytmu like DFS
- Wybieramy besta z bieżacej populacji.
- Dopóki jest czas
- Dopóki lista generowanych nie jest pełna (pop_size)
- Wygeneruj rodziców p1,p2 ( tournament selection)
- Zastosuj cycle crossover
- random swap dla dwójki utworzonych dzieci ( osobne swapy)
- Dołącz dzieci do nowej generacji
- Powiększ populację o nową generację
- Dodaj losowe rozwiązanie zachłanne (good quality)
- Przeprowadź reprodukcję tzn zachowaj 30% najlepszych osobników, a resztę dobierz losowo
- sprawdzaj Besta
- Dopóki lista generowanych nie jest pełna (pop_size)
- Narysuj wykres propozycja besta vs best
- Zwróć besta