- #include <cfloat>
- #include <cmath>
- #include <cstdlib>
- #include <ctime>
- #include <iostream>
- #include <vector>
- #include "rmath.h"
- using namespace std;
- #define POPULATION 50
- #define CHROMOSOMES 2
- #define MUTATE_AMOUNT 0.9
- #define MUTATE_PROBABILITY 0.9
- #define RANGE_LOWER 10
- #define RANGE_UPPER 100
- #define THRESHOLD 0.01
- #define VARIABLE_MUTATION
- #define MUTATION_EPOCH 4000
- double fitness(vector<double> *data) {
- return (1 + pow((
- pow(
- (data->at(0) - 0.2)
- ,2)
- +
- pow(
- (data->at(1) - 0.1)
- ,2)
- ),0.25) - cos(5 * 3.1415926535897932384626433832795 * sqrt(
- pow(
- (data->at(0) - 0.2)
- ,2)
- +
- pow(
- (data->at(1) - 0.1)
- ,2)
- )
- ));
- }
- class set {
- public:
- vector<double> data;
- double eval;
- //CONSTRUCTOR
- set(int n_data) {
- data.reserve(n_data);
- for (int i=0;i<n_data;i++) {
- data.push_back(RANGE_LOWER + (random(RANGE_UPPER - RANGE_LOWER)));
- }
- eval = 0;
- }
- //DESTRUCTOR
- ~set() {}
- //FUNCTIONS
- };
- class population {
- public:
- vector<set> sets;
- vector<set> sets2;
- double mutation;
- double mutation_probability;
- //CONSTRUCTOR
- population(int n_sets,int n_data, double mutation = 0.2, double mutation_probability = 0.05) {
- sets.reserve(n_sets);
- sets2.reserve(n_sets);
- this->mutation = mutation;
- this->mutation_probability = mutation_probability;
- for (int i=0;i<n_sets;i++) {
- sets.push_back(set(n_data));
- sets2.push_back(set(n_data));
- }
- }
- //DESTRUCTOR
- ~population() {}
- //FUNCTIONS
- void crossover(int a, int b, int c) {
- int count = sets2[c].data.size();
- int divider = count / 2;
- for (int i=0;i<divider;i++) {
- sets2[c].data[i] = sets[a].data[i];
- sets2[c].data[i+divider] = sets[b].data[i+divider];
- }
- if (count % 2 != 0) {
- sets2[c].data.back() = sets[b].data.back();
- }
- return;
- }
- void mutate(int a) {
- for (unsigned int i=0;i<sets[a].data.size();i++) {
- sets[a].data[i] += random(mutation);
- }
- return;
- }
- double evaluate() {
- double sum = 0;
- for (unsigned int i=0;i<sets.size();i++) {
- sets[i].eval = fitness(&sets[i].data) + DBL_MIN;
- sum += 1 / sets[i].eval;
- }
- return sum;
- }
- void evolve() {
- double sum = evaluate();
- for (unsigned int i=0;i<sets.size();i++) {
- crossover(findparent(sum),findparent(sum),i);
- if (urandom() < mutation_probability) {
- mutate(i);
- }
- }
- sets.swap(sets2);
- evaluate();
- return;
- }
- int findparent(double sum) {
- double rand = urandom(sum);
- sum = 0;
- for (unsigned int i=0;i<sets.size();i++) {
- sum += 1 / sets[i].eval;
- if (rand < sum) {
- return i;
- }
- }
- return (int)(urandom(sets.size()-1));
- }
- int findbest() {
- int index = 0;
- double min = sets[0].eval;
- for (unsigned int i=1;i<sets.size();i++) {
- if (sets[i].eval < min) {
- min = sets[i].eval;
- index = i;
- }
- }
- return index;
- }
- double average() {
- double sum = 0;
- for (unsigned int i=0;i<sets.size();i++) {
- sum += sets[i].eval;
- }
- return (sum/sets.size());
- }
- };
- void print(population *evo, int iterations) {
- cout << "\nFitness (Average): " << evo->average();
- cout << "\nFitness (Elite): " << evo->sets[evo->findbest()].eval;
- cout << "\nChromosomes (Elite) : [";
- for (int i=0;i<CHROMOSOMES;i++) {
- cout << " " << evo->sets[evo->findbest()].data[i] << ",";
- }
- cout << "]";
- cout << "\nIterations : " << iterations;
- return;
- };
- int main() {
- srand ((unsigned)time(NULL));
- /* INIT SETTINGS */
- population evo(POPULATION,CHROMOSOMES,MUTATE_AMOUNT,MUTATE_PROBABILITY);
- /* TRAIN UNTIL THRESHOLD */
- evo.evaluate();
- int i=0;
- while (evo.sets[evo.findbest()].eval > THRESHOLD) {
- evo.evolve();
- i++;
- #ifdef VARIABLE_MUTATION
- if (i % MUTATION_EPOCH == 0) {
- print(&evo,i);
- evo.mutation = urandom(evo.average());
- evo.mutation_probability = urandom(evo.average());
- }
- #endif
- }
- /* POST RESULTS */
- cout << "\n ---- RESULTS ----";
- print(&evo,i);
- cout << "\n";
- system("pause");
- return 0;
- }