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

Last change on this file since 1247 was 1239, checked in by Maciej Komosinski, 19 months ago

More robust stopping condition for organism development: no longer based on declarations of cells (I am active or I am not), but on the observation of their actual development progress

  • Property svn:eol-style set to native
File size: 18.1 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 returns
153         * to wait until 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.
156         *
157         * This method, unlike genotype tree creation, checks semantics. This means that
158         * this function will fail (set error code) if:
159         *  - the cell differentiated as a stick will have branching node '<',
160         *  - the undifferentiated cell will have termination node '>' (end of cell development without differentiation),
161         *  - the stack of repetition marker '#' will exceed maximum allowed value of repetition,
162         *  - the stick modifiers, like rotation, will be applied on neuron cell,
163         *  - the differentiated cell will be differentiated again,
164         *  - the connection between neurons cannot be established,
165         *  - the neuron class is not valid.
166         *
167         * This function returns either because the development of this cell was completed,
168         * or it was halted (yielding to other cells), or the error code was set in the f4_Cells object in the org attribute.
169         */
170        void oneStep();
171
172        /**
173         * Adds a connection between this neuron cell and a given neuron cell in nfrom.
174         * @param nfrom input neuron cell
175         * @param nweight weight of connection
176         * @return 0 if connection is established, -1 otherwise
177         */
178        int   addConnection(f4_Cell *nfrom, double nweight);
179
180        /**
181         * Adjusts properties of stick objects.
182         */
183        void  adjustRec();
184
185        int        nr;                 ///<number of cell (seems to be used only in old f1 converter for neuron connections)
186        int        type;               ///<type
187        f4_Cell *dadlink;              ///<pointer to cell parent
188        f4_Cells  *org;                ///<uplink to organism
189
190        f4_Node *genot;                    ///<genotype tree
191        f4_Node *gcur;                 ///<current genotype execution pointer
192        f4_Node *old_gcur;             ///<used externally by f4_Cells::oneStep() to track changes of gcur, i.e., to detect progress in cell development
193        repeat_stack repeat;           ///<stack holding repetition nodes and counters
194        int recProcessedFlag;          ///<used during recursive traverse
195        MultiRange genoRange;          ///<remember the genotype codes affecting this cell so far
196
197        GeneProps    P;                ///<properties
198        int          anglepos;         ///<number of position within dad's children (,)
199        int          childcount;       ///<number of children
200        int          commacount;       ///<number of postitions at lastend (>=childcount)
201        double       rolling;          ///<rolling angle ('R') (around x)
202        double       xrot;                         ///<rotation angle around x
203        double       zrot;             ///<horizontal rotation angle due to branching (around z)
204
205        double       mz;               ///<freedom in z
206        int          p2_refno;         ///<the number of the last end part object, used in f0
207        int          joint_refno;      ///<the number of the joint object, used in f0
208        int          neuro_refno;      ///<the number of the neuro object, used in f0
209
210        double       inertia;          ///<inertia of neuron
211        double       force;            ///<force of neuron
212        double       sigmo;            ///<sigmoid of neuron
213        f4_CellConn *conns[F4_MAX_CELL_INPUTS]; ///<array of neuron connections
214        int          conns_count;      ///<number of connections
215        NeuroClass *neuclass;          ///<pointer to neuron class
216};
217
218/**
219 * Class representing a connection between neuron cells.
220 */
221class f4_CellConn
222{
223public:
224        /**
225         * Constructor for f4_CellLink class. Parameter nfrom represents input
226         * neuron cell.
227         * @param nfrom pointer to input neuron cell
228         * @param nweight weight of connection
229         */
230        f4_CellConn(f4_Cell *nfrom, double nweight);
231
232        f4_Cell *from;  ///<pointer to input neuron cell
233        double weight;  ///<weight of connection
234};
235
236
237/**
238 * A class representing a collection of cells. It is equivalent to an organism.
239 */
240class f4_Cells
241{
242public:
243
244        /**
245         * Constructor taking genotype in a form of a tree.
246         * @param genome genotype tree
247         * @param nrepair false if nothing to repair
248         */
249        f4_Cells(f4_Node *genome, bool nrepair);
250
251        /**
252         * Destructor removing cells from memory.
253         */
254        ~f4_Cells();
255
256        /**
257         * Adds a new cell to organism.
258         * @param newcell cell to be added
259         */
260        void addCell(f4_Cell *newcell);
261
262        /**
263         * Creates an approximate genotype in the f1 encoding and stores it in a given parameter.
264         * @param out the string in which the approximate f1 genotype will be stored
265         */
266        void toF1Geno(SString &out);
267
268        /**
269         * Performs a single step of organism development. It runs each active cell in the organism.
270         * @return false if all cells are developed or there is an error, true otherwise
271         */
272        bool oneStep();
273
274        /**
275         * Performs the full development of organism and returns error code if something
276         * went wrong.
277         * @return 0 if organism developed successfully, error code if something went wrong
278         */
279        int simulate();
280
281        /**
282         * Prints the current state of the organism (for debugging purposes).
283         * @param description printout header
284         */
285        void print_cells(const char* description);
286
287        /**
288         * Returns error code of the last simulation.
289         * @return error code
290         */
291        int getErrorCode() { return errorcode; };
292
293        /**
294         * Returns position of an error in genotype.
295         * @return position of an error
296         */
297        int getErrorPos() { return errorpos; };
298
299        /**
300         * Sets error code GENOPER_OPFAIL for a simulation on a given position.
301         * @param nerrpos position of an error
302         */
303        void setError(int nerrpos);
304
305        /**
306         * Sets the element of genotype to be repaired by removal.
307         * @param nerrpos position of an error in genotype
308         * @param to_remove the f4_Node to be removed from the genotype tree in order to repair
309         */
310        void setRepairRemove(int nerrpos, f4_Node *to_remove);
311
312        /**
313         * Sets repairing of a genotype by inserting a new node to the current genotype.
314         * @param nerrpos position of an error in genotype
315         * @param parent the parent of a new element
316         * @param to_insert the element to be inserted
317         * @return 0 if repair can be performed, or -1 otherwise because the repair flag wasn't set in the constructor
318         */
319        int setRepairInsert(int nerrpos, f4_Node *parent, f4_Node *to_insert);
320
321        /**
322         * Repairs the genotype according to setRepairRemove or setRepairInsert methods.
323         * @param geno pointer to the genotype tree
324         * @param whichchild 1 if first child, 2 otherwise
325         */
326        void repairGeno(f4_Node *geno, int whichchild);
327
328        // the cells
329        f4_Cell *C[F4_MAX_CELLS];  ///<Array of all cells of an organism
330        int     cell_count;        ///<Number of cells in an organism
331        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
332
333private:
334        // for error reporting / genotype fixing
335        bool repair;
336        int errorcode;
337        int errorpos;
338        f4_Node *repair_remove;
339        f4_Node *repair_parent;
340        f4_Node *repair_insert;
341        void toF1GenoRec(int curc, SString &out);
342        f4_Cell *tmpcel;  // needed by toF1Geno
343};
344
345
346/**
347 * A class to organize a f4 genotype in a tree structure.
348 */
349class f4_Node
350{
351public:
352        string name; ///<one-letter gene code or multiple characters for neuron classes (then neuclass != NULL)
353        f4_Node *parent; ///<parent link or NULL
354        f4_Node *child; ///<child or NULL
355        f4_Node *child2; ///<second child or NULL
356        int pos; ///<original position in the string
357
358        int reps; ///<repetition counter for the '#' gene
359        char prop_symbol; ///<old-style properties (force,intertia,sigmoid) of the N neuron: !=/
360        bool prop_increase; ///<false=decrease neuron property (force,intertia,sigmoid), true=increase it
361        int conn_from; ///<relative number of the neuron this neuron get an input from
362        double conn_weight; ///<neuron connection weight
363        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).
364
365        f4_Node();
366
367        /**
368         * Multiple-character name constructor.
369         * @param nname string from genotype representing node
370         * @param nparent pointer to parent of the node
371         * @param npos position of node substring in the genotype string
372         */
373        f4_Node(string nname, f4_Node *nparent, int npos);
374
375        /**
376         * Single-character name constructor.
377         * @param nname character from genotype representing node
378         * @param nparent pointer to parent of the node
379         * @param npos position of node character in the genotype string
380         */
381        f4_Node(char nname, f4_Node *nparent, int npos);
382
383        ~f4_Node();
384
385        /**
386         * Recursively print subtree (for debugging).
387         * @param root starting node
388         * @param indent initial indentation
389         */
390        static void print_tree(const f4_Node *root, int indent);
391
392        /**
393         * Adds the child to the node.
394         * @param nchi the child to be added to the node
395         * @return 0 if the child could be added, -1 otherwise
396         */
397        int addChild(f4_Node *nchi);
398
399        /**
400         * Removes the child from the node.
401         * @param nchi the child to be removed from the node
402         * @return 0 if child could be removed, -1 otherwise
403         */
404        int removeChild(f4_Node *nchi);
405
406        /**
407         * Returns the number of children.
408         * @return 0, 1 or 2
409         */
410        int childCount();
411
412        /**
413         * Returns the number of nodes coming from this node in a recursive way.
414         * @return the number of nodes from this node
415         */
416        int count() const;
417
418        /**
419         * Returns the nth subnode (0-)
420         * @param n index of the child to be found
421         * @return pointer to the nth subnode or NULL if not found
422         */
423        f4_Node* ordNode(int n);
424
425        /**
426         * Returns a random subnode.
427         * @return random subnode
428         */
429        f4_Node* randomNode();
430
431        /**
432         * Returns a random subnode with a given size.
433         * @param min minimum size
434         * @param max maximum size
435         * @return a random subnode with a given size or NULL
436         */
437        f4_Node* randomNodeWithSize(int min, int max);
438
439        /**
440         * Prints recursively the tree from a given node.
441         * @param buf variable to store printing result
442         */
443        void      sprintAdj(char *&buf);
444
445        /**
446         * Recursively copies the genotype tree from this node.
447         * @return pointer to a tree copy
448         */
449        f4_Node* duplicate();
450
451        /**
452         * Recursively releases memory from all node children.
453         */
454        void      destroy();
455private:
456        void     sprint(SString &out);  // print recursively
457};
458
459/**
460 * The main function for converting a string of f4 encoding to a tree structure. Prepares
461 * f4_Node root of tree and runs f4_processRecur function for it.
462 * @param geno the string representing an f4 genotype
463 * @return a pointer to the f4_Node object representing the f4 tree root
464 */
465//f4_Node* f4_processTree(const char *geno);
466
467/**
468 * Scans a genotype string starting from a given position. This recursive method creates
469 * a tree of f4_Node objects. This method extracts each potentially functional element
470 * of a genotype string to a separate f4_Nodes. When the branching character '<' occurs,
471 * f4_processRecur is deployed for the latest f4_Node element. This method does not
472 * analyse the genotype semantically, it only checks if the syntax is proper. The only
473 * semantic aspect is neuron class name extraction, where the GenoOperators
474 * class is used to parse the potential neuron class name.
475 * This is an internal function; for regular cases, use f4_process().
476 * @param genot the string with the entire genotype
477 * @param genot_len length of genot (precomputed for efficiency)
478 * @param pos_inout the current position of processing in string (advanced by the function)
479 * @param parent current parent of the analysed branch of the genotype
480 * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
481 */
482int f4_processRecur(const char *genot, const int genot_len, int &pos_inout, f4_Node *parent);
483
484/**
485 * A wrapper for f4_processRecur(). Creates a tree of f4_Node objects corresponding to
486 * the provided genotype.
487 * @param genot the string with the entire genotype
488 * @param root root of the tree corresponding to the genotype
489 * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
490 */
491int f4_process(const char *genot, f4_Node *root);
492
493/**
494 * Parses notation of the neuron connection - takes the beginning of the connection
495 * definition, extracts the relative position of input neurons and the weight of the connection.
496 * After successful parsing, returns the pointer to the first character after the connection
497 * definition, or NULL if the connection definition was not valid due to the lack of [, :, ]
498 * characters or an invalid value of relfrom or weight.
499 * @param fragm the beginning of connection definition, should be the '[' character
500 * @param relfrom the reference to an int variable in which the relative position of the input neuron will be stored
501 * @param weight the reference to a double variable in which the weight of the connection will be stored
502 * @return the pointer to the first character in string after connection definition
503 */
504const char *parseConnection(const char *fragm, int &relfrom, double &weight);
505
506#endif
Note: See TracBrowser for help on using the repository browser.