ECF 1.5
APGenotype.cpp
1#include <iostream>
2#include <cmath>
3#include "APGenotype.h"
4
5
6namespace Tree {
7
8
10{
11 registerParameter(state, "lbound", (voidP) new double(-10), ECF::DOUBLE,
12 "lower bound for each variable (mandatory)");
13 registerParameter(state, "ubound", (voidP) new double(10), ECF::DOUBLE,
14 "upper bound for each variable (mandatory)");
15 registerParameter(state, "dimension", (voidP) new uint(1), ECF::UINT,
16 "number of real valued variables (mandatory)");
17
18 registerParameter(state, "functionset", (voidP)(new std::string), ECF::STRING,
19 "set of functional tree elements (mandatory)");
20 registerParameter(state, "terminalset", (voidP)(new std::string), ECF::STRING,
21 "set of terminal tree elements (mandatory)");
22}
23
24
25bool APGenotype::addFunction(PrimitiveP func)
26{
27 userFunctions_.push_back(func);
28 return true;
29}
30
31
32bool APGenotype::addTerminal(PrimitiveP term)
33{
34 userTerminals_.push_back(term);
35 return true;
36}
37
38
39bool APGenotype::initialize(StateP state)
40{
41 state_ = state;
42
43 // 'persistent' is the AP genotype instance kept in the State;
44 // we use it to link the PrimitiveSet to it and store the parameters
45 APGenotype* persistent = (APGenotype*)state->getGenotypes()[genotypeId_].get();
46
47 // if we are the first one to initialize
48 if (!persistent->primitiveSet)
49 initializeFirst(persistent);
50
51 // in any case, read parameters from hometree
52 this->primitiveSet = persistent->primitiveSet;
53 this->maxValue_ = persistent->maxValue_;
54 this->minValue_ = persistent->minValue_;
55 this->nDimension_ = persistent->nDimension_;
56
57 // create this genotype instance
58 realValue.resize(nDimension_);
59 // randomly create each dimension
60 for (uint i = 0; i < nDimension_; i++) {
61 realValue[i] = (minValue_ + (maxValue_ - minValue_) * state->getRandomizer()->getRandomDouble());
62 }
63
64 return true;
65}
66
67
68void APGenotype::initializeFirst(APGenotype* persistent)
69{
70 // create and link PrimitiveSet to the persistent object
71 persistent->primitiveSet = (PrimitiveSetAPP)(new PrimitiveSetAP);
72 persistent->primitiveSet->initialize(state_);
73 this->primitiveSet = persistent->primitiveSet;
74
75 if (!isParameterDefined(state_, "lbound") ||
76 !isParameterDefined(state_, "ubound") ||
77 !isParameterDefined(state_, "dimension")) {
78 ECF_LOG_ERROR(state_, "Error: required parameters not defined (lbound, ubound, dimension)!");
79 throw("");
80 }
81
82 voidP genp = getParameterValue(state_, "lbound");
83 persistent->minValue_ = *((double*)genp.get());
84
85 genp = getParameterValue(state_, "ubound");
86 persistent->maxValue_ = *((double*)genp.get());
87
88 if (persistent->minValue_ >= persistent->maxValue_) {
89 ECF_LOG_ERROR(state_, "Error: 'lbound' must be smaller than 'ubound'!");
90 throw("");
91 }
92
93 genp = getParameterValue(state_, "dimension");
94 persistent->nDimension_ = *((uint*)genp.get());
95
96 if (persistent->nDimension_ < 1) {
97 ECF_LOG_ERROR(state_, "Error: 'dimension' must be > 0 !");
98 throw("");
99 }
100
101 // add user defined functions to primitiveSet
102 for (int i = 0; i < (int)userFunctions_.size(); i++) {
103 primitiveSet->mAllPrimitives_[userFunctions_[i]->getName()] = userFunctions_[i];
104 primitiveSet->mAllPrimitives_[userFunctions_[i]->getName()]->initialize(state_);
105 }
106
107 voidP sptr = getParameterValue(state_, "functionset");
108 std::stringstream names;
109 std::string name;
110 names << *((std::string*) sptr.get());
111 while (names >> name) {
112 if (!primitiveSet->addFunction(name)) {
113 ECF_LOG_ERROR(state_, "Error: unknown function in function set (\'" + name + "\')!");
114 throw("");
115 }
116
117 }
118
119 if (primitiveSet->getFunctionSetSize() == 0) {
120 ECF_LOG_ERROR(state_, "AP genotype: empty function set!");
121 throw("");
122 }
123
124 // set default terminal type
125 Primitives::terminal_type currentType = Primitives::Double;
126 type_iter typeIter;
127
128 // read terminal set from the configuration
129 std::stringstream tNames;
130 sptr = getParameterValue(state_, "terminalset");
131 tNames << *((std::string*) sptr.get());
132
133 while (tNames >> name)
134 {
135 // read current terminal type (if set)
136 typeIter = primitiveSet->mTypeNames_.find(name);
137 if (typeIter != primitiveSet->mTypeNames_.end()) {
138 currentType = typeIter->second;
139 continue;
140 }
141
142 // see if it's a user-defined terminal
143 uint iTerminal = 0;
144 for (; iTerminal < userTerminals_.size(); iTerminal++)
145 if (userTerminals_[iTerminal]->getName() == name)
146 break;
147 if (iTerminal < userTerminals_.size()) {
148 userTerminals_[iTerminal]->initialize(state_);
149 primitiveSet->addTerminal(userTerminals_[iTerminal]);
150 continue;
151 }
152
153
154 // read ERC definition (if set)
155 // ERC's are defined as interval [x y] or set {a b c}
156 if (name[0] == '[' || name[0] == '{') {
157
158 std::string ercValues = "";
159
160 // name this ERC (ERC's name is its value!)
161 PrimitiveP erc;
162 switch (currentType) {
163 case Primitives::Double:
164 erc = (PrimitiveP)(new Primitives::ERCD);
165 ercValues = DBL_PREFIX;
166 break;
167 case Primitives::Int:
168 erc = (PrimitiveP)(new Primitives::ERC<int>);
169 ercValues = INT_PREFIX;
170 break;
171 case Primitives::Bool:
172 erc = (PrimitiveP)(new Primitives::ERC<bool>);
173 ercValues = BOOL_PREFIX;
174 break;
175 case Primitives::Char:
176 erc = (PrimitiveP)(new Primitives::ERC<char>);
177 ercValues = CHR_PREFIX;
178 break;
179 case Primitives::String:
180 erc = (PrimitiveP)(new Primitives::ERC<std::string>);
181 ercValues = STR_PREFIX;
182 break;
183 }
184
185 while (name[name.size() - 1] != ']' && name[name.size() - 1] != '}') {
186 ercValues += " " + name;
187 tNames >> name;
188 }
189 ercValues += " " + name;
190
191 // ERC ocekuje "D_ [<value> <value> ...]" kao ime prije initialize()
192 erc->setName(ercValues);
193 erc->initialize(state_);
194 primitiveSet->addTerminal(erc);
195
196 continue;
197 }
198
199
200 // otherwise, read terminal of current type
201 PrimitiveP terminal;
202 switch (currentType)
203 {
204 case Primitives::Double:
205 terminal = (PrimitiveP)(new Primitives::Terminal); break;
206 case Primitives::Int:
207 terminal = (PrimitiveP)(new Primitives::TerminalT<int>); break;
208 case Primitives::Bool:
209 terminal = (PrimitiveP)(new Primitives::TerminalT<bool>); break;
210 case Primitives::Char:
211 terminal = (PrimitiveP)(new Primitives::TerminalT<char>); break;
212 case Primitives::String:
213 terminal = (PrimitiveP)(new Primitives::TerminalT<std::string>); break;
214 }
215
216 // if the 'name' can be identified as a value of the 'currentType', then it's a _constant terminal_ (of that value)
217 // otherwise, it's a regular terminal with 'name'
218 std::istringstream ss(name);
219 switch (currentType)
220 {
221 case Primitives::Double:
222 double dblValue;
223 ss >> dblValue;
224 if (ss.fail() == false)
225 terminal->setValue(&dblValue);
226 break;
227 case Primitives::Int:
228 int intValue;
229 ss >> intValue;
230 if (ss.fail() == false)
231 terminal->setValue(&intValue);
232 break;
233 case Primitives::Bool:
234 bool boolValue;
235 ss >> boolValue;
236 if (name == "true")
237 boolValue = true;
238 else if (name == "false")
239 boolValue = false;
240 if (ss.fail() == false || name == "true" || name == "false") {
241 if (boolValue)
242 name = "true";
243 else
244 name = "false";
245 terminal->setValue(&boolValue);
246 }
247 break;
248 case Primitives::Char:
249 char charValue;
250 ss >> charValue;
251 if (ss.fail() == false)
252 terminal->setValue(&charValue);
253 break;
254 case Primitives::String:
255 std::string stringValue;
256 ss >> stringValue;
257 if (ss.fail() == false)
258 terminal->setValue(&stringValue);
259 break;
260 }
261 terminal->setName(name);
262 primitiveSet->addTerminal(terminal);
263
264 }
265
266 if (primitiveSet->getTerminalSetSize() == 0) {
267 ECF_LOG_ERROR(state_, "APGenotype: Empty terminal set!");
268 throw("");
269 }
270
271}
272
273
274std::vector<uint> APGenotype::getDiscreteIndices()
275{
276 std::vector<uint> discrete;
277 discrete.resize(nDimension_);
278
279 double dindex, diff, delta;
280 int imax = primitiveSet->getPrimitivesSize() - 1, dis_index;
281 diff = maxValue_ - minValue_;
282 delta = 1.0 / (double)primitiveSet->getPrimitivesSize();
283
284 for (uint i = 0; i < nDimension_; i++) {
285 dis_index = 0;
286 dindex = (realValue[i] - minValue_) / diff;
287
288 dindex -= delta;
289 while (dindex > 0 && dis_index != imax) {
290 dindex -= delta;
291 dis_index++;
292 }
293
294 discrete[i] = dis_index;
295 }
296
297 return discrete;
298}
299
300
301void APGenotype::buildTree(std::vector<uint> indices, uint current, uint depth)
302{
303 Node* node = new Node();
304 node->depth_ = depth;
305
306 uint index = current - 1;
307
308 uint numArgs = primitiveSet->getPrimitiveByIndex(index)->getNumberOfArguments();
309
310 if (numArgs < toEnd) {
311 node->setPrimitive(primitiveSet->getPrimitiveByIndex(index));
312 nodes.push_back(static_cast<NodeP> (node));
313 } else if (toEnd >= 2 && toEnd <= numArgs && primitiveSet->getGFSTwoSetSize() != 0) {
314 node->setPrimitive(primitiveSet->getGFSTwoByIndex(index));
315 nodes.push_back(static_cast<NodeP> (node));
316 } else if (toEnd == 1 && primitiveSet->getGFSOneSetSize() != 0) {
317 node->setPrimitive(primitiveSet->getGFSOneByIndex(index));
318 nodes.push_back(static_cast<NodeP> (node));
319 } else {
320 node->setPrimitive(primitiveSet->getTerminalByIndex(index));
321 nodes.push_back(static_cast<NodeP> (node));
322 }
323
324 numArgs = node->primitive_->getNumberOfArguments();
325
326 toEnd -= numArgs;
327
328 if (numArgs > 0) {
329 std::vector<uint> passableIndices(indices.begin(), indices.begin() + numArgs);
330 indices.erase(indices.begin(), indices.begin() + numArgs - 1);
331
332 for (uint i = 0; i < numArgs; i++) {
333 buildTree(indices, passableIndices[i], depth + 1);
334 }
335 }
336}
337
338
339Tree* APGenotype::convertToPhenotype()
340{
341 std::vector<uint> indices = getDiscreteIndices();
342
343 toEnd = nDimension_ - 1;
344 uint first = indices[0];
345 nodes.clear();
346
347 indices.erase(indices.begin());
348
349 buildTree(indices, first, 0);
350
351 Tree* tree = new Tree();
352 for (uint i = 0; i < nodes.size(); i++) {
353 tree->addNode(nodes[i]);
354 }
355
356 std::stringstream sValue;
357 for (uint i = 0; i < tree->size(); i++) {
358 sValue << (*tree)[i]->primitive_->getName() << " ";
359 }
360
361 //cout << sValue.str() << endl;
362
363 return tree;
364}
365
366
367void APGenotype::setTerminalValue(Tree* tree, std::string name, void* value)
368{
369 PrimitiveP term = primitiveSet->getTerminalByName(name);
370 if (term == PrimitiveP()) {
371 ECF_LOG_ERROR(state_, "AP genotype: invalid terminal name referenced in setTerminalValue()!");
372 throw("");
373 }
374
375 term->setValue(value);
376}
377
378
379void APGenotype::write(XMLNode &xFloatingPoint)
380{
381 xFloatingPoint = XMLNode::createXMLTopNode("APGenotype");
382 std::stringstream sValue;
383 sValue << nDimension_;
384 xFloatingPoint.addAttribute("size", sValue.str().c_str());
385
386 sValue.str("");
387 for (uint iVar = 0; iVar < nDimension_; iVar++)
388 sValue << "\t" << realValue[iVar];
389 xFloatingPoint.addText(sValue.str().c_str());
390}
391
392
393void APGenotype::read(XMLNode& xFloatingPoint)
394{
395 XMLCSTR values = xFloatingPoint.getText();
396 std::stringstream sValues;
397 sValues << values;
398
399 for (uint iVar = 0; iVar < nDimension_; iVar++) {
400 sValues >> realValue[iVar];
401 }
402}
403
404
405}
voidP getParameterValue(StateP state, std::string name)
Read single parameter value from Registry.
Definition: Genotype.cpp:10
std::string getName()
Return genotype's name (each genotype is uniquely identified with its name).
Definition: Genotype.h:86
bool registerParameter(StateP state, std::string name, voidP value, enum ECF::type T, std::string description="")
Register a single parameter.
Definition: Genotype.cpp:4
bool isParameterDefined(StateP state, std::string name)
Check if parameter is defined in the configuration.
Definition: Genotype.cpp:22
uint genotypeId_
this genotype's unique index in individual structure
Definition: Genotype.h:110
uint nDimension_
dimensionality
double minValue_
lower bound
double maxValue_
upper bound
std::vector< double > realValue
vector of floating point values
Analytical Programing genotype class - implements genotype as a vector of floating point values that ...
Definition: APGenotype.h:50
void write(XMLNode &xFloatingPoint)
Write genotype data to XMLNode.
Definition: APGenotype.cpp:379
void read(XMLNode &xFloatingPoint)
Read genotype data from XMLNode.
Definition: APGenotype.cpp:393
bool initialize(StateP state)
Initialize a genotype object (read parameters, perform sanity check, build data)
Definition: APGenotype.cpp:39
void registerParameters(StateP)
Register genotype's parameters (called before Genotype::initialize)
Definition: APGenotype.cpp:9
Primitive set class for APGenotype: collects all Tree Primitives.
Definition: nodes.h:92