source: cpp/frams/genetics/f4/f4_general.h

Last change on this file was 1259, checked in by Maciej Komosinski, 11 months ago

f4: three #define's -> enum, minor refactorizations, added comments

  • Property svn:eol-style set to native
File size: 18.0 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1227]2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[193]4
[196]5// Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
6
[193]7#ifndef _F4_GENERAL_H_
8#define _F4_GENERAL_H_
9
[196]10#include <frams/util/3d.h>
11#include <frams/util/sstring.h>
12#include <frams/util/multirange.h>
[760]13#include <frams/genetics/geneprops.h>
[193]14
15#ifdef DMALLOC
16#include <dmalloc.h>
17#endif
18
[760]19/**
20 * Performs single rotation angle decrementation on a given value.
21 * @param v pointer to the decremented value
22 */
[774]23void rolling_dec(double *v);
[193]24
[760]25/**
26 * Performs single rotation angle incrementation on a given value.
27 * @param v pointer to the incremented value
28 */
[774]29void rolling_inc(double *v);
[193]30
[1227]31class f4_Node;   // later
[193]32class f4_Cell;   // later
33class f4_Cells;  // later
34
[1259]35enum class f4_Cell_type {
36        CELL_UNDIFF, ///<undifferentiated cell
37        CELL_STICK,  ///<differentiated to stick, cannot divide
38        CELL_NEURON  ///<differentiated to neuron, can divide
39};
[193]40
[1227]41class f4_CellConn;
[193]42
[760]43/** @name Constraints of f4 genotype structures */
44//@{
[1227]45#define F4_MAX_CELL_INPUTS  10 ///<maximum number of neuron inputs in a developing organism
46#define F4_MAX_CELLS 100 ///<maximum number of f4 organism cells
[760]47//@}
48
49/**
[1227]50 * Abstract cell type - the representation of a single component in the developmental
[760]51 * encoding. In the beginning, each f4_Cell is undifferentiated. During the process
52 * of development it can divide or differentiate into a stick or a neuron. If it
53 * differentiates to a neuron, then it preserves the ability to divide, but divided
54 * cells will be the same type as the parent cell. If it is a stick, then it cannot
55 * be divided anymore.
56 *
57 * From f4_Cell array the final Model of a creature is created.
58 */
[193]59class f4_Cell
60{
61public:
[760]62        /**
63         * Represents the repetition marker. It holds information about the pointer
64         * to the repetition node and the count of repetitions.
65         */
[196]66        class repeat_ptr
67        {
68        public:
69                repeat_ptr() : node(NULL), count(-1) { };
[760]70
71                /**
72                 * A constructor that takes the pointer to the repetition node and the count of repetitions.
[1227]73                 * @param a pointer to f4_Node for repetition character
[760]74                 * @param b the number of repetitions
75                 */
[1227]76                repeat_ptr(f4_Node *a, int b) : node(a), count(b) { };
[760]77
78                inline void makeNull() { node = NULL; count = -1; };
79
[196]80                inline bool isNull() const { return ((node == NULL) || (count <= 0)); };
[760]81
[196]82                inline void dec() { count--; };
[1227]83                f4_Node    *node; ///<pointer to the repetition code
[767]84                int       count; ///<repetition counter
[196]85        };
[193]86
[760]87        /**
88         * Represents the stack of repeat_ptr objects. The objects are
89         * pushed to the stack when '#' repetition symbol appears, and are popped when
90         * the end of the current cell definition, i.e. the '>' character, appears. After the
91         * '>' character, the cell is duplicated as many times as it is defined after the
92         * repetition marker.
93         */
94        class repeat_stack
[196]95        {
96        public:
[760]97                repeat_stack() { top = 0; }
98
99                inline void clear() { top = 0; }
100
101                /**
102                 * Pushes repeat_ptr object onto the stack. If the stack size is exceeded, then no
103                 * information is provided.
104                 * @param rn repetition node info
105                 */
106                inline void push(repeat_ptr rn) { if (top >= stackSize) return; ptr[top] = rn; top++; }
107
108                inline void pop() { if (top > 0) top--; }
109
110                /**
111                 * Gets the current top element.
112                 * @return pointer to the element on top of the repeat_stack object
113                 */
114                inline repeat_ptr* first() { return &(ptr[top - (top > 0)]); };
115                static const int stackSize = 4;  ///<max 4 nested levels
116                repeat_ptr ptr[stackSize]; ///<array holding pointers to repeat_ptr
[1227]117                int top;  ///<index of the top of the stack
[196]118        };
[193]119
[760]120        /**
121         * Creates a new f4_Cell object.
[1227]122         * @param nnr number of the cell
[760]123         * @param ndad pointer to the parent of the created cell
124         * @param nangle the amount of commas affecting branch angles
125         * @param newP genotype properties of a given cell
126         */
[1227]127        f4_Cell(int nnr, f4_Cell *ndad, int nangle, GeneProps newP);
[760]128        /**
129         * Creates a new f4_Cell object.
130         * @param nO pointer to an organism containing the cell
[1227]131         * @param nnr number of the cell
[760]132         * @param ngeno pointer to the root of the genotype tree
[1227]133         * @param ngcur pointer to the f4_Node representing the current cell in the genotype tree
[760]134         * @param ndad pointer to the parent of the created cell
135         * @param nangle the number of commas affecting branch angles
136         * @param newP genotype properties of a given cell
137         */
[1227]138        f4_Cell(f4_Cells *nO, int nnr, f4_Node *ngeno, f4_Node *ngcur, f4_Cell *ndad, int nangle, GeneProps newP);
[760]139
[196]140        ~f4_Cell();
[193]141
[760]142        /**
[767]143         * Performs a single step of cell development. This method requires a pointer to
144         * the f4_Cells object in org attribute. If the current node in genotype tree
145         * is the branching character '<', the cell divides into two cells, unless the
146         * cell was already differentiated into the stick cell. Otherwise, the current
147         * differentiation or modification is performed on the cell. If current node is
148         * creating a connection between two neuron nodes and the input node is not
[1237]149         * yet developed, the simulation of the development of the current cell returns
150         * to wait until the input node is created. The oneStep method is deployed for every cell
151         * at least once. If one cell requires another one to develop, oneStep
152         * should be deployed again on this cell.
[1259]153         *
[1237]154         * This method, unlike genotype tree creation, checks semantics. This means that
155         * this function will fail (set error code) if:
[767]156         *  - the cell differentiated as a stick will have branching node '<',
157         *  - the undifferentiated cell will have termination node '>' (end of cell development without differentiation),
158         *  - the stack of repetition marker '#' will exceed maximum allowed value of repetition,
[760]159         *  - the stick modifiers, like rotation, will be applied on neuron cell,
160         *  - the differentiated cell will be differentiated again,
[767]161         *  - the connection between neurons cannot be established,
[760]162         *  - the neuron class is not valid.
163         *
[1237]164         * This function returns either because the development of this cell was completed,
165         * or it was halted (yielding to other cells), or the error code was set in the f4_Cells object in the org attribute.
[760]166         */
[1237]167        void oneStep();
[193]168
[760]169        /**
[1227]170         * Adds a connection between this neuron cell and a given neuron cell in nfrom.
171         * @param nfrom input neuron cell
172         * @param nweight weight of connection
173         * @return 0 if connection is established, -1 otherwise
[760]174         */
[1227]175        int   addConnection(f4_Cell *nfrom, double nweight);
[760]176
177        /**
178         * Adjusts properties of stick objects.
179         */
[1249]180        void  adjustRecur();
[193]181
[1249]182        int        nr;                 ///<number of cell (seems to be used only in the approximate f1 converter for neuron connections)
[1259]183        f4_Cell_type type;             ///<type
[767]184        f4_Cell *dadlink;              ///<pointer to cell parent
185        f4_Cells  *org;                ///<uplink to organism
[193]186
[1227]187        f4_Node *genot;                    ///<genotype tree
188        f4_Node *gcur;                 ///<current genotype execution pointer
[1239]189        f4_Node *old_gcur;             ///<used externally by f4_Cells::oneStep() to track changes of gcur, i.e., to detect progress in cell development
[760]190        repeat_stack repeat;           ///<stack holding repetition nodes and counters
[1249]191        bool recurProcessedFlag;       ///<used during recursive traverse
[760]192        MultiRange genoRange;          ///<remember the genotype codes affecting this cell so far
[193]193
[767]194        GeneProps    P;                ///<properties
[760]195        int          anglepos;         ///<number of position within dad's children (,)
[1249]196        int          stickchildcount;  ///<number of children (sticks only)
[760]197        int          commacount;       ///<number of postitions at lastend (>=childcount)
198        double       rolling;          ///<rolling angle ('R') (around x)
199        double       xrot;                         ///<rotation angle around x
200        double       zrot;             ///<horizontal rotation angle due to branching (around z)
[193]201
[767]202        int          p2_refno;         ///<the number of the last end part object, used in f0
203        int          joint_refno;      ///<the number of the joint object, used in f0
204        int          neuro_refno;      ///<the number of the neuro object, used in f0
[760]205
[1249]206        double       inertia;          ///<inertia of neuron N
207        double       force;            ///<force of neuron N
208        double       sigmo;            ///<sigmoid of neuron N
[1227]209        f4_CellConn *conns[F4_MAX_CELL_INPUTS]; ///<array of neuron connections
210        int          conns_count;      ///<number of connections
[767]211        NeuroClass *neuclass;          ///<pointer to neuron class
[193]212};
213
[760]214/**
[1227]215 * Class representing a connection between neuron cells.
[760]216 */
[1227]217class f4_CellConn
[193]218{
219public:
[760]220        /**
[767]221         * Constructor for f4_CellLink class. Parameter nfrom represents input
[1227]222         * neuron cell.
223         * @param nfrom pointer to input neuron cell
224         * @param nweight weight of connection
[760]225         */
[1227]226        f4_CellConn(f4_Cell *nfrom, double nweight);
[760]227
[1227]228        f4_Cell *from;  ///<pointer to input neuron cell
229        double weight;  ///<weight of connection
[193]230};
231
232
[760]233/**
[767]234 * A class representing a collection of cells. It is equivalent to an organism.
[760]235 */
[193]236class f4_Cells
237{
[196]238public:
[760]239
240        /**
241         * Constructor taking genotype in a form of a tree.
242         * @param genome genotype tree
[1231]243         * @param nrepair false if nothing to repair
[760]244         */
[1231]245        f4_Cells(f4_Node *genome, bool nrepair);
[760]246
247        /**
248         * Destructor removing cells from memory.
249         */
[196]250        ~f4_Cells();
[760]251
252        /**
[767]253         * Adds a new cell to organism.
[760]254         * @param newcell cell to be added
255         */
[767]256        void addCell(f4_Cell *newcell);
[760]257
258        /**
[767]259         * Creates an approximate genotype in the f1 encoding and stores it in a given parameter.
260         * @param out the string in which the approximate f1 genotype will be stored
[760]261         */
262        void toF1Geno(SString &out);
263
264        /**
[1227]265         * Performs a single step of organism development. It runs each active cell in the organism.
266         * @return false if all cells are developed or there is an error, true otherwise
[760]267         */
[1227]268        bool oneStep();
[760]269
270        /**
[767]271         * Performs the full development of organism and returns error code if something
[760]272         * went wrong.
273         * @return 0 if organism developed successfully, error code if something went wrong
274         */
[1227]275        int simulate();
[760]276
277        /**
[1227]278         * Prints the current state of the organism (for debugging purposes).
279         * @param description printout header
280         */
281        void print_cells(const char* description);
282
283        /**
[767]284         * Returns error code of the last simulation.
[760]285         * @return error code
286         */
[1227]287        int getErrorCode() { return errorcode; };
[760]288
289        /**
[767]290         * Returns position of an error in genotype.
291         * @return position of an error
[760]292         */
[1227]293        int getErrorPos() { return errorpos; };
[760]294
295        /**
[767]296         * Sets error code GENOPER_OPFAIL for a simulation on a given position.
297         * @param nerrpos position of an error
[760]298         */
[196]299        void setError(int nerrpos);
[760]300
301        /**
302         * Sets the element of genotype to be repaired by removal.
[767]303         * @param nerrpos position of an error in genotype
[1232]304         * @param to_remove the f4_Node to be removed from the genotype tree in order to repair
[760]305         */
[1232]306        void setRepairRemove(int nerrpos, f4_Node *to_remove);
[760]307
308        /**
[767]309         * Sets repairing of a genotype by inserting a new node to the current genotype.
310         * @param nerrpos position of an error in genotype
311         * @param parent the parent of a new element
[1232]312         * @param to_insert the element to be inserted
[774]313         * @return 0 if repair can be performed, or -1 otherwise because the repair flag wasn't set in the constructor
[760]314         */
[1232]315        int setRepairInsert(int nerrpos, f4_Node *parent, f4_Node *to_insert);
[760]316
317        /**
[767]318         * Repairs the genotype according to setRepairRemove or setRepairInsert methods.
319         * @param geno pointer to the genotype tree
[760]320         * @param whichchild 1 if first child, 2 otherwise
321         */
[1227]322        void repairGeno(f4_Node *geno, int whichchild);
[193]323
[196]324        // the cells
[1227]325        f4_Cell *C[F4_MAX_CELLS];  ///<Array of all cells of an organism
326        int     cell_count;        ///<Number of cells in an organism
[1239]327        bool    development_stagnation; ///< simulate() and oneStep() use it to force f4_Cell's waiting to develop their neural connections to progress, indicating that all cells have not had progress during the last step
[193]328
329private:
[196]330        // for error reporting / genotype fixing
[1231]331        bool repair;
[1227]332        int errorcode;
[196]333        int errorpos;
[1227]334        f4_Node *repair_remove;
335        f4_Node *repair_parent;
336        f4_Node *repair_insert;
[196]337        void toF1GenoRec(int curc, SString &out);
[1231]338        f4_Cell *tmpcel;  // needed by toF1Geno
[193]339};
340
341
342/**
[767]343 * A class to organize a f4 genotype in a tree structure.
[193]344 */
[1227]345class f4_Node
[193]346{
347public:
[1227]348        string name; ///<one-letter gene code or multiple characters for neuron classes (then neuclass != NULL)
349        f4_Node *parent; ///<parent link or NULL
350        f4_Node *child; ///<child or NULL
351        f4_Node *child2; ///<second child or NULL
[767]352        int pos; ///<original position in the string
[193]353
[1227]354        int reps; ///<repetition counter for the '#' gene
355        char prop_symbol; ///<old-style properties (force,intertia,sigmoid) of the N neuron: !=/
356        bool prop_increase; ///<false=decrease neuron property (force,intertia,sigmoid), true=increase it
357        int conn_from; ///<relative number of the neuron this neuron get an input from
358        double conn_weight; ///<neuron connection weight
359        NeuroClass *neuclass; ///< NULL or not if "name" is a neuroclass name with a proper genotype context ("N:neuroclassname"). New in 2023-04 - to fix fatal flaw with fundamental assumptions: it was impossible to distinguish between single-character neuron names such as S, D, G and single-character modifiers. They were all stored in the "name" field. Before 2018 this was never a problem because the only supported neuroclasses had distinctive symbols such as @|*GTS, and the set of supported modifiers was small and different from neuroclass letters (no G,D,S clash).
[760]360
[1227]361        f4_Node();
362
[760]363        /**
364         * Multiple-character name constructor.
365         * @param nname string from genotype representing node
[767]366         * @param nparent pointer to parent of the node
367         * @param npos position of node substring in the genotype string
[760]368         */
[1227]369        f4_Node(string nname, f4_Node *nparent, int npos);
[760]370
371        /**
[767]372         * Single-character name constructor.
[760]373         * @param nname character from genotype representing node
[767]374         * @param nparent pointer to parent of the node
375         * @param npos position of node character in the genotype string
[760]376         */
[1227]377        f4_Node(char nname, f4_Node *nparent, int npos);
[760]378
[1227]379        ~f4_Node();
[760]380
381        /**
[1227]382         * Recursively print subtree (for debugging).
383         * @param root starting node
384         * @param indent initial indentation
385         */
386        static void print_tree(const f4_Node *root, int indent);
387
388        /**
[767]389         * Adds the child to the node.
390         * @param nchi the child to be added to the node
391         * @return 0 if the child could be added, -1 otherwise
[760]392         */
[1227]393        int addChild(f4_Node *nchi);
[760]394
395        /**
[767]396         * Removes the child from the node.
397         * @param nchi the child to be removed from the node
[760]398         * @return 0 if child could be removed, -1 otherwise
399         */
[1227]400        int removeChild(f4_Node *nchi);
[760]401
402        /**
[767]403         * Returns the number of children.
[760]404         * @return 0, 1 or 2
405         */
[767]406        int childCount();
[760]407
408        /**
[767]409         * Returns the number of nodes coming from this node in a recursive way.
410         * @return the number of nodes from this node
[760]411         */
[1227]412        int count() const;
[760]413
414        /**
415         * Returns the nth subnode (0-)
[767]416         * @param n index of the child to be found
417         * @return pointer to the nth subnode or NULL if not found
[760]418         */
[1227]419        f4_Node* ordNode(int n);
[760]420
421        /**
422         * Returns a random subnode.
423         * @return random subnode
424         */
[1227]425        f4_Node* randomNode();
[760]426
427        /**
[767]428         * Returns a random subnode with a given size.
[760]429         * @param min minimum size
430         * @param max maximum size
[767]431         * @return a random subnode with a given size or NULL
[760]432         */
[1227]433        f4_Node* randomNodeWithSize(int min, int max);
[760]434
435        /**
[767]436         * Prints recursively the tree from a given node.
437         * @param buf variable to store printing result
[760]438         */
[767]439        void      sprintAdj(char *&buf);
[760]440
441        /**
[767]442         * Recursively copies the genotype tree from this node.
[760]443         * @return pointer to a tree copy
444         */
[1227]445        f4_Node* duplicate();
[760]446
447        /**
448         * Recursively releases memory from all node children.
449         */
450        void      destroy();
[193]451private:
[767]452        void     sprint(SString &out);  // print recursively
[193]453};
454
[760]455/**
[767]456 * The main function for converting a string of f4 encoding to a tree structure. Prepares
[1228]457 * f4_Node root of tree and runs f4_processRecur function for it.
[767]458 * @param geno the string representing an f4 genotype
[1227]459 * @return a pointer to the f4_Node object representing the f4 tree root
[760]460 */
[1259]461 //f4_Node* f4_processTree(const char *geno);
[760]462
[1259]463 /**
464  * Scans a genotype string starting from a given position. This recursive method creates
465  * a tree of f4_Node objects. This method extracts each potentially functional element
466  * of a genotype string to a separate f4_Nodes. When the branching character '<' occurs,
467  * f4_processRecur is deployed for the latest f4_Node element. This method does not
468  * analyse the genotype semantically, it only checks if the syntax is proper. The only
469  * semantic aspect is neuron class name extraction, where the GenoOperators
470  * class is used to parse the potential neuron class name.
471  * This is an internal function; for regular cases, use f4_process().
472  * @param genot the string with the entire genotype
473  * @param genot_len length of genot (precomputed for efficiency)
474  * @param pos_inout the current position of processing in string (advanced by the function)
475  * @param parent current parent of the analysed branch of the genotype
476  * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
477  */
[1234]478int f4_processRecur(const char *genot, const int genot_len, int &pos_inout, f4_Node *parent);
[193]479
[760]480/**
[1231]481 * A wrapper for f4_processRecur(). Creates a tree of f4_Node objects corresponding to
482 * the provided genotype.
483 * @param genot the string with the entire genotype
484 * @param root root of the tree corresponding to the genotype
485 * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
486 */
487int f4_process(const char *genot, f4_Node *root);
488
489/**
[767]490 * Parses notation of the neuron connection - takes the beginning of the connection
491 * definition, extracts the relative position of input neurons and the weight of the connection.
492 * After successful parsing, returns the pointer to the first character after the connection
493 * definition, or NULL if the connection definition was not valid due to the lack of [, :, ]
494 * characters or an invalid value of relfrom or weight.
495 * @param fragm the beginning of connection definition, should be the '[' character
496 * @param relfrom the reference to an int variable in which the relative position of the input neuron will be stored
497 * @param weight the reference to a double variable in which the weight of the connection will be stored
498 * @return the pointer to the first character in string after connection definition
[760]499 */
[774]500const char *parseConnection(const char *fragm, int &relfrom, double &weight);
[193]501
502#endif
Note: See TracBrowser for help on using the repository browser.