diff --git a/Makefile b/Makefile index 3a0e14f..09ee422 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,7 @@ SOURCEFILES = cpp SRCDIR = src TMPDIR = build TARGET = gross -#FILES = Chromosome Fitness Generation main -FILES = Genes Chromosome Fitness main +FILES = Genes Chromosome Fitness Generation main #SOURCES = $(patsubst %,$(SRCDIR)/%.cpp,$(FILES)) OBJECTS = $(patsubst %,$(TMPDIR)/%.o,$(FILES)) diff --git a/src/Generation.cpp b/src/Generation.cpp index 01bc089..f87e129 100644 --- a/src/Generation.cpp +++ b/src/Generation.cpp @@ -4,10 +4,109 @@ size_t Generation::size = 500; size_t Generation::living = Generation::size*0.25; +float Generation::crossover = 0.25; Fitness* Generation::fitness; std::minstd_rand* Generation::re; +Generation::Generation() +{ + this->individuals.resize(Generation::size, {Chromosome(), 0, false, false}); +} + + +void Generation::sort() +{ + std::sort( + this->individuals.begin(), + this->individuals.end(), + [](Generation::Individual& a, Generation::Individual& b) -> bool { + if (a.alive && b.alive) { + if (a.fitnessEvaluated && b.fitnessEvaluated) { + return a.fitness < b.fitness; + } else { + return a.fitnessEvaluated; + } + } else { + return a.alive; + } + } + ); +} + + +void Generation::advance(unsigned int generations) +{ + for (unsigned int i=0; i alive: "<updateFitness(); +// std::cout << "-- sorting" << std::endl; +// debugcount + this->sort(); +// std::cout << "-- culling" << std::endl; +// debugcount + this->cull(); +// std::cout << "-- sorting" << std::endl; +// debugcount + this->sort(); +// std::cout << "-- reproducing" << std::endl; +// debugcount + this->reproduce(); +// #undef debugcount + } +} + + +void Generation::updateFitness() +{ + for (auto& individual : this->individuals) { + if (!individual.fitnessEvaluated) { + individual.fitness = Generation::fitness->of(individual.chromosome); + individual.fitnessEvaluated = true; + } + } +} + + +void Generation::cull() +{ + auto it = this->individuals.begin() + Generation::living; + for (; it!=this->individuals.end(); ++it) { + it->alive = false; + } +} + + +void Generation::reproduce() +{ + // reproduce according to parameter(s) + std::uniform_int_distribution<> alivedist(0, Generation::living-1); + std::uniform_real_distribution<> crossoverdist(0, 1); + + for (auto& individual : this->individuals) { + if (individual.alive) continue; + + auto father = this->individuals.begin() + alivedist(*Generation::re); + + if (crossoverdist(*Generation::re) < crossover) { + auto mother = this->individuals.begin() + alivedist(*Generation::re); + individual.chromosome = Chromosome(father->chromosome, mother->chromosome); + } else { + individual.chromosome = father->chromosome; + } + + individual.alive = true; + individual.fitness = 0; // technically unnecessary, but who cares + individual.fitnessEvaluated = false; + + individual.chromosome.mutate(); + } +} + + +/* Generation::Generation() { this->individuals.resize(Generation::size, {Chromosome(), 0, false, true}); @@ -95,3 +194,4 @@ void Generation::cullRoulette() { // TODO: implement this } +*/ diff --git a/src/Generation.hpp b/src/Generation.hpp index f09eb97..3c817b7 100644 --- a/src/Generation.hpp +++ b/src/Generation.hpp @@ -10,48 +10,32 @@ class Generation { public: - static size_t size; - static size_t living; - static Fitness* fitness; - static std::minstd_rand* re; - - Generation(); - - enum CullType - { - CUTOFF, - ROULETTE - }; - - void updateFitness(); - void cull(CullType algorithm=Generation::ROULETTE); - void reproduce(float crossover=0.5); // how often a child is the result of two parents, - // and not simply mutation. - struct Individual { -// Individual(Chromosome& father, Chromosome& mother) : chromosome(father, mother) {} - Chromosome chromosome; unsigned long long fitness = 0; bool fitnessEvaluated = false; bool alive = true; }; + static size_t size; // total size of generation + static size_t living; // amount of chromosomes to stay alive between generations + static float crossover; // probability for a new chromosome to have two parents + static Fitness* fitness; + static std::minstd_rand* re; + + Generation(); + + // sorts by + // 1. alive ones first + // 2. ones with fitness first + // 3. ones with lowest fitness first + void sort(); + + void advance(unsigned int generations=1); + void updateFitness(); + void cull(); + void reproduce(); + std::vector individuals; - -private: - // all of the culling algorithms can assume: - // - sorted array - // - alive flag set to true on all individuals - void cullCutoff(); - void cullRoulette(); - - // pool of Chromosomes - // sort pool? - // min/max/median - // extract stats - // calculate fitness - // cull/selection - // render full generation? No }; diff --git a/src/main.cpp b/src/main.cpp index e34324f..bd9a72b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include #include "Chromosome.hpp" #include "Fitness.hpp" +#include "Generation.hpp" int main() { @@ -12,26 +13,36 @@ int main() std::minstd_rand randomEngine; randomEngine.seed(time(nullptr)); - Chromosome::allowGeneType(Gene::Circle); - Chromosome::allowGeneType(Gene::Triangle); - Chromosome::re = &randomEngine; Gene::re = &randomEngine; + Generation::re = &randomEngine; + +// Chromosome::allowGeneType(Gene::Circle); + Chromosome::allowGeneType(Gene::Triangle); + + Generation::size = 100; + Generation::living = 10; + Generation::crossover = 0; Fitness fitn; - fitn.loadTarget("tom-face.png"); +// fitn.loadTarget("tom-face.png"); + fitn.loadTarget("firefox.png"); +// fitn.loadTarget("goldman_sachs.jpg"); fitn.loadShader("compare.glsl"); Gene::size = sf::Vector2f(fitn.target.getSize()); + Generation::fitness = &fitn; - Chromosome a; - for (int i=0; i<1000; ++i) a.mutate(); - Chromosome b(a); - for (int i=0; i<10; ++i) b.mutate(); - Chromosome c(a); - Chromosome d(a, b); + Generation gen; - std::cout << a.length() << " | " << b.length() << " | " << c.length() << " | " << d.length() << std::endl; +// Chromosome a; +// for (int i=0; i<1000; ++i) a.mutate(); +// Chromosome b(a); +// for (int i=0; i<10; ++i) b.mutate(); +// Chromosome c(a); +// Chromosome d(a, b); + +// std::cout << a.length() << " | " << b.length() << " | " << c.length() << " | " << d.length() << std::endl; sf::Sprite ts(fitn.target.getTexture()); sf::Sprite cs(fitn.chromosome.getTexture()); @@ -39,19 +50,31 @@ int main() sf::RenderWindow window(sf::VideoMode(winW, winH), "gross"); // window.setMouseCursorVisible(false); + int gencnt = 0; + while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { - if (event.type == sf::Event::KeyPressed) { - } +// if (event.type == sf::Event::KeyPressed) { +// std::cout << "Trying to advance generation" << std::endl; +// gen.advance(); +// std::cout << "Advanced generation" << std::endl; +// } } + + gen.advance(); + std::cout << "Generation: " << ++gencnt << " (length: " << gen.individuals[0].chromosome.length() << ")" << std::endl; + // display results window.clear(); - fitn.render(a); cs.setPosition( 0, 0); window.draw(cs); - fitn.render(b); cs.setPosition(240, 0); window.draw(cs); - fitn.render(c); cs.setPosition( 0, 240); window.draw(cs); - fitn.render(d); cs.setPosition(240, 240); window.draw(cs); + ts.setPosition( 0, 0); window.draw(ts); + fitn.render(gen.individuals[0].chromosome); cs.setPosition(240, 0); window.draw(cs); + fitn.render(gen.individuals[9].chromosome); cs.setPosition(240, 240); window.draw(cs); +// fitn.render(a); cs.setPosition( 0, 0); window.draw(cs); +// fitn.render(b); cs.setPosition(240, 0); window.draw(cs); +// fitn.render(c); cs.setPosition( 0, 240); window.draw(cs); +// fitn.render(d); cs.setPosition(240, 240); window.draw(cs); window.display(); // std::cout << "Generation finished: " << ++gencnt << " (winner's length: "