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

Last change on this file since 969 was 969, checked in by Maciej Komosinski, 5 weeks ago

fS: preserved volume during shape-type changes

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