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

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

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

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