Reimplement and test Generation
This commit is contained in:
parent
c10a12f29c
commit
5c10ba4a78
4 changed files with 160 additions and 54 deletions
3
Makefile
3
Makefile
|
|
@ -9,8 +9,7 @@ SOURCEFILES = cpp
|
||||||
SRCDIR = src
|
SRCDIR = src
|
||||||
TMPDIR = build
|
TMPDIR = build
|
||||||
TARGET = gross
|
TARGET = gross
|
||||||
#FILES = Chromosome Fitness Generation main
|
FILES = Genes Chromosome Fitness Generation main
|
||||||
FILES = Genes Chromosome Fitness main
|
|
||||||
|
|
||||||
#SOURCES = $(patsubst %,$(SRCDIR)/%.cpp,$(FILES))
|
#SOURCES = $(patsubst %,$(SRCDIR)/%.cpp,$(FILES))
|
||||||
OBJECTS = $(patsubst %,$(TMPDIR)/%.o,$(FILES))
|
OBJECTS = $(patsubst %,$(TMPDIR)/%.o,$(FILES))
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,109 @@
|
||||||
|
|
||||||
size_t Generation::size = 500;
|
size_t Generation::size = 500;
|
||||||
size_t Generation::living = Generation::size*0.25;
|
size_t Generation::living = Generation::size*0.25;
|
||||||
|
float Generation::crossover = 0.25;
|
||||||
Fitness* Generation::fitness;
|
Fitness* Generation::fitness;
|
||||||
std::minstd_rand* Generation::re;
|
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<generations; ++i) {
|
||||||
|
// #define debugcount {int alive=0,fitness=0;for(auto&i:individuals){i.alive?++alive:1;i.fitnessEvaluated?++fitness:1;}std::cout<<" -> alive: "<<alive<<", fitness: "<<fitness<<std::endl;}
|
||||||
|
// std::cout << "-- updating fitness" << std::endl;
|
||||||
|
// debugcount
|
||||||
|
this->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()
|
Generation::Generation()
|
||||||
{
|
{
|
||||||
this->individuals.resize(Generation::size, {Chromosome(), 0, false, true});
|
this->individuals.resize(Generation::size, {Chromosome(), 0, false, true});
|
||||||
|
|
@ -95,3 +194,4 @@ void Generation::cullRoulette()
|
||||||
{
|
{
|
||||||
// TODO: implement this
|
// TODO: implement this
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -10,48 +10,32 @@
|
||||||
class Generation
|
class Generation
|
||||||
{
|
{
|
||||||
public:
|
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
|
struct Individual
|
||||||
{
|
{
|
||||||
// Individual(Chromosome& father, Chromosome& mother) : chromosome(father, mother) {}
|
|
||||||
|
|
||||||
Chromosome chromosome;
|
Chromosome chromosome;
|
||||||
unsigned long long fitness = 0;
|
unsigned long long fitness = 0;
|
||||||
bool fitnessEvaluated = false;
|
bool fitnessEvaluated = false;
|
||||||
bool alive = true;
|
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<Individual> individuals;
|
std::vector<Individual> 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
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
57
src/main.cpp
57
src/main.cpp
|
|
@ -4,6 +4,7 @@
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
#include "Chromosome.hpp"
|
#include "Chromosome.hpp"
|
||||||
#include "Fitness.hpp"
|
#include "Fitness.hpp"
|
||||||
|
#include "Generation.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|
@ -12,26 +13,36 @@ int main()
|
||||||
std::minstd_rand randomEngine;
|
std::minstd_rand randomEngine;
|
||||||
randomEngine.seed(time(nullptr));
|
randomEngine.seed(time(nullptr));
|
||||||
|
|
||||||
Chromosome::allowGeneType(Gene::Circle);
|
|
||||||
Chromosome::allowGeneType(Gene::Triangle);
|
|
||||||
|
|
||||||
Chromosome::re = &randomEngine;
|
Chromosome::re = &randomEngine;
|
||||||
Gene::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;
|
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");
|
fitn.loadShader("compare.glsl");
|
||||||
|
|
||||||
Gene::size = sf::Vector2f(fitn.target.getSize());
|
Gene::size = sf::Vector2f(fitn.target.getSize());
|
||||||
|
Generation::fitness = &fitn;
|
||||||
|
|
||||||
Chromosome a;
|
Generation gen;
|
||||||
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;
|
// 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 ts(fitn.target.getTexture());
|
||||||
sf::Sprite cs(fitn.chromosome.getTexture());
|
sf::Sprite cs(fitn.chromosome.getTexture());
|
||||||
|
|
@ -39,19 +50,31 @@ int main()
|
||||||
sf::RenderWindow window(sf::VideoMode(winW, winH), "gross");
|
sf::RenderWindow window(sf::VideoMode(winW, winH), "gross");
|
||||||
// window.setMouseCursorVisible(false);
|
// window.setMouseCursorVisible(false);
|
||||||
|
|
||||||
|
int gencnt = 0;
|
||||||
|
|
||||||
while (window.isOpen()) {
|
while (window.isOpen()) {
|
||||||
sf::Event event;
|
sf::Event event;
|
||||||
while (window.pollEvent(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
|
// display results
|
||||||
window.clear();
|
window.clear();
|
||||||
fitn.render(a); cs.setPosition( 0, 0); window.draw(cs);
|
ts.setPosition( 0, 0); window.draw(ts);
|
||||||
fitn.render(b); cs.setPosition(240, 0); window.draw(cs);
|
fitn.render(gen.individuals[0].chromosome); cs.setPosition(240, 0); window.draw(cs);
|
||||||
fitn.render(c); cs.setPosition( 0, 240); window.draw(cs);
|
fitn.render(gen.individuals[9].chromosome); cs.setPosition(240, 240); window.draw(cs);
|
||||||
fitn.render(d); 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();
|
window.display();
|
||||||
|
|
||||||
// std::cout << "Generation finished: " << ++gencnt << " (winner's length: "
|
// std::cout << "Generation finished: " << ++gencnt << " (winner's length: "
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue