aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2024-02-29 19:04:34 +0100
committerPaul Oliver <contact@pauloliver.dev>2024-02-29 19:16:14 +0100
commite6ab4a8ed100d5d5b7611c74cf3ccd556f1f1d71 (patch)
tree129cf13c2f9b3eae54402300db4570815789a02a
Initial commitHEADmaster
-rw-r--r--.gitignore3
-rw-r--r--Makefile24
-rw-r--r--README.md22
-rw-r--r--include/HyperNeat/Behavior.hpp40
-rw-r--r--include/HyperNeat/Cppn.hpp58
-rw-r--r--include/HyperNeat/Genome.hpp42
-rw-r--r--include/HyperNeat/Innovation.hpp25
-rw-r--r--include/HyperNeat/NeuralNet.hpp78
-rw-r--r--include/HyperNeat/NeuralNetPrms.hpp25
-rw-r--r--include/HyperNeat/NodeSearchPrms.hpp33
-rw-r--r--include/HyperNeat/NoveltyMetric.hpp37
-rw-r--r--include/HyperNeat/NoveltyMetricPrms.hpp20
-rw-r--r--include/HyperNeat/Organism.hpp71
-rw-r--r--include/HyperNeat/Population.hpp148
-rw-r--r--include/HyperNeat/PopulationPrms.hpp63
-rw-r--r--include/HyperNeat/QuadTree.hpp30
-rw-r--r--include/HyperNeat/Utils/Atomic.hpp12
-rw-r--r--include/HyperNeat/Utils/Function.hpp12
-rw-r--r--include/HyperNeat/Utils/LoadFile.hpp40
-rw-r--r--include/HyperNeat/Utils/Map.hpp12
-rw-r--r--include/HyperNeat/Utils/NodeTypes.hpp22
-rw-r--r--include/HyperNeat/Utils/Pi.hpp9
-rw-r--r--include/HyperNeat/Utils/Point.hpp21
-rw-r--r--include/HyperNeat/Utils/Pointer.hpp12
-rw-r--r--include/HyperNeat/Utils/Random.hpp14
-rw-r--r--include/HyperNeat/Utils/SaveFile.hpp45
-rw-r--r--include/HyperNeat/Utils/Set.hpp12
-rw-r--r--include/HyperNeat/Utils/Size.hpp12
-rw-r--r--include/HyperNeat/Utils/String.hpp11
-rw-r--r--include/HyperNeat/Utils/Thread.hpp11
-rw-r--r--include/HyperNeat/Utils/ValueMap.hpp12
-rw-r--r--include/HyperNeat/Utils/ValuePoint.hpp19
-rw-r--r--include/HyperNeat/Utils/Vector.hpp12
-rw-r--r--include/HyperNeat/Utils/Vector2D.hpp12
-rw-r--r--lib/.keep0
-rw-r--r--obj/.keep0
-rw-r--r--obj/Utils/.keep0
-rw-r--r--plugins/CppnExplorer/CppnExplorer.sublime-project41
-rw-r--r--plugins/CppnExplorer/CppnExplorer.sublime-workspace1199
-rw-r--r--plugins/CppnExplorer/Makefile19
-rw-r--r--plugins/CppnExplorer/include/CppnExplorer.hpp129
-rw-r--r--plugins/CppnExplorer/lib/.keep0
-rw-r--r--plugins/CppnExplorer/obj/.keep0
-rw-r--r--plugins/CppnExplorer/src/CppnExplorer.cpp549
-rw-r--r--plugins/CppnExplorer/todolist.txt21
-rw-r--r--src/Behavior.cpp59
-rw-r--r--src/Cppn.cpp292
-rw-r--r--src/Genome.cpp15
-rw-r--r--src/Innovation.cpp16
-rw-r--r--src/NeuralNet.cpp294
-rw-r--r--src/NodeSearchPrms.cpp23
-rw-r--r--src/NoveltyMetric.cpp101
-rw-r--r--src/Organism.cpp180
-rw-r--r--src/Population.cpp939
-rw-r--r--src/QuadTree.cpp55
-rw-r--r--src/Utils/LoadFile.cpp280
-rw-r--r--src/Utils/NodeTypes.cpp41
-rw-r--r--src/Utils/Point.cpp33
-rw-r--r--src/Utils/SaveFile.cpp249
-rw-r--r--src/Utils/ValuePoint.cpp7
-rw-r--r--todolist.txt44
61 files changed, 5605 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d45b26f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+**/*.a
+**/*.d
+**/*.o
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5b6acff
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+LIBRARY := lib/libHyperNeat.a
+SOURCES := $(wildcard src/*.cpp) $(wildcard src/Utils/*.cpp)
+OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
+DEPS := $(patsubst %.o,%.d,$(OBJECTS))
+CFLAGS := -c -O3 -Wall -std=c++11 -MMD -Iinclude -IC:/cereal/include
+LFLAGS := rvs
+
+all: $(OBJECTS)
+ ar $(LFLAGS) $(LIBRARY) $(OBJECTS)
+ make -C plugins/CppnExplorer
+
+-include $(DEPS)
+
+$(OBJECTS): $(patsubst obj/%.o,src/%.cpp,$@)
+ g++ $(CFLAGS) $(patsubst obj/%.o,src/%.cpp,$@) -o $@
+
+rebuild: clean all
+
+clean:
+ del lib\*.a
+ del obj\*.o
+ del obj\*.d
+ del obj\Utils\*.o
+ del obj\Utils\*.d
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8e68cec
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+rtES-HyperNeat (Real Time Evolving Substrate Hypercube based Neuro-Evolution of
+Augmenting Topologies) is a real time neuro-evolution algorithm based on the
+papers written by Kenneth Stanley and other researchers at the EPLEX group
+([http://eplex.cs.ucf.edu/](http://eplex.cs.ucf.edu/)). More specifically,
+rtES-HyperNeat tries to blend the existing ES-HyperNeat
+([http://eplex.cs.ucf.edu/ESHyperNEAT/](http://eplex.cs.ucf.edu/ESHyperNEAT/))
+algorithm with rtNeat
+([http://nn.cs.utexas.edu/?rtNEAT](http://nn.cs.utexas.edu/?rtNEAT)), a previous
+version which allowed real time evolution of agents on a virtual field.
+
+The main problem with trying to make ES-HyperNeat real-timed was that the CPPNs
+(genotypes) had to be converted into functional Neural Networks (phenotypes) on
+a single time-step. This was proven to be impossible, so, as a solution, the
+library handles these transformations on separate execution threads. This way,
+the algorithm flows seamlessly.
+
+Although several implementations existed for HyperNeat, I've decided to code
+mine from scratch, based only on the original papers by EPLEX. My goal is to
+construct a simple, easy to use, well documented and tutorialized C++ library
+that will allow any user to evolve Neural Networks for any imaginable task. I
+also plan to apply this library to my Guppies experiment once its finished (see
+my channel for more info on Guppies).
diff --git a/include/HyperNeat/Behavior.hpp b/include/HyperNeat/Behavior.hpp
new file mode 100644
index 0000000..2f474a6
--- /dev/null
+++ b/include/HyperNeat/Behavior.hpp
@@ -0,0 +1,40 @@
+#ifndef __HYPERNEAT_BEHAVIOR_HPP__
+#define __HYPERNEAT_BEHAVIOR_HPP__
+
+#include <HyperNeat/Utils/Size.hpp>
+#include <HyperNeat/Utils/Vector.hpp>
+
+namespace hyperneat
+{
+ class Organism;
+ class NoveltyMetric;
+
+ class Behavior
+ {
+ public:
+ void clear();
+ void reset(bool archive = true);
+
+ double& at(size_t i);
+ double getNoveltyScore() const;
+ bool isToBeArchived() const;
+ Organism& getOrganism();
+ const NoveltyMetric& getNoveltyMetric() const;
+ const Vector<double>& getCharacterization() const;
+
+ bool _criteriaReached = true;
+
+ private:
+ double _noveltyScore = 0.0;
+ bool _isReady = false;
+ bool _toBeArchived = false;
+ Organism* _organism = nullptr;
+ NoveltyMetric* _noveltyMetric = nullptr;
+ Vector<double> _characterization;
+
+ friend class LoadFile;
+ friend class NoveltyMetric;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Cppn.hpp b/include/HyperNeat/Cppn.hpp
new file mode 100644
index 0000000..a4511c8
--- /dev/null
+++ b/include/HyperNeat/Cppn.hpp
@@ -0,0 +1,58 @@
+#ifndef __HYPERNEAT_CPPN_HPP__
+#define __HYPERNEAT_CPPN_HPP__
+
+#include <HyperNeat/Utils/Size.hpp>
+#include <HyperNeat/Utils/ValueMap.hpp>
+#include <HyperNeat/Utils/Vector2D.hpp>
+#include <HyperNeat/Utils/NodeTypes.hpp>
+
+namespace hyperneat
+{
+ class Genome;
+ class NodeSearchPrms;
+
+ class Cppn
+ {
+ public:
+ Cppn() = default;
+
+ void create(const Genome& genome);
+ void clear();
+
+ size_t getInputsCount() const;
+ size_t getOutputsCount() const;
+ size_t getNodesCount() const;
+
+ double& inputAt(size_t i);
+ double outputAt(size_t i) const;
+
+ void cycle();
+ void findNodesIn2DSection(ValueMap& valueMap, const NodeSearchPrms& qpPrms, const Point& source = Point());
+
+ private:
+ class Node
+ {
+ public:
+ void appendInput();
+ void flushOutput();
+
+ class Link
+ {
+ public:
+ double* _input = nullptr;
+ double _weight = 0.0;
+ };
+
+ Vector<Link> _links;
+ NodeType _nodeType = NodeType::NULL_TYPE;
+ double _storedInput = 0.0;
+ double _output = 0.0;
+ };
+
+ Vector<double> _inputs;
+ Vector<double*> _outputs;
+ Vector2D<Node> _nodeLayers;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Genome.hpp b/include/HyperNeat/Genome.hpp
new file mode 100644
index 0000000..d8f678f
--- /dev/null
+++ b/include/HyperNeat/Genome.hpp
@@ -0,0 +1,42 @@
+#ifndef __HYPERNEAT_GENOME_HPP__
+#define __HYPERNEAT_GENOME_HPP__
+
+#include <HyperNeat/Utils/Map.hpp>
+#include <HyperNeat/Utils/Size.hpp>
+#include <HyperNeat/Utils/NodeTypes.hpp>
+
+namespace hyperneat
+{
+ class Genome
+ {
+ public:
+ Genome() = default;
+ explicit Genome(size_t inputs);
+
+ class NodeGene
+ {
+ public:
+ NodeGene() = default;
+ NodeGene(double depth, NodeType nodeType);
+
+ class LinkGene
+ {
+ public:
+ LinkGene() = default;
+ LinkGene(double weight, bool isEnabled = true);
+
+ double _weight = 0.0;
+ bool _isEnabled = true;
+ };
+
+ double _depth = 0.0;
+ NodeType _nodeType = NodeType::NULL_TYPE;
+ Map<size_t, LinkGene> _linkGenes;
+ };
+
+ size_t _inputs = 0;
+ Map<size_t, NodeGene> _nodeGenes;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Innovation.hpp b/include/HyperNeat/Innovation.hpp
new file mode 100644
index 0000000..ac618e5
--- /dev/null
+++ b/include/HyperNeat/Innovation.hpp
@@ -0,0 +1,25 @@
+#ifndef __HYPERNEAT_INNOVATION_HPP__
+#define __HYPERNEAT_INNOVATION_HPP__
+
+#include <Hyperneat/Utils/Size.hpp>
+#include <Hyperneat/Utils/NodeTypes.hpp>
+
+namespace hyperneat
+{
+ class Innovation
+ {
+ public:
+ Innovation() = default;
+ Innovation(size_t number, size_t source, size_t target, double depth, NodeType nodeType);
+
+ bool operator== (const Innovation& other) const;
+
+ size_t _number = 0;
+ size_t _source = 0;
+ size_t _target = 0;
+ double _depth = 0.0;
+ NodeType _nodeType = NodeType::NULL_TYPE;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/NeuralNet.hpp b/include/HyperNeat/NeuralNet.hpp
new file mode 100644
index 0000000..7f4a81f
--- /dev/null
+++ b/include/HyperNeat/NeuralNet.hpp
@@ -0,0 +1,78 @@
+#ifndef __HYPERNEAT_NEURALNET_HPP__
+#define __HYPERNEAT_NEURALNET_HPP__
+
+#include <HyperNeat/Utils/Size.hpp>
+#include <HyperNeat/Utils/ValueMap.hpp>
+
+namespace hyperneat
+{
+ class Cppn;
+ class NeuralNetPrms;
+
+ class NeuralNet
+ {
+ public:
+ class Neuron;
+
+ NeuralNet() = default;
+
+ void create(Cppn& cppn, const NeuralNetPrms& nnPrms);
+ void clear();
+
+ size_t getInputsCount() const;
+ size_t getOutputsCount() const;
+ size_t getNeuronsCount() const;
+
+ const Vector<double*>& getInputs() const;
+ const Vector<double*>& getOutputs() const;
+ const Vector<Neuron>& getNeurons() const;
+
+ double getAverageActivation() const;
+
+ double& inputAt(size_t i);
+ double outputAt(size_t i) const;
+
+ void cycle();
+
+ class Neuron
+ {
+ public:
+ enum class Type {
+ INPUT, HIDDEN, OUTPUT
+ };
+
+ Neuron() = default;
+ Neuron(const Point& position, Type type, double bias);
+
+ void appendInput();
+ void flushOutput();
+
+ class Synapse
+ {
+ public:
+ Synapse() = default;
+ Synapse(Neuron* inputNeuron, double weight);
+
+ double* _input = nullptr;
+ Neuron* _neuron = nullptr;
+ double _weight = 0.0;
+ };
+
+ Vector<Synapse> _synapses;
+ Point _position;
+ Type _type = Type::HIDDEN;
+ double _bias = 0.0;
+ double _storedInput = 0.0;
+ double _output = 0.0;
+ };
+
+ private:
+ Vector<double*> _inputs;
+ Vector<double*> _outputs;
+ Vector<Neuron> _neurons;
+
+ friend class Organism;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/NeuralNetPrms.hpp b/include/HyperNeat/NeuralNetPrms.hpp
new file mode 100644
index 0000000..fb5c349
--- /dev/null
+++ b/include/HyperNeat/NeuralNetPrms.hpp
@@ -0,0 +1,25 @@
+#ifndef __HYPERNEAT_NEURALNETPRMS_HPP__
+#define __HYPERNEAT_NEURALNETPRMS_HPP__
+
+#include <HyperNeat/Utils/Size.hpp>
+#include <HyperNeat/Utils/Point.hpp>
+#include <HyperNeat/Utils/Vector.hpp>
+
+namespace hyperneat
+{
+ class NeuralNetPrms
+ {
+ public:
+ Vector<Point> _inputMap;
+ Vector<Point> _outputMap;
+ size_t _testGridLevel = 3;
+ size_t _maxQuadTreeLevel = SIZE_MAX;
+ size_t _minQuadTreeLevel = 0;
+ double _bandPruningThreshold = 0.3;
+ double _varianceThreshold = 0.03;
+ double _divisionThreshold = 0.03;
+ size_t _iterations = SIZE_MAX;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/NodeSearchPrms.hpp b/include/HyperNeat/NodeSearchPrms.hpp
new file mode 100644
index 0000000..52d9083
--- /dev/null
+++ b/include/HyperNeat/NodeSearchPrms.hpp
@@ -0,0 +1,33 @@
+#ifndef __HYPERNEAT_QUERYPLANEPRMS_HPP__
+#define __HYPERNEAT_QUERYPLANEPRMS_HPP__
+
+#include <HyperNeat/Utils/Size.hpp>
+
+namespace hyperneat
+{
+ class NeuralNetPrms;
+
+ class NodeSearchPrms
+ {
+ public:
+ NodeSearchPrms() = default;
+ NodeSearchPrms(size_t o, size_t x, size_t y);
+ NodeSearchPrms(size_t o, size_t x, size_t y, size_t d);
+
+ void importFrom(const NeuralNetPrms& nnPrms);
+
+ size_t _o = 0;
+ size_t _x = 0;
+ size_t _y = 1;
+ bool _useDistance = true;
+ size_t _d = 4;
+ size_t _testGridLevel = 3;
+ size_t _maxQuadTreeLevel = -1;
+ size_t _minQuadTreeLevel = 0;
+ double _bandPruningThreshold = 0.3;
+ double _varianceThreshold = 0.03;
+ double _divisionThreshold = 0.03;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/NoveltyMetric.hpp b/include/HyperNeat/NoveltyMetric.hpp
new file mode 100644
index 0000000..01a6f75
--- /dev/null
+++ b/include/HyperNeat/NoveltyMetric.hpp
@@ -0,0 +1,37 @@
+#ifndef __HYPERNEAT_NOVELTY_METRIC_HPP__
+#define __HYPERNEAT_NOVELTY_METRIC_HPP__
+
+#include <Hyperneat/Behavior.hpp>
+#include <Hyperneat/Utils/Vector2D.hpp>
+#include <Hyperneat/NoveltyMetricPrms.hpp>
+
+namespace hyperneat
+{
+ class Population;
+
+ class NoveltyMetric
+ {
+ public:
+ const NoveltyMetricPrms& getPrms() const;
+ const Vector<Behavior>& getBehaviors() const;
+ const Vector2D<double>& getArchive() const;
+
+ Behavior& getBehaviorOf(size_t i);
+
+ private:
+ void initialize(const NoveltyMetricPrms& prms, Population* population = nullptr);
+ void setScores();
+
+ double getDistance(const Vector<double>& v1, const Vector<double>& v2) const;
+
+ NoveltyMetricPrms _prms;
+ Vector<Behavior> _behaviors;
+ Vector2D<double> _archive;
+
+ friend class Behavior;
+ friend class LoadFile;
+ friend class Population;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/NoveltyMetricPrms.hpp b/include/HyperNeat/NoveltyMetricPrms.hpp
new file mode 100644
index 0000000..305d075
--- /dev/null
+++ b/include/HyperNeat/NoveltyMetricPrms.hpp
@@ -0,0 +1,20 @@
+#ifndef __HYPERNEAT_NOVELTY_METRIC_PRMS_HPP__
+#define __HYPERNEAT_NOVELTY_METRIC_PRMS_HPP__
+
+#include <Hyperneat/Utils/Size.hpp>
+
+namespace hyperneat
+{
+ class Population;
+
+ class NoveltyMetricPrms
+ {
+ public:
+ double _noveltyThreshold = 10.0;
+ size_t _referenceOrganisms = 15;
+ size_t _characterizationSize = 3;
+ bool _criteriaReachedByDefault = true;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Organism.hpp b/include/HyperNeat/Organism.hpp
new file mode 100644
index 0000000..d35210c
--- /dev/null
+++ b/include/HyperNeat/Organism.hpp
@@ -0,0 +1,71 @@
+#ifndef __HYPERNEAT_ORGANISM_HPP__
+#define __HYPERNEAT_ORGANISM_HPP__
+
+#include <HyperNeat/Genome.hpp>
+#include <HyperNeat/NeuralNet.hpp>
+#include <HyperNeat/Utils/Atomic.hpp>
+#include <HyperNeat/Utils/Pointer.hpp>
+
+namespace hyperneat
+{
+ class Behavior;
+ class NeuralNet;
+ class Population;
+ class NeuralNetPrms;
+
+ class Organism
+ {
+ public:
+ Organism(const Organism& other);
+ Organism& operator=(const Organism& other);
+
+ size_t getIndex() const;
+
+ void lock();
+ void unlock();
+ bool isLocked() const;
+
+ void freeze();
+ void unfreeze();
+ bool isFrozen() const;
+
+ bool isBeingGenerated() const;
+ size_t getSpecie() const;
+ bool isOld() const;
+ size_t getLifetime() const;
+
+ Behavior& getBehavior();
+ const Genome& getGenome() const;
+
+ bool isChampion() const;
+ Population& getPopulation() const;
+
+ void createNeuralNet();
+
+ Pointer<NeuralNet> _neuralNet;
+ double _fitness = 0.0;
+
+ private:
+ Organism(Population* population);
+ Organism(size_t inputs, Population* population);
+
+ void reset(bool archive = false);
+
+ size_t _index = 0;
+ bool _isLocked = false;
+ bool _isFrozen = false;
+ Atomic<bool> _isBeingGenerated = {false};
+ size_t _specie = 0;
+ size_t _lifetime = 0;
+ Behavior* _behavior = nullptr;
+ Genome _genome;
+
+ Population* _population = nullptr;
+
+ friend class LoadFile;
+ friend class Population;
+ friend class NoveltyMetric;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Population.hpp b/include/HyperNeat/Population.hpp
new file mode 100644
index 0000000..6d79d14
--- /dev/null
+++ b/include/HyperNeat/Population.hpp
@@ -0,0 +1,148 @@
+#ifndef __HYPERNEAT_POPULATION_HPP__
+#define __HYPERNEAT_POPULATION_HPP__
+
+#include <HyperNeat/Organism.hpp>
+#include <HyperNeat/Innovation.hpp>
+#include <HyperNeat/Utils/Random.hpp>
+#include <HyperNeat/Utils/Vector.hpp>
+#include <HyperNeat/Utils/Pointer.hpp>
+#include <HyperNeat/NeuralNetPrms.hpp>
+#include <HyperNeat/NoveltyMetric.hpp>
+#include <HyperNeat/Utils/Vector2D.hpp>
+#include <HyperNeat/Utils/Function.hpp>
+#include <HyperNeat/PopulationPrms.hpp>
+
+namespace hyperneat
+{
+ class NeuralNet;
+ class NoveltyMetricPrms;
+
+ class Population
+ {
+ public:
+ void create(const PopulationPrms& popPrms);
+ void create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms);
+ void create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms, const NoveltyMetricPrms& nmPrms);
+ void shutdown(bool resetOrganisms = false, bool archiveOrganisms = false);
+ ~Population();
+
+ void setMinimumLifetime(size_t lifetime);
+
+ const PopulationPrms& getPopulationPrms() const;
+ const NeuralNetPrms& getNeuralNetPrms() const;
+ bool hasNeuralNets() const;
+ const Vector<Organism>& getAllOrganisms() const;
+ const Vector2D<Organism*>& getSpecies() const;
+
+ Organism& getOrganism(size_t i);
+ Organism& getChampion();
+ const Vector<Organism*>& getSpecie(size_t i) const;
+
+ void lock();
+ void unlock();
+ bool isLocked() const;
+
+ void lockOrganism(size_t i);
+ void unlockOrganism(size_t i);
+ bool isOrganismLocked(size_t i) const;
+ bool isAnyOrganismLocked() const;
+ size_t getLockedOrganisms() const;
+
+ void freezeOrganism(size_t i);
+ void unfreezeOrganism(size_t i);
+ bool isOrganismFrozen(size_t i) const;
+ bool isAnyOrganismFrozen() const;
+ size_t getFrozenOrganisms() const;
+
+ bool isOrganismBeingGenerated(size_t i) const;
+ bool isAnyOrganismBeingGenerated() const;
+ size_t getOrganismsBeingGenerated() const;
+
+ size_t getReadyOrganisms() const;
+
+ const Vector<Innovation>& getInnovations() const;
+ size_t getInnovationsCount() const;
+ size_t getBasicInnovationsCount() const;
+ Organism* getLastReplacement();
+ Organism* getLastMother();
+ Organism* getLastFather();
+ size_t getReplacements() const;
+ bool recentReplacement() const;
+ double getDistanceThreshold() const;
+ size_t getOldOrganisms() const;
+ size_t getMinimumOldOrganisms() const;
+ double getAverageFitness() const;
+ double getAverageOldFitness() const;
+
+ void setNoveltyMetric(const NoveltyMetricPrms& prms);
+ void clearNoveltyMetric();
+ bool isNoveltyMetricSet() const;
+ const NoveltyMetric& getNoveltyMetric() const;
+
+ size_t getUpdates() const;
+
+ double& fitnessOf(size_t i);
+ bool update(Function<void(void)> beforeReplacement = []() {}, Function<void(void)> afterReplacement = []() {});
+
+ private:
+ void generateAllNeuralNets();
+
+ void replaceOrganism();
+ Organism* killPoorOrganism();
+ Vector<Organism*>* chooseParentSpecie();
+
+ void breedAsexually(Genome& child, const Genome& mother);
+ void breedSexually(Genome& child, const Genome& mother, const Genome& father);
+ bool mutateNodesAndLinks(Genome& child);
+
+ void assignToSpecie(Organism& org);
+ void organizeSpecies();
+ double computeDistance(const Genome& g1, const Genome& g2) const;
+
+ size_t getRandSeed() const;
+ size_t getRandSize(size_t low, size_t hi);
+ double getRandReal(double low, double hi);
+ double getRandWeight();
+ double getWeightDeviation();
+ NodeType getRandNodeType();
+ bool getChance(double ratio);
+
+ PopulationPrms _prms;
+ Pointer<NeuralNetPrms> _nnPrms;
+ Vector2D<Organism*> _species;
+ Vector<Organism> _allOrganisms;
+
+ bool _populationLock = false;
+ size_t _lockedOrganisms = 0;
+ size_t _frozenOrganisms = 0;
+ Atomic<size_t> _organismsBeingGenerated = {0};
+
+ Vector<Innovation> _innovations;
+ size_t _basicInnovs = 0;
+
+ Organism* _lastReplacement = nullptr;
+ Organism* _lastMother = nullptr;
+ Organism* _lastFather = nullptr;
+ size_t _replacements = 0;
+ bool _recentReplacement = false;
+ double _distanceThreshold = 0.0;
+ size_t _oldOrganisms = 0;
+ size_t _minOldOrganisms = 0;
+
+ Pointer<NoveltyMetric> _noveltyMetric;
+
+ size_t _updates = 0;
+
+ RandGen _randGen;
+ IntDist _nodeTypeSelector = IntDist(0, NODE_TYPES_COUNT - 1);
+ RealDist _weightSelector = RealDist(0.0, 1.0);
+ BellDist _weightDeviator;
+ RealDist _chanceSelector;
+
+ friend class LoadFile;
+ friend class Organism;
+ friend class NoveltyMetric;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/PopulationPrms.hpp b/include/HyperNeat/PopulationPrms.hpp
new file mode 100644
index 0000000..21a6bc3
--- /dev/null
+++ b/include/HyperNeat/PopulationPrms.hpp
@@ -0,0 +1,63 @@
+#ifndef __HYPERNEAT_POPULATIONPRMS_HPP__
+#define __HYPERNEAT_POPULATIONPRMS_HPP__
+
+// #include <cereal/cereal.hpp>
+#include <HyperNeat/Utils/Size.hpp>
+
+namespace hyperneat
+{
+ class PopulationPrms
+ {
+ public:
+ size_t _popSize = 200;
+ size_t _cppnInputs = 6;
+ size_t _cppnOutputs = 2;
+ size_t _seed = 0;
+ double _weightRange = 1.0;
+ double _c1Disjoint = 1.0;
+ double _c3WeightDifference = 0.4;
+ double _initialDistanceThreshold = 4.0;
+ double _distanceThresholdShift = 0.3;
+ double _sexualReproductionRate = 0.5;
+ double _weightMutationRate = 0.94;
+ double _weightDeviation = 0.25;
+ double _interspeciesMatingRate = 0.001;
+ double _geneDisablingRatio = 0.75;
+ double _linkMutationRate = 0.03;
+ double _nodeMutationRate = 0.01;
+ size_t _targetSpeciesCount = 8;
+ double _eligibilityRatio = 0.5;
+ size_t _minimumLifetime = 120;
+ size_t _replBeforeReorganization = 5;
+
+ // private:
+ // friend class cereal::access;
+
+ // template <class Archive>
+ // void serialize(Archive &ar)
+ // {
+ // ar(CEREAL_NVP(_popSize));
+ // ar(CEREAL_NVP(_cppnInputs));
+ // ar(CEREAL_NVP(_cppnOutputs));
+ // ar(CEREAL_NVP(_seed));
+ // ar(CEREAL_NVP(_weightRange));
+ // ar(CEREAL_NVP(_c1Disjoint));
+ // ar(CEREAL_NVP(_c3WeightDifference));
+ // ar(CEREAL_NVP(_initialDistanceThreshold));
+ // ar(CEREAL_NVP(_distanceThresholdShift));
+ // ar(CEREAL_NVP(_sexualReproductionRate));
+ // ar(CEREAL_NVP(_weightMutationRate));
+ // ar(CEREAL_NVP(_weightDeviation));
+ // ar(CEREAL_NVP(_interspeciesMatingRate));
+ // ar(CEREAL_NVP(_geneDisablingRatio));
+ // ar(CEREAL_NVP(_linkMutationRate));
+ // ar(CEREAL_NVP(_nodeMutationRate));
+ // ar(CEREAL_NVP(_targetSpeciesCount));
+ // ar(CEREAL_NVP(_eligibilityRatio));
+ // ar(CEREAL_NVP(_minimumLifetime));
+ // ar(CEREAL_NVP(_replBeforeReorganization));
+ // }
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/QuadTree.hpp b/include/HyperNeat/QuadTree.hpp
new file mode 100644
index 0000000..8090254
--- /dev/null
+++ b/include/HyperNeat/QuadTree.hpp
@@ -0,0 +1,30 @@
+#ifndef __HYPERNEAT_QUADTREE_HPP__
+#define __HYPERNEAT_QUADTREE_HPP__
+
+#include <HyperNeat/Utils/Vector.hpp>
+#include <HyperNeat/Utils/Function.hpp>
+
+namespace hyperneat
+{
+ class QuadTree
+ {
+ public:
+ QuadTree() = default;
+ QuadTree(double segment, double x, double y);
+
+ double getSegment() const;
+ double getX() const;
+ double getY() const;
+
+ void subdivide(Function<bool(QuadTree*)> subdivider);
+ void traverse(Function<void(const QuadTree*)> traverser) const;
+
+ private:
+ Vector<QuadTree> _children;
+ double _segment = 0.0;
+ double _x = 0.0;
+ double _y = 0.0;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Atomic.hpp b/include/HyperNeat/Utils/Atomic.hpp
new file mode 100644
index 0000000..850a06e
--- /dev/null
+++ b/include/HyperNeat/Utils/Atomic.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_ATOM_HPP__
+#define __HYPERNEAT_ATOM_HPP__
+
+#include <atomic>
+
+namespace hyperneat
+{
+ template <class T>
+ using Atomic = std::atomic<T>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Function.hpp b/include/HyperNeat/Utils/Function.hpp
new file mode 100644
index 0000000..ebcb27b
--- /dev/null
+++ b/include/HyperNeat/Utils/Function.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_FUNCTION_HPP__
+#define __HYPERNEAT_FUNCTION_HPP__
+
+#include <functional>
+
+namespace hyperneat
+{
+ template <class F>
+ using Function = std::function<F>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/LoadFile.hpp b/include/HyperNeat/Utils/LoadFile.hpp
new file mode 100644
index 0000000..1960e90
--- /dev/null
+++ b/include/HyperNeat/Utils/LoadFile.hpp
@@ -0,0 +1,40 @@
+#ifndef __HYPERNEAT_LOADFILE_HPP__
+#define __HYPERNEAT_LOADFILE_HPP__
+
+#include <iostream>
+#include <HyperNeat/Utils/String.hpp>
+#include <HyperNeat/Utils/Vector.hpp>
+
+namespace hyperneat
+{
+ using Istream = std::istream;
+
+ class Genome;
+ class Organism;
+ class Population;
+ class NoveltyMetric;
+ class PopulationPrms;
+ class NoveltyMetricPrms;
+
+ class LoadFile
+ {
+ public:
+ LoadFile(Istream& stream);
+
+ void loadPopulation(Population& population);
+ void loadPopulationPrms(PopulationPrms& prms);
+ void loadNeuralNetPrms(NeuralNetPrms& prms);
+ void loadNoveltyMetric(NoveltyMetric& noveltyMetric);
+ void loadNoveltyMetricPrms(NoveltyMetricPrms& prms);
+ void loadOrganism(Organism& organism);
+ void loadGenome(Genome& genome);
+
+ private:
+ Istream& nextPrm(bool arrayVal = false);
+ Istream& nextArrayValue();
+
+ Istream& _stream;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Map.hpp b/include/HyperNeat/Utils/Map.hpp
new file mode 100644
index 0000000..c735ab3
--- /dev/null
+++ b/include/HyperNeat/Utils/Map.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_MAP_HPP__
+#define __HYPERNEAT_MAP_HPP__
+
+#include <map>
+
+namespace hyperneat
+{
+ template <class K, class V>
+ using Map = std::map<K, V>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/NodeTypes.hpp b/include/HyperNeat/Utils/NodeTypes.hpp
new file mode 100644
index 0000000..815214e
--- /dev/null
+++ b/include/HyperNeat/Utils/NodeTypes.hpp
@@ -0,0 +1,22 @@
+#ifndef __HYPERNEAT_NODETYPES_HPP__
+#define __HYPERNEAT_NODETYPES_HPP__
+
+#include <HyperNeat/Utils/String.hpp>
+
+namespace hyperneat
+{
+ enum class NodeType {
+ NULL_TYPE = -1,
+ SIGMOID = 0,
+ GAUSSIAN = 1,
+ SINE = 2,
+ ABSOLUTE = 3,
+ };
+
+ String nodeToString(NodeType type);
+ NodeType stringToNode(const String& str);
+
+ const size_t NODE_TYPES_COUNT = 4;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Pi.hpp b/include/HyperNeat/Utils/Pi.hpp
new file mode 100644
index 0000000..00a3df2
--- /dev/null
+++ b/include/HyperNeat/Utils/Pi.hpp
@@ -0,0 +1,9 @@
+#ifndef __HYPERNEAT_PI_HPP__
+#define __HYPERNEAT_PI_HPP__
+
+namespace hyperneat
+{
+ const double PI = 3.14159265359;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Point.hpp b/include/HyperNeat/Utils/Point.hpp
new file mode 100644
index 0000000..ba51bac
--- /dev/null
+++ b/include/HyperNeat/Utils/Point.hpp
@@ -0,0 +1,21 @@
+#ifndef __HYPERNEAT_POINT_HPP__
+#define __HYPERNEAT_POINT_HPP__
+
+namespace hyperneat
+{
+ class Point
+ {
+ public:
+ Point() = default;
+ Point(double x, double y);
+
+ double distance(const Point& other) const;
+ bool operator== (const Point& other) const;
+ bool operator< (const Point& other) const;
+
+ double _x = 0.0;
+ double _y = 0.0;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Pointer.hpp b/include/HyperNeat/Utils/Pointer.hpp
new file mode 100644
index 0000000..f02e853
--- /dev/null
+++ b/include/HyperNeat/Utils/Pointer.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_POINTER_HPP__
+#define __HYPERNEAT_POINTER_HPP__
+
+#include <memory>
+
+namespace hyperneat
+{
+ template <class T>
+ using Pointer = std::unique_ptr<T>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Random.hpp b/include/HyperNeat/Utils/Random.hpp
new file mode 100644
index 0000000..4a4d979
--- /dev/null
+++ b/include/HyperNeat/Utils/Random.hpp
@@ -0,0 +1,14 @@
+#ifndef __HYPERNEAT_RANDOM_HPP__
+#define __HYPERNEAT_RANDOM_HPP__
+
+#include <random>
+
+namespace hyperneat
+{
+ using RandGen = std::mt19937_64;
+ using IntDist = std::uniform_int_distribution<size_t>;
+ using RealDist = std::uniform_real_distribution<double>;
+ using BellDist = std::normal_distribution<double>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/SaveFile.hpp b/include/HyperNeat/Utils/SaveFile.hpp
new file mode 100644
index 0000000..18cad38
--- /dev/null
+++ b/include/HyperNeat/Utils/SaveFile.hpp
@@ -0,0 +1,45 @@
+#ifndef __HYPERNEAT_SAVEFILE_HPP__
+#define __HYPERNEAT_SAVEFILE_HPP__
+
+#include <iostream>
+#include <HyperNeat/Utils/String.hpp>
+#include <HyperNeat/Utils/Vector.hpp>
+
+namespace hyperneat
+{
+ using Ostream = std::ostream;
+
+ class Genome;
+ class Organism;
+ class Population;
+ class NoveltyMetric;
+ class NeuralNetPrms;
+ class PopulationPrms;
+ class NoveltyMetricPrms;
+
+ class SaveFile
+ {
+ public:
+ SaveFile(Ostream& stream);
+
+ void savePopulation(Population& population, bool shuttedDown = false, size_t tabs = 0,
+ const String& prefix = "");
+ void savePopulationPrms(const PopulationPrms& prms, size_t tabs = 0, const String& prefix = "");
+ void saveNeuralNetPrms(const NeuralNetPrms& prms, size_t tabs = 0, const String& prefix = "");
+ void saveOrganism(const Organism& organism, bool shuttedDown = false, size_t tabs = 0,
+ const String& prefix = "");
+ void saveGenome(const Genome& genome, size_t tabs = 0, const String& prefix = "");
+ void saveNoveltyMetric(const NoveltyMetric& noveltyMetric, bool shuttedDown = false, size_t tabs = 0,
+ const String& prefix = "");
+ void saveNoveltyMetricPrms(const NoveltyMetricPrms& noveltyMetricPrms, size_t tabs = 0,
+ const String& prefix = "");
+
+ private:
+ Ostream& print(size_t tabs = 0);
+ String newl(size_t lines = 1);
+
+ Ostream& _stream;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Set.hpp b/include/HyperNeat/Utils/Set.hpp
new file mode 100644
index 0000000..d403e6b
--- /dev/null
+++ b/include/HyperNeat/Utils/Set.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_SET_HPP__
+#define __HYPERNEAT_SET_HPP__
+
+#include <set>
+
+namespace hyperneat
+{
+ template <class V>
+ using Set = std::set<V>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Size.hpp b/include/HyperNeat/Utils/Size.hpp
new file mode 100644
index 0000000..0ef5616
--- /dev/null
+++ b/include/HyperNeat/Utils/Size.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_SIZE_HPP__
+#define __HYPERNEAT_SIZE_HPP__
+
+#include <cstddef>
+#include <climits>
+
+namespace hyperneat
+{
+ using std::size_t;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/String.hpp b/include/HyperNeat/Utils/String.hpp
new file mode 100644
index 0000000..ab74d45
--- /dev/null
+++ b/include/HyperNeat/Utils/String.hpp
@@ -0,0 +1,11 @@
+#ifndef HYPERNEAT_STRING_HPP
+#define HYPERNEAT_STRING_HPP
+
+#include <string>
+
+namespace hyperneat
+{
+ using String = std::string;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Thread.hpp b/include/HyperNeat/Utils/Thread.hpp
new file mode 100644
index 0000000..4b861e3
--- /dev/null
+++ b/include/HyperNeat/Utils/Thread.hpp
@@ -0,0 +1,11 @@
+#ifndef __HYPERNEAT_THREAD_HPP__
+#define __HYPERNEAT_THREAD_HPP__
+
+#include <thread>
+
+namespace hyperneat
+{
+ using Thread = std::thread;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/ValueMap.hpp b/include/HyperNeat/Utils/ValueMap.hpp
new file mode 100644
index 0000000..c2910b5
--- /dev/null
+++ b/include/HyperNeat/Utils/ValueMap.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_VALUEMAP_HPP__
+#define __HYPERNEAT_VALUEMAP_HPP__
+
+#include <HyperNeat/Utils/Vector.hpp>
+#include <HyperNeat/Utils/ValuePoint.hpp>
+
+namespace hyperneat
+{
+ using ValueMap = Vector<ValuePoint>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/ValuePoint.hpp b/include/HyperNeat/Utils/ValuePoint.hpp
new file mode 100644
index 0000000..b9e15ab
--- /dev/null
+++ b/include/HyperNeat/Utils/ValuePoint.hpp
@@ -0,0 +1,19 @@
+#ifndef __HYPERNEAT_VALUEPOINT_HPP__
+#define __HYPERNEAT_VALUEPOINT_HPP__
+
+#include <HyperNeat/Utils/Point.hpp>
+
+namespace hyperneat
+{
+ class ValuePoint : public Point
+ {
+ public:
+ ValuePoint() = default;
+ ValuePoint(double x, double y, double value, double segment);
+
+ double _value = 0.0;
+ double _segment = 0.0;
+ };
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Vector.hpp b/include/HyperNeat/Utils/Vector.hpp
new file mode 100644
index 0000000..f7352e4
--- /dev/null
+++ b/include/HyperNeat/Utils/Vector.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_VECTOR_HPP__
+#define __HYPERNEAT_VECTOR_HPP__
+
+#include <vector>
+
+namespace hyperneat
+{
+ template <class V>
+ using Vector = std::vector<V>;
+}
+
+#endif
diff --git a/include/HyperNeat/Utils/Vector2D.hpp b/include/HyperNeat/Utils/Vector2D.hpp
new file mode 100644
index 0000000..257dbe6
--- /dev/null
+++ b/include/HyperNeat/Utils/Vector2D.hpp
@@ -0,0 +1,12 @@
+#ifndef __HYPERNEAT_VECTOR2D_HPP__
+#define __HYPERNEAT_VECTOR2D_HPP__
+
+#include <Hyperneat/Utils/Vector.hpp>
+
+namespace hyperneat
+{
+ template <class V>
+ using Vector2D = Vector<Vector<V>>;
+}
+
+#endif
diff --git a/lib/.keep b/lib/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/.keep
diff --git a/obj/.keep b/obj/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obj/.keep
diff --git a/obj/Utils/.keep b/obj/Utils/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obj/Utils/.keep
diff --git a/plugins/CppnExplorer/CppnExplorer.sublime-project b/plugins/CppnExplorer/CppnExplorer.sublime-project
new file mode 100644
index 0000000..dee3d7f
--- /dev/null
+++ b/plugins/CppnExplorer/CppnExplorer.sublime-project
@@ -0,0 +1,41 @@
+{
+ "build_systems":
+ [
+ {
+ "cmd":
+ [
+ "make",
+ "-C",
+ "${project_path}"
+ ],
+ "name": "Build"
+ },
+ {
+ "cmd":
+ [
+ "make",
+ "clean",
+ "-C",
+ "${project_path}"
+ ],
+ "name": "Clean"
+ }
+ ],
+ "folders":
+ [
+ {
+ "file_exclude_patterns":
+ [
+ "*.sublime-project",
+ "*.sublime-workspace"
+ ],
+ "folder_exclude_patterns":
+ [
+ "obj",
+ "lib",
+ "Algorithm Documentation"
+ ],
+ "path": "."
+ }
+ ]
+}
diff --git a/plugins/CppnExplorer/CppnExplorer.sublime-workspace b/plugins/CppnExplorer/CppnExplorer.sublime-workspace
new file mode 100644
index 0000000..cf691cc
--- /dev/null
+++ b/plugins/CppnExplorer/CppnExplorer.sublime-workspace
@@ -0,0 +1,1199 @@
+{
+ "auto_complete":
+ {
+ "selected_items":
+ [
+ [
+ "fiel",
+ "fieldGenerator"
+ ],
+ [
+ "_ne",
+ "_neuralNetReady"
+ ],
+ [
+ "_neu",
+ "_neuralNetReady"
+ ],
+ [
+ "_neur",
+ "_neuralNet"
+ ],
+ [
+ "setOu",
+ "setOutlineColor"
+ ],
+ [
+ "PIX",
+ "PIXEL_SIZE"
+ ],
+ [
+ "Neu",
+ "Neuron"
+ ],
+ [
+ "IN",
+ "INPUT"
+ ],
+ [
+ "setO",
+ "setOrigin"
+ ],
+ [
+ "Uin",
+ "Uint8"
+ ],
+ [
+ "PI",
+ "PIXEL_SIZE"
+ ],
+ [
+ "Neur",
+ "Neuron"
+ ],
+ [
+ "Bl",
+ "BlendAdd"
+ ],
+ [
+ "_wi",
+ "_withNeuralNet"
+ ],
+ [
+ "neura",
+ "neuralNetGenerator"
+ ],
+ [
+ "neural",
+ "_neuralNetGenerator"
+ ],
+ [
+ "_win",
+ "_windowOpen"
+ ],
+ [
+ "eve",
+ "event"
+ ],
+ [
+ "joi",
+ "joinable"
+ ],
+ [
+ "win",
+ "_windowThread"
+ ],
+ [
+ "grid",
+ "gridSpacing"
+ ],
+ [
+ "Rende",
+ "RenderTarget"
+ ],
+ [
+ "Render",
+ "RenderWindow"
+ ],
+ [
+ "sr",
+ "srcNeuron"
+ ],
+ [
+ "colo",
+ "colorMult"
+ ],
+ [
+ "setOutl",
+ "setOutlineThickness"
+ ],
+ [
+ "gri",
+ "gridClr"
+ ],
+ [
+ "_sh",
+ "_showGrid"
+ ],
+ [
+ "res",
+ "resolution"
+ ],
+ [
+ "fie",
+ "field"
+ ],
+ [
+ "fi",
+ "_field"
+ ],
+ [
+ "out",
+ "outputAt"
+ ],
+ [
+ "cpp",
+ "_cppn"
+ ],
+ [
+ "_bia",
+ "_biasTexture"
+ ],
+ [
+ "in",
+ "inputAt"
+ ],
+ [
+ "INV",
+ "INV_WEIGHTS"
+ ],
+ [
+ "col",
+ "colorInt"
+ ],
+ [
+ "C",
+ "CircleShape"
+ ],
+ [
+ "Neural",
+ "NeuralNet"
+ ],
+ [
+ "_cur",
+ "_cursorPos"
+ ],
+ [
+ "_cu",
+ "_cursorPos"
+ ],
+ [
+ "prin",
+ "printWeights"
+ ],
+ [
+ "Key",
+ "Keyboard"
+ ],
+ [
+ "Cpp",
+ "CppnExplorer"
+ ],
+ [
+ "co",
+ "Color"
+ ],
+ [
+ "_is",
+ "_isLocked"
+ ],
+ [
+ "Ne",
+ "Neuron"
+ ],
+ [
+ "_re",
+ "_recentReplacement"
+ ],
+ [
+ "re",
+ "relateIO"
+ ],
+ [
+ "_in",
+ "_inputMap"
+ ],
+ [
+ "en",
+ "endl"
+ ],
+ [
+ "_ou",
+ "_output"
+ ],
+ [
+ "_",
+ "_position"
+ ],
+ [
+ "_out",
+ "_outputMap"
+ ],
+ [
+ "pu",
+ "previousNeurons"
+ ],
+ [
+ "tem",
+ "tempNeurons"
+ ],
+ [
+ "def",
+ "default"
+ ],
+ [
+ "gene",
+ "generateNeuralNet"
+ ],
+ [
+ "c",
+ "const"
+ ],
+ [
+ "ato",
+ "atomic_size_t"
+ ],
+ [
+ "db",
+ "dbgFileName"
+ ],
+ [
+ "dbg",
+ "dbgFileName"
+ ],
+ [
+ "th",
+ "threadID"
+ ],
+ [
+ "Pop",
+ "PopulationDefaults"
+ ],
+ [
+ "Vec",
+ "Vector2D"
+ ],
+ [
+ "wor",
+ "worldFile"
+ ],
+ [
+ "ste",
+ "onStep"
+ ],
+ [
+ "pr",
+ "print"
+ ],
+ [
+ "str",
+ "struct struct"
+ ],
+ [
+ "SE",
+ "SELECT_LOAD"
+ ],
+ [
+ "SELE",
+ "SELECT_NEW"
+ ],
+ [
+ "pri",
+ "printCommand"
+ ],
+ [
+ "com",
+ "command"
+ ],
+ [
+ "arg",
+ "argv"
+ ],
+ [
+ "org",
+ "organismIdx"
+ ],
+ [
+ "spe",
+ "specieSize"
+ ],
+ [
+ "nod",
+ "nodeType"
+ ],
+ [
+ "loa",
+ "loadGenome"
+ ],
+ [
+ "load",
+ "loadPopulationPrms"
+ ],
+ [
+ "getCHa",
+ "getChampionIdx"
+ ],
+ [
+ "cham",
+ "champIdx"
+ ],
+ [
+ "size",
+ "size_t"
+ ],
+ [
+ "file",
+ "fileName"
+ ],
+ [
+ "fil",
+ "fileName"
+ ],
+ [
+ "Po",
+ "Population"
+ ],
+ [
+ "File",
+ "FileStream"
+ ],
+ [
+ "Fil",
+ "FileStream"
+ ],
+ [
+ "Inp",
+ "InputFile"
+ ],
+ [
+ "pop",
+ "population"
+ ],
+ [
+ "isO",
+ "isOrganismBeingGenerated"
+ ],
+ [
+ "isA",
+ "isAnyOrganismBeingGenerated"
+ ],
+ [
+ "organ",
+ "organismIsBeingGenerated"
+ ],
+ [
+ "_orga",
+ "_organismsBeingGenerated"
+ ],
+ [
+ "is",
+ "isBeingGenerated"
+ ],
+ [
+ "_or",
+ "_organismsBeingGenerated"
+ ],
+ [
+ "_org",
+ "_organismIsLocked"
+ ],
+ [
+ "_isL",
+ "_isLocked"
+ ],
+ [
+ "organi",
+ "_organismsBeingGenerated"
+ ],
+ [
+ "_lock",
+ "_lockedOrganisms"
+ ],
+ [
+ "isL",
+ "isLockedByReplacement"
+ ],
+ [
+ "si",
+ "size_t"
+ ],
+ [
+ "_pop",
+ "_populationLock"
+ ],
+ [
+ "leve",
+ "levelToSegment"
+ ],
+ [
+ "inc",
+ "include"
+ ],
+ [
+ "beg",
+ "begin"
+ ],
+ [
+ "dis",
+ "distance"
+ ],
+ [
+ "emp",
+ "emplace_back"
+ ],
+ [
+ "mu",
+ "mutex"
+ ],
+ [
+ "incl",
+ "inclIter"
+ ],
+ [
+ "siz",
+ "size_t"
+ ],
+ [
+ "cr",
+ "crntInclusions"
+ ],
+ [
+ "sour",
+ "sourceNeuron"
+ ],
+ [
+ "neuro",
+ "_neurons"
+ ],
+ [
+ "syn",
+ "synTot"
+ ],
+ [
+ "thre",
+ "threadVec"
+ ],
+ [
+ "_organi",
+ "_allOrganisms"
+ ],
+ [
+ "poo",
+ "poorOrganism"
+ ],
+ [
+ "fta",
+ "fatherIdx"
+ ],
+ [
+ "fath",
+ "fatherIdx"
+ ],
+ [
+ "fat",
+ "fatherIdx"
+ ],
+ [
+ "orga",
+ "organismReplaced"
+ ],
+ [
+ "repla",
+ "replaceOrganism"
+ ],
+ [
+ "ran",
+ "randWeight"
+ ],
+ [
+ "_cpp",
+ "_cppnInputs"
+ ],
+ [
+ "_i",
+ "_innovationNo"
+ ],
+ [
+ "gen",
+ "geneIdx"
+ ],
+ [
+ "ra",
+ "randSeed"
+ ],
+ [
+ "_o",
+ "_output"
+ ]
+ ]
+ },
+ "buffers":
+ [
+ {
+ "file": "todolist.txt",
+ "settings":
+ {
+ "buffer_size": 1115,
+ "line_ending": "Windows"
+ }
+ },
+ {
+ "file": "include/CppnExplorer.hpp",
+ "settings":
+ {
+ "buffer_size": 4318,
+ "line_ending": "Windows"
+ }
+ },
+ {
+ "file": "src/CppnExplorer.cpp",
+ "settings":
+ {
+ "buffer_size": 17141,
+ "line_ending": "Windows"
+ }
+ }
+ ],
+ "build_system": "Build",
+ "command_palette":
+ {
+ "height": 375.0,
+ "selected_items":
+ [
+ [
+ "tas",
+ "Tasks: New document"
+ ],
+ [
+ "TAS",
+ "Tasks: New document"
+ ],
+ [
+ "",
+ "Build: Build"
+ ],
+ [
+ "ops",
+ "View: Toggle Open Files in Side Bar"
+ ]
+ ],
+ "width": 378.0
+ },
+ "console":
+ {
+ "height": 118.0,
+ "history":
+ [
+ ]
+ },
+ "distraction_free":
+ {
+ "menu_visible": true,
+ "show_minimap": false,
+ "show_open_files": false,
+ "show_tabs": false,
+ "side_bar_visible": false,
+ "status_bar_visible": false
+ },
+ "expanded_folders":
+ [
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer"
+ ],
+ "file_history":
+ [
+ "/C/Projects/Applications/NeuroRacers/bin/current.population",
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/Makefile",
+ "/C/Users/Paul/Downloads/ID/Adobe Indesign CS6/DLL FILE/IMPORTANT.txt",
+ "/C/Users/Paul/Downloads/ID/Adobe Indesign CS6/INSTALLING INSTRUCTIONS.txt",
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/CppnExplorer.sublime-project",
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/src/CppnExplorer.cpp",
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/include/CppnExplorer.hpp",
+ "/C/TBB/include/tbb/atomic.h",
+ "/C/Program Files (x86)/Orbiter/Modules/D3D11Shaders/Planet_Clouds.fx",
+ "/C/Program Files (x86)/Orbiter/Modules/D3D11Shaders/Planet.fx",
+ "/C/Program Files (x86)/Orbiter/Config/NGPlanetConfig/Earth_ng.cfg",
+ "/C/Program Files (x86)/Orbiter/Config/Jupiter.cfg",
+ "/C/Program Files (x86)/Orbiter/Config/NGPlanetConfig/Titan_ng.cfg",
+ "/C/Program Files (x86)/Orbiter/D3D11Client.cfg",
+ "/C/Projects/.git",
+ "/C/Projects/New Text Document.txt",
+ "/C/Users/Paul/Downloads/orbiter100830/Config/Mars.cfg",
+ "/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/todo",
+ "/C/Users/Paul/Downloads/orbiter100830/Config/Earth.cfg",
+ "/C/Users/Paul/Downloads/asmi-ovp-1f2ee85a8579/asmi-ovp-1f2ee85a8579/D3D11CLIENT README.txt",
+ "/C/Users/Paul/Downloads/orbiter100830/readme.txt",
+ "/C/Users/Paul/Downloads/orbiter100830/patch.txt",
+ "/C/Sublime Text 3/Data/Packages/User/Preferences.sublime-settings",
+ "/C/Users/Paul/Documents/Trabajo/Will Bourdreau/Laurieta Rose/NextStepsBoat.txt",
+ "/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/src/CppnExplorer.cpp",
+ "/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/Makefile",
+ "/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/include/CppnExplorer.hpp",
+ "/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/cppn.explorer.sublime-project",
+ "/C/Projects/Libraries/HyperNeat/HyperNeat.sublime-project",
+ "/C/Projects/Libraries/HyperNeat/src/Organism.cpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Population.hpp",
+ "/C/Projects/Libraries/HyperNeat/src/Population.cpp",
+ "/C/Projects/Libraries/HyperNeat/src/NeuralNet.cpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/NeuralNet.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Organism.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Atomic.hpp",
+ "/C/Projects/Libraries/HyperNeat/Makefile",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Future.hpp",
+ "/C/Projects/Libraries/HyperNeat/todo",
+ "/C/Users/Paul/Downloads/tbb42_20130725oss_win/tbb42_20130725oss/include/tbb/tbb.h",
+ "/C/Users/Paul/Downloads/tbb41_20130516oss_src/tbb41_20130516oss_src/tbb41_20130516oss/README.txt",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Vector.hpp",
+ "/C/Projects/Libraries/HyperNeat/src/Utils/Point.cpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Point.hpp",
+ "/C/Projects/Libraries/HyperNeat/src/QuadTree.cpp",
+ "/C/Projects/Libraries/HyperNeat/src/Utils/LoadFile.cpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Atom.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Vector2D.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Debugger.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Thread.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Mutex.hpp",
+ "/C/Projects/Libraries/HyperNeat/src/Cppn.cpp",
+ "/C/Projects/Libraries/HyperNeat/src/Cppn.s",
+ "/C/Users/Paul/Downloads/FitVids.js-master/FitVids.js-master/tests.html",
+ "/C/Users/Paul/Downloads/FitVids.js-master/FitVids.js-master/CONTRIBUTING.md",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/StackMacros.hpp",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/PopulationPrms.hpp",
+ "/C/Users/Paul/Downloads/Ida Pro v6.1/READ ME !!.txt",
+ "/C/Projects/Libraries/HyperNeat/src/QueryPlanePrms.cpp",
+ "/C/Projects/Libraries/HyperNeat/src/Utils/SaveFile.cpp",
+ "/C/SFML/build-debug/CMakeCache.txt",
+ "/C/Box2D/build-debug/CMakeCache.txt",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Genome.hpp",
+ "/C/Projects/Applications/NeuroRacers/bin/population",
+ "/C/Projects/Libraries/HyperNeat/include/HyperNeat/Cppn.hpp",
+ "/C/SFML/build-dynamic/CMakeCache.txt",
+ "/C/Box2D/build-dynamic/CMakeCache.txt",
+ "/C/Projects/Libraries/HyperNeat/src/Utils/TEMP_Vector.cpp",
+ "/C/Projects/Applications/HyperGuppies/Makefile",
+ "/C/Projects/Applications/Guppies SFML/SimBase_Execute.cpp",
+ "/C/Projects/Applications/HyperGuppies/include/Utils/String.hpp",
+ "/C/Projects/Applications/HyperGuppies/todo",
+ "/C/Programming/Applications/HyperGuppies/include/Utils/RLUtils.hpp",
+ "/C/Programming/Applications/HyperGuppies/include/WorldParams.hpp",
+ "/C/Users/Paul/Downloads/pdc25_vc_w32/README",
+ "/C/Programming/Applications/HyperGuppies/bin/worlds/default.world",
+ "/C/Programming/Applications/HyperGuppies/include/Utils/File.hpp",
+ "/C/Programming/Applications/HyperGuppies/Makefile",
+ "/C/Programming/Applications/HyperGuppies/HyperGuppies.sublime-project",
+ "/C/Programming/Applications/Guppies SFML/Params.hpp",
+ "/C/Users/Paul/Downloads/SFML/SFML-master/CMakeLists.txt",
+ "/C/Programming/Applications/HyperGuppies/include/Utils/Function.hpp",
+ "/C/Users/Paul/Downloads/RBTray-4_3/readme.txt",
+ "/C/Programming/Applications/HyperGuppies/src/Main.cpp",
+ "/C/Programming/Applications/HyperGuppies/todo",
+ "/C/RLUtil/RLUtil.hpp",
+ "/C/Users/Paul/Downloads/PlainTasks-master/PlainTasks-master/Readme.md",
+ "/C/Programming/Applications/HyperGuppies/include/App.hpp",
+ "/C/Programming/Applications/HyperGuppies/src/App.cpp",
+ "/C/Users/Paul/Downloads/rlutil-master/rlutil-master/rlutil.hpp",
+ "/C/Users/Paul/Downloads/rlutil-master/rlutil-master/example.c",
+ "/C/Users/Paul/Downloads/rlutil-master/rlutil-master/test.cpp",
+ "/C/Users/Paul/Downloads/rlutil-master/rlutil-master/rlutil.h",
+ "/C/Box2D/include/Common/b2Settings.h",
+ "/C/Users/Paul/Desktop/Box2D/Box2D/Common/b2Settings.h",
+ "/C/Users/Paul/Desktop/Box2D/CMakeLists.txt",
+ "/C/Users/Paul/Desktop/Box2D/Box2D/CMakeLists.txt",
+ "/C/Programming/Libraries/HyperNeat/Makefile",
+ "/C/Users/Paul/Downloads/neuro.3.0.3/neuro/style.css",
+ "/C/Users/Paul/Downloads/tapio-rlutil-c49f5ae/tapio-rlutil-c49f5ae/rlutil.h",
+ "/C/Programming/Libraries/HyperNeat/src/Utils/LoadFile.cpp",
+ "/C/Programming/Applications/NeuroRacers/bin/population",
+ "/C/Programming/Libraries/HyperNeat/todo",
+ "/C/Programming/Libraries/HyperNeat/include/Population.hpp",
+ "/C/Programming/Libraries/HyperNeat/include/Utils/LoadFile.hpp",
+ "/C/Programming/Libraries/HyperNeat/src/Utils/SaveFile.cpp",
+ "/C/Programming/Libraries/HyperNeat/include/Utils/SaveFile.hpp",
+ "/C/Programming/Libraries/HyperNeat/include/Organism.hpp",
+ "/C/Users/Paul/Desktop/Box2D_v2.2.1/Box2D/Common/b2Settings.h",
+ "/C/Users/Paul/Desktop/Box2D_v2.2.1/Building.txt",
+ "/C/Users/Paul/Desktop/Box2D_v2.2.1/Box2D/Box2D.h",
+ "/C/Users/Paul/Desktop/Box2D_v2.2.1/Readme.txt",
+ "/C/Programming/Libraries/HyperNeat/src/Genome.cpp",
+ "/C/Programming/Libraries/HyperNeat/include/Genome.hpp",
+ "/C/Programming/Libraries/HyperNeat/src/Cppn.cpp",
+ "/C/Programming/Libraries/HyperNeat/include/Cppn.hpp",
+ "/C/Programming/Libraries/HyperNeat/src/Organism.cpp",
+ "/C/Programming/Libraries/HyperNeat/src/Population.cpp",
+ "/C/Box2D/src/Dynamics/b2World.cpp",
+ "/C/Box2D/src/Dynamics/b2World.h",
+ "/C/Box2D/src/Dynamics/b2WorldCallbacks.h",
+ "/C/Programming/Libraries/HyperNeat/include/Utils/NodeTypes.hpp",
+ "/C/Programming/Libraries/HyperNeat/include/Utils/String.hpp",
+ "/C/Programming/Libraries/HyperNeat/src/LoadSaveSystem.cpp",
+ "/C/Programming/Libraries/HyperNeat/include/LoadSaveSystem.hpp",
+ "/C/Programming/Libraries/HyperNeat/include/Saver.hpp",
+ "/C/Programming/Libraries/HyperNeat/src/Utils/File.cpp",
+ "/C/Programming/Libraries/HyperNeat/include/Utils/File.hpp"
+ ],
+ "find":
+ {
+ "height": 36.0
+ },
+ "find_in_files":
+ {
+ "height": 92.0,
+ "where_history":
+ [
+ ""
+ ]
+ },
+ "find_state":
+ {
+ "case_sensitive": true,
+ "find_history":
+ [
+ "BlendMode",
+ "fieldGenerator",
+ "value",
+ "_grid",
+ "223",
+ "refNeuron",
+ "0",
+ "PIXEL_SIZE",
+ "cout",
+ "_windowOpen",
+ "64",
+ "bias",
+ "pos",
+ "bias",
+ "PIXEL",
+ "CPPN_EX_WIDTH",
+ "_withNeuralNet",
+ "600",
+ "512",
+ "_window",
+ "System",
+ "Graphics",
+ "RenderWindow",
+ "WIN",
+ "sf::",
+ "gridClr",
+ "64",
+ "sf::",
+ " = nullptr",
+ "16",
+ "128",
+ "=",
+ "_resolution",
+ "SunDir",
+ "16",
+ "128",
+ "32",
+ "sf::Uint8",
+ "Alpha",
+ "sf::Color::White",
+ "{ 0, 0, 0, 0 }",
+ "sf::Color::Black",
+ "Add",
+ "2",
+ "1.0f",
+ "Thickness",
+ "setOrigin",
+ "0",
+ "_uiColor",
+ "0.0",
+ "resolution",
+ "Neurons",
+ "\\",
+ "{ 0, 0, 0 }",
+ "_uiColor",
+ "6",
+ "8",
+ "10",
+ "3",
+ "_uiColor",
+ "{ 0, 0, 0 }",
+ ", 128",
+ "PIXEL * 1.0f",
+ "6",
+ "4",
+ "0",
+ "_cppn.outputAt(0)",
+ "_valueImage.",
+ "bias",
+ "mage",
+ "val",
+ "*",
+ "{ 0, 0, 0, 128 }",
+ "_uiColor",
+ "4.",
+ "3.0",
+ "2",
+ "1.5",
+ "colorInt / 2",
+ "radius",
+ "_body",
+ "64",
+ "0",
+ "20",
+ "128",
+ "20.0",
+ "16",
+ "10.0",
+ "0.025f",
+ "2",
+ "4",
+ "x1",
+ "1",
+ "x",
+ "_weight",
+ "64",
+ "PIXEL",
+ "0.008f",
+ "0",
+ "_body",
+ "128",
+ "0.1",
+ "Scale",
+ "H",
+ ", 2, sf::Lines",
+ ")",
+ "sf::Vertex(",
+ "sf::Vector2f",
+ "Color",
+ "cursor",
+ "cVal",
+ "weight",
+ "_cppn",
+ "weight",
+ "_cppn",
+ "cVal",
+ " - cBias",
+ "abs(",
+ "cVal",
+ "val",
+ "static_cast<double>(",
+ "0",
+ "int",
+ "int(255)",
+ "sf::Uint8",
+ "float",
+ "x",
+ "cppn"
+ ],
+ "highlight": true,
+ "in_selection": false,
+ "preserve_case": false,
+ "regex": true,
+ "replace_history":
+ [
+ "_"
+ ],
+ "reverse": false,
+ "show_context": true,
+ "use_buffer2": true,
+ "whole_word": false,
+ "wrap": true
+ },
+ "groups":
+ [
+ {
+ "selected": 2,
+ "sheets":
+ [
+ {
+ "buffer": 0,
+ "file": "todolist.txt",
+ "semi_transient": false,
+ "settings":
+ {
+ "buffer_size": 1115,
+ "regions":
+ {
+ },
+ "selection":
+ [
+ [
+ 363,
+ 363
+ ]
+ ],
+ "settings":
+ {
+ "BracketHighlighterBusy": false,
+ "bh_regions":
+ [
+ "bh_double_quote",
+ "bh_double_quote_center",
+ "bh_double_quote_open",
+ "bh_double_quote_close",
+ "bh_square",
+ "bh_square_center",
+ "bh_square_open",
+ "bh_square_close",
+ "bh_regex",
+ "bh_regex_center",
+ "bh_regex_open",
+ "bh_regex_close",
+ "bh_curly",
+ "bh_curly_center",
+ "bh_curly_open",
+ "bh_curly_close",
+ "bh_angle",
+ "bh_angle_center",
+ "bh_angle_open",
+ "bh_angle_close",
+ "bh_tag",
+ "bh_tag_center",
+ "bh_tag_open",
+ "bh_tag_close",
+ "bh_default",
+ "bh_default_center",
+ "bh_default_open",
+ "bh_default_close",
+ "bh_round",
+ "bh_round_center",
+ "bh_round_open",
+ "bh_round_close",
+ "bh_unmatched",
+ "bh_unmatched_center",
+ "bh_unmatched_open",
+ "bh_unmatched_close",
+ "bh_single_quote",
+ "bh_single_quote_center",
+ "bh_single_quote_open",
+ "bh_single_quote_close"
+ ],
+ "syntax": "Packages/PlainTasks/PlainTasks.tmLanguage",
+ "tab_size": 2,
+ "translate_tabs_to_spaces": true
+ },
+ "translation.x": 0.0,
+ "translation.y": 0.0,
+ "zoom_level": 1.0
+ },
+ "stack_index": 2,
+ "type": "text"
+ },
+ {
+ "buffer": 1,
+ "file": "include/CppnExplorer.hpp",
+ "semi_transient": false,
+ "settings":
+ {
+ "buffer_size": 4318,
+ "regions":
+ {
+ },
+ "selection":
+ [
+ [
+ 391,
+ 391
+ ]
+ ],
+ "settings":
+ {
+ "BracketHighlighterBusy": false,
+ "bh_regions":
+ [
+ "bh_double_quote",
+ "bh_double_quote_center",
+ "bh_double_quote_open",
+ "bh_double_quote_close",
+ "bh_square",
+ "bh_square_center",
+ "bh_square_open",
+ "bh_square_close",
+ "bh_regex",
+ "bh_regex_center",
+ "bh_regex_open",
+ "bh_regex_close",
+ "bh_curly",
+ "bh_curly_center",
+ "bh_curly_open",
+ "bh_curly_close",
+ "bh_angle",
+ "bh_angle_center",
+ "bh_angle_open",
+ "bh_angle_close",
+ "bh_tag",
+ "bh_tag_center",
+ "bh_tag_open",
+ "bh_tag_close",
+ "bh_default",
+ "bh_default_center",
+ "bh_default_open",
+ "bh_default_close",
+ "bh_round",
+ "bh_round_center",
+ "bh_round_open",
+ "bh_round_close",
+ "bh_unmatched",
+ "bh_unmatched_center",
+ "bh_unmatched_open",
+ "bh_unmatched_close",
+ "bh_single_quote",
+ "bh_single_quote_center",
+ "bh_single_quote_open",
+ "bh_single_quote_close"
+ ],
+ "syntax": "Packages/C++ Starting Kit/CCpp.tmLanguage",
+ "tab_size": 4,
+ "translate_tabs_to_spaces": true
+ },
+ "translation.x": 0.0,
+ "translation.y": 0.0,
+ "zoom_level": 1.0
+ },
+ "stack_index": 1,
+ "type": "text"
+ },
+ {
+ "buffer": 2,
+ "file": "src/CppnExplorer.cpp",
+ "semi_transient": false,
+ "settings":
+ {
+ "buffer_size": 17141,
+ "regions":
+ {
+ },
+ "selection":
+ [
+ [
+ 1778,
+ 1778
+ ]
+ ],
+ "settings":
+ {
+ "BracketHighlighterBusy": false,
+ "bh_regions":
+ [
+ "bh_single_quote",
+ "bh_single_quote_center",
+ "bh_single_quote_open",
+ "bh_single_quote_close",
+ "bh_unmatched",
+ "bh_unmatched_center",
+ "bh_unmatched_open",
+ "bh_unmatched_close",
+ "bh_round",
+ "bh_round_center",
+ "bh_round_open",
+ "bh_round_close",
+ "bh_default",
+ "bh_default_center",
+ "bh_default_open",
+ "bh_default_close",
+ "bh_square",
+ "bh_square_center",
+ "bh_square_open",
+ "bh_square_close",
+ "bh_regex",
+ "bh_regex_center",
+ "bh_regex_open",
+ "bh_regex_close",
+ "bh_curly",
+ "bh_curly_center",
+ "bh_curly_open",
+ "bh_curly_close",
+ "bh_angle",
+ "bh_angle_center",
+ "bh_angle_open",
+ "bh_angle_close",
+ "bh_tag",
+ "bh_tag_center",
+ "bh_tag_open",
+ "bh_tag_close",
+ "bh_double_quote",
+ "bh_double_quote_center",
+ "bh_double_quote_open",
+ "bh_double_quote_close"
+ ],
+ "syntax": "Packages/C++ Starting Kit/CCpp.tmLanguage",
+ "tab_size": 4,
+ "translate_tabs_to_spaces": true
+ },
+ "translation.x": 0.0,
+ "translation.y": 828.0,
+ "zoom_level": 1.0
+ },
+ "stack_index": 0,
+ "type": "text"
+ }
+ ]
+ }
+ ],
+ "incremental_find":
+ {
+ "height": 0.0
+ },
+ "input":
+ {
+ "height": 30.0
+ },
+ "layout":
+ {
+ "cells":
+ [
+ [
+ 0,
+ 0,
+ 1,
+ 1
+ ]
+ ],
+ "cols":
+ [
+ 0.0,
+ 1.0
+ ],
+ "rows":
+ [
+ 0.0,
+ 1.0
+ ]
+ },
+ "menu_visible": false,
+ "output.exec":
+ {
+ "height": 96.0
+ },
+ "output.find_results":
+ {
+ "height": 0.0
+ },
+ "project": "CppnExplorer.sublime-project",
+ "replace":
+ {
+ "height": 64.0
+ },
+ "save_all_on_build": true,
+ "select_file":
+ {
+ "height": 0.0,
+ "selected_items":
+ [
+ ],
+ "width": 0.0
+ },
+ "select_project":
+ {
+ "height": 500.0,
+ "selected_items":
+ [
+ [
+ "",
+ "C:\\Projects\\Libraries\\HyperNeat\\HyperNeat.sublime-project"
+ ]
+ ],
+ "width": 805.0
+ },
+ "select_symbol":
+ {
+ "height": 0.0,
+ "selected_items":
+ [
+ ],
+ "width": 0.0
+ },
+ "settings":
+ {
+ },
+ "show_minimap": true,
+ "show_open_files": false,
+ "show_tabs": true,
+ "side_bar_visible": true,
+ "side_bar_width": 160.0,
+ "status_bar_visible": true,
+ "template_settings":
+ {
+ }
+}
diff --git a/plugins/CppnExplorer/Makefile b/plugins/CppnExplorer/Makefile
new file mode 100644
index 0000000..0d31499
--- /dev/null
+++ b/plugins/CppnExplorer/Makefile
@@ -0,0 +1,19 @@
+LIBRARY := lib/libCppnExplorer.a
+SOURCES := $(wildcard src/*.cpp)
+OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
+DEPS := $(patsubst %.o,%.d,$(OBJECTS))
+CFLAGS := -c -O3 -Wall -std=c++11 -MMD -Iinclude -I../../include -IC:/SFML/include
+LFLAGS := rvs
+
+all: $(OBJECTS)
+ ar $(LFLAGS) $(LIBRARY) $(OBJECTS)
+
+-include $(DEPS)
+
+$(OBJECTS): $(patsubst obj/%.o,src/%.cpp,$@)
+ g++ $(CFLAGS) $(patsubst obj/%.o,src/%.cpp,$@) -o $@
+
+clean:
+ del lib\*.a
+ del obj\*.o
+ del obj\*.d
diff --git a/plugins/CppnExplorer/include/CppnExplorer.hpp b/plugins/CppnExplorer/include/CppnExplorer.hpp
new file mode 100644
index 0000000..5ca20c5
--- /dev/null
+++ b/plugins/CppnExplorer/include/CppnExplorer.hpp
@@ -0,0 +1,129 @@
+#ifndef __CPPN_EXPLORER_HPP__
+#define __CPPN_EXPLORER_HPP__
+
+#include <Hyperneat/Cppn.hpp>
+#include <Hyperneat/Genome.hpp>
+#include <Hyperneat/NeuralNet.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <HyperNeat/Utils/Atomic.hpp>
+#include <HyperNeat/Utils/Thread.hpp>
+#include <Hyperneat/NeuralNetPrms.hpp>
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/Graphics/CircleShape.hpp>
+#include <SFML/Graphics/RenderWindow.hpp>
+#include <SFML/Graphics/RectangleShape.hpp>
+
+namespace hyperneat
+{
+ class CppnExplorer
+ {
+ public:
+ CppnExplorer();
+ ~CppnExplorer();
+
+ void run(const Genome& genome, const NeuralNetPrms* nnPrms = nullptr, sf::RenderTarget* target = nullptr);
+ void shutdown();
+ void draw();
+
+ // void run(const Genome& genome, const NeuralNetPrms& nnPrms);
+ // void shutdown();
+
+ private:
+ void windowHandler();
+ void eventHandler();
+ void neuralNetGenerator();
+ void fieldGenerator();
+
+ class Neuron
+ {
+ public:
+ Neuron(const NeuralNet::Neuron& refNeuron);
+
+ sf::VertexArray _synapses = sf::VertexArray(sf::Lines);
+ sf::CircleShape _nucleus = sf::CircleShape(4.0f * PIXEL_SIZE, 12);
+ };
+
+ Cppn _cppn;
+ Genome _genome;
+ NeuralNetPrms _nnPrms;
+ Vector<Neuron> _neurons;
+ NeuralNet _neuralNet;
+ bool _withNeuralNet = false;
+ Atomic<bool> _neuralNetReady = {false};
+
+ sf::RenderWindow _window;
+ Atomic<bool> _windowOpen = {false};
+ sf::RenderTarget* _target = nullptr;
+ const sf::Color _uiColor = {255, 255, 255, 8};
+
+ sf::Image _fieldImage;
+ sf::RectangleShape _fieldSprite;
+ sf::Texture _fieldTexture;
+ size_t _currentField = 0;
+ Atomic<bool> _fieldReady = {false};
+
+ Thread _windowHandler;
+ Thread _fieldGenerator;
+ Thread _neuralNetGenerator;
+
+ static constexpr unsigned RESOLUTION = 512;
+ static constexpr float PIXEL_SIZE = 1.0f / static_cast<float>(RESOLUTION);
+
+ // class Neuron
+ // {
+ // public:
+ // enum class Type {
+ // INPUT,
+ // HIDDEN,
+ // OUTPUT
+ // };
+
+ // Type _type;
+ // sf::CircleShape _body = sf::CircleShape(0.0f, 30);
+ // sf::CircleShape _nucleus = sf::CircleShape(0.0f, 30);
+ // sf::VertexArray _synapses = sf::VertexArray(sf::Lines);
+ // };
+
+ // void print(const sf::Color* field);
+ // void placeCursorAt(const sf::Vector2f& newPos);
+ // void createNeuron(Neuron& repNeuron, const NeuralNet::Neuron& srcNeuron);
+
+ // Cppn _cppn;
+ // Genome _genome;
+ // NeuralNet _neuralNet;
+ // NeuralNetPrms _nnPrms;
+
+ // const unsigned RESOLUTION = 512;
+ // sf::RenderWindow _window;
+ // Atomic<bool> _running;
+ // Thread _executor;
+
+ // const sf::Color WEIGHTS = { 128, 0, 255 };
+ // const sf::Color INV_WEIGHTS = { 255, 0, 128 };
+ // const sf::Color BIAS = { 0, 255, 255 };
+ // const sf::Color* _field = &WEIGHTS;
+
+ // sf::Image _valueImage;
+ // sf::Texture _valueTexture;
+ // sf::RectangleShape _valueSprite;
+ // sf::Image _biasImage;
+ // sf::Texture _biasTexture;
+ // sf::RectangleShape _biasSprite;
+ // bool _showBias = false;
+
+ // const sf::Color _uiColor = { 64, 64, 64 };
+ // const float PIXEL = 1.0f / static_cast<float>(RESOLUTION);
+
+ // sf::Vector2f _cursorPos = { 0.0f, 0.0f };
+ // sf::RectangleShape _cursorH = sf::RectangleShape(sf::Vector2f(0.2f, PIXEL * 3.0f));
+ // sf::RectangleShape _cursorV = sf::RectangleShape(sf::Vector2f(PIXEL * 3.0f, 0.2f));
+ // sf::VertexArray _grid = sf::VertexArray(sf::Lines);
+
+ // bool _showField = true;
+ // bool _showNeurons = true;
+ // bool _showGrid = true;
+ // Vector<Neuron> _neurons;
+ };
+}
+
+#endif
diff --git a/plugins/CppnExplorer/lib/.keep b/plugins/CppnExplorer/lib/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/CppnExplorer/lib/.keep
diff --git a/plugins/CppnExplorer/obj/.keep b/plugins/CppnExplorer/obj/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/CppnExplorer/obj/.keep
diff --git a/plugins/CppnExplorer/src/CppnExplorer.cpp b/plugins/CppnExplorer/src/CppnExplorer.cpp
new file mode 100644
index 0000000..555922a
--- /dev/null
+++ b/plugins/CppnExplorer/src/CppnExplorer.cpp
@@ -0,0 +1,549 @@
+#include <CppnExplorer.hpp>
+#include <SFML/Window/Event.hpp>
+#include <HyperNeat/Utils/Point.hpp>
+
+using namespace sf;
+using namespace hyperneat;
+
+CppnExplorer::CppnExplorer()
+{
+ _fieldSprite.setOrigin(1.0f, 1.0f);
+ _fieldSprite.setPosition(0.0f, 0.0f);
+ _fieldSprite.setTexture(&_fieldTexture);
+ _fieldSprite.setSize(Vector2f(2.0f, 2.0f));
+ _fieldImage.create(RESOLUTION, RESOLUTION);
+}
+
+CppnExplorer::~CppnExplorer()
+{
+ shutdown();
+}
+
+void
+CppnExplorer::run(const Genome& genome, const NeuralNetPrms* nnPrms, RenderTarget* target)
+{
+ shutdown();
+ _target = target;
+ _genome = genome;
+
+ _cppn.clear();
+ _cppn.create(_genome);
+
+ if (nnPrms) {
+ _withNeuralNet = true;
+ _nnPrms = *nnPrms;
+ _neuralNetGenerator = Thread(&CppnExplorer::neuralNetGenerator, this);
+ }
+
+ if (!_target) {
+ _windowOpen = true;
+ _target = &_window;
+ _windowHandler = Thread(&CppnExplorer::windowHandler, this);
+ }
+
+ _fieldGenerator = Thread(&CppnExplorer::fieldGenerator, this);
+}
+
+void
+CppnExplorer::shutdown()
+{
+ if (_neuralNetGenerator.joinable()) {
+ _neuralNetGenerator.join();
+ }
+
+ if (_windowHandler.joinable()) {
+ _windowOpen = false;
+ _windowHandler.join();
+ }
+
+ _neurons.clear();
+ _withNeuralNet = false;
+ _neuralNetReady = false;
+ _windowOpen = false;
+ _target = nullptr;
+}
+
+void
+CppnExplorer::draw()
+{
+ _target->clear({8, 8, 16});
+
+ if (_neuralNetReady) {
+ for (auto& i : _neurons) {
+ _target->draw(i._synapses, BlendAdd);
+ }
+
+ for (auto& i : _neurons) {
+ _target->draw(i._nucleus, BlendAdd);
+ }
+ }
+
+ if (_windowOpen) {
+ _window.display();
+ }
+}
+
+void
+CppnExplorer::windowHandler()
+{
+ ContextSettings settings(0, 0, 8);
+ String title("Cppn Explorer");
+ View view({-1.0f, -1.0f, 2.0f, 2.0f});
+ VideoMode videoMode(RESOLUTION, RESOLUTION);
+ Uint32 style(Style::Titlebar | Style::Close);
+
+ _window.create(videoMode, title, style, settings);
+ _window.setVerticalSyncEnabled(true);
+ _window.setView(view);
+
+ while (_windowOpen) {
+ eventHandler();
+ draw();
+ }
+}
+
+void
+CppnExplorer::eventHandler()
+{
+ Event event;
+
+ while (_window.pollEvent(event)) {
+ switch (event.type) {
+ case Event::Closed:
+ _windowOpen = false;
+ break;
+
+ default:;
+ }
+ }
+}
+
+void
+CppnExplorer::neuralNetGenerator()
+{
+ _neuralNet.clear();
+ _neuralNet.create(_cppn, _nnPrms);
+
+ _neurons.reserve(_neuralNet.getNeurons().size());
+
+ for (auto& i : _neuralNet.getNeurons()) {
+ _neurons.emplace_back(i);
+ }
+
+ _neuralNetReady = true;
+}
+
+void
+CppnExplorer::fieldGenerator()
+{
+
+}
+
+CppnExplorer::Neuron::Neuron(const NeuralNet::Neuron& refNeuron)
+{
+ _nucleus.setPosition(refNeuron._position._x, refNeuron._position._y);
+ _nucleus.setOrigin(_nucleus.getRadius(), _nucleus.getRadius());
+
+ Color nColor = (refNeuron._bias > 0.0 ? Color::White : Color::Red);
+ nColor.a = static_cast<Uint8>(fabs((refNeuron._bias / 3.0) * 112.0) + 16.0);
+ _nucleus.setFillColor(nColor);
+
+ switch (refNeuron._type) {
+ case NeuralNet::Neuron::Type::INPUT:
+ _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE);
+ _nucleus.setOutlineColor({255, 255, 255, nColor.a});
+ break;
+
+ case NeuralNet::Neuron::Type::OUTPUT:
+ _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE);
+ _nucleus.setOutlineColor({255, 0, 0, nColor.a});
+ break;
+
+ default:;
+ }
+
+ for (auto& i : refNeuron._synapses) {
+ auto iNeuron = *i._neuron;
+ Color sColor = (i._weight > 0.0 ? Color::White : Color::Red);
+ sColor.a = static_cast<Uint8>(fabs((i._weight / 3.0) * 112.0) + 16.0);
+ Vector2f iPos = {static_cast<float>(iNeuron._position._x), static_cast<float>(iNeuron._position._y)};
+ Vector2f tPos = {static_cast<float>(refNeuron._position._x), static_cast<float>(refNeuron._position._y)};
+
+ _synapses.append({iPos, sColor});
+ _synapses.append({tPos, sColor});
+ }
+}
+
+// void
+// CppnExplorer::run(const Genome& genome, const NeuralNetPrms& nnPrms)
+// {
+// shutdown();
+
+// _genome = genome;
+// _nnPrms = nnPrms;
+
+// _cppn.create(_genome);
+// _neuralNet.create(_cppn, _nnPrms);
+
+// {
+// float gridStep = 2.0f / 16.0f;
+// Color gridClr = _uiColor;
+// gridClr.a = 64;
+
+// for (float i = -1.0f; i <= 1.0f; i += gridStep) {
+// _grid.append({{ -1.0f, i }, gridClr });
+// _grid.append({{ 1.0f, i }, gridClr });
+// _grid.append({{ i, -1.0f }, gridClr });
+// _grid.append({{ i, 1.0f }, gridClr });
+// }
+// }
+
+// _executor = Thread([&]() {
+// _running = true;
+
+// {
+// VideoMode videoMode(RESOLUTION, RESOLUTION);
+// String title("Cppn Explorer");
+// Uint32 style(Style::Titlebar | Style::Close);
+// ContextSettings settings(0, 0, 8);
+// View view(FloatRect(-1.0f, -1.0f, 2.0f, 2.0f));
+
+// _window.create(videoMode, title, style, settings);
+// _window.setVerticalSyncEnabled(true);
+// _window.setView(view);
+// }
+
+// _cppn.inputAt(5) = 1.0;
+
+// _valueImage.create(RESOLUTION, RESOLUTION);
+// _biasImage.create(RESOLUTION, RESOLUTION);
+// print(&WEIGHTS);
+// print(&BIAS);
+
+// _valueSprite.setTexture(&_valueTexture);
+// _valueSprite.setSize(Vector2f(2.0f, 2.0f));
+// _valueSprite.setOrigin(1.0f, 1.0f);
+// _valueSprite.setPosition(0.0f, 0.0f);
+
+// _biasSprite.setTexture(&_biasTexture);
+// _biasSprite.setSize(Vector2f(2.0f, 2.0f));
+// _biasSprite.setOrigin(1.0f, 1.0f);
+// _biasSprite.setPosition(0.0f, 0.0f);
+
+// _cursorH.setFillColor(_uiColor);
+// _cursorV.setFillColor(_uiColor);
+// _cursorH.setOrigin(_cursorH.getSize() / 2.0f);
+// _cursorV.setOrigin(_cursorV.getSize() / 2.0f);
+// _cursorH.setOutlineThickness(PIXEL);
+// _cursorV.setOutlineThickness(PIXEL);
+// _cursorH.setOutlineColor({ 128, 128, 128 });
+// _cursorV.setOutlineColor({ 128, 128, 128 });
+
+// _neurons.reserve(_neuralNet.getNeuronsCount());
+
+// for (auto& i : _neuralNet.getNeurons()) {
+// _neurons.emplace_back();
+// createNeuron(_neurons.back(), i);
+// }
+
+// while (_running) {
+// Event event;
+
+// while (_window.pollEvent(event)) {
+// switch (event.type) {
+// case Event::KeyPressed:
+// switch (event.key.code) {
+// case Keyboard::B:
+// _showBias = !_showBias;
+// break;
+
+// case Keyboard::C:
+// placeCursorAt({ 0.0f, 0.0f });
+// print(_field);
+// break;
+
+// case Keyboard::F:
+// _field == &WEIGHTS ? ++_field : --_field;
+// print(_field);
+// break;
+
+// case Keyboard::V:
+// _showField = !_showField;
+// break;
+
+// case Keyboard::N:
+// _showNeurons = !_showNeurons;
+// break;
+
+// case Keyboard::G:
+// _showGrid = !_showGrid;
+// break;
+
+// default:;
+// }
+
+// break;
+
+// case Event::MouseButtonPressed:
+// if (event.mouseButton.button == Mouse::Left) {
+// placeCursorAt(_window.mapPixelToCoords(Mouse::getPosition(_window)));
+// print(_field);
+// }
+
+// break;
+
+// case Event::Closed:
+// _running = false;
+// break;
+
+// default:;
+// }
+// }
+
+// _window.clear({ 8, 8, 16 });
+
+// if (_showField) {
+// if (_showBias) {
+// _window.draw(_biasSprite);
+// } else {
+// _window.draw(_valueSprite);
+// }
+// }
+
+// if (_showGrid) {
+// _window.draw(_grid, { BlendMode::BlendAdd });
+// }
+
+// if (_showNeurons) {
+// for (auto& i : _neurons) {
+// _window.draw(i._synapses);
+// }
+
+// for (auto& i : _neurons) {
+// if (i._type != Neuron::Type::HIDDEN) {
+// continue;
+// }
+
+// _window.draw(i._body);
+// _window.draw(i._nucleus);
+// }
+
+// for (auto& i : _neurons) {
+// if (i._type == Neuron::Type::HIDDEN) {
+// continue;
+// }
+
+// _window.draw(i._body);
+// _window.draw(i._nucleus);
+// }
+// }
+
+// _window.draw(_cursorH);
+// _window.draw(_cursorV);
+
+// _window.display();
+// }
+// });
+// }
+
+// void
+// CppnExplorer::shutdown()
+// {
+// if (_executor.joinable()) {
+// _running = false;
+// _executor.join();
+// }
+
+// this->~CppnExplorer();
+// new (this) CppnExplorer();
+// }
+
+// void
+// CppnExplorer::print(const Color* field)
+// {
+// size_t out = 0;
+// double* x1 = nullptr;
+// double* y1 = nullptr;
+// double* x2 = nullptr;
+// double* y2 = nullptr;
+// Image* image = nullptr;
+// Texture* texture = nullptr;
+
+// if (field == &WEIGHTS) {
+// x1 = &_cppn.inputAt(0);
+// y1 = &_cppn.inputAt(1);
+// x2 = &_cppn.inputAt(2);
+// y2 = &_cppn.inputAt(3);
+// } else {
+// x1 = &_cppn.inputAt(2);
+// y1 = &_cppn.inputAt(3);
+// x2 = &_cppn.inputAt(0);
+// y2 = &_cppn.inputAt(1);
+// }
+
+// *x1 = _cursorPos.x;
+// *y1 = _cursorPos.y;
+
+// if (field == &BIAS) {
+// out = 1;
+// image = &_biasImage;
+// texture = &_biasTexture;
+// } else {
+// image = &_valueImage;
+// texture = &_valueTexture;
+// }
+
+// double half = static_cast<double>(RESOLUTION / 2);
+
+// for (unsigned y = 0; y < RESOLUTION; ++y) {
+// for (unsigned x = 0; x < RESOLUTION; ++x) {
+// *x2 = (static_cast<double>(x) - half) / half;
+// *y2 = (static_cast<double>(y) - half) / half;
+// _cppn.inputAt(4) = Point(*x1, *y1).distance(Point(*x2, *y2));
+// _cppn.cycle();
+
+// auto multColor = [](const Color& base, double factor) {
+// Color result;
+
+// result.r = static_cast<Uint8>(static_cast<double>(base.r) * factor);
+// result.g = static_cast<Uint8>(static_cast<double>(base.g) * factor);
+// result.b = static_cast<Uint8>(static_cast<double>(base.b) * factor);
+
+// return result;
+// };
+
+// if (_cppn.outputAt(out) > 0) {
+// image->setPixel(x, y, multColor(Color::White, _cppn.outputAt(out)));
+// } else {
+// image->setPixel(x, y, multColor(*field, fabs(_cppn.outputAt(out))));
+// }
+// }
+// }
+
+// texture->loadFromImage(*image);
+// }
+
+// void
+// CppnExplorer::placeCursorAt(const Vector2f& newPos)
+// {
+// _cursorPos = newPos;
+// _cursorH.setPosition(_cursorPos);
+// _cursorV.setPosition(_cursorPos);
+// }
+
+// void
+// CppnExplorer::createNeuron(Neuron& repNeuron, const NeuralNet::Neuron& srcNeuron)
+// {
+// repNeuron._body.setOutlineThickness(PIXEL * 2.0f);
+// repNeuron._nucleus.setOutlineThickness(PIXEL * 2.0f);
+
+// float radius = 0.0f;
+// Color inputColor = BIAS;
+// Color hiddenColor = INV_WEIGHTS;
+// Color outputColor = WEIGHTS;
+
+// inputColor.a = 128;
+// hiddenColor.a = 128;
+// outputColor.a = 128;
+
+// switch (srcNeuron._type) {
+// case NeuralNet::Neuron::Type::INPUT:
+// repNeuron._type = Neuron::Type::INPUT;
+// repNeuron._body.setOutlineColor(inputColor);
+// repNeuron._body.setFillColor({ 0, 0, 0, 200 });
+// radius = PIXEL * 24.0f;
+// break;
+
+// case NeuralNet::Neuron::Type::HIDDEN:
+// repNeuron._type = Neuron::Type::HIDDEN;
+// repNeuron._body.setOutlineColor(hiddenColor);
+// repNeuron._body.setFillColor({ 0, 0, 0, 200 });
+
+// {
+// float level = 1.0f;
+// for (; srcNeuron._position._x * level != floor(srcNeuron._position._x * level); level *= 2.0f);
+// radius = 1.0f / (level * 4.0f);
+
+// if (radius > PIXEL * 16.0f) {
+// radius = PIXEL * 16.0f;
+// }
+// }
+
+// break;
+
+// case NeuralNet::Neuron::Type::OUTPUT:
+// repNeuron._type = Neuron::Type::OUTPUT;
+// repNeuron._body.setOutlineColor(outputColor);
+// repNeuron._body.setFillColor({ 0, 0, 0, 200 });
+// radius = PIXEL * 24.0f;
+// break;
+// }
+
+// repNeuron._body.setRadius(radius);
+// repNeuron._body.setOrigin(radius, radius);
+// repNeuron._body.setPosition(srcNeuron._position._x, srcNeuron._position._y);
+
+// repNeuron._nucleus.setRadius(radius / 2.0f);
+// repNeuron._nucleus.setOrigin(radius / 2.0f, radius / 2.0f);
+// repNeuron._nucleus.setPosition(srcNeuron._position._x, srcNeuron._position._y);
+// repNeuron._nucleus.setOutlineColor(repNeuron._body.getOutlineColor());
+
+// double multInt = static_cast<Uint8>(fabs(srcNeuron._bias / 3.0) * 255.0);
+// Color colorMult(multInt, multInt, multInt, 128);
+
+// if (srcNeuron._bias > 0) {
+// repNeuron._nucleus.setFillColor(Color::White * colorMult);
+// } else {
+// repNeuron._nucleus.setFillColor(BIAS * colorMult);
+// }
+
+// Color synColor = WEIGHTS;
+
+// for (auto& i : srcNeuron._synapses) {
+// for (auto& j : _neuralNet.getNeurons()) {
+// if (&j._output == i._input) {
+// Uint8 weight = static_cast<Uint8>(i._weight * 20.0);
+// Vector2f srcPos(j._position._x, j._position._y);
+
+// if (i._input == &srcNeuron._output) {
+// Color selfSynColor;
+
+// if (i._weight > 0.0) {
+// selfSynColor = Color(255, 255, 255, 20 + weight);
+// } else {
+// selfSynColor = synColor;
+// }
+
+// float rad2 = repNeuron._body.getRadius() * 2.0f;
+// Vector2f p1 = repNeuron._body.getPosition() + Vector2f(-rad2, -rad2);
+// Vector2f p2 = repNeuron._body.getPosition() + Vector2f(-rad2, rad2);
+// Vector2f p3 = repNeuron._body.getPosition() + Vector2f( rad2, rad2);
+// Vector2f p4 = repNeuron._body.getPosition() + Vector2f( rad2, -rad2);
+
+// repNeuron._synapses.append({ p1, selfSynColor });
+// repNeuron._synapses.append({ p2, selfSynColor });
+
+// repNeuron._synapses.append({ p2, selfSynColor });
+// repNeuron._synapses.append({ p3, selfSynColor });
+
+// repNeuron._synapses.append({ p3, selfSynColor });
+// repNeuron._synapses.append({ p4, selfSynColor });
+
+// repNeuron._synapses.append({ p4, selfSynColor });
+// repNeuron._synapses.append({ p1, selfSynColor });
+// } else {
+// repNeuron._synapses.append({ repNeuron._body.getPosition(), Color::Black });
+
+// if (i._weight > 0.0) {
+// repNeuron._synapses.append({{ srcPos }, Color(255, 255, 255, 20 + weight) });
+// } else {
+// synColor.a = 20 + weight;
+// repNeuron._synapses.append({{ srcPos }, synColor });
+// }
+// }
+
+// break;
+// }
+// }
+// }
+// }
diff --git a/plugins/CppnExplorer/todolist.txt b/plugins/CppnExplorer/todolist.txt
new file mode 100644
index 0000000..5677680
--- /dev/null
+++ b/plugins/CppnExplorer/todolist.txt
@@ -0,0 +1,21 @@
+Cppn Explorer:
+ ☐ Render to any sf::RenderTarget
+ ☐ Calculate field on separate thread (keep 2 textures)
+ ☐ Render Neurons as crossmarks
+ ☐ (When Rendering to Window) Cycle fields with F key
+ ☐ (When Rendering to Window) Cycle between Neurons and Synapses using arrow keys
+ ☐ Display text data
+ ☐ (When Rendering to Window) Embed icon
+ ☐ Show Cppn Network
+
+
+___________________
+Archive:
+ ✔ Display connection to same neuron as square around neuron @done (13-12-10 00:29) @project(Cppn Explorer)
+ ✔ Use better color and blending for neurons @done (13-11-25 00:24) @project(Cppn Explorer)
+ ✔ Display Synapses as blended lines with Transparency representing Weights @done (13-11-25 00:24) @project(Cppn Explorer)
+ ✔ Display cursor beatifully @done (13-11-23 20:31) @project(Cppn Explorer)
+ ✔ Display grid @done (13-11-23 01:58) @project(Cppn Explorer)
+ ✔ Fix cursor @done (13-11-21 02:18) @project(Cppn Explorer)
+ ✔ Print and switch between fields @done (13-11-06 04:35) @project(Cppn Explorer)
+ ✔ Display Neurons beautifully (with bias represented as a nucleus) @done (13-11-04 20:52) @project(Cppn Explorer)
diff --git a/src/Behavior.cpp b/src/Behavior.cpp
new file mode 100644
index 0000000..15b2ad9
--- /dev/null
+++ b/src/Behavior.cpp
@@ -0,0 +1,59 @@
+#include <HyperNeat/Behavior.hpp>
+#include <HyperNeat/NoveltyMetric.hpp>
+
+using namespace hyperneat;
+
+void
+Behavior::clear()
+{
+ _characterization.assign(_characterization.size(), 0.0);
+}
+
+void
+Behavior::reset(bool archive)
+{
+ if (_toBeArchived && archive) {
+ _noveltyMetric->_archive.emplace_back(_characterization);
+ }
+
+ _noveltyScore = 0.0;
+ _toBeArchived = false;
+ _criteriaReached = _noveltyMetric->_prms._criteriaReachedByDefault;
+ _characterization.assign(_characterization.size(), 0.0);
+}
+
+double&
+Behavior::at(size_t i)
+{
+ return _characterization[i];
+}
+
+double
+Behavior::getNoveltyScore() const
+{
+ return _noveltyScore;
+}
+
+bool
+Behavior::isToBeArchived() const
+{
+ return _toBeArchived;
+}
+
+Organism&
+Behavior::getOrganism()
+{
+ return *_organism;
+}
+
+const NoveltyMetric&
+Behavior::getNoveltyMetric() const
+{
+ return *_noveltyMetric;
+}
+
+const Vector<double>&
+Behavior::getCharacterization() const
+{
+ return _characterization;
+}
diff --git a/src/Cppn.cpp b/src/Cppn.cpp
new file mode 100644
index 0000000..fb1d19d
--- /dev/null
+++ b/src/Cppn.cpp
@@ -0,0 +1,292 @@
+#include <cmath>
+#include <HyperNeat/Cppn.hpp>
+#include <HyperNeat/Genome.hpp>
+#include <HyperNeat/QuadTree.hpp>
+#include <HyperNeat/Utils/Pi.hpp>
+#include <HyperNeat/NodeSearchPrms.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+void
+Cppn::create(const Genome& genome)
+{
+ using DepthSorter = Map<double, Map<size_t, const Genome::NodeGene*>>;
+ DepthSorter dSorter;
+
+ for (auto& i : genome._nodeGenes) {
+ dSorter[i.second._depth][i.first] = &i.second;
+ }
+
+ _inputs.resize(genome._inputs, 0.0);
+ _nodeLayers.resize(dSorter.size());
+
+ {
+ auto layerIter = _nodeLayers.begin();
+
+ for (auto& i : dSorter) {
+ layerIter->resize(i.second.size());
+ auto nodeIter = layerIter->begin();
+
+ for (auto& j : i.second) {
+ size_t enabledLinks = 0;
+
+ for (auto& k : j.second->_linkGenes) {
+ if (k.second._isEnabled) {
+ ++enabledLinks;
+ }
+ }
+
+ nodeIter->_links.resize(enabledLinks);
+ ++nodeIter;
+ }
+
+ ++layerIter;
+ }
+ }
+
+ size_t layerIdx = 0;
+
+ for (auto& i : dSorter) {
+ size_t nodeIdx = 0;
+
+ for (auto& j : i.second) {
+ Node& crntNode = _nodeLayers[layerIdx][nodeIdx];
+ size_t linkIdx = 0;
+
+ for (auto& k : j.second->_linkGenes) {
+ if (k.second._isEnabled) {
+ Node::Link& crntLink = crntNode._links[linkIdx];
+
+ if (k.first < _inputs.size()) {
+ crntLink._input = &_inputs[k.first];
+ } else {
+ double depth = genome._nodeGenes.at(k.first)._depth;
+ size_t layer = distance(dSorter.begin(), dSorter.find(depth));
+ size_t node = distance(dSorter[depth].begin(), dSorter[depth].find(k.first));
+
+ crntLink._input = &_nodeLayers[layer][node]._output;
+ }
+
+ crntLink._weight = k.second._weight;
+ ++linkIdx;
+ }
+ }
+
+ crntNode._nodeType = j.second->_nodeType;
+ ++nodeIdx;
+
+ if (i.first == 1.0) {
+ _outputs.push_back(&crntNode._output);
+ }
+ }
+
+ ++layerIdx;
+ }
+}
+
+void
+Cppn::clear()
+{
+ _inputs.clear();
+ _outputs.clear();
+ _nodeLayers.clear();
+}
+
+size_t
+Cppn::getInputsCount() const
+{
+ return _inputs.size();
+}
+
+size_t
+Cppn::getOutputsCount() const
+{
+ return _outputs.size();
+}
+
+size_t
+Cppn::getNodesCount() const
+{
+ size_t nodesCount = 0;
+
+ for (auto& i : _nodeLayers) {
+ nodesCount += i.size();
+ }
+
+ return nodesCount;
+}
+
+double&
+Cppn::inputAt(size_t i)
+{
+ return _inputs[i];
+}
+
+double
+Cppn::outputAt(size_t i) const
+{
+ return *_outputs[i];
+}
+
+void
+Cppn::cycle()
+{
+ for (auto& i : _nodeLayers) {
+ for (auto& j : i) {
+ j.appendInput();
+ }
+
+ for (auto& j : i) {
+ j.flushOutput();
+ }
+ }
+}
+
+void
+Cppn::findNodesIn2DSection(ValueMap& valueMap, const NodeSearchPrms& nsPrms, const Point& source)
+{
+ QuadTree qTree(1.0, 0.0, 0.0);
+
+ qTree.subdivide([&](QuadTree* qt) {
+ auto levelToSegment = [](size_t level) {
+ double dlevel = static_cast<double>(level);
+ return 1.0 / pow(2.0, dlevel);
+ };
+
+ double minQuadTreeSegment = levelToSegment(nsPrms._maxQuadTreeLevel);
+ double maxQuadTreeSegment = levelToSegment(nsPrms._minQuadTreeLevel);
+ double testGridResolution = levelToSegment(nsPrms._testGridLevel);
+
+ if (qt->getSegment() <= minQuadTreeSegment) {
+ return false;
+ }
+
+ if (qt->getSegment() > maxQuadTreeSegment) {
+ return true;
+ }
+
+ double gridStep = qt->getSegment() * 2.0 * testGridResolution;
+ double gridHalf = gridStep / 2.0;
+ double initX = qt->getX() - qt->getSegment() + gridHalf;
+ double initY = qt->getY() - qt->getSegment() + gridHalf;
+ double endX = qt->getX() + qt->getSegment();
+ double endY = qt->getY() + qt->getSegment();
+ double cellsNo = (1.0 / testGridResolution) * (1.0 / testGridResolution);
+
+ Vector<double> w;
+ w.reserve(static_cast<size_t>(cellsNo));
+
+ for (double y = initY; y < endY; y += gridStep) {
+ for (double x = initX; x < endX; x += gridStep) {
+ _inputs[nsPrms._x] = x;
+ _inputs[nsPrms._y] = y;
+
+ if (nsPrms._useDistance) {
+ _inputs[nsPrms._d] = Point(x, y).distance(source);
+ }
+
+ cycle();
+ w.emplace_back(*_outputs[nsPrms._o]);
+ }
+ }
+
+ double wMean = 0.0;
+ double variance = 0.0;
+
+ for (auto& i : w) {
+ wMean += i;
+ }
+
+ wMean /= cellsNo;
+
+ for (auto& i : w) {
+ variance += (wMean - i) * (wMean - i);
+ }
+
+ variance /= cellsNo;
+
+ if (variance > nsPrms._varianceThreshold) {
+ return true;
+ }
+
+ return false;
+ });
+
+ qTree.traverse([&](const QuadTree* qt) {
+ auto measureDistAndIO = [&]() {
+ if (nsPrms._useDistance) {
+ _inputs[nsPrms._d] = Point(_inputs[nsPrms._x], _inputs[nsPrms._y]).distance(source);
+ }
+
+ cycle();
+ return *_outputs[nsPrms._o];
+ };
+
+ double gridSize = qt->getSegment() * 2.0;
+
+ _inputs[nsPrms._y] = qt->getY();
+ _inputs[nsPrms._x] = qt->getX() - gridSize;
+ double valLeft = measureDistAndIO();
+
+ _inputs[nsPrms._x] = qt->getX() + gridSize;
+ double valRight = measureDistAndIO();
+
+ _inputs[nsPrms._x] = qt->getX();
+ _inputs[nsPrms._y] = qt->getY() - gridSize;
+ double valBottom = measureDistAndIO();
+
+ _inputs[nsPrms._y] = qt->getY() + gridSize;
+ double valTop = measureDistAndIO();
+
+ _inputs[nsPrms._y] = qt->getY();
+ double valCenter = measureDistAndIO();
+
+ valLeft = fabs(valCenter - valLeft);
+ valRight = fabs(valCenter - valRight);
+ valBottom = fabs(valCenter - valBottom);
+ valTop = fabs(valCenter - valTop);
+
+ double bandValue = max(min(valLeft, valRight), min(valBottom, valTop));
+
+ if (bandValue > nsPrms._bandPruningThreshold) {
+ valueMap.emplace_back(qt->getX(), qt->getY(), valCenter, qt->getSegment());
+ }
+ });
+}
+
+void
+Cppn::Node::appendInput()
+{
+ for (auto& i : _links) {
+ _storedInput += *i._input * i._weight;
+ }
+}
+
+void
+Cppn::Node::flushOutput()
+{
+ switch (_nodeType) {
+ case NodeType::SIGMOID:
+ _output = 1.0 / (1.0 + exp(-_storedInput * 2.0));
+ _output = _output * 2.0 - 1.0;
+ break;
+
+ case NodeType::GAUSSIAN:
+ _output = exp(-_storedInput * _storedInput);
+ _output = _output * 2.0 - 1.0;
+ break;
+
+ case NodeType::SINE:
+ _output = sin((_storedInput / 2.0) * PI);
+ break;
+
+ case NodeType::ABSOLUTE:
+ _output = max(min(fabs(_storedInput), 0.0), 1.0);
+ break;
+
+ default:;
+ }
+
+ _storedInput = 0.0;
+}
diff --git a/src/Genome.cpp b/src/Genome.cpp
new file mode 100644
index 0000000..ce5fc11
--- /dev/null
+++ b/src/Genome.cpp
@@ -0,0 +1,15 @@
+#include <HyperNeat/Genome.hpp>
+
+using namespace hyperneat;
+
+Genome::Genome(size_t inputs)
+ : _inputs(inputs)
+{}
+
+Genome::NodeGene::NodeGene(double depth, NodeType nodeType)
+ : _depth(depth), _nodeType(nodeType)
+{}
+
+Genome::NodeGene::LinkGene::LinkGene(double weight, bool isEnabled)
+ : _weight(weight), _isEnabled(isEnabled)
+{}
diff --git a/src/Innovation.cpp b/src/Innovation.cpp
new file mode 100644
index 0000000..0332616
--- /dev/null
+++ b/src/Innovation.cpp
@@ -0,0 +1,16 @@
+#include <Hyperneat/Innovation.hpp>
+
+using namespace hyperneat;
+
+Innovation::Innovation(size_t number, size_t source, size_t target, double depth, NodeType nodeType)
+ : _number(number), _source(source), _target(target), _depth(depth), _nodeType(nodeType)
+{}
+
+bool
+Innovation::operator==(const Innovation& other) const
+{
+ return (_source == other._source ) &&
+ (_target == other._target ) &&
+ (_depth == other._depth ) &&
+ (_nodeType == other._nodeType);
+}
diff --git a/src/NeuralNet.cpp b/src/NeuralNet.cpp
new file mode 100644
index 0000000..abed262
--- /dev/null
+++ b/src/NeuralNet.cpp
@@ -0,0 +1,294 @@
+#include <cmath>
+#include <algorithm>
+#include <HyperNeat/Cppn.hpp>
+#include <HyperNeat/NeuralNet.hpp>
+#include <HyperNeat/Utils/Map.hpp>
+#include <HyperNeat/Utils/Set.hpp>
+#include <HyperNeat/NeuralNetPrms.hpp>
+#include <HyperNeat/Utils/Function.hpp>
+#include <HyperNeat/NodeSearchPrms.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+void
+NeuralNet::create(Cppn& cppn, const NeuralNetPrms& nnPrms)
+{
+ class TempNeuronSynapse {
+ public:
+ TempNeuronSynapse() = default;
+ TempNeuronSynapse(double weight, Point neuronSource)
+ : _weight(weight), _neuronSource(neuronSource)
+ {}
+
+ double _weight = 0.0;
+ Point _neuronSource;
+ };
+
+ class TempNeuron {
+ public:
+ bool _isIncluded = false;
+ double _bias = 0.0;
+ Vector<TempNeuronSynapse> _neuronSynapses;
+ };
+
+ _inputs.reserve(nnPrms._inputMap.size());
+ _outputs.reserve(nnPrms._outputMap.size());
+
+ NodeSearchPrms nsPrms(0, 2, 3, 4);
+ nsPrms.importFrom(nnPrms);
+ cppn.inputAt(5) = 1.0;
+
+ Map<Point, TempNeuron> tempNeurons;
+
+ auto findConnections = [&](const Point& source, size_t x1, size_t y1, size_t x2, size_t y2, size_t d,
+ bool checkExist, Function<void(double, const Point&)> storeConn) {
+ cppn.inputAt(x1) = source._x;
+ cppn.inputAt(y1) = source._y;
+ cppn.inputAt(x2) = 0.0;
+ cppn.inputAt(y2) = 0.0;
+ cppn.inputAt(d) = 0.0;
+
+ ValueMap newConnections;
+ cppn.findNodesIn2DSection(newConnections, nsPrms, source);
+
+ for (auto& i : newConnections) {
+ if (checkExist && !tempNeurons.count(i)) {
+ continue;
+ }
+
+ if (fabs(i._value) > 0.2) {
+ storeConn((i._value + (i._value > 0 ? -0.2 : 0.2)) * 3.75, i);
+ }
+ }
+ };
+
+ {
+ Set<Point> neuronSet1;
+ Set<Point> neuronSet2;
+ Set<Point>* previousNeurons = &neuronSet1;
+ Set<Point>* nextNeurons = &neuronSet2;
+
+ for (auto& i : nnPrms._inputMap) {
+ tempNeurons[i];
+ previousNeurons->insert(i);
+ }
+
+ for (size_t i = 0; i < nnPrms._iterations && !previousNeurons->empty(); ++i) {
+ Map<Point, TempNeuron> newNeurons;
+
+ for (auto& j : *previousNeurons) {
+ findConnections(j, 0, 1, 2, 3, 4, false, [&](double weight, const Point& target) {
+ if (tempNeurons.count(target)) {
+ auto& synapses = tempNeurons[target]._neuronSynapses;
+ synapses.emplace_back(weight, j);
+ } else {
+ auto& synapses = newNeurons[target]._neuronSynapses;
+ synapses.emplace_back(weight, j);
+ nextNeurons->insert(target);
+ }
+ });
+ }
+
+ previousNeurons->clear();
+ swap(nextNeurons, previousNeurons);
+ tempNeurons.insert(newNeurons.begin(), newNeurons.end());
+ }
+ }
+
+ nsPrms._x = 0;
+ nsPrms._y = 1;
+
+ {
+ Vector<TempNeuron*> inclusionSet1;
+ Vector<TempNeuron*> inclusionSet2;
+ Vector<TempNeuron*>* crntInclusions = &inclusionSet1;
+ Vector<TempNeuron*>* nextInclusions = &inclusionSet2;
+
+ for (auto& i : nnPrms._outputMap) {
+ tempNeurons[i]._isIncluded = true;
+ nextInclusions->push_back(&tempNeurons[i]);
+
+ findConnections(i, 2, 3, 0, 1, 4, true, [&](double weight, const Point& target) {
+ auto& synapses = tempNeurons[i]._neuronSynapses;
+ synapses.emplace_back(weight, target);
+ });
+ }
+
+ while (!nextInclusions->empty()) {
+ crntInclusions->clear();
+ swap(crntInclusions, nextInclusions);
+
+ for (auto& i : *crntInclusions) {
+ for (auto& j : i->_neuronSynapses) {
+ auto& sourceNeuron = tempNeurons.at(j._neuronSource);
+
+ if (!sourceNeuron._isIncluded) {
+ nextInclusions->push_back(&sourceNeuron);
+ sourceNeuron._isIncluded = true;
+ }
+ }
+ }
+ }
+ }
+
+ for (auto& i : nnPrms._inputMap) {
+ tempNeurons[i]._isIncluded = true;
+ }
+
+ cppn.inputAt(2) = 0.0;
+ cppn.inputAt(3) = 0.0;
+ cppn.inputAt(4) = 0.0;
+
+ for (auto i = tempNeurons.begin(), end = tempNeurons.end(); i != end;) {
+ if (i->second._isIncluded) {
+ cppn.inputAt(0) = i->first._x;
+ cppn.inputAt(1) = i->first._y;
+ cppn.inputAt(4) = i->first.distance(Point());
+ cppn.cycle();
+ i->second._bias = cppn.outputAt(1) * 3.0;
+ ++i;
+ } else {
+ i = tempNeurons.erase(i);
+ }
+ }
+
+ _neurons.resize(tempNeurons.size());
+
+ {
+ auto nIter = _neurons.begin();
+
+ for (auto& i : tempNeurons) {
+ nIter->_bias = i.second._bias;
+ nIter->_position = i.first;
+ auto& crntNrnSyns = nIter->_synapses;
+ auto& neuronSynapses = i.second._neuronSynapses;
+ crntNrnSyns.reserve(neuronSynapses.size());
+
+ for (auto& j : neuronSynapses) {
+ auto src = tempNeurons.find(j._neuronSource);
+ size_t sIdx = distance(tempNeurons.begin(), src);
+ crntNrnSyns.emplace_back(&_neurons[sIdx], j._weight);
+ }
+
+ ++nIter;
+ }
+ }
+
+ auto relateIO = [&](Vector<double*>& ptrVec, const Vector<Point>& map, Neuron::Type type) {
+ for (auto& i : map) {
+ auto neuron = tempNeurons.find(i);
+ size_t nIdx = distance(tempNeurons.begin(), neuron);
+ _neurons[nIdx]._type = type;
+ ptrVec.push_back(&_neurons[nIdx]._output);
+ }
+ };
+
+ relateIO(_inputs, nnPrms._inputMap, Neuron::Type::INPUT);
+ relateIO(_outputs, nnPrms._outputMap, Neuron::Type::OUTPUT);
+}
+
+void
+NeuralNet::clear()
+{
+ _inputs.clear();
+ _outputs.clear();
+ _neurons.clear();
+}
+
+size_t
+NeuralNet::getInputsCount() const
+{
+ return _inputs.size();
+}
+
+size_t
+NeuralNet::getOutputsCount() const
+{
+ return _outputs.size();
+}
+
+size_t
+NeuralNet::getNeuronsCount() const
+{
+ return _neurons.size();
+}
+
+double
+NeuralNet::getAverageActivation() const
+{
+ double totalActivation = 0.0;
+
+ for (auto& i : _neurons) {
+ totalActivation += i._output;
+ }
+
+ return totalActivation / static_cast<double>(_neurons.size());
+}
+
+double&
+NeuralNet::inputAt(size_t i)
+{
+ return *_inputs[i];
+}
+
+double
+NeuralNet::outputAt(size_t i) const
+{
+ return *_outputs[i];
+}
+
+const Vector<double*>&
+NeuralNet::getInputs() const
+{
+ return _inputs;
+}
+
+const Vector<double*>&
+NeuralNet::getOutputs() const
+{
+ return _outputs;
+}
+
+const Vector<NeuralNet::Neuron>&
+NeuralNet::getNeurons() const
+{
+ return _neurons;
+}
+
+void
+NeuralNet::cycle()
+{
+ for (auto& i : _neurons) {
+ i.appendInput();
+ }
+
+ for (auto& i : _neurons) {
+ i.flushOutput();
+ }
+}
+
+NeuralNet::Neuron::Neuron(const Point& position, Type type, double bias)
+ : _position(position), _type(type), _bias(bias)
+{}
+
+void
+NeuralNet::Neuron::appendInput()
+{
+ for (auto& i : _synapses) {
+ _storedInput += *i._input * i._weight;
+ }
+
+ _storedInput += _bias;
+}
+
+void
+NeuralNet::Neuron::flushOutput()
+{
+ _output = 1.0 / (1.0 + exp(-_storedInput * 4.9));
+ _storedInput = 0.0;
+}
+
+NeuralNet::Neuron::Synapse::Synapse(Neuron* inputNeuron, double weight)
+ : _input(&inputNeuron->_output), _neuron(inputNeuron), _weight(weight)
+{}
diff --git a/src/NodeSearchPrms.cpp b/src/NodeSearchPrms.cpp
new file mode 100644
index 0000000..db2421a
--- /dev/null
+++ b/src/NodeSearchPrms.cpp
@@ -0,0 +1,23 @@
+#include <HyperNeat/NeuralNetPrms.hpp>
+#include <HyperNeat/NodeSearchPrms.hpp>
+
+using namespace hyperneat;
+
+NodeSearchPrms::NodeSearchPrms(size_t o, size_t x, size_t y)
+ : _o(o), _x(x), _y(y), _useDistance(false)
+{}
+
+NodeSearchPrms::NodeSearchPrms(size_t o, size_t x, size_t y, size_t d)
+ : _o(o), _x(x), _y(y), _d(d)
+{}
+
+void
+NodeSearchPrms::importFrom(const NeuralNetPrms& nnPrms)
+{
+ _testGridLevel = nnPrms._testGridLevel;
+ _maxQuadTreeLevel = nnPrms._maxQuadTreeLevel;
+ _minQuadTreeLevel = nnPrms._minQuadTreeLevel;
+ _bandPruningThreshold = nnPrms._bandPruningThreshold;
+ _varianceThreshold = nnPrms._varianceThreshold;
+ _divisionThreshold = nnPrms._divisionThreshold;
+}
diff --git a/src/NoveltyMetric.cpp b/src/NoveltyMetric.cpp
new file mode 100644
index 0000000..dd40118
--- /dev/null
+++ b/src/NoveltyMetric.cpp
@@ -0,0 +1,101 @@
+#include <algorithm>
+#include <Hyperneat/Population.hpp>
+#include <Hyperneat/NoveltyMetric.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+const NoveltyMetricPrms&
+NoveltyMetric::getPrms() const
+{
+ return _prms;
+}
+
+const Vector<Behavior>&
+NoveltyMetric::getBehaviors() const
+{
+ return _behaviors;
+}
+
+const Vector2D<double>&
+NoveltyMetric::getArchive() const
+{
+ return _archive;
+}
+
+Behavior&
+NoveltyMetric::getBehaviorOf(size_t i)
+{
+ return _behaviors[i];
+}
+
+void
+NoveltyMetric::initialize(const NoveltyMetricPrms& prms, Population* population)
+{
+ _prms = prms;
+ _behaviors.resize(population->getAllOrganisms().size());
+
+ for (size_t i = 0; i < _behaviors.size(); ++i) {
+ population->getOrganism(i)._behavior = &_behaviors[i];
+ _behaviors[i]._organism = &population->getOrganism(i);
+ _behaviors[i]._noveltyMetric = this;
+ _behaviors[i]._criteriaReached = prms._criteriaReachedByDefault;
+ _behaviors[i]._characterization.resize(prms._characterizationSize, 0.0);
+ }
+}
+
+void
+NoveltyMetric::setScores()
+{
+ size_t readyOrganisms = 0;
+
+ for (auto& i : _behaviors) {
+ if ((i._isReady = (i._organism->isOld() && i._criteriaReached))) {
+ ++readyOrganisms;
+ }
+ }
+
+ for (auto& i : _behaviors) {
+ if (!i._isReady) {
+ i._toBeArchived = false;
+ i._organism->_fitness = i._noveltyScore = 0.0;
+ continue;
+ }
+
+ Vector<double> distances;
+ distances.reserve(readyOrganisms + _archive.size() - 1);
+
+ for (auto& j : _behaviors) {
+ if (j._isReady && (&i != &j)) {
+ distances.emplace_back(getDistance(i._characterization, j._characterization));
+ }
+ }
+
+ for (auto& j : _archive) {
+ distances.emplace_back(getDistance(i._characterization, j));
+ }
+
+ auto dEnd = distances.end();
+ auto dBeg = distances.begin();
+ auto dRef = dBeg + _prms._referenceOrganisms;
+
+ partial_sort(dBeg, dRef, dEnd);
+
+ double totalDistance = accumulate(dBeg, dRef, 0.0);
+ i._organism->_fitness = i._noveltyScore = (totalDistance / static_cast<double>(_prms._referenceOrganisms));
+ i._toBeArchived = (i._noveltyScore > _prms._noveltyThreshold);
+ }
+}
+
+double
+NoveltyMetric::getDistance(const Vector<double>& v1, const Vector<double>& v2) const
+{
+ double result = 0.0;
+
+ for (size_t i = 0; i < v1.size(); ++i) {
+ double diff = v1[i] - v2[i];
+ result += diff * diff;
+ }
+
+ return sqrt(result);
+}
diff --git a/src/Organism.cpp b/src/Organism.cpp
new file mode 100644
index 0000000..0c2c1bc
--- /dev/null
+++ b/src/Organism.cpp
@@ -0,0 +1,180 @@
+#include <HyperNeat/Cppn.hpp>
+#include <HyperNeat/Behavior.hpp>
+#include <HyperNeat/NeuralNet.hpp>
+#include <HyperNeat/Population.hpp>
+#include <HyperNeat/Utils/Thread.hpp>
+#include <HyperNeat/NeuralNetPrms.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+Organism::Organism(const Organism& other)
+{
+ *this = other;
+}
+
+Organism&
+Organism::operator=(const Organism& other)
+{
+ _fitness = other._fitness;
+ _index = other._index;
+ _isLocked = other._isLocked;
+ _isFrozen = other._isFrozen;
+ _specie = other._specie;
+ _lifetime = other._lifetime;
+ _genome = other._genome;
+ _population = other._population;
+
+ return *this;
+}
+
+size_t
+Organism::getIndex() const
+{
+ return _index;
+}
+
+void
+Organism::lock()
+{
+ if (!_isLocked) {
+ _isLocked = true;
+ ++_population->_lockedOrganisms;
+ }
+}
+
+void
+Organism::unlock()
+{
+ if (_isLocked) {
+ _isLocked = false;
+ --_population->_lockedOrganisms;
+ }
+}
+
+bool
+Organism::isLocked() const
+{
+ return _isLocked;
+}
+
+void
+Organism::freeze()
+{
+ if (!_isFrozen) {
+ _isFrozen = true;
+ ++_population->_frozenOrganisms;
+ }
+}
+
+void
+Organism::unfreeze()
+{
+ if (_isFrozen) {
+ _isFrozen = false;
+ --_population->_frozenOrganisms;
+ }
+}
+
+bool
+Organism::isFrozen() const
+{
+ return _isFrozen;
+}
+
+bool
+Organism::isBeingGenerated() const
+{
+ return _isBeingGenerated;
+}
+
+size_t
+Organism::getSpecie() const
+{
+ return _specie;
+}
+
+bool
+Organism::isOld() const {
+ return _lifetime >= _population->_prms._minimumLifetime;
+}
+
+size_t
+Organism::getLifetime() const
+{
+ return _lifetime;
+}
+
+Behavior&
+Organism::getBehavior()
+{
+ return *_behavior;
+}
+
+const Genome&
+Organism::getGenome() const
+{
+ return _genome;
+}
+
+bool
+Organism::isChampion() const
+{
+ return &_population->getChampion() == this;
+}
+
+Population&
+Organism::getPopulation() const
+{
+ return *_population;
+}
+
+void
+Organism::createNeuralNet()
+{
+ if (_isBeingGenerated) {
+ return;
+ }
+
+ _isBeingGenerated = true;
+ ++_population->_organismsBeingGenerated;
+
+ Thread generator([&]() {
+ Cppn cppn;
+ cppn.create(_genome);
+
+ _neuralNet->clear();
+ _neuralNet->create(cppn, _population->getNeuralNetPrms());
+
+ _isBeingGenerated = false;
+ --_population->_organismsBeingGenerated;
+ });
+
+ generator.detach();
+}
+
+Organism::Organism(Population* population)
+ : _population(population)
+{}
+
+Organism::Organism(size_t inputs, Population* population)
+ : _genome(inputs), _population(population)
+{}
+
+void
+Organism::reset(bool archive)
+{
+ unlock();
+ unfreeze();
+
+ if (isOld()) {
+ --_population->_oldOrganisms;
+ }
+
+ _lifetime = 0;
+ _fitness = 0.0;
+
+ if (_behavior) {
+ _behavior->reset(archive);
+ }
+}
diff --git a/src/Population.cpp b/src/Population.cpp
new file mode 100644
index 0000000..f81887e
--- /dev/null
+++ b/src/Population.cpp
@@ -0,0 +1,939 @@
+#include <chrono>
+#include <algorithm>
+#include <HyperNeat/Cppn.hpp>
+#include <HyperNeat/NeuralNet.hpp>
+#include <HyperNeat/Population.hpp>
+#include <HyperNeat/Utils/Thread.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+void
+Population::create(const PopulationPrms& popPrms)
+{
+ if (_prms._seed != 0) {
+ _randGen.seed(_prms._seed);
+ } else {
+ _randGen.seed(getRandSeed());
+ }
+
+ _prms = popPrms;
+ _weightDeviator = BellDist(0.0, _prms._weightDeviation);
+ _weightSelector = RealDist(-_prms._weightRange, _prms._weightRange);
+ _distanceThreshold = _prms._initialDistanceThreshold;
+ _minOldOrganisms = _prms._popSize * _prms._eligibilityRatio;
+ _basicInnovs = _prms._cppnOutputs * NODE_TYPES_COUNT + _prms._cppnInputs;
+
+ _allOrganisms.resize(_prms._popSize, Organism(_prms._cppnInputs, this));
+
+ size_t orgIndex = 0;
+
+ for (auto& i : _allOrganisms) {
+ i._index = orgIndex++;
+ auto& nodeGenes = i._genome._nodeGenes;
+
+ for (size_t j = 0; j < _prms._cppnOutputs; ++j) {
+ size_t nodeType = _nodeTypeSelector(_randGen);
+ size_t geneIdx = _prms._cppnInputs + (j * NODE_TYPES_COUNT) + nodeType;
+ nodeGenes[geneIdx] = {1.0, static_cast<NodeType>(nodeType)};
+
+ for (size_t k = 0; k < _prms._cppnInputs; ++k) {
+ nodeGenes[geneIdx]._linkGenes[k] = {getRandWeight()};
+ }
+ }
+ }
+
+ organizeSpecies();
+}
+
+void
+Population::create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms)
+{
+ create(popPrms);
+ _nnPrms = Pointer<NeuralNetPrms>(new NeuralNetPrms(nnPrms));
+ generateAllNeuralNets();
+}
+
+void
+Population::create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms, const NoveltyMetricPrms& nmPrms)
+{
+ create(popPrms, nnPrms);
+ setNoveltyMetric(nmPrms);
+}
+
+void
+Population::shutdown(bool resetOrganisms, bool archiveOrganisms)
+{
+ while (isAnyOrganismBeingGenerated());
+
+ if (resetOrganisms) {
+ for (auto& i : _allOrganisms) {
+ i.reset(archiveOrganisms);
+ }
+ }
+}
+
+Population::~Population()
+{
+ while (isAnyOrganismBeingGenerated());
+}
+
+void
+Population::setMinimumLifetime(size_t lifetime)
+{
+ _oldOrganisms = 0;
+ _prms._minimumLifetime = lifetime;
+
+ for (auto& i : _allOrganisms) {
+ if (i._lifetime >= lifetime) {
+ ++_oldOrganisms;
+ }
+ }
+}
+
+const PopulationPrms&
+Population::getPopulationPrms() const
+{
+ return _prms;
+}
+
+const NeuralNetPrms&
+Population::getNeuralNetPrms() const
+{
+ return *_nnPrms;
+}
+
+bool
+Population::hasNeuralNets() const
+{
+ return (bool)_nnPrms;
+}
+
+const Vector<Organism>&
+Population::getAllOrganisms() const
+{
+ return _allOrganisms;
+}
+
+const Vector2D<Organism*>&
+Population::getSpecies() const
+{
+ return _species;
+}
+
+Organism&
+Population::getOrganism(size_t i)
+{
+ return _allOrganisms[i];
+}
+
+const Vector<Organism*>&
+Population::getSpecie(size_t i) const
+{
+ return _species[i];
+}
+
+Organism&
+Population::getChampion()
+{
+ auto comFitness = [](Organism& a, Organism& b) {
+ return a._fitness < b._fitness;
+ };
+
+ auto comNovelty = [](Organism& a, Organism& b) {
+ return a.getBehavior().getNoveltyScore() < b.getBehavior().getNoveltyScore();
+ };
+
+ return *max_element(_allOrganisms.begin(), _allOrganisms.end(), isNoveltyMetricSet() ? comNovelty : comFitness);
+}
+
+void
+Population::lock()
+{
+ _populationLock = true;
+}
+
+void
+Population::unlock()
+{
+ _populationLock = false;
+}
+
+bool
+Population::isLocked() const
+{
+ return _populationLock;
+}
+
+void
+Population::lockOrganism(size_t i)
+{
+ _allOrganisms[i].lock();
+}
+
+void
+Population::unlockOrganism(size_t i)
+{
+ _allOrganisms[i].unlock();
+}
+
+bool
+Population::isOrganismLocked(size_t i) const
+{
+ return _allOrganisms[i]._isLocked;
+}
+
+bool
+Population::isAnyOrganismLocked() const
+{
+ return _lockedOrganisms != 0 ? true : false;
+}
+
+size_t
+Population::getLockedOrganisms() const
+{
+ return _lockedOrganisms;
+}
+
+void
+Population::freezeOrganism(size_t i)
+{
+ _allOrganisms[i].freeze();
+}
+
+void
+Population::unfreezeOrganism(size_t i)
+{
+ _allOrganisms[i].unfreeze();
+}
+
+bool
+Population::isOrganismFrozen(size_t i) const
+{
+ return _allOrganisms[i]._isFrozen;
+}
+
+bool
+Population::isAnyOrganismFrozen() const
+{
+ return _frozenOrganisms != 0 ? true : false;
+}
+
+size_t
+Population::getFrozenOrganisms() const
+{
+ return _frozenOrganisms;
+}
+
+bool
+Population::isOrganismBeingGenerated(size_t i) const
+{
+ return _allOrganisms[i].isBeingGenerated();
+}
+
+bool
+Population::isAnyOrganismBeingGenerated() const
+{
+ return _organismsBeingGenerated != 0 ? true : false;
+}
+
+size_t
+Population::getOrganismsBeingGenerated() const
+{
+ return _organismsBeingGenerated;
+}
+
+size_t
+Population::getReadyOrganisms() const
+{
+ size_t result = 0;
+
+ for (auto& i : _allOrganisms) {
+ if (i.isOld() && !i.isLocked()) {
+ ++result;
+ }
+ }
+
+ return result;
+}
+
+const Vector<Innovation>&
+Population::getInnovations() const
+{
+ return _innovations;
+}
+
+size_t
+Population::getInnovationsCount() const
+{
+ return _innovations.size();
+}
+
+size_t
+Population::getBasicInnovationsCount() const
+{
+ return _basicInnovs;
+}
+
+Organism*
+Population::getLastReplacement()
+{
+ return _lastReplacement;
+}
+
+Organism*
+Population::getLastMother()
+{
+ return _lastMother;
+}
+
+Organism*
+Population::getLastFather()
+{
+ return _lastFather;
+}
+
+size_t
+Population::getReplacements() const
+{
+ return _replacements;
+}
+
+bool
+Population::recentReplacement() const
+{
+ return _recentReplacement;
+}
+
+double
+Population::getDistanceThreshold() const
+{
+ return _distanceThreshold;
+}
+
+size_t
+Population::getOldOrganisms() const
+{
+ return _oldOrganisms;
+}
+
+size_t
+Population::getMinimumOldOrganisms() const
+{
+ return _minOldOrganisms;
+}
+
+double
+Population::getAverageFitness() const
+{
+ double total = 0.0;
+
+ for (auto& i : _allOrganisms) {
+ total += i._fitness;
+ }
+
+ return total / static_cast<double>(_allOrganisms.size());
+}
+
+double
+Population::getAverageOldFitness() const
+{
+ double total = 0.0;
+
+ for (auto& i : _allOrganisms) {
+ if (i.isOld()) {
+ total += i._fitness;
+ }
+ }
+
+ return total / static_cast<double>(getOldOrganisms());
+}
+
+void
+Population::setNoveltyMetric(const NoveltyMetricPrms& prms) {
+ _noveltyMetric = Pointer<NoveltyMetric>(new NoveltyMetric);
+ _noveltyMetric->initialize(prms, this);
+}
+
+void
+Population::clearNoveltyMetric()
+{
+ _noveltyMetric.reset();
+
+ for (auto& i : _allOrganisms) {
+ i._behavior = nullptr;
+ }
+}
+
+bool
+Population::isNoveltyMetricSet() const
+{
+ return _noveltyMetric.get();
+}
+
+const NoveltyMetric&
+Population::getNoveltyMetric() const
+{
+ return *_noveltyMetric;
+}
+
+size_t
+Population::getUpdates() const
+{
+ return _updates;
+}
+
+double&
+Population::fitnessOf(size_t i)
+{
+ return _allOrganisms[i]._fitness;
+}
+
+bool
+Population::update(Function<void(void)> beforeReplacement, Function<void(void)> afterReplacement)
+{
+ ++_updates;
+
+ for (auto& i : _allOrganisms) {
+ if (!i._isFrozen && !i.isBeingGenerated()) {
+ ++i._lifetime;
+
+ if (i._lifetime == _prms._minimumLifetime) {
+ ++_oldOrganisms;
+ }
+ }
+ }
+
+ if (_populationLock) {
+ return false;
+ }
+
+ if ((getReadyOrganisms() >= _minOldOrganisms) && !isAnyOrganismBeingGenerated()) {
+ beforeReplacement();
+
+ if (isNoveltyMetricSet()) {
+ _noveltyMetric->setScores();
+ }
+
+ _recentReplacement = true;
+ replaceOrganism();
+ afterReplacement();
+ } else {
+ _recentReplacement = false;
+ }
+
+ return _recentReplacement;
+}
+
+void
+Population::generateAllNeuralNets()
+{
+ auto generateChunk = [&](size_t i, size_t end) {
+ for (; i < end; ++i) {
+ Cppn cppn;
+ cppn.create(_allOrganisms[i].getGenome());
+
+ _allOrganisms[i]._neuralNet = Pointer<NeuralNet>(new NeuralNet);
+ _allOrganisms[i]._neuralNet->create(cppn, *_nnPrms);
+ }
+ };
+
+ size_t threadCount = max(1u, Thread::hardware_concurrency());
+ size_t chunkSize = _allOrganisms.size() / threadCount;
+
+ Vector<Thread> chunks(threadCount);
+
+ for (size_t i = 0; i < threadCount - 1; ++i) {
+ chunks[i] = Thread(generateChunk, i * chunkSize, (i + 1) * chunkSize);
+ }
+
+ chunks.back() = Thread(generateChunk, (chunks.size() - 1) * chunkSize, _allOrganisms.size());
+
+ for (auto& i : chunks) {
+ i.join();
+ }
+}
+
+void
+Population::replaceOrganism()
+{
+ _lastReplacement = killPoorOrganism();
+ _lastMother = nullptr;
+ _lastFather = nullptr;
+ auto parentSpecie = chooseParentSpecie();
+ Vector<Organism*> eligibleMothers;
+
+ for (auto& i : *parentSpecie) {
+ if (i->_lifetime >= _prms._minimumLifetime) {
+ eligibleMothers.emplace_back(i);
+ }
+ }
+
+ size_t motherIdx = getRandSize(0, eligibleMothers.size() - 1);
+ _lastMother = eligibleMothers[motherIdx];
+
+ if (getChance(_prms._sexualReproductionRate)) {
+ if (getChance(_prms._interspeciesMatingRate)) {
+ Vector<Organism*> eligibleFathers;
+
+ for (auto& i : _species) {
+ if (&i == parentSpecie) {
+ continue;
+ }
+
+ for (auto& j : i) {
+ if (j->_lifetime >= _prms._minimumLifetime) {
+ eligibleFathers.emplace_back(j);
+ }
+ }
+ }
+
+ if (eligibleFathers.size() > 0) {
+ size_t fatherIdx = getRandSize(0, eligibleFathers.size() - 1);
+ _lastFather = eligibleFathers[fatherIdx];
+ }
+ } else {
+ if (eligibleMothers.size() > 1) {
+ size_t fatherIdx = getRandSize(0, eligibleMothers.size() - 2);
+
+ if (fatherIdx >= motherIdx) {
+ ++fatherIdx;
+ }
+
+ _lastFather = eligibleMothers[fatherIdx];
+ }
+ }
+
+ if (!_lastFather) {
+ breedAsexually(_lastReplacement->_genome, _lastMother->_genome);
+ } else {
+ if (_lastFather->_fitness > _lastMother->_fitness) {
+ swap(_lastFather, _lastMother);
+ }
+
+ breedSexually(_lastReplacement->_genome, _lastMother->_genome, _lastFather->_genome);
+ }
+ } else {
+ breedAsexually(_lastReplacement->_genome, _lastMother->_genome);
+ }
+
+ assignToSpecie(*_lastReplacement);
+ ++_replacements;
+ --_oldOrganisms;
+
+ if ((_replacements % _prms._replBeforeReorganization) == 0) {
+ organizeSpecies();
+ }
+}
+
+Organism*
+Population::killPoorOrganism()
+{
+ Organism* poorOrganism = nullptr;
+ double minAdjFitness = -1.0;
+
+ for (auto& i : _allOrganisms) {
+ if (i._lifetime >= _prms._minimumLifetime && !i._isLocked) {
+ double orgAdjFitness = i._fitness / static_cast<double>(_species[i._specie].size());
+
+ if (orgAdjFitness < minAdjFitness || minAdjFitness == -1.0) {
+ minAdjFitness = orgAdjFitness;
+ poorOrganism = &i;
+ }
+ }
+ }
+
+ if (poorOrganism->_isFrozen) {
+ poorOrganism->_isFrozen = false;
+ --_frozenOrganisms;
+ }
+
+ poorOrganism->_fitness = 0.0;
+ poorOrganism->_lifetime = 0;
+ poorOrganism->_genome._nodeGenes.clear();
+
+ if (poorOrganism->_behavior) {
+ poorOrganism->_behavior->reset();
+ }
+
+ auto& childSpec = _species[poorOrganism->_specie];
+ auto childIdx = find(childSpec.begin(), childSpec.end(), poorOrganism);
+ childSpec.erase(childIdx);
+
+ return poorOrganism;
+}
+
+Vector<Organism*>*
+Population::chooseParentSpecie()
+{
+ double totalAverageFitnesses = 0.0;
+ Vector<double> averageFitnesses;
+ averageFitnesses.reserve(_species.size());
+
+ for (auto &i : _species) {
+ double specieFitness = 0.0;
+ size_t specieSize = 0;
+
+ for (auto &j : i) {
+ if (j->_lifetime >= _prms._minimumLifetime) {
+ specieFitness += j->_fitness;
+ ++specieSize;
+ }
+ }
+
+ if (specieSize == 0) {
+ averageFitnesses.emplace_back(0.0);
+ } else {
+ specieFitness /= static_cast<double>(specieSize);
+ averageFitnesses.emplace_back(specieFitness);
+ totalAverageFitnesses += specieFitness;
+ }
+ }
+
+ size_t specieIdx = 0;
+ double selector = getRandReal(0.0, totalAverageFitnesses) - averageFitnesses.front();
+
+ while (selector > 0.0) {
+ ++specieIdx;
+ selector -= averageFitnesses[specieIdx];
+ }
+
+ return &_species[specieIdx];
+}
+
+void
+Population::breedAsexually(Genome& child, const Genome& mother)
+{
+ child = mother;
+
+ if (mutateNodesAndLinks(child)) {
+ return;
+ }
+
+ for (auto& i : child._nodeGenes) {
+ for (auto& j : i.second._linkGenes) {
+ if (getChance(_prms._weightMutationRate)) {
+ j.second._weight += getWeightDeviation();
+
+ if (j.second._weight > _prms._weightRange) {
+ j.second._weight = _prms._weightRange;
+ } else if (j.second._weight < -_prms._weightRange) {
+ j.second._weight = -_prms._weightRange;
+ }
+ }
+ }
+ }
+}
+
+void
+Population::breedSexually(Genome& child, const Genome& mother, const Genome& father)
+{
+ child = mother;
+
+ for (auto& i : child._nodeGenes) {
+ if (father._nodeGenes.count(i.first)) {
+ auto& fatherNode = father._nodeGenes.at(i.first);
+
+ for (auto& j : i.second._linkGenes) {
+ if (fatherNode._linkGenes.count(j.first)) {
+ auto& childLink = j.second;
+ auto& fatherLink = fatherNode._linkGenes.at(j.first);
+
+ childLink._weight += fatherLink._weight;
+ childLink._weight /= 2.0;
+
+ if (!childLink._isEnabled || !fatherLink._isEnabled) {
+ if (getChance(_prms._geneDisablingRatio)) {
+ childLink._isEnabled = false;
+ } else {
+ childLink._isEnabled = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+Population::mutateNodesAndLinks(Genome& child)
+{
+ class LinkMutation {
+ public:
+ LinkMutation() = default;
+ LinkMutation(size_t source, size_t target)
+ : _source(source), _target(target)
+ {}
+
+ size_t _source = 0;
+ size_t _target = 0;
+ };
+
+ class NodeMutation {
+ public:
+ NodeMutation() = default;
+ NodeMutation(size_t source, size_t target, double weight)
+ : _source(source), _target(target), _weight(weight)
+ {}
+
+ size_t _source = 0;
+ size_t _target = 0;
+ double _weight = 0.0;
+ };
+
+ if (getChance(_prms._linkMutationRate)) {
+ Vector<LinkMutation> linkMutations;
+
+ for (auto& i : child._nodeGenes) {
+ auto& childNode = i.first;
+ auto& childLinks = i.second._linkGenes;
+ auto& childDepth = i.second._depth;
+
+ for (size_t j = 0; j < child._inputs; ++j) {
+ if (!childLinks.count(j)) {
+ linkMutations.emplace_back(j, childNode);
+ }
+ }
+
+ for (auto& j : child._nodeGenes) {
+ auto& sourceNode = j.first;
+ auto& sourceDepth = j.second._depth;
+
+ if (!childLinks.count(sourceNode) && childDepth > sourceDepth) {
+ linkMutations.emplace_back(sourceNode, childNode);
+ }
+ }
+ }
+
+ if (!linkMutations.empty()) {
+ size_t mutationIdx = getRandSize(0, linkMutations.size() - 1);
+ size_t target = linkMutations[mutationIdx]._target;
+ size_t source = linkMutations[mutationIdx]._source;
+
+ child._nodeGenes[target]._linkGenes[source] = {0.0};
+ }
+
+ return true;
+ }
+
+ if (getChance(_prms._nodeMutationRate)) {
+ Vector<NodeMutation> nodeMutations;
+
+ for (auto& i : child._nodeGenes) {
+ for (auto& j : i.second._linkGenes) {
+ auto& childLink = j.second;
+
+ if (childLink._isEnabled) {
+ nodeMutations.emplace_back(j.first, i.first, childLink._weight);
+ }
+ }
+ }
+
+ size_t mutationIdx = getRandSize(0, nodeMutations.size() - 1);
+ size_t target = nodeMutations[mutationIdx]._target;
+ size_t source = nodeMutations[mutationIdx]._source;
+ double targetDepth = child._nodeGenes[target]._depth;
+ double sourceDepth = 0.0;
+
+ if (source >= child._inputs) {
+ sourceDepth = child._nodeGenes[source]._depth;
+ }
+
+ double depth = (targetDepth + sourceDepth) / 2.0;
+ NodeType function = getRandNodeType();
+
+ Innovation innov = {0, source, target, depth, function};
+ auto iter = find(_innovations.begin(), _innovations.end(), innov);
+ size_t newID = 0;
+
+ if (iter != _innovations.end()) {
+ newID = iter->_number;
+ } else {
+ newID = _innovations.size() + _basicInnovs;
+ _innovations.emplace_back(newID, source, target, depth, function);
+ }
+
+ child._nodeGenes[newID] = {depth, function};
+ child._nodeGenes[newID]._linkGenes[source] = {0.0};
+ child._nodeGenes[target]._linkGenes[newID] = {0.0};
+ child._nodeGenes[target]._linkGenes[source]._isEnabled = false;
+
+ return true;
+ }
+
+ return false;
+}
+
+void
+Population::assignToSpecie(Organism& org)
+{
+ bool included = false;
+
+ for (auto i = _species.begin(), end = _species.end(); i != end; ++i) {
+ if (i->empty()) {
+ continue;
+ }
+
+ double genDistance = computeDistance((*i)[0]->_genome, org._genome);
+
+ if (genDistance < _distanceThreshold) {
+ included = true;
+ org._specie = distance(_species.begin(), i);
+ i->emplace_back(&org);
+ break;
+ }
+ }
+
+ if (!included) {
+ org._specie = _species.size();
+ _species.emplace_back(1, &org);
+ }
+}
+
+void
+Population::organizeSpecies()
+{
+ _species.clear();
+
+ for (auto& i : _allOrganisms) {
+ assignToSpecie(i);
+ }
+
+ if (_species.size() < _prms._targetSpeciesCount && _distanceThreshold > _prms._distanceThresholdShift) {
+ _distanceThreshold -= _prms._distanceThresholdShift;
+ } else if (_species.size() > _prms._targetSpeciesCount) {
+ _distanceThreshold += _prms._distanceThresholdShift;
+ }
+}
+
+
+double
+Population::computeDistance(const Genome& g1, const Genome& g2) const
+{
+ class LinkPair {
+ public:
+ const Genome::NodeGene::LinkGene* _l1 = nullptr;
+ const Genome::NodeGene::LinkGene* _l2 = nullptr;
+ };
+
+ using LinkPairs = Map<size_t, LinkPair>;
+
+ class GenePair {
+ public:
+ const Genome::NodeGene* _g1 = nullptr;
+ const Genome::NodeGene* _g2 = nullptr;
+ LinkPairs _links;
+ };
+
+ using GenePairs = Map<size_t, GenePair>;
+
+ auto alignGenes = [](GenePairs& gPairs, const Genome& g1, const Genome& g2) {
+ for (auto& i : g1._nodeGenes) {
+ gPairs[i.first]._g1 = &i.second;
+
+ for (auto& j : i.second._linkGenes) {
+ gPairs[i.first]._links[j.first]._l1 = &j.second;
+ }
+ }
+
+ for (auto& i : g2._nodeGenes) {
+ gPairs[i.first]._g2 = &i.second;
+
+ for (auto& j : i.second._linkGenes) {
+ gPairs[i.first]._links[j.first]._l2 = &j.second;
+ }
+ }
+ };
+
+ GenePairs gPairs;
+ alignGenes(gPairs, g1, g2);
+
+ double g1Size = 0.0;
+ double g2Size = 0.0;
+ double disjointGenes = 0.0;
+ double linkGenePairs = 0.0;
+ double weightDifference = 0.0;
+
+ for (auto& i : gPairs) {
+ if (i.second._g1 && i.second._g2) {
+ ++g1Size;
+ ++g2Size;
+
+ for (auto& j : i.second._links) {
+ if (j.second._l1 && j.second._l2) {
+ ++g1Size;
+ ++g2Size;
+
+ ++linkGenePairs;
+ weightDifference += fabs(j.second._l1->_weight - j.second._l2->_weight);
+ } else if (j.second._l1) {
+ ++g1Size;
+ ++disjointGenes;
+ } else {
+ ++g2Size;
+ ++disjointGenes;
+ }
+ }
+ } else if (i.second._g1) {
+ double geneSize = static_cast<double>(1 + i.second._links.size());
+ g1Size += geneSize;
+ disjointGenes += geneSize;
+ } else {
+ double geneSize = static_cast<double>(1 + i.second._links.size());
+ g2Size += geneSize;
+ disjointGenes += geneSize;
+ }
+ }
+
+ double normalize = g1Size > g2Size ? g1Size : g2Size;
+ double disjointFactor = (_prms._c1Disjoint * disjointGenes) / normalize;
+ double weightFactor = 0.0;
+
+ if (linkGenePairs != 0.0) {
+ weightFactor = (_prms._c3WeightDifference * weightDifference) / linkGenePairs;
+ }
+
+ return disjointFactor + weightFactor;
+}
+
+size_t
+Population::getRandSeed() const
+{
+ return chrono::system_clock::now().time_since_epoch().count();
+}
+
+size_t
+Population::getRandSize(size_t low, size_t hi)
+{
+ return IntDist(low, hi)(_randGen);
+}
+
+double
+Population::getRandReal(double low, double hi)
+{
+ return RealDist(low, hi)(_randGen);
+}
+
+double
+Population::getRandWeight()
+{
+ return _weightSelector(_randGen);
+}
+
+double
+Population::getWeightDeviation()
+{
+ return _weightDeviator(_randGen);
+}
+
+NodeType
+Population::getRandNodeType()
+{
+ return static_cast<NodeType>(_nodeTypeSelector(_randGen));
+}
+
+bool
+Population::getChance(double ratio)
+{
+ return _chanceSelector(_randGen) < ratio;
+}
diff --git a/src/QuadTree.cpp b/src/QuadTree.cpp
new file mode 100644
index 0000000..d6686ff
--- /dev/null
+++ b/src/QuadTree.cpp
@@ -0,0 +1,55 @@
+#include <HyperNeat/QuadTree.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+QuadTree::QuadTree(double segment, double x, double y)
+ : _segment(segment), _x(x), _y(y)
+{}
+
+double
+QuadTree::getSegment() const
+{
+ return _segment;
+}
+
+double
+QuadTree::getX() const
+{
+ return _x;
+}
+
+double
+QuadTree::getY() const
+{
+ return _y;
+}
+
+void
+QuadTree::subdivide(Function<bool(QuadTree*)> subdivider)
+{
+ if (subdivider(this)) {
+ double newSeg = _segment / 2.0;
+ _children.resize(4);
+ _children[0] = {newSeg, _x - newSeg, _y - newSeg};
+ _children[1] = {newSeg, _x + newSeg, _y - newSeg};
+ _children[2] = {newSeg, _x - newSeg, _y + newSeg};
+ _children[3] = {newSeg, _x + newSeg, _y + newSeg};
+
+ for (auto &i : _children) {
+ i.subdivide(subdivider);
+ }
+ }
+}
+
+void
+QuadTree::traverse(Function<void(const QuadTree*)> traverser) const
+{
+ if (!_children.empty()) {
+ for (auto &i : _children) {
+ i.traverse(traverser);
+ }
+ } else {
+ traverser(this);
+ }
+}
diff --git a/src/Utils/LoadFile.cpp b/src/Utils/LoadFile.cpp
new file mode 100644
index 0000000..3849f76
--- /dev/null
+++ b/src/Utils/LoadFile.cpp
@@ -0,0 +1,280 @@
+#include <HyperNeat/Population.hpp>
+#include <HyperNeat/NoveltyMetric.hpp>
+#include <HyperNeat/NeuralNetPrms.hpp>
+#include <HyperNeat/Utils/LoadFile.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+LoadFile::LoadFile(Istream& stream)
+ : _stream(stream)
+{
+ _stream.setf(ios::boolalpha);
+}
+
+void
+LoadFile::loadPopulation(Population& population)
+{
+ size_t speciesCnt = 0;
+ size_t innovationsCount = 0;
+ ssize_t lastReplacement = 0;
+ ssize_t lastMother = 0;
+ ssize_t lastFather = 0;
+ bool hasNoveltyMetric = false;
+ bool hasNeuralNets = false;
+ auto& prms = population._prms;
+
+ nextPrm() >> population._populationLock;
+ nextPrm() >> population._lockedOrganisms;
+ nextPrm() >> population._frozenOrganisms;
+ nextPrm() >> innovationsCount;
+ nextPrm() >> population._basicInnovs;
+ nextPrm() >> lastReplacement;
+ nextPrm() >> lastMother;
+ nextPrm() >> lastFather;
+ nextPrm() >> population._replacements;
+ nextPrm() >> population._distanceThreshold;
+ nextPrm() >> population._oldOrganisms;
+ nextPrm() >> population._minOldOrganisms;
+ nextPrm() >> hasNoveltyMetric;
+ nextPrm() >> population._updates;
+ nextPrm() >> speciesCnt;
+ nextPrm() >> hasNeuralNets;
+
+ loadPopulationPrms(prms);
+
+ if (hasNeuralNets) {
+ population._nnPrms = Pointer<NeuralNetPrms>(new NeuralNetPrms);
+ loadNeuralNetPrms(*population._nnPrms);
+ }
+
+ population._innovations.resize(innovationsCount);
+
+ for (auto& i : population._innovations) {
+ String nodeStr;
+
+ nextPrm() >> i._number;
+ nextPrm() >> i._source;
+ nextPrm() >> i._target;
+ nextPrm() >> i._depth;
+ nextPrm() >> nodeStr;
+
+ i._nodeType = stringToNode(nodeStr);
+ }
+
+ population._allOrganisms.resize(prms._popSize, Organism(&population));
+ population._species.resize(speciesCnt);
+
+ for (auto& i : population._allOrganisms) {
+ loadOrganism(i);
+ }
+
+ population._lastReplacement = (lastReplacement == -1 ? nullptr: &population._allOrganisms[lastReplacement]);
+ population._lastMother = (lastMother == -1 ? nullptr: &population._allOrganisms[lastMother]);
+ population._lastFather = (lastFather == -1 ? nullptr: &population._allOrganisms[lastFather]);
+
+ for (auto& i : population._species) {
+ size_t specieSize = 0;
+ nextPrm() >> specieSize;
+
+ while (specieSize--) {
+ size_t organismIdx = 0;
+ nextArrayValue() >> organismIdx;
+
+ i.emplace_back(&population._allOrganisms[organismIdx]);
+ }
+ }
+
+ if (hasNoveltyMetric) {
+ NoveltyMetricPrms nmPrms;
+ loadNoveltyMetricPrms(nmPrms);
+
+ population.setNoveltyMetric(nmPrms);
+ loadNoveltyMetric(*population._noveltyMetric);
+ }
+
+ if (hasNeuralNets) {
+ population.generateAllNeuralNets();
+ }
+
+ if (prms._seed != 0) {
+ population._randGen.seed(prms._seed);
+ } else {
+ population._randGen.seed(population.getRandSeed());
+ }
+
+ population._weightDeviator = BellDist(0.0, prms._weightDeviation);
+ population._weightSelector = RealDist(-prms._weightRange, prms._weightRange);
+
+ population._organismsBeingGenerated = 0;
+}
+
+void
+LoadFile::loadPopulationPrms(PopulationPrms& prms)
+{
+ nextPrm() >> prms._popSize;
+ nextPrm() >> prms._cppnInputs;
+ nextPrm() >> prms._cppnOutputs;
+ nextPrm() >> prms._seed;
+ nextPrm() >> prms._weightRange;
+ nextPrm() >> prms._c1Disjoint;
+ nextPrm() >> prms._c3WeightDifference;
+ nextPrm() >> prms._initialDistanceThreshold;
+ nextPrm() >> prms._distanceThresholdShift;
+ nextPrm() >> prms._sexualReproductionRate;
+ nextPrm() >> prms._weightMutationRate;
+ nextPrm() >> prms._weightDeviation;
+ nextPrm() >> prms._interspeciesMatingRate;
+ nextPrm() >> prms._geneDisablingRatio;
+ nextPrm() >> prms._linkMutationRate;
+ nextPrm() >> prms._nodeMutationRate;
+ nextPrm() >> prms._targetSpeciesCount;
+ nextPrm() >> prms._eligibilityRatio;
+ nextPrm() >> prms._minimumLifetime;
+ nextPrm() >> prms._replBeforeReorganization;
+}
+
+void
+LoadFile::loadNeuralNetPrms(NeuralNetPrms& prms)
+{
+ size_t inputs = 0;
+ size_t outputs = 0;
+
+ nextPrm() >> prms._testGridLevel;
+ nextPrm() >> prms._maxQuadTreeLevel;
+ nextPrm() >> prms._minQuadTreeLevel;
+ nextPrm() >> prms._bandPruningThreshold;
+ nextPrm() >> prms._varianceThreshold;
+ nextPrm() >> prms._divisionThreshold;
+ nextPrm() >> prms._iterations;
+ nextPrm() >> inputs;
+ nextPrm() >> outputs;
+
+ prms._inputMap.resize(inputs);
+ prms._outputMap.resize(outputs);
+
+ for (auto& i : prms._inputMap) {
+ nextArrayValue() >> i._x;
+ nextArrayValue() >> i._y;
+ }
+
+ for (auto& i : prms._outputMap) {
+ nextArrayValue() >> i._x;
+ nextArrayValue() >> i._y;
+ }
+}
+
+void
+LoadFile::loadNoveltyMetric(NoveltyMetric& noveltyMetric)
+{
+ for (auto& i : noveltyMetric._behaviors) {
+ nextPrm() >> i._criteriaReached;
+ nextPrm() >> i._noveltyScore;
+ nextPrm() >> i._toBeArchived;
+
+ for (auto& j : i._characterization) {
+ nextArrayValue() >> j;
+ }
+ }
+
+ size_t archiveSize = 0;
+ nextPrm() >> archiveSize;
+ noveltyMetric._archive.resize(archiveSize);
+
+ for (auto& i : noveltyMetric._archive) {
+ i.resize(noveltyMetric._prms._characterizationSize, 0.0);
+
+ for (auto& j : i) {
+ nextArrayValue() >> j;
+ }
+ }
+}
+
+void
+LoadFile::loadNoveltyMetricPrms(NoveltyMetricPrms& noveltyMetricPrms)
+{
+ nextPrm() >> noveltyMetricPrms._noveltyThreshold;
+ nextPrm() >> noveltyMetricPrms._referenceOrganisms;
+ nextPrm() >> noveltyMetricPrms._characterizationSize;
+ nextPrm() >> noveltyMetricPrms._criteriaReachedByDefault;
+}
+
+void
+LoadFile::loadOrganism(Organism& organism)
+{
+ nextPrm() >> organism._index;
+ nextPrm() >> organism._fitness;
+ nextPrm() >> organism._isLocked;
+ nextPrm() >> organism._isFrozen;
+ nextPrm() >> organism._specie;
+ nextPrm() >> organism._lifetime;
+
+ loadGenome(organism._genome);
+}
+
+void
+LoadFile::loadGenome(Genome& genome)
+{
+ size_t nodes = 0;
+
+ nextPrm() >> genome._inputs;
+ nextPrm() >> nodes;
+
+ while (nodes--) {
+ String nodeType;
+ size_t links = 0;
+ size_t innov = 0;
+
+ nextPrm() >> innov;
+ auto& nodeGene = genome._nodeGenes[innov];
+
+ nextPrm() >> nodeGene._depth;
+ nextPrm() >> nodeType;
+ nodeGene._nodeType = stringToNode(nodeType);
+
+ nextPrm() >> links;
+
+ while (links--) {
+ size_t source = 0;
+
+ nextPrm() >> source;
+ auto& linkGene = nodeGene._linkGenes[source];
+
+ nextPrm() >> linkGene._weight;
+ nextPrm() >> linkGene._isEnabled;
+ }
+ }
+}
+
+Istream&
+LoadFile::nextPrm(bool arrayVal)
+{
+ for (;;) {
+ char ch = static_cast<char>(_stream.peek());
+
+ if (ch == '#') {
+ _stream.ignore(numeric_limits<streamsize>::max(), '\n');
+ } else {
+ if (!arrayVal) {
+ _stream.ignore();
+
+ if (ch == '=') {
+ return _stream;
+ }
+ } else {
+ if (string("-0123456789").find(ch) != string::npos) {
+ return _stream;
+ }
+
+ _stream.ignore();
+ }
+ }
+ }
+}
+
+
+Istream&
+LoadFile::nextArrayValue()
+{
+ return nextPrm(true);
+}
diff --git a/src/Utils/NodeTypes.cpp b/src/Utils/NodeTypes.cpp
new file mode 100644
index 0000000..b11b079
--- /dev/null
+++ b/src/Utils/NodeTypes.cpp
@@ -0,0 +1,41 @@
+#include <HyperNeat/Utils/NodeTypes.hpp>
+
+namespace hyperneat
+{
+ String
+ nodeToString(NodeType type)
+ {
+ switch (type) {
+ case NodeType::SIGMOID:
+ return "\"sigmoid\"";
+
+ case NodeType::GAUSSIAN:
+ return "\"gaussian\"";
+
+ case NodeType::SINE:
+ return "\"sine\"";
+
+ case NodeType::ABSOLUTE:
+ return "\"absolute\"";
+
+ default:
+ return "\"nullType\"";
+ }
+ }
+
+ NodeType
+ stringToNode(const String& str)
+ {
+ if (str == "\"sigmoid\"") {
+ return NodeType::SIGMOID;
+ } else if (str == "\"gaussian\"") {
+ return NodeType::GAUSSIAN;
+ } else if (str == "\"sine\"") {
+ return NodeType::SINE;
+ } else if (str == "\"absolute\"") {
+ return NodeType::ABSOLUTE;
+ } else {
+ return NodeType::NULL_TYPE;
+ }
+ }
+}
diff --git a/src/Utils/Point.cpp b/src/Utils/Point.cpp
new file mode 100644
index 0000000..7dd9610
--- /dev/null
+++ b/src/Utils/Point.cpp
@@ -0,0 +1,33 @@
+#include <cmath>
+#include <HyperNeat/Utils/Point.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+Point::Point(double x, double y)
+ : _x(x), _y(y)
+{}
+
+double
+Point::distance(const Point& other) const
+{
+ double x = _x - other._x;
+ double y = _y - other._y;
+
+ return sqrt(x * x + y * y);
+}
+
+bool
+Point::operator==(const Point& other) const{
+ return (_x == other._x) && (_y == other._y);
+}
+
+bool
+Point::operator<(const Point& other) const
+{
+ if (_x == other._x) {
+ return _y < other._y;
+ } else {
+ return _x < other._x;
+ }
+}
diff --git a/src/Utils/SaveFile.cpp b/src/Utils/SaveFile.cpp
new file mode 100644
index 0000000..8c471f6
--- /dev/null
+++ b/src/Utils/SaveFile.cpp
@@ -0,0 +1,249 @@
+#include <HyperNeat/Population.hpp>
+#include <HyperNeat/NoveltyMetric.hpp>
+#include <HyperNeat/NeuralNetPrms.hpp>
+#include <HyperNeat/Utils/SaveFile.hpp>
+
+using namespace std;
+using namespace hyperneat;
+
+SaveFile::SaveFile(Ostream& stream)
+ : _stream(stream)
+{
+ _stream.setf(ios::boolalpha);
+ _stream.precision(numeric_limits<double>::digits10);
+}
+
+void
+SaveFile::savePopulation(Population& population, bool shuttedDown, size_t tabs, const String& prefix)
+{
+ print(tabs) << "# hyperneat::Population data:" << newl();
+ print(tabs) << "# -------------------------------------------------------------------------------------" << newl();
+ print(tabs) << "# DO NOT erase or change the order of any entry! Data is read back ENTRY by ENTRY." << newl(2);
+
+ ssize_t lastReplacement = (population.getLastReplacement() ? population.getLastReplacement()->getIndex() : -1);
+ ssize_t lastMother = (population.getLastMother() ? population.getLastMother()->getIndex() : -1);
+ ssize_t lastFather = (population.getLastFather() ? population.getLastFather()->getIndex() : -1);
+
+ print(tabs) << "[" << prefix << "population]" << newl();
+ print(tabs + 1) << "populationLock = " << (shuttedDown ? false : population.isLocked()) << newl();
+ print(tabs + 1) << "lockedOrganisms = " << (shuttedDown ? 0 : population.getLockedOrganisms()) << newl();
+ print(tabs + 1) << "frozenOrganisms = " << (shuttedDown ? 0 : population.getFrozenOrganisms()) << newl();
+ print(tabs + 1) << "innovationsCount = " << population.getInnovationsCount() << newl();
+ print(tabs + 1) << "basicInnovations = " << population.getBasicInnovationsCount() << newl();
+ print(tabs + 1) << "lastReplacement = " << lastReplacement << newl();
+ print(tabs + 1) << "lastMother = " << lastMother << newl();
+ print(tabs + 1) << "lastFather = " << lastFather << newl();
+ print(tabs + 1) << "replacements = " << population.getReplacements() << newl();
+ print(tabs + 1) << "distanceThreshold = " << population.getDistanceThreshold() << newl();
+ print(tabs + 1) << "oldOrganisms = " << (shuttedDown ? 0 : population.getOldOrganisms()) << newl();
+ print(tabs + 1) << "minOldOrganisms = " << population.getMinimumOldOrganisms() << newl();
+ print(tabs + 1) << "noveltyMetric = " << population.isNoveltyMetricSet() << newl();
+ print(tabs + 1) << "updates = " << population.getUpdates() << newl();
+ print(tabs + 1) << "species = " << population.getSpecies().size() << newl();
+ print(tabs + 1) << "withNeuralNets = " << population.hasNeuralNets() << newl(2);
+
+ savePopulationPrms(population.getPopulationPrms(), tabs + 1, prefix + "population.");
+
+ if (population.hasNeuralNets()) {
+ print() << newl();
+ saveNeuralNetPrms(population.getNeuralNetPrms(), tabs + 1, prefix + "population.");
+ }
+
+ for (auto& i : population.getInnovations()) {
+ print() << newl();
+ print(tabs + 1) << "[[" + prefix + "population.innovation]]" << newl();
+ print(tabs + 2) << "number = " << i._number << newl();
+ print(tabs + 2) << "source = " << i._source << newl();
+ print(tabs + 2) << "target = " << i._target << newl();
+ print(tabs + 2) << "depth = " << i._depth << newl();
+ print(tabs + 2) << "function = " << nodeToString(i._nodeType) << newl();
+ }
+
+ for (auto& i : population.getAllOrganisms()) {
+ print() << newl();
+ saveOrganism(i, shuttedDown, tabs + 1, prefix + "population.");
+ }
+
+ for (auto& i : population.getSpecies()) {
+ print() << newl();
+ print(tabs + 1) << "[[" + prefix + "population.specie]]" << newl();
+ print(tabs + 2) << "size = " << i.size() << newl();
+ print(tabs + 2) << "members = [" << newl();
+
+ for (auto& j : i) {
+ print(tabs + 3) << j->getIndex() << "," << newl();
+ }
+
+ print(tabs + 2) << "]" << newl();
+ }
+
+ if (population.isNoveltyMetricSet()) {
+ print() << newl();
+ saveNoveltyMetric(population.getNoveltyMetric(), shuttedDown, tabs + 1, prefix + "population.");
+ }
+}
+
+void
+SaveFile::savePopulationPrms(const PopulationPrms& prms, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[" << prefix << "parameters]" << newl();
+ print(tabs + 1) << "popSize = " << prms._popSize << newl();
+ print(tabs + 1) << "cppnInputs = " << prms._cppnInputs << newl();
+ print(tabs + 1) << "cppnOutputs = " << prms._cppnOutputs << newl();
+ print(tabs + 1) << "seed = " << prms._seed << newl();
+ print(tabs + 1) << "weightRange = " << prms._weightRange << newl();
+ print(tabs + 1) << "disjointCoeff = " << prms._c1Disjoint << newl();
+ print(tabs + 1) << "weightDifferenceCoeff = " << prms._c3WeightDifference << newl();
+ print(tabs + 1) << "initialDistanceThreshold = " << prms._initialDistanceThreshold << newl();
+ print(tabs + 1) << "distanceThresholdShift = " << prms._distanceThresholdShift << newl();
+ print(tabs + 1) << "sexualReproductionRate = " << prms._sexualReproductionRate << newl();
+ print(tabs + 1) << "weightMutationRate = " << prms._weightMutationRate << newl();
+ print(tabs + 1) << "weightDeviation = " << prms._weightDeviation << newl();
+ print(tabs + 1) << "interspeciesMatingRate = " << prms._interspeciesMatingRate << newl();
+ print(tabs + 1) << "geneDisablingRatio = " << prms._geneDisablingRatio << newl();
+ print(tabs + 1) << "linkMutationRate = " << prms._linkMutationRate << newl();
+ print(tabs + 1) << "nodeMutationRate = " << prms._nodeMutationRate << newl();
+ print(tabs + 1) << "targetSpeciesCount = " << prms._targetSpeciesCount << newl();
+ print(tabs + 1) << "eligibilityRatio = " << prms._eligibilityRatio << newl();
+ print(tabs + 1) << "minimumLifetime = " << prms._minimumLifetime << newl();
+ print(tabs + 1) << "replBeforeReorganization = " << prms._replBeforeReorganization << newl();
+}
+
+void
+SaveFile::saveNeuralNetPrms(const NeuralNetPrms& prms, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[" << prefix << "neuralNetParameters]" << newl();
+ print(tabs + 1) << "testGridLevel = " << prms._testGridLevel << newl();
+ print(tabs + 1) << "maxQuadTreeLevel = " << prms._maxQuadTreeLevel << newl();
+ print(tabs + 1) << "minQuadTreeLevel = " << prms._minQuadTreeLevel << newl();
+ print(tabs + 1) << "bandPruningThreshold = " << prms._bandPruningThreshold << newl();
+ print(tabs + 1) << "varianceThreshold = " << prms._varianceThreshold << newl();
+ print(tabs + 1) << "divisionThreshold = " << prms._divisionThreshold << newl();
+ print(tabs + 1) << "iterations = " << prms._iterations << newl();
+ print(tabs + 1) << "inputs = " << prms._inputMap.size() << newl();
+ print(tabs + 1) << "outputs = " << prms._outputMap.size() << newl(2);
+ print(tabs + 1) << "inputMap = [" << newl();
+
+ for (auto& i : prms._inputMap) {
+ print(tabs + 2) << "[" << i._x << ", " << i._y << "]," << newl();
+ }
+
+ print(tabs + 1) << "]" << newl(2);
+ print(tabs + 1) << "outputMap = [" << newl();
+
+ for (auto& i : prms._outputMap) {
+ print(tabs + 2) << "[" << i._x << ", " << i._y << "]," << newl();
+ }
+
+ print(tabs + 1) << "]" << newl();
+}
+
+void
+SaveFile::saveOrganism(const Organism& organism, bool shuttedDown, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[[" << prefix << "organism]]" << newl();
+
+ if (organism.isChampion()) {
+ print(tabs + 1) << "# Current champion." << newl(2);
+ }
+
+ print(tabs + 1) << "index = " << organism.getIndex() << newl();
+ print(tabs + 1) << "fitness = " << (shuttedDown ? 0 : organism._fitness) << newl();
+ print(tabs + 1) << "isLocked = " << (shuttedDown ? false : organism.isLocked()) << newl();
+ print(tabs + 1) << "isFrozen = " << (shuttedDown ? false : organism.isFrozen()) << newl();
+ print(tabs + 1) << "specie = " << organism.getSpecie() << newl();
+ print(tabs + 1) << "lifetime = " << (shuttedDown ? 0 : organism.getLifetime()) << newl(2);
+
+ saveGenome(organism.getGenome(), tabs + 1, prefix + "organism.");
+
+ // If shutted down, save Neural Net
+}
+
+void
+SaveFile::saveGenome(const Genome& genome, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[" << prefix << "genome]" << newl();
+ print(tabs + 1) << "inputs = " << genome._inputs << newl();
+ print(tabs + 1) << "nodes = " << genome._nodeGenes.size() << newl();
+
+ for (auto& i : genome._nodeGenes) {
+ print() << newl();
+ print(tabs + 1) << "[[" << prefix << "genome.nodeGene]]" << newl();
+ print(tabs + 2) << "innovation = " << i.first << newl();
+ print(tabs + 2) << "depth = " << i.second._depth << newl();
+ print(tabs + 2) << "function = " << nodeToString(i.second._nodeType) << newl();
+ print(tabs + 2) << "links = " << i.second._linkGenes.size() << newl();
+
+ for (auto& j : i.second._linkGenes) {
+ print() << newl();
+ print(tabs + 2) << "[[" << prefix << "genome.nodeGene.linkGene]]" << newl();
+ print(tabs + 3) << "source = " << j.first << newl();
+ print(tabs + 3) << "weight = " << j.second._weight << newl();
+ print(tabs + 3) << "isEnabled = " << j.second._isEnabled << newl();
+ }
+ }
+}
+
+void
+SaveFile::saveNoveltyMetric(const NoveltyMetric& noveltyMetric, bool shuttedDown, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[" << prefix << "noveltyMetric]" << newl();
+ saveNoveltyMetricPrms(noveltyMetric.getPrms(), tabs + 1, prefix + "noveltyMetric.");
+
+ bool critDef = noveltyMetric.getPrms()._criteriaReachedByDefault;
+
+ for (auto& i : noveltyMetric.getBehaviors()) {
+ print() << newl();
+ print(tabs + 1) << "[[" << prefix << "noveltyMetric.behavior]]" << newl();
+ print(tabs + 2) << "criteriaReached = " << (shuttedDown ? critDef : i._criteriaReached) << newl();
+ print(tabs + 2) << "noveltyScore = " << (shuttedDown ? 0 : i.getNoveltyScore()) << newl();
+ print(tabs + 2) << "toBeArchived = " << (shuttedDown ? false : i.isToBeArchived()) << newl();
+ print(tabs + 2) << "characterization = [" << newl();
+
+ for (auto& j : i.getCharacterization()) {
+ print(tabs + 3) << j << "," << newl();
+ }
+
+ print(tabs + 2) << "]" << newl();
+ }
+
+ print() << newl();
+ print(tabs + 1) << "[" << prefix << "noveltyMetric.archive]" << newl();
+ print(tabs + 2) << "size = " << noveltyMetric.getArchive().size() << newl();
+ print(tabs + 2) << "characterizations = [" << newl();
+
+ for (auto& i : noveltyMetric.getArchive()) {
+ print(tabs + 3) << "[" << newl();
+
+ for (auto& j : i) {
+ print(tabs + 4) << j << "," << newl();
+ }
+
+ print(tabs + 3) << "]," << newl();
+ }
+
+ print(tabs + 2) << "]" << newl();
+}
+
+void
+SaveFile::saveNoveltyMetricPrms(const NoveltyMetricPrms& noveltyMetricPrms, size_t tabs, const String& prefix)
+{
+ print(tabs) << "[" << prefix << "parameters]" << newl();
+ print(tabs + 1) << "noveltyThreshold = " << noveltyMetricPrms._noveltyThreshold << newl();
+ print(tabs + 1) << "referenceOrganisms = " << noveltyMetricPrms._referenceOrganisms << newl();
+ print(tabs + 1) << "characterizationSize = " << noveltyMetricPrms._characterizationSize << newl();
+ print(tabs + 1) << "criteriaReachedByDefault = " << noveltyMetricPrms._criteriaReachedByDefault << newl();
+}
+
+Ostream&
+SaveFile::print(size_t tabs)
+{
+ _stream << String(tabs * 4, ' ');
+ return _stream;
+}
+
+String
+SaveFile::newl(size_t lines)
+{
+ return String(lines, '\n');
+}
diff --git a/src/Utils/ValuePoint.cpp b/src/Utils/ValuePoint.cpp
new file mode 100644
index 0000000..d9cdc64
--- /dev/null
+++ b/src/Utils/ValuePoint.cpp
@@ -0,0 +1,7 @@
+#include <HyperNeat/Utils/ValuePoint.hpp>
+
+using namespace hyperneat;
+
+ValuePoint::ValuePoint(double x, double y, double value, double segment)
+ : Point(x, y), _value(value), _segment(segment)
+{}
diff --git a/todolist.txt b/todolist.txt
new file mode 100644
index 0000000..2071772
--- /dev/null
+++ b/todolist.txt
@@ -0,0 +1,44 @@
+FOR VERSION 0.1 Beta:
+ ✔ Test [minimal criteria = above average fitness] on NeuroRacers @done (14-04-05 03:47)
+ ✔ Serialize loaded and saved files in TOML @done (14-04-05 03:48)
+ ✔ Cppn functions should be Sine, Gaussian, Sigmoid and Absolute @done (14-04-05 18:44)
+ ✔ Add Population::setMinimumLifetime() @done (14-04-05 19:18)
+ ✔ Add NeuralNet::getAverageActivation() @done (14-04-05 19:53)
+ ✔ Place NeuralNet inside Organism class @done (14-04-11 03:08)
+ ✔ Load/Save system links to a iostream object instead of fstream @done (14-05-09 19:14)
+ ☐ Test cereal library (branch)
+ ☐ Load/Save system for NNets (Add Save Sim to Guppies)
+ ☐ Plugins:
+ ☐ CPPN explorer
+ ☐ NeuralNet Monitor
+ ☐ Population Monitor
+ ☐ Create HyperGuppies
+ ☐ Code Doxygen documentation
+ ☐ Make tutorial
+ ☐ Release hyperneat:: 0.1 Beta
+
+FOR VERSION 1.0:
+ ☐ Test recursive CPPNs
+ ☐ addOrganism() / removeOrganism() / Change some parameters (Add Feature to Guppies)
+ ☐ Create functional copy & move operators (for CPPNs, NNets and Populations)
+ ☐ Create simple exception handling (for all public methods)
+ ☐ Create Brain class (apply on Guppies)
+ ☐ Allow non-realtime updating (NEAT instead of rtNEAT)
+ ☐ Test Population::update() as separate thread
+ ☐ Update documentation and tutorial
+
+
+___________________
+Archive:
+ ✔ Find nice way to organize #includes @done (13-09-05 15:03) @project(FOR VERSION 0.1 Beta)
+ ✔ DEBUG!!! - Done ??? @done (13-10-06 23:53) @project(FOR VERSION 0.1 Beta)
+ ✔ Fix NeuralNet::create() @done (13-10-09 17:38) @project(FOR VERSION 0.1 Beta)
+ ✔ Make everything HyperThreaded again @done (13-10-11 04:41) @project(FOR VERSION 0.1 Beta)
+ ✔ Eliminate Population::getAllNeuralNets() @done (13-10-10 23:02) @project(FOR VERSION 0.1 Beta)
+ ✔ Recent update flag on Population @done (13-10-11 04:00) @project(FOR VERSION 0.1 Beta)
+ ✔ Make Neuron::Type @done (13-10-11 05:22) @project(FOR VERSION 0.1 Beta)
+ ✔ Test Genome::NodeGene matching system (Save & Load) @done (13-10-28 01:37) @project(FOR VERSION 0.1 Beta)
+ ✔ Include distance on Node Search @done (13-11-06 04:22) @project(FOR VERSION 0.1 Beta)
+ ✔ Revise Integer data types @done (13-11-09 23:52) @project(FOR VERSION 0.1 Beta)
+ ✔ Include a pointSetter() function as parameter to Population::update() function @done (13-11-10 00:20) @project(FOR VERSION 0.1 Beta)
+ ✔ Implement "Minimal Criteria Novelty Search" (test on NeuroRacers) @done (13-11-21 01:54) @project(FOR VERSION 0.1 Beta)