Ignore:
Timestamp:
04/27/23 04:04:06 (17 months ago)
Author:
Maciej Komosinski
Message:

Improvements in f4:

  • fixed a bug where newly created cells in a given development step were not counted as in-active-development (overlooked), and if they were the only in-active-development cells, the development of an organism would stop
  • added one extra development step (#ifdef EXTRA_STEP_CELL_DEVELOPMENT) so that cells that became not in-active-development ("halted" or yielding, usually due to waiting for neurons to develop in other cells) would get a chance to continue development (important when we don't want to ignore invalid neuron connections, #ifdef TREAT_BAD_CONNECTIONS_AS_INVALID_GENO)
  • ensured that all connections in a cell are processed (earlier they could be skipped if the development of the cell was "halted" and all cells became not in-active-development)
  • got rid of neuron connection syntax [sensor:weight], now all neuron classes are handled in a uniform way and their [connections] too; the only allowed syntax is [input_index:weight]
  • unified handling of all neuroclasses during parsing, conversion and mutation
  • more correct syntax coloring
  • got rid of general-purpose fields (i1, i2, f1, s1) in class f4_node - now separate fields serve their individual purpose
  • rewritten creating and modifying neuron connections - it is more deliberate to satisfy neuron input/output preferences
  • some invalid neuron connections make a genotype invalid (previously invalid neuron connections were ignored and the genotype was considered valid)
  • added (surprisingly missing) simple debug printout functions to see the f4_Node tree structure and the developing f4_Cells
  • more informative variable and constant names
  • improved performance
File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/f4/f4_general.h

    r829 r1227  
    11// This file is a part of Framsticks SDK.  http://www.framsticks.com/
    2 // Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
     2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
    33// See LICENSE.txt for details.
    44
     
    2929void rolling_inc(double *v);
    3030
    31 class f4_node;   // later
     31class f4_Node;   // later
    3232class f4_Cell;   // later
    3333class f4_Cells;  // later
     
    3636/** @name Types of f4_Cell's */
    3737//@{
    38 #define T_UNDIFF4 40 ///<undifferentiated cell
    39 #define T_STICK4  41 ///<differentiated to stick, cannot divide
    40 #define T_NEURON4 42 ///<differentiated to neuron, can divide
     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
    4141//@}
    4242
     
    5454
    5555
    56 class f4_CellLink;
     56class f4_CellConn;
    5757
    5858/** @name Constraints of f4 genotype structures */
    5959//@{
    60 #define MAXINPUTS 100 ///<maximum number of neuron inputs
    61 #define MAX4CELLS 100 ///<maximum number of f4 organism cells
     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
    6262//@}
    6363
    6464/**
    65  * Abstract cell type - the representation of single component in the developmental
     65 * Abstract cell type - the representation of a single component in the developmental
    6666 * encoding. In the beginning, each f4_Cell is undifferentiated. During the process
    6767 * of development it can divide or differentiate into a stick or a neuron. If it
     
    8686                /**
    8787                 * A constructor that takes the pointer to the repetition node and the count of repetitions.
    88                  * @param a pointer to f4_node for repetition character
     88                 * @param a pointer to f4_Node for repetition character
    8989                 * @param b the number of repetitions
    9090                 */
    91                 repeat_ptr(f4_node *a, int b) : node(a), count(b) { };
     91                repeat_ptr(f4_Node *a, int b) : node(a), count(b) { };
    9292
    9393                inline void makeNull() { node = NULL; count = -1; };
     
    9696
    9797                inline void dec() { count--; };
    98                 f4_node    *node; ///<pointer to the repetition code
     98                f4_Node    *node; ///<pointer to the repetition code
    9999                int       count; ///<repetition counter
    100100        };
     
    130130                static const int stackSize = 4;  ///<max 4 nested levels
    131131                repeat_ptr ptr[stackSize]; ///<array holding pointers to repeat_ptr
    132                 short int top;  ///<index of the top of the stack
     132                int top;  ///<index of the top of the stack
    133133        };
    134134
    135135        /**
    136136         * Creates a new f4_Cell object.
    137          * @param nname name of a cell, can be T_UNDIFF4, T_STICK4 or T_NEURON4
     137         * @param nnr number of the cell
    138138         * @param ndad pointer to the parent of the created cell
    139139         * @param nangle the amount of commas affecting branch angles
    140140         * @param newP genotype properties of a given cell
    141141         */
    142         f4_Cell(int nname, f4_Cell *ndad, int nangle, GeneProps newP);
     142        f4_Cell(int nnr, f4_Cell *ndad, int nangle, GeneProps newP);
    143143        /**
    144144         * Creates a new f4_Cell object.
    145145         * @param nO pointer to an organism containing the cell
    146          * @param nname name of the cell, can be T_UNDIFF4, T_STICK4 or T_NEURON4
     146         * @param nnr number of the cell
    147147         * @param ngeno pointer to the root of the genotype tree
    148          * @param ngcur pointer to the f4_node representing the current cell in the genotype tree
     148         * @param ngcur pointer to the f4_Node representing the current cell in the genotype tree
    149149         * @param ndad pointer to the parent of the created cell
    150150         * @param nangle the number of commas affecting branch angles
    151151         * @param newP genotype properties of a given cell
    152152         */
    153         f4_Cell(f4_Cells *nO, int nname, f4_node *ngeno, f4_node *ngcur, f4_Cell *ndad, int nangle, GeneProps newP);
     153        f4_Cell(f4_Cells *nO, int nnr, f4_Node *ngeno, f4_Node *ngcur, f4_Cell *ndad, int nangle, GeneProps newP);
    154154
    155155        ~f4_Cell();
     
    172172         *  - the stick modifiers, like rotation, will be applied on neuron cell,
    173173         *  - the differentiated cell will be differentiated again,
    174          *  - the neuron class inside cell connection (i.e. N[G:5]) is not a sensor,
    175174         *  - the connection between neurons cannot be established,
    176175         *  - the neuron class is not valid.
     
    178177         * @return 0 if development was successful, 1 if there was an error in genotype tree
    179178         */
    180         int onestep();
    181 
    182         /**
    183          * Adds a link between this neuron cell and a given neuron cell in nfrom. If the nfrom object
    184          * is not given, neuron type in nt should be a sensor type.
    185          * @param nfrom input neuron cell, or NULL if not given
    186          * @param nw weight of connection
    187          * @param nt empty string or name of sensor class
    188          * @return 0 if link is established, -1 otherwise
    189          */
    190         int   addlink(f4_Cell *nfrom, double nw, string nt);
     179        int oneStep();
     180
     181        /**
     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
     186         */
     187        int   addConnection(f4_Cell *nfrom, double nweight);
    191188
    192189        /**
     
    195192        void  adjustRec();
    196193
    197         int        name;               ///<name of cell (number)
     194        int        nr;                 ///<number of cell (seems to be used only in old f1 converter for neuron connections)
    198195        int        type;               ///<type
    199196        f4_Cell *dadlink;              ///<pointer to cell parent
    200197        f4_Cells  *org;                ///<uplink to organism
    201198
    202         f4_node *genot;                    ///<genotype tree
    203         f4_node *gcur;                 ///<current genotype execution pointer
    204         int active;                    ///<determines whether development is still active
     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
    205202        repeat_stack repeat;           ///<stack holding repetition nodes and counters
    206203        int recProcessedFlag;          ///<used during recursive traverse
     
    220217        int          neuro_refno;      ///<the number of the neuro object, used in f0
    221218
    222         int          ctrl;             ///<neuron type
    223219        double       inertia;          ///<inertia of neuron
    224220        double       force;            ///<force of neuron
    225221        double       sigmo;            ///<sigmoid of neuron
    226         f4_CellLink *links[MAXINPUTS]; ///<array of neuron links
    227         int          nolink;           ///<number of links
     222        f4_CellConn *conns[F4_MAX_CELL_INPUTS]; ///<array of neuron connections
     223        int          conns_count;      ///<number of connections
    228224        NeuroClass *neuclass;          ///<pointer to neuron class
    229225};
    230226
    231227/**
    232  * Class representing link between neuron cells.
    233  */
    234 class f4_CellLink
     228 * Class representing a connection between neuron cells.
     229 */
     230class f4_CellConn
    235231{
    236232public:
    237233        /**
    238234         * Constructor for f4_CellLink class. Parameter nfrom represents input
    239          * neuron cell or NULL if connection has defined sensor type inside, like "[G:5]".
    240          * The name of sensor class defined inside neuron connection is stored in the nt
    241          * parameter.
    242          * @param nfrom pointer to input neuron cell or NULL
    243          * @param nw weight of connection
    244          * @param nt name of neuron class or empty string
    245          */
    246         f4_CellLink(f4_Cell *nfrom, double nw, string nt);
    247 
    248         f4_Cell *from; ///<pointer to input neuron cell
    249         string t;      ///<empty if 'from' cell is given, NeuroClass name otherwise
    250         double w;      ///<weight of connection
     235         * neuron cell.
     236         * @param nfrom pointer to input neuron cell
     237         * @param nweight weight of connection
     238         */
     239        f4_CellConn(f4_Cell *nfrom, double nweight);
     240
     241        f4_Cell *from;  ///<pointer to input neuron cell
     242        double weight;  ///<weight of connection
    251243};
    252244
     
    264256         * @param nrepair 0 if nothing to repair
    265257         */
    266         f4_Cells(f4_node *genome, int nrepair);
     258        f4_Cells(f4_Node *genome, int nrepair);
    267259
    268260        /**
     
    291283
    292284        /**
    293          * Performs a single step of organism development. It runs each active cell
    294          * in the organism.
    295          * @return 0 if all cells are developed, or 1 otherwise
    296          */
    297         int  onestep();
     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
     287         */
     288        bool oneStep();
    298289
    299290        /**
     
    302293         * @return 0 if organism developed successfully, error code if something went wrong
    303294         */
    304         int  simulate();
     295        int simulate();
     296
     297        /**
     298         * Prints the current state of the organism (for debugging purposes).
     299         * @param description printout header
     300         */
     301        void print_cells(const char* description);
    305302
    306303        /**
     
    308305         * @return error code
    309306         */
    310         int  geterror() { return error; };
     307        int getErrorCode() { return errorcode; };
    311308
    312309        /**
     
    314311         * @return position of an error
    315312         */
    316         int  geterrorpos() { return errorpos; };
     313        int getErrorPos() { return errorpos; };
    317314
    318315        /**
     
    325322         * Sets the element of genotype to be repaired by removal.
    326323         * @param nerrpos position of an error in genotype
    327          * @param rem the f4_node to be removed from the  genotype tree in order to repair
    328          */
    329         void setRepairRemove(int nerrpos, f4_node *rem);
     324         * @param rem the f4_Node to be removed from the  genotype tree in order to repair
     325         */
     326        void setRepairRemove(int nerrpos, f4_Node *rem);
    330327
    331328        /**
     
    336333         * @return 0 if repair can be performed, or -1 otherwise because the repair flag wasn't set in the constructor
    337334         */
    338         int  setRepairInsert(int nerrpos, f4_node *parent, f4_node *insert);
     335        int setRepairInsert(int nerrpos, f4_Node *parent, f4_Node *insert);
    339336
    340337        /**
     
    343340         * @param whichchild 1 if first child, 2 otherwise
    344341         */
    345         void repairGeno(f4_node *geno, int whichchild);
     342        void repairGeno(f4_Node *geno, int whichchild);
    346343
    347344        // the cells
    348         f4_Cell *C[MAX4CELLS];  ///<Array of all cells of an organism
    349         int       nc;           ///<Number of cells in an organism
     345        f4_Cell *C[F4_MAX_CELLS];  ///<Array of all cells of an organism
     346        int     cell_count;        ///<Number of cells in an organism
    350347
    351348private:
    352349        // for error reporting / genotype fixing
    353350        int repair;
    354         int error;
     351        int errorcode;
    355352        int errorpos;
    356         f4_node *repair_remove;
    357         f4_node *repair_parent;
    358         f4_node *repair_insert;
     353        f4_Node *repair_remove;
     354        f4_Node *repair_parent;
     355        f4_Node *repair_insert;
    359356        void toF1GenoRec(int curc, SString &out);
    360357        f4_Cell *tmpcel;                // needed by toF1Geno
    361         f4_node *f4rootnode;          // used by constructor
     358        f4_Node *f4rootnode;          // used by constructor
    362359};
    363360
     
    366363 * A class to organize a f4 genotype in a tree structure.
    367364 */
    368 class f4_node
     365class f4_Node
    369366{
    370367public:
    371         string name; ///<one-letter 'name', multiple characters for classes
    372         f4_node *parent; ///<parent link or NULL
    373         f4_node *child; ///<child or NULL
    374         f4_node *child2; ///<second child or NULL
     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
    375372        int pos; ///<original position in the string
    376         int i1; ///<internal int parameter1
    377         int l1; ///<internal long parameter1 (now also int, since long is not well specified and it is in our scenarios equivalent to int)
    378         double f1; ///<internal double parameter1
    379         string s1; ///<internal string parameter1
    380 
    381         f4_node();
     373
     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).
     380
     381        f4_Node();
    382382
    383383        /**
     
    387387         * @param npos position of node substring in the genotype string
    388388         */
    389         f4_node(string nname, f4_node *nparent, int npos);
     389        f4_Node(string nname, f4_Node *nparent, int npos);
    390390
    391391        /**
     
    395395         * @param npos position of node character in the genotype string
    396396         */
    397         f4_node(char nname, f4_node *nparent, int npos);
    398 
    399         ~f4_node();
     397        f4_Node(char nname, f4_Node *nparent, int npos);
     398
     399        ~f4_Node();
     400
     401        /**
     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);
    400407
    401408        /**
     
    404411         * @return 0 if the child could be added, -1 otherwise
    405412         */
    406         int addChild(f4_node *nchi);
     413        int addChild(f4_Node *nchi);
    407414
    408415        /**
     
    411418         * @return 0 if child could be removed, -1 otherwise
    412419         */
    413         int removeChild(f4_node *nchi);
     420        int removeChild(f4_Node *nchi);
    414421
    415422        /**
     
    423430         * @return the number of nodes from this node
    424431         */
    425         int count();
     432        int count() const;
    426433
    427434        /**
     
    430437         * @return pointer to the nth subnode or NULL if not found
    431438         */
    432         f4_node* ordNode(int n);
     439        f4_Node* ordNode(int n);
    433440
    434441        /**
     
    436443         * @return random subnode
    437444         */
    438         f4_node* randomNode();
     445        f4_Node* randomNode();
    439446
    440447        /**
     
    444451         * @return a random subnode with a given size or NULL
    445452         */
    446         f4_node* randomNodeWithSize(int min, int max);
     453        f4_Node* randomNodeWithSize(int min, int max);
    447454
    448455        /**
     
    456463         * @return pointer to a tree copy
    457464         */
    458         f4_node* duplicate();
     465        f4_Node* duplicate();
    459466
    460467        /**
     
    468475/**
    469476 * The main function for converting a string of f4 encoding to a tree structure. Prepares
    470  * f4_node root of tree and runs f4_processrec function for it.
     477 * f4_Node root of tree and runs f4_processrec function for it.
    471478 * @param geno the string representing an f4 genotype
    472  * @return a pointer to the f4_node object representing the f4 tree root
    473  */
    474 f4_node* f4_processtree(const char *geno);
     479 * @return a pointer to the f4_Node object representing the f4 tree root
     480 */
     481f4_Node* f4_processtree(const char *geno);
    475482
    476483/**
    477484 * Scans a genotype string starting from a given position. This recursive method creates
    478  * a tree of f4_node objects. This method extracts each potentially functional element
    479  * of a genotype string to a separate f4_nodes. When the branching character '<' occurs,
    480  * f4_processrec is deployed for the latest f4_node element. This method does not
     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,
     487 * f4_processrec is deployed for the latest f4_Node element. This method does not
    481488 * analyse the genotype semantically, it only checks if the syntax is proper. The only
    482489 * semantic aspect is neuron class name extraction, where the GenoOperators
     
    487494 * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
    488495 */
    489 int f4_processrec(const char *genot, unsigned pos0, f4_node *parent);
     496int f4_processrec(const char *genot, unsigned pos0, f4_Node *parent);
    490497
    491498/**
     
    502509const char *parseConnection(const char *fragm, int &relfrom, double &weight);
    503510
    504 /**
    505  * Parses the notation of the neuron connection with neuron definition - takes
    506  * the beginning of the connection definition, extracts the name of neuron class
    507  * that will be the input for the current neuron and the weight of the connection.
    508  * After successful parsing, returns a pointer to the first character after the connection
    509  * definition, or NULL if the connection definition was not valid due to the lack of [, :, ]
    510  * characters, an invalid value of the weight or an invalid neuron class name.
    511  * @param fragm the beginning of the connection definition, should be the '[' character
    512  * @param neutype the reference to a string representing the input neuron class name. The name of the class is validated with GenoOperators::parseNeuroClass()
    513  * @param weight the reference to a double variable in which the weight of the connection will be stored
    514  * @return the pointer to the first character in string after the connection definition
    515  */
    516 const char *parseConnectionWithNeuron(const char *fragm, string &neutype, double &weight);
    517 
    518511#endif
Note: See TracChangeset for help on using the changeset viewer.