POLITECHNIKA POZNAŃSKA WYDZIAŁ ELEKTRONIKI I TELEKOMUNIKACJI RAPORT METODY OPTYMALIZACJI ALGORYTM GENETYCZNY 1C Michał Kaszuba, #88515 Multimedia i Elektronika Powszechnego Użytku Poznań, 2012/13 str. 1
1. Treść zadania Proszę znaleźd wartośd minimalną funkcji postaci: Przed przystąpieniem do rozwiązania zadania metodą algorytmu genetycznego proszę znaleźd rozwiązanie analityczne. Zdefiniowad parametry algorytmu. Określid wpływ metody selekcji i parametrów rekombinacji oraz rozmiaru populacji, ilości generacji, wielkości populacji elitarnej na rozwiązanie zadania, gdzie: Selekcja może zostad przeprowadzona jedną z poniższych metod: metodą ruletki, metodą turniejową, metodą rankingową. Krzyżowanie jednopunktowe, wielopunktowe, wielowymiarowe, zliczające-1, ewolucja powiązao. Mutacja wymiana bitu, wstawienie bitu, usunięcie genu, mutacja infekcją wirusową, mutacja różnicowaniem lub naśladowaniem. str. 2
2. Analiza funkcji Minimalizowana funkcja celu: f(x1,x2,x3) = a 1 x 1 + a 2 x 2 + a 3 x 3 warunki ograniczające: Łatwo zauważyd, że wartośd funkcji będzie najmniejsza, gdy przy parametrach decydujących a 1, a 2 oraz a 3 jak w poniższej tabeli współrzędne x 1, x 2, x 3 będą osiągały następujące wartości: Parametry decydujące Punkt minimum 5.12 5.12 5.12 5.12 5.12 5.12 5.12 5.12 5.12 5.12 5.12 5.12 3. Zdefiniowanie parametrów algorytmu a) Parametry wejściowe: Liczba osobników (chromosomów) w jednym pokoleniu (populacji, iteracji algorytmu): POP_SIZE Liczba iteracji algorytmu (liczba pokoleo, generacji): MAX_ITER Rodzaj selekcji: seltype Rodzaj krzyżowania: crosstype Rodzaj mutacji: muttype Prawdopodobieostwo krzyżowania (o ile wymagane w danej metodzie krzyżowania): CROSS_PROBAB Prawdopodobieostwo mutacji (o ile wymagane w danej metodzie mutacji): MUT_PROBAB b) Parametry wyjściowe: Znalezione współrzędne x1,x2,x3 minimum analizowanej funkcji Wartośd analizowanej funkcji dla znalezionego minimum: f(x1,x2,x3) 4. Realizacja programowa założenia, wybór platformy i narzędzi Implementacja algorytmu genetycznego została wykonana w języku C++ z tekstowym (konsola) interfejsem użytkownika. Do implementacji posłużył program Visual C++ 2008 Professional firmy Microsoft. 5. Interakcja zaimplementowanego algorytmu z użytkownikiem Zaimplementowany algorytm wczytuje od użytkownika kolejno dane wymienione w punkcie 3., następnie przeprowadza niezbędne przetwarzanie (MAX_ITER iteracji algorytmu genetycznego) i prezentuje na ekranie wyniki swojego działania. Podczas przetwarzania na ekranie widoczny jest procentowy wskaźnik postępu, więc z góry wiadomo, na jakim etapie przetwarzania jest program (istotne, gdy poda się np. setki tysięcy pokoleo jako daną wejściową). Przykładowy wynik działania programu przedstawiono poniżej. str. 3
6. Wyniki badań i wnioski Ciężko jest stwierdzid która metoda selekcji/krzyżowania/mutacji jest najlepsza z uwagi na to, że algorytm za każdym razem daje inny wynik (z uwagi na czynnik losowy, który jest istotą algorytmów genetycznych), jednak poczynione obserwacje pozwalają wysnud ogólny wniosek, że wszystkie zaimplementowane metody selekcji/krzyżowania/mutacji dają zadowalające wyniki, tj. algorytm jest zbieżny dla każdej kombinacji metod selekcji/krzyżowania/mutacji. Minimum analizowanej funkcji jest zawsze znajdowane, jednak z dokładnością jego lokalizacji przez algorytm jest różnie. Dla parametrów a 1 =a 2 =a 3 =1 analizowana funkcja przyjmuje postad f(x1,x2,x3) = x1 + x2 + x3. Jest zatem oczywiste, że wówczas minimum funkcji znajduje się dla x1,x2,x3 jak najmniejszych, co przy zadanych ograniczeniach równa się: Rzeczywiste minimum funkcji: f(,,) = -15.36 Wg tego kryterium zostało przeprowadzonych kilka testów praktycznych implementacji AG. Wyniki przedstawiono poniżej (z uwagi na mnogośd zaimplementowanych metod ograniczono się do niektórych ich kombinacji): Wielkość populacji (POP_SIZE) Ilość pokoleń (MAX_ITER) selekcja krzyżowanie mutacja prawd. krzyż. [%] 1. 5 100 Ruletka Jednopunktowe Wymiana bitu 40 30 2. 5 100 Ruletka Jednopunktowe Wymiana bitu 30 10 3. 100 100 Ruletka Jednopunktowe Wymiana bitu 40 30 4. 100 100 turniejowa Jednopunktowe Wymiana bitu 40 30 5. 100 100 Rankingowa Jednopunktowe Wymiana bitu 40 30 6. 100 4 Rankingowa Jednopunktowe Wymiana bitu 40 30 7. 100 30 000 Rankingowa Jednopunktowe Wymiana bitu 40 30 prawd. mutacji [%] x1,x2,x3-4.79875-3.03184-3.91529-4.75859 1.70667-4.07592-4.75859-5.03969-4.99953-5.07984-4.35702-4.87906-5.03969-3.27278-4.59796-5.07984 f(x1,x2,x3) str. 4-11.7459-7.12784-14.7978-14.5569-15.0387-12.9907-15.3198
8. 20 100 Ruletka wielowymiarowe Usunięcie genu 20-9. 20 100 Rankingowa ewolucja powiązao naśladowaniem 20-10. 10 60 turniejowa zliczające-1 różnicowaniem 10-11. 3 4 turniejowa wielopunktowe wstawienie bitu 22-12. 15 90 turniejowa wielopunktowe wstawienie bitu 18-13. 2 10 000 Ruletka Jednopunktowe usunięcie genu 30-14. 1 000 2 turniejowa ewolucja powiązao naśladowaniem 25 - -4.8389-4.95937-5.03969-5.03969-5.07984-3.79482-3.072 1.66651-4.99953-3.59404-3.67435 1.14447-1.06416-15.36-14.9183-15.1592-5.20031-12.2679-5.03969-15.36 Wnioski (komentarz do wyników): w powyższej tabeli starano się ukazad możliwie jak najwięcej scenariuszy działania AG. Wnioski jakie płyną z obserwacji wyników są następujące: im większa populacja (jedno pokolenie), tym wyniki są lepsze (porównaj przypadek 2 i 3, przypadek 14), im więcej pokoleo (iteracji AG), tym wynik dokładniejszy (porównaj przypadek 6 i 7), duża liczba iteracji AG przy niewielkiej populacji daje słaby wynik przypadek 13. Wynika to stąd, że tak naprawdę poza chromosomem ulegającemu elitaryzmowi mamy tutaj tylko jeden regularny chromosom, więc ciężko mówid tu o rozmnażaniu i pokoleniowości, a zarazem o zbieżności AG w takim przypadku, duża liczba iteracji oraz liczna populacja (przypadek 7) daje bardzo dobre wyniki, jednak jest to okupione długim czasem obliczeo (kilkadziesiąt sekund na procesorze 2,2 GHz, 1,5 GB RAM), prawdopodobieostwo wystąpienia mutacji i krzyżowania ma znaczący wpływ na wynik - porównaj przypadek 1 i 2. Bardzo liczna populacja przy bardzo niewielu pokoleniach (iteracjach AG) daje optymalny wynik (przypadek 13) jest to spowodowane tym, że jako wynik jest tutaj brany chromosom poddany elitaryzmowi, więc najlepszy z 1 000 chromosomów. Wada: duża zajętośd pamięci RAM, długi czas przetwarzania. Bardzo nieliczna populacja i mało pokoleo daje bardzo słabe rezultaty -> przypadek 11 Każda zaimplementowana metoda selekcji/krzyżowania/mutacji daje zadowalający wynik (błąd maksymalnie kilka procent) przy dobrze dobranych pozostałych parametrach, Przybliżona (z uwagi na brak powtarzalności działania AG) minimalna wielkośd populacji zapewniająca zadowalający wynik: 20-30 Przybliżona (z uwagi na brak powtarzalności działania AG) minimalna liczba pokoleo (iteracji AG) zapewniająca zadowalający wynik: 50 Dla pokazania, że zaimplementowany AG działa również dla innych a i, poniżej przedstawiono podobną tabelę dla a 1 =-1, a 2 =-2, a 3 =4 Analizowana funkcja: f(x 1,x 2,x 3 ) = -x 1-2x 2 +4x 3 Jest zatem oczywiste, że wówczas minimum funkcji znajduje się dla x1 oraz x2 jak największych oraz x3 jak najmniejszego co przy zadanych ograniczeniach równa się: str. 5
Rzeczywiste minimum funkcji: f(5.12,5.12,) = -35.84 Wielkość populacji (POP_SIZE) Ilość pokoleń (MAX_ITER) selekcja krzyżowanie mutacja prawd. krzyż. [%] 1. 30 50 turniejowa zliczające-1 różnicowaniem 20-2. 25 60 rankingowa ewolucja powiązao usunięcie genu 35-3. 40 70 ruletka wielopunktowe wstawienie bitu 20-4. 100 100 ruletka wielopunktowe naśladowaniem 15 - prawd. mutacji [%] x1,x2,x3 4.51765 4.75859-4.31686-0.742902 3.71451 4.95937 5.12-5.07984 4.67827 4.71843 f(x1,x2,x3) -31.3023-27.1661-35.5187-34.5951 7. Reprezentacja chromosomu Przyjęte kodowanie: binarne. Długośd chromosomu: 8 bitów/gen (8 bitów/zmienną analizowanej funkcji). 24 bity/chromosom. Długośd chromosomu wyznaczona zostala w następujący sposób: Zał. 3 zmienne (x 1,x 2,x 3 ) => długośd chromosomu: 24 bity const unsigned int CHROM_LENGHT = 24; typedef struct unsigned short gen[chrom_lenght]; unsigned short seltourgroup; unsigned short selrankval; chromosom; // długośc chromosomu // chromosom // geny // grupa w której jest chromosom (selekcja turniejowa) // ranga chromosomu (selekcja rankingowa) 8. Reprezentacja populacji chromosomów (jedno pokolenie i MAX_ITER pokoleń) typedef struct // para rodzicielska unsigned int mom; unsigned int dad; parentcouple; typedef struct chromosom* pop; parentcouple* parents; // pojedyncze pokolenie // POP_SIZE chromosomów // POP_SIZE-1 par rodzicielskich str. 6
population; population* tpop; tpop = new population[max_iter]; for(int i=0; i<max_iter; i++) tpop[i].pop = new chromosom[pop_size]; tpop[i].parents = new parentcouple[pop_size-1]; Komentarz: jedno pokolenie zawiera POP_SIZE chromosomów oraz POP_SIZE-1 par rodzicielskich. Par rodzicielskich jest o 1 mniej niż chromosomów, bo jeden chromosom (najlepiej przystosowany) jest bezpośrednio kopiowany do następnej populacji, więc potrzeba jedynie POP_SIZE-1 potomków. Z każdej pary rodzicielskiej powstaje jeden potomek. 9. Główna funkcja AG int main() srand((int)time(null)); loadparams(); firstpop(); // wczytanie parametrów // wygenerowanie pierwszej populacji for(int i=0; i<max_iter-1; i++) // ----- generowanie nowej populacji ----- elitism(i); selection(i); crossing(i); mutatation(i); // --------------------------------------- progress(i); showres(); cleanup(); // wyniki // porządki Powyżej przedstawiono główną funkcję (main()) oraz główną pętlę zaimplementowanego AG. Kolejno następuje: wczytanie parametrów od użytkownika, wygenerowanie pierwszej populacji, następnie w pętli następuje tworzenie kolejnych pokoleo w procesach kolejno: elitaryzmu, selekcji, krzyżowania i mutacji. Funkcja progres(i) pokazuje procentowy wskaźnik postępu obliczeo na ekranie. Po wyjściu z głównej pętli następuje wyświetlenie wyników działania AG oraz porządki (dealokacja pamięci zajętej przez dynamicznie utworzone tablice). 10. Kod źródłowy zaimplementowanego AG Kod programu składa się z pięciu plików: - main.c -> główny plik programu, pętla główna, - guni.h -> plik nagłówkowy generatora liczb pseudolosowych o rozkładzie równomiernym, - guni.c -> plik źródłowy generatora liczb pseudolosowych o rozkładzie równomiernym, - genalg.h -> plik nagłówkowy AG - genalg.c -> plik źródłowy AG str. 7
main.c: #include <iostream> #include <ctime> #include "genalg.h" #include "guni.h" using namespace std; int main() srand((int)time(null)); loadparams(); firstpop(); // wczytanie parametrów // wygenerowanie pierwszej populacji for(int i=0; i<max_iter-1; i++) // ----- generowanie nowej populacji ----- elitism(i); selection(i); crossing(i); mutatation(i); // --------------------------------------- progress(i); showres(); cleanup(); // wyniki // porządki guni.h: #ifndef _GUNI_H_ #define _GUNI_H_ /////////////////////////////////////////////////////////////////////////////////////////////// // klasa guni // // // // rozklad rownomierny w przedziale 0-1 // // generator mieszany // // X(n+1) = (a * X(n) + c) mod m // // a=11 // // X(0) = seed <= jadro (ziarno) generatora // // c=7 // // m=1997 // /////////////////////////////////////////////////////////////////////////////////////////////// class guni int seed; // jadro generatora int temp; double result; // wynik losowania public: ; guni(); // konstruktor double getrand(); #endif guni.c: #include <iostream> #include <ctime> #include "guni.h" using namespace std; guni::guni() // konstruktor srand((int)time(null)); seed = rand() % 100; // losowe jadro generatora z zakresu 0-99 temp = seed; // zmienna pomocnicza str. 8
double guni::getrand() temp = (11 * temp + 7) % 1997; result = temp/1997.; // przeskalowanie na zakres (0-1), kropka na koncu -> niejawny casting return result; genalg.h: #ifndef _GENALG_ #define _GENALG_ void cleanup(); void progress(int); void loadparams(); void firstpop(); void elitism(int); void selection(int); void crossing(int); void mutatation(int); void showres(); // porządki // licznik procentowy (odpowiednik progress bara) // wczytanie wielkosci populacji (jedno pokolenie) i ilości generacji (pokoleń) // tworzy pierwsza populacje // elitaryzm // selekcja // krzyżowanie // mutacja // pokazanie wyniku algorytmu, x1,x2,x3 oraz f(x1,x2,x3) // ------------------------------------- stałe ------------------------------------- const unsigned int CHROM_LENGHT = 24; // długośc chromosomu const unsigned int VAR_NR = 3; // liczba zmiennych optymalizacji (x1, x2, x3) const double XI_THR = 5.12; // granica przedziału xi // --------------------------------------------------------------------------------- extern int POP_SIZE; extern int MAX_ITER; extern double* tfitfunval; // wielkość populacji // max liczba iteracji (warunek stopu) // wartości funkcji przystosowania dla pokolenia typedef struct double a1; double a2; double a3; aival; typedef struct double x1; double x2; double x3; xival; typedef struct // para rodzicielska unsigned int mom; unsigned int dad; parentcouple; typedef struct unsigned short gen[chrom_lenght]; unsigned short seltourgroup; unsigned short selrankval; chromosom; typedef struct chromosom* pop; parentcouple* parents; population; extern population* tpop; // chromosom // geny // grupa w której jest chromosom (selekcja turniejowa) // ranga chromosomu (selekcja rankingowa) // pojedyncze pokolenie // POP_SIZE chromosomów // POP_SIZE-1 par rodzicielskich // MAX_ITER pokoleń // wartość funkcji dopasowania + indeks chromosomu // przydatna struktura gdy chcemy posortować pokolenie wg wartości funkcji przystosowania typedef struct double fitval; unsigned int chind; indfitv; extern enum selectiontype; extern selectiontype seltype; extern enum crossingtype; extern crossingtype crosstype; str. 9
extern enum mutationtype; extern mutationtype muttype; extern aival ai; extern xival xi; // a1,a2,a3 // x1,x2,x3 #endif //_GENALG_ genalg.c: #include <iostream> #include <vector> #include <algorithm> #include "genalg.h" #include "guni.h" using namespace std; aival ai; xival xi; selectiontype seltype; crossingtype crosstype; mutationtype muttype; int POP_SIZE; int MAX_ITER; population* tpop = NULL; double* tfitfunval = NULL; double MUT_PROBAB = 0; // prawd. mutacji double CROSS_PROBAB = 0; // prawd. krzyzowania double fitfunval(xival val); double chfitfunval(chromosom ch); xival ch2xi(chromosom ch); void progress(int iter) static int cnt = 0; static int result = 0; if(cnt++ == 0) cout << "\n\n\n"; result = int((double(iter) / double(max_iter)) * 100); cout << "=============== " << result << "%\t=============== " << "\r"; bool cond(indfitv arg1, indfitv arg2) return arg1.fitval < arg2.fitval; enum selectiontype st_none, st_roulette, st_tournament, st_ranking, ; enum crossingtype ct_none, ct_onepoint, ct_manypoints, ct_multidimensional, ct_countingminusone, ct_evolutionoflinks, ; enum mutationtype mt_none, mt_replacebit, mt_insertbit, mt_remgen, mt_infectionvirus, mt_diff, mt_imitation ; void load_ai() for(int i=0; i<3; i++) cout << "Podaj a" << i+1 << ": "; str. 10
if(i == 0) cin >> ai.a1; if(i == 1) cin >> ai.a2; cin >> ai.a3; void chooseselmode() seltype = st_none; int temp = 0; bool fcorrectsel = false; while(fcorrectsel == false) fcorrectsel = true; cout << "\nwybor metody selekcji\n" << "\t1 - metoda ruletki\n" "\t2 - metoda turniejowa\n" "\t3 - metoda rankingowa\n\n" "Twoj wybor: "; cin >> temp; switch(temp) case 1: seltype = st_roulette; case 2: seltype = st_tournament; case 3: seltype = st_ranking; default: cout << "zly nr metody!\n"; fcorrectsel = false; void choosecrosstype() crosstype = ct_none; int temp = 0; bool fcorrectcross = false; while(fcorrectcross == false) fcorrectcross = true; cout << "\nwybor krzyzowania\n" << "\t1 - jednopuntkowe\n" "\t2 - wielopunktowe\n" "\t3 - wielowymiarowe\n" "\t4 - zliczajace-1\n" "\t5 - ewolucja powiazan\n\n" "Twoj wybor: "; cin >> temp; switch(temp) case 1: crosstype = ct_onepoint; case 2: crosstype = ct_manypoints; case 3: crosstype = ct_multidimensional; case 4: crosstype = ct_countingminusone; case 5: crosstype = ct_evolutionoflinks; default: cout << "zly nr metody!\n"; fcorrectcross = false; str. 11
void choosemuttype() muttype = mt_none; int temp = 0; bool fcorrectmut = false; while(fcorrectmut == false) fcorrectmut = true; cout << "\nwybor mutacji\n" << "\t1 - wymiana bitu\n" "\t2 - wstawienie bitu\n" "\t3 - usuniecie genu\n" "\t4 - infekcja wirusowa\n" "\t5 - roznicowaniem\n" "\t6 - nasladowaniem\n\n" "Twoj wybor: "; cin >> temp; switch(temp) case 1: muttype = mt_replacebit; case 2: muttype = mt_insertbit; case 3: muttype = mt_remgen; case 4: muttype = mt_infectionvirus; case 5: muttype = mt_diff; case 6: muttype = mt_imitation; default: cout << "zly nr metody!\n"; fcorrectmut = false; void loadparams() load_ai(); // wczytanie a1, a2, a3 cout << "Podaj wielkosc populacji (jedno pokolenie): "; bool fcorrinp = false; while(fcorrinp == false) cin >> POP_SIZE; if(pop_size <= 0) fcorrinp = false; cout << "Zla wielkosc populacji! Podaj jeszcze raz: "; continue; fcorrinp = true; fcorrinp = false; cout << "Podaj ilosc generacji (pokolen): "; while(fcorrinp == false) cin >> MAX_ITER; if(max_iter <= 0) fcorrinp = false; cout << "Zla ilosc generacji! Podaj jeszcze raz: "; continue; fcorrinp = true; tpop = new population[max_iter]; for(int i=0; i<max_iter; i++) tpop[i].pop = new chromosom[pop_size]; tpop[i].parents = new parentcouple[pop_size-1]; tfitfunval = new double[pop_size]; str. 12
chooseselmode(); // wybór metody selekcji choosecrosstype(); // wybór metody krzyzowania choosemuttype(); // wybór metody mutacji void firstpop() guni g1stpop; unsigned short tmpt[chrom_lenght] = ; for(int j=0; j<pop_size; j++) double tmp = g1stpop.getrand(); tmp *= 16777216; int tmpi = int(tmp); for(int i=0; i<chrom_lenght; i++) tmpt[chrom_lenght-i-1] = tmpi % 2; tmpi /= 2; for(int i=0; i<chrom_lenght; i++) tpop[0].pop[j].gen[i] = tmpt[i]; void elitism(int popnr) // liczymy wartosc funkcji przystosowania // F(ch(x)) = -[a1x1 + a2x2 + a3x3] // chromosom o max F jest kopiowany do nastepnej populacji bez zmian double maxf = -10000; double tempf = 0; unsigned short maxf_ind = 0; for(int i=0; i<pop_size; i++) tempf = chfitfunval(tpop[popnr].pop[i]); tfitfunval[i] = tempf; if(tempf >= maxf) maxf = tempf; maxf_ind = i; // chromosom o tym numerze ulegnie elitaryzmowi for(int k=0; k<chrom_lenght; k++) tpop[(popnr + 1) % MAX_ITER].pop[0].gen[k] = tpop[popnr].pop[maxf_ind].gen[k]; void selection(int popnr) double minfitv, maxfitv, fitfunvrange, fitvsum; // koło ruletki dla selekcji metodą koła ruletki double* tthrroulette = new double[pop_size + 1]; tthrroulette[0] = 0; tthrroulette[pop_size] = 1; // koło ruletki dla selekcji metodą rankingową double* tthrrankroulet = new double[pop_size + 1]; tthrrankroulet[0] = 0; tthrrankroulet[pop_size] = 1; guni genselection; double group; unsigned int gracnt = 0, grbcnt = 0; double maxfitgra = -100000, maxfitgrb = -100000; unsigned int maxfitgraind = 0, maxfitgrbind = 0; bool fonegroup = true; unsigned int sumofrank = 0; vector <indfitv> tfitval; switch(seltype) case st_roulette: //min fdop: minfitv = 100000; for(int i=0; i<pop_size; i++) if(tfitfunval[i] < minfitv) minfitv = tfitfunval[i]; str. 13
//max fdop: maxfitv = -100000; for(int i=0; i<pop_size; i++) if(tfitfunval[i] > maxfitv) maxfitv = tfitfunval[i]; fitfunvrange = maxfitv - minfitv; // zakres zmienności wartości funkcji dopasowania if(minfitv <= 0) for(int i = 0; i<pop_size; i++) tfitfunval[i] += (-minfitv) + 1; // suma fitvsum = 0; for(int i = 0; i<pop_size; i++) fitvsum += tfitfunval[i]; for(int i = 1; i<pop_size; i++) tthrroulette[i] = tthrroulette[i-1] + tfitfunval[i-1]/fitvsum; for(int i=0; i<(pop_size-1); i++) // losowanie par rodzicielskich unsigned int momind = 0, dadind = 0; while(momind == dadind) double mom = genselection.getrand(); for(int j=0; j<pop_size; j++) if(mom < tthrroulette[j+1]) momind = j; momind++; double dad = genselection.getrand(); dadind = 0; for(int j=0; j<pop_size; j++) if(dad < tthrroulette[j+1]) dadind = j; dadind++; tpop[popnr].parents[i].mom = momind; tpop[popnr].parents[i].dad = dadind; case st_tournament: for(int pnr=0; pnr<(pop_size-1); pnr++) while(fonegroup == true) // losowanie grup for(int i=0; i<pop_size; i++) group = genselection.getrand(); if(group >= 0.5) // gra tpop[popnr].pop[i].seltourgroup = 1; //grb tpop[popnr].pop[i].seltourgroup = 2; str. 14
// sprawdzenie, czy liczebnośc każdej grupy jest niezerowa for(int i=0; i<pop_size; i++) if(tpop[popnr].pop[i].seltourgroup == 1) gracnt++; grbcnt++; if((gracnt == 0) (grbcnt == 0)) fonegroup = true; fonegroup = false; maxfitgra = -100000; maxfitgrb = -100000; // najlepiej dopasowany chromosom z gra for(int i=0; i<pop_size; i++) double tmp = chfitfunval(tpop[popnr].pop[i]); if(tpop[popnr].pop[i].seltourgroup == 1) if(tmp >= maxfitgra) maxfitgra = tmp; maxfitgraind = i; // najlepiej dopasowany chromosom z grb if(tpop[popnr].pop[i].seltourgroup == 2) if(tmp >= maxfitgrb) maxfitgrb = tmp; maxfitgrbind = i; // przypisanie wyznaczonych rodziców tpop[popnr].parents[pnr].mom = maxfitgraind; tpop[popnr].parents[pnr].dad = maxfitgrbind; fonegroup = true; case st_ranking: // wypełnienie wektora struktur z wartosciami funkcji dopasowania dla populacji i indeksami chromosomów for(int i=0; i<pop_size; i++) indfitv tmp; tmp.fitval = chfitfunval(tpop[popnr].pop[i]); tmp.chind = i; tfitval.push_back(tmp); //posortowanie tego wektora sort(tfitval.begin(),tfitval.end(), cond); // przydzielenie rang chromosomom w populacji // wieksza ranga = wieksza wartosc funkcji przystosowania for(int i=0; i<pop_size; i++) tpop[popnr].pop[tfitval[i].chind].selrankval = i+1; sumofrank += (i+1); for(int i = 1; i<pop_size; i++) tthrrankroulet[i] = tthrrankroulet[i-1] + double(tpop[popnr].pop[i-1].selrankval)/sumofrank; for(int i=0; i<(pop_size-1); i++) // losowanie par rodzicielskich unsigned int momind = 0, dadind = 0; while(momind == dadind) str. 15
double mom = genselection.getrand(); for(int j=0; j<pop_size; j++) if(mom < tthrrankroulet[j+1]) momind = j; momind++; double dad = genselection.getrand(); dadind = 0; for(int j=0; j<pop_size; j++) if(dad < tthrrankroulet[j+1]) dadind = j; dadind++; tpop[popnr].parents[i].mom = momind; tpop[popnr].parents[i].dad = dadind; delete[] tthrroulette; delete[] tthrrankroulet; void crossing(int popnr) guni gencross; unsigned short onepointk = 0; unsigned short twopointk1 = 0, twopointk2 = 0; double draw = 0; double iscross = 0; chromosom mom, dad, child, child2; static unsigned int crprobcnt = 0; if(crprobcnt == 0) cout << "Podaj prawdopodobienstwo zajscia krzyzowania w % (0-100) "; while(true) cin >> CROSS_PROBAB; if((cross_probab < 0) (CROSS_PROBAB > 100)) cout << "Zla wartosc prawdopodobienstwa! Podaj jeszcze raz: "; CROSS_PROBAB /= 100; crprobcnt++; switch(crosstype) case ct_onepoint: for(int i=1; i<pop_size; i++) // losowanie punktu podziału onepointk = 1 + int((chrom_lenght - 1) * gencross.getrand()); // rodzice mom = tpop[popnr].pop[tpop[popnr].parents[i-1].mom]; dad = tpop[popnr].pop[tpop[popnr].parents[i-1].dad]; iscross = gencross.getrand(); if(iscross < CROSS_PROBAB) draw = gencross.getrand(); str. 16
if(draw <= 0.5) // childa for(int j=0; j<onepointk; j++) child.gen[j] = mom.gen[j]; for(int j=onepointk; j<chrom_lenght; j++) child.gen[j] = dad.gen[j]; // childb for(int j=0; j<onepointk; j++) child.gen[j] = dad.gen[j]; for(int j=onepointk; j<chrom_lenght; j++) child.gen[j] = mom.gen[j]; draw = gencross.getrand(); if(draw <= 0.5) // childa child = mom; // childb child = dad; // wygenerowany potomek wchodzi do następnej populacji // potem jeszcze bedzie podlegal mutacji tpop[popnr+1].pop[i] = child; case ct_manypoints: for(int i=1; i<pop_size; i++) // losowanie punktów podziału, twopointk1 < twopointk2 do twopointk1 = 1 + int((chrom_lenght - 1) * gencross.getrand()); twopointk2 = 1 + int((chrom_lenght - 1) * gencross.getrand()); while (twopointk2 <= twopointk1); // rodzice mom = tpop[popnr].pop[tpop[popnr].parents[i-1].mom]; dad = tpop[popnr].pop[tpop[popnr].parents[i-1].dad]; if(iscross < CROSS_PROBAB) draw = gencross.getrand(); if(draw <= 0.5) // childa for(int j=0; j<twopointk1; j++) child.gen[j] = mom.gen[j]; for(int j=twopointk1; j<twopointk2; j++) child.gen[j] = dad.gen[j]; for(int j=twopointk2; j<chrom_lenght; j++) child.gen[j] = mom.gen[j]; // childb for(int j=0; j<twopointk1; j++) child.gen[j] = dad.gen[j]; for(int j=twopointk1; j<twopointk2; j++) child.gen[j] = mom.gen[j]; for(int j=twopointk2; j<chrom_lenght; j++) str. 17
child.gen[j] = dad.gen[j]; draw = gencross.getrand(); if(draw <= 0.5) // childa child = mom; // childb child = dad; // wygenerowany potomek wchodzi do następnej populacji // potem jeszcze bedzie podlegal mutacji tpop[popnr+1].pop[i] = child; case ct_multidimensional: for(int i=1; i<pop_size; i++) // rodzice mom = tpop[popnr].pop[tpop[popnr].parents[i-1].mom]; dad = tpop[popnr].pop[tpop[popnr].parents[i-1].dad]; unsigned short momx1[chrom_lenght/var_nr]; unsigned short momx2[chrom_lenght/var_nr]; unsigned short momx3[chrom_lenght/var_nr]; unsigned short dadx1[chrom_lenght/var_nr]; unsigned short dadx2[chrom_lenght/var_nr]; unsigned short dadx3[chrom_lenght/var_nr]; // podział ojca i matki na wymiary (zmienne optymalizacji) for(int j=0; j<chrom_lenght/var_nr; j++) momx1[j] = mom.gen[j]; momx2[j] = mom.gen[j+8]; momx3[j] = mom.gen[j+16]; dadx1[j] = dad.gen[j]; dadx2[j] = dad.gen[j+8]; dadx3[j] = dad.gen[j+16]; for(int j=0; j<var_nr; j++) double iscross = gencross.getrand(); if(iscross <= CROSS_PROBAB) // cross draw = gencross.getrand(); // losowanie punktu podziału onepointk = 1 + int(((chrom_lenght/var_nr) - 1) * gencross.getrand()); if(draw <= 0.5) // childa for(int k=(j*8); k<(onepointk + j*8); k++) child.gen[k] = mom.gen[k]; for(int k=(onepointk + j*8); k<((j+1)*8); k++) child.gen[k] = dad.gen[k]; // childb for(int k=(j*8); k<(onepointk + j*8); k++) child.gen[k] = dad.gen[k]; for(int k=(onepointk + j*8); k<((j+1)*8); k++) child.gen[k] = mom.gen[k]; // don't cross draw = gencross.getrand(); str. 18
if(draw <= 0.5) for(int k=(j*8); k<((j+1)*8); k++) child.gen[k] = mom.gen[k]; for(int k=(j*8); k<((j+1)*8); k++) child.gen[k] = dad.gen[k]; // wygenerowany potomek wchodzi do następnej populacji // potem jeszcze bedzie podlegal mutacji tpop[popnr+1].pop[i] = child; case ct_countingminusone: for(int i=1; i<pop_size; i++) // vector przechowujący indeksy różniących się bitów potomków vector <unsigned short> vdiffind; // rodzice mom = tpop[popnr].pop[tpop[popnr].parents[i-1].mom]; dad = tpop[popnr].pop[tpop[popnr].parents[i-1].dad]; child = mom; child2 = dad; for(unsigned short j=0; j<chrom_lenght; j++) if(child.gen[j]!= child2.gen[j]) vdiffind.push_back(j); // swap unsigned short tmp; double isswap = 0; for(unsigned int j=0; j<vdiffind.size(); j++) isswap = gencross.getrand(); if(isswap <= 0.5) tmp = child2.gen[vdiffind[j]]; child2.gen[vdiffind[j]] = child.gen[vdiffind[j]]; child.gen[vdiffind[j]] = tmp; double whichchild = gencross.getrand(); // wygenerowany potomek wchodzi do następnej populacji // potem jeszcze bedzie podlegal mutacji if(whichchild <= 0.5) tpop[popnr+1].pop[i] = child; tpop[popnr+1].pop[i] = child2; case ct_evolutionoflinks: // rodzicami jest cała populacja for(int i=1; i<pop_size; i++) unsigned short fillpos = 0; unsigned short nextstartpos = 0; // pozycja wypełnienia while(fillpos < CHROM_LENGHT) fillpos += (1 + unsigned short(chrom_lenght*gencross.getrand())); // nr losowanego chromosomu unsigned short chid = unsigned short(pop_size*gencross.getrand()); for(int j=nextstartpos; j<chrom_lenght; j++) child.gen[j] = tpop[popnr].pop[chid].gen[j]; nextstartpos = j+1; str. 19
if(j == fillpos) // wygenerowany potomek wchodzi do następnej populacji // potem jeszcze bedzie podlegal mutacji tpop[popnr+1].pop[i] = child; void mutatation(int popnr) chromosom mutatedch; guni genmut; static unsigned int mutprobcnt = 0; if(mutprobcnt == 0 && muttype == mt_replacebit) cout << "Podaj prawdopodobienstwo zajscia mutacji w % (0-100) "; while(true) cin >> MUT_PROBAB; if((mut_probab < 0) (MUT_PROBAB > 100)) cout << "Zla wartosc prawdopodobienstwa! Podaj jeszcze raz: "; MUT_PROBAB /= 100; mutprobcnt++; switch(muttype) case mt_replacebit: for(int i=1; i<pop_size; i++) mutatedch = tpop[popnr+1].pop[i]; double ismutatedgen; for(int j=0; j<chrom_lenght; j++) ismutatedgen = genmut.getrand(); if(ismutatedgen <= MUT_PROBAB) if(mutatedch.gen[j] == 1) mutatedch.gen[j] = 0; mutatedch.gen[j] = 1; tpop[popnr+1].pop[i] = mutatedch; case mt_insertbit: for(int i=1; i<pop_size; i++) mutatedch = tpop[popnr+1].pop[i]; unsigned short inspoint = unsigned short(chrom_lenght*genmut.getrand()); unsigned short insbit = unsigned short(0.5 + genmut.getrand()); mutatedch.gen[inspoint] = insbit; tpop[popnr+1].pop[i] = mutatedch; case mt_remgen: for(int i=1; i<pop_size; i++) mutatedch = tpop[popnr+1].pop[i]; // ktory gen wywalić? unsigned short gen2rem = unsigned short(var_nr*genmut.getrand()); // wywalamy gen (zerujemy jego bity) str. 20
for(int j=gen2rem*8; j<((gen2rem+1)*8); j++) mutatedch.gen[j] = 0; // chromosom wraca do swojego pokolenia tpop[popnr+1].pop[i] = mutatedch; case mt_infectionvirus: for(int i=1; i<pop_size; i++) mutatedch = tpop[popnr+1].pop[i]; tpop[popnr+1].pop[i] = mutatedch; case mt_diff: case mt_imitation: const int mi = 3; chromosom worstch[mi]; vector <indfitv> tfitval; // wypełnienie wektora struktur z wartosciami funkcji dopasowania dla populacji i indeksami chromosomów for(int i=0; i<pop_size; i++) indfitv tmp; tmp.fitval = chfitfunval(tpop[popnr].pop[i]); tmp.chind = i; tfitval.push_back(tmp); //posortowanie tego wektora sort(tfitval.begin(),tfitval.end(), cond); // mi najgorszych osobników for(int i=0; i<mi; i++) worstch[i] = tpop[popnr].pop[tfitval[i].chind]; double profilevector[chrom_lenght] = ; for(int i=1; i<pop_size; i++) mutatedch = tpop[popnr+1].pop[i]; for(int j=0; j<mi; j++) for(int k=0; k<chrom_lenght; k++) if(mutatedch.gen[k]!= worstch[j].gen[k]) profilevector[k] += double(1)/double(mi); double rnd; if(muttype == mt_diff) for(int j=0; j<chrom_lenght; j++) rnd = genmut.getrand(); if(rnd < (1 - profilevector[j])) if(mutatedch.gen[j] == 1) mutatedch.gen[j] = 0; mutatedch.gen[j] = 1; if(muttype == mt_imitation) for(int j=0; j<chrom_lenght; j++) rnd = genmut.getrand(); if(rnd < profilevector[j]) if(mutatedch.gen[j] == 1) str. 21