===== Przykład wykorzystania generate i generate_n ===== /** Bernard Fugas E1-ISIII Przykład wykorzystania szablonów generate oraz generate_n W skrócie: Szablony generate i generate_n pozwalają przypisać wartości zwracane przez bezargumentową funkcję lub obiekt funkcyjny do tablicy lub kontenera udostępniającego iterator. */ #include #include // tu jest definicja generate i generate_n #include #include "boost/random.hpp" //generator liczb losowych - użyty w przykładzie using namespace std; /** GeneticAlgorithm to klasa realizująca przykładowy algorytm genetyczny. Nie wnikamy w jego implementację. Istotne jest to, że populacja początkowa składa się nie tylko z osobników wygenerowanych losowo, ale również ze znanych "w miarę dobrych" rozwiązań zwanych "ekspertami". Szablony generate oraz generate_n pozwalają w wygodny sposób stworzyć populację początkową o zadanej procentowej ilości ekspertów. Przykłady użycia w funkcjach createGeneration0() oraz operator<<(ostream& os, const GeneticAlgorithm& ga) */ class GeneticAlgorithm { public: /** Przykładowa klasa osobnika używanego w algorytmie genetycznym */ class Individual { unsigned char chromosome_; //w rzeczywistym algorytmie byłaby to co najmniej tablica bajtów public: Individual() {} Individual(unsigned char chromosome) : chromosome_(chromosome) {} friend class GeneticAlgorithm; friend ostream& operator<<(ostream& os, const Individual& i); }; /** Obiekt funkcyjny generujący liczby pseudolosowe */ class RandomIndividualGenerator { boost::mt19937 state_; boost::uniform_int rng_; public: RandomIndividualGenerator(unsigned long state) : state_(state), rng_(0,255) {} Individual operator() (void) { return Individual( static_cast(rng_(state_)) ); } }; ////Definicje typów typedef vector Individuals; typedef vector::iterator IndividualsIt; typedef vector::const_iterator IndividualsCit; ////Metody publiczne /** @brief Konstruktor algorytmu. @param[in] population_size Rozmiar populacji @param[in] expert_percent Procent ekspertów w populacji początkowej */ GeneticAlgorithm(unsigned long seed, size_t population_size, size_t expert_percent) : rig_(seed), population_size_(population_size), expert_percent_(expert_percent) {} /** @brief Uruchamia szkielet algorytmu. */ void run(void) { bool finish_condition = false; createGeneration0(); //stwórz populację początkową while( !finish_condition ) { //korzystaj z operatorów genetycznych //selekcja, krzyżowanie, mutacja, ... //w w którejś z iteracji... finish_condition = true; } } private: /** @brief Zwraca osobników "ekspertów" - znane, dość dobre rozwiązania @return Nowy osobnik "ekspert" @note Eksperci tworzeni są zgodnie z jakąś zależnością funkcyjną. */ static Individual getExpert(void) { static unsigned char i = 0x77; ++i; return Individual(i); } /** @brief Tworzy populację początkową @note Przykład użycia generate */ void createGeneration0(void) { individuals_ = Individuals(population_size_); size_t experts_num = population_size_*expert_percent_/100; //liczba ekspertów IndividualsIt expertsEnd = individuals_.begin() + experts_num; //iterator "końca ekspertów" /************************************************************************************** void generate(_FwdIt _First, _FwdIt _Last, _Fn0 _Func) Pozwala przypisać elementom od iteratora _First (włącznie z _First) do _Last (bez _Last) kolejne wartości funkcji _Func **************************************************************************************/ //generuj ekspertów //zgodnie z zależnością funkcyjną; korzystając z funkcji generate(individuals_.begin(), expertsEnd, getExpert); //generuj losowe osobniki //losowo; korzystając z funktora generate(expertsEnd, individuals_.end(), rig_); //można sobie wyobrazić jeszcze inne rodzaje tworzonych w ten sposób osobników... } Individuals individuals_; /**< wektor osobników w populacji */ size_t population_size_; /**< rozmiar populacji */ size_t expert_percent_; /**< procentowy udział ekspertów w populacji początkowej */ RandomIndividualGenerator rig_; /**< generator losowych osobników (obiekt funkcyjny) */ friend ostream& operator<<(ostream& os, const GeneticAlgorithm& ga); friend class Individual; }; //class GeneticAlgorithm /** @brief Zaimplementowany w celu łatwego wyświetlenia rezultatu */ ostream& operator<<(ostream& os, const GeneticAlgorithm::Individual& individual) { os.setf(ios::hex, ios::basefield); os.width(2); os.fill('0'); return os << static_cast(individual.chromosome_); } /** @brief Wyświetla bieżącą populację. Dla celów dydaktycznych rozpoczyna od wyświetlenia sekwencji losowych osobników. @note Przykład użycia generate_n */ ostream& operator<<(ostream& os, const GeneticAlgorithm& ga) { /************************************************************************************** generate_n(_OutIt _Dest, _Diff _Count, _Fn0 _Func) Pozwala przypisać n elementom począwszy od _First kolejne wartości zwracane przez _Func Uwaga: tego nie da się wykonać za pomocą generate **************************************************************************************/ os << "Losowe liczby:" << endl; generate_n(ostream_iterator(os, " "), 10, ga.rig_); os << endl << "Populacja:" << endl; for(GeneticAlgorithm::IndividualsCit it=ga.individuals_.begin(); it != ga.individuals_.end(); ++it) os << *it << endl; return os; } // ================== main ================ int main(/*int argc, char** argv*/) { size_t population_size = 20; /** < całkowity rozmiar populacji */ size_t expert_percent = 10; /** < procentowa ilość ekspertów w populacji początkowej */ unsigned long seed = 0; GeneticAlgorithm ga(seed, population_size, expert_percent); //stwórz algorytm ga.run(); //i go uruchom //... cout << ga; //wyświetl populację }