ECF 1.7
Cartesian.cpp
1#include <cctype>
2#include <map>
3#include <vector>
4#include "Cartesian.h"
5
6// crossover operators
7#include "CartesianCrxOnePoint.h"
8#include "CartesianCrxHalfUniform.h"
9#include "CartesianCrxUniform.h"
10
11// mutation operators
12#include "CartesianMutOnePoint.h"
13#include "CartesianMutNonSilent.h"
14#include "CartesianMutOnePointActive.h"
15
16
17namespace Cartesian {
18
19
20Cartesian::Cartesian(void)
21{
22 name_ = "Cartesian";
23 functionSet_ = (FunctionSetP)(new FunctionSet);
24}
25
26
27Cartesian::~Cartesian(void)
28{}
29
30
31Cartesian* Cartesian::copy()
32{
33 Cartesian *newObject = new Cartesian(*this);
34 return newObject;
35}
36
37
38std::vector<CrossoverOpP> Cartesian::getCrossoverOp()
39{
40 std::vector<CrossoverOpP> crxOps;
41 crxOps.push_back((CrossoverOpP) (new CartesianCrxOnePoint)); // ok
42 crxOps.push_back((CrossoverOpP) (new CartesianCrxHalfUniform)); // ok
43 crxOps.push_back((CrossoverOpP) (new CartesianCrxUniform)); // ok
44 return crxOps;
45}
46
47
48std::vector<MutationOpP> Cartesian::getMutationOp()
49{
50 std::vector<MutationOpP> mutOps;
51 mutOps.push_back((MutationOpP) (new CartesianMutOnePoint));
52 mutOps.push_back((MutationOpP) (new CartesianMutNonSilent));
53 mutOps.push_back((MutationOpP) (new CartesianMutOnePointActive));
54 return mutOps;
55}
56
57
59{
60 registerParameter(state, "numoutputs", (voidP) (new uint(1)), ECF::UINT, "number of functional outputs (default: 1)");
61 registerParameter(state, "numrows", (voidP) (new uint(1)), ECF::UINT, "number of rows (default: 1)");
62 registerParameter(state, "numcols", (voidP) (new uint(10)), ECF::UINT, "number of columns (default: 10)");
63 registerParameter(state, "levelsback", (voidP) (new uint(2)), ECF::UINT, "number of previous columns to be used as possible inputs (default: 2)");
64 registerParameter(state, "numvariables", (voidP) (new uint(1)), ECF::UINT, "number of input variables (default: 1)");
65 registerParameter(state, "functionset", (voidP) (new std::string), ECF::STRING, "set of functions to use (mandatory)");
66 registerParameter(state, "constantset", (voidP)(new std::string), ECF::STRING, "set of input constants (default: none)");
67}
68
69
70bool Cartesian::initialize(StateP state)
71{
72 state_ = state;
73 std::stringstream ss;
74 std::string names,name;
75 voidP sptr;
76
77 sptr = getParameterValue(state, "functionset");
78 names = *((std::string*)sptr.get());
79
80 if (!isParameterDefined(state, "functionset")) {
81 ECF_LOG_ERROR(state, "Cartesian initialization error: required parameters for CGP genotype not defined (functionset)!");
82 return false;
83 }
84
85 // create and initialize the function set
86 //functionSet_ = FunctionSetP (new FunctionSet); // TODO: vratiti ako se FunctionSet prebaci u State
87 functionSet_->initialize(state_);
88
89 uint number;
90 // Simple parameters
91 sptr = getParameterValue(state, "numvariables");
92 number = *((uint*) sptr.get());
93 if(number <= 0) {
94 ECF_LOG_ERROR(state, "Cartesian initialization error: Number of variables is smaller than 1 or cannot be parsed into a number.");
95 return false;
96 }
97 nVariables_ = number;
98
99 sptr = getParameterValue(state,"numoutputs");
100 number = *((uint*) sptr.get());
101 if(number <= 0) {
102 ECF_LOG_ERROR(state, "Cartesian initialization error: Number of outputs is smaller than 1 or cannot be parsed into a number.");
103 return false;
104 }
105 nOutputs_ = number;
106
107 sptr = getParameterValue(state,"numrows");
108 number = *((uint*) sptr.get());
109 if(number <= 0) {
110 ECF_LOG_ERROR(state, "Cartesian initialization error: Number of rows is smaller than 1 or cannot be parsed into a number.");
111 return false;
112 }
113 nRows_ = number;
114
115 sptr = getParameterValue(state,"numcols");
116 number = *((uint*) sptr.get());
117 if(number <= 0) {
118 ECF_LOG_ERROR(state, "Cartesian initialization error: Number of columns is smaller than 1 or cannot be parsed into a number.");
119 return false;
120 }
121 nCols_ = number;
122
123 sptr = getParameterValue(state,"levelsback");
124 number = *((uint*) sptr.get());
125 if(number <= 0) {
126 ECF_LOG_ERROR(state, "Cartesian initialization error: Number of columns is smaller than 1 or cannot be parsed into a number.");
127 return false;
128 }
129 nLevelsBack_ = number;
130
131 nConstants_ = 0;
132 constants_.clear();
133 sptr = getParameterValue(state,"constantset");
134 if (sptr) {
135 names = *((std::string*)sptr.get());
136 ss.str("");
137 ss.clear();
138 ss << names;
139 while (ss >> name) {
140 std::istringstream token(name);
141 double value;
142 if (token >> value) {
143 constants_.push_back(value);
144 }
145 }
146 nConstants_ = (uint) constants_.size();
147 }
149
150 // Functionset parameters
151 sptr = getParameterValue(state, "functionset");
152 names = *((std::string*) sptr.get());
153 ss.str("");
154 ss.clear();
155 ss << names;
156 name="";
157
158 nFunctions_ = 0;
159 while(ss >> name) {
160 if (functionSet_->addFunction(name))
161 nFunctions_++;
162 else {
163 ECF_LOG_ERROR(state, "Cartesian initialization error: unknown function (\"" + name + "\")");
164 return false;
165 }
166 }
167 if (nFunctions_ == 0) {
168 ECF_LOG_ERROR(state, "Cartesian initialization error: no valid functions in functionset");
169 return false;
170 }
171
172 maxArity_ = 0;
173 std::map<std::string, uint>::iterator it;
174 for (it = functionSet_->mFunctionSet.begin(); it != functionSet_->mFunctionSet.end(); it++) {
175 uint nArgs = functionSet_->vFunctions[it->second]->getNumberOfArguments();
176 if (nArgs > maxArity_)
177 maxArity_ = nArgs;
178 }
179
181
182 return true;
183}
184
185
186void Cartesian::read(XMLNode &xCart)
187{
188 std::string s = xCart.getText(0);
189 std::istringstream ss(s);
190 std::string token;
191 uint iNode = nInputs_; // starting node index
192 uint iOutput = 0;
193 FunctionP func;
194 while (ss >> token)
195 {
196 if (token[0] != '(') { // output connections
197 outputs_[iOutput++] = stoi(token);
198 continue;
199 }
200
201 token.erase(0, 1); // erase opening (
202 std::map <std::string, unsigned int>::iterator it = functionSet_->mFunctionSet.find(token);
203 if (it == functionSet_->mFunctionSet.end()) {
204 ECF_LOG_ERROR(state_, "Cartesian genotype: unused function (" + token + ")!");
205 throw std::runtime_error("Cartesian genotype: unused function (" + token + ")!");
206 }
207
208 nodes_[iNode].setPrimitive(functionSet_->vFunctions[it->second]);
209
210 uint nArgs = functionSet_->vFunctions[it->second]->getNumberOfArguments();
211 nodes_[iNode].arguments_.resize(nArgs);
212
213 for (uint arg = 0; arg < nArgs; arg++) {
214 ss >> token;
215 nodes_[iNode].arguments_[arg] = stoi(token);
216 }
217
218 iNode++;
219 }
220}
221
222
223void Cartesian::write(XMLNode &xCart)
224{
225 xCart = XMLNode::createXMLTopNode("Cartesian");
226 std::stringstream sValue;
227 sValue << getGenomeSize();
228 xCart.addAttribute("size", sValue.str().c_str());
229
230 sValue.str("");
231
232 // output all nodes
233 for (uint iNode = nInputs_; iNode < nodes_.size(); iNode++) {
234 sValue << "(" << nodes_[iNode].primitive_->getName() << " ";
235 uint nArgs = (uint) nodes_[iNode].arguments_.size();
236 for (uint i = 0; i < nArgs; i++) {
237 sValue << nodes_[iNode].arguments_[i];
238 if (i < nArgs - 1)
239 sValue << " ";
240 }
241 sValue << ") ";
242 }
243 for (uint i = 0; i < outputs_.size(); i++)
244 sValue << outputs_[i] << " ";
245
246 xCart.addText(sValue.str().c_str());
247}
248
249
251{
252 return nRows_ * nCols_ + nOutputs_;
253}
254
255
257{
258 // allocate for input nodes
259 nodes_.resize(nInputs_);
260
261 for (uint iCol = 0; iCol < nCols_; iCol++) {
262 for(uint j = 0; j < nRows_; j++) {
263
264 Node newNode;
265
266 // select a function
267 int functionID = state_->getRandomizer()->getRandomInteger(nFunctions_);
268 newNode.setPrimitive(functionSet_->vFunctions[functionID]);
269
270 // select arguments
271 FunctionP function = functionSet_->vFunctions[functionID];
272 for (uint k = 0; k < function->getNumberOfArguments(); k++) {
273 uint iArgument = randomNodeInputConnection(iCol);
274 newNode.arguments_.push_back(iArgument);
275 }
276 nodes_.push_back(newNode);
277 }
278 }
279
280 // select outputs (among all function nodes)
281 outputs_.resize(nOutputs_);
282 for(uint i = 0; i < nOutputs_; i++) {
284 }
285}
286
287
289{
290 // First node index in this column
291 uint firstNodeInColumn = nInputs_ + column * nRows_;
292
293 // First column that is allowed
294 uint firstAllowedColumn = (column > nLevelsBack_) ? column - nLevelsBack_ : 0;
295
296 uint firstAllowedNode = nInputs_ + firstAllowedColumn * nRows_;
297
298 uint nPreviousFunctionNodes = firstNodeInColumn - firstAllowedNode;
299
300 uint nCandidates = nInputs_ + nPreviousFunctionNodes;
301
302 uint id = state_->getRandomizer()->getRandomInteger(nCandidates);
303
304 // primary inputs
305 if (id < nInputs_)
306 return id;
307
308 // allowed function nodes
309 return firstAllowedNode + (id - nInputs_);
310}
311
312
314{
315 return (uint) state_->getRandomizer()->getRandomInteger(nInputs_, (uint) nodes_.size() - 1);
316}
317
318
319void Cartesian::evaluate(std::vector<double>& inputData, std::vector<double>& results)
320{
321 if (inputData.size() != nVariables_) {
322 throw std::runtime_error("Cartesian error: inputData vector size not equal to number of input variables.");
323 }
324
325 std::vector<double> node_values(inputData);
326 // add constants to values vector
327 node_values.insert(node_values.end(), constants_.begin(), constants_.end());
328
329 std::vector<double> operands(this->maxArity_);
330 double result = 0;
331 // calculate
332 for (uint i = nInputs_; i < nodes_.size(); i++) {
333 int numberOfArguments = nodes_[i].primitive_->getNumberOfArguments();
334 for(int k = 0; k < numberOfArguments; k++) {
335 operands[k] = node_values[nodes_[i].arguments_[k]];
336 }
337 nodes_[i].primitive_->evaluate(operands, result);
338 node_values.push_back(result);
339 }
340 results.resize(nOutputs_);
341 int ir = 0;
342 for (uint i = 0; i < outputs_.size(); i++) {
343 results[i] = node_values[outputs_[i]];
344 }
345}
346
347
348void Cartesian::getActiveFunctionNodes(std::vector<uint>& activeNodes)
349{
350 const uint size = (uint) nodes_.size();
351 std::vector<bool> activeFlags(size, false);
352
353 // for all output nodes, recursively add their argument nodes
354 for (const uint i : outputs_)
355 if (i >= nInputs_) {
356 activeFlags[i] = true;
357 addRecursivelyActiveFunctionNodes(activeFlags, i);
358 }
359
360 activeNodes.clear();
361 for (uint i = nInputs_; i < activeFlags.size(); i++)
362 if(activeFlags[i])
363 activeNodes.push_back(i);
364}
365
366
367void Cartesian::addRecursivelyActiveFunctionNodes(std::vector<bool>& activeFlags, uint node)
368{
369 for (uint iArg = 0; iArg < nodes_[node].primitive_->getNumberOfArguments(); iArg++) {
370 uint iActive = nodes_[node].arguments_[iArg];
371
372 if (iActive >= nInputs_ && activeFlags[iActive] == false) {
373 activeFlags[iActive] = true;
374 addRecursivelyActiveFunctionNodes(activeFlags, iActive);
375 }
376 }
377}
378
379
380}
Cartesian genotype: half uniform crossover operator.
Cartesian genotype: one point crossover operator.
Cartesian genotype: uniform crossover operator.
uint nVariables_
number of input variables
void read(XMLNode &xCart)
StateP state_
local copy of state
uint nRows_
number of rows
uint nFunctions_
number of used functions
Cartesian * copy()
Definition Cartesian.cpp:31
uint nInputs_
total number of inputs (variables and constants)
uint nCols_
number of columns
void evaluate(std::vector< double > &inputData, std::vector< double > &results)
uint randomNodeInputConnection(uint column)
std::vector< MutationOpP > getMutationOp()
Definition Cartesian.cpp:48
FunctionSetP functionSet_
pointer to function set
std::vector< double > constants_
input nodes with constant values
void getActiveFunctionNodes(std::vector< uint > &)
uint maxArity_
max number of inputs for all function nodes
uint nLevelsBack_
levels back parameter
void registerParameters(StateP state)
Definition Cartesian.cpp:58
bool initialize(StateP state)
Definition Cartesian.cpp:70
uint nConstants_
number of input constants
std::vector< CrossoverOpP > getCrossoverOp()
Definition Cartesian.cpp:38
std::vector< uint > outputs_
output nodes
void write(XMLNode &xCart)
uint nOutputs_
number of final outputs
std::vector< Node > nodes_
genotype nodes (input nodes and function nodes)
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
bool isParameterDefined(StateP state, std::string name)
Check if parameter is defined in the configuration.
Definition Genotype.cpp:22