Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neural evolution algorithms implementation (CNE, NEAT, HyperNEAT) #686

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
dc27518
change .gitignore to ignore .DS_Store
BangLiu May 17, 2016
88788d6
create gene.hpp, add ne_test.cpp, and created or modified multiple CM…
BangLiu May 20, 2016
6ab9add
Created gene.happ, add tests and changed or created CMakeLists.txt
BangLiu May 20, 2016
ca73f95
Add aDepth to NeuronGene.
BangLiu May 20, 2016
30ec0ba
implement CNE, haven't finish.
BangLiu May 28, 2016
7fdd7ca
delete blank files
BangLiu May 28, 2016
e4fbabd
finished genome.hpp, revised gene.hpp
BangLiu Jun 7, 2016
3c8aa62
modified gene.hpp
BangLiu Jun 7, 2016
cbb79a2
implemented CNE skeleton; more genome and population functions.
BangLiu Jun 9, 2016
65f093d
implemented XOR test case; need debugging; one heart function -- CNE:…
BangLiu Jun 10, 2016
eb16ce2
solved most bugs for testing XOR
BangLiu Jun 11, 2016
c6976ac
further solved some bugs in code.
BangLiu Jun 11, 2016
8919bb9
Solved bugs. Need to fulfill Reproduce() to finish CNE.
BangLiu Jun 12, 2016
ee548b6
CNE algorithm finished. XOR test passes. Need to revise coding style …
BangLiu Jun 12, 2016
faf47a2
Create Species class.
BangLiu Jun 19, 2016
adc45b2
Revised LinkGene and related file for NEAT
BangLiu Jun 20, 2016
95c2e53
revised sortSpecies()
BangLiu Jun 21, 2016
1ee07a0
add aAdjustedFitness to genome
BangLiu Jun 21, 2016
39ef07b
fix bug in CNE Reproduce()
BangLiu Jun 21, 2016
74fb4a0
Implemented neat mutations, replace size_t by ssize_t
BangLiu Jun 24, 2016
d0883f4
Implemented crossover, some bug exist
BangLiu Jun 26, 2016
a605eef
Revise Crossover, solve bugs, more functions implementations.
BangLiu Jun 26, 2016
e059af0
revised neat functions. In paper,disabled links also consider for cro…
BangLiu Jun 27, 2016
6c11f32
neat almost finished. Need debugging,need revise coding style, need t…
BangLiu Jun 28, 2016
3c10995
NEAT finished, but has bugs. XOR not pass.
BangLiu Jun 29, 2016
57d4165
In progress of debugging. Add lots of printf ... Will clear them afte…
BangLiu Jun 30, 2016
6a770ec
seems bugs solved. keep printf. Seems information such as species siz…
BangLiu Jun 30, 2016
cce115b
solve more bugs
BangLiu Jun 30, 2016
2a9899c
solved more. But still have problem.
BangLiu Jun 30, 2016
1a2cfd8
solved CalcAverageRank bug. Still have more.
BangLiu Jun 30, 2016
dacc2e6
currently seems no bug. Previously we removed stale species even when…
BangLiu Jun 30, 2016
2a4c715
revised WeightDiff
BangLiu Jun 30, 2016
6f901a1
Removed redundant members in species, population. haven't remove in g…
BangLiu Jul 1, 2016
a80f5f7
Further cleaned some code.
BangLiu Jul 1, 2016
3db85fd
changed the place where we should set the childGenome's NumInput, Num…
BangLiu Jul 1, 2016
8168779
changed neuron_gene, genome's activation. Still need to revise neat.
BangLiu Jul 2, 2016
554a279
Revised MutateAddLink.
BangLiu Jul 2, 2016
1fe7d73
solved some bugs about activation.
BangLiu Jul 7, 2016
ff45785
Add Cart Pole test. Result not good. Fitness doesn't improve.
BangLiu Jul 10, 2016
48e15c4
Solved more bugs.
BangLiu Jul 13, 2016
fc982b9
Fixed a bug in task. Removed adjustFitness. Problems maybe the parame…
BangLiu Jul 16, 2016
66b0f41
further revised something.
BangLiu Jul 17, 2016
109f05b
Passed Cart Pole problem. Revised neat, task.
BangLiu Jul 20, 2016
8054f00
Implemented test MountainCar, not pass yet.
BangLiu Jul 21, 2016
5ef61fe
Seems passed Mountain Car.. in 1 iteration
BangLiu Jul 21, 2016
f213dd8
Revised a bug in TaskMountainCar Action()
BangLiu Jul 21, 2016
f234ebd
added Success() for tasks.
BangLiu Jul 21, 2016
96ccef5
Finished double pole. Non-Markov have bug.
BangLiu Aug 3, 2016
24f9baf
revised non-markov, still have bug
BangLiu Aug 3, 2016
4decb0e
revised neat MutateAddLink. Non-Markov still have bug.
BangLiu Aug 3, 2016
c46436e
revised neat, clean genome before evaluate.
BangLiu Aug 4, 2016
000d6aa
Merge pull request #1 from mlpack/master
BangLiu Aug 5, 2016
2599077
revised a bug in Activate()
BangLiu Aug 5, 2016
408b40f
fix conflict
BangLiu Aug 5, 2016
0fc792c
changed header file in ne_test
BangLiu Aug 5, 2016
847db95
solved compile bug
BangLiu Aug 5, 2016
10b99ab
change ssize_t, size_t to int. Windows doesn't support ssize_t
BangLiu Aug 6, 2016
da55507
revised comment style, bracket style etc. Have strange compile error.
BangLiu Aug 8, 2016
beb8ba8
rebuild, solved compile problem. Add default constructors back. Witho…
BangLiu Aug 8, 2016
3b66431
Revised the style of all current code
BangLiu Aug 10, 2016
9480379
revised some tiny styles
BangLiu Aug 11, 2016
4483fc8
Revised NeuronGene to add aCoordinate. Tests all previous testings an…
BangLiu Aug 13, 2016
190e639
Revised neat.hpp. NeuronInnovation considers activation function type…
BangLiu Aug 13, 2016
4cd0054
Implemented first version of Hyperneat.
BangLiu Aug 15, 2016
668fa6e
revised HyperNEAT. No inheritance.
BangLiu Aug 16, 2016
62d5885
Solved bugs. Implemented XOR test. Not pass. Need debug.
BangLiu Aug 16, 2016
e176571
in the progress of debugging XOR test
BangLiu Aug 18, 2016
dec32ac
Find important bug in Activate()! revised. Still not pass hyperneat xor.
BangLiu Aug 19, 2016
bc178c3
small change.
BangLiu Aug 19, 2016
432331b
Solved the duplicated link bug. Changed MutateAddNeuron. Still not pa…
BangLiu Aug 21, 2016
0944516
Make the new neuron type random when add new neuron. Still not pass xor.
BangLiu Aug 26, 2016
d66bb14
Revised naming style
BangLiu Aug 29, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/mlpack/methods/ne/genome.hpp
Expand Up @@ -377,6 +377,18 @@ class Genome {
// TODO: check this works well.
}

