Changeset 1228


Ignore:
Timestamp:
04/28/23 23:44:31 (12 months ago)
Author:
Maciej Komosinski
Message:

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

Location:
cpp/frams/genetics/f4
Files:
3 edited

Legend:

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

    r1227 r1228  
    3333}
    3434
    35 int scanrec(const char* s, size_t slen, char stopchar)
    36 {
    37         size_t i = 0;
     35int scanRecur(const char* s, int slen, char stopchar)
     36{
     37        int i = 0;
    3838        //DB( printf("    scan('%s', '%c')\n", s, stopchar); )
    3939        while (1)
    4040        {
    41                 if (i >= slen)  // ran out the string, should never happen with correct string
     41                if (i >= slen)  // ran out the string, should never happen with a correct string
    4242                        return 1;
    4343                if (stopchar == s[i])  // bumped into stopchar
     
    4747                        if (s[i] == '(')
    4848                        {
    49                                 i += 2 + scanrec(s + i + 1, slen - i - 1, ')');
     49                                i += 2 + scanRecur(s + i + 1, slen - i - 1, ')');
    5050                                continue;
    5151                        }
    5252                        if (s[i] == '<')
    5353                        {
    54                                 i += 2 + scanrec(s + i + 1, slen - i - 1, '>');
     54                                i += 2 + scanRecur(s + i + 1, slen - i - 1, '>');
    5555                                continue;
    5656                        }
    5757                        if (s[i] == '#')
    5858                        {
    59                                 i += 2 + scanrec(s + i + 1, slen - i - 1, '>');
     59                                i += 2 + scanRecur(s + i + 1, slen - i - 1, '>');
    6060                                continue;
    6161                        }
    6262                }
    63                 // s[i] a non-special character
     63                // s[i] is a non-special character
    6464                i++;
    6565        }
    66         return int(i);
     66        return i;
    6767}
    6868
     
    703703f4_Cells::f4_Cells(SString & genome, int nrepair)
    704704{
    705         int res;
    706705        repair = nrepair;
    707706        errorcode = GENOPER_OK;
     
    715714        // transform geno from string to nodes
    716715        f4rootnode = new f4_Node();
    717         res = f4_processrec(genome.c_str(), 0, f4rootnode);
    718         if ((res < 0) || (1 != f4rootnode->childCount()))
     716        int res = f4_processRecur(genome.c_str(), 0, f4rootnode);
     717        if (res || (f4rootnode->childCount() != 1))
    719718        {
    720719                errorcode = GENOPER_OPFAIL;
     
    833832                switch (c->type)
    834833                {
    835                 case CELL_UNDIFF: type = "UNDIFF"; break;
     834                case CELL_UNDIFF: type = "undiff"; break;
    836835                case CELL_STICK:  type = "STICK"; break;
    837836                case CELL_NEURON: type = string("NEURON:") + c->neuclass->name.c_str(); break;
     
    12181217{
    12191218        int n = count();
    1220         // pick a random node, between 0 and n-1
     1219        // pick a random node between 0 and n-1
    12211220        return ordNode(rndUint(n));
    12221221}
     
    13411340// scan genotype string and build tree
    13421341// return >1 for error (errorpos)
    1343 int f4_processrec(const char* genot, unsigned pos0, f4_Node *parent)
    1344 {
    1345         int i, res;
    1346         unsigned gpos, oldpos;
    1347         f4_Node *node1, *par;
    1348         unsigned beginindex;
     1342int f4_processRecur(const char* genot, unsigned pos0, f4_Node *parent)
     1343{
     1344        unsigned int gpos;
     1345        f4_Node *par;
    13491346
    13501347        gpos = pos0;
     
    13591356                {
    13601357                        // find out genotype start for child
    1361                         int j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), '>');
    1362 
    1363                         node1 = new f4_Node("<", par, gpos);
    1364                         par = node1;
    1365                         res = f4_processrec(genot, gpos + 1, par);
     1358                        int stopchar_offset = scanRecur(genot + gpos + 1, (int)strlen(genot + gpos + 1), '>');
     1359
     1360                        f4_Node *node = new f4_Node("<", par, gpos);
     1361                        par = node;
     1362                        int res = f4_processRecur(genot, gpos + 1, par);
    13661363                        if (res) return res;
    1367                         if (gpos + j + 2 < strlen(genot))
    1368                         {
    1369                                 res = f4_processrec(genot, gpos + j + 2, par);
     1364                        if (gpos + stopchar_offset + 2 < strlen(genot))
     1365                        {
     1366                                res = f4_processRecur(genot, gpos + stopchar_offset + 2, par);
    13701367                                if (res) return res;
    13711368                        }
    13721369                        else // ran out
    13731370                        {
    1374                                 node1 = new f4_Node(">", par, int(strlen(genot)) - 1);
    1375                                 par = node1;
     1371                                node = new f4_Node(">", par, int(strlen(genot)) - 1);
     1372                                par = node;
    13761373                        }
    13771374                        gpos++;
     
    13801377                case '>':
    13811378                {
    1382                         node1 = new f4_Node(">", par, gpos);
    1383                         par = node1;
     1379                        f4_Node *node = new f4_Node(">", par, gpos);
     1380                        par = node;
    13841381                        gpos = (unsigned int)strlen(genot);
    13851382                        return 0;  // OK
     
    13901387                        ExtValue val;
    13911388                        const char* end = val.parseNumber(genot + gpos + 1, ExtPType::TInt);
    1392                         if (end == NULL) i = 1;
    1393                         else i = val.getInt();
     1389                        int reps = (end == NULL) ? 1 : val.getInt();
    13941390                        // find out genotype start for continuation
    1395                         int j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), '>');
     1391                        int stopchar_offset = scanRecur(genot + gpos + 1, (int)strlen(genot + gpos + 1), '>');
    13961392                        // skip number
    1397                         oldpos = gpos;
     1393                        unsigned int oldpos = gpos;
    13981394                        gpos += end - (genot + gpos);
    13991395                        //gpos++;
    14001396                        //while ((genot[gpos] >= '0') && (genot[gpos] <= '9')) gpos++;node1 = new f4_Node("#", par, oldpos);
    1401                         node1 = new f4_Node("#", par, oldpos);
    1402                         node1->reps = i;
    1403                         par = node1;
    1404                         res = f4_processrec(genot, gpos, node1);
     1397                        f4_Node *node = new f4_Node("#", par, oldpos);
     1398                        node->reps = reps;
     1399                        par = node;
     1400                        int res = f4_processRecur(genot, gpos, node);
    14051401                        if (res) return res;
    1406                         if (oldpos + j + 2 < strlen(genot))
    1407                         {
    1408                                 res = f4_processrec(genot, oldpos + j + 2, node1);
     1402                        if (oldpos + stopchar_offset + 2 < strlen(genot))
     1403                        {
     1404                                res = f4_processRecur(genot, oldpos + stopchar_offset + 2, node);
    14091405                                if (res) return res;
    14101406                        }
    14111407                        else // ran out
    14121408                        {
    1413                                 node1 = new f4_Node(">", par, int(strlen(genot)) - 1);
     1409                                node = new f4_Node(">", par, int(strlen(genot)) - 1);
    14141410                        }
    14151411                        return 0;  // OK
     
    14301426                                return gpos + 1; //error
    14311427                        gpos += 2; //skipping "N:"
    1432                         beginindex = gpos;
    1433                         char* end = (char*)genot + beginindex;
     1428                        unsigned int begin_index = gpos;
     1429                        char* end = (char*)genot + begin_index;
    14341430                        NeuroClass *neuclass = GenoOperators::parseNeuroClass(end, ModelEnum::SHAPETYPE_BALL_AND_STICK);
    14351431                        if (neuclass == NULL)
    14361432                                return gpos + 1; //error
    1437                         gpos += end - genot - beginindex;
    1438                         string neutype = string(genot + beginindex, genot + gpos);
    1439                         node1 = new f4_Node(neutype, par, forgenorange);
    1440                         node1->neuclass = neuclass;
    1441                         par = node1;
     1433                        gpos += end - genot - begin_index;
     1434                        string neutype = string(genot + begin_index, genot + gpos);
     1435                        f4_Node *node = new f4_Node(neutype, par, forgenorange);
     1436                        node->neuclass = neuclass;
     1437                        par = node;
    14421438                        // if it continues with a colon that determines a neuron parameter (e.g. N:N:+=: ), then let the switch case for colon handle this
    14431439                        break;
     
    14591455                                return gpos + 1 + 1; //error
    14601456                        }
    1461                         node1 = new f4_Node(":", par, gpos);
    1462                         node1->prop_symbol = prop_symbol;
    1463                         node1->prop_increase = prop_dir == '+' ? true : false; // + or -
    1464                         par = node1;
    1465                         int chars = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ':');
    1466                         gpos += chars + 2;
     1457                        f4_Node *node = new f4_Node(":", par, gpos);
     1458                        node->prop_symbol = prop_symbol;
     1459                        node->prop_increase = prop_dir == '+' ? true : false; // + or -
     1460                        par = node;
     1461                        int stopchar_offset = scanRecur(genot + gpos + 1, (int)strlen(genot + gpos + 1), ':');
     1462                        gpos += stopchar_offset + 2;
    14671463                        break;
    14681464                }
     
    14751471                                return gpos + 1; //error
    14761472
    1477                         node1 = new f4_Node("[", par, gpos);
    1478                         node1->conn_from = relfrom;
    1479                         node1->conn_weight = weight;
    1480                         par = node1;
    1481                         int j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ']');
    1482                         gpos += j + 2;
     1473                        f4_Node *node = new f4_Node("[", par, gpos);
     1474                        node->conn_from = relfrom;
     1475                        node->conn_weight = weight;
     1476                        par = node;
     1477                        int stopchar_offset = scanRecur(genot + gpos + 1, (int)strlen(genot + gpos + 1), ']');
     1478                        gpos += stopchar_offset + 2;
    14831479                        break;
    14841480                }
     
    14861482                {
    14871483                        //printf("any regular character '%c'\n", genot[gpos]);
    1488                         node1 = new f4_Node(genot[gpos], par, gpos);
    1489                         par = node1;
     1484                        f4_Node *node = new f4_Node(genot[gpos], par, gpos);
     1485                        par = node;
    14901486                        gpos++;
    14911487                        break;
     
    14991495                if (par->name != ">")
    15001496                {
    1501                         node1 = new f4_Node('>', par, int(strlen(genot)) - 1);
    1502                         par = node1;
     1497                        f4_Node *node = new f4_Node('>', par, int(strlen(genot)) - 1);
     1498                        par = node;
    15031499                }
    15041500        }
     
    15261522}
    15271523
    1528 f4_Node* f4_processtree(const char* geno)
     1524/*
     1525f4_Node* f4_processTree(const char* geno)
    15291526{
    15301527        f4_Node *root = new f4_Node();
    1531         int res = f4_processrec(geno, 0, root);
     1528        int res = f4_processRecur(geno, 0, root);
    15321529        if (res) return NULL;
    15331530        //DB( printf("test f4  "); )
     
    15451542                return root->child;
    15461543}
     1544*/
  • cpp/frams/genetics/f4/f4_general.h

    r1227 r1228  
    5151 * @return 1 if end of string was reached, or position of found character in sequence
    5252 */
    53 int scanrec(const char* s, unsigned int slen, char stopchar);
     53int scanRecur(const char* s, int slen, char stopchar);
    5454
    5555
     
    475475/**
    476476 * The main function for converting a string of f4 encoding to a tree structure. Prepares
    477  * f4_Node root of tree and runs f4_processrec function for it.
     477 * f4_Node root of tree and runs f4_processRecur function for it.
    478478 * @param geno the string representing an f4 genotype
    479479 * @return a pointer to the f4_Node object representing the f4 tree root
    480480 */
    481 f4_Node* f4_processtree(const char *geno);
     481//f4_Node* f4_processTree(const char *geno);
    482482
    483483/**
     
    485485 * a tree of f4_Node objects. This method extracts each potentially functional element
    486486 * 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
     487 * f4_processRecur is deployed for the latest f4_Node element. This method does not
    488488 * analyse the genotype semantically, it only checks if the syntax is proper. The only
    489489 * semantic aspect is neuron class name extraction, where the GenoOperators
     
    494494 * @return 0 if processing was successful, otherwise returns the position of an error in the genotype
    495495 */
    496 int f4_processrec(const char *genot, unsigned pos0, f4_Node *parent);
     496int f4_processRecur(const char *genot, unsigned pos0, f4_Node *parent);
    497497
    498498/**
  • cpp/frams/genetics/f4/f4_oper.cpp

    r1227 r1228  
    1313// TODO getting rid of redundancy (having valid genotypes with a lot of "junk code") in this representation looks like a good idea.
    1414//
    15 // Note: symbols after the last > are ignored, for example /*4*/<X>N:N>N:N[2:-0.5]XXXwhatever but since they are not parsed into the f4_Node tree, they will be lost after any mutation.
     15// Note: symbols after the last > are ignored, for example /*4*/<X>N:N>blablaN:N[2:-0.5]XXXwhatever but since they are not parsed into the f4_Node tree, they will be lost after any mutation.
    1616//
    17 // TODO the behavior of neuron input indexes during mutation seems badly implemented (see also TREAT_BAD_CONNECTIONS_AS_ERRORS). Are they kept properly maintained when nodes are added and removed? This could be done well because during mutation we operate on the tree structure with cross-references between nodes (so they should not be affected by local changes in the tree), and then convert the tree back to string. Yet, the f4_Node.conn_from is an integer and these fields in nodes do not seem to be maintained on tree node adding/removal... change these integer offsets to references to node objects? But actually, do the offsets that constitute relative connection references concern the f4_Node tree structure (and all these sophisticated calculations of offsets during mutation are useful) or rather they concern the f4_Cells development? verify all situations in f4_Cell::oneStep(), case '['.
     17// TODO the behavior of neuron input indexes during mutation seems badly implemented (see also TREAT_BAD_CONNECTIONS_AS_INVALID_GENO). Are they kept properly maintained when nodes are added and removed? This could be done well because during mutation we operate on the tree structure with cross-references between nodes (so they should not be affected by local changes in the tree), and then convert the tree back to string. Yet, the f4_Node.conn_from is an integer and these fields in nodes do not seem to be maintained on tree node adding/removal... change these integer offsets to references to node objects? But actually, do the offsets that constitute relative connection references concern the f4_Node tree structure (and all these sophisticated calculations of offsets during mutation are useful) or rather they concern the f4_Cells development? verify all situations in f4_Cell::oneStep(), case '['.
    1818// TODO add simplifying sequences of modifiers (so capital and small letter cancel out, like in f1) - but seems like each single modifier is a separate f4_Node? and perhaps we don't want to use the repair mechanism for this... maybe mutations, when they add/modify/remove a modifier node, should be "cleaning" the tree by removing nodes when they encounter contradictory modifiers on the same subpath?
    1919// TODO add support for properties of (any class of) neurons - not just sigmoid/force/intertia (':' syntax) for N
     
    122122        // convert geno to tree, then try to validate 20 times
    123123        f4_Node root;
    124         if (f4_processrec(geno, 0, &root) || root.childCount() != 1) return GENOPER_OK; // cannot repair
     124        if (f4_processRecur(geno, 0, &root) || root.childCount() != 1) return GENOPER_OK; // cannot repair
    125125        if (ValidateRec(&root, 20) == GENOPER_REPAIR) // if repaired, make it back to string
    126126        {
     
    135135{
    136136        f4_Node root;
    137         int res = f4_processrec(geno, 0, &root);
     137        int res = f4_processRecur(geno, 0, &root);
    138138        if (res) return res;  // errorpos, >0
    139139        if (root.childCount() != 1) return 1; //earlier: GENOPER_OPFAIL
     
    208208                                                        // The "false" argument in findConnectionNeuronIndexes() below is not suffient, because we also need to access (find) the f4_Node of the other neuron.
    209209                                                        // A similar logic is implemented in F4_ADD_CONN below, but let's not complicate this F4_ADD_DIV mutation anymore.
    210                                                         // A disadvantage is that the node_new_neuron added here which is a neuron that provides output (e.g., a receptor, N, etc.) will not get connected immediately here even when there are already existing neurons wanting inputs (e.g., muscles, N, etc.).
     210                                                        // The disadvantage is that the node_new_neuron added here which is a neuron that provides output (e.g., a receptor, N, etc.) will not get connected immediately here even when there are already existing neurons wanting inputs (e.g., muscles, N, etc.).
    211211                                                        //bool ok = findConnectionNeuronIndexes(g, ... , false, ..., ...);
    212212                                                }
     
    230230
    231231                        // the probability that a randomly selected node will be a neuron and additionally this neuron will accept inputs is low,
    232                         // so we disregard randomly picked node_mutated and build a list of all valid candidate nodes here, then select a random one from them.
     232                        // so we disregard randomly picked node_mutated and build a list of all valid candidate nodes here, then randomly select one from them.
    233233
    234234                        vector<f4_Node*> candidate_nodes; //neurons that accept input(s)
     
    476476        // relative input connection to some existing neuron
    477477        nn->conn_from = nn_index - other_index;
    478         //nn->conn_from = (int)(4.0f * (rndDouble(1) - 0.5f)); //in very old times - did not care about neuron input/output preferences
     478        //nn->conn_from = (int)(4.0f * (rndDouble(1) - 0.5)); //in very old times - did not care about neuron input/output preferences
    479479
    480480        nn->conn_weight = GenoOperators::getMutatedNeuronConnectionWeight(nn->conn_weight);
     
    493493void Geno_f4::repeatNodeChangeRandom(f4_Node *nn) const
    494494{
    495         if (rndDouble(1) < 0.5f) nn->reps++; else nn->reps--; // change count
     495        if (rndDouble(1) < 0.5) nn->reps++; else nn->reps--; // change count
    496496        if (nn->reps < 1) nn->reps = 1;
    497497        if (nn->reps > mut_max_rep) nn->reps = mut_max_rep;
     
    547547{
    548548        f4_Node *root = new f4_Node;
    549         if (f4_processrec(g, 0, root) || root->childCount() != 1)
     549        if (f4_processRecur(g, 0, root) || root->childCount() != 1)
    550550        {
    551551                delete root;
     
    607607
    608608// decide number of nodes to mutate
    609 n = (int)( 0.5f + rndDouble(1) * maxToMut );
     609n = (int)( 0.5 + rndDouble(1) * maxToMut );
    610610if (n<1) n=1;
    611611if (n>totNodes) n=totNodes;
     
    671671
    672672        // convert genotype strings into tree structures
    673         if (f4_processrec(g1, 0, &root1) || (root1.childCount() != 1)) return GENOPER_OPFAIL;
    674         if (f4_processrec(g2, 0, &root2) || (root2.childCount() != 1)) return GENOPER_OPFAIL;
     673        if (f4_processRecur(g1, 0, &root1) || (root1.childCount() != 1)) return GENOPER_OPFAIL;
     674        if (f4_processRecur(g2, 0, &root2) || (root2.childCount() != 1)) return GENOPER_OPFAIL;
    675675
    676676        // decide amounts of crossover, 0.25-0.75
Note: See TracChangeset for help on using the changeset viewer.