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

Last change on this file since 1228 was 1228, checked in by Maciej Komosinski, 21 months ago

Fixed a bug where an f4_Node tree that resulted from an f4 genotype that was not properly/completely parsed due to some error would still be used to try growing an organism

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