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

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

fS: refactoring

File size: 13.0 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 SCALE "s"
46#define SCALE_X "x"
47#define SCALE_Y "y"
48#define SCALE_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 SCALE_MODIFIER = 's';
86const vector<string> PARAMS {INGESTION, FRICTION, ROT_X, ROT_Y, ROT_Z, RX, RY, RZ, SCALE, SCALE_X, SCALE_Y, SCALE_Z};
87const vector<string> SCALE_PARAMS {SCALE, SCALE_X, SCALE_Y, SCALE_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        /// When calculating the distance between parts, the internal result is a range of numbers
250        /// distanceTolerance is the maximal allowed size of this range
251        double distanceTolerance;
252        /// Used for deriving density for MeshBuilder
253        double relativeDensity;
254        ///
255        bool turnWithRotation;
256        ///
257        double paramMutationStrength;
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        static std::map<string, double> minValues;      /// Min parameter values
277        static std::map<string, double> defaultValues;  /// Default parameter values
278        static std::map<string, double> maxValues;      /// Max parameter values
279
280        vector<Node *> children;    /// Vector of all direct children
281        std::map<char, int> modifiers;     /// Vector of all modifiers
282        vector<fS_Neuron *> neurons;    /// Vector of all the neurons
283
284        void prepareParams();
285
286        void cleanUp();
287
288        /// Get part's  rotation
289        Pt3D getRotation();
290
291        /// Get the rotation of vector
292        Pt3D getVectorRotation();
293
294        bool isPartScaleValid();
295
296        /**
297         * Get the position of part type in genotype
298         *
299         * @return the position of part type
300         */
301        int getPartPosition(Substring &restOfGenotype);
302
303        /**
304         * Extract modifiers from the rest of genotype
305         * @return the remainder of the genotype
306         */
307        void extractModifiers(Substring &restOfGenotype);
308
309        /**
310         * Extract part type from the rest of genotype
311         * @return the remainder of the genotype
312         */
313        void extractPartType(Substring &restOfGenotype);
314
315        /**
316         * Extract neurons from the rest of genotype
317         * @return the remainder of the genotype
318         */
319        void extractNeurons(Substring &restOfGenotype);
320
321        /**
322         * Extract params from the rest of genotype
323         * @return the length og the remainder of the genotype
324         */
325        void extractParams(Substring &restOfGenotype);
326
327        /**
328         * Extract child branches from the rest of genotype
329         * @return vector of child branches
330         */
331        vector<Substring> getBranches(Substring &restOfGenotype);
332
333        /**
334         * Get phenotypic state that derives from ancestors.
335         * Used when building model
336         * @param _state state of the parent
337         */
338        void getState(State *_state, bool calculateLocation);
339
340        /**
341         * Build children internal representations from fS genotype
342         * @param restOfGenotype part of genotype that describes the subtree
343         */
344        void getChildren(Substring &restOfGenotype);
345
346        /**
347         * Create part object from internal representation
348         */
349        void createPart();
350
351        /**
352         * Add joints between current node and the specified child
353         * Used in building model
354         * @param mode pointer to build model
355         * @param child pointer to the child
356         */
357        void addJointsToModel(Model &model, Node *parent);
358
359        /**
360         * Get all the nodes from the subtree that starts in this node
361         * @param reference to vector which contains nodes
362         */
363        void getAllNodes(vector<Node *> &allNodes);
364
365
366        /**
367         * Build model from the subtree that starts in this node
368         * @param pointer to model
369         */
370        void buildModel(Model &model, Node *parent);
371
372public:
373        char joint = DEFAULT_JOINT;           /// Set of all joints
374        Part::Shape partShape;  /// The type of the part
375        State *state = nullptr; /// The phenotypic state that inherits from ancestors
376        std::map<string, double> params; /// The map of all the node params
377        GenotypeParams genotypeParams; /// Parameters that affect the whole genotype
378
379        Node(Substring &genotype, Node *parent, GenotypeParams genotypeParams);
380
381        ~Node();
382
383        /**
384         * Get fS representation of the subtree that starts from this node
385         * @param result the reference to an object which is used to contain fS genotype
386         */
387        void getGeno(SString &result);
388
389        /**
390         * Calculate the effective scale of the part (after applying all multipliers and params)
391         * @return The effective scales
392         */
393        void calculateScale(Pt3D &scale);
394
395        /**
396         * Calculate the effective volume of the part
397         * @return The effective volume
398         */
399        double calculateVolume();
400
401        /**
402         * Counts all the nodes in subtree
403         * @return node count
404         */
405        int getNodeCount();
406
407        /**
408         * Extract the value of parameter or return default if parameter not exists
409         * @return the param value
410         */
411        double getParam(const string &key);
412        double getParam(const string &key, double defaultValue);
413
414        /// Calculate distance between the part its parent
415        double calculateDistanceFromParent();
416};
417
418/**
419 * Represents an fS genotype.
420 */
421class fS_Genotype
422{
423        friend class Node;
424
425        friend class GenoOper_fS;
426
427private:
428        /**
429         * Draws a node that has an index greater that specified
430         * @param fromIndex minimal index of the node
431         * @return pointer to drawn node
432         */
433        Node *chooseNode(int fromIndex=0);
434
435        /**
436         * Draws a value from defined distribution
437         * @return Drawn value
438         */
439        void randomFromDistribution();
440
441        /**
442         * Find a node that is nearest (euclidean distance to specified node) and is not a child of specified node
443         * @return Nearest node
444         */
445        Node *getNearestNode(vector<Node *> allNodes, Node *node);
446
447public:
448        Node *startNode = nullptr;    /// The start (root) node. All other nodes are its descendants
449
450
451        static int precision; /// Number of decimal places for numbers in genotype
452
453        /**
454         * Build internal representation from fS format
455         * @param genotype in fS format
456         */
457        fS_Genotype(const string &genotype);
458
459        ~fS_Genotype();
460
461        /// Calculate the State field for all the nodes
462        void getState(bool calculateLocation);
463
464        /**
465         * Get all existing nodes
466         * @return vector of all nodes
467         */
468        vector<Node *> getAllNodes();
469
470        /**
471         * Get all the neurons from the subtree that starts in given node
472         * @param node The beginning of subtree
473         * @return The vector of neurons
474         */
475        static vector<fS_Neuron *> extractNeurons(Node *node);
476
477        /**
478         * Get the index of the neuron in vector of neurons
479         * @param neurons
480         * @param changedNeuron
481         * @return
482         */
483        static int getNeuronIndex(vector<fS_Neuron *> neurons, fS_Neuron *changedNeuron);
484
485        /**
486         * Left- or right- shift the indexes of neuro connections by the given range
487         * @param neurons
488         * @param start The beginning of the range
489         * @param end The end of the range
490         * @param shift
491         */
492        static void shiftNeuroConnections(vector<fS_Neuron *> &neurons, int start, int end, SHIFT shift);
493
494        /**
495         * Get all existing neurons
496         * @return vector of all neurons
497         */
498        vector<fS_Neuron *> getAllNeurons();
499
500        /**
501         * Counts all the nodes in genotype
502         * @return node count
503         */
504        int getNodeCount();
505
506        /**
507         * Check if scales of all parts in genotype are valid
508        \retval error_position 1-based
509        \retval 0 when all part sizes are valid
510         */
511        int checkValidityOfPartSizes();
512
513        void validateNeuroInputs();
514
515        /**
516         * Builds Model object from internal representation
517         * @param a reference to a model that will contain a built model
518         */
519        Model buildModel(bool using_checkpoints);
520
521        /**
522         * Adds neuro connections to model
523         * @param a reference to a model where the connections will be added
524         */
525        void buildNeuroConnections(Model &model);
526
527        /**
528         * @return genotype in fS format
529         */
530        SString getGeno();
531
532        /**
533         * After creating or deleting a new neuron, rearrange other neurons so that the inputs match
534         */
535        void rearrangeNeuronConnections(fS_Neuron *newNeuron, SHIFT shift);
536
537};
538
539
540#endif
Note: See TracBrowser for help on using the repository browser.