source: cpp/frams/genetics/fS/fS_oper.cpp @ 1006

Last change on this file since 1006 was 1006, checked in by Maciej Komosinski, 4 years ago

Improved the fS encoding

File size: 23.5 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 2019-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include <float.h>
6#include <assert.h>
7#include "fS_oper.h"
8#include "frams/util/rndutil.h"
9
10#define FIELDSTRUCT GenoOper_fS
11static ParamEntry genooper_fS_paramtab[] =
12                {
13                                {"Genetics: fS",            1, FS_OPCOUNT + 5,},
14                                {"fS_mut_add_part",         0, 0, "Add part",                    "f 0 100 10", FIELD(prob[FS_ADD_PART]),             "mutation: probability of adding a part",},
15                                {"fS_mut_rem_part",         0, 0, "Remove part",                 "f 0 100 10", FIELD(prob[FS_REM_PART]),             "mutation: probability of deleting a part",},
16                                {"fS_mut_mod_part",         0, 0, "Modify part",                 "f 0 100 10", FIELD(prob[FS_MOD_PART]),             "mutation: probability of changing the part type",},
17                                {"fS_mut_change_joint",     0, 0, "Change joint",                "f 0 100 10", FIELD(prob[FS_CHANGE_JOINT]),         "mutation: probability of changing a joint",},
18                                {"fS_mut_add_param",        0, 0, "Add param",                   "f 0 100 10", FIELD(prob[FS_ADD_PARAM]),            "mutation: probability of adding a parameter",},
19                                {"fS_mut_rem_param",        0, 0, "Remove param",                "f 0 100 10", FIELD(prob[FS_REM_PARAM]),            "mutation: probability of removing a parameter",},
20                                {"fS_mut_mod_param",        0, 0, "Modify param",                "f 0 100 10", FIELD(prob[FS_MOD_PARAM]),            "mutation: probability of modifying a parameter",},
21                                {"fS_mut_mod_mod",          0, 0, "Modify modifier",             "f 0 100 10", FIELD(prob[FS_MOD_MOD]),              "mutation: probability of modifying a modifier",},
22                                {"fS_mut_add_neuro",        0, 0, "Add neuron",                  "f 0 100 10", FIELD(prob[FS_ADD_NEURO]),            "mutation: probability of adding a neuron",},
23                                {"fS_mut_rem_neuro",        0, 0, "Remove neuron",               "f 0 100 10", FIELD(prob[FS_REM_NEURO]),            "mutation: probability of removing a neuron",},
24                                {"fS_mut_mod_neuro_conn",   0, 0, "Modify neuron connection",    "f 0 100 10", FIELD(prob[FS_MOD_NEURO_CONNECTION]), "mutation: probability of changing a neuron connection",},
25                                {"fS_mut_add_neuro_conn",   0, 0, "Add neuron connection",       "f 0 100 10", FIELD(prob[FS_ADD_NEURO_CONNECTION]), "mutation: probability of adding a neuron connection",},
26                                {"fS_mut_rem neuro_conn",   0, 0, "Remove neuron connection",    "f 0 100 10", FIELD(prob[FS_REM_NEURO_CONNECTION]), "mutation: probability of removing a neuron connection",},
27                                {"fS_mut_mod_neuro_params", 0, 0, "Modify neuron params",        "f 0 100 10", FIELD(prob[FS_MOD_NEURO_PARAMS]),     "mutation: probability of changing a neuron param",},
28                                {"fS_circle_section",       0, 0, "Ensure circle section",       "d 0 1 1",    FIELD(ensureCircleSection),           "Ensure that ellipsoids and cylinders have circle cross-section"},
29                                {"fS_use_elli",             0, 0, "Use ellipsoids in mutations", "d 0 1 1",    FIELD(useElli),                       "Use ellipsoids in mutations"},
30                                {"fS_use_cub",              0, 0, "Use cuboids in mutations",    "d 0 1 1",    FIELD(useCub),                        "Use cuboids in mutations"},
31                                {"fS_use_cyl",              0, 0, "Use cylinders in mutations",  "d 0 1 1",    FIELD(useCyl),                        "Use cylinders in mutations"},
32                                {"fS_mut_add_part_strong",  0, 0, "Strong add part mutation",    "d 0 1 1",    FIELD(strongAddPart),                 "Add part mutation will produce more parametrized parts"},
33                };
34
35#undef FIELDSTRUCT
36
37
38void GenoOper_fS::prepareParams()
39{
40        minValues = {
41                        {INGESTION, Model::getMinPart().ingest},
42                        {FRICTION,  Model::getMinPart().friction},
43                        {STIFFNESS, 0.1},
44                        {ROT_X,     -M_PI},
45                        {ROT_Y,     -M_PI},
46                        {ROT_Z,     -M_PI},
47                        {RX,        -M_PI},
48                        {RY,        -M_PI},
49                        {RZ,        -M_PI},
50                        {SIZE,      0.01},
51                        {SIZE_X,    Model::getMinPart().scale.x},
52                        {SIZE_Y,    Model::getMinPart().scale.y},
53                        {SIZE_Z,    Model::getMinPart().scale.z}
54        };
55
56        maxValues = {
57                        {INGESTION, Model::getMaxPart().ingest},
58                        {FRICTION,  Model::getMaxPart().friction},
59                        {STIFFNESS, 0.5},
60                        {ROT_X,     M_PI},
61                        {ROT_Y,     M_PI},
62                        {ROT_Z,     M_PI},
63                        {RX,        M_PI},
64                        {RY,        M_PI},
65                        {RZ,        M_PI},
66                        {SIZE,      100.0},
67                        {SIZE_X,    Model::getMaxPart().scale.x},
68                        {SIZE_Y,    Model::getMaxPart().scale.y},
69                        {SIZE_Z,    Model::getMaxPart().scale.z}
70        };
71}
72
73GenoOper_fS::GenoOper_fS()
74{
75        prepareParams();
76        par.setParamTab(genooper_fS_paramtab);
77        par.select(this);
78        par.setDefault();
79        supported_format = 'S';
80}
81
82int GenoOper_fS::checkValidity(const char *geno, const char *genoname)
83{
84        try
85        {
86                fS_Genotype genotype(geno);
87                int errorPosition = genotype.checkValidityOfPartSizes();
88                if (errorPosition != 0)
89                {
90                        logPrintf("GenoOper_fS", "checkValidity", LOG_WARN, "Invalid part size");
91                        return errorPosition;
92                }
93        }
94        catch (fS_Exception &e)
95        {
96                logPrintf("GenoOper_fS", "checkValidity", LOG_WARN, e.what());
97                return 1 + e.errorPosition;
98        }
99        return 0;
100}
101
102
103int GenoOper_fS::mutate(char *&geno, float &chg, int &method)
104{
105        try
106        {
107                fS_Genotype genotype(geno);
108
109                // Calculate available part types
110                vector <Part::Shape> availablePartShapes;
111                if (useElli)
112                        availablePartShapes.push_back(Part::Shape::SHAPE_ELLIPSOID);
113                if (useCub)
114                        availablePartShapes.push_back(Part::Shape::SHAPE_CUBOID);
115                if (useCyl)
116                        availablePartShapes.push_back(Part::Shape::SHAPE_CYLINDER);
117
118                // Select a mutation
119                bool result = false;
120                method = GenoOperators::roulette(prob, FS_OPCOUNT);
121                switch (method)
122                {
123                        case FS_ADD_PART:
124                                result = addPart(genotype, availablePartShapes);
125                                break;
126                        case FS_REM_PART:
127                                result = removePart(genotype);
128                                break;
129                        case FS_MOD_PART:
130                                result = changePartType(genotype, availablePartShapes);
131                                break;
132                        case FS_CHANGE_JOINT:
133                                result = changeJoint(genotype);
134                                break;
135                        case FS_ADD_PARAM:
136                                result = addParam(genotype);
137                                break;
138                        case FS_REM_PARAM:
139                                result = removeParam(genotype);
140                                break;
141                        case FS_MOD_PARAM:
142                                result = changeParam(genotype);
143                                break;
144                        case FS_MOD_MOD:
145                                result = changeModifier(genotype);
146                                break;
147                        case FS_ADD_NEURO:
148                                result = addNeuro(genotype);
149                                break;
150                        case FS_REM_NEURO:
151                                result = removeNeuro(genotype);
152                                break;
153                        case FS_MOD_NEURO_CONNECTION:
154                                result = changeNeuroConnection(genotype);
155                                break;
156                        case FS_ADD_NEURO_CONNECTION:
157                                result = addNeuroConnection(genotype);
158                                break;
159                        case FS_REM_NEURO_CONNECTION:
160                                result = removeNeuroConnection(genotype);
161                                break;
162                        case FS_MOD_NEURO_PARAMS:
163                                result = changeNeuroParam(genotype);
164                                break;
165                }
166
167                if (result)
168                {
169                        free(geno);
170                        geno = strdup(genotype.getGeno().c_str());
171                        return GENOPER_OK;
172                }
173                return GENOPER_OPFAIL;
174        }
175        catch (fS_Exception &e)
176        {
177                logPrintf("GenoOper_fS", "mutate", LOG_WARN, e.what());
178                return GENOPER_OPFAIL;
179        }
180}
181
182int GenoOper_fS::crossOver(char *&g0, char *&g1, float &chg0, float &chg1)
183{
184        try
185        {
186                assert(PARENT_COUNT == 2); // Cross over works only for 2 parents
187                fS_Genotype *parents[PARENT_COUNT] = {new fS_Genotype(g0), new fS_Genotype(g1)};
188
189                // Choose random subtrees that have similar size
190                Node *selected[PARENT_COUNT];
191                vector < Node * > allNodes0 = parents[0]->getAllNodes();
192                vector < Node * > allNodes1 = parents[1]->getAllNodes();
193
194                double bestQuotient = DBL_MAX;
195                for (int i = 0; i < crossOverTries; i++)
196                {
197                        Node *tmp0 = allNodes0[rndUint(allNodes0.size())];
198                        Node *tmp1 = allNodes1[rndUint(allNodes1.size())];
199                        // Choose this pair if it is the most similar
200                        double quotient = double(tmp0->getNodeCount()) / double(tmp1->getNodeCount());
201                        if (quotient < 1.0)
202                                quotient = 1.0 / quotient;
203                        if (quotient < bestQuotient)
204                        {
205                                bestQuotient = quotient;
206                                selected[0] = tmp0;
207                                selected[1] = tmp1;
208                        }
209                        if (bestQuotient == 1.0)
210                                break;
211                }
212
213                // Compute gene percentages in children
214                double subtreeSizes[PARENT_COUNT], restSizes[PARENT_COUNT];
215                for (int i = 0; i < PARENT_COUNT; i++)
216                {
217
218                        subtreeSizes[i] = selected[i]->getNodeCount();
219                        restSizes[i] = parents[i]->getNodeCount() - subtreeSizes[i];
220                }
221                chg0 = restSizes[0] / (restSizes[0] + subtreeSizes[1]);
222                chg1 = restSizes[1] / (restSizes[1] + subtreeSizes[0]);
223
224                // Rearrange neurons before crossover
225                int subOldStart[PARENT_COUNT] {-1, -1};
226                rearrangeConnectionsBeforeCrossover(parents[0], selected[0], subOldStart[0]);
227                rearrangeConnectionsBeforeCrossover(parents[1], selected[1], subOldStart[1]);
228
229                // Swap the subtress
230                for (int i = 0; i < PARENT_COUNT; i++)
231                {
232                        Node *other = selected[1 - i];
233                        Node *p = selected[i]->parent;
234                        if (p != nullptr)
235                        {
236                                size_t index = std::distance(p->children.begin(), std::find(p->children.begin(), p->children.end(), selected[i]));
237                                p->children[index] = other;
238                        } else
239                                parents[i]->startNode = other;
240                }
241
242                // Rearrange neurons after crossover
243                rearrangeConnectionsAfterCrossover(parents[0], selected[1], subOldStart[0]);
244                rearrangeConnectionsAfterCrossover(parents[1], selected[0], subOldStart[1]);
245
246                // Clenup, assign children to result strings
247                free(g0);
248                free(g1);
249                g0 = strdup(parents[0]->getGeno().c_str());
250                g1 = strdup(parents[1]->getGeno().c_str());
251
252                delete parents[0];
253                delete parents[1];
254        }
255        catch (fS_Exception &e)
256        {
257                logPrintf("GenoOper_fS", "crossOver", LOG_WARN, e.what());
258                return GENOPER_OPFAIL;
259        }
260        return GENOPER_OK;
261}
262
263const char *GenoOper_fS::getSimplest()
264{
265        return "1.1:C{x=0.80599;y=0.80599;z=0.80599}";
266}
267
268uint32_t GenoOper_fS::style(const char *geno, int pos)
269{
270        char ch = geno[pos];
271        uint32_t style = GENSTYLE_CS(0, GENSTYLE_NONE);
272        if (ch == ELLIPSOID || ch == CUBOID || ch == CYLINDER) // part type
273        {
274                style = GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
275        } else if (JOINTS.find(ch) != string::npos)    // Joint type
276        {
277                style = GENSTYLE_RGBS(0, 200, 200, GENSTYLE_BOLD);
278        } else if (MODIFIERS.find(ch) != string::npos) // Modifier
279        {
280                style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_NONE);
281        } else if (isdigit(ch) || strchr(".", ch)) // Numerical value
282        {
283                style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_NONE);
284        } else if (strchr("()_;[],=", ch))
285        {
286                style = GENSTYLE_CS(0, GENSTYLE_BOLD); // Important char
287        }
288
289        return style;
290}
291
292void GenoOper_fS::rearrangeConnectionsBeforeCrossover(fS_Genotype *geno, Node *sub, int &subStart)
293{
294        vector < fS_Neuron * > genoNeurons = geno->getAllNeurons();
295        vector < fS_Neuron * > subNeurons = fS_Genotype::extractNeurons(sub);
296
297        if (!subNeurons.empty())
298        {
299                subStart = fS_Genotype::getNeuronIndex(genoNeurons, subNeurons[0]);
300                fS_Genotype::shiftNeuroConnections(genoNeurons, subStart, subStart + subNeurons.size() - 1, SHIFT::LEFT);
301        }
302}
303
304void GenoOper_fS::rearrangeConnectionsAfterCrossover(fS_Genotype *geno, Node *sub, int subOldStart)
305{
306        vector < fS_Neuron * > genoNeurons = geno->getAllNeurons();
307        vector < fS_Neuron * > subNeurons = fS_Genotype::extractNeurons(sub);
308
309        // Shift the inputs right
310        if (!subNeurons.empty())
311        {
312                int subStart = fS_Genotype::getNeuronIndex(genoNeurons, subNeurons[0]);
313                int subCount = subNeurons.size();
314                int subEnd = subStart + subCount - 1;
315                for (int i = 0; i < subCount; i++)
316                {
317                        auto inputs = subNeurons[i]->inputs;
318                        std::map<int, double> newInputs;
319                        // TODO figure out how to keep internal connections in subtree
320//                      for (auto it = inputs.begin(); it != inputs.end(); ++it)
321//                      {
322//                              int newIndex = it->first + subStart;
323//                              if(subEnd > newIndex && newIndex > subStart)
324//                                      newInputs[newIndex] = it->second;
325//                      }
326                        subNeurons[i]->inputs = newInputs;
327                }
328                fS_Genotype::shiftNeuroConnections(genoNeurons, subStart, subEnd, SHIFT::RIGHT);
329        }
330}
331
332bool GenoOper_fS::addPart(fS_Genotype &geno, const vector <Part::Shape> &availablePartShapes, bool mutateSize)
333{
334        geno.getState();
335        Node *node = geno.chooseNode();
336        char partType = SHAPE_TO_GENE.at(availablePartShapes[rndUint(availablePartShapes.size())]);
337
338        Substring substring(&partType, 0, 1);
339        Node *newNode = new Node(substring, node, node->genotypeParams);
340        // Add random rotation
341        string rotationParams[] {ROT_X, ROT_Y, ROT_Z};
342        if (strongAddPart)
343        {
344                for (int i = 0; i < 3; i++)
345                        newNode->params[rotationParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
346        } else
347        {
348                string selectedParam = rotationParams[rndUint(3)];
349                newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
350        }
351        string rParams[] {RX, RY, RZ};
352        if (strongAddPart)
353        {
354                for (int i = 0; i < 3; i++)
355                        newNode->params[rParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
356        } else
357        {
358                string selectedParam = rParams[rndUint(3)];
359                newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
360        }
361        // Assign part size to default value
362        double volumeMultiplier = pow(node->getParam(SIZE) * node->state->s, 3);
363        double minVolume = Model::getMinPart().volume;
364        double defVolume = Model::getDefPart().volume * volumeMultiplier;    // Default value after applying modifiers
365        double maxVolume = Model::getMaxPart().volume;
366        double volume = std::min(maxVolume, std::max(minVolume, defVolume));
367        double relativeVolume = volume / volumeMultiplier;    // Volume without applying modifiers
368
369        double newRadius = std::cbrt(relativeVolume / volumeMultipliers.at(newNode->partType));
370        newNode->params[SIZE_X] = newRadius;
371        newNode->params[SIZE_Y] = newRadius;
372        newNode->params[SIZE_Z] = newRadius;
373        node->children.push_back(newNode);
374
375        if (mutateSize)
376        {
377                geno.getState();
378                mutateSizeParam(newNode, SIZE_X, true);
379                mutateSizeParam(newNode, SIZE_Y, true);
380                mutateSizeParam(newNode, SIZE_Z, true);
381        }
382        return true;
383}
384
385bool GenoOper_fS::removePart(fS_Genotype &geno)
386{
387        Node *randomNode, *selectedChild;
388        // Choose a parent with children
389        for (int i = 0; i < mutationTries; i++)
390        {
391                randomNode = geno.chooseNode();
392                int childCount = randomNode->children.size();
393                if (childCount > 0)
394                {
395                        int selectedIndex = rndUint(childCount);
396                        selectedChild = randomNode->children[selectedIndex];
397                        if (selectedChild->children.empty() && selectedChild->neurons.empty())
398                        {
399                                // Remove the selected child
400                                swap(randomNode->children[selectedIndex], randomNode->children[childCount - 1]);
401                                randomNode->children.pop_back();
402                                randomNode->children.shrink_to_fit();
403                                delete selectedChild;
404                                return true;
405                        }
406                }
407        }
408        return false;
409}
410
411bool GenoOper_fS::changePartType(fS_Genotype &geno, const vector <Part::Shape> &availablePartShapes)
412{
413        int availShapesLen = availablePartShapes.size();
414        for (int i = 0; i < mutationTries; i++)
415        {
416                Node *randomNode = geno.chooseNode();
417                int index = rndUint(availShapesLen);
418                if (availablePartShapes[index] == randomNode->partType)
419                        index = (index + 1 + rndUint(availShapesLen - 1)) % availShapesLen;
420                Part::Shape newType = availablePartShapes[index];
421
422#ifdef _DEBUG
423                if(newType == randomNode->partType)
424                        throw fS_Exception("Internal error: invalid part type chosen in mutation.", 1);
425#endif
426
427                geno.getState();
428                double sizeMultiplier = randomNode->getParam(SIZE) * randomNode->state->s;
429                double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
430
431                if (!ensureCircleSection || newType == Part::Shape::SHAPE_CUBOID || (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID && newType == Part::Shape::SHAPE_CYLINDER))
432                {
433                        double radiusQuotient = std::cbrt(volumeMultipliers.at(randomNode->partType) / volumeMultipliers.at(newType));
434                        randomNode->params[SIZE_X] = randomNode->getParam(SIZE_X) * radiusQuotient;
435                        randomNode->params[SIZE_Y] = randomNode->getParam(SIZE_Y) * radiusQuotient;
436                        randomNode->params[SIZE_Z] = randomNode->getParam(SIZE_Z) * radiusQuotient;
437                } else if (randomNode->partType == Part::Shape::SHAPE_CUBOID && newType == Part::Shape::SHAPE_CYLINDER)
438                {
439                        double newRadius = 0.5 * (randomNode->getParam(SIZE_X) + randomNode->getParam(SIZE_Y));
440                        randomNode->params[SIZE_X] = 0.5 * relativeVolume / (M_PI * newRadius * newRadius);
441                        randomNode->params[SIZE_Y] = newRadius;
442                        randomNode->params[SIZE_Z] = newRadius;
443                } else if (newType == Part::Shape::SHAPE_ELLIPSOID)
444                {
445                        double newRelativeRadius = cbrt(relativeVolume / volumeMultipliers.at(newType));
446                        randomNode->params[SIZE_X] = newRelativeRadius;
447                        randomNode->params[SIZE_Y] = newRelativeRadius;
448                        randomNode->params[SIZE_Z] = newRelativeRadius;
449                } else
450                {
451                        throw fS_Exception("Invalid part type", 1);
452                }
453                randomNode->partType = newType;
454                return true;
455        }
456        return false;
457}
458
459bool GenoOper_fS::changeJoint(fS_Genotype &geno)
460{
461        if (geno.startNode->children.empty())
462                return false;
463
464        Node *randomNode = geno.chooseNode(1);        // First part does not have joints
465        int jointLen = ALL_JOINTS.length();
466        int index = rndUint(jointLen);
467        if (ALL_JOINTS[index] == randomNode->joint)
468                index = (index + 1 + rndUint(jointLen - 1)) % jointLen;
469
470        randomNode->joint = ALL_JOINTS[index];
471        return true;
472}
473
474bool GenoOper_fS::addParam(fS_Genotype &geno)
475{
476        Node *randomNode = geno.chooseNode();
477        int paramCount = randomNode->params.size();
478        if (paramCount == int(PARAMS.size()))
479                return false;
480        string key = PARAMS[rndUint(PARAMS.size())];
481        if (randomNode->params.count(key) > 0)
482                return false;
483        // Do not allow invalid changes in part size
484        bool isRadiusOfBase = key == SIZE_Y || key == SIZE_Z;
485        bool isRadius = isRadiusOfBase || key == SIZE_X;
486        if (ensureCircleSection && isRadius)
487        if (ensureCircleSection && isRadius)
488        {
489                if (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID)
490                        return false;
491                if (randomNode->partType == Part::Shape::SHAPE_CYLINDER && isRadiusOfBase)
492                        return false;
493        }
494        // Add modified default value for param
495        randomNode->params[key] = mutateCreep('f', randomNode->defaultValues.at(key), minValues.at(key), maxValues.at(key), true);
496        return true;
497}
498
499bool GenoOper_fS::removeParam(fS_Genotype &geno)
500{
501        // Choose a node with params
502        for (int i = 0; i < mutationTries; i++)
503        {
504                Node *randomNode = geno.chooseNode();
505                int paramCount = randomNode->params.size();
506                if (paramCount >= 1)
507                {
508                        auto it = randomNode->params.begin();
509                        advance(it, rndUint(paramCount));
510                        randomNode->params.erase(it->first);
511                        return true;
512                }
513        }
514        return false;
515}
516
517bool GenoOper_fS::changeParam(fS_Genotype &geno)
518{
519        geno.getState();
520        for (int i = 0; i < mutationTries; i++)
521        {
522                Node *randomNode = geno.chooseNode();
523                int paramCount = randomNode->params.size();
524                if (paramCount >= 1)
525                {
526                        auto it = randomNode->params.begin();
527                        advance(it, rndUint(paramCount));
528
529                        // Do not allow invalid changes in part size
530                        if (std::find(SIZE_PARAMS.begin(), SIZE_PARAMS.end(), it->first) == SIZE_PARAMS.end())
531                        {
532                                it->second = GenoOperators::mutateCreep('f', it->second, minValues.at(it->first), maxValues.at(it->first), true);
533                                return true;
534                        } else
535                                return mutateSizeParam(randomNode, it->first, ensureCircleSection);
536                }
537        }
538        return false;
539}
540
541bool GenoOper_fS::changeModifier(fS_Genotype &geno)
542{
543        Node *randomNode = geno.chooseNode();
544        char randomModifier = MODIFIERS[rndUint(MODIFIERS.length())];
545        randomNode->modifiers[randomModifier] += rndUint(2) == 0 ? 1 : -1;
546
547        bool isSizeMod = tolower(randomModifier) == SIZE_MODIFIER;
548        if (isSizeMod && geno.checkValidityOfPartSizes() != 0)
549        {
550                randomNode->modifiers[randomModifier]++;
551                return false;
552        }
553        return true;
554}
555
556bool GenoOper_fS::addNeuro(fS_Genotype &geno)
557{
558        Node *randomNode = geno.chooseNode();
559        fS_Neuron *newNeuron;
560        NeuroClass *rndclass = GenoOperators::getRandomNeuroClass(Model::SHAPETYPE_SOLIDS);
561        if (rndclass->preflocation == NeuroClass::PREFER_JOINT && randomNode == geno.startNode)
562                return false;
563
564        const char *name = rndclass->getName().c_str();
565        newNeuron = new fS_Neuron(name, randomNode->partDescription->start, strlen(name));
566        int effectiveInputCount = rndclass->prefinputs > -1 ? rndclass->prefinputs : 1;
567        if (effectiveInputCount > 0)
568        {
569                // Create as many connections for the neuron as possible (at most prefinputs)
570                vector < fS_Neuron * > allNeurons = geno.getAllNeurons();
571                vector<int> neuronsWithOutput;
572                for (int i = 0; i < int(allNeurons.size()); i++)
573                {
574                        if (allNeurons[i]->getClass()->prefoutput > 0)
575                                neuronsWithOutput.push_back(i);
576                }
577                int size = neuronsWithOutput.size();
578                if (size > 0)
579                {
580                        for (int i = 0; i < effectiveInputCount; i++)
581                        {
582                                int selectedNeuron = neuronsWithOutput[rndUint(size)];
583                                newNeuron->inputs[selectedNeuron] = DEFAULT_NEURO_CONNECTION_WEIGHT;
584                        }
585                }
586        }
587
588        randomNode->neurons.push_back(newNeuron);
589
590        geno.rearrangeNeuronConnections(newNeuron, SHIFT::RIGHT);
591        return true;
592}
593
594bool GenoOper_fS::removeNeuro(fS_Genotype &geno)
595{
596        Node *randomNode = geno.chooseNode();
597        for (int i = 0; i < mutationTries; i++)
598        {
599                randomNode = geno.chooseNode();
600                if (!randomNode->neurons.empty())
601                {
602                        // Remove the selected neuron
603                        int size = randomNode->neurons.size();
604                        fS_Neuron *it = randomNode->neurons[rndUint(size)];
605                        geno.rearrangeNeuronConnections(it, SHIFT::LEFT);        // Important to rearrange the neurons before deleting
606                        swap(it, randomNode->neurons.back());
607                        randomNode->neurons.pop_back();
608                        randomNode->neurons.shrink_to_fit();
609                        delete it;
610                        return true;
611                }
612        }
613        return false;
614}
615
616bool GenoOper_fS::changeNeuroConnection(fS_Genotype &geno)
617{
618        vector < fS_Neuron * > neurons = geno.getAllNeurons();
619        if (neurons.empty())
620                return false;
621
622        int size = neurons.size();
623        for (int i = 0; i < mutationTries; i++)
624        {
625                fS_Neuron *selectedNeuron = neurons[rndUint(size)];
626                if (!selectedNeuron->inputs.empty())
627                {
628                        int inputCount = selectedNeuron->inputs.size();
629                        auto it = selectedNeuron->inputs.begin();
630                        advance(it, rndUint(inputCount));
631
632                        it->second = GenoOperators::getMutatedNeuronConnectionWeight(it->second);
633                        return true;
634                }
635        }
636        return false;
637}
638
639bool GenoOper_fS::addNeuroConnection(fS_Genotype &geno)
640{
641        vector < fS_Neuron * > neurons = geno.getAllNeurons();
642        if (neurons.empty())
643                return false;
644
645        int size = neurons.size();
646        fS_Neuron *selectedNeuron;
647        for (int i = 0; i < mutationTries; i++)
648        {
649                selectedNeuron = neurons[rndUint(size)];
650                if (selectedNeuron->acceptsInputs())
651                        break;
652        }
653        if (!selectedNeuron->acceptsInputs())
654                return false;
655
656        for (int i = 0; i < mutationTries; i++)
657        {
658                int index = rndUint(size);
659                if (selectedNeuron->inputs.count(index) == 0 && neurons[index]->getClass()->getPreferredOutput() > 0)
660                {
661
662                        selectedNeuron->inputs[index] = DEFAULT_NEURO_CONNECTION_WEIGHT;
663                        return true;
664                }
665        }
666        return false;
667}
668
669bool GenoOper_fS::removeNeuroConnection(fS_Genotype &geno)
670{
671        vector < fS_Neuron * > neurons = geno.getAllNeurons();
672        if (neurons.empty())
673                return false;
674
675        int size = neurons.size();
676        for (int i = 0; i < mutationTries; i++)
677        {
678                fS_Neuron *selectedNeuron = neurons[rndUint(size)];
679                if (!selectedNeuron->inputs.empty())
680                {
681                        int inputCount = selectedNeuron->inputs.size();
682                        auto it = selectedNeuron->inputs.begin();
683                        advance(it, rndUint(inputCount));
684                        selectedNeuron->inputs.erase(it->first);
685                        return true;
686                }
687        }
688        return false;
689}
690
691bool GenoOper_fS::changeNeuroParam(fS_Genotype &geno)
692{
693        vector < fS_Neuron * > neurons = geno.getAllNeurons();
694        if (neurons.empty())
695                return false;
696
697        fS_Neuron *neu = neurons[rndUint(neurons.size())];
698        return GenoOperators::mutateRandomNeuroClassProperty(neu);
699}
700
701bool GenoOper_fS::mutateSizeParam(Node *node, string key, bool ensureCircleSection)
702{
703        double oldValue = node->getParam(key);
704        double volume = node->calculateVolume();
705        double valueAtMinVolume, valueAtMaxVolume;
706        if(key == SIZE)
707        {
708                valueAtMinVolume = oldValue * std::cbrt(Model::getMinPart().volume / volume);
709                valueAtMaxVolume = oldValue * std::cbrt(Model::getMaxPart().volume / volume);
710        }
711        else
712        {
713                valueAtMinVolume = oldValue * Model::getMinPart().volume / volume;
714                valueAtMaxVolume = oldValue * Model::getMaxPart().volume / volume;
715        }
716
717        double min = std::max(minValues.at(key), valueAtMinVolume);
718        double max = std::min(maxValues.at(key), valueAtMaxVolume);
719
720        node->params[key] = GenoOperators::mutateCreep('f', node->getParam(key), min, max, true);
721
722        if (!ensureCircleSection || node->isPartSizeValid())
723                return true;
724        else
725        {
726                node->params[key] = oldValue;
727                return false;
728        }
729}
Note: See TracBrowser for help on using the repository browser.