// Add link.
void AddLink(LinkGene& linkGene) {
aLinkGenes.push_back(linkGene);
}

// Add neuron.
void AddHiddenNeuron(NeuronGene& neuronGene) {
if (neuronGene.Type() == HIDDEN) {
aNeuronGenes.push_back(neuronGene);
}
}

// TODO: More potential operators to search genome.


Expand Down
234 changes: 173 additions & 61 deletions src/mlpack/methods/ne/neat.hpp
Expand Up @@ -107,6 +107,7 @@ class NEAT {
}

// Mutate: add new link to genome.
// TODO: what if created looped link? It will influence the depth calculation in genome class!!
void MutateAddLink(Genome& genome, double mutateAddLinkProb) {
// Whether mutate or not.
double p = mlpack::math::Random();
Expand Down Expand Up @@ -135,7 +136,7 @@ class NEAT {
aLinkInnovations[innovIdx].newLinkInnovId,
mlpack::math::RandNormal(0, 1), // TODO: make the distribution an argument for control?
true);
genome.aLinkGenes.push_back(linkGene);
genome.AddLink(linkGene);
return;
}

Expand All @@ -146,7 +147,7 @@ class NEAT {
linkInnov.newLinkInnovId,
mlpack::math::RandNormal(0, 1), // TODO: make the distribution an argument for control?
true);
genome.aLinkGenes.push_back(linkGene);
genome.AddLink(linkGene);
}

