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

Last change on this file since 1158 was 1158, checked in by Maciej Komosinski, 2 weeks ago

Cosmetic/minor improvements

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