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

Last change on this file since 1234 was 1234, checked in by Maciej Komosinski, 12 months ago

Simplify sequences of modifier genes, cancelling out antagonistic ones and limiting the number of identical genes

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