source: cpp/frams/genetics/fS/fS_general.cpp @ 1017

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

fS: faster collision detection, depends on "geometry" algorithms

File size: 21.2 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 "fS_general.h"
7#include "frams/model/geometry/geometryutils.h"
8#include "frams/genetics/genooperators.h"
9#include "common/Convert.h"
10#include "frams/util/rndutil.h"
11#include "frams/neuro/neurolibrary.h"
12#include "../genooperators.h"
13#include "common/nonstd_math.h"
14#include "part_distance_estimator.h"
15
16int fS_Genotype::precision = 4;
17bool fS_Genotype::TURN_WITH_ROTATION = false;
18std::map<string, double> Node::minValues;
19std::map<string, double> Node::defaultValues;
20std::map<string, double> Node::maxValues;
21
22void Node::prepareParams()
23{
24        if(minValues.empty())
25        {
26                minValues = {
27                                {INGESTION, Model::getMinPart().ingest},
28                                {FRICTION,  Model::getMinPart().friction},
29                                {ROT_X,     -M_PI},
30                                {ROT_Y,     -M_PI},
31                                {ROT_Z,     -M_PI},
32                                {RX,        -M_PI},
33                                {RY,        -M_PI},
34                                {RZ,        -M_PI},
35                                {SIZE,      0.01},
36                                {SIZE_X,    Model::getMinPart().scale.x},
37                                {SIZE_Y,    Model::getMinPart().scale.y},
38                                {SIZE_Z,    Model::getMinPart().scale.z}
39                };
40        }
41
42        if(maxValues.empty())
43        {
44                maxValues = {
45                                {INGESTION, Model::getMaxPart().ingest},
46                                {FRICTION,  Model::getMaxPart().friction},
47                                {ROT_X,     M_PI},
48                                {ROT_Y,     M_PI},
49                                {ROT_Z,     M_PI},
50                                {RX,        M_PI},
51                                {RY,        M_PI},
52                                {RZ,        M_PI},
53                                {SIZE,      100.0},
54                                {SIZE_X,    Model::getMaxPart().scale.x},
55                                {SIZE_Y,    Model::getMaxPart().scale.y},
56                                {SIZE_Z,    Model::getMaxPart().scale.z}
57                };
58        }
59        if(defaultValues.empty())
60        {
61                defaultValues = {
62                                {INGESTION, Model::getDefPart().ingest},
63                                {FRICTION,  Model::getDefPart().friction},
64                                {ROT_X,     0.0},
65                                {ROT_Y,     0.0},
66                                {ROT_Z,     0.0},
67                                {RX,        0.0},
68                                {RY,        0.0},
69                                {RZ,        0.0},
70                                {SIZE,      1.0},
71                                {SIZE_X,    Model::getDefPart().scale.x},
72                                {SIZE_Y,    Model::getDefPart().scale.y},
73                                {SIZE_Z,    Model::getDefPart().scale.z}
74                };
75        }
76}
77
78double fS_stod(const string&  str, int start, size_t* size)
79{
80        try
81        {
82                return std::stod(str, size);
83        }
84        catch(const std::invalid_argument& ex)
85        {
86                throw fS_Exception("Invalid numeric value", start);
87        }
88        catch(const std::out_of_range& ex)
89        {
90                throw fS_Exception("Invalid numeric value; out of range", start);
91        }
92}
93
94State::State(State *_state)
95{
96        location = Pt3D(_state->location);
97        v = Pt3D(_state->v);
98        fr = _state->fr;
99        s = _state->s;
100}
101
102State::State(Pt3D _location, Pt3D _v)
103{
104        location = Pt3D(_location);
105        v = Pt3D(_v);
106}
107
108void State::addVector(const double length)
109{
110        location += v * length;
111}
112
113void State::rotate(const Pt3D &rotation)
114{
115       fS_Utils::rotateVector(v, rotation);
116       v.normalize();
117}
118
119
120fS_Neuron::fS_Neuron(const char *str, int _start, int length)
121{
122        start = _start + 1;
123        end = start + length;
124        if (length == 0)
125                return;
126
127        vector<SString> inputStrings;
128        strSplit(SString(str, length), NEURON_INTERNAL_SEPARATOR, false, inputStrings);
129        if (inputStrings.empty())
130                return;
131
132        int inputStart = 0;
133        SString details = "N";
134
135        SString tmp = inputStrings[0];
136        if(tmp.indexOf(':') != -1)
137                tmp = tmp.substr(0, tmp.indexOf(':'));
138
139        if (NeuroLibrary::staticlibrary.findClassIndex(tmp, true) != -1)
140        {
141                inputStart = 1;
142                details = inputStrings[0];
143        }
144        setDetails(details);
145
146        for (int i = inputStart; i < int(inputStrings.size()); i++)
147        {
148                SString keyValue = inputStrings[i];
149                int separatorIndex = keyValue.indexOf(NEURON_I_W_SEPARATOR);
150                const char *buffer = keyValue.c_str();
151                size_t keyLength;
152                double value;
153                if (separatorIndex == -1)
154                {
155                        keyLength = keyValue.length();
156                        value = DEFAULT_NEURO_CONNECTION_WEIGHT;
157                } else
158                {
159                        keyLength = separatorIndex;
160                        size_t valueLength = keyValue.length() - (separatorIndex);
161                        value = fS_stod(buffer + separatorIndex + 1, start, &valueLength);
162                }
163                inputs[fS_stod(buffer, start, &keyLength)] = value;
164        }
165}
166
167Node::Node(Substring &restOfGeno, Node *_parent, GenotypeParams _genotypeParams)
168{
169        prepareParams();
170        partDescription = new Substring(restOfGeno);
171        genotypeParams = _genotypeParams;
172        parent = _parent;
173
174        try
175        {
176                extractModifiers(restOfGeno);
177                extractPartType(restOfGeno);
178                extractNeurons(restOfGeno);
179                extractParams(restOfGeno);
180
181                partDescription->shortenBy(restOfGeno.len);
182                if (restOfGeno.len > 0)
183                        getChildren(restOfGeno);
184        }
185        catch(fS_Exception &e)
186        {
187                cleanUp();
188                throw e;
189        }
190}
191
192Node::~Node()
193{
194        cleanUp();
195}
196
197void Node::cleanUp()
198{
199        delete partDescription;
200        if (state != nullptr)
201                delete state;
202        for (int i = 0; i < int(neurons.size()); i++)
203                delete neurons[i];
204        for (int i = 0; i < int(children.size()); i++)
205                delete children[i];
206}
207
208int Node::getPartPosition(Substring &restOfGenotype)
209{
210        for (int i = 0; i < restOfGenotype.len; i++)
211        {
212                if (GENE_TO_SHAPE.find(restOfGenotype.at(i)) != GENE_TO_SHAPE.end())
213                        return i;
214        }
215        return -1;
216}
217
218void Node::extractModifiers(Substring &restOfGenotype)
219{
220        int partTypePosition = getPartPosition(restOfGenotype);
221        if (partTypePosition == -1)
222                throw fS_Exception("Part type missing", restOfGenotype.start);
223
224        for (int i = 0; i < partTypePosition; i++)
225        {
226                // Extract modifiers and joint
227                char mType = restOfGenotype.at(i);
228                if (JOINTS.find(tolower(mType)) != string::npos)
229                        joint = tolower(mType);
230                else if (MODIFIERS.find(toupper(mType)) != string::npos)
231                        modifiers[toupper(mType)] += isupper(mType) ? 1 : -1;
232                else
233                        throw fS_Exception("Invalid modifier", restOfGenotype.start + i);
234        }
235        restOfGenotype.startFrom(partTypePosition);
236}
237
238void Node::extractPartType(Substring &restOfGenotype)
239{
240        auto itr = GENE_TO_SHAPE.find(restOfGenotype.at(0));
241        if (itr == GENE_TO_SHAPE.end())
242                throw fS_Exception("Invalid part type", restOfGenotype.start);
243
244        partType = itr->second;
245        restOfGenotype.startFrom(1);
246}
247
248vector<int> getSeparatorPositions(const char *str, int len, char separator, char endSign, int &endIndex)
249{
250        endIndex = -1;
251        vector<int> separators {-1};
252        for (int i = 0; i < len; i++)
253        {
254                if (str[i] == separator)
255                        separators.push_back(i);
256                else if (str[i] == endSign)
257                {
258                        endIndex = i;
259                        break;
260                }
261        }
262        separators.push_back(endIndex); // End of string as last separator
263        return separators;
264}
265
266void Node::extractNeurons(Substring &restOfGenotype)
267{
268        if (restOfGenotype.len == 0 || restOfGenotype.at(0) != NEURON_START)
269                return;
270
271        const char *ns = restOfGenotype.c_str() + 1;
272        int neuronsEndIndex;
273        vector<int> separators = getSeparatorPositions(ns, restOfGenotype.len, NEURON_SEPARATOR, NEURON_END, neuronsEndIndex);
274        if(neuronsEndIndex == -1)
275                throw fS_Exception("Lacking neuro end sign", restOfGenotype.start);
276
277        for (int i = 0; i < int(separators.size()) - 1; i++)
278        {
279                int start = separators[i] + 1;
280                int length = separators[i + 1] - start;
281                fS_Neuron *newNeuron = new fS_Neuron(ns + start, restOfGenotype.start + start, length);
282                neurons.push_back(newNeuron);
283        }
284
285        restOfGenotype.startFrom(neuronsEndIndex + 2);
286}
287
288void Node::extractParams(Substring &restOfGenotype)
289{
290        if (restOfGenotype.len == 0 || restOfGenotype.at(0) != PARAM_START)
291                return;
292
293        const char *paramString = restOfGenotype.c_str() + 1;
294
295        // Find the indexes of the parameter separators
296        int paramsEndIndex;
297        vector<int> separators = getSeparatorPositions(paramString, restOfGenotype.len, PARAM_SEPARATOR, PARAM_END, paramsEndIndex);
298        if(paramsEndIndex == -1)
299                throw fS_Exception("Lacking param end sign", restOfGenotype.start);
300
301        for (int i = 0; i < int(separators.size()) - 1; i++)
302        {
303                int start = separators[i] + 1;
304                int length = separators[i + 1] - start;
305                const char *buffer = paramString + start;
306
307                // Find the index of key-value separator
308                int separatorIndex = -1;
309                for (int i = 0; i < length; i++)
310                {
311                        if (buffer[i] == PARAM_KEY_VALUE_SEPARATOR)
312                        {
313                                separatorIndex = i;
314                                break;
315                        }
316                }
317                if (-1 == separatorIndex)
318                        throw fS_Exception("Parameter separator expected", restOfGenotype.start);
319
320                // Compute the value of parameter and assign it to the key
321                int valueStartIndex = separatorIndex + 1;
322                string key(buffer, separatorIndex);
323                if(std::find(PARAMS.begin(), PARAMS.end(), key) == PARAMS.end())
324                        throw fS_Exception("Invalid parameter key", restOfGenotype.start + start);
325
326                const char *val = buffer + valueStartIndex;
327                size_t len = length - valueStartIndex;
328                double value = fS_stod(val, restOfGenotype.start + start + valueStartIndex, &len);
329                if((key==SIZE_X || key==SIZE_Y || key==SIZE_Z) && value <= 0.0)
330                        throw fS_Exception("Invalid value of radius parameter", restOfGenotype.start + start + valueStartIndex);
331
332                params[key] = value;
333
334        }
335
336        restOfGenotype.startFrom(paramsEndIndex + 2);
337}
338
339double Node::getParam(const string &key)
340{
341        auto item = params.find(key);
342        if (item != params.end())
343                return item->second;
344        return defaultValues.at(key);
345}
346
347double Node::getParam(const string &key, double defaultValue)
348{
349        auto item = params.find(key);
350        if (item != params.end())
351                return item->second;
352        return defaultValue;
353}
354
355
356void Node::getState(State *_state, bool calculateLocation)
357{
358        if (state != nullptr)
359                delete state;
360        if (parent == nullptr)
361                state = _state;
362        else
363                state = new State(_state);
364
365
366        // Update state by modifiers
367        for (auto it = modifiers.begin(); it != modifiers.end(); ++it)
368        {
369                char mod = it->first;
370                double multiplier = pow(genotypeParams.modifierMultiplier, it->second);
371                if (mod == MODIFIERS[0])
372                        state->ing *= multiplier;
373                else if (mod == MODIFIERS[1])
374                        state->fr *= multiplier;
375                else if (mod == MODIFIERS[2])
376                        state->s *= multiplier;
377        }
378
379        if (parent != nullptr && calculateLocation)
380        {
381                // Rotate
382                state->rotate(getVectorRotation());
383
384                double distance = getDistance();
385                state->addVector(distance);
386        }
387        for (int i = 0; i < int(children.size()); i++)
388                children[i]->getState(state, calculateLocation);
389}
390
391void Node::getChildren(Substring &restOfGenotype)
392{
393        vector<Substring> branches = getBranches(restOfGenotype);
394        for (int i = 0; i < int(branches.size()); i++)
395        {
396                children.push_back(new Node(branches[i], this, genotypeParams));
397        }
398}
399
400vector<Substring> Node::getBranches(Substring &restOfGenotype)
401{
402        vector<Substring> children;
403        if (restOfGenotype.at(0) != BRANCH_START)
404        {
405                children.push_back(restOfGenotype);  // Only one child
406                return children;
407        }
408
409        int depth = 0;
410        int start = 1;
411        char c;
412        const char *str = restOfGenotype.c_str();
413        for (int i = 0; i < restOfGenotype.len; i++)
414        {
415                if (depth < 0)
416                        throw fS_Exception("The number of branch start signs does not equal the number of branch end signs", restOfGenotype.start + i);
417                c = str[i];
418                if (c == BRANCH_START)
419                        depth++;
420                else if ((c == BRANCH_SEPARATOR && depth == 1) || i + 1 == restOfGenotype.len)
421                {
422                        Substring substring(restOfGenotype);
423                        substring.startFrom(start);
424                        substring.len = i - start;
425                        children.push_back(substring);
426                        start = i + 1;
427                } else if (c == BRANCH_END)
428                        depth--;
429        }
430        if (depth != 1)    // T
431                throw fS_Exception("The number of branch start signs does not equal the number of branch end signs", restOfGenotype.start);
432        return children;
433}
434
435void Node::calculateSize(Pt3D &scale)
436{
437        double sizeMultiplier = getParam(SIZE) * state->s;
438        scale.x = getParam(SIZE_X) * sizeMultiplier;
439        scale.y = getParam(SIZE_Y) * sizeMultiplier;
440        scale.z = getParam(SIZE_Z) * sizeMultiplier;
441}
442
443double Node::calculateVolume()
444{
445        double result;
446        Pt3D size;
447        calculateSize(size);
448        double radiiProduct = size.x * size.y * size.z;
449        switch (partType)
450        {
451                case Part::Shape::SHAPE_CUBOID:
452                        result = 8.0 * radiiProduct;
453                        break;
454                case Part::Shape::SHAPE_CYLINDER:
455                        result = 2.0 * M_PI * radiiProduct;
456                        break;
457                case Part::Shape::SHAPE_ELLIPSOID:
458                        result = (4.0 / 3.0) * M_PI * radiiProduct;
459                        break;
460                default:
461                        logMessage("fS", "calculateVolume", LOG_ERROR, "Invalid part type");
462        }
463        return result;
464}
465
466bool Node::isPartSizeValid()
467{
468        Pt3D size;
469        calculateSize(size);
470        double volume = calculateVolume();
471        Part_MinMaxDef minP = Model::getMinPart();
472        Part_MinMaxDef maxP = Model::getMaxPart();
473
474        if (volume > maxP.volume || minP.volume > volume)
475                return false;
476        if (size.x < minP.scale.x || size.y < minP.scale.y || size.z < minP.scale.z)
477                return false;
478        if (size.x > maxP.scale.x || size.y > maxP.scale.y || size.z > maxP.scale.z)
479                return false;
480
481        if (partType == Part::Shape::SHAPE_ELLIPSOID && fS_Utils::max3(size) != fS_Utils::min3(size))
482                // When not all radii have different values
483                return false;
484        if (partType == Part::Shape::SHAPE_CYLINDER && size.y != size.z)
485                // If base radii have different values
486                return false;
487        return true;
488}
489
490bool Node::hasPartSizeParam()
491{
492        return params.count(SIZE_X) > 0 || params.count(SIZE_Y) > 0 || params.count(SIZE_Z) > 0;
493}
494
495Pt3D Node::getVectorRotation()
496{
497        return Pt3D(getParam(ROT_X, 0.0), getParam(ROT_Y, 0.0), getParam(ROT_Z, 0.0));
498}
499
500Pt3D Node::getRotation()
501{
502        Pt3D rotation = Pt3D(getParam(RX, 0.0), getParam(RY, 0.0), getParam(RZ, 0.0));
503        if(fS_Genotype::TURN_WITH_ROTATION)
504                rotation += getVectorRotation();
505        return rotation;
506}
507
508void Node::buildModel(Model &model, Node *parent)
509{
510        createPart();
511        model.addPart(part);
512        if (parent != nullptr)
513                addJointsToModel(model, parent);
514
515        for (int i = 0; i < int(neurons.size()); i++)
516        {
517                Neuro *neuro = new Neuro(*neurons[i]);
518                model.addNeuro(neuro);
519                neuro->addMapping(MultiRange(IRange(neurons[i]->start, neurons[i]->end)));
520                if (neuro->getClass()->preflocation == NeuroClass::PREFER_JOINT && parent != nullptr)
521                {
522                        neuro->attachToJoint(model.getJoint(model.getJointCount() - 1));
523                } else
524                        neuro->attachToPart(part);
525        }
526
527        model.checkpoint();
528        part->addMapping(partDescription->toMultiRange());
529
530        for (int i = 0; i < int(children.size()); i++)
531        {
532                Node *child = children[i];
533                child->buildModel(model, this);
534        }
535}
536
537void Node::createPart()
538{
539        part = new Part(partType);
540        part->p = Pt3D(state->location);
541
542        part->friction = getParam(FRICTION) * state->fr;
543        part->ingest = getParam(INGESTION) * state->ing;
544        calculateSize(part->scale);
545        part->setRot(getRotation());
546}
547
548void Node::addJointsToModel(Model &model, Node *parent)
549{
550        Joint *j = new Joint();
551        j->attachToParts(parent->part, part);
552        switch (joint)
553        {
554                case HINGE_X:
555                        j->shape = Joint::Shape::SHAPE_HINGE_X;
556                        break;
557                case HINGE_XY:
558                        j->shape = Joint::Shape::SHAPE_HINGE_XY;
559                        break;
560                default:
561                        j->shape = Joint::Shape::SHAPE_FIXED;
562        }
563        model.addJoint(j);
564        j->addMapping(partDescription->toMultiRange());
565}
566
567
568void Node::getGeno(SString &result)
569{
570        if (joint != DEFAULT_JOINT)
571                result += joint;
572        for (auto it = modifiers.begin(); it != modifiers.end(); ++it)
573        {
574                char mod = it->first;
575                int count = it->second;
576                if(it->second < 0)
577                {
578                        mod = tolower(mod);
579                        count = fabs(count);
580                }
581                result += std::string(count, mod).c_str();
582        }
583        result += SHAPE_TO_GENE.at(partType);
584
585        if (!neurons.empty())
586        {
587                // Add neurons to genotype string
588                result += NEURON_START;
589                for (int i = 0; i < int(neurons.size()); i++)
590                {
591                        fS_Neuron *n = neurons[i];
592                        if (i != 0)
593                                result += NEURON_SEPARATOR;
594
595                        result += n->getDetails();
596                        if (!n->inputs.empty())
597                                result += NEURON_INTERNAL_SEPARATOR;
598
599                        for (auto it = n->inputs.begin(); it != n->inputs.end(); ++it)
600                        {
601                                if (it != n->inputs.begin())
602                                        result += NEURON_INTERNAL_SEPARATOR;
603                                result += SString::valueOf(it->first);
604                                if (it->second != DEFAULT_NEURO_CONNECTION_WEIGHT)
605                                {
606                                        result += NEURON_I_W_SEPARATOR;
607                                        result += SString::valueOf(it->second);
608                                }
609                        }
610                }
611                result += NEURON_END;
612        }
613
614        if (!params.empty())
615        {
616                // Add parameters to genotype string
617                result += PARAM_START;
618                for (auto it = params.begin(); it != params.end(); ++it)
619                {
620                        if (it != params.begin())
621                                result += PARAM_SEPARATOR;
622
623                        result += it->first.c_str();                    // Add parameter key to string
624                        result += PARAM_KEY_VALUE_SEPARATOR;
625                        // Round the value to two decimal places and add to string
626                        result += doubleToString(it->second, fS_Genotype::precision).c_str();
627                }
628                result += PARAM_END;
629        }
630
631        if (children.size() == 1)
632                children[0]->getGeno(result);
633        else if (children.size() > 1)
634        {
635                result += BRANCH_START;
636                for (int i = 0; i < int(children.size()) - 1; i++)
637                {
638                        children[i]->getGeno(result);
639                        result += BRANCH_SEPARATOR;
640                }
641                children.back()->getGeno(result);
642                result += BRANCH_END;
643        }
644}
645
646void Node::getAllNodes(vector<Node *> &allNodes)
647{
648        allNodes.push_back(this);
649        for (int i = 0; i < int(children.size()); i++)
650                children[i]->getAllNodes(allNodes);
651}
652
653int Node::getNodeCount()
654{
655        vector<Node*> allNodes;
656        getAllNodes(allNodes);
657        return allNodes.size();
658}
659
660fS_Genotype::fS_Genotype(const string &geno)
661{
662        try
663        {
664                GenotypeParams genotypeParams;
665                genotypeParams.modifierMultiplier = 1.1;
666
667                size_t modeSeparatorIndex = geno.find(MODE_SEPARATOR);
668                if (modeSeparatorIndex == string::npos)
669                        throw fS_Exception("Genotype parameters missing", 0);
670
671                genotypeParams.modifierMultiplier = fS_stod(geno, 0, &modeSeparatorIndex);
672
673                int genoStart = modeSeparatorIndex + 1;
674                Substring substring(geno.c_str(), genoStart, geno.length() - genoStart);
675                startNode = new Node(substring, nullptr, genotypeParams);
676                validateNeuroInputs();
677        }
678        catch (fS_Exception &e)
679        {
680                delete startNode;
681                throw e;
682        }
683}
684
685fS_Genotype::~fS_Genotype()
686{
687        delete startNode;
688}
689
690void fS_Genotype::getState(bool calculateLocation)
691{
692        State *initialState = new State(Pt3D(0), Pt3D(1, 0, 0));
693        startNode->getState(initialState, calculateLocation);
694}
695
696Model fS_Genotype::buildModel(bool using_checkpoints)
697{
698
699        Model model;
700        model.open(using_checkpoints);
701
702        getState(true);
703        startNode->buildModel(model, nullptr);
704        buildNeuroConnections(model);
705
706        model.close();
707        return model;
708}
709
710
711void fS_Genotype::buildNeuroConnections(Model &model)
712{
713        // All the neurons are already created in the model
714        vector<fS_Neuron*> allNeurons = getAllNeurons();
715        for (int i = 0; i < int(allNeurons.size()); i++)
716        {
717                fS_Neuron *neuron = allNeurons[i];
718                Neuro *modelNeuro = model.getNeuro(i);
719                for (auto it = neuron->inputs.begin(); it != neuron->inputs.end(); ++it)
720                {
721                        Neuro *inputNeuro = model.getNeuro(it->first);
722                        modelNeuro->addInput(inputNeuro, it->second);
723
724                }
725        }
726}
727
728Node *fS_Genotype::getNearestNode(vector<Node *> allNodes, Node *node)
729{
730        Node *result = nullptr;
731        double minDistance = DBL_MAX, distance = DBL_MAX;
732        for (int i = 0; i < int(allNodes.size()); i++)
733        {
734                Node *otherNode = allNodes[i];
735                auto v = node->children;
736                if (otherNode != node &&
737                        find(v.begin(), v.end(), otherNode) == v.end())
738                {   // Not the same node and not a child
739                        distance = node->state->location.distanceTo(otherNode->state->location);
740                        if (distance < minDistance)
741                        {
742                                minDistance = distance;
743                                result = otherNode;
744                        }
745                }
746        }
747        return result;
748}
749
750SString fS_Genotype::getGeno()
751{
752        SString geno;
753        geno.reserve(100);
754
755        geno += doubleToString(startNode->genotypeParams.modifierMultiplier, fS_Genotype::precision).c_str();
756        geno += MODE_SEPARATOR;
757
758        startNode->getGeno(geno);
759        return geno;
760}
761
762vector<fS_Neuron *> fS_Genotype::extractNeurons(Node *node)
763{
764        vector<Node*> allNodes;
765        node->getAllNodes(allNodes);
766
767        vector<fS_Neuron*> allNeurons;
768        for (int i = 0; i < int(allNodes.size()); i++)
769        {
770                for (int j = 0; j < int(allNodes[i]->neurons.size()); j++)
771                {
772                        allNeurons.push_back(allNodes[i]->neurons[j]);
773                }
774        }
775        return allNeurons;
776}
777
778int fS_Genotype::getNeuronIndex(vector<fS_Neuron *> neurons, fS_Neuron *changedNeuron)
779{
780        int neuronIndex = -1;
781        for (int i = 0; i < int(neurons.size()); i++)
782        {
783                if (changedNeuron == neurons[i])
784                {
785                        neuronIndex = i;
786                        break;
787                }
788        }
789        return neuronIndex;
790}
791
792void fS_Genotype::shiftNeuroConnections(vector<fS_Neuron *> &neurons, int start, int end, SHIFT shift)
793{
794        if (start == -1 || end == -1)
795                return;
796        int shiftValue = end - start + 1;
797        if (shift == SHIFT::LEFT)
798                shiftValue *= -1;
799
800        for (int i = 0; i < int(neurons.size()); i++)
801        {
802                fS_Neuron *n = neurons[i];
803                std::map<int, double> newInputs;
804                for (auto it = n->inputs.begin(); it != n->inputs.end(); ++it)
805                {
806                        if (start > it->first)
807                                newInputs[it->first] = it->second;
808                        else if (it->first >= start)
809                        {
810                                if (end >= it->first)
811                                {
812                                        if (shift == SHIFT::RIGHT)
813                                                newInputs[it->first + shiftValue] = it->second;
814                                        // If shift == -1, just delete the input
815                                } else if (it->first > end)
816                                        newInputs[it->first + shiftValue] = it->second;
817                        }
818                }
819                n->inputs = newInputs;
820        }
821}
822
823vector<Node *> fS_Genotype::getAllNodes()
824{
825        vector<Node*> allNodes;
826        startNode->getAllNodes(allNodes);
827        return allNodes;
828}
829
830vector<fS_Neuron *> fS_Genotype::getAllNeurons()
831{
832        return extractNeurons(startNode);
833}
834
835Node *fS_Genotype::chooseNode(int fromIndex)
836{
837        vector<Node*> allNodes = getAllNodes();
838        return allNodes[fromIndex + rndUint(allNodes.size() - fromIndex)];
839}
840
841int fS_Genotype::getNodeCount()
842{
843        return startNode->getNodeCount();
844}
845
846int fS_Genotype::checkValidityOfPartSizes()
847{
848        getState(false);
849        vector<Node*> nodes = getAllNodes();
850        for (int i = 0; i < int(nodes.size()); i++)
851        {
852                if (!nodes[i]->isPartSizeValid())
853                {
854                        return 1 + nodes[i]->partDescription->start;
855                }
856        }
857        return 0;
858}
859
860
861void fS_Genotype::validateNeuroInputs()
862{
863
864        // Validate neuro input numbers
865        vector<fS_Neuron*> allNeurons = getAllNeurons();
866        int allNeuronsSize = allNeurons.size();
867        for(int i=0; i<allNeuronsSize; i++)
868        {
869                fS_Neuron *n = allNeurons[i];
870                for (auto it = n->inputs.begin(); it != n->inputs.end(); ++it)
871                {
872                        if (it->first < 0 || it->first >= allNeuronsSize)
873                                throw fS_Exception("Invalid neuron input", 0);
874                }
875        }
876}
877
878
879void fS_Genotype::rearrangeNeuronConnections(fS_Neuron *changedNeuron, SHIFT shift)
880{
881        vector<fS_Neuron*> neurons = getAllNeurons();
882        int changedNeuronIndex = getNeuronIndex(neurons, changedNeuron);
883        shiftNeuroConnections(neurons, changedNeuronIndex, changedNeuronIndex, shift);
884}
885
Note: See TracBrowser for help on using the repository browser.