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

Last change on this file since 1181 was 1130, checked in by Maciej Komosinski, 3 years ago

Used std::min(), std::max() explicitly to avoid compiler confusion. Used std::size() explicitly instead of the equivalent macro

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