ECF 1.7
GEPChromosome.cpp
1#include "GEPChromosome.h"
2
3namespace GEP{
4 // mandatory: define name, other things as needed
5 GEPChromosome::GEPChromosome(){
6 Genotype::name_ = "GEPChromosome";
7 usesERC = false;
8 dcLength = 0;
9 staticLink = false;
10 }
11
12 // mandatory: must provide copy method
13 GEPChromosome* GEPChromosome::copy()
14 {
15 GEPChromosome *newObject = new GEPChromosome(*this);
16 return newObject;
17 }
18
19 // optional: declare crx operators (if not, no crossover will be performed)
20 std::vector<CrossoverOpP> GEPChromosome::getCrossoverOp()
21 {
22 std::vector<CrossoverOpP> crx;
23 crx.push_back(static_cast<CrossoverOpP> (new GEPChromosomeCrsOnePoint));
24 crx.push_back(static_cast<CrossoverOpP> (new GEPChromosomeCrsTwoPoint));
25 crx.push_back(static_cast<CrossoverOpP> (new GEPChromosomeCrsGene));
26 return crx;
27 }
28
29 // optional: declare mut operators (if not, no mutation will be performed)
30 std::vector<MutationOpP> GEPChromosome::getMutationOp()
31 {
32 std::vector<MutationOpP> mut;
33 mut.push_back(static_cast<MutationOpP> (new GEPChromosomeMutOp));
34 mut.push_back(static_cast<MutationOpP> (new GEPChromosomeMutGauss));
35 return mut;
36 }
37
38 // optional: register any parameters
40 {
41 registerParameter(state, "headlength", (voidP)(new uint(1)), ECF::UINT);
42 registerParameter(state, "genes", (voidP)(new uint(1)), ECF::UINT);
43 registerParameter(state, "functionset", (voidP)(new std::string), ECF::STRING);
44 registerParameter(state, "terminalset", (voidP)(new std::string), ECF::STRING);
45 registerParameter(state, "linkingfunctions", (voidP)(new std::string), ECF::STRING);
46 registerParameter(state, "linklength", (voidP)(new uint(1)), ECF::UINT);
47 }
48
49
54 bool GEPChromosome::addFunction(Tree::PrimitiveP func)
55 {
56 userFunctions_.push_back(func);
57 return true;
58 }
59
60
61 void GEPChromosome::generateChromosome()
62 {
63 Tree::Node* node;
64 for (uint i = 0; i < genes; i++){
65 // Generate random primitives for the head (Functions + Terminals)
66 for (uint j = 0; j < headLength; j++) {
67 node = new Tree::Node();
68 node->setPrimitive(primitiveSet_->getRandomPrimitive());
69 this->push_back(static_cast<Tree::NodeP>(node));
70 }
71 // Generate random terminals for the tail
72 for (uint j = 0; j < tailLength; j++) {
73 node = new Tree::Node();
74 node->setPrimitive(primitiveSet_->getRandomTerminal());
75 this->push_back(static_cast<Tree::NodeP>(node));
76 }
77 // Generate ERCs for the Dc domain
78 for (uint j = 0; j < dcLength; j++){
79 node = new Tree::Node();
80 node->setPrimitive(ercSet_->getRandomTerminal());
81 this->push_back(static_cast<Tree::NodeP>(node));
82 }
83 }
84 // Set the homeotic gene (this controls the linking functions)
85 for (uint i = 0; i < linkHeadLength; i++){
86 node = new Tree::Node();
87 node->setPrimitive(linkFunctionSet_->getRandomPrimitive());
88 this->push_back(static_cast<Tree::NodeP>(node));
89 }
90 for (uint i = 0; i < linkTailLength; i++){
91 node = new Tree::Node();
92 node->setPrimitive(linkFunctionSet_->getRandomTerminal());
93 this->push_back(static_cast<Tree::NodeP>(node));
94 }
95 }
96
97 // mandatory: build initial genotype structure
98 bool GEPChromosome::initialize(StateP state)
99 {
100 // 'homegep' is a Gep instance kept in the State;
101 // we use it to link the PrimitiveSet to it and store the parameters
102 GEPChromosome* homegep = (GEPChromosome*)state->getGenotypes()[genotypeId_].get();
103 state_ = state;
104
105 // if we are the first one to initialize
106 if (!homegep->primitiveSet_){
107 initializeFirst(homegep);
108 }
109 // in any case, read parameters from from hometree
110 this->primitiveSet_ = homegep->primitiveSet_;
111 this->linkFunctionSet_ = homegep->linkFunctionSet_;
112 this->ercSet_ = homegep->ercSet_;
113 this->headLength = homegep->headLength;
114 this->genes = homegep->genes;
115 this->tailLength = homegep->tailLength;
116 this->dcLength = homegep->dcLength;
117 this->geneLength = homegep->geneLength;
118 this->linkHeadLength = homegep->linkHeadLength;
119 this->linkTailLength = homegep->linkTailLength;
120 // generate the chromosome
121 generateChromosome();
122
123 return true;
124 }
125
126 void GEPChromosome::initializeFirst(GEPChromosome* home)
127 {
128
129 // create and link PrimitiveSet to the hometree
130 if (home == NULL){
131 return;
132 }
133 home->primitiveSet_ = static_cast<Tree::PrimitiveSetP> (new Tree::PrimitiveSet);
134 home->primitiveSet_->initialize(state_);
135 this->primitiveSet_ = home->primitiveSet_;
136
137 home->linkFunctionSet_ = static_cast<Tree::PrimitiveSetP> (new Tree::PrimitiveSet);
138 home->linkFunctionSet_->initialize(state_);
139 this->linkFunctionSet_ = home->linkFunctionSet_;
140
141 home->ercSet_ = static_cast<Tree::PrimitiveSetP> (new Tree::PrimitiveSet);
142 home->ercSet_->initialize(state_);
143 this->ercSet_ = home->ercSet_;
144
145 // read number of genes, store in hometree
146 voidP sptr = getParameterValue(state_, "genes");
147 home->genes = *((uint*)sptr.get());
148
149 if (home->genes < 1) {
150 ECF_LOG_ERROR(state_, "Gep genotype: number of genes must be >=1");
151 }
152
153 // add user defined functions to primitiveSet
154
155 for (int i = 0; i < (int)userFunctions_.size(); i++) {
156 primitiveSet_->mAllPrimitives_[userFunctions_[i]->getName()] = userFunctions_[i];
157 }
158
159 uint maxArg = 0;
160 uint tmpArg = 0;
161 // read function set from the configuration
162 sptr = getParameterValue(state_, "functionset");
163 std::stringstream names;
164 std::string name;
165 names << *((std::string*) sptr.get());
166 while (names >> name) {
167 if (!primitiveSet_->addFunction(name)) {
168 ECF_LOG_ERROR(state_, "Error: unknown function in function set (\'" + name + "\')!");
169 throw("");
170 }
171 tmpArg = primitiveSet_->getPrimitiveByName(name)->getNumberOfArguments();
172 if (tmpArg > maxArg)
173 maxArg = tmpArg;
174 }
175 // read Gep head length, store in hometree
176 sptr = getParameterValue(state_, "headlength");
177 home->headLength = *((uint*)sptr.get());
178
179 if (home->headLength < 1) {
180 ECF_LOG_ERROR(state_, "Gep genotype: length of head must be >= 1");
181 }
182
183 // now we can tell how long tail must be
184 home->tailLength = home->headLength * (maxArg - 1) + 1;
185 home->geneLength = home->headLength + home->tailLength;
186
187 if (primitiveSet_->getFunctionSetSize() == 0) {
188 ECF_LOG_ERROR(state_, "Tree genotype: empty function set!");
189 throw("");
190 }
191
192 // create and link the linking function set
193 // Mono-genic chromosomes should have a constant homeotic gene for the sake of simplicity (i.e., their homeotic gene shall always be "0")
194 // Multi-genic chromosomes can evolve their homeotic gene by default, unless a static linking configuration is specified (TO-DO)
195
196 uint linkMaxArg = 0;
197 uint linkTmpArg = 0;
198 std::stringstream linkNames;
199 // read linking function set from the configuration
200 sptr = getParameterValue(state_, "linkingfunctions");
201 linkNames << *((std::string*) sptr.get());
202 while (linkNames >> name) {
203 if (!linkFunctionSet_->addFunction(name)) {
204 ECF_LOG_ERROR(state_, "Error: unknown function in linking function set (\'" + name + "\')!");
205 throw("");
206 }
207 linkTmpArg = linkFunctionSet_->getPrimitiveByName(name)->getNumberOfArguments();
208 if (linkTmpArg > linkMaxArg)
209 linkMaxArg = linkTmpArg;
210 }
211 // read homeotic gene head length, store in hometree
212 sptr = getParameterValue(state_, "linklength");
213 home->linkHeadLength = *((uint*)sptr.get());
214
215 if (home->linkHeadLength < 1) {
216 ECF_LOG_ERROR(state_, "Gep genotype: length of linking function gene head must be >= 1");
217 }
218
219 // now we can tell how long tail must be
220 home->linkTailLength = home->linkHeadLength * (linkMaxArg - 1) + 1;
221
222 if (linkFunctionSet_->getFunctionSetSize() == 0) {
223 ECF_LOG_ERROR(state_, "GEP genotype: empty linking function set!");
224 }
225 // Add "terminals" to the linking function set. These will be a prefix + integers from [0, # of genes]
226 for (uint i = 0; i < home->genes; i++){
227 Tree::PrimitiveP geneTerminals = (Tree::PrimitiveP)(new Tree::Primitives::Terminal);
228 std::string geneTermStr = GEP_GENE_PREFIX;
229 geneTermStr += uint2str(i);
230 geneTerminals->setName(geneTermStr);
231 geneTerminals->initialize(state_);
232 linkFunctionSet_->addTerminal(geneTerminals);
233 }
234 // set default terminal type
235 Tree::Primitives::terminal_type currentType = Tree::Primitives::Double;
236 Tree::type_iter typeIter;
237
238 // read terminal set from the configuration
239
240 std::stringstream tNames;
241 sptr = getParameterValue(state_, "terminalset");
242 tNames << *((std::string*) sptr.get());
243
244 while (tNames >> name) {
245 // read current terminal type (if set)
246 typeIter = primitiveSet_->mTypeNames_.find(name);
247 if (typeIter != primitiveSet_->mTypeNames_.end()) {
248 currentType = typeIter->second;
249 continue;
250 }
251
252 // see if it's a user-defined terminal
253 /*
254 uint iTerminal = 0;
255 for (; iTerminal < userTerminals_.size(); iTerminal++)
256 if (userTerminals_[iTerminal]->getName() == name)
257 break;
258 if (iTerminal < userTerminals_.size()) {
259 primitiveSet_->addTerminal(userTerminals_[iTerminal]);
260 continue;
261 }
262 */
263 // read ERC definition (if set)
264 // ERC's are defined as interval [x y] or set {a b c}
265 // If ERCs are requested by the user, we add the placeholder terminal '?' to primitiveSet_
266 // We then add any ERCs to ercSet_
267
268 if (name[0] == '[' || name[0] == '{') {
269
270 //if this is the first ERC range we encounter, add the placeholder and switch on the ERC flag
271 if (!usesERC){
272 usesERC = true;
273 Tree::PrimitiveP placeholder = (Tree::PrimitiveP) (new Tree::Primitives::Terminal);
274 placeholder->setName("?");
275 primitiveSet_->addTerminal(placeholder);
276 // If ERCs are used, the length of the Dc domain is the same as the tail length
277 home->dcLength = home->tailLength;
278 home->geneLength += home->dcLength;
279 }
280
281 std::string ercValues = "";
282
283 // name this ERC (ERC's name is its value!)
284 Tree::PrimitiveP erc;
285 switch (currentType) {
286 case Tree::Primitives::Double:
287 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERCD);
288 ercValues = DBL_PREFIX;
289 break;
290 case Tree::Primitives::Int:
291 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<int>);
292 ercValues = INT_PREFIX;
293 break;
294 case Tree::Primitives::Bool:
295 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<bool>);
296 ercValues = BOOL_PREFIX;
297 break;
298 case Tree::Primitives::Char:
299 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<char>);
300 ercValues = CHR_PREFIX;
301 break;
302 case Tree::Primitives::String:
303 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<std::string>);
304 ercValues = STR_PREFIX;
305 break;
306 }
307
308 while (name[name.size() - 1] != ']' && name[name.size() - 1] != '}') {
309 ercValues += " " + name;
310 tNames >> name;
311 }
312 ercValues += " " + name;
313 erc->setName(ercValues);
314 erc->initialize(state_);
315 ercSet_->addTerminal(erc);
316
317 continue;
318 }
319
320 //read terminal of current type
321 Tree::PrimitiveP terminal;
322 switch (currentType)
323 {
324 case Tree::Primitives::Double:
325 terminal = (Tree::PrimitiveP) (new Tree::Primitives::Terminal); break;
326 case Tree::Primitives::Int:
327 terminal = (Tree::PrimitiveP) (new Tree::Primitives::TerminalT<int>); break;
328 case Tree::Primitives::Bool:
329 terminal = (Tree::PrimitiveP) (new Tree::Primitives::TerminalT<bool>); break;
330 case Tree::Primitives::Char:
331 terminal = (Tree::PrimitiveP) (new Tree::Primitives::TerminalT<char>); break;
332 case Tree::Primitives::String:
333 terminal = (Tree::PrimitiveP) (new Tree::Primitives::TerminalT<std::string>); break;
334 }
335
336 // if the 'name' can be identified as a value of the 'currentType', then it's a _constant terminal_ (of that value)
337 // otherwise, it's a regular terminal with 'name'
338 std::istringstream ss(name);
339 switch (currentType)
340 {
341 case Tree::Primitives::Double:
342 double dblValue;
343 ss >> dblValue;
344 if (ss.fail() == false)
345 terminal->setValue(&dblValue);
346 break;
347 case Tree::Primitives::Int:
348 int intValue;
349 ss >> intValue;
350 if (ss.fail() == false)
351 terminal->setValue(&intValue);
352 break;
353 case Tree::Primitives::Bool:
354 bool boolValue;
355 ss >> boolValue;
356 if (name == "true")
357 boolValue = true;
358 else if (name == "false")
359 boolValue = false;
360 if (ss.fail() == false || name == "true" || name == "false") {
361 if (boolValue)
362 name = "true";
363 else
364 name = "false";
365 terminal->setValue(&boolValue);
366 }
367 break;
368 case Tree::Primitives::Char:
369 char charValue;
370 ss >> charValue;
371 if (ss.fail() == false)
372 terminal->setValue(&charValue);
373 break;
374 case Tree::Primitives::String:
375 std::string stringValue;
376 ss >> stringValue;
377 if (ss.fail() == false)
378 terminal->setValue(&stringValue);
379 break;
380 }
381 terminal->setName(name);
382 primitiveSet_->addTerminal(terminal);
383
384 }
385
386 if (primitiveSet_->getTerminalSetSize() == 0) {
387 ECF_LOG_ERROR(state_, "Tree: Empty terminal set!");
388 throw("");
389 }
390
391 }
392
393 // mandatory: write to XMLNode
394 void GEPChromosome::write(XMLNode &xGEPChromosome)
395 {
396 xGEPChromosome = XMLNode::createXMLTopNode("GEPChromosome");
397 std::stringstream sValue;
398 sValue << genes;
399 xGEPChromosome.addAttribute("genes", sValue.str().c_str());
400 sValue.str("");
401 sValue << headLength;
402 xGEPChromosome.addAttribute("headLength",sValue.str().c_str());
403 sValue.str("");
404 sValue << tailLength;
405 xGEPChromosome.addAttribute("tailLength", sValue.str().c_str());
406 sValue.str("");
407 sValue << linkHeadLength;
408 xGEPChromosome.addAttribute("linkLength", sValue.str().c_str());
409 for (uint g = 0; g < genes; g++){
410 sValue.str("");
411 XMLNode xGene = XMLNode::createXMLTopNode("Gene");
412 for (uint i = 0; i < this->geneLength; i++) {
413 sValue << this->at(g*(this->geneLength)+i)->primitive_->getName() << " ";
414 }
415 xGene.addText(sValue.str().c_str());
416 xGEPChromosome.addChild(xGene);
417 }
418 // print homeotic gene
419 sValue.str("");
420 XMLNode xCell = XMLNode::createXMLTopNode("Cell");
421 uint cellOffset = this->genes * this->geneLength;
422 for (uint i = 0; i < this->linkHeadLength + this->linkTailLength; i++) {
423 sValue << this->at(cellOffset + i)->primitive_->getName() << " ";
424 }
425 xCell.addText(sValue.str().c_str());
426 xGEPChromosome.addChild(xCell);
427 }
428
429
430 // read from XMLNode
431 // mandatory if running parallel ECF or reading population from a milestone file
432 void GEPChromosome::read(XMLNode& xGEPChromosome)
433 {
434 // temporary comment-out, to avoid access to primitiveSet_->primitives_
435 return;
436
437/*
438 this->clear();
439 //this->primitiveSet_ = static_cast<Tree::PrimitiveSetP> (new Tree::PrimitiveSet);
440 //this->primitiveSet_->initialize(state_);
441 XMLCSTR genesStr = xGEPChromosome.getAttribute("genes");
442 uint size = str2uint(genesStr);
443
444 XMLCSTR hlenStr = xGEPChromosome.getAttribute("headLength");
445 uint headlen = str2uint(hlenStr);
446
447 XMLCSTR tlenStr = xGEPChromosome.getAttribute("linkLength");
448 uint linklen = str2uint(tlenStr);
449 // loop over genes
450 for (uint i = 0; i <= size; i++){
451 XMLNode xGene = xGEPChromosome.getChildNode(i);
452 XMLCSTR tree = xGene.getText();
453 std::stringstream stream;
454 stream << tree;
455
456 if (i < size){
457 std::vector<Tree::PrimitiveP>& primitives = primitiveSet_->primitives_;
458 std::string primitiveStr;
459 uint position = 0;
460
461 for (uint iNode = 0; iNode < this->geneLength; iNode++) {
462 stream >> primitiveStr;
463 Tree::Node* node = new Tree::Node();
464
465 // 'regular' primitives
466 Tree::PrimitiveP prim = primitiveSet_->getPrimitiveByName(primitiveStr);
467 if (prim != Tree::PrimitiveP()) {
468 node->setPrimitive(prim);
469 this->push_back(static_cast<Tree::NodeP>(node));
470 continue;
471 }
472 // ERCs
473 // (TODO: include user defined ERC types)
474 Tree::PrimitiveP erc;
475 std::string prefix = primitiveStr.substr(0, 2);
476 std::string value = primitiveStr.substr(2);
477 std::stringstream ss;
478 ss << value;
479 if (prefix == DBL_PREFIX) {
480 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERCD);
481 double v;
482 ss >> v;
483 erc->setValue(&v);
484 }
485 else if (prefix == INT_PREFIX) {
486 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<int>);
487 int v;
488 ss >> v;
489 erc->setValue(&v);
490 }
491 else if (prefix == BOOL_PREFIX) {
492 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<bool>);
493 bool v;
494 ss >> v;
495 erc->setValue(&v);
496 }
497 else if (prefix == CHR_PREFIX) {
498 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<char>);
499 char v;
500 ss >> v;
501 erc->setValue(&v);
502 }
503 else if (prefix == STR_PREFIX) {
504 erc = (Tree::PrimitiveP)(new Tree::Primitives::ERC<std::string>);
505 std::string v;
506 ss >> v;
507 erc->setValue(&v);
508 }
509 else {
510 ECF_LOG_ERROR(state_, "GEPChromosome genotype: undefined primitive (" + primitiveStr + ")!");
511 throw("");
512 }
513 erc->setName(primitiveStr);
514 node->primitive_ = erc;
515 this->push_back(static_cast<Tree::NodeP>(node));
516 }
517 }
518 else{ // Deal with the "Cell" gene
519 std::vector<Tree::PrimitiveP>& primitives = linkFunctionSet_->primitives_;
520 std::string primitiveStr;
521 uint position = 0;
522
523 for (uint iNode = 0; iNode < this->linkHeadLength+this->linkTailLength; iNode++) {
524 stream >> primitiveStr;
525 Tree::Node* node = new Tree::Node();
526 // 'regular' primitives
527 Tree::PrimitiveP prim = linkFunctionSet_->getPrimitiveByName(primitiveStr);
528 if (prim != Tree::PrimitiveP()) { // if it is a linking function
529 node->setPrimitive(prim);
530 this->push_back(static_cast<Tree::NodeP>(node));
531 continue;
532 }
533 else{
534 ECF_LOG_ERROR(state_, "GEPChromosome genotype: undefined primitive (" + primitiveStr + ") for the Cell gene!");
535 throw("");
536 }
537 }
538 }
539 }
540 */
541 }
542
543 Tree::Tree* GEPChromosome::toTree(uint gene)
544 {
545 ECF_LOG(this->state_, 5, "Performing GEP -> Tree conversion...");
546
547 Tree::Tree* tree = new Tree::Tree();
548 // Copy primitive set
549 tree->primitiveSet_ = this->primitiveSet_;
550
551 uint geneOffset = gene*(this->geneLength);
552 uint ercIdx = geneOffset + this->headLength + this->tailLength;
553 uint ercCount = 0;
554 // Get root node arity
555 //geneOffset = 0;
556 uint i = geneOffset;
557 uint nArgs = this->at(i++)->primitive_->getNumberOfArguments();
558 // Get tree level indices
559 std::vector<uint> idx;
560 int level = 0;
561 uint nextLevelStart = 1 + geneOffset;
562 idx.push_back(geneOffset);
563 while (nArgs > 0){
564 uint lvlArity = 0;
565 idx.push_back(nextLevelStart);
566 for (uint j = 0; j < nArgs; j++){
567 lvlArity += this->at(nextLevelStart++)->primitive_->getNumberOfArguments();
568 }
569 nArgs = lvlArity;
570 }
571 //Read the gene and annotate the locations of the constants (needed later)
572 std::vector<int> constants(this->size(), -99999);
573 if (this->dcLength > 0){
574 for (uint c = geneOffset; c < geneOffset + this->headLength + this->tailLength; c++){
575 if (this->at(c)->primitive_->getName() == "?"){
576 constants[c] = ercCount++;
577 }
578 }
579 }
580 // Translate expression
581 // Helper array to store the per-level arguments needed
582 std::vector<uint> args(idx.size(), 0);
583 // Iterate while root node hasn't completed
584 std::vector<bool> visited(this->size(), false);
585 while (idx.at(0) == geneOffset){
586 // Read and this node to GP expression, if it hasn't been visited yet
587 if (!visited.at(idx.at(level))){
588 Tree::NodeP GEPnode = static_cast<Tree::NodeP> (new Tree::Node(this->at(idx.at(level))));
589 // If it is an ERC placeholder, replace with the next ERC
590 if (GEPnode->primitive_->getName() == "?"){
591 GEPnode = static_cast<Tree::NodeP> (new Tree::Node(this->at(ercIdx+constants.at(idx.at(level)))));
592 }
593 args[level] = GEPnode->primitive_->getNumberOfArguments();
594 // Push node into Tree representation
595 Tree::NodeP node = static_cast<Tree::NodeP> (new Tree::Node(GEPnode));
596 tree->addNode(node);
597 visited.at(idx.at(level)) = true;
598 }
599 // If operator still needs children, go down one level and read the necessary arguments
600 if (args.at(level) > 0){
601 level++;
602 }
603 // If it is a terminal or a satisfied operator, go up one level and increase reading index
604 else{
605 idx[level]++;
606 level--;
607 // Decrease needed arguments
608 if (level >= 0) args[level]--;
609 }
610 }
611 // Update the size and depth of each tree node
612 tree->update();
613 // Print tree
614 XMLNode xInd;
615 tree->write(xInd);
616 char *s = xInd.createXMLString();
617 ECF_LOG(this->state_, 5, "Tree conversion result: \n" + std::string(s));
618 freeXMLString(s);
619 return tree;
620 }
621
622 Tree::Tree* GEPChromosome::makeCellTree()
623 {
624 ECF_LOG(this->state_, 5, "Performing GEP -> Tree conversion at the cell level...");
625
626 Tree::Tree* tree = new Tree::Tree();
627 // Copy primitive set
628 tree->primitiveSet_ = this->linkFunctionSet_;
629
630 uint geneOffset = this->genes*(this->geneLength);
631 // Get root node arity
632 uint i = geneOffset;
633 uint nArgs = this->at(i++)->primitive_->getNumberOfArguments();
634 // Get tree level indices
635 std::vector<uint> idx;
636 int level = 0;
637 uint nextLevelStart = 1 + geneOffset;
638 idx.push_back(geneOffset);
639 while (nArgs > 0){
640 uint lvlArity = 0;
641 idx.push_back(nextLevelStart);
642 for (uint j = 0; j < nArgs; j++){
643 lvlArity += this->at(nextLevelStart++)->primitive_->getNumberOfArguments();
644 }
645 nArgs = lvlArity;
646 }
647 // Translate expression
648 // Helper array to store the per-level arguments needed
649 std::vector<uint> args(idx.size(), 0);
650 // Iterate while root node hasn't completed
651 std::vector<bool> visited(this->size(), false);
652 while (idx.at(0) == geneOffset){
653 // Read and this node to GP expression, if it hasn't been visited yet
654 if (!visited.at(idx.at(level))){
655 Tree::NodeP GEPnode = static_cast<Tree::NodeP> (new Tree::Node(this->at(idx.at(level))));
656 args[level] = GEPnode->primitive_->getNumberOfArguments();
657 // Push node into Tree representation
658 Tree::NodeP node = static_cast<Tree::NodeP> (new Tree::Node(GEPnode));
659 tree->addNode(node);
660 visited.at(idx.at(level)) = true;
661 }
662 // If operator still needs children, go down one level and read the necessary arguments
663 if (args.at(level) > 0){
664 level++;
665 }
666 // If it is a terminal or a satisfied operator, go up one level and increase reading index
667 else{
668 idx[level]++;
669 level--;
670 // Decrease needed arguments
671 if (level >= 0) args[level]--;
672 }
673 }
674 // Update the size and depth of each tree node
675 tree->update();
676 // Print tree
677 XMLNode xInd;
678 tree->write(xInd);
679 char *s = xInd.createXMLString();
680 ECF_LOG(this->state_, 5, "Tree conversion result: \n" + std::string(s));
681 freeXMLString(s);
682 return tree;
683 }
684 void GEPChromosome::assemble(){
685 this->subtrees.clear();
686 this->cellTree = this->makeCellTree();
687 for (uint i = 0; i < this->genes; i++){
688 Tree::Tree *subtree = this->toTree(i);
689 this->subtrees.push_back(subtree);
690 }
691 }
692
693 void GEPChromosome::execute(void *result)
694 {
695 // Obtain the cell tree structure
696 //Tree::Tree *tree = this->cellTree();
697 // Translate and execute all the gene subtrees
698 // TODO: detect which genes are actually used so as to not evaluate unneeded ones
699 double tmp = 0;
700 for (uint i = 0; i < this->genes; i++){
701 Tree::Tree *subtree = this->subtrees.at(i);
702 subtree->execute(&tmp);
703 // Set the terminal values according to the subtrees
704 this->cellTree->setTerminalValue(GEP_GENE_PREFIX + uint2str(i), &tmp);
705 }
706 // Finally, translate the cell tree and store the result
707 this->cellTree->execute(result);
708 }
709
716 void GEPChromosome::setTerminalValue(std::string name, void* value)
717 {
718 Tree::PrimitiveP term = primitiveSet_->getTerminalByName(name);
719 if (term == Tree::PrimitiveP()) {
720 ECF_LOG_ERROR(state_, "GEPChromosome genotype: invalid terminal name referenced in setTerminalValue()!");
721 throw("");
722 }
723
724 term->setValue(value);
725 }
726}
727
GEPChromosome genotype: gene crx operator. Selects a gene number and swaps it between both parents.
GEPChromosome genotype: one point crx operator. Selects a crossing point from which to exchange genet...
GEPChromosome genotype: two point crx operator. Selects two crossing points between which to exchange...
GEPChromosome class - implements genotype as a Gene Expression Programming chromosome.
uint genes
number of genes
void read(XMLNode &xGEPChromosomeInd)
Read genotype data from XMLNode.
bool initialize(StateP state)
Initialize a genotype object (read parameters, perform sanity check, build data).
bool usesERC
whether or not the chromosome uses random constants
std::vector< CrossoverOpP > getCrossoverOp()
Create and return a vector of crossover operators.
void write(XMLNode &xGEPChromosome)
Write genotype data to XMLNode.
uint tailLength
length of the tail. Automatically calculated.
GEPChromosome * copy()
Create an identical copy of the genotype object.
uint linkTailLength
length of the linking function gene's tail
uint geneLength
total length of each gene
void setTerminalValue(std::string name, void *value)
Set a terminal's value.
uint linkHeadLength
length of the linking function gene's head
uint dcLength
length of the constant values domain
uint headLength
length of the head. User-specified
void registerParameters(StateP state)
Register genotype's parameters (called before Genotype::initialize).
std::vector< MutationOpP > getMutationOp()
Create and return a vector of mutation operators.
bool addFunction(Tree::PrimitiveP func)
Add user defined function primitive. Must be called prior to initialization (no impact otherwise).
bool staticLink
whether we are using a static linking function or if it should be allowed to evolve
GEPChromosome genotype: standard normal distribution noise mutation operator. Applicable only on ephe...
GEPChromosome genotype: node replacement mutation operator. Tries to replace the selected primitive w...
voidP getParameterValue(StateP state, std::string name)
Read single parameter value from Registry.
Definition Genotype.cpp:10
bool registerParameter(StateP state, std::string name, voidP value, enum ECF::type T, std::string description="")
Register a single parameter.
Definition Genotype.cpp:4
std::string name_
genotype's name
Definition Genotype.h:109
uint genotypeId_
this genotype's unique index in individual structure
Definition Genotype.h:110
Node base class (Tree genotype).
Definition Node.h:20
void setPrimitive(PrimitiveP primitive)
Set the primitive this node points to (when creating a new tree node). In case of an ephemereal rando...
Definition Node.cpp:46
Primitive set class: collects all Tree Primitives.
Tree class - implements genotype as a tree.
Definition Tree_c.h:29
void write(XMLNode &)
Write genotype data to XMLNode.
Definition Tree.cpp:535
void update()
Calculate depth and subtree sizes of each node in the tree.
Definition Tree.cpp:435
void execute(void *)
Execute current tree.
Definition Tree.cpp:362