source: cpp/frams/genetics/fS/fS_general.h @ 969

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

fS: preserved volume during shape-type changes

File size: 14.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#ifndef _FS_GENERAL_H_
6#define _FS_GENERAL_H_
7
8#include <iostream>
9#include <vector>
10#include <map>
11#include <unordered_map>
12#include <exception>
13#include "frams/model/model.h"
14#include "frams/util/multirange.h"
15
16/** @name Values of constants used in encoding */
17//@{
18#define BRANCH_START '('
19#define BRANCH_END ')'
20#define BRANCH_SEPARATOR '^'
21#define PARAM_START '{'
22#define PARAM_END '}'
23const char PARAM_SEPARATOR = ';';
24const char PARAM_KEY_VALUE_SEPARATOR = '=';
25#define NEURON_START '['
26const char NEURON_END = ']';
27const char NEURON_SEPARATOR = ';';
28const SString NEURON_INTERNAL_SEPARATOR("_");
29#define NEURON_I_W_SEPARATOR ':'
30//@}
31
32enum class SHIFT
33{
34        LEFT = -1,
35        RIGHT = 1
36};
37
38/** @name Every modifier changes the underlying value by this multiplier */
39const double MODIFIER_MULTIPLIER = 1.1;
40/**
41 * Used in finding the proper distance between the parts
42 * distance between spheres / sphere radius
43 * That default value can be changed in certain cases
44 * */
45const float SPHERE_RELATIVE_DISTANCE = 0.25;
46/**
47 * Used in finding the proper distance between the parts
48 * The maximal allowed value for
49 * maximal radius of the node / sphere radius
50 */
51const int MAX_DIAMETER_QUOTIENT = 30;
52/**
53 * The tolerance of the value of distance between parts
54 */
55const double SPHERE_DISTANCE_TOLERANCE = 0.99;
56
57
58/** @name Names of node parameters and modifiers*/
59//@{
60#define INGESTION "i"
61#define FRICTION "f"
62#define STIFFNESS "st"
63#define SIZE "s"
64#define SIZE_X "x"
65#define SIZE_Y "y"
66#define SIZE_Z "z"
67#define ROT_X "tx"
68#define ROT_Y "ty"
69#define ROT_Z "tz"
70#define RX "rx"
71#define RY "ry"
72#define RZ "rz"
73//@}
74/** @name Macros and values used in collision detection */
75//@{
76#define DISJOINT 0
77#define COLLISION 1
78#define ADJACENT 2
79//@}
80
81#define HINGE_X 'b'
82#define HINGE_XY 'c'
83
84const double DEFAULT_NEURO_CONNECTION_WEIGHT = 1.0;
85
86const char ELLIPSOID = 'E';
87const char CUBOID = 'C';
88const char CYLINDER = 'R';
89const std::unordered_map<Part::Shape, char> SHAPETYPE_TO_GENE = {
90                {Part::Shape::SHAPE_ELLIPSOID, ELLIPSOID},
91                {Part::Shape::SHAPE_CUBOID,    CUBOID},
92                {Part::Shape::SHAPE_CYLINDER,  CYLINDER},
93};
94
95// This map is inverse to SHAPE_TO_SYMBOL. Those two should be compatible
96const std::unordered_map<char, Part::Shape> GENE_TO_SHAPETYPE = {
97                {ELLIPSOID, Part::Shape::SHAPE_ELLIPSOID},
98                {CUBOID,    Part::Shape::SHAPE_CUBOID},
99                {CYLINDER,  Part::Shape::SHAPE_CYLINDER},
100};
101const int SHAPE_COUNT = 3;    // This should be the count of SHAPETYPE_TO_GENE and GENE_TO_SHAPETYPE
102
103const char DEFAULT_JOINT = 'a';
104const string JOINTS = "bc";
105const string ALL_JOINTS = "abc";
106const int JOINT_COUNT = JOINTS.length();
107const string MODIFIERS = "IFST";
108const char SIZE_MODIFIER = 's';
109const vector<string> PARAMS {INGESTION, FRICTION, ROT_X, ROT_Y, ROT_Z, RX, RY, RZ, SIZE, SIZE_X, SIZE_Y, SIZE_Z,
110                                                         STIFFNESS};
111
112/** @name Default values of node parameters*/
113static const Part defPart = Model::getDefPart();
114static const Joint defJoint = Model::getDefJoint();
115const std::map<Part::Shape, double> volumeMultipliers = {
116                {Part::Shape::SHAPE_CUBOID, 8.0},
117                {Part::Shape::SHAPE_CYLINDER, 2.0 * M_PI},
118                {Part::Shape::SHAPE_ELLIPSOID, (4.0 / 3.0) * M_PI},
119};
120const std::map<string, double> defaultValues = {
121                {INGESTION,      defPart.ingest},
122                {FRICTION,       defPart.friction},
123                {STIFFNESS,              defJoint.stif},
124                {ROT_X,          0.0},
125                {ROT_Y,          0.0},
126                {ROT_Z,          0.0},
127                {RX,             0.0},
128                {RY,             0.0},
129                {RZ,             0.0},
130                {SIZE,           1.0},
131                {SIZE_X,         1.0},
132                {SIZE_Y,         1.0},
133                {SIZE_Z,         1.0}
134};
135
136const std::map<string, double> minValues = {
137                {INGESTION,      0},
138                {FRICTION,       0},
139                {STIFFNESS,      0.0},
140                {ROT_X,          -M_PI},
141                {ROT_Y,          -M_PI},
142                {ROT_Z,          -M_PI},
143                {RX,             -M_PI},
144                {RY,             -M_PI},
145                {RZ,             -M_PI},
146                {SIZE,           0.01},
147                {SIZE_X,         0.01},
148                {SIZE_Y,         0.01},
149                {SIZE_Z,         0.01}
150};
151
152const std::map<string, double> maxValues = {
153                {INGESTION,      1.0},
154                {FRICTION,       1.0},
155                {STIFFNESS,      0.0},
156                {ROT_X,          M_PI},
157                {ROT_Y,          M_PI},
158                {ROT_Z,          M_PI},
159                {RX,             M_PI},
160                {RY,             M_PI},
161                {RZ,             M_PI},
162                {SIZE,           100.0},
163                {SIZE_X,         100.0},
164                {SIZE_Y,         100.0},
165                {SIZE_Z,         100.0}
166};
167
168/** @name Number of tries of performing a mutation before GENOPER_FAIL is returned */
169#define mutationTries  20
170
171class fS_Exception : public std::exception
172{
173        string msg;
174public:
175
176        int errorPosition;
177        virtual const char *what() const throw()
178        {
179                return msg.c_str();
180        }
181
182        fS_Exception(string _msg, int _errorPosition)
183        {
184                msg = _msg;
185                errorPosition = _errorPosition;
186        }
187};
188
189/**
190 * Draws an integer value from given range
191 * @param to maximal value
192 * @param from minimal value
193 * @return Drawn value
194 */
195int randomFromRange(int to, int from);
196
197/**
198 * Represents a substring of a larger string.
199 * The reference to the original string is stored along with indexes of beginning end length of the substring.
200 */
201class Substring
202{
203public:
204        char *str;        // Pointer to the beginning of the substring
205        int start;        // The beginning index of substring
206        int len;        // The length of substring
207
208        Substring(const char *_str, int _start, int _len)
209        {
210                str = (char *) _str + _start;
211                start = _start;
212                len = _len;
213        }
214
215        Substring(const Substring &other)
216        {
217                str = other.str;
218                start = other.start;
219                len = other.len;
220        }
221
222        const char *c_str()
223        {
224                return str;
225        }
226
227        SString substr(int relativeStart, int len)
228        {
229                const char *substrStart = str + relativeStart;
230                return SString(substrStart, len);
231        }
232
233        int indexOf(char ch)
234        {
235                for (int i = 0; i < len; i++)
236                        if (str[i] == ch)
237                                return i;
238                return -1;
239        }
240
241        void startFrom(int index)
242        {
243                str += index;
244                start += index;
245                len -= index;
246        }
247
248        void shortenBy(int charCount)
249        {
250                len = std::max(len - charCount, 0);
251        }
252
253        char at(int index)
254        {
255                return str[index];
256        }
257
258        /**
259         * Create a new instance of multirange, corresponding to the substring
260         * @return a created multirange
261         */
262        MultiRange toMultiRange()
263        {
264                MultiRange range;
265                range.add(start, start + len - 1);
266                return range;
267        }
268};
269
270/**
271 * Stores the state of the node.
272 * The state consists od current location, the direction in which the branch develops
273 * and the current default values of the parameters (default values can be changed by modifiers).
274 */
275class State
276{
277public:
278        Pt3D location;  /// Location of the node
279        Pt3D v;         /// The normalised vector in which current branch develops
280        double fr = 1.0;      /// Friction multiplier
281        double ing = 1.0;      /// Ingestion multiplier
282        double s = 1.0;      /// Size multipliers
283        double stif = 1.0;      /// Stiffness multipliers
284
285        State(State *_state); /// Derive the state from parent
286
287        State(Pt3D _location, Pt3D _v); /// Create the state from parameters
288
289        /**
290         * Add the vector of specified length to location
291         * @param length the length of the vector
292         */
293        void addVector(const double length);
294
295        /**
296         * Rotate the vector by specified values
297         * @param rx rotation by x axis
298         * @param ry rotation by y axis
299         * @param rz rotation by z axis
300         */
301        void rotate(const Pt3D &rotation);
302};
303
304/**
305 * Represent a neuron and its inputs
306 */
307class fS_Neuron: public Neuro
308{
309public:
310        std::map<int, double> inputs;
311
312        fS_Neuron(const char *str, int start, int length);
313
314        bool acceptsInputs()
315        {
316                return getClass()->prefinputs < int(inputs.size());
317        }
318};
319
320/**
321 * Represents a node in the graph that represents a genotype.
322 * A node corresponds to a single part.
323 * However, it also stores attributes that are specific to fS encoding, such as modifiers and joint types.
324 */
325class Node
326{
327        friend class fS_Genotype;
328
329        friend class GenoOper_fS;
330
331private:
332        Substring *partDescription = nullptr;
333        Node *parent;
334        Part *part;     /// A part object built from node. Used in building the Model
335        int partCodeLen; /// The length of substring that directly describes the corresponding part
336
337        std::map<string, double> params; /// The map of all the node params
338        vector<Node *> children;    /// Vector of all direct children
339        std::map<char, int> modifiers;     /// Vector of all modifiers
340        vector<fS_Neuron *> neurons;    /// Vector of all the neurons
341
342        double getDistance();
343
344        void cleanUp();
345
346        Pt3D getRotation();
347
348        Pt3D getVectorRotation();
349
350        bool isPartSizeValid();
351
352        bool hasPartSizeParam();
353
354        /**
355         * Get the position of part type in genotype
356         *
357         * @return the position of part type
358         */
359        int getPartPosition(Substring &restOfGenotype);
360
361        /**
362         * Extract modifiers from the rest of genotype
363         * @return the remainder of the genotype
364         */
365        void extractModifiers(Substring &restOfGenotype);
366
367        /**
368         * Extract part type from the rest of genotype
369         * @return the remainder of the genotype
370         */
371        void extractPartType(Substring &restOfGenotype);
372
373        /**
374         * Extract neurons from the rest of genotype
375         * @return the remainder of the genotype
376         */
377        void extractNeurons(Substring &restOfGenotype);
378
379        /**
380         * Extract params from the rest of genotype
381         * @return the length og the remainder of the genotype
382         */
383        void extractParams(Substring &restOfGenotype);
384
385        /**
386         * Extract child branches from the rest of genotype
387         * @return vector of child branches
388         */
389        vector<Substring> getBranches(Substring &restOfGenotype);
390
391        /**
392         * Get phenotypic state that derives from ancestors.
393         * Used when building model
394         * @param _state state of the parent
395         */
396        void getState(State *_state);
397
398        /**
399         * Build children internal representations from fS genotype
400         * @param restOfGenotype part of genotype that describes the subtree
401         */
402        void getChildren(Substring &restOfGenotype);
403
404        /**
405         * Create part object from internal representation
406         */
407        void createPart();
408
409        /**
410         * Add joints between current node and the specified child
411         * Used in building model
412         * @param mode pointer to build model
413         * @param child pointer to the child
414         */
415        void addJointsToModel(Model &model, Node *parent);
416
417        /**
418         * Get all the nodes from the subtree that starts in this node
419         * @param reference to vector which contains nodes
420         */
421        void getAllNodes(vector<Node *> &allNodes);
422
423
424        /**
425         * Build model from the subtree that starts in this node
426         * @param pointer to model
427         */
428        void buildModel(Model &model, Node *parent);
429
430public:
431        char joint = DEFAULT_JOINT;           /// Set of all joints
432        Part::Shape partType;  /// The type of the part
433        State *state = nullptr; /// The phenotypic state that inherits from ancestors
434
435        Node(Substring &genotype, Node *parent);
436
437        ~Node();
438
439        /**
440         * Get fS representation of the subtree that starts from this node
441         * @param result the reference to an object which is used to contain fS genotype
442         */
443        void getGeno(SString &result);
444
445        /**
446         * Calculate the effective size of the part (after applying all multipliers and params)
447         * @return The effective size
448         */
449        Pt3D calculateSize();
450
451        /**
452         * Calculate the effective volume of the part
453         * @return The effective volume
454         */
455        double calculateVolume();
456
457        /**
458         * Change the value of the size parameter by given multiplier
459         * Do not change the value if any of the size restrictions is not satisfied
460         * @param paramKey
461         * @param multiplier
462         * @param ensureCircleSection
463         * @return True if the parameter value was change, false otherwise
464         */
465        bool changeSizeParam(string paramKey,  bool ensureCircleSection);
466
467        /**
468         * Counts all the nodes in subtree
469         * @return node count
470         */
471        int getNodeCount();
472
473        /**
474         * Extract the value of parameter or return default if parameter not exists
475         * @return the param value
476         */
477        double getParam(string key);
478};
479
480/**
481 * Represents an fS genotype.
482 */
483class fS_Genotype
484{
485        friend class Node;
486
487        friend class GenoOper_fS;
488
489private:
490        /**
491         * Draws a node that has an index greater that specified
492         * @param fromIndex minimal index of the node
493         * @return pointer to drawn node
494         */
495        Node *chooseNode(int fromIndex=0);
496
497        /**
498         * Draws a value from defined distribution
499         * @return Drawn value
500         */
501        void randomFromDistribution();
502
503        /**
504         * Find a node that is nearest (euclidean distance to specified node) and is not a child of specified node
505         * @return Nearest node
506         */
507        Node *getNearestNode(vector<Node *> allNodes, Node *node);
508
509public:
510        Node *startNode = nullptr;    /// The start (root) node. All other nodes are its descendants
511
512
513        static int precision;
514        static bool TURN_WITH_ROTATION;
515
516        /**
517         * Build internal representation from fS format
518         * @param genotype in fS format
519         */
520        fS_Genotype(const string &genotype);
521
522        ~fS_Genotype();
523
524        void getState();
525
526        /**
527         * Get all existing nodes
528         * @return vector of all nodes
529         */
530        vector<Node *> getAllNodes();
531
532        /**
533         * Get all the neurons from the subtree that starts in given node
534         * @param node The beginning of subtree
535         * @return The vector of neurons
536         */
537        static vector<fS_Neuron *> extractNeurons(Node *node);
538
539        /**
540         * Get the index of the neuron in vector of neurons
541         * @param neurons
542         * @param changedNeuron
543         * @return
544         */
545        static int getNeuronIndex(vector<fS_Neuron *> neurons, fS_Neuron *changedNeuron);
546
547        /**
548         * Left- or right- shift the indexes of neuro connections by the given range
549         * @param neurons
550         * @param start The beginning of the range
551         * @param end The end of the range
552         * @param shift
553         */
554        static void shiftNeuroConnections(vector<fS_Neuron *> &neurons, int start, int end, SHIFT shift);
555
556        /**
557         * Get all existing neurons
558         * @return vector of all neurons
559         */
560        vector<fS_Neuron *> getAllNeurons();
561
562        /**
563         * Counts all the nodes in genotype
564         * @return node count
565         */
566        int getNodeCount();
567
568        /**
569         * Check if sizes of all parts in genotype are valid
570        \retval error_position 1-based
571        \retval 0 when all part sizes are valid
572         */
573        int checkValidityOfPartSizes();
574
575        void validateNeuroInputs();
576
577        /**
578         * Builds Model object from internal representation
579         * @param a reference to a model that will contain a built model
580         */
581        void buildModel(Model &model);
582
583        /**
584         * Adds neuro connections to model
585         * @param a reference to a model where the connections will be added
586         */
587        void buildNeuroConnections(Model &model);
588
589        /**
590         * @return genotype in fS format
591         */
592        SString getGeno();
593
594        /**
595         * After creating or deleting a new neuron, rearrange other neurons so that the inputs match
596         */
597        void rearrangeNeuronConnections(fS_Neuron *newNeuron, SHIFT shift);
598
599};
600
601
602#endif
Note: See TracBrowser for help on using the repository browser.