- Timestamp:
- 06/06/18 01:45:18 (7 years ago)
- Location:
- cpp/frams/genetics
- Files:
-
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
cpp/frams/genetics/fB/fB_conv.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include "fB_conv.h" 2 6 … … 89 93 continue; 90 94 } 91 fH_Handle *handle = convertCharacterToHandle(gene[2], dims, start, end, ranges); 95 int hclasspos = 2; 96 if (gene[2] == '"') 97 { 98 hclasspos--; 99 if (!getNextCharId(gene, hclasspos)) 100 { 101 return ""; 102 } 103 } 104 fH_Handle *handle = convertCharacterToHandle(gene[hclasspos], dims, start, end, ranges); 92 105 ParamEntry *tab = creature.getParamTab(handle->type); 93 106 void *obj = ParamObject::makeObject(tab); … … 97 110 98 111 int propindex = 0; 99 int z = 3; 112 int z = hclasspos; 113 if (gene[z] == '"') 114 { 115 z--; 116 if (!getNextCharId(gene, z)) 117 { 118 delete handle; 119 ParamObject::freeObject(obj); 120 return ""; 121 } 122 } 100 123 endoffset = 0; 101 124 if (gene.indexOf("zz", 0) != -1) endoffset = 2; 125 int nclassdefcount = 1; 102 126 while (z < gene.len() - endoffset) 103 127 { 104 if (processNextLetter(creature, handle, par, gene, propindex, z, ranges) == -1) 105 { 106 logMessage("GenoConv_fBH", "convert", LOG_WARN, "Property of fH could not be parsed"); 107 } 128 if (processNextLetter(creature, handle, par, gene, propindex, z, ranges, nclassdefcount) == -1) 129 { 130 logMessage("GenoConv_fBH", "convert", LOG_ERROR, "Property of fH could not be parsed"); 131 delete handle; 132 ParamObject::freeObject(obj); 133 return ""; 134 } 135 } 136 if (handle->type == fHBodyType::NEURON && propindex < par.getPropCount()) 137 { 138 SString nclass; 139 if (!getNeuroClass(gene, nclass, nclassdefcount)) 140 { 141 delete handle; 142 ParamObject::freeObject(obj); 143 return ""; 144 } 145 par.setStringById(FH_PE_NEURO_DET, nclass); 108 146 } 109 147 handle->loadProperties(par); … … 132 170 } 133 171 134 int GenoConv_fBH::processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3]) 172 bool GenoConv_fBH::getNextCharId(SString genotype, int &i) 173 { 174 i++; 175 if (genotype[i] == '"') 176 { 177 int nextid = i + 1; 178 do 179 { 180 nextid = genotype.indexOf('"', nextid); 181 if (nextid == -1) 182 { 183 return false; 184 } 185 nextid++; 186 } 187 while (genotype[nextid] == '"'); 188 i = nextid; 189 } 190 return true; 191 } 192 193 bool GenoConv_fBH::getNeuroClass(SString gene, SString &def, int nclassdefcount) 194 { 195 SString lastdef = "N"; 196 int nclass = 0; 197 int pos = 0; 198 while (nclass < nclassdefcount) 199 { 200 pos = gene.indexOf('\"', pos); 201 if (pos == -1) 202 { 203 def = lastdef; 204 return true; 205 } 206 pos++; 207 SString currdef; 208 if (gene.indexOf('\"', pos) == -1 || !gene.getNextToken(pos, currdef, '\"')) 209 { 210 def = lastdef; 211 return false; 212 } 213 lastdef = currdef; 214 nclass++; 215 } 216 def = lastdef; 217 return true; 218 } 219 220 int GenoConv_fBH::processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3], int &nclassdefcount) 135 221 { 136 222 if (propindex >= par.getPropCount()) … … 147 233 par.setDefault(); 148 234 propindex = 0; 149 i++; 235 if (!getNextCharId(gene, i)) 236 return -1; 150 237 return 0; 151 238 } … … 166 253 } 167 254 propindex++; 168 i++; 255 if (!getNextCharId(gene, i)) 256 return -1; 169 257 return 0; 170 258 } 171 259 else if (currhandle->type == fHBodyType::NEURON && *par.id(propindex) == 'd') 172 260 { 173 //TODO: handle neuron classes and properties 261 //When 'd' property appears for i-th element in gene, the method 262 //looks for i-th neuron definition 263 SString nclass; 264 if (!getNeuroClass(gene, nclass, nclassdefcount)) return -1; 265 par.setString(propindex, nclass); 174 266 propindex++; 175 i++; 267 nclassdefcount++; 268 if (!getNextCharId(gene, i)) 269 return -1; 176 270 return 0; 177 271 } -
cpp/frams/genetics/fB/fB_conv.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FB_CONV_H_ 2 6 #define _FB_CONV_H_ … … 8 12 { 9 13 private: 14 bool getNextCharId(SString genotype, int &i); 10 15 double convertCharacterTo01(char c); 11 16 double convertCharacterToWeight(char c); 12 17 static fH_Handle* convertCharacterToHandle(char c, int dims, int start, int end, std::vector<IRange> ranges[3]); 13 int processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3]); 18 int processNextLetter(fH_Builder &creature, fH_Handle *&currhandle, Param &par, SString gene, int &propindex, int &i, std::vector<IRange> ranges[3], int &nclassdefcount); 19 bool getNeuroClass(SString gene, SString &def, int nclassdefcount); 14 20 15 21 public: -
cpp/frams/genetics/fB/fB_general.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FB_GENERAL_H_ 2 6 #define _FB_GENERAL_H_ … … 10 14 { 11 15 int start = 0; 16 int prev = 0; 12 17 int count = -1; 13 18 do { 14 19 count++; 15 20 start = geno.indexOf("aa", start) + 1; // +1 is for progress, starting codons can overlap 21 int quotecount = 0; 22 for (int q = prev; q < start; q++) if (geno[q] == '\"') quotecount++; 23 prev = start; 24 if (quotecount % 2 != 0) count--; // 'aa' sequence is within quotes 16 25 } while (start - 1 != -1); 17 26 return count; … … 25 34 count++; 26 35 start = genotype.indexOf("aa", start) + 1; 36 int quotecount = 0; 37 for (int q = 0; q < start; q++) if (genotype[q] == '\"') quotecount++; 38 if (quotecount % 2 != 0) count--; // 'aa' sequence is within quotes 27 39 } while (start - 1 != -1 && count != i); 28 40 if (start - 1 == -1) // there is no gene with a given "i" … … 33 45 } 34 46 end = start; 35 end = genotype.indexOf("zz", end); 47 int quotecount = 0; 48 do { 49 quotecount = 0; 50 end = genotype.indexOf("zz", end); 51 if (end != -1) 52 { 53 for (int q = start; q < end; q++) if (genotype[q] == '\"') quotecount++; 54 if (quotecount % 2 != 0) end++; 55 } 56 } while (quotecount % 2 != 0 && end != -1); 57 36 58 if (end == -1) end = genotype.len(); 37 59 else end += 2; -
cpp/frams/genetics/fB/fB_oper.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include <frams/util/sstring.h> 2 6 #include <vector> … … 5 9 #include "fB_general.h" 6 10 #include "fB_oper.h" 11 #include "../fH/fH_oper.h" 7 12 8 13 #define FIELDSTRUCT Geno_fB … … 10 15 static ParamEntry GENOfBparam_tab[] = 11 16 { 12 { "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, }, // ask about it17 { "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, }, 13 18 { "Genetics: fB: Mutation", }, 14 19 { "Genetics: fB: Crossover", }, 15 20 { "fB_mut_substitution", 1, 0, "Substitution", "f 0 1 0.6", FIELD(mutationprobs[FB_SUBSTITUTION]), "Probability of mutation by changing single random letter in genotype", }, 16 { "fB_mut_insertion", 1, 0, "Insertion", "f 0 1 0.1", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", }, 21 { "fB_mut_insertion", 1, 0, "Insertion", "f 0 1 0.95", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", }, 22 { "fB_mut_nclassins", 1, 0, "Insertion of neuron class definition", "f 0 1 0.05", FIELD(mutationprobs[FB_NCLASSINS]), "Probability of mutation by inserting neuron class definition in random place of genotype", }, 17 23 { "fB_mut_deletion", 1, 0, "Deletion", "f 0 1 0.1", FIELD(mutationprobs[FB_DELETION]), "Probability of mutation by deleting random characters in genotype", }, 18 24 { "fB_mut_duplication", 1, 0, "Duplication", "f 0 1 0.05", FIELD(mutationprobs[FB_DUPLICATION]), "Probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype", }, … … 81 87 if (!islower(genotype[i])) 82 88 { 83 return i + 1; 89 if (genotype[i] == '"') 90 { 91 SString neuclassdef; 92 int nextid = i + 1; 93 if (!genotype.getNextToken(nextid, neuclassdef, '"')) 94 { 95 return i + 1; 96 } 97 Neuro *neu = new Neuro(); 98 neu->setDetails(neuclassdef); 99 100 bool isclass = neu->getClass() ? true : false; 101 delete neu; 102 if (!isclass) 103 { 104 return i + 1; 105 } 106 i = nextid; 107 } 108 else 109 { 110 return i + 1; 111 } 84 112 } 85 113 } … … 121 149 if (!isalpha(genotype[i])) 122 150 { 123 return GENOPER_OPFAIL; 151 if (genotype[i] == '"') 152 { 153 SString neuclassdef; 154 int nextid = i + 1; 155 if (!genotype.getNextToken(nextid, neuclassdef, '"')) 156 { 157 return i + 1; 158 } 159 Neuro *neu = new Neuro(); 160 neu->setDetails(neuclassdef); 161 162 bool isclass = neu->getClass() ? true : false; 163 delete neu; 164 if (!isclass) 165 { 166 return i + 1; 167 } 168 i = nextid; 169 } 170 else 171 { 172 return GENOPER_OPFAIL; 173 } 124 174 } 125 175 // if character is uppercase, then convert it to lowercase 126 if (isupper(genotype[i]))176 else if (isupper(genotype[i])) 127 177 { 128 178 genotype.directWrite()[i] = tolower(genotype[i]); … … 142 192 } 143 193 return GENOPER_OK; 194 } 195 196 SString Geno_fB::detokenizeSequence(std::list<SString> tokenlist) 197 { 198 SString res = ""; 199 for (std::list<SString>::iterator it = tokenlist.begin(); it != tokenlist.end(); it++) 200 { 201 res += (*it); 202 } 203 return res; 204 } 205 206 std::list<SString> Geno_fB::tokenizeSequence(SString genotype) 207 { 208 std::list<SString> res; 209 int i = 0; 210 while (i < genotype.len()) 211 { 212 // if character is not alphabetic - error 213 if (isalpha(genotype[i])) 214 { 215 SString el = ""; 216 el += genotype[i]; 217 res.push_back(el); 218 i++; 219 } 220 else 221 { 222 SString neuclassdef; 223 i++; 224 genotype.getNextToken(i, neuclassdef, '"'); 225 SString ndef = "\""; 226 ndef += neuclassdef; 227 ndef += "\""; 228 res.push_back(ndef); 229 } 230 } 231 return res; 144 232 } 145 233 … … 157 245 case FB_SUBSTITUTION: 158 246 { 159 int rndid = randomN(line.len()); // select random letter from genotype 247 std::list<SString> tokenized = tokenizeSequence(line); 248 int rndid = randomN(tokenized.size()); // select random letter from genotype 160 249 // increment/decrement character - when overflow happens, this method 161 250 // uses reflect method 162 if (randomN(2) == 0) 163 { 164 if (line[rndid] == 'a') line.directWrite()[rndid] = 'b'; 165 else line.directWrite()[rndid] = line[rndid] - 1; 251 std::list<SString>::iterator it = tokenized.begin(); 252 std::advance(it, rndid); 253 SString t = (*it); 254 if ((*it).len() == 1) 255 { 256 if (randomN(2) == 0) 257 { 258 if ((*it)[0] == 'a') (*it).directWrite()[0] = 'b'; 259 else (*it).directWrite()[0] = (*it)[0] - 1; 260 } 261 else 262 { 263 if ((*it)[0] == 'z') (*it).directWrite()[0] = 'y'; 264 else (*it).directWrite()[0] = (*it)[0] + 1; 265 } 266 chg = 1.0 / line.len(); 166 267 } 167 268 else 168 269 { 169 if (line[rndid] == 'z') line.directWrite()[rndid] = 'y'; 170 else line.directWrite()[rndid] = line[rndid] + 1; 171 } 270 // first method needs to extract quotes 271 SString def = (*it); 272 def = def.substr(1, def.len() - 2); 273 Geno_fH::mutateNeuronProperties(def); 274 SString res = "\""; 275 res += def; 276 res += "\""; 277 (*it) = res; 278 chg = (double)def.len() / line.len(); 279 } 280 line = detokenizeSequence(tokenized); 281 break; 282 } 283 case FB_INSERTION: 284 { 172 285 chg = 1.0 / line.len(); 173 break; 174 } 175 case FB_INSERTION: 286 std::list<SString> tokenized = tokenizeSequence(line); 287 int rndid = randomN(tokenized.size()); // select random insertion point 288 std::list<SString>::iterator it = tokenized.begin(); 289 std::advance(it, rndid); 290 SString letter = "a"; 291 letter.directWrite()[0] = 'a' + randomN(26); 292 tokenized.insert(it, letter); 293 line = detokenizeSequence(tokenized); 294 break; 295 } 296 case FB_NCLASSINS: 297 { 298 std::list<SString> tokenized = tokenizeSequence(line); 299 std::list<SString>::iterator it = tokenized.begin(); 300 int rndid = randomN(tokenized.size()); // select random insertion point 301 std::advance(it, rndid); 302 NeuroClass *cls = getRandomNeuroClass(); 303 SString classdef = cls->getName(); 304 Geno_fH::mutateNeuronProperties(classdef); 305 SString res = "\""; 306 res += classdef; 307 res += "\""; 308 tokenized.insert(it, res); 309 chg = (double)classdef.len() / line.len(); 310 line = detokenizeSequence(tokenized); 311 break; 312 } 313 case FB_DELETION: 176 314 { 177 315 chg = 1.0 / line.len(); 178 int rndid = randomN(genotype.len()); // select random insertion point 179 char letter = 'a' + randomN(26); 180 SString result = line.substr(0, rndid); 181 result += letter; 182 result += line.substr(rndid); 183 line = result; 184 break; 185 } 186 case FB_DELETION: 187 { 188 chg = 1.0 / line.len(); 189 int rndid = randomN(line.len()); // select random insertion point 190 if (rndid == line.len() - 1) 191 { 192 line = line.substr(0, line.len() - 1); 193 } 194 else 195 { 196 line = line.substr(0, rndid) + line.substr(rndid + 1); 197 } 316 std::list<SString> tokenized = tokenizeSequence(line); 317 std::list<SString>::iterator it = tokenized.begin(); 318 int rndid = randomN(tokenized.size()); // select random deletion point 319 std::advance(it, rndid); 320 tokenized.erase(it); 321 line = detokenizeSequence(tokenized); 198 322 break; 199 323 } … … 210 334 case FB_TRANSLOCATION: 211 335 { 212 std::vector<int> cuts(4); 336 std::list<SString> tokenized = tokenizeSequence(line); 337 std::vector<unsigned int> cuts(4); 213 338 for (int i = 0; i < 4; i++) 214 339 { 215 cuts[i] = randomN( line.len());340 cuts[i] = randomN(tokenized.size()); 216 341 } 217 342 std::sort(cuts.begin(), cuts.end()); 218 SString first = line.substr(cuts[0], cuts[1] - cuts[0]); 219 SString second = line.substr(cuts[2], cuts[3] - cuts[2]); 220 SString result = line.substr(0, cuts[0]) + second + 221 line.substr(cuts[1], cuts[2] - cuts[1]) + first + line.substr(cuts[3]); 222 line = result; 343 std::vector<std::list<SString>::iterator> iters(4); 344 for (int i = 0; i < 4; i++) 345 { 346 iters[i] = tokenized.begin(); 347 std::advance(iters[i], cuts[i]); 348 } 349 350 std::list<SString> res; 351 res.insert(res.end(), tokenized.begin(), iters[0]); 352 res.insert(res.end(), iters[2], iters[3]); 353 res.insert(res.end(), iters[1], iters[2]); 354 res.insert(res.end(), iters[0], iters[1]); 355 res.insert(res.end(), iters[3], tokenized.end()); 356 357 // SString first = line.substr(cuts[0], cuts[1] - cuts[0]); 358 // SString second = line.substr(cuts[2], cuts[3] - cuts[2]); 359 // SString result = line.substr(0, cuts[0]) + second + 360 // line.substr(cuts[1], cuts[2] - cuts[1]) + first + line.substr(cuts[3]); 361 line = detokenizeSequence(res); 223 362 chg = (float)(cuts[3] - cuts[2] + cuts[1] - cuts[0]) / line.len(); 224 363 break; -
cpp/frams/genetics/fB/fB_oper.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FB_OPER_H_ 2 6 #define _FB_OPER_H_ 3 7 4 8 #include "../genooperators.h" 9 #include <list> 5 10 6 11 /** @name Codes for general fB mutation types */ … … 8 13 #define FB_SUBSTITUTION 0 ///<Relative probability of mutation by changing single random letter in genotype (substitution) 9 14 #define FB_INSERTION 1 ///<Relative probability of mutation by inserting characters in random place of genotype 10 #define FB_DELETION 2 ///<Relative probability of mutation by deleting random characters in genotype 11 #define FB_DUPLICATION 3 ///<Relative probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype 12 #define FB_TRANSLOCATION 4 ///<Relative probability of mutation by replacing two substrings in genotype 13 #define FB_MUT_COUNT 5 ///<Count of mutation types 15 #define FB_NCLASSINS 2 ///<Relative probability of mutation by inserting neuron class definition in random place of genotype 16 #define FB_DELETION 3 ///<Relative probability of mutation by deleting random characters in genotype 17 #define FB_DUPLICATION 4 ///<Relative probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype 18 #define FB_TRANSLOCATION 5 ///<Relative probability of mutation by replacing two substrings in genotype 19 #define FB_MUT_COUNT 6 ///<Count of mutation types 14 20 //@} 15 21 … … 25 31 private: 26 32 bool hasStick(SString genotype); 33 SString detokenizeSequence(std::list<SString> tokenlist); 34 std::list<SString> tokenizeSequence(SString genotype); 27 35 28 36 public: -
cpp/frams/genetics/fH/fH_conv.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include "fH_conv.h" 2 6 -
cpp/frams/genetics/fH/fH_conv.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FH_CONV_H_ 2 6 #define _FH_CONV_H_ -
cpp/frams/genetics/fH/fH_general.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include <string> 2 6 #include <limits> … … 13 17 // Methods for loading handles 14 18 15 const char *fH_part_names[ PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };16 17 const char *fH_joint_names[ JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };19 const char *fH_part_names[FH_PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" }; 20 21 const char *fH_joint_names[FH_JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" }; 18 22 19 23 void fH_Handle::loadProperties(Param par) … … 106 110 107 111 Part p; 108 for (int i = 0; i < PART_PROPS_COUNT; i++)112 for (int i = 0; i < FH_PART_PROPS_COUNT; i++) 109 113 { 110 114 stickmut.addProperty(&p.properties().getParamTab()[p.properties().findId(fH_part_names[i]) + p.properties().getGroupCount()], -1); … … 112 116 113 117 Joint j; 114 for (int i = 0; i < JOINT_PROPS_COUNT; i++)118 for (int i = 0; i < FH_JOINT_PROPS_COUNT; i++) 115 119 { 116 120 stickmut.addProperty(&j.properties().getParamTab()[j.properties().findId(fH_joint_names[i]) + j.properties().getGroupCount()], -1); … … 119 123 120 124 Neuro n; 121 neuronmut.addProperty(&n.properties().getParamTab()[n.properties().findId( PE_NEURO_DET) + n.properties().getGroupCount()], -1);125 neuronmut.addProperty(&n.properties().getParamTab()[n.properties().findId(FH_PE_NEURO_DET) + n.properties().getGroupCount()], -1); 122 126 123 127 Param tmp(f0_neuroconn_paramtab, NULL); 124 connectionmut.addProperty(&tmp.getParamTab()[tmp.findId( PE_CONN_WEIGHT) + tmp.getGroupCount()], -1);128 connectionmut.addProperty(&tmp.getParamTab()[tmp.findId(FH_PE_CONN_WEIGHT) + tmp.getGroupCount()], -1); 125 129 126 130 stickparamtab = ParamObject::makeParamTab((ParamInterface *)&stickmut, 0, 0, stickmut.firstMutableIndex()); … … 343 347 { 344 348 Param par(tab, obj); 345 double partprops[ PART_PROPS_COUNT];346 for (int i = 0; i < PART_PROPS_COUNT; i++)349 double partprops[FH_PART_PROPS_COUNT]; 350 for (int i = 0; i < FH_PART_PROPS_COUNT; i++) 347 351 { 348 352 partprops[i] = par.getDouble(2 * getDimensions() + i); … … 357 361 { 358 362 par.select(child->obj); 359 for (int i = 0; i < PART_PROPS_COUNT; i++)363 for (int i = 0; i < FH_PART_PROPS_COUNT; i++) 360 364 { 361 365 partprops[i] += par.getDouble(2 * getDimensions() + i); … … 364 368 } 365 369 366 for (int i = 0; i < PART_PROPS_COUNT; i++)370 for (int i = 0; i < FH_PART_PROPS_COUNT; i++) 367 371 { 368 372 partprops[i] /= stickscount; … … 522 526 msg += det + "\" does not exist"; 523 527 logMessage("fH_Builder", "developBrain", LOG_ERROR, msg.c_str()); 528 delete currneu->neuron; 524 529 return -1; 525 530 } … … 601 606 if (!beginneu) 602 607 { 603 logMessage("fH_Builder", "developBrain", LOG_WARN, "There are no available neurons with outputs, connection could not be established"); 608 // due to often appearance of connection genes in fB encoding, this 609 // log message is commented 610 // logMessage("fH_Builder", "developBrain", LOG_DEBUG, "There are no available neurons with outputs, connection could not be established"); 604 611 continue; 605 612 } … … 628 635 if (!endneu) 629 636 { 630 logMessage("fH_Builder", "developBrain", LOG_WARN, "There are no available neurons with free inputs, connection could not be established"); 637 // due to often appearance of connection genes in fB encoding, this 638 // log message is commented 639 // logMessage("fH_Builder", "developBrain", LOG_DEBUG, "There are no available neurons with free inputs, connection could not be established"); 631 640 continue; 632 641 } -
cpp/frams/genetics/fH/fH_general.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FH_GENERAL_H_ 2 6 #define _FH_GENERAL_H_ … … 14 18 #define HANDLE_VECTOR_TYPE "f -1.0 1.0 0.0" ///<Vector values type definition 15 19 #define STICKH_LENGTH_TYPE "f 0.001 1.999 1.0" ///<Length of stick handle. Minimum should not be equal to 0, because calculating direction of next part from current stick with length 0 would be impossible 16 #define PART_PROPS_COUNT 4 ///<Count of part properties17 #define JOINT_PROPS_COUNT 3 ///<Count of joint properties18 #define PE_NEURO_DET "d" ///<Id of details type definition in f0_neuro_paramtab19 #define PE_CONN_WEIGHT "w" ///<Id of weight type definition in f0_neuroconn_paramtab20 #define FH_PART_PROPS_COUNT 4 ///<Count of part properties 21 #define FH_JOINT_PROPS_COUNT 3 ///<Count of joint properties 22 #define FH_PE_NEURO_DET "d" ///<Id of details type definition in f0_neuro_paramtab 23 #define FH_PE_CONN_WEIGHT "w" ///<Id of weight type definition in f0_neuroconn_paramtab 20 24 //@} 21 25 -
cpp/frams/genetics/fH/fH_oper.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include "fH_oper.h" 2 6 … … 421 425 } 422 426 423 void Geno_fH::mutateNeuron HandleProperties(fH_NeuronHandle *handle, ParamEntry *tab, bool userandomclass)427 void Geno_fH::mutateNeuronProperties(SString &det) 424 428 { 425 429 Neuro neu; 426 Param hpar(tab, handle->obj); 427 SString det = hpar.getStringById("d"); 430 det = det == "" ? "N" : det; 428 431 neu.setDetails(det == "" ? "N" : det); 429 NeuroClass *nc = neu.getClass();430 431 if (userandomclass)432 {433 nc = getRandomNeuroClass();434 if (!nc) nc = Neuro::getClass("N");435 }436 437 det = nc->getName();438 neu.setDetails(det);439 432 440 433 SyntParam par = neu.classProperties(); … … 455 448 if (props != "") 456 449 { 450 det = neu.getClass()->name; 457 451 det += ": "; 458 452 det += props; 459 hpar.setStringById("d", det); 460 } 461 } 462 } 463 464 uint32_t Geno_fH::style(const char *geno, int pos) 465 { 466 char ch = geno[pos]; 467 uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT); 468 if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character handle type and all colons 469 { 470 style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD); 471 } 472 else if (isalpha(ch)) // properties name 473 { 474 style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD); 475 } 476 else if (isdigit(ch) || strchr(",.=", ch)) // properties values 477 { 478 style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE); 479 } 480 else if (ch == '\"') 481 { 482 style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD); 483 } 484 485 return style; 486 } 453 } 454 } 455 } 456 457 void Geno_fH::mutateNeuronHandleProperties(fH_NeuronHandle *handle, ParamEntry *tab, bool userandomclass) 458 { 459 Neuro neu; 460 Param hpar(tab, handle->obj); 461 SString det = hpar.getStringById("d"); 462 neu.setDetails(det == "" ? "N" : det); 463 NeuroClass *nc = neu.getClass(); 464 465 if (userandomclass) 466 { 467 nc = getRandomNeuroClass(); 468 if (!nc) nc = Neuro::getClass("N"); 469 } 470 471 det = nc->getName(); 472 473 mutateNeuronProperties(det); 474 475 hpar.setStringById("d", det); 476 } 477 478 //uint32_t Geno_fH::style(const char *geno, int pos) 479 //{ 480 // char ch = geno[pos]; 481 // uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT); 482 // if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character handle type and all colons 483 // { 484 // style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD); 485 // } 486 // else if (isalpha(ch)) // properties name 487 // { 488 // style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD); 489 // } 490 // else if (isdigit(ch) || strchr(",.=", ch)) // properties values 491 // { 492 // style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE); 493 // } 494 // else if (ch == '\"') 495 // { 496 // style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD); 497 // } 498 // 499 // return style; 500 //} 501 502 uint32_t Geno_fH::style(const char *g, int pos) 503 { 504 char ch=g[pos]; 505 uint32_t style=GENSTYLE_CS(0,GENSTYLE_NONE); //default, should be changed below 506 507 int pp=pos; //detect comment line 508 while (pp>1 && g[pp-1]!='\n') pp--; 509 if (g[pp]=='#') return GENSTYLE_RGBS(0,220,0,GENSTYLE_NONE); //comment line 510 511 if (pos==0 || g[pos-1]=='\n' || ch==':' || ch==',') style=GENSTYLE_CS(0,GENSTYLE_BOLD); else 512 if (ch=='\"') style=GENSTYLE_RGBS(150,0,0,GENSTYLE_BOLD); else 513 { 514 int cudz=0,neuclass=1; //ile cudz. do poczatku linii; czy w nazwie neuroklasy? 515 while (pos>0) 516 { 517 pos--; 518 if (g[pos]=='\"') cudz++; 519 if (cudz==0 && (g[pos]==':' || g[pos]==',')) neuclass=0; 520 if (g[pos]=='\n') break; 521 } 522 if (cudz%2) 523 { 524 if (neuclass) style=GENSTYLE_RGBS(150,0,150,GENSTYLE_BOLD); else //neuroclass 525 if (isalpha(ch)) style=GENSTYLE_RGBS(255,140,0,GENSTYLE_BOLD); else //property 526 style=GENSTYLE_RGBS(200,0,0,GENSTYLE_NONE); 527 } else 528 if (isalpha(ch)) style=GENSTYLE_RGBS(0,0,200,GENSTYLE_BOLD); 529 } 530 return style; 531 } -
cpp/frams/genetics/fH/fH_oper.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FH_OPER_H_ 2 6 #define _FH_OPER_H_ … … 87 91 double addoperations[FH_ADD_OPCOUNT]; ///<relative probabilities of selecting mutation addition subtypes 88 92 93 // TODO add to GenoOperators? 94 /** 95 * Mutates properties of neuron and returns full neuron class description. 96 * @param det current neuron class definition with its parameters 97 */ 98 static void mutateNeuronProperties(SString &det); 99 89 100 Geno_fH(); 90 101 -
cpp/frams/genetics/fL/fL_conv.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include "fL_conv.h" 6 #include "fL_general.h" 2 7 3 8 SString GenoConv_fL0::convert(SString &i, MultiMap *map, bool using_checkpoints) 4 9 { 5 return ""; 10 fL_Builder builder(NULL != map, using_checkpoints); 11 if (builder.parseGenotype(i) != 0) return ""; 12 double neededtime; 13 Model *m = builder.developModel(neededtime); 14 if (!m) return SString(); 15 if (NULL != map) 16 m->getCurrentToF0Map(*map); 17 SString gen = m->getF0Geno().getGenes(); 18 delete m; 19 return gen; 6 20 } -
cpp/frams/genetics/fL/fL_conv.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FL_CONV_ 2 6 #define _FL_CONV_ -
cpp/frams/genetics/fL/fL_general.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include <algorithm> 2 6 #include <stack> 3 7 #include "fL_general.h" 4 5 const char *fL_part_names[PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" }; 6 const char *fL_part_fullnames[PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" }; 7 8 const char *fL_joint_names[JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" }; 9 const char *fL_joint_fullnames[JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" }; 8 #include <frams/util/multirange.h> 9 #include <iterator> 10 11 const char *fL_part_names[FL_PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" }; 12 const char *fL_part_fullnames[FL_PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" }; 13 14 const char *fL_joint_names[FL_JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" }; 15 const char *fL_joint_fullnames[FL_JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" }; 10 16 11 17 #define FIELDSTRUCT fL_Word … … 14 20 { "Word", 1, 2, "w" }, 15 21 { "name", 0, PARAM_CANOMITNAME, "word name", "s", FIELD(name), }, 16 { "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 30", FIELD(npar), },22 { "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 " FL_MAXPARAMS " 0", FIELD(npar), }, 17 23 { 0, 0, 0, } 18 24 }; … … 23 29 { 24 30 { "Rule", 1, 3, "r" }, 25 { "pred", 0, PARAM_CANOMITNAME, "predecessor", "s", FIELD(predecessor), },26 { "cond", 0, PARAM_CANOMITNAME, "parameter condition", "s", FIELD(condition), },27 { "succ", 0, PARAM_CANOMITNAME, "successor", "s", FIELD(successor), },31 { "pred", 0, 0, "predecessor", "s", FIELD(predecessor), }, 32 { "cond", 0, 0, "parameter condition", "s", FIELD(condition), }, 33 { "succ", 0, 0, "successor", "s", FIELD(successor), }, 28 34 { 0, 0, 0, } 29 35 }; … … 33 39 ParamEntry fL_builder_paramtab[] = 34 40 { 35 { "LSystemInfo", 1, 3, "i" }, 36 { "axiom", 0, PARAM_CANOMITNAME, "starting sequence of L-System", "s", FIELD(axiom), }, 37 { "time", 0, PARAM_CANOMITNAME, "development time", "f 1.0 100.0 1.0", FIELD(time), }, 38 { "numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp), }, 39 { 0, 0, 0, } 41 {"LSystemInfo", 1, 4, "i"}, 42 {"axiom", 0, 0, "starting sequence of L-System", "s", FIELD(axiom),}, 43 {"time", 0, PARAM_CANOMITNAME, "development time", "f 0.0 " FL_MAXITER " 1.0", FIELD(time),}, 44 {"numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp),}, 45 {"maxwords", 0, PARAM_CANOMITNAME, "Maximum number of words within genotype sequence", "d -1 9999 -1", FIELD(maxwords),}, 46 {0,0,0,} 40 47 }; 41 48 #undef FIELDSTRUCT … … 134 141 } 135 142 136 int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams) 143 int fL_Builder::createWord(SString token, fL_Word *&word, int numparams, int begin, int end) 144 { 145 SString wordn; 146 int tokpos = 0; 147 // if word name cannot be extracted, then return error 148 if (!token.getNextToken(tokpos, wordn, '(')) 149 { 150 return 1; 151 } 152 std::string wordname = fL_Builder::trimSpaces(wordn.c_str()); 153 // if word cannot be found in available words, then return error 154 if (words.find(wordname) == words.end()) 155 { 156 SString message = "Word '"; 157 message += wordname.c_str(); 158 message += "' in sequence does not exist"; 159 logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str()); 160 return 1; 161 } 162 163 if (word) delete word; 164 // create new word and assign parameters 165 word = new fL_Word(false, begin, end); 166 167 *word = *words[wordname]; 168 169 SString temp; 170 temp = token.substr(tokpos); 171 temp = temp.substr(0, temp.len() - 1); 172 173 // if word has parameters 174 if (word->npar > 0) 175 { 176 // create ParamObject that will hold parameter data 177 word->data = ParamObject::makeObject(word->tab); 178 Param par(word->tab); 179 par.select(word->data); 180 par.setDefault(); 181 ParamInterface::LoadOptions opts; 182 183 // load parameters from string 184 par.load(ParamInterface::FormatSingleLine, temp, &opts); 185 for (int i = 0; i < par.getPropCount(); i++) 186 { 187 SString t(par.id(i)); 188 if (word->builtin && (t == SString("d") || t == SString(FL_PE_CONN_ATTR))) 189 { 190 word->parevals.push_back(NULL); 191 } 192 else 193 { 194 // create MathEvaluation object to check if string contained by 195 // parameter is valid 196 double tmp; 197 MathEvaluation *eval = NULL; 198 SString seq = par.getString(i); 199 // if string is empty, then evaluate this with 0 200 // if sequence could not be evaluated, then return error 201 if (seq.len() > 0) 202 { 203 eval = new MathEvaluation(numparams); 204 if (eval->evaluate(seq.c_str(), tmp) != 0) 205 { 206 SString message = "Word in sequence has invalid parameter: "; 207 message += temp; 208 logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str()); 209 delete eval; 210 delete word; 211 word = NULL; 212 return 1; 213 } 214 } 215 word->parevals.push_back(eval); 216 } 217 } 218 } 219 else if (word->npar == 0 && temp.len() > 0) 220 { 221 SString message = "Too many parameters for word: "; 222 message += token; 223 logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str()); 224 delete word; 225 word = NULL; 226 return 1; 227 } 228 return 0; 229 } 230 231 int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams, int begin, int end) 137 232 { 138 233 int pos = 0; … … 153 248 if (token.indexOf("[", 0) != -1) 154 249 { 155 fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN );250 fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN, begin, end); 156 251 result.push_back(word); 157 252 branchcount++; … … 168 263 return 1; 169 264 } 170 fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE );265 fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE, begin, end); 171 266 result.push_back(word); 172 267 branchcount--; 173 268 continue; 174 269 } 175 SString wordn; 176 int tokpos = 0; 177 // if word name cannot be extracted, then return error 178 if (!token.getNextToken(tokpos, wordn, '(')) 270 fL_Word *word = NULL; 271 if (createWord(token, word, numparams, begin, end) != 0) 179 272 { 180 273 SString message = "Error during parsing words sequence: "; … … 183 276 return 1; 184 277 } 185 std::string wordname = fL_Builder::trimSpaces(wordn.c_str()); 186 // if word cannot be found in available words, then return error 187 if (words.find(wordname) == words.end()) 188 { 189 SString message = "Word '"; 190 message += wordname.c_str(); 191 message += "' in sequence does not exist"; 192 logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str()); 193 return 1; 194 } 195 196 // create new word and assign parameters 197 fL_Word *word = new fL_Word(); 198 199 *word = *words[wordname]; 200 201 // if word has parameters 202 if (word->npar > 0) 203 { 204 // create ParamObject that will hold parameter data 205 word->data = ParamObject::makeObject(word->tab); 206 Param par(word->tab); 207 par.select(word->data); 208 par.setDefault(); 209 ParamInterface::LoadOptions opts; 210 211 SString temp; 212 temp = token.substr(tokpos); 213 temp = temp.substr(0, temp.len() - 1); 214 // load parameters from string 215 par.load(ParamInterface::FormatSingleLine, temp, &opts); 216 for (int i = 0; i < par.getPropCount(); i++) 217 { 218 // create MathEvaluation object to check if string contained by 219 // parameter is valid 220 double tmp; 221 MathEvaluation *eval = new MathEvaluation(numparams); 222 SString seq = par.getString(i); 223 // if string is empty, then evaluate this with 0 224 if (seq.len() == 0) 225 { 226 eval->evaluate("0", tmp); 227 } 228 // if sequence could not be evaluated, then return error 229 else if (eval->evaluate(seq.c_str(), tmp) != 0) 230 { 231 SString message = "Word in sequence has invalid parameter: "; 232 message += temp; 278 if (word->name == "C") 279 { 280 Param par(word->tab, word->data); 281 SString attr = par.getStringById(FL_PE_CONN_ATTR); 282 if (attr.indexOf("$t", 0) != -1) 283 { 284 logMessage("fL_Builder", "tokenize", LOG_ERROR, "Attractor definition cannot contain time variable"); 285 delete word; 286 return 1; 287 288 } 289 if (attr != "") 290 { 291 fL_Word *attrword = NULL; 292 if (createWord(attr, attrword, numparams, begin, end) != 0) 293 { 294 SString message = "Error during parsing attractor word: "; 295 message += attr; 233 296 logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str()); 234 delete eval;235 297 delete word; 298 if (attrword) delete attrword; 236 299 return 1; 237 300 } 238 word->parevals.push_back(eval); 301 if (attrword->builtin) 302 { 303 logMessage("fL_Builder", "tokenize", LOG_ERROR, "Attractor words cannot be built-in"); 304 delete word; 305 delete attrword; 306 return 1; 307 } 308 delete attrword; 239 309 } 240 310 } … … 272 342 parevals = src.parevals; 273 343 344 builtin = src.builtin; 345 274 346 data = NULL; // properties cannot be copied 275 347 } … … 303 375 304 376 builder->words[this->name.c_str()] = this; 377 builder->wordnames.push_back(this->name.c_str()); 305 378 return 0; 306 379 } … … 318 391 *objpred = *builder->words[predecessor.c_str()]; 319 392 393 if (objpred->builtin) 394 { 395 logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Builtin words cannot be predecessors"); 396 return 1; 397 } 398 320 399 // parse condition 321 400 if (condition != "") 322 401 { 402 if (objpred->builtin && (objpred->name == "N" || objpred->name == "C")) 403 { 404 logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Rules with neuron/connection word predecessors cannot contain conditions"); 405 return 1; 406 } 323 407 std::string cond = condition.c_str(); 324 408 condeval = new MathEvaluation(objpred->npar); … … 340 424 } 341 425 342 if (builder->tokenize(successor, objsucc, objpred->npar ) != 0)426 if (builder->tokenize(successor, objsucc, objpred->npar, begin, end) != 0) 343 427 { 344 428 logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Unable to process successor sequence"); … … 353 437 { 354 438 // tokenize axiom 355 if (tokenize(axiom, genotype, 0 ) != 0)439 if (tokenize(axiom, genotype, 0, begin, end) != 0) 356 440 { 357 441 logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Unable to process axiom sequence"); … … 372 456 switch (type) 373 457 { 374 case fLElementType::TERM:375 {376 tab = fL_word_paramtab;377 obj = new fL_Word();378 break;379 }380 case fLElementType::INFO:381 {382 tab = fL_builder_paramtab;383 obj = this;384 break;385 }386 case fLElementType::RULE:387 {388 tab = fL_rule_paramtab;389 obj = new fL_Rule(begin, end);390 break;391 }392 default:393 break;458 case fLElementType::TERM: 459 { 460 tab = fL_word_paramtab; 461 obj = new fL_Word(); 462 break; 463 } 464 case fLElementType::INFO: 465 { 466 tab = fL_builder_paramtab; 467 obj = this; 468 break; 469 } 470 case fLElementType::RULE: 471 { 472 tab = fL_rule_paramtab; 473 obj = new fL_Rule(begin, end); 474 break; 475 } 476 default: 477 break; 394 478 } 395 479 Param par(tab); … … 417 501 stick->name = "S"; 418 502 stick->npar = 8; 419 for (int i = 0; i < PART_PROPS_COUNT; i++)503 for (int i = 0; i < FL_PART_PROPS_COUNT; i++) 420 504 { 421 505 stick->mut.addProperty(NULL, fL_part_names[i], "s", fL_part_fullnames[i], fL_part_fullnames[i], PARAM_CANOMITNAME, 0, -1); 422 506 } 423 507 424 for (int i = 0; i < JOINT_PROPS_COUNT; i++)508 for (int i = 0; i < FL_JOINT_PROPS_COUNT; i++) 425 509 { 426 510 stick->mut.addProperty(NULL, fL_joint_names[i], "s", fL_joint_fullnames[i], fL_joint_fullnames[i], PARAM_CANOMITNAME, 0, -1); … … 430 514 stick->tab = ParamObject::makeParamTab((ParamInterface *)&stick->mut, 0, 0, stick->mut.firstMutableIndex()); 431 515 words["S"] = stick; 516 wordnames.push_back("S"); 432 517 433 518 // neuron N … … 435 520 neuron->name = "N"; 436 521 neuron->npar = 1; 437 neuron->mut.addProperty(NULL, "d", "s", "details", "details", PARAM_CANOMITNAME, 0, -1);522 neuron->mut.addProperty(NULL, "d", "s", "details", "details", 0, 0, -1); 438 523 neuron->tab = ParamObject::makeParamTab((ParamInterface *)&neuron->mut, 0, 0, neuron->mut.firstMutableIndex()); 439 524 words["N"] = neuron; 525 wordnames.push_back("N"); 440 526 441 527 // connection C … … 443 529 connection->name = "C"; 444 530 connection->npar = 2; 445 connection->mut.addProperty(NULL, "w", "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1);446 connection->mut.addProperty(NULL, "attr", "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1);531 connection->mut.addProperty(NULL, FL_PE_CONN_WEIGHT, "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1); 532 connection->mut.addProperty(NULL, FL_PE_CONN_ATTR, "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1); 447 533 connection->tab = ParamObject::makeParamTab((ParamInterface *)&connection->mut, 0, 0, connection->mut.firstMutableIndex()); 448 534 words["C"] = connection; 535 wordnames.push_back("C"); 449 536 450 537 // rotation objects … … 463 550 rotz->npar = 1; 464 551 rotz->processDefinition(this); 552 553 //fL_Branch *branch = new fL_Branch(fL_Branch::BranchType::OPEN, 0, 0); 554 //branch->processDefinition(this); 555 556 builtincount = words.size(); 465 557 } 466 558 … … 521 613 return res; 522 614 } 615 if (obj == this) 616 { 617 begin = lastpos; 618 end = pos - 1; 619 } 523 620 res = obj->processDefinition(this); 524 621 if (res != 0) … … 546 643 for (int i = 0; i < npar; i++) 547 644 { 645 SString t(par.id(i)); 548 646 if (parevals[i] != NULL) 549 647 { … … 667 765 } 668 766 getStringifiedProducts(); 767 removeRedundantRules(); 669 768 Param par(fL_builder_paramtab); 670 769 fL_Builder *obj = new fL_Builder(); … … 681 780 } 682 781 683 int fL_Rule::deploy(fL_ Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime)782 int fL_Rule::deploy(fL_Builder *builder, fL_Word *in, std::list<fL_Word *>::iterator &it, double currtime) 684 783 { 685 784 // if predecessor and given word differ, then rule is not applicable … … 720 819 721 820 // remove predecessor word from genotype and replace it with successor 722 it = genotype.erase(it);821 it = builder->genotype.erase(it); 723 822 for (std::list<fL_Word *>::iterator word = objsucc.begin(); word != objsucc.end(); word++) 724 823 { 725 824 // create new word and copy properties from word definition 726 fL_Word *nword = new fL_Word( );825 fL_Word *nword = new fL_Word(false, begin, end); 727 826 *nword = **word; 728 827 // store information about when word has been created … … 735 834 // calculate word parameters and store MathEvaluation objects for further 736 835 // time manipulations. 836 Param par((*word)->tab, (*word)->data); 837 Param npar(nword->tab, nword->data); 737 838 for (int q = 0; q < nword->npar; q++) 738 839 { 739 840 if ((*word)->parevals[q] == NULL) 740 841 { 741 MathEvaluation *ev = new MathEvaluation(0); 742 ev->convertString("0"); 743 nword->parevals.push_back(ev); 842 if ((*word)->builtin && (strcmp(npar.id(q), "d") == 0)) 843 { 844 SString t = par.getString(q); 845 npar.setString(q, t); 846 nword->parevals.push_back(NULL); 847 } 848 if ((*word)->builtin && (strcmp(npar.id(q), FL_PE_CONN_ATTR) == 0)) 849 { 850 SString t = par.getString(q); 851 if (t.len() > 0) 852 { 853 fL_Word *attrword = NULL; 854 builder->createWord(t, attrword, in->npar, begin, end); 855 for (int j = 0; j < attrword->npar; j++) 856 { 857 if (attrword->parevals[j]) 858 { 859 for (int i = 0; i < in->npar; i++) 860 { 861 attrword->parevals[j]->modifyVariable(i, inwordvalues[i]); 862 } 863 } 864 } 865 SString res = attrword->stringify(false); 866 npar.setString(q, res); 867 nword->parevals.push_back(NULL); 868 delete attrword; 869 } 870 } 871 else 872 { 873 //MathEvaluation *ev = new MathEvaluation(0); 874 //ev->convertString("0"); 875 //nword->parevals.push_back(ev); 876 nword->parevals.push_back(NULL); 877 } 744 878 } 745 879 else … … 757 891 } 758 892 } 759 genotype.insert(it, nword);893 builder->genotype.insert(it, nword); 760 894 } 761 895 delete[] inwordvalues; … … 773 907 for (fL_Rule * rule : rules) 774 908 { 775 if (rule->deploy( (*word), word, genotype, currtime) == 0)909 if (rule->deploy(this, (*word), word, currtime) == 0) 776 910 { 777 911 deployed = true; … … 806 940 Param par(stickword->tab, stickword->data); 807 941 Param ppar = part->properties(); 808 for (int i = 0; i < PART_PROPS_COUNT; i++) 809 { 810 double partprop; 942 for (int i = 0; i < FL_PART_PROPS_COUNT; i++) 943 { 944 double mn, mx, df; 945 ppar.getMinMaxDouble(ppar.findId(fL_part_names[i]), mn, mx, df); 811 946 double currval; 812 if (!ExtValue::parseDouble(par.getStringById(fL_part_names[i]).c_str(), currval, false)) 813 { 814 logMessage("fL_Builder", "alterPartProperties", LOG_ERROR, 815 "Error parsing word parameter"); 816 return 1; 817 } 818 partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount + 819 currval) / (alterationcount + 1.0); 947 if (!stickword->parevals[i]) 948 { 949 currval = df; 950 } 951 else 952 { 953 stickword->parevals[i]->evaluateRPN(currval); 954 currval = sigmoidTransform(currval, mn, mx); 955 } 956 double partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount + 957 currval) / (alterationcount + 1.0); 820 958 ppar.setDoubleById(fL_part_names[i], partprop); 821 959 } … … 823 961 } 824 962 825 bool fL_Word::operator==(const fL_Word& other) const 826 { 827 if (name == other.name) return false; 828 if (npar == other.npar) return false; 963 double fL_Word::distance(fL_Word *right) 964 { 965 if (name != right->name || npar != right->npar) 966 { 967 return -1; 968 } 969 double distance = 0; 829 970 for (int i = 0; i < npar; i++) 830 971 { 831 if (parevals[i] && other.parevals[i]) 832 { 833 double first; 834 double second; 835 parevals[i]->evaluateRPN(first); 836 other.parevals[i]->evaluateRPN(second); 837 if (first != second) 838 { 839 return false; 840 } 841 } 842 else 843 { 844 return false; 845 } 846 } 847 return true; 848 } 849 850 void fL_Builder::findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it) 851 { 852 int rightdist = 0; 853 std::list<fL_Word *>::iterator iter(it); 854 for (; iter != genotype.end(); iter++) 855 { 856 if (*word == **iter) 857 { 858 break; 859 } 860 rightdist++; 861 } 862 int leftdist = 0; 863 std::list<fL_Word *>::reverse_iterator riter(it); 864 for (; riter != genotype.rend(); riter++) 865 { 866 if (*word == **riter) 867 { 868 break; 869 } 870 leftdist++; 871 } 872 if (iter == genotype.end()) 873 { 874 it = riter.base(); 875 } 876 else if (riter == genotype.rend()) 877 { 878 it = iter; 879 } 880 else if (leftdist < rightdist) 881 { 882 it = riter.base(); 972 double l = 0; 973 double r = 0; 974 if (parevals[i]) parevals[i]->evaluateRPN(l); 975 if (right->parevals[i]) right->parevals[i]->evaluateRPN(r); 976 distance += (l - r) * (l - r); 977 } 978 return sqrt(distance); 979 } 980 981 Neuro *fL_Builder::findInputNeuron(std::pair<std::list<fL_Word *>::iterator, Neuro *> currneu, fL_Word *attractor) 982 { 983 if (!attractor) 984 { 985 std::list<fL_Word *>::reverse_iterator riter(currneu.first); 986 std::list<fL_Word *>::iterator iter(currneu.first); 987 iter++; 988 while (riter != genotype.rend() || iter != genotype.end()) 989 { 990 if (iter != genotype.end()) 991 { 992 if ((*iter)->name == "N" && (*iter)->bodyelementpointer != currneu.second) 993 { 994 return (Neuro *)(*iter)->bodyelementpointer; 995 } 996 iter++; 997 } 998 if (riter != genotype.rend()) 999 { 1000 if ((*riter)->name == "N" && (*riter)->bodyelementpointer != currneu.second) 1001 { 1002 return (Neuro *)(*riter)->bodyelementpointer; 1003 } 1004 riter++; 1005 } 1006 } 1007 return NULL; 883 1008 } 884 1009 else 885 1010 { 886 it = iter; 887 } 888 } 889 890 Neuro *fL_Builder::findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor) 891 { 892 if (!attractor) 893 { 894 attractor = new fL_Word(); 895 *attractor = *(*it); 896 attractor->data = NULL; 897 // TODO implement 1011 double mindistance = -1; 1012 std::list<fL_Word *>::iterator minit = genotype.end(); 1013 for (std::list<fL_Word *>::iterator it = genotype.begin(); it != genotype.end(); it++) 1014 { 1015 double currdist = attractor->distance((*it)); 1016 if (currdist != -1 && (currdist < mindistance || mindistance == -1)) 1017 { 1018 mindistance = currdist; 1019 minit = it; 1020 } 1021 } 1022 if (minit != genotype.end()) 1023 { 1024 for (; minit != genotype.end(); minit++) 1025 { 1026 if ((*minit)->name == "N" && (*minit)->bodyelementpointer) 1027 { 1028 Neuro *n = (Neuro *)(*minit)->bodyelementpointer; 1029 if (n->getClass()->getPreferredOutput() != 0) 1030 { 1031 return n; 1032 } 1033 } 1034 } 1035 } 898 1036 } 899 1037 return NULL; 900 1038 } 901 1039 902 int fL_Builder::developModel(Model &model) 903 { 904 // TODO implement 1040 double fL_Builder::sigmoidTransform(double input, double mn, double mx) 1041 { 1042 return mn + (mx - mn) * (1.0 / (1.0 + exp(-input))); 1043 } 1044 1045 int fL_Builder::buildModelFromSequence(Model *model) 1046 { 905 1047 fL_State currstate; 906 1048 std::unordered_map<Part *, double> counters; … … 923 1065 firstpart->p = Pt3D_0; 924 1066 counters[firstpart] = 0; 925 model.addPart(firstpart); 1067 model->addPart(firstpart); 1068 if (using_mapping) firstpart->addMapping(IRange(word->begin, word->end)); 926 1069 } 927 1070 currstate.currpart = firstpart; … … 941 1084 Param par(word->tab, word->data); 942 1085 double length; 943 if (!ExtValue::parseDouble(par.getStringById("l").c_str(), length, false)) 944 { 945 delete newpart; 946 logMessage("fL_Builder", "alterPartProperties", LOG_ERROR, 947 "Error parsing word parameter"); 948 return 1; 1086 if (!word->parevals[FL_PART_PROPS_COUNT + FL_JOINT_PROPS_COUNT]) 1087 { 1088 length = FL_DEFAULT_LENGTH; // default length value 1089 } 1090 else 1091 { 1092 double parsedval = 0.0; 1093 if (word->parevals[FL_PART_PROPS_COUNT + FL_JOINT_PROPS_COUNT]->evaluateRPN(parsedval) != 0) 1094 { 1095 delete newpart; 1096 logMessage("fL_Builder", "developModel", LOG_ERROR, 1097 "Error parsing word parameter"); 1098 return 1; 1099 } 1100 length = sigmoidTransform(parsedval, FL_MINIMAL_LENGTH, FL_MAXIMAL_LENGTH); 949 1101 } 950 1102 newpart->p = currstate.currpart->p + currstate.direction * length; 951 1103 counters[newpart] += 1; 952 model .addPart(newpart);953 1104 model->addPart(newpart); 1105 if (using_mapping) newpart->addMapping(IRange(word->begin, word->end)); 954 1106 Joint *newjoint = new Joint(); 955 1107 newjoint->attachToParts(currstate.currpart, newpart); 956 1108 957 1109 Param jpar = newjoint->properties(); 958 for (int i = 0; i < JOINT_PROPS_COUNT; i++) 959 { 1110 for (int i = 0; i < FL_JOINT_PROPS_COUNT; i++) 1111 { 1112 double mn, mx, df; 1113 jpar.getMinMaxDouble(jpar.findId(fL_joint_names[i]), mn, mx, df); 960 1114 double jointprop; 961 if (! ExtValue::parseDouble(par.getStringById(fL_joint_names[i]).c_str(), jointprop, false))1115 if (!word->parevals[FL_PART_PROPS_COUNT + i]) 962 1116 { 963 logMessage("fL_Builder", "developModel", LOG_ERROR, 964 "Error parsing word parameter"); 965 delete newjoint; 966 return 1; 1117 jointprop = df; // assign default value 1118 } 1119 else 1120 { 1121 if (word->parevals[FL_PART_PROPS_COUNT + i]->evaluateRPN(jointprop) != 0) 1122 { 1123 logMessage("fL_Builder", "developModel", LOG_ERROR, 1124 "Error parsing word parameter"); 1125 delete newjoint; 1126 return 1; 1127 } 1128 jointprop = sigmoidTransform(jointprop, mn, mx); 967 1129 } 968 1130 jpar.setDoubleById(fL_joint_names[i], jointprop); 969 1131 } 970 model.addJoint(newjoint); 1132 model->addJoint(newjoint); 1133 if (using_mapping) newjoint->addMapping(IRange(word->begin, word->end)); 971 1134 currstate.currpart = newpart; 972 1135 } … … 975 1138 Param npar(word->tab, word->data); 976 1139 Neuro *neu = new Neuro(); 977 neu->setDetails(npar.getStringById("d")); 1140 SString details = npar.getStringById("d"); 1141 if (details == "") 1142 { 1143 details = "N"; 1144 } 1145 neu->setDetails(details); 978 1146 if (!neu->getClass()) 979 1147 { … … 982 1150 return 1; 983 1151 } 984 model.addNeuro(neu); 985 currstate.currneuron = neu; 1152 model->addNeuro(neu); 1153 if (using_mapping) neu->addMapping(IRange(word->begin, word->end)); 1154 if (neu->getClass()->getPreferredInputs() != 0) 1155 { 1156 currstate.currneuron = neu; 1157 } 1158 word->bodyelementpointer = neu; 986 1159 } 987 1160 else if (word->name == "C") 988 1161 { 989 connsbuffer.push_back({ w, currstate.currneuron});1162 connsbuffer.push_back({w, currstate.currneuron}); 990 1163 } 991 1164 else if (word->name.startsWith("rot")) 992 1165 { 993 Orient rotmatrix ;1166 Orient rotmatrix = Orient_1; 994 1167 double rot; 995 if (word->parevals[0]->evaluateRPN(rot) != 0) 996 { 997 logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class"); 1168 if (!word->parevals[0]) 1169 { 1170 rot = 0; 1171 } 1172 else if (word->parevals[0]->evaluateRPN(rot) != 0) 1173 { 1174 logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing rotation word"); 998 1175 return 1; 999 1176 } 1177 1178 rot = sigmoidTransform(rot, -M_PI, M_PI); 1179 1000 1180 if (word->name == "rotX") 1001 1181 { 1002 rotmatrix.rotate(Pt3D(rot, 0.0, 0.0));1182 rotmatrix.rotate(Pt3D(rot,0,0)); 1003 1183 } 1004 1184 else if (word->name == "rotY") 1005 1185 { 1006 rotmatrix.rotate(Pt3D(0 .0, rot, 0.0));1186 rotmatrix.rotate(Pt3D(0,rot,0)); 1007 1187 } 1008 1188 else if (word->name == "rotZ") 1009 1189 { 1010 rotmatrix.rotate(Pt3D(0 .0, 0.0,rot));1190 rotmatrix.rotate(Pt3D(0,0,rot)); 1011 1191 } 1012 1192 currstate.direction = rotmatrix.transform(currstate.direction); 1193 currstate.direction.normalize(); 1013 1194 } 1014 1195 else if (word->name == "[") … … 1025 1206 1026 1207 // connections need 1027 // for (std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer) 1028 // { 1029 // 1030 // } 1208 // std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer 1209 for (unsigned int i = 0; i < connsbuffer.size(); i++) 1210 { 1211 if (connsbuffer[i].second == NULL || 1212 (connsbuffer[i].second->getClass()->getPreferredInputs() != -1 && 1213 connsbuffer[i].second->getInputCount() >= 1214 connsbuffer[i].second->getClass()->getPreferredInputs())) 1215 { 1216 // since connections are separated entities from neurons, it may happen 1217 // that there will be no neuron to connect to 1218 // logMessage("fL_Builder", "developModel", LOG_DEBUG, "Connection could not be established"); 1219 } 1220 else 1221 { 1222 Param par((*connsbuffer[i].first)->tab, (*connsbuffer[i].first)->data); 1223 SString attr = par.getStringById(FL_PE_CONN_ATTR); 1224 fL_Word *attractor = NULL; 1225 if (attr.len() > 0) 1226 { 1227 createWord(attr, attractor, 0, (*connsbuffer[i].first)->begin, (*connsbuffer[i].first)->end); 1228 } 1229 Neuro *neu = findInputNeuron(connsbuffer[i], attractor); 1230 double weight = 0.0; 1231 if ((*connsbuffer[i].first)->parevals[0]) 1232 { 1233 if ((*connsbuffer[i].first)->parevals[0]->evaluateRPN(weight) != 0) 1234 { 1235 logMessage("fL_Builder", "developModel", LOG_ERROR, 1236 "Error parsing word parameter"); 1237 delete attractor; 1238 return 1; 1239 } 1240 } 1241 if (neu) 1242 { 1243 connsbuffer[i].second->addInput(neu, weight); 1244 if (using_mapping) neu->addMapping( 1245 IRange((*connsbuffer[i].first)->begin, 1246 (*connsbuffer[i].first)->end)); 1247 } 1248 else 1249 { 1250 connsbuffer[i].second->addInput(connsbuffer[i].second, weight); 1251 if (using_mapping) neu->addMapping( 1252 IRange((*connsbuffer[i].first)->begin, 1253 (*connsbuffer[i].first)->end)); 1254 } 1255 delete attractor; 1256 } 1257 } 1031 1258 return 0; 1032 1259 } 1033 1260 1034 int fL_Builder::develop() 1035 { 1036 Model m; 1261 void fL_Builder::clearModelElements(Model *m) 1262 { 1263 for (int i = 0; i < m->getJointCount(); i++) 1264 { 1265 m->removeJoint(i, 0); 1266 } 1267 for (int i = 0; i < m->getNeuroCount(); i++) 1268 { 1269 m->removeNeuro(i, true); 1270 } 1271 for (int i = 0; i < m->getNeuroCount(); i++) 1272 { 1273 m->removePart(i, 0, 0); 1274 } 1275 m->clearMap(); 1276 } 1277 1278 Model* fL_Builder::developModel(double &neededtime) 1279 { 1037 1280 double curriter = 0; 1038 1281 double timestamp = 1.0 / numckp; 1039 1282 double t = 0; 1040 for (; t <= time; t += timestamp) 1283 Model *m = new Model(); 1284 m->open(using_checkpoints); 1285 bool wordsexceeded = false; 1286 for (; t <= time; t+= timestamp) 1041 1287 { 1042 1288 alterTimedProperties(t); // always alter timed properties in the beginning … … 1045 1291 { 1046 1292 iterate(t); 1047 curriter += 1.0; 1048 } 1049 } 1293 curriter+=1.0; 1294 } 1295 if (using_checkpoints) 1296 { 1297 clearModelElements(m); 1298 if (buildModelFromSequence(m) != 0) 1299 { 1300 delete m; 1301 return NULL; 1302 } 1303 m->checkpoint(); 1304 } 1305 if (maxwords != -1 && genotype.size() > (unsigned int)maxwords) 1306 { 1307 wordsexceeded = true; 1308 break; 1309 } 1310 } 1311 1312 if (wordsexceeded) 1313 { 1314 neededtime = t; 1315 } 1316 else 1317 { 1318 neededtime = time; 1319 } 1320 1050 1321 // if exact time of development was not reached due to floating point errors, 1051 1322 // then alter timed properties … … 1054 1325 alterTimedProperties(time); 1055 1326 } 1056 return 0; 1057 } 1327 clearModelElements(m); 1328 if (buildModelFromSequence(m) != 0) 1329 { 1330 delete m; 1331 return NULL; 1332 } 1333 if (using_checkpoints) 1334 { 1335 m->checkpoint(); 1336 } 1337 m->close(); 1338 return m; 1339 } 1340 1341 int fL_Builder::countSticksInSequence(std::list<fL_Word *> sequence) 1342 { 1343 int count = 0; 1344 for (std::list<fL_Word *>::iterator it = sequence.begin(); it != sequence.end(); it++) 1345 { 1346 if ((*it)->builtin && (*it)->name == "S") 1347 { 1348 count++; 1349 } 1350 } 1351 return count; 1352 } 1353 1354 int fL_Builder::countDefinedWords() 1355 { 1356 return words.size() - builtincount; 1357 } 1358 1359 int fL_Builder::countWordsInLSystem() 1360 { 1361 int count = genotype.size(); 1362 for (fL_Rule *rul: rules) 1363 { 1364 count += rul->objsucc.size(); 1365 } 1366 count += words.size(); 1367 return count; 1368 } 1369 1370 void fL_Builder::removeRedundantRules() 1371 { 1372 for (std::vector<fL_Rule *>::iterator it = rules.begin(); 1373 it != rules.end(); it++) 1374 { 1375 std::vector<fL_Rule *>::iterator it2 = it; 1376 it2++; 1377 while (it2 != rules.end()) 1378 { 1379 bool todelete = false; 1380 if ((*it)->objpred->name == (*it2)->objpred->name) 1381 { 1382 if ((*it)->condeval == NULL && (*it2)->condeval == NULL) 1383 { 1384 todelete = true; 1385 } 1386 else if ((*it)->condeval == NULL && (*it2)->condeval != NULL) 1387 { 1388 std::iter_swap(it, it2); 1389 } 1390 else if ((*it)->condeval != NULL && (*it2)->condeval != NULL) 1391 { 1392 if ((*it)->condeval->getStringifiedRPN() == 1393 (*it2)->condeval->getStringifiedRPN()) 1394 { 1395 todelete = true; 1396 } 1397 } 1398 } 1399 if (todelete) 1400 { 1401 delete (*it2); 1402 it2 = rules.erase(it2); 1403 } 1404 else 1405 { 1406 it2++; 1407 } 1408 } 1409 } 1410 } -
cpp/frams/genetics/fL/fL_general.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FL_GENERAL_ 2 3 6 #define _FL_GENERAL_ 4 7 … … 22 25 /** @name Constants used in fL methods */ 23 26 //@{ 24 #define PART_PROPS_COUNT 4 ///<Count of part properties 25 #define JOINT_PROPS_COUNT 3 ///<Count of joint properties 26 #define PE_NEURO_DET "d" ///<Id of details type definition in f0_neuro_paramtab 27 #define PE_CONN_WEIGHT "w" ///<Id of weight type definition in f0_neuroconn_paramtab 27 #define FL_PART_PROPS_COUNT 4 ///<Count of part properties 28 #define FL_JOINT_PROPS_COUNT 3 ///<Count of joint properties 29 #define FL_PE_NEURO_DET "d" ///<Id of details type definition in f0_neuro_paramtab 30 #define FL_PE_CONN_WEIGHT "w" ///<Id of weight type definition in f0_neuroconn_paramtab 31 #define FL_PE_CONN_ATTR "attr" ///<Id of attractor of neural connection 32 #define FL_DEFAULT_LENGTH 1.0 ///<Default length of a stick in fL encoding 33 #define FL_MINIMAL_LENGTH 0.0 ///<Minimal length of a stick in fL encoding 34 #define FL_MAXIMAL_LENGTH 2.0 ///<Maximal length of a stick in fL encoding 35 #define FL_MAXITER "100.0" ///<Maximal iteration available in fL 36 #define FL_MAXPARAMS "3" ///<Maximal number of user-parameters 28 37 //@} 29 38 30 39 extern const char *fL_part_names[]; 31 40 extern const char *fL_joint_names[]; 32 extern const char *fL_joint_fullnames[ JOINT_PROPS_COUNT];33 extern const char *fL_part_fullnames[ PART_PROPS_COUNT];41 extern const char *fL_joint_fullnames[FL_JOINT_PROPS_COUNT]; 42 extern const char *fL_part_fullnames[FL_PART_PROPS_COUNT]; 34 43 35 44 #define LSYSTEM_PARAM_TYPE "s" ///< standard type of L-System elements … … 46 55 fLElementType type; ///< type of fL_Element 47 56 48 fL_Element(fLElementType type) : type(type) {} 57 int begin; ///<beginning of the element definition in genotype 58 int end; ///<end of the element definition in genotype 59 60 61 fL_Element(fLElementType type) : type(type) { begin = end = 0; } 49 62 virtual ~fL_Element() { } 50 63 … … 78 91 void *data; ///<pointer to properties of word 79 92 bool builtin; ///<determines if word is built-in (true) or not (false). 93 PartBase *bodyelementpointer; ///<helper field for built-in words 80 94 std::vector<MathEvaluation *> parevals; ///<stores MathEvaluation objects with parameter functions 81 95 double creationiter; ///<this helper field is used during L-System iterations and determines when word was created 82 fL_Word(bool builtin = false ) :83 fL_Element(fLElementType::TERM), mut("Word", "Properties"), //TODO change Word to Term everywhere96 fL_Word(bool builtin = false, int begin = 0, int end = 0) : 97 fL_Element(fLElementType::TERM), mut("Word", "Properties"), 84 98 builtin(builtin) 85 99 { … … 89 103 data = NULL; 90 104 creationiter = 0; 105 this->begin = begin; 106 this->end = end; 107 bodyelementpointer = NULL; 91 108 } 92 109 … … 102 119 for (MathEvaluation *ev : parevals) 103 120 { 104 delete ev;121 if (ev) delete ev; 105 122 } 106 123 parevals.clear(); … … 125 142 126 143 /** 127 * TODO128 */129 bool operator==(const fL_Word& other) const;130 131 /**132 144 * Returns 'w:' line defining word in genotype. 133 145 * @return string representation of word definition … … 150 162 */ 151 163 int saveEvals(bool keepformulas); 164 165 /** 166 * Computes distance between two L-System words in genotype. Distance has sense 167 * only when two words have the same name. Otherwise, returned value equals -1. 168 * The distance is computed as Euclidean distance between words arguments. 169 * @param right the second word 170 * @return Euclidean distance between words in genotype or -1 if words have different name 171 */ 172 double distance(fL_Word *right); 152 173 }; 153 174 … … 164 185 }; 165 186 BranchType btype; ///< branch parenthesis type 166 fL_Branch(BranchType branchtype ) : fL_Word()187 fL_Branch(BranchType branchtype, int begin, int end) : fL_Word(true, begin, end) 167 188 { 168 189 type = fLElementType::BRANCH; … … 192 213 std::list<fL_Word *> objsucc; ///<objec representation of successors 193 214 194 int start; ///<beginning of the rule definition in genotype 195 int end; ///<end of the rule definition in genotype 196 197 fL_Rule(int start, int end) : fL_Element(fLElementType::RULE), 198 start(start), end(end) 215 fL_Rule(int begin, int end) : fL_Element(fLElementType::RULE) 199 216 { 200 217 predecessor = ""; … … 203 220 objpred = NULL; 204 221 condeval = NULL; 222 this->begin = begin; 223 this->end = end; 205 224 } 206 225 … … 231 250 * pointer and iterator of list and inserting successor sequence into list. 232 251 * Final iterator value points to the first word after processed word. 252 * @param builder builder containing current genotype 233 253 * @param in word that is currently processed 234 254 * @param it iterator of genotype list which determines position of current analysis 235 * @param genotype current genotype. Words on the left of genotype are processed and possibly replaced by previous rules236 255 * @param currtime value representing continuous time value for rule 237 256 * @return 0 if rule processed current word, 1 if rule is no applicable 238 257 */ 239 int deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime); 240 }; 241 258 int deploy(fL_Builder *builder, fL_Word *in, std::list<fL_Word *>::iterator &it, double currtime); 259 }; 260 261 /** 262 * Structure for holding current Turtle state. 263 */ 242 264 struct fL_State 243 265 { … … 245 267 Part *currpart; ///<Latest created part 246 268 Neuro *currneuron; ///<Latest created neuron 247 fL_State() : direction(1, 0,0), currpart(NULL), currneuron(NULL)269 fL_State() : direction(1,0,0), currpart(NULL), currneuron(NULL) 248 270 { } 249 271 }; … … 266 288 double time; ///<time of creature development 267 289 int numckp; ///<number of checkpoints per growth step - checkpoints are always created after rules deployment in integer steps, numckp determines how many checkpoints should be created within single step (to watch changes of parameters) 290 int maxwords; ///<maximum number of words that can 291 bool using_checkpoints; ///<true if checkpoints should be created, or false 292 bool using_mapping; ///<true if mappings should be created, or false 293 294 int builtincount; ///<number of built-in words 268 295 269 296 std::list<fL_Word *> genotype; ///<list of current words of genotype 270 297 std::unordered_map<std::string, fL_Word *> words; ///<map from string to words existing in L-System 298 std::vector<std::string> wordnames; 271 299 std::vector<fL_Rule *> rules; ///<rules available in system 272 300 273 fL_Builder() : fL_Element(fLElementType::INFO) 301 fL_Builder(bool using_mapping = false, bool using_checkpoints = false) : fL_Element(fLElementType::INFO), 302 using_checkpoints(using_checkpoints), using_mapping(using_mapping) 274 303 { 275 304 axiom = ""; 276 305 time = 1.0; 277 306 numckp = 1; 307 builtincount = 0; 308 maxwords = -1; 278 309 } 279 310 ~fL_Builder(); … … 337 368 338 369 /** 370 * Creates fL_Word object for a given token. 371 * @param worddef string representing single word object in sequence 372 * @param word a reference to a pointer of created word by this method 373 * @param numparams number of parameters for a given sequence (usually number of rule predecessor's arguments) 374 * @param begin the begin of word definition in genotype 375 * @param end the end of word definition in genotype 376 * @return 0 if conversion went successfully, 1 when there is a problem with parsing 377 */ 378 int createWord(SString worddef, fL_Word *&word, int numparams, int begin, int end); 379 380 /** 339 381 * Helper function that converts input sequence into list of L-System words. 340 382 * @param sequence input sequence of stringified word objects … … 343 385 * @return 0 if tokenizing finished successfully, 1 otherwise 344 386 */ 345 int tokenize(SString sequence, std::list<fL_Word *> &result, int numparams );387 int tokenize(SString sequence, std::list<fL_Word *> &result, int numparams, int begin, int end); 346 388 347 389 /** … … 363 405 /** 364 406 * Developes L-System from given genotype and builds Framsticks Model from it. 365 */ 366 int develop(); 407 * When using_checkpoints is enabled, method generates checkpoint for each 408 * step defined in timestamp. 409 * @param neededtime reference to a time value after stopping development (usually it will be equal to time specified in the time field, unless the number of allowed words will be exceeded earlier) 410 * @return final model from a fL genotype 411 */ 412 Model* developModel(double &neededtime); 367 413 368 414 /** … … 371 417 * @return 0 if developing went successfully, 1 otherwise 372 418 */ 373 int developModel(Model &model);419 int buildModelFromSequence(Model *model); 374 420 375 421 /** … … 386 432 387 433 /** 388 * TODO 434 * Alters part properties according to informations stored in stickword. 435 * Method takes current values of part's properties computed from previous 436 * calls of the alterPartProperties and computes mean according to upcoming 437 * values of properties. 438 * @param part analysed part 439 * @param stickword the L-System word that affects current part 440 * @param alterationcount the number of times of part modifications - used to compute mean of every word properties 441 * @return always 0 389 442 */ 390 443 int alterPartProperties(Part *part, fL_Word *stickword, double &alterationcount); 391 444 392 445 /** 393 * TODO 394 */ 395 Neuro *findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor); 396 397 /** 398 * TODO 399 */ 400 void findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it); 446 * Finds input neuron that is nearest to attractor or connection definition. 447 * When attractor object is given, then the word with name matching attractor and 448 * with nearest values of parameters is chosen as the point, from which input 449 * neuron is looked for. The searching goes both sides. 450 * @param currneu object storing informations about connection word iterator and current neuron 451 * @param attractor pointer to an attractor definition presented in connection word 452 * @return pointer to the input neuron, or NULL if no neuron could be found 453 */ 454 Neuro *findInputNeuron(std::pair<std::list<fL_Word *>::iterator, Neuro *> currneu, fL_Word *attractor); 455 456 /** 457 * Removes joints, parts and neurons with its connections from current model, without 458 * removing checkpoint data. 459 * @param m model to clear 460 */ 461 void clearModelElements(Model *m); 462 463 /** 464 * Converts parameters defined in built-in words into desired 465 * range with use of sigmoid function, which ensures staying 466 * within min and max value. 467 * @param input the value from evaluation of parameter 468 * @param min minimal value of property 469 * @param max maximal value of property 470 * @return value of body element property 471 */ 472 double sigmoidTransform(double input, double min, double max); 473 474 /** 475 * Counts words defined in the genotype. 476 * @return number of defined words 477 */ 478 int countDefinedWords(); 479 480 /** 481 * Counts number of sticks in a given sequence 482 * @return number of sticks in sequence 483 */ 484 int countSticksInSequence(std::list<fL_Word *> sequence); 485 486 /** 487 * Counts all definitions of words, all words in axiom and rule successors in a genotype. 488 * Used for computing change between original genotype and mutation. 489 * @return number of words in definitions, axiom and rule successors 490 */ 491 int countWordsInLSystem(); 492 493 /** 494 * Sorts rules and removes rules that will not be used. The "sorting" is 495 * done in such way that all rules with conditions are first, and rules 496 * without conditions go to the end. If there are more than one rule 497 * for the same word with no condition or same condition, than the 498 * second one is removed. 499 */ 500 void removeRedundantRules(); 401 501 }; 402 502 -
cpp/frams/genetics/fL/fL_matheval.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include <frams/util/extvalue.h> 2 6 #include <frams/util/sstring.h> 3 7 #include <stack> 4 8 #include "fL_matheval.h" 9 #include <frams/genetics/genooperators.h> 5 10 6 11 // Used available operators in MathEvaluation … … 94 99 } 95 100 101 void MathEvaluation::registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol) 102 { 103 operators[opsymbol] = new Operator(operation, precedence, assoc, opsymbol); 104 operatorstrings.push_back(opsymbol); 105 } 106 96 107 void MathEvaluation::registerOperators() 97 108 { 98 109 // list of available operators in MathEvaluation 99 operators["+"] = new Operator(madd, 2, Associativity::LEFT, "+"); 100 operators["-"] = new Operator(msub, 2, Associativity::LEFT, "-"); 101 operators["*"] = new Operator(mmul, 3, Associativity::LEFT, "*"); 102 operators["&"] = new Operator(mand, 0, Associativity::LEFT, "&"); 103 operators["|"] = new Operator(mor, 0, Associativity::LEFT, "|"); 104 operators[">"] = new Operator(mgreater, 1, Associativity::LEFT, ">"); 105 operators["<"] = new Operator(mless, 1, Associativity::LEFT, "<"); 106 operators[">="] = new Operator(meqgreater, 1, Associativity::LEFT, ">="); 107 operators["<="] = new Operator(meqless, 1, Associativity::LEFT, "<="); 108 operators["="] = new Operator(mequal, 1, Associativity::RIGHT, "="); 109 operators["~"] = new Operator(mnotequal, 1, Associativity::RIGHT, "~"); 110 registerOperator(madd, 2, Associativity::LEFT, "+"); 111 registerOperator(msub, 2, Associativity::LEFT, "-"); 112 registerOperator(mmul, 3, Associativity::LEFT, "*"); 113 registerOperator(mgreater, 1, Associativity::LEFT, ">"); 114 registerOperator(mless, 1, Associativity::LEFT, "<"); 115 registerOperator(meqgreater, 1, Associativity::LEFT, ">="); 116 registerOperator(meqless, 1, Associativity::LEFT, "<="); 117 registerOperator(mequal, 1, Associativity::RIGHT, "="); 118 registerOperator(mnotequal, 1, Associativity::RIGHT, "~"); 119 registerOperator(mand, 0, Associativity::LEFT, "&"); 120 registerOperator(mor, 0, Associativity::LEFT, "|"); 121 arithmeticoperatorscount = 3; 122 comparisonoperatorscount = 6; 110 123 } 111 124 … … 159 172 int MathEvaluation::convertString(std::string expression) 160 173 { 174 originalexpression = expression; 161 175 clearPostfix(); //clear previous objects 162 176 ExtValue val; … … 193 207 { 194 208 delete operatorstack.back(); 195 operatorstack.pop_back();196 }209 } 210 operatorstack.pop_back(); 197 211 } 198 212 return -1; … … 247 261 { 248 262 delete operatorstack.back(); 249 operatorstack.pop_back();250 }263 } 264 operatorstack.pop_back(); 251 265 } 252 266 return -1; … … 407 421 { 408 422 delete operatorstack.back(); 409 operatorstack.pop_back();410 }423 } 424 operatorstack.pop_back(); 411 425 } 412 426 return -1; … … 434 448 { 435 449 delete operatorstack.back(); 436 operatorstack.pop_back();437 }450 } 451 operatorstack.pop_back(); 438 452 } 439 453 return -1; … … 448 462 // stack holds number used during operator execution 449 463 std::stack<Number *> numberstack; 450 451 464 for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++) 452 465 { … … 532 545 int MathEvaluation::RPNToInfix(std::string &result) 533 546 { 547 if (postfixlist.size() == 0) 548 { 549 result = ""; 550 return 0; 551 } 534 552 // stack holds stringified chunk and its precedence 535 553 std::stack<std::pair<std::string, int>> chunks; … … 585 603 { 586 604 logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR, 587 "Could not convert RPN notation to infix notation ");605 "Could not convert RPN notation to infix notation - formula is not complete"); 588 606 return -1; 589 607 } … … 592 610 return 0; 593 611 } 612 613 void MathEvaluation::mutateValueOrVariable(MathEvaluation::Number *&currval, bool usetime) 614 { 615 if (randomN(2) == 0 && varcount > 0) // use variable 616 { 617 if (currval && currval->type == TokenType::NUMBER) 618 { 619 delete currval; 620 } 621 int var = randomN(varcount + (usetime ? 1 : 0)); 622 if (varcount == var) // time is used 623 { 624 currval = t; 625 } 626 else 627 { 628 currval = vars[var]; 629 } 630 } 631 else 632 { 633 if (!currval || currval->type == TokenType::VARIABLE) 634 { 635 currval = new Number(rnd01); 636 } 637 else 638 { 639 currval->value = rnd01; 640 } 641 } 642 } 643 644 MathEvaluation::Operator* MathEvaluation::getRandomOperator(int type) 645 { // 0 for all, 1 for arithmetic only, 2 for logical only 646 int randop = type == 2 ? arithmeticoperatorscount : 0; 647 int count = arithmeticoperatorscount; 648 if (type == 0) 649 { 650 count = operatorstrings.size(); 651 } 652 else if (type == 2) 653 { 654 count = operatorstrings.size() - arithmeticoperatorscount; 655 } 656 randop += randomN(count); 657 return operators[operatorstrings[randop]]; 658 } 659 660 void MathEvaluation::mutateConditional() 661 { 662 if (varcount > 0) 663 { 664 int currsize = postfixlist.size(); 665 int varid = randomN(varcount); 666 postfixlist.push_back(vars[varid]); 667 if (randomN(2) == 0 && varcount > 1) 668 { 669 int varid2 = randomN(varcount - 1); 670 if (varid2 >= varid) varid2++; 671 postfixlist.push_back(vars[varid2]); 672 } 673 else 674 { 675 Number *num = new Number(rnd01); 676 postfixlist.push_back(num); 677 } 678 int opid = arithmeticoperatorscount + randomN(comparisonoperatorscount); 679 postfixlist.push_back(operators[operatorstrings[opid]]); 680 if (currsize > 0) 681 { 682 postfixlist.push_back(operators["&"]); 683 } 684 } 685 } 686 687 int MathEvaluation::mutate(bool logical, bool usetime) 688 { 689 if (postfixlist.size() == 0) 690 { 691 Number *val = new Number(rnd01); 692 postfixlist.push_back(val); 693 return -1; 694 } 695 int method = randomN(postfixlist.size() < MAX_MUT_FORMULA_SIZE ? MATH_MUT_COUNT : MATH_MUT_COUNT - 1); 696 switch (method) 697 { 698 case MATH_MUT_INSERTION: 699 { 700 std::list<Token *> insertpair; 701 Number *val = NULL; 702 mutateValueOrVariable(val, usetime); 703 insertpair.push_back(val); 704 std::list<Token *>::iterator it = postfixlist.begin(); 705 // insertion can be applied from 1st occurrence 706 int insertlocation = 1 + randomN(postfixlist.size() - 1); 707 std::advance(it, insertlocation); 708 Operator *rndop; 709 if (insertlocation == (int)postfixlist.size() - 1) 710 { 711 rndop = getRandomOperator(logical ? 2 : 1); 712 } 713 else 714 { 715 rndop = getRandomOperator(logical ? 0 : 1); 716 717 } 718 insertpair.push_back(rndop); 719 postfixlist.insert(it, insertpair.begin(), insertpair.end()); 720 break; 721 } 722 case MATH_MUT_CHANGEVAL: 723 { 724 std::vector<std::list<Token *>::iterator> numbersineval; 725 int id = 0; 726 for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++) 727 { 728 if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE) 729 { 730 numbersineval.push_back(it); 731 } 732 id++; 733 } 734 int randid = randomN(numbersineval.size()); 735 Number *numptr = (Number *)(*numbersineval[randid]); 736 mutateValueOrVariable(numptr, usetime); 737 (*numbersineval[randid]) = numptr; 738 break; 739 } 740 case MATH_MUT_CHANGEOPER: 741 { 742 std::vector<std::list<Token *>::iterator> ops; 743 for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++) 744 { 745 if ((*it)->type == TokenType::OPERATOR) 746 { 747 ops.push_back(it); 748 } 749 } 750 if (ops.size() > 0) 751 { 752 int randid = randomN(ops.size()); 753 Operator *rndop; 754 if (randid == (int)ops.size() - 1) 755 { 756 rndop = getRandomOperator(logical ? 2 : 1); 757 } 758 else 759 { 760 rndop = getRandomOperator(logical ? 0 : 1); 761 } 762 (*ops[randid]) = rndop; 763 } 764 break; 765 } 766 case MATH_MUT_DELETION: 767 { 768 std::list<Token *>::iterator it = postfixlist.begin(); 769 std::vector<std::list<Token *>::iterator> firstofpairs; 770 while (it != postfixlist.end()) 771 { 772 if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE) 773 { 774 std::list<Token *>::iterator next = it; 775 next++; 776 if (next != postfixlist.end() && (*next)->type == TokenType::OPERATOR) 777 { 778 firstofpairs.push_back(it); 779 } 780 } 781 it++; 782 } 783 if (firstofpairs.size() > 0) 784 { 785 int rndid = randomN(firstofpairs.size()); 786 if ((*firstofpairs[rndid])->type == TokenType::NUMBER) 787 { 788 delete (*firstofpairs[rndid]); 789 } 790 firstofpairs[rndid] = postfixlist.erase(firstofpairs[rndid]); 791 postfixlist.erase(firstofpairs[rndid]); 792 } 793 break; 794 } 795 } 796 return method; 797 } 798 799 std::string MathEvaluation::getStringifiedRPN() 800 { 801 std::string res = ""; 802 for (Token *el: postfixlist) 803 { 804 res += el->toString(); 805 res += " "; 806 } 807 return res; 808 } -
cpp/frams/genetics/fL/fL_matheval.h
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #ifndef _FL_MATHEVAL_H_ 2 6 #define _FL_MATHEVAL_H_ … … 8 12 9 13 #define VARIABLEPREFIX '$' 14 15 #define MATH_MUT_DELETION 0 16 #define MATH_MUT_CHANGEVAL 1 17 #define MATH_MUT_CHANGEOPER 2 18 #define MATH_MUT_INSERTION 3 19 #define MATH_MUT_COUNT 4 20 21 #define MAX_MUT_FORMULA_SIZE 7 22 #define XOVER_MAX_MIGRATED_RULES 3 10 23 11 24 /** @name Available operators for MathEvaluation */ … … 171 184 void registerOperators(); 172 185 186 std::string originalexpression; 173 187 std::unordered_map<std::string, Operator *> operators; ///<map containing available operators for MathEvaluation 174 188 std::list<Token *> postfixlist; ///<list with tokens ordered as postfix (RPN) notation of the given string … … 176 190 std::vector<Variable *> vars; ///<vector of variables, default values are 0 177 191 Variable *t; ///<additional t variable, that can act as time for evaluation 192 std::vector<std::string> operatorstrings; ///<list of registered operators 193 int arithmeticoperatorscount; ///<count of arithmetic operators 194 int comparisonoperatorscount; 178 195 public: 179 196 … … 226 243 227 244 /** 245 * Registers new operator for MathEvaluation object. 246 * @param operation function that needs to be called during evaluation 247 * @param precedence precedence of operator 248 * @param assoc associativity of the operator 249 * @param opsymbol symbol of the operator 250 */ 251 void registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol); 252 253 /** 228 254 * Converts stored RPN list to infix string. 229 255 * @param result reference to variable that will hold the result … … 231 257 */ 232 258 int RPNToInfix(std::string &result); 259 260 /** 261 * Mutates formula. 262 * @param logical if true, method uses logical operators only 263 * @param usetime if true, method may use time variable during mutation 264 * @param 0 if mutation could be performed, -1 if postfixlist is empty 265 */ 266 int mutate(bool logical, bool usetime); 267 268 /** 269 * Mutates formula so it creates conjuctive of comparisons. 270 */ 271 void mutateConditional(); 272 273 /** 274 * Mutates number by using random value or one of variables. 275 * @param currval current value of number 276 * @param usetime if true, then time variable may be used 277 */ 278 void mutateValueOrVariable(Number *&currval, bool usetime); 279 280 /** 281 * Returns formula in RPN notation 282 * @param RPN notation string 283 */ 284 std::string getStringifiedRPN(); 285 286 /** 287 * Returns random operator available in object. 288 * @param type 0 for all operators, 1 for arithmetic only, 2 for logical only 289 * @return pointer to random operator 290 */ 291 Operator* getRandomOperator(int type); 233 292 }; 234 293 -
cpp/frams/genetics/fL/fL_oper.cpp
r780 r797 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 1 5 #include "fL_oper.h" 6 #include <common/loggers/loggers.h> 7 #include "../fH/fH_oper.h" 8 #include <algorithm> 9 10 #define FIELDSTRUCT Geno_fL 11 static ParamEntry GENOfLparam_tab[] = 12 { 13 {"Genetics: fL", 3, FL_OPCOUNT + FL_MUTGROUPSCOUNT + FL_CHG_COUNT + 2 + FL_ADD_COUNT, }, 14 {"Genetics: fL: Probabilities of mutating axiom and rules", }, 15 {"Genetics: fL: Probabilities of mutation types", }, 16 {"fL_maxdefinedwords", 0, 0, "Maximum number of defined words", "d 0 100 10", FIELD(maxdefinedwords), "Maximum number of words that can be defined in L-System", }, 17 18 {"fL_axm_mut_prob", 1, 0, "Axiom mutation", "f 0 1 0.2", FIELD(groupprobabilities[FL_AXM_WORD_MUT_PROB]), "Probability of performing mutation operations on axiom", }, 19 {"fL_rul_mut_prob", 1, 0, "Rule's successor mutation", "f 0 1 0.8", FIELD(groupprobabilities[FL_RUL_WORD_MUT_PROB]), "Probability of performing mutation operations on the successor of random rule", }, 20 21 {"fL_mut_addition", 2, 0, "Addition of word to sequence", "f 0 1 0.2", FIELD(operations[FL_ADD_WORD]), "Probability of adding random existing word to the axiom or one of successors", }, 22 23 {"fL_mut_add_stick", 2, 0, " - addition of stick", "f 0 1 0.2", FIELD(addtypes[FL_ADD_STICK]), "Probability of adding stick", }, 24 {"fL_mut_add_neuro", 2, 0, " - addition of neuron", "f 0 1 0.2", FIELD(addtypes[FL_ADD_NEURO]), "Probability of adding neuron", }, 25 {"fL_mut_add_conn", 2, 0, " - addition of neuron connection", "f 0 1 0.2", FIELD(addtypes[FL_ADD_CONN]), "Probability of adding connection", }, 26 {"fL_mut_add_rot", 2, 0, " - addition of rotation words", "f 0 1 0.2", FIELD(addtypes[FL_ADD_ROT]), "Probability of adding one of rotation words", }, 27 {"fL_mut_add_branch", 2, 0, " - addition of branched stick", "f 0 1 0.2", FIELD(addtypes[FL_ADD_BRANCH]), "Probability of adding branch with rotation and stick", }, 28 {"fL_mut_add_other", 2, 0, " - addition of defined words", "f 0 1 0.4", FIELD(addtypes[FL_ADD_OTHER]), "Probability of adding other word, defined in genotype", }, 29 30 {"fL_mut_worddefaddition", 2, 0, "Addition of new word definition", "f 0 1 0.05", FIELD(operations[FL_ADD_WDEF]), "Probability of adding new word definition to the genotype", }, 31 {"fL_mut_ruleaddition", 2, 0, "Addition of new rule definition", "f 0 1 0.1", FIELD(operations[FL_ADD_RULE]), "Probability of adding new rule definition for existing word", }, 32 {"fL_mut_rulecond", 2, 0, "Modification of rule condition", "f 0 1 0.1", FIELD(operations[FL_CHG_COND]), "Probability of modifying random rule condition", }, 33 34 {"fL_mut_changeword", 2, 0, "Change of random word", "f 0 1 0.3", FIELD(operations[FL_CHG_WORD]), "Probability of changing word name or formula of a random word from axiom or one of successors", }, 35 {"fL_mut_changeword_formula", 2, 0, " - change of formula", "f 0 1 0.7", FIELD(chgoperations[FL_CHG_WORD_FORMULA]), "Probability of changing formula in word", }, 36 {"fL_mut_changeword_name", 2, 0, " - change of name", "f 0 1 0.3", FIELD(chgoperations[FL_CHG_WORD_NAME]), "Probability of changing name in word", }, 37 38 {"fL_mut_changeiter", 2, 0, "Change of L-System iteration", "f 0 1 0.3", FIELD(operations[FL_CHG_ITER]), "Probability of changing number of iterations of L-Systems", }, 39 {"fL_mut_changeiter_step", 2, 0, "Step of iteration changing", "f 0 1 1.0", FIELD(iterchangestep), "Minimal step that should be used for changing iterations in L-Systems", }, 40 {"fL_mut_deletion", 2, 0, "Deletion of random word", "f 0 1 0.2", FIELD(operations[FL_DEL_WORD]), "Probability of deleting random word from axiom or random successor (also deletes rule if there is only one word in successor)", }, 41 { 0, }, 42 }; 43 #undef FIELDSTRUCT 2 44 3 45 Geno_fL::Geno_fL() 4 46 { 5 // par.setParamTab(GENOfHparam_tab); 6 // par.select(this); 7 // par.setDefault(); 8 supported_format = 'H'; 9 } 47 par.setParamTab(GENOfLparam_tab); 48 par.select(this); 49 par.setDefault(); 50 supported_format = 'L'; 51 iterchangestep = 1.0; 52 maxdefinedwords = 10; 53 } 54 55 int Geno_fL::checkValidity(const char *geno, const char *genoname) 56 { 57 LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN); 58 fL_Builder builder(false, false); 59 60 int err = builder.parseGenotype(geno); 61 if (err != 0) 62 { 63 return err; 64 } 65 66 if (builder.countSticksInSequence(builder.genotype) == 0) 67 { 68 return GENOPER_OPFAIL; 69 } 70 double neededtime = 0; 71 Model *m = builder.developModel(neededtime); 72 if (!m) 73 { 74 return GENOPER_OPFAIL; 75 } 76 if (!m->isValid()) 77 { 78 delete m; 79 return GENOPER_OPFAIL; 80 } 81 delete m; 82 83 84 return GENOPER_OK; 85 } 86 87 int Geno_fL::validate(char *&geno, const char *genoname) 88 { 89 LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN); 90 fL_Builder builder(false, false); 91 92 int err = builder.parseGenotype(geno); 93 if (err != 0) 94 { 95 return err; 96 } 97 double neededtime = 0; 98 Model *m = builder.developModel(neededtime); 99 if (!m->isValid()) 100 { 101 delete m; 102 return GENOPER_OPFAIL; 103 } 104 if (neededtime != builder.time) 105 { 106 builder.time = neededtime; 107 free(geno); 108 geno = strdup(builder.toString().c_str()); 109 delete m; 110 return GENOPER_OK; 111 } 112 delete m; 113 return GENOPER_OK; 114 } 115 116 bool Geno_fL::addWord(std::list<fL_Word *>* list, fL_Word *definition, std::list<fL_Word *>::iterator it) 117 { 118 fL_Word *newword = new fL_Word(); 119 *newword = *definition; 120 121 // if word has parameters 122 if (newword->npar > 0) 123 { 124 // create ParamObject that will hold parameter data 125 newword->data = ParamObject::makeObject(newword->tab); 126 Param par(newword->tab); 127 par.select(newword->data); 128 par.setDefault(); 129 for (int i = 0; i < par.getPropCount(); i++) 130 { 131 newword->parevals.push_back(NULL); 132 } 133 if (newword->name.startsWith("rot")) 134 { 135 double rot = 2 * rnd01; 136 MathEvaluation *eval = new MathEvaluation(0); 137 eval->convertString(SString::valueOf(rot).c_str()); 138 newword->parevals[0] = eval; 139 } 140 else if (newword->name == "N") 141 { 142 SString det; 143 NeuroClass *cls = getRandomNeuroClass(); 144 if (!cls) cls = Neuro::getClass("N"); 145 det = cls->getName(); 146 Geno_fH::mutateNeuronProperties(det); 147 par.setStringById(FL_PE_NEURO_DET, det); 148 } 149 else if (newword->name == "C") 150 { 151 MathEvaluation *eval = new MathEvaluation(0); 152 eval->convertString(SString::valueOf(2 * rnd01 - 1).c_str()); 153 newword->parevals[0] = eval; 154 } 155 } 156 157 list->insert(it, newword); 158 return true; 159 } 160 161 std::list<fL_Word *>* Geno_fL::selectRandomSequence(fL_Builder *creature, int &numparams, int &ruleid) 162 { 163 std::list<fL_Word *> *list = NULL; 164 int axiomorrules = roulette(groupprobabilities, FL_MUTGROUPSCOUNT); 165 bool axiomused = axiomorrules == FL_AXM_WORD_MUT_PROB || creature->rules.size() == 0; 166 if (axiomused) 167 { 168 list = &creature->genotype; 169 numparams = 0; 170 ruleid = -1; 171 } 172 else 173 { 174 int rid = randomN(creature->rules.size()); 175 list = &creature->rules[rid]->objsucc; 176 numparams = creature->rules[rid]->objpred->npar; 177 ruleid = rid; 178 } 179 return list; 180 } 181 182 fL_Word* Geno_fL::randomWordDefinition(fL_Builder *creature, int method) 183 { 184 if (method == FL_ADD_OTHER && creature->builtincount < (int)creature->words.size()) 185 { 186 return creature->words[creature->wordnames[creature->builtincount + randomN((int)creature->words.size() - creature->builtincount)]]; 187 } 188 else 189 { 190 if (method == FL_ADD_OTHER) // we should be able to select stick, neuro or conn 191 { 192 double alttypes[FL_ADD_COUNT - 2]; 193 alttypes[FL_ADD_STICK] = addtypes[FL_ADD_STICK]; 194 alttypes[FL_ADD_NEURO] = addtypes[FL_ADD_NEURO]; 195 alttypes[FL_ADD_CONN] = addtypes[FL_ADD_CONN]; 196 alttypes[FL_ADD_ROT] = addtypes[FL_ADD_ROT]; 197 method = roulette(alttypes, FL_ADD_COUNT - 2); 198 } 199 switch (method) 200 { 201 case FL_ADD_STICK: 202 return creature->words["S"]; 203 case FL_ADD_NEURO: 204 return creature->words["N"]; 205 case FL_ADD_CONN: 206 return creature->words["C"]; 207 case FL_ADD_ROT: 208 { 209 int rottype = randomN(3); 210 switch (rottype) 211 { 212 case 0: 213 return creature->words["rotX"]; 214 case 1: 215 return creature->words["rotY"]; 216 case 2: 217 return creature->words["rotZ"]; 218 } 219 break; 220 } 221 case FL_ADD_BRANCH: 222 // return NULL 223 break; 224 } 225 } 226 return NULL; 227 } 228 229 void Geno_fL::deleteBranch(std::list<fL_Word *> *list, std::list<fL_Word *>::iterator openbranchposition) 230 { 231 fL_Branch *branch = (fL_Branch *)(*openbranchposition); 232 if (branch->btype == fL_Branch::BranchType::OPEN) 233 { 234 int bcount = 1; 235 delete (*openbranchposition); 236 openbranchposition = list->erase(openbranchposition); 237 for (; openbranchposition != list->end(); openbranchposition++) 238 { 239 if ((*openbranchposition)->type == fLElementType::BRANCH) 240 { 241 branch = (fL_Branch *)(*openbranchposition); 242 if (branch->btype == fL_Branch::BranchType::OPEN) 243 { 244 bcount++; 245 } 246 else 247 { 248 bcount--; 249 if (bcount == 0) 250 { 251 delete branch; 252 list->erase(openbranchposition); 253 break; 254 } 255 } 256 } 257 } 258 } 259 else 260 { 261 openbranchposition++; 262 if (openbranchposition != list->end()) 263 { 264 delete (*openbranchposition); 265 list->erase(openbranchposition); 266 } 267 } 268 } 269 270 int Geno_fL::mutate(char *&geno, float& chg, int &method) 271 { 272 fL_Builder *creature = new fL_Builder(false, false); 273 274 if (creature->parseGenotype(geno) != 0) 275 { 276 delete creature; 277 return GENOPER_OPFAIL; 278 } 279 280 int before = creature->countWordsInLSystem(); 281 282 method = roulette(operations, FL_OPCOUNT); 283 switch (method) 284 { 285 case FL_CHG_ITER: 286 { 287 if (randomN(2) == 0) 288 { 289 creature->time = creature->time + iterchangestep <= ExtValue::getDouble(FL_MAXITER) ? 290 creature->time + iterchangestep : creature->time - iterchangestep; 291 } 292 else 293 { 294 creature->time = creature->time - iterchangestep >= 0 ? 295 creature->time - iterchangestep : creature->time + iterchangestep; 296 } 297 break; 298 } 299 case FL_CHG_COND: 300 { 301 if (creature->rules.size() > 0) 302 { 303 int ruleid = randomN(creature->rules.size()); 304 if (!creature->rules[ruleid]->condeval) 305 { 306 creature->rules[ruleid]->condeval = new MathEvaluation(creature->rules[ruleid]->objpred->npar); 307 } 308 creature->rules[ruleid]->condeval->mutateConditional(); 309 break; 310 } 311 // if there are no rules - create one 312 } 313 /* no break */ 314 case FL_ADD_RULE: 315 { 316 std::unordered_map<std::string, fL_Word *>::iterator pred = creature->words.begin(); 317 std::vector<fL_Word *> wordswithnorules; 318 for (; pred != creature->words.end(); pred++) 319 { 320 if (!pred->second->builtin) 321 { 322 bool norules = true; 323 for (fL_Rule * r : creature->rules) 324 { 325 if (pred->second->name == r->objpred->name && 326 pred->second->npar == r->objpred->npar) 327 { 328 norules = false; 329 break; 330 } 331 } 332 if (norules) 333 { 334 wordswithnorules.push_back(pred->second); 335 } 336 } 337 } 338 if (wordswithnorules.size() > 0) 339 { 340 int predid = randomN(wordswithnorules.size()); 341 fL_Rule *newrule = new fL_Rule(0,0); 342 fL_Word *pred = new fL_Word(); 343 *pred = *wordswithnorules[predid]; 344 newrule->objpred = pred; 345 fL_Word *initdef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); // -1 to avoid branching 346 addWord(&newrule->objsucc, initdef, newrule->objsucc.begin()); 347 creature->rules.push_back(newrule); 348 break; 349 } 350 else if (creature->rules.size() > 0) 351 { 352 int ruleid = randomN(creature->rules.size()); 353 fL_Rule *newrule = new fL_Rule(0, 0); 354 fL_Word *pred = new fL_Word(); 355 *pred = *creature->rules[ruleid]->objpred; 356 newrule->objpred = pred; 357 if (creature->rules[ruleid]->condeval) 358 { 359 std::string formula = ""; 360 creature->rules[ruleid]->condeval->RPNToInfix(formula); 361 if (formula.find("1.0-(") != 0) 362 { 363 std::string res = "1.0-("; 364 res += formula; 365 res += ")"; 366 newrule->condeval = new MathEvaluation(pred->npar); 367 newrule->condeval->convertString(res); 368 } 369 else 370 { 371 newrule->condeval = new MathEvaluation(pred->npar); 372 newrule->condeval->mutateConditional(); 373 } 374 } 375 else 376 { 377 newrule->condeval = new MathEvaluation(pred->npar); 378 newrule->condeval->mutateConditional(); 379 } 380 fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); 381 addWord(&newrule->objsucc, worddef, newrule->objsucc.begin()); 382 creature->rules.push_back(newrule); 383 break; 384 } 385 // if there are no words, from which rules can be formed, then add one 386 } 387 /* no break */ 388 case FL_ADD_WDEF: 389 { 390 if (creature->countDefinedWords() <= maxdefinedwords) 391 { 392 int npar = randomN(ExtValue::getInt(FL_MAXPARAMS, false)); 393 for (int i = 0; i < maxdefinedwords; i++) 394 { 395 std::string name = "w"; 396 name += std::to_string(i); 397 if (creature->words.find(name) == creature->words.end()) 398 { 399 fL_Word *word = new fL_Word(false, 0, 0); 400 word->npar = npar; 401 word->name = name.c_str(); 402 word->processDefinition(creature); 403 break; 404 } 405 } 406 break; 407 } 408 //no break at the end of case - if there is too many words, then 409 // deletion should be performed 410 } 411 /* no break */ 412 case FL_DEL_WORD: 413 { 414 int numpars = 0; 415 int ruleid = 0; 416 std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, ruleid); 417 if (ruleid == -1 && creature->countSticksInSequence((*list)) == 1) 418 { 419 if (list->size() > 1) 420 { 421 int rndid = randomN(list->size() - 1); 422 int j = 0; 423 std::list<fL_Word *>::iterator it = list->begin(); 424 if ((*it)->name == "S") 425 { 426 it++; 427 } 428 while (it != list->end() && j < rndid && ((*it)->name == "S")) 429 { 430 if ((*it)->name != "S") 431 { 432 j++; 433 } 434 it++; 435 } 436 if (it != list->end()) 437 { 438 if ((*it)->type == fLElementType::BRANCH) 439 { 440 deleteBranch(list, it); 441 } 442 else 443 { 444 delete (*it); 445 list->erase(it); 446 } 447 break; 448 } 449 // else add word 450 } 451 // else add word 452 } 453 else 454 { 455 int rndid = randomN(list->size()); 456 std::list<fL_Word *>::iterator it = list->begin(); 457 std::advance(it, rndid); 458 if ((*it)->type == fLElementType::BRANCH) 459 { 460 deleteBranch(list, it); 461 } 462 else 463 { 464 delete (*it); 465 list->erase(it); 466 } 467 if (ruleid > -1 && creature->rules[ruleid]->objsucc.size() == 0) 468 { 469 delete creature->rules[ruleid]; 470 creature->rules.erase(creature->rules.begin() + ruleid); 471 } 472 break; 473 } 474 // if no words available, then add word 475 } 476 /* no break */ 477 case FL_ADD_WORD: 478 { 479 int numpars = 0; 480 int tmp = 0; 481 std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp); 482 int rndid = randomN(list->size()); 483 std::list<fL_Word *>::iterator it = list->begin(); 484 std::advance(it, rndid); 485 int meth = roulette(addtypes, FL_ADD_COUNT); 486 if (tmp == -1) 487 { // if sequence is axiom and it does not have non-builtin words 488 bool hasdefined = false; 489 for (std::list<fL_Word *>::iterator elem = list->begin(); elem != list->end(); elem++) 490 { 491 if (!(*elem)->builtin) 492 { 493 hasdefined = true; 494 break; 495 } 496 } 497 if (!hasdefined) 498 { 499 meth = FL_ADD_OTHER; 500 } 501 502 } 503 if (meth != FL_ADD_BRANCH) 504 { 505 fL_Word *worddef = randomWordDefinition(creature, meth); 506 addWord(list, worddef, it); 507 } 508 else 509 { 510 fL_Branch *start = new fL_Branch(fL_Branch::BranchType::OPEN, 0, 0); 511 list->insert(it, start); 512 int rottype = randomN(2); 513 switch (rottype) 514 { 515 case 0: 516 addWord(list, creature->words["rotY"], it); 517 case 1: 518 addWord(list, creature->words["rotZ"], it); 519 } 520 addWord(list, creature->words["S"], it); 521 fL_Branch *end = new fL_Branch(fL_Branch::BranchType::CLOSE, 0, 0); 522 list->insert(it, end); 523 } 524 break; 525 } 526 case FL_CHG_WORD: 527 { 528 int numpars = 0; 529 int tmp = 0; 530 std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp); 531 int rndid = randomN(list->size()); 532 std::list<fL_Word *>::iterator selectedword = list->begin(); 533 std::advance(selectedword, rndid); 534 if ((*selectedword)->type == fLElementType::BRANCH) 535 { 536 break; 537 } 538 int chgtype = roulette(chgoperations, FL_CHG_COUNT); 539 if (creature->countSticksInSequence((*list)) == 1 && tmp == -1) // if sequence is axiom 540 { 541 fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); 542 543 int numpars = 0; 544 std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp); 545 int rndid = randomN(list->size()); 546 std::list<fL_Word *>::iterator it = list->begin(); 547 std::advance(it, rndid); 548 549 addWord(list, worddef, it); 550 551 break; 552 } 553 else if (chgtype == FL_CHG_WORD_NAME) 554 { 555 if ((*selectedword)->builtin) 556 { 557 delete (*selectedword); 558 selectedword = list->erase(selectedword); 559 fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); 560 addWord(list, worddef, selectedword); 561 } 562 else 563 { 564 std::vector<fL_Word *> available; 565 for (std::unordered_map<std::string, fL_Word *>::iterator wit = creature->words.begin(); 566 wit != creature->words.end(); wit++) 567 { 568 if ((*selectedword)->npar == wit->second->npar && 569 (*selectedword)->name != wit->second->name && 570 !wit->second->builtin) 571 { 572 available.push_back(wit->second); 573 } 574 } 575 if (available.size() > 0) 576 { 577 int newnameid = randomN(available.size()); 578 (*selectedword)->name = available[newnameid]->name; 579 } 580 else 581 { 582 delete (*selectedword); 583 selectedword = list->erase(selectedword); 584 fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); 585 addWord(list, worddef, selectedword); 586 } 587 } 588 } 589 else 590 { 591 if ((*selectedword)->npar > 0) 592 { 593 int randeval = randomN((*selectedword)->npar); 594 Param par((*selectedword)->tab, (*selectedword)->data); 595 if ((*selectedword)->builtin && (*selectedword)->name == "N" 596 && strcmp(par.id(randeval), FL_PE_NEURO_DET) == 0) 597 { 598 SString res = par.getStringById(FL_PE_NEURO_DET); 599 Geno_fH::mutateNeuronProperties(res); 600 par.setStringById(FL_PE_NEURO_DET, res); 601 } 602 else if ((*selectedword)->builtin && 603 (*selectedword)->name == "C" && 604 strcmp(par.id(randeval), FL_PE_CONN_ATTR) == 0) 605 { 606 SString strattractor = par.getStringById(FL_PE_CONN_ATTR); 607 if (strattractor.len() > 0) 608 { 609 fL_Word *w = NULL; 610 creature->createWord(strattractor, w, numpars, 0, 0); 611 // mutate attractor parameter 612 if (w->npar > 0) 613 { 614 int rndattr = randomN(w->npar); 615 if (!w->parevals[rndattr]) 616 { 617 w->parevals[rndattr] = new MathEvaluation(numpars); 618 } 619 w->parevals[rndattr]->mutate(false, false); 620 } 621 strattractor = w->stringify(true); 622 par.setStringById(FL_PE_CONN_ATTR, strattractor); 623 delete w; 624 } 625 else 626 { 627 if (creature->builtincount < (int)creature->words.size()) 628 { 629 fL_Word *wdef = randomWordDefinition(creature, FL_ADD_OTHER); 630 fL_Word *w = new fL_Word(); 631 *w = *wdef; 632 w->data = ParamObject::makeObject(w->tab); 633 Param apar(w->tab); 634 apar.select(w->data); 635 apar.setDefault(); 636 if (w->npar > 0) 637 { 638 int rndattr = randomN(w->npar); 639 for (int i = 0; i < w->npar; i++) 640 { 641 if (i == rndattr) 642 { 643 MathEvaluation *ev = new MathEvaluation(numpars); 644 ev->mutate(false, false); 645 w->parevals.push_back(ev); 646 } 647 else 648 { 649 w->parevals.push_back(NULL); 650 } 651 } 652 653 } 654 strattractor = w->stringify(false); 655 par.setStringById(FL_PE_CONN_ATTR, strattractor); 656 delete w; 657 } 658 } 659 } 660 else 661 { 662 if (!(*selectedword)->parevals[randeval]) 663 { 664 (*selectedword)->parevals[randeval] = new MathEvaluation(numpars); 665 } 666 (*selectedword)->parevals[randeval]->mutate(false, iterchangestep != 1.0); 667 } 668 } 669 } 670 break; 671 } 672 } 673 674 free(geno); 675 geno = strdup(creature->toString().c_str()); 676 chg = (double)abs(before - creature->countWordsInLSystem()) / before; 677 delete creature; 678 679 return GENOPER_OK; 680 } 681 682 fL_Word* Geno_fL::getAppropriateWord(fL_Builder *from, fL_Builder *to, fL_Word *fromword, std::unordered_map<std::string, std::string> &map) 683 { 684 if (fromword->name == "[" || fromword->name == "]") // if words are branching words 685 { 686 fL_Branch *newword = new fL_Branch(fromword->name == "[" ? fL_Branch::BranchType::OPEN : fL_Branch::BranchType::CLOSE, 0, 0); 687 return newword; 688 } 689 if (fromword->builtin) 690 { 691 fL_Word *newword = new fL_Word(); 692 (*newword) = (*to->words[fromword->name.c_str()]); 693 return newword; 694 } 695 if (map.find(fromword->name.c_str()) != map.end()) // if word is already mapped 696 { 697 fL_Word *newword = new fL_Word(); 698 (*newword) = (*to->words[map[fromword->name.c_str()]]); 699 return newword; 700 } 701 else if (to->words.find(fromword->name.c_str()) != to->words.end() && 702 to->words[fromword->name.c_str()]->npar == fromword->npar) // if there is already same word with same number of parameters 703 { 704 fL_Word *newword = new fL_Word(); 705 map[fromword->name.c_str()] = fromword->name.c_str(); 706 (*newword) = (*to->words[map[fromword->name.c_str()]]); 707 return newword; 708 } 709 for (std::unordered_map<std::string, fL_Word *>::iterator it = to->words.begin(); 710 it != to->words.end(); it++) 711 { // find word with same number of parameters 712 if (fromword->npar == it->second->npar && map.find(fromword->name.c_str()) == map.end() && !it->second->builtin) 713 { // if there is a word with same number of parameters 714 map[fromword->name.c_str()] = it->second->name.c_str(); 715 fL_Word *newword = new fL_Word(); 716 (*newword) = (*it->second); 717 return newword; 718 } 719 } 720 fL_Word *newworddef = new fL_Word(); 721 (*newworddef) = (*fromword); 722 newworddef->parevals.clear(); 723 if (to->words.find(newworddef->name.c_str()) != to->words.end()) 724 { 725 int i = 0; 726 while (true) 727 { 728 std::string name = "w"; 729 name += std::to_string(i); 730 if (to->words.find(name) == to->words.end()) 731 { 732 newworddef->name = name.c_str(); 733 break; 734 } 735 i++; 736 } 737 } 738 newworddef->processDefinition(to); 739 map[fromword->name.c_str()] = newworddef->name.c_str(); 740 fL_Word *newword = new fL_Word(); 741 (*newword) = (*to->words[map[fromword->name.c_str()]]); 742 return newword; 743 } 744 745 void Geno_fL::migrateRandomRules(fL_Builder *from, fL_Builder *to, int numselrules) 746 { 747 std::unordered_map<std::string, std::string> map; 748 if (from->rules.size() > 0) 749 { 750 for (int i = 0; i < numselrules; i++) 751 { 752 int rulid = randomN(from->rules.size()); 753 fL_Rule *rul = from->rules[rulid]; 754 fL_Rule *newrule = new fL_Rule(0, 0); 755 newrule->objpred = getAppropriateWord(from, to, rul->objpred, map); 756 for (fL_Word *w : rul->objsucc) 757 { 758 fL_Word *el = getAppropriateWord(from, to, w, map); 759 if (el->type == fLElementType::BRANCH) 760 { 761 newrule->objsucc.push_back(el); 762 continue; 763 } 764 Param origpar(w->tab); 765 origpar.select(w->data); 766 el->data = ParamObject::makeObject(el->tab); 767 Param par(el->tab); 768 par.select(el->data); 769 par.setDefault(); 770 for (int i = 0; i < el->npar; i++) 771 { 772 std::string form; 773 if (w->builtin && w->name == "N" 774 && strcmp(par.id(i), FL_PE_NEURO_DET) == 0) 775 { 776 SString res = origpar.getStringById(FL_PE_NEURO_DET); 777 par.setStringById(FL_PE_NEURO_DET, res); 778 el->parevals.push_back(NULL); 779 } 780 else if (w->builtin && w->name == "C" 781 && strcmp(par.id(i), FL_PE_CONN_ATTR) == 0) 782 { 783 SString strattractor = origpar.getStringById(FL_PE_CONN_ATTR); 784 if (strattractor.len() > 0) 785 { 786 fL_Word *tmp = NULL; 787 from->createWord(strattractor, tmp, newrule->objpred->npar, 0, 0); 788 fL_Word *newsuccword = getAppropriateWord(from, to, tmp, map); 789 newsuccword->data = ParamObject::makeObject(el->tab); 790 newsuccword->parevals = tmp->parevals; 791 tmp->parevals.clear(); 792 strattractor = newsuccword->stringify(true); 793 par.setStringById(FL_PE_CONN_ATTR, strattractor); 794 delete newsuccword; 795 delete tmp; 796 } 797 par.setStringById(FL_PE_CONN_ATTR, strattractor); 798 el->parevals.push_back(NULL); 799 } 800 else if (w->parevals[i]) 801 { 802 MathEvaluation *eval = new MathEvaluation(newrule->objpred->npar); 803 w->parevals[i]->RPNToInfix(form); 804 eval->convertString(form); 805 el->parevals.push_back(eval); 806 } 807 else 808 { 809 el->parevals.push_back(NULL); 810 } 811 } 812 newrule->objsucc.push_back(el); 813 } 814 to->rules.push_back(newrule); 815 } 816 } 817 } 818 819 int Geno_fL::crossOver(char *&g1, char *&g2, float& chg1, float& chg2) 820 { 821 fL_Builder *creature1 = new fL_Builder(false, false); 822 fL_Builder *creature1template = new fL_Builder(false, false); 823 fL_Builder *creature2 = new fL_Builder(false, false); 824 fL_Builder *creature2template = new fL_Builder(false, false); 825 826 int count1 = creature1->countWordsInLSystem(); 827 int count2 = creature2->countWordsInLSystem(); 828 829 if (creature1->parseGenotype(g1) != 0 || creature2->parseGenotype(g2) != 0) 830 { 831 delete creature1; 832 delete creature2; 833 delete creature1template; 834 delete creature2template; 835 return GENOPER_OPFAIL; 836 } 837 838 creature1template->parseGenotype(g1); 839 creature2template->parseGenotype(g2); 840 841 int numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES); 842 numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size(); 843 844 migrateRandomRules(creature1template, creature2, numselrules); 845 846 numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES); 847 numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size(); 848 849 migrateRandomRules(creature2template, creature1, numselrules); 850 851 free(g1); 852 free(g2); 853 854 g1 = strdup(creature1->toString().c_str()); 855 g2 = strdup(creature2->toString().c_str()); 856 857 chg1 = (double)count1 / creature1->countWordsInLSystem(); 858 chg1 = (double)count2 / creature2->countWordsInLSystem(); 859 860 delete creature1; 861 delete creature2; 862 delete creature1template; 863 delete creature2template; 864 865 return GENOPER_OK; 866 } 867 868 uint32_t Geno_fL::style(const char *geno, int pos) 869 { 870 char ch = geno[pos]; 871 uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT); 872 if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character line definition 873 { 874 style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD); 875 } 876 else if (strchr("()", ch) != NULL) 877 { 878 style = GENSTYLE_RGBS(50, 50, 50, GENSTYLE_BOLD); 879 } 880 else if (isalpha(ch)) // properties name 881 { 882 style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD); 883 } 884 else if (isdigit(ch) || strchr(",.=", ch)) // properties values 885 { 886 style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE); 887 } 888 else if (ch == '\"') 889 { 890 style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD); 891 } 892 893 return style; 894 } -
cpp/frams/genetics/fL/fL_oper.h
r780 r797 1 #ifndef _FL_OPER_ 2 #define _FL_OPER_ 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 // See LICENSE.txt for details. 4 5 #ifndef _FL_OPER_H_ 6 #define _FL_OPER_H_ 3 7 4 8 #include "../genooperators.h" 9 #include "fL_general.h" 10 11 /** @name Codes for general fL mutation types */ 12 //@{ 13 #define FL_ADD_WORD 0 ///<probability of adding word to axiom or rule successor 14 #define FL_ADD_WDEF 1 ///<probability of adding word definition 15 #define FL_ADD_RULE 2 ///<probability of adding new rule 16 #define FL_CHG_COND 3 ///<probability of modification or rule condition 17 #define FL_CHG_WORD 4 ///<probability of changing word name or formula in axiom or rule successor 18 #define FL_CHG_ITER 5 ///<probability of changing iteration of genotype 19 #define FL_DEL_WORD 6 ///<probability of deleting word from axiom or rule. Deleting all occurrences of word deletes word definition. Deleting all words in rule deletes this rule 20 #define FL_OPCOUNT 7 ///<count of mutation operators 21 //@} 22 23 /** @name Codes for probabilities of mutating axiom words or rule words */ 24 //@{ 25 #define FL_AXM_WORD_MUT_PROB 0 ///<probability of performing addition, substitution or deletion of word in axiom 26 #define FL_RUL_WORD_MUT_PROB 1 ///<probability of performing addition, substitution or deletion of word in rule's successor 27 #define FL_MUTGROUPSCOUNT 2 ///<count of possible groups for mutations 28 //@} 29 30 /** @name Codes for probabilities of mutating word names or formula during change */ 31 //@{ 32 #define FL_CHG_WORD_FORMULA 0 ///<probability of changing formula of one of parameters 33 #define FL_CHG_WORD_NAME 1 ///<probability of changing word name to other word name with <= number of parameters 34 #define FL_CHG_COUNT 2 ///<count of possible changes in words 35 //@} 36 37 /** @name Codes for probabilities of choosing one of word types for addition */ 38 //@{ 39 #define FL_ADD_STICK 0 ///<probability of adding stick 40 #define FL_ADD_NEURO 1 ///<probability of adding neuron 41 #define FL_ADD_CONN 2 ///<probability of adding connection 42 #define FL_ADD_ROT 3 ///<probability of adding one of rotation words 43 #define FL_ADD_OTHER 4 ///<probability of adding word defined in the genotype 44 #define FL_ADD_BRANCH 5 ///<probability of adding a branch 45 #define FL_ADD_COUNT 6 ///<count of possible additions 46 //@} 5 47 6 48 class Geno_fL : public GenoOperators 7 49 { 50 private: 51 52 /** 53 * Adds word with a given definition to the list in place pointed by an iterator. 54 * @param list list, to which new word will be added 55 * @param definition temporal object that will act as pattern for newly created word 56 * @param it the iterator pointing to addition point 57 * @return true 58 */ 59 bool addWord(std::list<fL_Word *>* list, fL_Word *definition, std::list<fL_Word *>::iterator it); 60 61 /** 62 * Selects axiom or one of rule's successors. 63 * @param creature the object with defined axiom and rules 64 * @param numparams reference holding the number of parameters that are available for this list, 0 for axiom 65 * @param ruleid the index of the rule in rules structure or -1 if selected sequence is the axiom 66 * @return pointer to a selected sequence 67 */ 68 std::list<fL_Word *>* selectRandomSequence(fL_Builder *creature, int &numparams, int &ruleid); 69 70 /** 71 * Selects word definition according to a method. Method is one of 72 * values FL_ADD_STICK, FL_ADD_NEURO, FL_ADD_CONN, FL_ADD_ROT, FL_ADD_OTHER 73 * etc. If FL_ADD_OTHER is chosen, then one of defined words is chosen. If 74 * there are no defined words, then one of built-in words is chosen. 75 * If FL_ADD_BRANCH is selected, then method returns NULL. 76 * @param creature current genotype 77 * @param method one of methods of addition 78 * @return object defining one of genotype words, or NULL if branching method is used 79 */ 80 fL_Word* randomWordDefinition(fL_Builder *creature, int method); 81 82 /** 83 * Tries to find appropriate word in second creature that matches the word in first creature. 84 * Firstly, it tries to check if some word is not already assigned to a word in second creature. 85 * If the searching is successful, then appropriate word is used. Otherwise, method tries to find 86 * word that matches by name and number of parameters, or at least by number of parameters and hasn't 87 * been used already for other translation. If this is impossible, method creates new word definition 88 * for the second creature. 89 * @param from creature, from rule is taken 90 * @param to creature, which takes the rule 91 * @param fromword word from the first creature that needs to be translated 92 * @param map hashmap for current assignments 93 * @return word instance that need to be used by generated rule for the second genotype 94 */ 95 fL_Word* getAppropriateWord(fL_Builder *from, fL_Builder *to, fL_Word *fromword, std::unordered_map<std::string, std::string> &map); 96 97 /** 98 * Migrates random rule from one creature to the other creature. 99 * @param from creature, from rule is taken 100 * @param to creature, which takes the rule 101 * @param numselrules number of rules that need to be moved 102 */ 103 void migrateRandomRules(fL_Builder *from, fL_Builder *to, int numselrules); 104 105 /** 106 * Deletes branch from a given sequence starting from iterator. The deletion 107 * removes only braces, not whole branch. 108 * @param list current list that needs to be modified 109 * @param openbranchposition the iterator pointing to the open branch word 110 */ 111 void deleteBranch(std::list<fL_Word *> *list, std::list<fL_Word *>::iterator openbranchposition); 8 112 public: 113 double operations[FL_OPCOUNT]; ///<Relative probabilities of mutation types 114 double groupprobabilities[FL_MUTGROUPSCOUNT]; ///<Relative probabilities of changing elements in rules or axioms 115 double chgoperations[FL_CHG_COUNT]; ///<Relative probabilities of changing word names or parameters of word during change mutation 116 double addtypes[FL_ADD_COUNT]; ///<Relative probabilities of selecting special word types 117 118 double iterchangestep; ///<minimal value, by which time of development is modified 119 int maxdefinedwords; ///<maximal number of defined words for single fL genotype 120 9 121 Geno_fL(); 10 122 11 //int checkValidity(const char *geno, const char *genoname);123 int checkValidity(const char *geno, const char *genoname); 12 124 13 //int validate(char *&geno, const char *genoname);125 int validate(char *&geno, const char *genoname); 14 126 15 //int mutate(char *&geno, float& chg, int &method);127 int mutate(char *&geno, float& chg, int &method); 16 128 17 //int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);129 int crossOver(char *&g1, char *&g2, float& chg1, float& chg2); 18 130 19 // virtual const char* getSimplest() { return "5\naaazz"; }131 const char* getSimplest() { return "i:axiom=\"S()\", time=0, maxwords=300"; } 20 132 21 //uint32_t style(const char *geno, int pos);133 uint32_t style(const char *geno, int pos); 22 134 }; 23 135 24 #endif // _FL_OPER_ 136 #endif // _FL_OPER_H_
Note: See TracChangeset
for help on using the changeset viewer.