Created
January 30, 2018 12:08
-
-
Save FONQRI/856f1943fd5857752e5722b866e6ff85 to your computer and use it in GitHub Desktop.
Little example of how genetic algorithms can work in c++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <chrono> | |
#include <cmath> | |
#include <iostream> | |
#include <thread> | |
#include <time.h> | |
#include <vector> | |
// lets create a population | |
struct Member { | |
std::string DNA; | |
size_t Fitness; | |
}; | |
struct Population { | |
// this will create a population with 50k | |
// members, lets choose a lower number first | |
// to see the progress, works fine... | |
std::vector<Member> Members = std::vector<Member>(5000); | |
}; | |
int main() | |
{ | |
// for this example we are going to use a string as a kind of "goal" to | |
// achieve | |
std::string DNA = | |
"I am a DNA string that needs to be found, shall happen soon!"; | |
bool sequenceFound{false}; | |
std::string sequenceString{""}; | |
// We are going to use this for mutation of genes | |
// 1000 = 100% 1 = .01% mutation rate | |
int mutationRate{25}; | |
srand(static_cast<unsigned int>(time(NULL))); | |
// create a population and initialize it with random DNA, also set the | |
// fitness to 0 | |
Population Pop; | |
for (auto &member : Pop.Members) { | |
member.DNA.resize(DNA.size()); | |
for (size_t j = 0; j < DNA.size(); j++) { | |
member.DNA.at(j) = | |
static_cast<char>(std::abs(rand() % 96 + 32)); | |
} | |
member.Fitness = 0; | |
} | |
std::clog << "initializing done !" << std::endl; | |
// we will use a variable to keep track of how many generations there have | |
// been | |
int generation = 0; | |
// our actuall work will be inside this loop, it will stop when the DNA | |
// sequence has fully evolved to the target | |
while (!sequenceFound) { | |
generation++; | |
// clear out the fitness here and then reevaluate for each | |
// member, also check if fitness has reached maximum | |
for (auto &member : Pop.Members) { | |
member.Fitness = 0; | |
for (size_t j = 0; j < member.DNA.size(); j++) { | |
if (member.DNA.at(j) == DNA.at(j)) { | |
member.Fitness += 10; | |
} | |
} | |
if (member.Fitness == DNA.size() * 10) | |
sequenceFound = true; | |
sequenceString = member.DNA; | |
} | |
// now lets sort the population by fitness, from highest to lowest | |
std::sort(Pop.Members.begin(), Pop.Members.end(), | |
[](Member const &a, Member &b) { | |
return a.Fitness > b.Fitness; | |
}); | |
// select x amount of highest fitness members to pair from, lets use | |
// 2 parents in this case | |
std::vector<Member> Parents{Pop.Members.at(0), Pop.Members.at(1)}; | |
// lets do some gene permutation and mating | |
for (auto &member : Pop.Members) { | |
for (size_t j = 0; j < member.DNA.size(); j++) { | |
// lets use an equal chance to take each parents | |
// gene (on a per gene basis) | |
size_t TempSelection = static_cast<size_t>( | |
static_cast<size_t>(rand()) % Parents.size()); | |
member.DNA.at(j) = | |
Parents.at(TempSelection).DNA.at(j); | |
// dont forget to apply random mutation based on | |
// our value from above | |
if (rand() % 1000 < mutationRate) { | |
member.DNA.at(j) = static_cast<char>( | |
std::abs(rand() % 96 + 32)); | |
} | |
} | |
} | |
// lets print some stuff | |
std::cout << "generation : " << generation | |
<< " Highest Fitness : " << Parents.at(0).Fitness | |
<< " With Sequence : " << Parents.at(0).DNA.c_str() | |
<< std::endl; | |
} | |
std::cout << "generation " << generation << " Evolved to the full sequence" | |
<< std::endl; | |
std::cout << "sequenceFound :" << sequenceFound << std::endl; | |
std::cout << "sequence DNA :" << sequenceString << std::endl; | |
return 0; | |
} | |
// done... :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment