aboutsummaryrefslogtreecommitdiff
path: root/src/Utils
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 /src/Utils
Initial commitHEADmaster
Diffstat (limited to 'src/Utils')
-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
5 files changed, 610 insertions, 0 deletions
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)
+{}