W ostatnim poście nieco przybliżyłem teorię jeżeli chodzi o selekcję chromosomów do kolejnych generacji w algorytmach genetycznych. Tym razem zobaczymy jak będzie wyglądała sama implementacja selekcji w easyGALib.

W tym tygodniu pora na nadrabianie i trzy posty w ramach #dajsiepoznac, więc trzeba nieco podkręcić tempo prac. Ostatnio przeanalizowaliśmy temat selekcji, więc już mniej więcej wiadomo co w trawie piszczy – naszym zadaniem jest znaleźć chromosomy, na bazie których zostanie utworzone kolejne pokolenie królików doświadczalnych.

Implementacja selekcji w easyGALib

Cały czas działamy wokół serca biblioteki i oczywiście w klasie GABase znajdziemy metodę odpowiadającą za selekcję chromosomów – SelectChromosomes. Bez zbędnego gadania jej kod wygląda tak:

private void SelectChromosomes()
{
    //Elitism - best chromosome always go to the next generation
    NextGeneration.Add(BestChromosome.CreateCopy());

    for (int i = 0; i < _input.Parameters.ChromosomesQuantity; i++)
    {
        var chromosome = FindChromosome();
        NextGeneration.Add(chromosome.CreateCopy());
    }
}

Po pierwsze, stosujemy elitaryzm, czyli zawsze na wstępie najlepszy chromosom od razu przerzucamy do nowej generacji. Następnie tyle razy ile zmieści się w naszej populacji, losujemy szczęśliwego osobnika, który będzie podstawą tworzenia nowego pokolenia. Jak wygląda wnętrze metody losującej?

private IChromosome FindChromosome()
{
    Random rdm = new Random();
    bool found = false;
    int index = -1;

    while (!found)
    {
        index = rdm.Next(0, _input.Parameters.ChromosomesQuantity - 1);

        //We should give some random selection chance by parameter
        if (_input.Parameters.RandomSelectionChance > rdm.Next(0, 100))
        {
            found = true;
        }
        else if (CurrentGeneration[index].FitnessRank > rdm.Next(0, 100)) //Better chromosome = bigger chance to go to the next generation
        {
            found = true;
        }
    }

    return CurrentGeneration[index];
}

Względem poprzedniego opisu wprowadziłem tu mały dodatek, a mianowicie parametr, którym na wejściu algorytmu będziemy mogli sterować losowość wybieranych chromosomów. Po pierwsze więc jest sprawdzane, czy dzięki temu parametrowi wylosowany właśnie chromosom przejdzie do następnego pokolenia, a jeżeli nie, to tradycyjnie stosujemy metodę ruletki. FitnessRank będzie oznaczać udział dopasowania danego osobnika w stosunku do całej populacji (procentowo). Im lepiej będzie dopasowany, tym większa szansa, że wylosujemy akurat jego. Nie decydowałem się tutaj jeszcze na metodę rankingową, aby uprościć zrozumienie działania biblioteki. Myślę że wprowadzony dodatkowy parametr zniweluje problem przewagi jednego chromosomu nad resztą populacji.


Tym sposobem w miarę bezboleśnie przeszliśmy przez temat selekcji chromosomów. Oczywiście w dużej części kodu jeszcze stosuję zaślepki, ale cały czas uzupełniane są kolejne metody, więc praca idzie do przodu i nie mogę się doczekać pierwszego uruchomienia biblioteki, chociaż do tego jeszcze trochę brakuje. Idziemy jednak konsekwentnie ścieżką algorytmu i następnym razem zajmiemy się krzyżowaniem chromosomów!