Vita
evaluator_proxy.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2011-2023 EOS di Manlio Morini.
6 *
7 * \license
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
10 * You can obtain one at http://mozilla.org/MPL/2.0/
11 */
12
13#if !defined(VITA_EVALUATOR_PROXY_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_EVALUATOR_PROXY_TCC)
18#define VITA_EVALUATOR_PROXY_TCC
19
20///
21/// \param[in] eva pointer that lets the proxy access the real evaluator
22/// \param[in] ts `2^ts` is the number of elements of the cache
23///
24template<class T, class E>
25evaluator_proxy<T, E>::evaluator_proxy(E eva, unsigned ts)
26 : eva_(std::move(eva)), cache_(ts)
27{
28 Expects(ts > 6);
29}
30
31///
32/// \param[in] prg the program (individual/team) whose fitness we want to know
33/// \return the fitness of `prg`
34///
35template<class T, class E>
36fitness_t evaluator_proxy<T, E>::operator()(const T &prg)
37{
38 fitness_t f(cache_.find(prg.signature()));
39
40 if (f.size())
41 {
42 // Hash collision checking code can slow down the program very much.
43#if !defined(NDEBUG)
44 const fitness_t f1(eva_(prg));
45 if (!almost_equal(f[0], f1[0]))
46 std::cerr << "********* COLLISION ********* [" << f << " != " << f1
47 << "]\n";
48
49 // In the above comparison we consider only the first component of the
50 // fitness otherwise we can have false positives.
51 // For example if the fitness is a 2D vector (where the first component
52 // is the "score" on the training set and the second one is the effective
53 // length of the program), then the following two programs:
54 //
55 // PROGRAM A PROGRAM B
56 // ------------------ ------------------
57 // [000] FADD 001 002 [000] FADD 001 001
58 // [001] X1 [001] X1
59 // [002] X1
60 //
61 // have the same signature, the same stored "score" but distinct
62 // effective size and so distinct fitnesses.
63#endif
64 }
65 else // not found in cache
66 {
67 f = eva_(prg);
68
69 cache_.insert(prg.signature(), f);
70
71#if !defined(NDEBUG)
72 fitness_t f1(cache_.find(prg.signature()));
73 assert(f1.size());
74 assert(almost_equal(f, f1));
75#endif
76 }
77
78 return f;
79}
80
81///
82/// \param[in] prg the program (individual/team) whose fitness we want to know
83/// \return an approximation of the fitness of `prg`
84///
85/// \remark
86/// The approximated ("fast") fitness isn't stored in the cache.
87///
88template<class T, class E>
89fitness_t evaluator_proxy<T, E>::fast(const T &prg)
90{
91 return eva_.fast(prg);
92}
93
94///
95/// \param[in] in input stream
96/// \return `true` if the object loaded correctly
97///
98/// \warning
99/// If the load operation isn't successful the current object COULD BE changed.
100/// The temporary object needed to holds values from the stream conceivably is
101/// too big to justify the "no change" warranty.
102///
103template<class T, class E>
104bool evaluator_proxy<T, E>::load(std::istream &in)
105{
106 return eva_.load(in) && cache_.load(in);
107}
108
109///
110/// \param[out] out output stream
111/// \return `true` if the object was saved correctly
112///
113template<class T, class E>
114bool evaluator_proxy<T, E>::save(std::ostream &out) const
115{
116 return eva_.save(out) && cache_.save(out);
117}
118
119///
120/// Resets the evaluation cache.
121///
122template<class T, class E>
123void evaluator_proxy<T, E>::clear()
124{
125 cache_.clear();
126}
127
128///
129/// \param[in] prg a program (individual/team)
130/// \return a pointer to the executable version of `prg`
131///
132template<class T, class E>
133std::unique_ptr<basic_lambda_f> evaluator_proxy<T, E>::lambdify(
134 const T &prg) const
135{
136 return eva_.lambdify(prg);
137}
138
139#endif // include guard