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

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

Improved the fS encoding

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