aboutsummaryrefslogtreecommitdiff
path: root/src/NoveltyMetric.cpp
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/NoveltyMetric.cpp
Initial commitHEADmaster
Diffstat (limited to 'src/NoveltyMetric.cpp')
-rw-r--r--src/NoveltyMetric.cpp101
1 files changed, 101 insertions, 0 deletions
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);
+}