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

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

Improved the fS encoding

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