aboutsummaryrefslogtreecommitdiff
path: root/src/NoveltyMetric.cpp
blob: dd4011884610d4f03206f4b64142a8364adb9697 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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);
}