// Mutate: add new neuron to genome.
Expand All @@ -173,7 +174,7 @@ class NEAT {
SIGMOID, // TODO: make it random??
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NEAT doesn't change the activation function, but it could be interesting to see if that would increase the performance. However, we have to find a good way, to abstract that functionality from the rest of the code. I think, it's good for now to go with a static activation function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree.

0,
0);
genome.aNeuronGenes.push_back(neuronGene);
genome.AddHiddenNeuron(neuronGene);

LinkGene inputLink(genome.aLinkGenes[linkIdx].FromNeuronId(),
aNeuronInnovations[innovIdx].newNeuronId,
Expand All @@ -185,8 +186,8 @@ class NEAT {
aNeuronInnovations[innovIdx].newOutputLinkInnovId,
genome.aLinkGenes[linkIdx].Weight(),
true);
genome.aLinkGenes.push_back(inputLink);
genome.aLinkGenes.push_back(outputLink);
genome.AddLink(inputLink);
genome.AddLink(outputLink);
return;
}

Expand All @@ -198,7 +199,7 @@ class NEAT {
SIGMOID, // TODO: make it random??
0,
0);
genome.aNeuronGenes.push_back(neuronGene);
genome.AddHiddenNeuron(neuronGene);

LinkGene inputLink(genome.aLinkGenes[linkIdx].FromNeuronId(),
neuronInnov.newNeuronId,
Expand All @@ -210,114 +211,213 @@ class NEAT {
neuronInnov.newOutputLinkInnovId,
genome.aLinkGenes[linkIdx].Weight(),
true);
genome.aLinkGenes.push_back(inputLink);
genome.aLinkGenes.push_back(outputLink);
genome.AddLink(inputLink);
genome.AddLink(outputLink);
}

