19 #include <core/darwin.h> 22 #include <unordered_set> 28 enum LstmWeightIds { Wi,
Ui, Bi, Wf, Uf, Bf, Wo, Uo, Bo, Wc, Uc, Bc, Nlstm };
30 using LstmWeights = array<float, Nlstm>;
38 using NodeId = size_t;
39 using Innovation = size_t;
41 constexpr NodeId kBiasNodeId = 0;
42 constexpr NodeId kFirstInput = 1;
46 Innovation innovation = 0;
51 bool recurrent =
false;
53 Gene(NodeId in, NodeId out,
float weight, Innovation innovation)
54 : innovation(innovation), in(in), out(out), weight(weight) {}
58 friend void to_json(json& json_obj,
const Gene& gene);
59 friend void from_json(
const json& json_obj, Gene& gene);
64 enum class VisitedColor {
72 size_t nodes_count = 0;
80 unique_ptr<darwin::Genotype> clone()
const override;
82 void reset()
override;
90 Innovation createPrimordialSeed();
92 void mutate(atomic<Innovation>& next_innovation,
bool weights_only =
false);
95 void inherit(
const Genotype& parent1,
const Genotype& parent2,
float preference);
100 double compatibility(
const Genotype& ref)
const;
102 unique_ptr<darwin::Brain> grow()
const override;
104 json save()
const override;
105 void load(
const json& json_obj)
override;
109 void mutateWeights(RND& rnd) {
110 std::bernoulli_distribution dist_mutate(g_config.weight_mutation_chance);
113 for (
auto& gene : genes)
114 if (dist_mutate(rnd))
117 if (g_config.use_lstm_nodes) {
119 if (dist_mutate(rnd))
126 bool canReach(NodeId src, NodeId dst, unordered_set<NodeId>& visited)
const;
129 bool detectCycles(NodeId node_id, vector<VisitedColor>& visited)
const;
132 void mutateNewLinks(RND& rnd, atomic<Innovation>& next_innovation) {
133 const NodeId kInputFirst = 1;
134 const NodeId kOutputFirst = 1 + g_inputs;
136 std::bernoulli_distribution dist_mutate(g_config.new_link_chance);
137 if (dist_mutate(rnd)) {
138 std::uniform_int_distribution<NodeId> dist_in_node(kInputFirst, nodes_count - 1);
139 std::uniform_int_distribution<NodeId> dist_out_node(kOutputFirst, nodes_count - 1);
141 NodeId in = dist_in_node(rnd);
142 NodeId out = dist_out_node(rnd);
145 std::uniform_real_distribution<float> dist_weight(-range, range);
148 for (Gene& gene : genes)
149 if (gene.in == in && gene.out == out) {
159 Gene new_gene(in, out,
ann::roundWeight(dist_weight(rnd)), next_innovation++);
160 unordered_set<NodeId> visited;
161 new_gene.recurrent = canReach(out, in, visited);
162 genes.push_back(new_gene);
167 void mutateNewNodes(RND& rnd, atomic<Innovation>& next_innovation) {
168 std::bernoulli_distribution dist_mutate(g_config.new_node_chance);
169 if (dist_mutate(rnd)) {
171 std::uniform_int_distribution<size_t> dist_gene_index(0, genes.size() - 1);
172 auto& gene = genes[dist_gene_index(rnd)];
175 std::uniform_real_distribution<float> dist_weight(-range, range);
177 NodeId new_node_id = nodes_count++;
178 Gene pre_link(gene.in, new_node_id, 1.0f, next_innovation++);
179 pre_link.recurrent =
false;
180 Gene post_link(new_node_id, gene.out, gene.weight, next_innovation++);
181 post_link.recurrent = gene.recurrent;
182 gene.enabled =
false;
183 genes.push_back(pre_link);
184 genes.push_back(post_link);
186 if (g_config.implicit_bias_links) {
187 Gene bias(kBiasNodeId,
191 genes.push_back(bias);
194 if (g_config.recurrent_hidden_nodes) {
195 Gene self_link(new_node_id,
199 self_link.recurrent =
true;
200 genes.push_back(self_link);
Definition: evolution_window.h:22
void reset(std::vector< T > &v)
Reset the values in a vector to 0.
Definition: ann_dynamic.h:32
NeuroEvolution of Augmenting Topologies (NEAT)
Definition: brain.cpp:20
void mutateValue(T &value, RND &rnd, T std_dev)
Mutate a value.
Definition: ann_utils.h:73
float roundWeight(float w)
Ajust a value by rounding to Config::connection_resolution.
Definition: ann_utils.h:63
float connection_range
"Initial connection values range"
Definition: ann_utils.h:44
The interface to the population-specific "genetic material", the Genotype
Definition: darwin.h:126