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

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

Avoided potentially dangerous subtraction from unsigned int

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