// Crossover link weights.
void Crossover(Genome& momGenome, Genome& dadGenome, Genome& childGenome) {
// Figure out which is the better genome.
Genome* g1 = NULL; // Save the better one.
Genome* g2 = NULL;
if (momGenome.Fitness() < dadGenome.Fitness()) { // NOTICE: we assume smaller is better.
g1 = &momGenome;
g2 = &dadGenome;
} else if (dadGenome.Fitness() < momGenome.Fitness()) {
g1 = &dadGenome;
g2 = &momGenome;
} else if (momGenome.NumLink() < dadGenome.NumLink()) {
g1 = &momGenome;
g2 = &dadGenome;
} else if (dadGenome.NumLink() < momGenome.NumLink()) {
g1 = &dadGenome;
g2 = &momGenome;
} else if (mlpack::math::Random() < 0.5) {
g1 = &momGenome;
g2 = &dadGenome;
} else {
g1 = &dadGenome;
g2 = &momGenome;
}

// NOTICE: assume momGenome is the better genome.
// NOTICE: assume childGenome is empty.
void CrossoverLinkAndNeuron(Genome& momGenome, Genome& dadGenome, Genome& childGenome) {
// Add input and output neuron genes to child genome.
for (ssize_t i=0; i<(g1->NumInput() + g1->NumOutput()); ++i) {
childGenome.aNeuronGenes.push_back(g1->aNeuronGenes[i]);
for (ssize_t i=0; i<(momGenome.NumInput() + momGenome.NumOutput()); ++i) {
childGenome.aNeuronGenes.push_back(momGenome.aNeuronGenes[i]);
}

// Iterate to add link genes and neuron genes to child genome.
for (ssize_t i=0; i<g1->NumLink(); ++i) {
ssize_t innovId = g1->aLinkGenes[i].InnovationId();
ssize_t idx = g2->GetLinkIndex(innovId);
for (ssize_t i=0; i<momGenome.NumLink(); ++i) {
ssize_t innovId = momGenome.aLinkGenes[i].InnovationId();
ssize_t idx = dadGenome.GetLinkIndex(innovId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the names of the genomes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!


if (idx == -1 && g1->aLinkGenes[i].Enabled()) { // exceed or not match
childGenome.aLinkGenes.push_back(g1->aLinkGenes[i]);
if (idx == -1 && momGenome.aLinkGenes[i].Enabled()) { // exceed or disjoint
childGenome.AddLink(momGenome.aLinkGenes[i]);

// Add from neuron
ssize_t idxInChild = childGenome.GetNeuronIndex(g1->aLinkGenes[i].FromNeuronId());
ssize_t idxInParent = g1->GetNeuronIndex(g1->aLinkGenes[i].FromNeuronId());
ssize_t idxInChild = childGenome.GetNeuronIndex(momGenome.aLinkGenes[i].FromNeuronId());
ssize_t idxInParent = momGenome.GetNeuronIndex(momGenome.aLinkGenes[i].FromNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g1->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(momGenome.aNeuronGenes[idxInParent]);
}

// Add to neuron
idxInChild = childGenome.GetNeuronIndex(g1->aLinkGenes[i].ToNeuronId());
idxInParent = g1->GetNeuronIndex(g1->aLinkGenes[i].ToNeuronId());
idxInChild = childGenome.GetNeuronIndex(momGenome.aLinkGenes[i].ToNeuronId());
idxInParent = momGenome.GetNeuronIndex(momGenome.aLinkGenes[i].ToNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g1->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(momGenome.aNeuronGenes[idxInParent]);
}

continue;
}

if (idx != -1 && g1->aLinkGenes[i].Enabled() && mlpack::math::Random() < 0.5) {
childGenome.aLinkGenes.push_back(g1->aLinkGenes[i]);
if (idx != -1 && momGenome.aLinkGenes[i].Enabled() && mlpack::math::Random() < 0.5) {
childGenome.AddLink(momGenome.aLinkGenes[i]);

// Add from neuron
ssize_t idxInChild = childGenome.GetNeuronIndex(g1->aLinkGenes[i].FromNeuronId());
ssize_t idxInParent = g1->GetNeuronIndex(g1->aLinkGenes[i].FromNeuronId());
ssize_t idxInChild = childGenome.GetNeuronIndex(momGenome.aLinkGenes[i].FromNeuronId());
ssize_t idxInParent = momGenome.GetNeuronIndex(momGenome.aLinkGenes[i].FromNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g1->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(momGenome.aNeuronGenes[idxInParent]);
}

// Add to neuron
idxInChild = childGenome.GetNeuronIndex(g1->aLinkGenes[i].ToNeuronId());
idxInParent = g1->GetNeuronIndex(g1->aLinkGenes[i].ToNeuronId());
idxInChild = childGenome.GetNeuronIndex(momGenome.aLinkGenes[i].ToNeuronId());
idxInParent = momGenome.GetNeuronIndex(momGenome.aLinkGenes[i].ToNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g1->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(momGenome.aNeuronGenes[idxInParent]);
}

continue;
}

if (idx != -1 && g1->aLinkGenes[i].Enabled() && mlpack::math::Random() >= 0.5) {
childGenome.aLinkGenes.push_back(g2->aLinkGenes[idx]);
if (idx != -1 && momGenome.aLinkGenes[i].Enabled() && mlpack::math::Random() >= 0.5) {
childGenome.AddLink(dadGenome.aLinkGenes[idx]);

// Add from neuron TODO: make it a function?? check whether crossover is correct.
ssize_t idxInChild = childGenome.GetNeuronIndex(g2->aLinkGenes[idx].FromNeuronId());
ssize_t idxInParent = g2->GetNeuronIndex(g2->aLinkGenes[idx].FromNeuronId());
ssize_t idxInChild = childGenome.GetNeuronIndex(dadGenome.aLinkGenes[idx].FromNeuronId());
ssize_t idxInParent = dadGenome.GetNeuronIndex(dadGenome.aLinkGenes[idx].FromNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g2->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(dadGenome.aNeuronGenes[idxInParent]);
}

// Add to neuron
idxInChild = childGenome.GetNeuronIndex(g2->aLinkGenes[idx].ToNeuronId());
idxInParent = g2->GetNeuronIndex(g2->aLinkGenes[idx].ToNeuronId());
idxInChild = childGenome.GetNeuronIndex(dadGenome.aLinkGenes[idx].ToNeuronId());
idxInParent = dadGenome.GetNeuronIndex(dadGenome.aLinkGenes[idx].ToNeuronId());
if (idxInChild == -1) {
childGenome.aNeuronGenes.push_back(g2->aNeuronGenes[idxInParent]);
childGenome.AddHiddenNeuron(dadGenome.aNeuronGenes[idxInParent]);
}

continue;
}
}
}

void Crossover(Genome& genome1, Genome& genome2, Genome& childGenome) {
if (Species::CompareGenome(genome1, genome2)) { // genome1 is better
CrossoverLinkAndNeuron(genome1, genome2, childGenome);
} else {
CrossoverLinkAndNeuron(genome2, genome1, childGenome);
}
}

// Measure two genomes' disjoint (including exceed).
// TODO: we can seperate into disjoint and exceed.
// But currently maybe it is enough.
double Disjoint(Genome& genome1, Genome& genome2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it should work for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let us distinguish between disjoint and excess here. At the same time, we can decrease the runtime, by not looping over the genomes twice:

size_t disjoint = 0;
size_t excess = 0;

if (genome1.NumLink() >= genome2.NumLink())
{
    DisjointExcess(genome1, genome2, disjoint, excess);
}
else
{
    DisjointExcess(genome2, genome1, disjoint, excess);
}


void DisjointExcess(Genome& genome1, Genome& genome2, size_t& disjoint, size_t& excess, size_t& matching)
{
    size_t maxInovation = genome2.GetMaxInnovation();

    for (size_t i = 0; i < genome1.NumLink(); ++i)
    {
        size_t innovationNumber = genome1.aLinkGenes[i].InnovationId();

        if (!genome2.ContainLink(innovId))
        {
            if (innovationNumber > maxInovation)
            {
                excess += 1;
            }
            else
            {
                disjoint += 1;
            }
        }
        else
        {
            matching += 1;
        }
    }

    disjoint += genome2.NumLink() - matching;
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to change this after NEAT passed Cart Pole problem. As I saw multiple implementations that the parameters for Exceed and Disjoint are the same. Thus, we can keep the current function for now and it won't influence the performance. After that, it can easily be changed.

double numDisjoint = 0;

for (ssize_t i=0; i<genome1.NumLink(); ++i) {
ssize_t innovId = genome1.aLinkGenes[i].InnovationId();
ssize_t idx = genome2.GetLinkIndex(innovId);
if (idx == -1 && genome1.aLinkGenes[i].Enabled()) {
++numDisjoint;
}
}

for (ssize_t i=0; i<genome2.NumLink(); ++i) {
ssize_t innovId = genome2.aLinkGenes[i].InnovationId();
ssize_t idx = genome1.GetLinkIndex(innovId);
if (idx == -1 && genome2.aLinkGenes[i].Enabled()) {
++numDisjoint;
}
}

ssize_t largerGenomeSize = std::max(genome1.NumLink(), genome2.NumLink());
double deltaD = numDisjoint / largerGenomeSize;
return deltaD;
}

// Measure two genomes' weight difference.
double WeightDiff(Genome& genome1, Genome& genome2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can integrate the weight difference into the function I proposed above.

double deltaW = 0;
ssize_t coincident = 0;

for (ssize_t i=0; i<genome1.NumLink(); ++i) {
ssize_t innovId = genome1.aLinkGenes[i].InnovationId();
ssize_t idx = genome2.GetLinkIndex(innovId);
if (idx != -1 && genome1.aLinkGenes[i].Enabled()) {
deltaW += std::abs(genome1.aLinkGenes[i].Weight() - genome2.aLinkGenes[idx].Weight());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If genome2 is disabled, isn't the weight difference, just the weight of genome1?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the NEAT paper, only calculate the difference of matched links.
Also, I just found that crossover and distance calculation also consider disabled links. Thus, I revised corresponding functions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I misunderstood. I think you are right.

++coincident;
}
}

deltaW = deltaW / coincident;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check if matching or coincident is > 0.

return deltaW;
}

// Whether two genome belong to same species or not.
bool IsSameSpecies(Genome& genome1, Genome& genome2) {
double deltaD = Disjoint(genome1, genome2);
double deltaW = WeightDiff(genome1, genome2);
double delta = aCoeffDisjoint * deltaD + aCoeffWeightDiff * deltaW;

if (delta < aCompatThreshold) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this aCompatThreshold = 1.0 parameter come from? Depending on the calculation of the disjoint, excess, and weight difference this could be different.

return true;
} else {
return false;
}
}

// Add genome to existing species or create new species.
void AddGenomeToSpecies(Genome& genome) {
for (ssize_t i=0; i<aPopulation.NumSpecies(); ++i) {
if (aPopulation.aSpecies[i].SpeciesSize() > 0) {
if (IsSameSpecies(aPopulation.aSpecies[i].aGenomes[0], genome)) { // each first genome in species is the representative genome.
aPopulation.aSpecies[i].AddGenome(genome);
return;
}
}
}

Species newSpecies = Species();
newSpecies.AddGenome(genome);
newSpecies.Id(aPopulation.NextSpeciesId()); // NOTICE: changed species id.
aPopulation.AddSpecies(newSpecies);
}

// Set adjusted fitness.
void AdjustFitness() {
for (ssize_t i=0; i<aPopulation.NumSpecies(); ++i) {
if (aPopulation.aSpecies[i].SpeciesSize() > 0) {
for (ssize_t j=0; j<aPopulation.aSpecies[i].SpeciesSize(); ++j) {
double fitness = aPopulation.aSpecies[i].aGenomes[j].Fitness();
ssize_t speciesSize = aPopulation.aSpecies[i].SpeciesSize();
double adjustedFitness = fitness / speciesSize;
aPopulation.aSpecies[i].aGenomes[j].AdjustedFitness(adjustedFitness);
}
}
}
}

// Distribute genomes into species.
void Speciate() {

}

// Initialize population.
void InitPopulation() {
aPopulation = Population(aSeedGenome, aPopulationSize);
}

// Reproduce next generation of population.
void Reproduce() {

}

// Evolve.

private:
// Task.
TaskType aTask;

// Seed genome. It is used for init species.
Genome aSeedGenome;

// Population to evolve.
Population aPopulation;

// Population size.
ssize_t aPopulationSize;

// List of link innovations.
std::vector<LinkInnovation> aLinkInnovations;

Expand All @@ -330,6 +430,18 @@ class NEAT {
// Next link id.
ssize_t aNextLinkInnovId;

// Max number of generation to evolve.
ssize_t aMaxGeneration;

// Efficient for disjoint.
double aCoeffDisjoint;

// Efficient for weight difference.
double aCoeffWeightDiff;

// Threshold for judge whether belong to same species.
double aCompatThreshold;

};

} // namespace ne
Expand Down