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

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

fS: refactoring

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