Changeset 797 for cpp/frams/genetics/fL


Ignore:
Timestamp:
06/06/18 01:45:18 (6 years ago)
Author:
Maciej Komosinski
Message:

A more complete implementation of fB, fH, fL

Location:
cpp/frams/genetics/fL
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/fL/fL_conv.cpp

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#include "fL_conv.h"
     6#include "fL_general.h"
    27
    38SString GenoConv_fL0::convert(SString &i, MultiMap *map, bool using_checkpoints)
    49{
    5         return "";
     10        fL_Builder builder(NULL != map, using_checkpoints);
     11        if (builder.parseGenotype(i) != 0)  return "";
     12        double neededtime;
     13        Model *m = builder.developModel(neededtime);
     14        if (!m) return SString();
     15        if (NULL != map)
     16                m->getCurrentToF0Map(*map);
     17        SString gen = m->getF0Geno().getGenes();
     18        delete m;
     19        return gen;
    620}
  • cpp/frams/genetics/fL/fL_conv.h

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#ifndef _FL_CONV_
    26#define _FL_CONV_
  • cpp/frams/genetics/fL/fL_general.cpp

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#include <algorithm>
    26#include <stack>
    37#include "fL_general.h"
    4 
    5 const char *fL_part_names[PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };
    6 const char *fL_part_fullnames[PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" };
    7 
    8 const char *fL_joint_names[JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };
    9 const char *fL_joint_fullnames[JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" };
     8#include <frams/util/multirange.h>
     9#include <iterator>
     10
     11const char *fL_part_names[FL_PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };
     12const char *fL_part_fullnames[FL_PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" };
     13
     14const char *fL_joint_names[FL_JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };
     15const char *fL_joint_fullnames[FL_JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" };
    1016
    1117#define FIELDSTRUCT fL_Word
     
    1420        { "Word", 1, 2, "w" },
    1521        { "name", 0, PARAM_CANOMITNAME, "word name", "s", FIELD(name), },
    16         { "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 3 0", FIELD(npar), },
     22        { "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 " FL_MAXPARAMS " 0", FIELD(npar), },
    1723        { 0, 0, 0, }
    1824};
     
    2329{
    2430        { "Rule", 1, 3, "r" },
    25         { "pred", 0, PARAM_CANOMITNAME, "predecessor", "s", FIELD(predecessor), },
    26         { "cond", 0, PARAM_CANOMITNAME, "parameter condition", "s", FIELD(condition), },
    27         { "succ", 0, PARAM_CANOMITNAME, "successor", "s", FIELD(successor), },
     31        { "pred", 0, 0, "predecessor", "s", FIELD(predecessor), },
     32        { "cond", 0, 0, "parameter condition", "s", FIELD(condition), },
     33        { "succ", 0, 0, "successor", "s", FIELD(successor), },
    2834        { 0, 0, 0, }
    2935};
     
    3339ParamEntry fL_builder_paramtab[] =
    3440{
    35         { "LSystemInfo", 1, 3, "i" },
    36         { "axiom", 0, PARAM_CANOMITNAME, "starting sequence of L-System", "s", FIELD(axiom), },
    37         { "time", 0, PARAM_CANOMITNAME, "development time", "f 1.0 100.0 1.0", FIELD(time), },
    38         { "numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp), },
    39         { 0, 0, 0, }
     41                {"LSystemInfo", 1, 4, "i"},
     42                {"axiom", 0, 0, "starting sequence of L-System", "s", FIELD(axiom),},
     43                {"time", 0, PARAM_CANOMITNAME, "development time", "f 0.0 " FL_MAXITER " 1.0", FIELD(time),},
     44                {"numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp),},
     45                {"maxwords", 0, PARAM_CANOMITNAME, "Maximum number of words within genotype sequence", "d -1 9999 -1", FIELD(maxwords),},
     46                {0,0,0,}
    4047};
    4148#undef FIELDSTRUCT
     
    134141}
    135142
    136 int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams)
     143int fL_Builder::createWord(SString token, fL_Word *&word, int numparams, int begin, int end)
     144{
     145        SString wordn;
     146        int tokpos = 0;
     147        // if word name cannot be extracted, then return error
     148        if (!token.getNextToken(tokpos, wordn, '('))
     149        {
     150                return 1;
     151        }
     152        std::string wordname = fL_Builder::trimSpaces(wordn.c_str());
     153        // if word cannot be found in available words, then return error
     154        if (words.find(wordname) == words.end())
     155        {
     156                SString message = "Word '";
     157                message += wordname.c_str();
     158                message += "' in sequence does not exist";
     159                logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str());
     160                return 1;
     161        }
     162
     163        if (word) delete word;
     164        // create new word and assign parameters
     165        word = new fL_Word(false, begin, end);
     166
     167        *word = *words[wordname];
     168
     169        SString temp;
     170        temp = token.substr(tokpos);
     171        temp = temp.substr(0, temp.len() - 1);
     172
     173        // if word has parameters
     174        if (word->npar > 0)
     175        {
     176                // create ParamObject that will hold parameter data
     177                word->data = ParamObject::makeObject(word->tab);
     178                Param par(word->tab);
     179                par.select(word->data);
     180                par.setDefault();
     181                ParamInterface::LoadOptions opts;
     182
     183                // load parameters from string
     184                par.load(ParamInterface::FormatSingleLine, temp, &opts);
     185                for (int i = 0; i < par.getPropCount(); i++)
     186                {
     187                        SString t(par.id(i));
     188                        if (word->builtin && (t == SString("d") || t == SString(FL_PE_CONN_ATTR)))
     189                        {
     190                                word->parevals.push_back(NULL);
     191                        }
     192                        else
     193                        {
     194                                // create MathEvaluation object to check if string contained by
     195                                // parameter is valid
     196                                double tmp;
     197                                MathEvaluation *eval = NULL;
     198                                SString seq = par.getString(i);
     199                                // if string is empty, then evaluate this with 0
     200                                // if sequence could not be evaluated, then return error
     201                                if (seq.len() > 0)
     202                                {
     203                                        eval = new MathEvaluation(numparams);
     204                                        if (eval->evaluate(seq.c_str(), tmp) != 0)
     205                                        {
     206                                                SString message = "Word in sequence has invalid parameter:  ";
     207                                                message += temp;
     208                                                logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str());
     209                                                delete eval;
     210                                                delete word;
     211                                                word = NULL;
     212                                                return 1;
     213                                        }
     214                                }
     215                                word->parevals.push_back(eval);
     216                        }
     217                }
     218        }
     219        else if (word->npar == 0 && temp.len() > 0)
     220        {
     221                SString message = "Too many parameters for word:  ";
     222                message += token;
     223                logMessage("fL_Builder", "createWord", LOG_ERROR, message.c_str());
     224                delete word;
     225                word = NULL;
     226                return 1;
     227        }
     228        return 0;
     229}
     230
     231int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams, int begin, int end)
    137232{
    138233        int pos = 0;
     
    153248                if (token.indexOf("[", 0) != -1)
    154249                {
    155                         fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN);
     250                        fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN, begin, end);
    156251                        result.push_back(word);
    157252                        branchcount++;
     
    168263                                return 1;
    169264                        }
    170                         fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE);
     265                        fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE, begin, end);
    171266                        result.push_back(word);
    172267                        branchcount--;
    173268                        continue;
    174269                }
    175                 SString wordn;
    176                 int tokpos = 0;
    177                 // if word name cannot be extracted, then return error
    178                 if (!token.getNextToken(tokpos, wordn, '('))
     270                fL_Word *word = NULL;
     271                if (createWord(token, word, numparams, begin, end) != 0)
    179272                {
    180273                        SString message = "Error during parsing words sequence:  ";
     
    183276                        return 1;
    184277                }
    185                 std::string wordname = fL_Builder::trimSpaces(wordn.c_str());
    186                 // if word cannot be found in available words, then return error
    187                 if (words.find(wordname) == words.end())
    188                 {
    189                         SString message = "Word '";
    190                         message += wordname.c_str();
    191                         message += "' in sequence does not exist";
    192                         logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
    193                         return 1;
    194                 }
    195 
    196                 // create new word and assign parameters
    197                 fL_Word *word = new fL_Word();
    198 
    199                 *word = *words[wordname];
    200 
    201                 // if word has parameters
    202                 if (word->npar > 0)
    203                 {
    204                         // create ParamObject that will hold parameter data
    205                         word->data = ParamObject::makeObject(word->tab);
    206                         Param par(word->tab);
    207                         par.select(word->data);
    208                         par.setDefault();
    209                         ParamInterface::LoadOptions opts;
    210 
    211                         SString temp;
    212                         temp = token.substr(tokpos);
    213                         temp = temp.substr(0, temp.len() - 1);
    214                         // load parameters from string
    215                         par.load(ParamInterface::FormatSingleLine, temp, &opts);
    216                         for (int i = 0; i < par.getPropCount(); i++)
    217                         {
    218                                 // create MathEvaluation object to check if string contained by
    219                                 // parameter is valid
    220                                 double tmp;
    221                                 MathEvaluation *eval = new MathEvaluation(numparams);
    222                                 SString seq = par.getString(i);
    223                                 // if string is empty, then evaluate this with 0
    224                                 if (seq.len() == 0)
    225                                 {
    226                                         eval->evaluate("0", tmp);
    227                                 }
    228                                 // if sequence could not be evaluated, then return error
    229                                 else if (eval->evaluate(seq.c_str(), tmp) != 0)
    230                                 {
    231                                         SString message = "Word in sequence has invalid parameter:  ";
    232                                         message += temp;
     278                if (word->name == "C")
     279                {
     280                        Param par(word->tab, word->data);
     281                        SString attr = par.getStringById(FL_PE_CONN_ATTR);
     282                        if (attr.indexOf("$t", 0) != -1)
     283                        {
     284                                logMessage("fL_Builder", "tokenize", LOG_ERROR, "Attractor definition cannot contain time variable");
     285                                delete word;
     286                                return 1;
     287
     288                        }
     289                        if (attr != "")
     290                        {
     291                                fL_Word *attrword = NULL;
     292                                if (createWord(attr, attrword, numparams, begin, end) != 0)
     293                                {
     294                                        SString message = "Error during parsing attractor word:  ";
     295                                        message += attr;
    233296                                        logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
    234                                         delete eval;
    235297                                        delete word;
     298                                        if (attrword) delete attrword;
    236299                                        return 1;
    237300                                }
    238                                 word->parevals.push_back(eval);
     301                                if (attrword->builtin)
     302                                {
     303                                        logMessage("fL_Builder", "tokenize", LOG_ERROR, "Attractor words cannot be built-in");
     304                                        delete word;
     305                                        delete attrword;
     306                                        return 1;
     307                                }
     308                                delete attrword;
    239309                        }
    240310                }
     
    272342                parevals = src.parevals;
    273343
     344                builtin = src.builtin;
     345
    274346                data = NULL; // properties cannot be copied
    275347        }
     
    303375
    304376        builder->words[this->name.c_str()] = this;
     377        builder->wordnames.push_back(this->name.c_str());
    305378        return 0;
    306379}
     
    318391        *objpred = *builder->words[predecessor.c_str()];
    319392
     393        if (objpred->builtin)
     394        {
     395                logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Builtin words cannot be predecessors");
     396                return 1;
     397        }
     398
    320399        // parse condition
    321400        if (condition != "")
    322401        {
     402                if (objpred->builtin && (objpred->name == "N" || objpred->name == "C"))
     403                {
     404                        logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Rules with neuron/connection word predecessors cannot contain conditions");
     405                        return 1;
     406                }
    323407                std::string cond = condition.c_str();
    324408                condeval = new MathEvaluation(objpred->npar);
     
    340424        }
    341425
    342         if (builder->tokenize(successor, objsucc, objpred->npar) != 0)
     426        if (builder->tokenize(successor, objsucc, objpred->npar, begin, end) != 0)
    343427        {
    344428                logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Unable to process successor sequence");
     
    353437{
    354438        // tokenize axiom
    355         if (tokenize(axiom, genotype, 0) != 0)
     439        if (tokenize(axiom, genotype, 0, begin, end) != 0)
    356440        {
    357441                logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Unable to process axiom sequence");
     
    372456        switch (type)
    373457        {
    374         case fLElementType::TERM:
    375         {
    376                 tab = fL_word_paramtab;
    377                 obj = new fL_Word();
    378                 break;
    379         }
    380         case fLElementType::INFO:
    381         {
    382                 tab = fL_builder_paramtab;
    383                 obj = this;
    384                 break;
    385         }
    386         case fLElementType::RULE:
    387         {
    388                 tab = fL_rule_paramtab;
    389                 obj = new fL_Rule(begin, end);
    390                 break;
    391         }
    392         default:
    393                 break;
     458                case fLElementType::TERM:
     459                {
     460                        tab = fL_word_paramtab;
     461                        obj = new fL_Word();
     462                        break;
     463                }
     464                case fLElementType::INFO:
     465                {
     466                        tab = fL_builder_paramtab;
     467                        obj = this;
     468                        break;
     469                }
     470                case fLElementType::RULE:
     471                {
     472                        tab = fL_rule_paramtab;
     473                        obj = new fL_Rule(begin, end);
     474                        break;
     475                }
     476                default:
     477                        break;
    394478        }
    395479        Param par(tab);
     
    417501        stick->name = "S";
    418502        stick->npar = 8;
    419         for (int i = 0; i < PART_PROPS_COUNT; i++)
     503        for (int i = 0; i < FL_PART_PROPS_COUNT; i++)
    420504        {
    421505                stick->mut.addProperty(NULL, fL_part_names[i], "s", fL_part_fullnames[i], fL_part_fullnames[i], PARAM_CANOMITNAME, 0, -1);
    422506        }
    423507
    424         for (int i = 0; i < JOINT_PROPS_COUNT; i++)
     508        for (int i = 0; i < FL_JOINT_PROPS_COUNT; i++)
    425509        {
    426510                stick->mut.addProperty(NULL, fL_joint_names[i], "s", fL_joint_fullnames[i], fL_joint_fullnames[i], PARAM_CANOMITNAME, 0, -1);
     
    430514        stick->tab = ParamObject::makeParamTab((ParamInterface *)&stick->mut, 0, 0, stick->mut.firstMutableIndex());
    431515        words["S"] = stick;
     516        wordnames.push_back("S");
    432517
    433518        // neuron N
     
    435520        neuron->name = "N";
    436521        neuron->npar = 1;
    437         neuron->mut.addProperty(NULL, "d", "s", "details", "details", PARAM_CANOMITNAME, 0, -1);
     522        neuron->mut.addProperty(NULL, "d", "s", "details", "details", 0, 0, -1);
    438523        neuron->tab = ParamObject::makeParamTab((ParamInterface *)&neuron->mut, 0, 0, neuron->mut.firstMutableIndex());
    439524        words["N"] = neuron;
     525        wordnames.push_back("N");
    440526
    441527        // connection C
     
    443529        connection->name = "C";
    444530        connection->npar = 2;
    445         connection->mut.addProperty(NULL, "w", "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1);
    446         connection->mut.addProperty(NULL, "attr", "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1);
     531        connection->mut.addProperty(NULL, FL_PE_CONN_WEIGHT, "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1);
     532        connection->mut.addProperty(NULL, FL_PE_CONN_ATTR, "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1);
    447533        connection->tab = ParamObject::makeParamTab((ParamInterface *)&connection->mut, 0, 0, connection->mut.firstMutableIndex());
    448534        words["C"] = connection;
     535        wordnames.push_back("C");
    449536
    450537        // rotation objects
     
    463550        rotz->npar = 1;
    464551        rotz->processDefinition(this);
     552
     553        //fL_Branch *branch = new fL_Branch(fL_Branch::BranchType::OPEN, 0, 0);
     554        //branch->processDefinition(this);
     555
     556        builtincount = words.size();
    465557}
    466558
     
    521613                                return res;
    522614                        }
     615                        if (obj == this)
     616                        {
     617                                begin = lastpos;
     618                                end = pos - 1;
     619                        }
    523620                        res = obj->processDefinition(this);
    524621                        if (res != 0)
     
    546643                for (int i = 0; i < npar; i++)
    547644                {
     645                        SString t(par.id(i));
    548646                        if (parevals[i] != NULL)
    549647                        {
     
    667765        }
    668766        getStringifiedProducts();
     767        removeRedundantRules();
    669768        Param par(fL_builder_paramtab);
    670769        fL_Builder *obj = new fL_Builder();
     
    681780}
    682781
    683 int fL_Rule::deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime)
     782int fL_Rule::deploy(fL_Builder *builder, fL_Word *in, std::list<fL_Word *>::iterator &it, double currtime)
    684783{
    685784        // if predecessor and given word differ, then rule is not applicable
     
    720819
    721820        // remove predecessor word from genotype and replace it with successor
    722         it = genotype.erase(it);
     821        it = builder->genotype.erase(it);
    723822        for (std::list<fL_Word *>::iterator word = objsucc.begin(); word != objsucc.end(); word++)
    724823        {
    725824                // create new word and copy properties from word definition
    726                 fL_Word *nword = new fL_Word();
     825                fL_Word *nword = new fL_Word(false, begin, end);
    727826                *nword = **word;
    728827                // store information about when word has been created
     
    735834                // calculate word parameters and store MathEvaluation objects for further
    736835                // time manipulations.
     836                Param par((*word)->tab, (*word)->data);
     837                Param npar(nword->tab, nword->data);
    737838                for (int q = 0; q < nword->npar; q++)
    738839                {
    739840                        if ((*word)->parevals[q] == NULL)
    740841                        {
    741                                 MathEvaluation *ev = new MathEvaluation(0);
    742                                 ev->convertString("0");
    743                                 nword->parevals.push_back(ev);
     842                                if ((*word)->builtin && (strcmp(npar.id(q), "d") == 0))
     843                                {
     844                                        SString t = par.getString(q);
     845                                        npar.setString(q, t);
     846                                        nword->parevals.push_back(NULL);
     847                                }
     848                                if ((*word)->builtin && (strcmp(npar.id(q), FL_PE_CONN_ATTR) == 0))
     849                                {
     850                                        SString t = par.getString(q);
     851                                        if (t.len() > 0)
     852                                        {
     853                                                fL_Word *attrword = NULL;
     854                                                builder->createWord(t, attrword, in->npar, begin, end);
     855                                                for (int j = 0; j < attrword->npar; j++)
     856                                                {
     857                                                        if (attrword->parevals[j])
     858                                                        {
     859                                                                for (int i = 0; i < in->npar; i++)
     860                                                                {
     861                                                                        attrword->parevals[j]->modifyVariable(i, inwordvalues[i]);
     862                                                                }
     863                                                        }
     864                                                }
     865                                                SString res = attrword->stringify(false);
     866                                                npar.setString(q, res);
     867                                                nword->parevals.push_back(NULL);
     868                                                delete attrword;
     869                                        }
     870                                }
     871                                else
     872                                {
     873                                        //MathEvaluation *ev = new MathEvaluation(0);
     874                                        //ev->convertString("0");
     875                                        //nword->parevals.push_back(ev);
     876                                        nword->parevals.push_back(NULL);
     877                                }
    744878                        }
    745879                        else
     
    757891                        }
    758892                }
    759                 genotype.insert(it, nword);
     893                builder->genotype.insert(it, nword);
    760894        }
    761895        delete[] inwordvalues;
     
    773907                for (fL_Rule * rule : rules)
    774908                {
    775                         if (rule->deploy((*word), word, genotype, currtime) == 0)
     909                        if (rule->deploy(this, (*word), word, currtime) == 0)
    776910                        {
    777911                                deployed = true;
     
    806940        Param par(stickword->tab, stickword->data);
    807941        Param ppar = part->properties();
    808         for (int i = 0; i < PART_PROPS_COUNT; i++)
    809         {
    810                 double partprop;
     942        for (int i = 0; i < FL_PART_PROPS_COUNT; i++)
     943        {
     944                double mn, mx, df;
     945                ppar.getMinMaxDouble(ppar.findId(fL_part_names[i]), mn, mx, df);
    811946                double currval;
    812                 if (!ExtValue::parseDouble(par.getStringById(fL_part_names[i]).c_str(), currval, false))
    813                 {
    814                         logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
    815                                 "Error parsing word parameter");
    816                         return 1;
    817                 }
    818                 partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount +
    819                         currval) / (alterationcount + 1.0);
     947                if (!stickword->parevals[i])
     948                {
     949                        currval = df;
     950                }
     951                else
     952                {
     953                        stickword->parevals[i]->evaluateRPN(currval);
     954                        currval = sigmoidTransform(currval, mn, mx);
     955                }
     956                double partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount +
     957                                currval) / (alterationcount + 1.0);
    820958                ppar.setDoubleById(fL_part_names[i], partprop);
    821959        }
     
    823961}
    824962
    825 bool fL_Word::operator==(const fL_Word& other) const
    826 {
    827         if (name == other.name) return false;
    828         if (npar == other.npar) return false;
     963double fL_Word::distance(fL_Word *right)
     964{
     965        if (name != right->name || npar != right->npar)
     966        {
     967                return -1;
     968        }
     969        double distance = 0;
    829970        for (int i = 0; i < npar; i++)
    830971        {
    831                 if (parevals[i] && other.parevals[i])
    832                 {
    833                         double first;
    834                         double second;
    835                         parevals[i]->evaluateRPN(first);
    836                         other.parevals[i]->evaluateRPN(second);
    837                         if (first != second)
    838                         {
    839                                 return false;
    840                         }
    841                 }
    842                 else
    843                 {
    844                         return false;
    845                 }
    846         }
    847         return true;
    848 }
    849 
    850 void fL_Builder::findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it)
    851 {
    852         int rightdist = 0;
    853         std::list<fL_Word *>::iterator iter(it);
    854         for (; iter != genotype.end(); iter++)
    855         {
    856                 if (*word == **iter)
    857                 {
    858                         break;
    859                 }
    860                 rightdist++;
    861         }
    862         int leftdist = 0;
    863         std::list<fL_Word *>::reverse_iterator riter(it);
    864         for (; riter != genotype.rend(); riter++)
    865         {
    866                 if (*word == **riter)
    867                 {
    868                         break;
    869                 }
    870                 leftdist++;
    871         }
    872         if (iter == genotype.end())
    873         {
    874                 it = riter.base();
    875         }
    876         else if (riter == genotype.rend())
    877         {
    878                 it = iter;
    879         }
    880         else if (leftdist < rightdist)
    881         {
    882                 it = riter.base();
     972                double l = 0;
     973                double r = 0;
     974                if (parevals[i]) parevals[i]->evaluateRPN(l);
     975                if (right->parevals[i]) right->parevals[i]->evaluateRPN(r);
     976                distance += (l - r) * (l - r);
     977        }
     978        return sqrt(distance);
     979}
     980
     981Neuro *fL_Builder::findInputNeuron(std::pair<std::list<fL_Word *>::iterator, Neuro *> currneu, fL_Word *attractor)
     982{
     983        if (!attractor)
     984        {
     985                std::list<fL_Word *>::reverse_iterator riter(currneu.first);
     986                std::list<fL_Word *>::iterator iter(currneu.first);
     987                iter++;
     988                while (riter != genotype.rend() || iter != genotype.end())
     989                {
     990                        if (iter != genotype.end())
     991                        {
     992                                if ((*iter)->name == "N" && (*iter)->bodyelementpointer != currneu.second)
     993                                {
     994                                        return (Neuro *)(*iter)->bodyelementpointer;
     995                                }
     996                                iter++;
     997                        }
     998                        if (riter != genotype.rend())
     999                        {
     1000                                if ((*riter)->name == "N" && (*riter)->bodyelementpointer != currneu.second)
     1001                                {
     1002                                        return (Neuro *)(*riter)->bodyelementpointer;
     1003                                }
     1004                                riter++;
     1005                        }
     1006                }
     1007                return NULL;
    8831008        }
    8841009        else
    8851010        {
    886                 it = iter;
    887         }
    888 }
    889 
    890 Neuro *fL_Builder::findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor)
    891 {
    892         if (!attractor)
    893         {
    894                 attractor = new fL_Word();
    895                 *attractor = *(*it);
    896                 attractor->data = NULL;
    897                 // TODO implement
     1011                double mindistance = -1;
     1012                std::list<fL_Word *>::iterator minit = genotype.end();
     1013                for (std::list<fL_Word *>::iterator it = genotype.begin(); it != genotype.end(); it++)
     1014                {
     1015                        double currdist = attractor->distance((*it));
     1016                        if (currdist != -1 && (currdist < mindistance || mindistance == -1))
     1017                        {
     1018                                mindistance = currdist;
     1019                                minit = it;
     1020                        }
     1021                }
     1022                if (minit != genotype.end())
     1023                {
     1024                        for (; minit != genotype.end(); minit++)
     1025                        {
     1026                                if ((*minit)->name == "N" && (*minit)->bodyelementpointer)
     1027                                {
     1028                                        Neuro *n = (Neuro *)(*minit)->bodyelementpointer;
     1029                                        if (n->getClass()->getPreferredOutput() != 0)
     1030                                        {
     1031                                                return n;
     1032                                        }
     1033                                }
     1034                        }
     1035                }
    8981036        }
    8991037        return NULL;
    9001038}
    9011039
    902 int fL_Builder::developModel(Model &model)
    903 {
    904         // TODO implement
     1040double fL_Builder::sigmoidTransform(double input, double mn, double mx)
     1041{
     1042        return mn + (mx - mn) * (1.0 / (1.0 + exp(-input)));
     1043}
     1044
     1045int fL_Builder::buildModelFromSequence(Model *model)
     1046{
    9051047        fL_State currstate;
    9061048        std::unordered_map<Part *, double> counters;
     
    9231065                                                firstpart->p = Pt3D_0;
    9241066                                                counters[firstpart] = 0;
    925                                                 model.addPart(firstpart);
     1067                                                model->addPart(firstpart);
     1068                                                if (using_mapping) firstpart->addMapping(IRange(word->begin, word->end));
    9261069                                        }
    9271070                                        currstate.currpart = firstpart;
     
    9411084                                Param par(word->tab, word->data);
    9421085                                double length;
    943                                 if (!ExtValue::parseDouble(par.getStringById("l").c_str(), length, false))
    944                                 {
    945                                         delete newpart;
    946                                         logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
    947                                                 "Error parsing word parameter");
    948                                         return 1;
     1086                                if (!word->parevals[FL_PART_PROPS_COUNT + FL_JOINT_PROPS_COUNT])
     1087                                {
     1088                                        length = FL_DEFAULT_LENGTH; // default length value
     1089                                }
     1090                                else
     1091                                {
     1092                                        double parsedval = 0.0;
     1093                                        if (word->parevals[FL_PART_PROPS_COUNT + FL_JOINT_PROPS_COUNT]->evaluateRPN(parsedval) != 0)
     1094                                        {
     1095                                                delete newpart;
     1096                                                logMessage("fL_Builder", "developModel", LOG_ERROR,
     1097                                                                "Error parsing word parameter");
     1098                                                return 1;
     1099                                        }
     1100                                        length = sigmoidTransform(parsedval, FL_MINIMAL_LENGTH, FL_MAXIMAL_LENGTH);
    9491101                                }
    9501102                                newpart->p = currstate.currpart->p + currstate.direction * length;
    9511103                                counters[newpart] += 1;
    952                                 model.addPart(newpart);
    953 
     1104                                model->addPart(newpart);
     1105                                if (using_mapping) newpart->addMapping(IRange(word->begin, word->end));
    9541106                                Joint *newjoint = new Joint();
    9551107                                newjoint->attachToParts(currstate.currpart, newpart);
    9561108
    9571109                                Param jpar = newjoint->properties();
    958                                 for (int i = 0; i < JOINT_PROPS_COUNT; i++)
    959                                 {
     1110                                for (int i = 0; i < FL_JOINT_PROPS_COUNT; i++)
     1111                                {
     1112                                        double mn, mx, df;
     1113                                        jpar.getMinMaxDouble(jpar.findId(fL_joint_names[i]), mn, mx, df);
    9601114                                        double jointprop;
    961                                         if (!ExtValue::parseDouble(par.getStringById(fL_joint_names[i]).c_str(), jointprop, false))
     1115                                        if (!word->parevals[FL_PART_PROPS_COUNT + i])
    9621116                                        {
    963                                                 logMessage("fL_Builder", "developModel", LOG_ERROR,
    964                                                         "Error parsing word parameter");
    965                                                 delete newjoint;
    966                                                 return 1;
     1117                                                jointprop = df; // assign default value
     1118                                        }
     1119                                        else
     1120                                        {
     1121                                                if (word->parevals[FL_PART_PROPS_COUNT + i]->evaluateRPN(jointprop) != 0)
     1122                                                {
     1123                                                        logMessage("fL_Builder", "developModel", LOG_ERROR,
     1124                                                                        "Error parsing word parameter");
     1125                                                        delete newjoint;
     1126                                                        return 1;
     1127                                                }
     1128                                                jointprop = sigmoidTransform(jointprop, mn, mx);
    9671129                                        }
    9681130                                        jpar.setDoubleById(fL_joint_names[i], jointprop);
    9691131                                }
    970                                 model.addJoint(newjoint);
     1132                                model->addJoint(newjoint);
     1133                                if (using_mapping) newjoint->addMapping(IRange(word->begin, word->end));
    9711134                                currstate.currpart = newpart;
    9721135                        }
     
    9751138                                Param npar(word->tab, word->data);
    9761139                                Neuro *neu = new Neuro();
    977                                 neu->setDetails(npar.getStringById("d"));
     1140                                SString details = npar.getStringById("d");
     1141                                if (details == "")
     1142                                {
     1143                                        details = "N";
     1144                                }
     1145                                neu->setDetails(details);
    9781146                                if (!neu->getClass())
    9791147                                {
     
    9821150                                        return 1;
    9831151                                }
    984                                 model.addNeuro(neu);
    985                                 currstate.currneuron = neu;
     1152                                model->addNeuro(neu);
     1153                                if (using_mapping) neu->addMapping(IRange(word->begin, word->end));
     1154                                if (neu->getClass()->getPreferredInputs() != 0)
     1155                                {
     1156                                        currstate.currneuron = neu;
     1157                                }
     1158                                word->bodyelementpointer = neu;
    9861159                        }
    9871160                        else if (word->name == "C")
    9881161                        {
    989                                 connsbuffer.push_back({ w, currstate.currneuron });
     1162                                connsbuffer.push_back({w, currstate.currneuron});
    9901163                        }
    9911164                        else if (word->name.startsWith("rot"))
    9921165                        {
    993                                 Orient rotmatrix;
     1166                                Orient rotmatrix = Orient_1;
    9941167                                double rot;
    995                                 if (word->parevals[0]->evaluateRPN(rot) != 0)
    996                                 {
    997                                         logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class");
     1168                                if (!word->parevals[0])
     1169                                {
     1170                                        rot = 0;
     1171                                }
     1172                                else if (word->parevals[0]->evaluateRPN(rot) != 0)
     1173                                {
     1174                                        logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing rotation word");
    9981175                                        return 1;
    9991176                                }
     1177
     1178                                rot = sigmoidTransform(rot, -M_PI, M_PI);
     1179
    10001180                                if (word->name == "rotX")
    10011181                                {
    1002                                         rotmatrix.rotate(Pt3D(rot, 0.0, 0.0));
     1182                                        rotmatrix.rotate(Pt3D(rot,0,0));
    10031183                                }
    10041184                                else if (word->name == "rotY")
    10051185                                {
    1006                                         rotmatrix.rotate(Pt3D(0.0, rot, 0.0));
     1186                                        rotmatrix.rotate(Pt3D(0,rot,0));
    10071187                                }
    10081188                                else if (word->name == "rotZ")
    10091189                                {
    1010                                         rotmatrix.rotate(Pt3D(0.0, 0.0, rot));
     1190                                        rotmatrix.rotate(Pt3D(0,0,rot));
    10111191                                }
    10121192                                currstate.direction = rotmatrix.transform(currstate.direction);
     1193                                currstate.direction.normalize();
    10131194                        }
    10141195                        else if (word->name == "[")
     
    10251206
    10261207        // connections need
    1027         //      for (std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer)
    1028         //      {
    1029         //
    1030         //      }
     1208        // std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer
     1209        for (unsigned int i = 0; i < connsbuffer.size(); i++)
     1210        {
     1211                if (connsbuffer[i].second == NULL ||
     1212                                (connsbuffer[i].second->getClass()->getPreferredInputs() != -1 &&
     1213                                connsbuffer[i].second->getInputCount() >=
     1214                                connsbuffer[i].second->getClass()->getPreferredInputs()))
     1215                {
     1216                        // since connections are separated entities from neurons, it may happen
     1217                        // that there will be no neuron to connect to
     1218                        // logMessage("fL_Builder", "developModel", LOG_DEBUG, "Connection could not be established");
     1219                }
     1220                else
     1221                {
     1222                        Param par((*connsbuffer[i].first)->tab, (*connsbuffer[i].first)->data);
     1223                        SString attr = par.getStringById(FL_PE_CONN_ATTR);
     1224                        fL_Word *attractor = NULL;
     1225                        if (attr.len() > 0)
     1226                        {
     1227                                createWord(attr, attractor, 0, (*connsbuffer[i].first)->begin, (*connsbuffer[i].first)->end);
     1228                        }
     1229                        Neuro *neu = findInputNeuron(connsbuffer[i], attractor);
     1230                        double weight = 0.0;
     1231                        if ((*connsbuffer[i].first)->parevals[0])
     1232                        {
     1233                                if ((*connsbuffer[i].first)->parevals[0]->evaluateRPN(weight) != 0)
     1234                                {
     1235                                        logMessage("fL_Builder", "developModel", LOG_ERROR,
     1236                                                        "Error parsing word parameter");
     1237                                        delete attractor;
     1238                                        return 1;
     1239                                }
     1240                        }
     1241                        if (neu)
     1242                        {
     1243                                connsbuffer[i].second->addInput(neu, weight);
     1244                                if (using_mapping) neu->addMapping(
     1245                                                IRange((*connsbuffer[i].first)->begin,
     1246                                                                (*connsbuffer[i].first)->end));
     1247                        }
     1248                        else
     1249                        {
     1250                                connsbuffer[i].second->addInput(connsbuffer[i].second, weight);
     1251                                if (using_mapping) neu->addMapping(
     1252                                                IRange((*connsbuffer[i].first)->begin,
     1253                                                                (*connsbuffer[i].first)->end));
     1254                        }
     1255                        delete attractor;
     1256                }
     1257        }
    10311258        return 0;
    10321259}
    10331260
    1034 int fL_Builder::develop()
    1035 {
    1036         Model m;
     1261void fL_Builder::clearModelElements(Model *m)
     1262{
     1263        for (int i = 0; i < m->getJointCount(); i++)
     1264        {
     1265                m->removeJoint(i, 0);
     1266        }
     1267        for (int i = 0; i < m->getNeuroCount(); i++)
     1268        {
     1269                m->removeNeuro(i, true);
     1270        }
     1271        for (int i = 0; i < m->getNeuroCount(); i++)
     1272        {
     1273                m->removePart(i, 0, 0);
     1274        }
     1275        m->clearMap();
     1276}
     1277
     1278Model* fL_Builder::developModel(double &neededtime)
     1279{
    10371280        double curriter = 0;
    10381281        double timestamp = 1.0 / numckp;
    10391282        double t = 0;
    1040         for (; t <= time; t += timestamp)
     1283        Model *m = new Model();
     1284        m->open(using_checkpoints);
     1285        bool wordsexceeded = false;
     1286        for (; t <= time; t+= timestamp)
    10411287        {
    10421288                alterTimedProperties(t); // always alter timed properties in the beginning
     
    10451291                {
    10461292                        iterate(t);
    1047                         curriter += 1.0;
    1048                 }
    1049         }
     1293                        curriter+=1.0;
     1294                }
     1295                if (using_checkpoints)
     1296                {
     1297                        clearModelElements(m);
     1298                        if (buildModelFromSequence(m) != 0)
     1299                        {
     1300                                delete m;
     1301                                return NULL;
     1302                        }
     1303                        m->checkpoint();
     1304                }
     1305                if (maxwords != -1 && genotype.size() > (unsigned int)maxwords)
     1306                {
     1307                        wordsexceeded = true;
     1308                        break;
     1309                }
     1310        }
     1311
     1312        if (wordsexceeded)
     1313        {
     1314                neededtime = t;
     1315        }
     1316        else
     1317        {
     1318                neededtime = time;
     1319        }
     1320
    10501321        // if exact time of development was not reached due to floating point errors,
    10511322        // then alter timed properties
     
    10541325                alterTimedProperties(time);
    10551326        }
    1056         return 0;
    1057 }
     1327        clearModelElements(m);
     1328        if (buildModelFromSequence(m) != 0)
     1329        {
     1330                delete m;
     1331                return NULL;
     1332        }
     1333        if (using_checkpoints)
     1334        {
     1335                m->checkpoint();
     1336        }
     1337        m->close();
     1338        return m;
     1339}
     1340
     1341int fL_Builder::countSticksInSequence(std::list<fL_Word *> sequence)
     1342{
     1343        int count = 0;
     1344        for (std::list<fL_Word *>::iterator it = sequence.begin(); it != sequence.end(); it++)
     1345        {
     1346                if ((*it)->builtin && (*it)->name == "S")
     1347                {
     1348                        count++;
     1349                }
     1350        }
     1351        return count;
     1352}
     1353
     1354int fL_Builder::countDefinedWords()
     1355{
     1356        return words.size() - builtincount;
     1357}
     1358
     1359int fL_Builder::countWordsInLSystem()
     1360{
     1361        int count = genotype.size();
     1362        for (fL_Rule *rul: rules)
     1363        {
     1364                count += rul->objsucc.size();
     1365        }
     1366        count += words.size();
     1367        return count;
     1368}
     1369
     1370void fL_Builder::removeRedundantRules()
     1371{
     1372        for (std::vector<fL_Rule *>::iterator it = rules.begin();
     1373                        it != rules.end(); it++)
     1374        {
     1375                std::vector<fL_Rule *>::iterator it2 = it;
     1376                it2++;
     1377                while (it2 != rules.end())
     1378                {
     1379                        bool todelete = false;
     1380                        if ((*it)->objpred->name == (*it2)->objpred->name)
     1381                        {
     1382                                if ((*it)->condeval == NULL && (*it2)->condeval == NULL)
     1383                                {
     1384                                        todelete = true;
     1385                                }
     1386                                else if ((*it)->condeval == NULL && (*it2)->condeval != NULL)
     1387                                {
     1388                                        std::iter_swap(it, it2);
     1389                                }
     1390                                else if ((*it)->condeval != NULL && (*it2)->condeval != NULL)
     1391                                {
     1392                                        if ((*it)->condeval->getStringifiedRPN() ==
     1393                                                        (*it2)->condeval->getStringifiedRPN())
     1394                                        {
     1395                                                todelete = true;
     1396                                        }
     1397                                }
     1398                        }
     1399                        if (todelete)
     1400                        {
     1401                                delete (*it2);
     1402                                it2 = rules.erase(it2);
     1403                        }
     1404                        else
     1405                        {
     1406                                it2++;
     1407                        }
     1408                }
     1409        }
     1410}
  • cpp/frams/genetics/fL/fL_general.h

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#ifndef _FL_GENERAL_
    2 
    36#define _FL_GENERAL_
    47
     
    2225/** @name Constants used in fL methods */
    2326//@{
    24 #define PART_PROPS_COUNT   4 ///<Count of part properties
    25 #define JOINT_PROPS_COUNT  3 ///<Count of joint properties
    26 #define PE_NEURO_DET       "d" ///<Id of details type definition in f0_neuro_paramtab
    27 #define PE_CONN_WEIGHT     "w" ///<Id of weight type definition in f0_neuroconn_paramtab
     27#define FL_PART_PROPS_COUNT   4 ///<Count of part properties
     28#define FL_JOINT_PROPS_COUNT  3 ///<Count of joint properties
     29#define FL_PE_NEURO_DET       "d" ///<Id of details type definition in f0_neuro_paramtab
     30#define FL_PE_CONN_WEIGHT     "w" ///<Id of weight type definition in f0_neuroconn_paramtab
     31#define FL_PE_CONN_ATTR       "attr" ///<Id of attractor of neural connection
     32#define FL_DEFAULT_LENGTH     1.0 ///<Default length of a stick in fL encoding
     33#define FL_MINIMAL_LENGTH     0.0 ///<Minimal length of a stick in fL encoding
     34#define FL_MAXIMAL_LENGTH     2.0 ///<Maximal length of a stick in fL encoding
     35#define FL_MAXITER           "100.0" ///<Maximal iteration available in fL
     36#define FL_MAXPARAMS          "3" ///<Maximal number of user-parameters
    2837//@}
    2938
    3039extern const char *fL_part_names[];
    3140extern const char *fL_joint_names[];
    32 extern const char *fL_joint_fullnames[JOINT_PROPS_COUNT];
    33 extern const char *fL_part_fullnames[PART_PROPS_COUNT];
     41extern const char *fL_joint_fullnames[FL_JOINT_PROPS_COUNT];
     42extern const char *fL_part_fullnames[FL_PART_PROPS_COUNT];
    3443
    3544#define LSYSTEM_PARAM_TYPE "s" ///< standard type of L-System elements
     
    4655        fLElementType type; ///< type of fL_Element
    4756
    48         fL_Element(fLElementType type) : type(type) {}
     57        int begin; ///<beginning of the element definition in genotype
     58        int end; ///<end of the element definition in genotype
     59
     60
     61        fL_Element(fLElementType type) : type(type) { begin = end = 0; }
    4962        virtual ~fL_Element() { }
    5063
     
    7891        void *data; ///<pointer to properties of word
    7992        bool builtin; ///<determines if word is built-in (true) or not (false).
     93        PartBase *bodyelementpointer; ///<helper field for built-in words
    8094        std::vector<MathEvaluation *> parevals; ///<stores MathEvaluation objects with parameter functions
    8195        double creationiter; ///<this helper field is used during L-System iterations and determines when word was created
    82         fL_Word(bool builtin = false) :
    83                 fL_Element(fLElementType::TERM), mut("Word", "Properties"), //TODO change Word to Term everywhere
     96        fL_Word(bool builtin = false, int begin = 0, int end = 0) :
     97                fL_Element(fLElementType::TERM), mut("Word", "Properties"),
    8498                builtin(builtin)
    8599        {
     
    89103                data = NULL;
    90104                creationiter = 0;
     105                this->begin = begin;
     106                this->end = end;
     107                bodyelementpointer = NULL;
    91108        }
    92109
     
    102119                for (MathEvaluation *ev : parevals)
    103120                {
    104                         delete ev;
     121                        if (ev) delete ev;
    105122                }
    106123                parevals.clear();
     
    125142
    126143        /**
    127          * TODO
    128          */
    129         bool operator==(const fL_Word& other) const;
    130 
    131         /**
    132144         * Returns 'w:' line defining word in genotype.
    133145         * @return string representation of word definition
     
    150162         */
    151163        int saveEvals(bool keepformulas);
     164
     165        /**
     166         * Computes distance between two L-System words in genotype. Distance has sense
     167         * only when two words have the same name. Otherwise, returned value equals -1.
     168         * The distance is computed as Euclidean distance between words arguments.
     169         * @param right the second word
     170         * @return Euclidean distance between words in genotype or -1 if words have different name
     171         */
     172        double distance(fL_Word *right);
    152173};
    153174
     
    164185        };
    165186        BranchType btype; ///< branch parenthesis type
    166         fL_Branch(BranchType branchtype) : fL_Word()
     187        fL_Branch(BranchType branchtype, int begin, int end) : fL_Word(true, begin, end)
    167188        {
    168189                type = fLElementType::BRANCH;
     
    192213        std::list<fL_Word *> objsucc; ///<objec representation of successors
    193214
    194         int start; ///<beginning of the rule definition in genotype
    195         int end; ///<end of the rule definition in genotype
    196 
    197         fL_Rule(int start, int end) : fL_Element(fLElementType::RULE),
    198                 start(start), end(end)
     215        fL_Rule(int begin, int end)  : fL_Element(fLElementType::RULE)
    199216        {
    200217                predecessor = "";
     
    203220                objpred = NULL;
    204221                condeval = NULL;
     222                this->begin = begin;
     223                this->end = end;
    205224        }
    206225
     
    231250         * pointer and iterator of list and inserting successor sequence into list.
    232251         * Final iterator value points to the first word after processed word.
     252         * @param builder builder containing current genotype
    233253         * @param in word that is currently processed
    234254         * @param it iterator of genotype list which determines position of current analysis
    235          * @param genotype current genotype. Words on the left of genotype are processed and possibly replaced by previous rules
    236255         * @param currtime value representing continuous time value for rule
    237256         * @return 0 if rule processed current word, 1 if rule is no applicable
    238257         */
    239         int deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime);
    240 };
    241 
     258        int deploy(fL_Builder *builder, fL_Word *in, std::list<fL_Word *>::iterator &it, double currtime);
     259};
     260
     261/**
     262 * Structure for holding current Turtle state.
     263 */
    242264struct fL_State
    243265{
     
    245267        Part *currpart; ///<Latest created part
    246268        Neuro *currneuron; ///<Latest created neuron
    247         fL_State() : direction(1, 0, 0), currpart(NULL), currneuron(NULL)
     269        fL_State() : direction(1,0,0), currpart(NULL), currneuron(NULL)
    248270        { }
    249271};
     
    266288        double time; ///<time of creature development
    267289        int numckp; ///<number of checkpoints per growth step - checkpoints are always created after rules deployment in integer steps, numckp determines how many checkpoints should be created within single step (to watch changes of parameters)
     290        int maxwords; ///<maximum number of words that can
     291        bool using_checkpoints; ///<true if checkpoints should be created, or false
     292        bool using_mapping; ///<true if mappings should be created, or false
     293
     294        int builtincount; ///<number of built-in words
    268295
    269296        std::list<fL_Word *> genotype; ///<list of current words of genotype
    270297        std::unordered_map<std::string, fL_Word *> words; ///<map from string to words existing in L-System
     298        std::vector<std::string> wordnames;
    271299        std::vector<fL_Rule *> rules; ///<rules available in system
    272300
    273         fL_Builder() : fL_Element(fLElementType::INFO)
     301        fL_Builder(bool using_mapping = false, bool using_checkpoints = false) : fL_Element(fLElementType::INFO),
     302                        using_checkpoints(using_checkpoints), using_mapping(using_mapping)
    274303        {
    275304                axiom = "";
    276305                time = 1.0;
    277306                numckp = 1;
     307                builtincount = 0;
     308                maxwords = -1;
    278309        }
    279310        ~fL_Builder();
     
    337368
    338369        /**
     370         * Creates fL_Word object for a given token.
     371         * @param worddef string representing single word object in sequence
     372         * @param word a reference to a pointer of created word by this method
     373         * @param numparams number of parameters for a given sequence (usually number of rule predecessor's arguments)
     374         * @param begin the begin of word definition in genotype
     375         * @param end the end of word definition in genotype
     376         * @return 0 if conversion went successfully, 1 when there is a problem with parsing
     377         */
     378        int createWord(SString worddef, fL_Word *&word, int numparams, int begin, int end);
     379
     380        /**
    339381         * Helper function that converts input sequence into list of L-System words.
    340382         * @param sequence input sequence of stringified word objects
     
    343385         * @return 0 if tokenizing finished successfully, 1 otherwise
    344386         */
    345         int tokenize(SString sequence, std::list<fL_Word *> &result, int numparams);
     387        int tokenize(SString sequence, std::list<fL_Word *> &result, int numparams, int begin, int end);
    346388
    347389        /**
     
    363405        /**
    364406         * Developes L-System from given genotype and builds Framsticks Model from it.
    365          */
    366         int develop();
     407         * When using_checkpoints is enabled, method generates checkpoint for each
     408         * step defined in timestamp.
     409         * @param neededtime reference to a time value after stopping development (usually it will be equal to time specified in the time field, unless the number of allowed words will be exceeded earlier)
     410         * @return final model from a fL genotype
     411         */
     412        Model* developModel(double &neededtime);
    367413
    368414        /**
     
    371417         * @return 0 if developing went successfully, 1 otherwise
    372418         */
    373         int developModel(Model &model);
     419        int buildModelFromSequence(Model *model);
    374420
    375421        /**
     
    386432
    387433        /**
    388          * TODO
     434         * Alters part properties according to informations stored in stickword.
     435         * Method takes current values of part's properties computed from previous
     436         * calls of the alterPartProperties and computes mean according to upcoming
     437         * values of properties.
     438         * @param part analysed part
     439         * @param stickword the L-System word that affects current part
     440         * @param alterationcount the number of times of part modifications - used to compute mean of every word properties
     441         * @return always 0
    389442         */
    390443        int alterPartProperties(Part *part, fL_Word *stickword, double &alterationcount);
    391444
    392445        /**
    393          * TODO
    394          */
    395         Neuro *findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor);
    396 
    397         /**
    398          * TODO
    399          */
    400         void findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it);
     446         * Finds input neuron that is nearest to attractor or connection definition.
     447         * When attractor object is given, then the word with name matching attractor and
     448         * with nearest values of parameters is chosen as the point, from which input
     449         * neuron is looked for. The searching goes both sides.
     450         * @param currneu object storing informations about connection word iterator and current neuron
     451         * @param attractor pointer to an attractor definition presented in connection word
     452         * @return pointer to the input neuron, or NULL if no neuron could be found
     453         */
     454        Neuro *findInputNeuron(std::pair<std::list<fL_Word *>::iterator, Neuro *> currneu, fL_Word *attractor);
     455
     456        /**
     457         * Removes joints, parts and neurons with its connections from current model, without
     458         * removing checkpoint data.
     459         * @param m model to clear
     460         */
     461        void clearModelElements(Model *m);
     462
     463        /**
     464         * Converts parameters defined in built-in words into desired
     465         * range with use of sigmoid function, which ensures staying
     466         * within min and max value.
     467         * @param input the value from evaluation of parameter
     468         * @param min minimal value of property
     469         * @param max maximal value of property
     470         * @return value of body element property
     471         */
     472        double sigmoidTransform(double input, double min, double max);
     473
     474        /**
     475         * Counts words defined in the genotype.
     476         * @return number of defined words
     477         */
     478        int countDefinedWords();
     479
     480        /**
     481         * Counts number of sticks in a given sequence
     482         * @return number of sticks in sequence
     483         */
     484        int countSticksInSequence(std::list<fL_Word *> sequence);
     485
     486        /**
     487         * Counts all definitions of words, all words in axiom and rule successors in a genotype.
     488         * Used for computing change between original genotype and mutation.
     489         * @return number of words in definitions, axiom and rule successors
     490         */
     491        int countWordsInLSystem();
     492
     493        /**
     494         * Sorts rules and removes rules that will not be used. The "sorting" is
     495         * done in such way that all rules with conditions are first, and rules
     496         * without conditions go to the end. If there are more than one rule
     497         * for the same word with no condition or same condition, than the
     498         * second one is removed.
     499         */
     500        void removeRedundantRules();
    401501};
    402502
  • cpp/frams/genetics/fL/fL_matheval.cpp

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#include <frams/util/extvalue.h>
    26#include <frams/util/sstring.h>
    37#include <stack>
    48#include "fL_matheval.h"
     9#include <frams/genetics/genooperators.h>
    510
    611// Used available operators in MathEvaluation
     
    9499}
    95100
     101void MathEvaluation::registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol)
     102{
     103        operators[opsymbol] = new Operator(operation, precedence, assoc, opsymbol);
     104        operatorstrings.push_back(opsymbol);
     105}
     106
    96107void MathEvaluation::registerOperators()
    97108{
    98109        // list of available operators in MathEvaluation
    99         operators["+"] = new Operator(madd, 2, Associativity::LEFT, "+");
    100         operators["-"] = new Operator(msub, 2, Associativity::LEFT, "-");
    101         operators["*"] = new Operator(mmul, 3, Associativity::LEFT, "*");
    102         operators["&"] = new Operator(mand, 0, Associativity::LEFT, "&");
    103         operators["|"] = new Operator(mor, 0, Associativity::LEFT, "|");
    104         operators[">"] = new Operator(mgreater, 1, Associativity::LEFT, ">");
    105         operators["<"] = new Operator(mless, 1, Associativity::LEFT, "<");
    106         operators[">="] = new Operator(meqgreater, 1, Associativity::LEFT, ">=");
    107         operators["<="] = new Operator(meqless, 1, Associativity::LEFT, "<=");
    108         operators["="] = new Operator(mequal, 1, Associativity::RIGHT, "=");
    109         operators["~"] = new Operator(mnotequal, 1, Associativity::RIGHT, "~");
     110        registerOperator(madd, 2, Associativity::LEFT, "+");
     111        registerOperator(msub, 2, Associativity::LEFT, "-");
     112        registerOperator(mmul, 3, Associativity::LEFT, "*");
     113        registerOperator(mgreater, 1, Associativity::LEFT, ">");
     114        registerOperator(mless, 1, Associativity::LEFT, "<");
     115        registerOperator(meqgreater, 1, Associativity::LEFT, ">=");
     116        registerOperator(meqless, 1, Associativity::LEFT, "<=");
     117        registerOperator(mequal, 1, Associativity::RIGHT, "=");
     118        registerOperator(mnotequal, 1, Associativity::RIGHT, "~");
     119        registerOperator(mand, 0, Associativity::LEFT, "&");
     120        registerOperator(mor, 0, Associativity::LEFT, "|");
     121        arithmeticoperatorscount = 3;
     122        comparisonoperatorscount = 6;
    110123}
    111124
     
    159172int MathEvaluation::convertString(std::string expression)
    160173{
     174        originalexpression = expression;
    161175        clearPostfix(); //clear previous objects
    162176        ExtValue val;
     
    193207                                        {
    194208                                                delete operatorstack.back();
    195                                                 operatorstack.pop_back();
    196                                         }
     209                                        }
     210                                        operatorstack.pop_back();
    197211                                }
    198212                                return -1;
     
    247261                                        {
    248262                                                delete operatorstack.back();
    249                                                 operatorstack.pop_back();
    250                                         }
     263                                        }
     264                                        operatorstack.pop_back();
    251265                                }
    252266                                return -1;
     
    407421                                        {
    408422                                                delete operatorstack.back();
    409                                                 operatorstack.pop_back();
    410                                         }
     423                                        }
     424                                        operatorstack.pop_back();
    411425                                }
    412426                                return -1;
     
    434448                                {
    435449                                        delete operatorstack.back();
    436                                         operatorstack.pop_back();
    437                                 }
     450                                }
     451                                operatorstack.pop_back();
    438452                        }
    439453                        return -1;
     
    448462        // stack holds number used during operator execution
    449463        std::stack<Number *> numberstack;
    450 
    451464        for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
    452465        {
     
    532545int MathEvaluation::RPNToInfix(std::string &result)
    533546{
     547        if (postfixlist.size() == 0)
     548        {
     549                result = "";
     550                return 0;
     551        }
    534552        // stack holds stringified chunk and its precedence
    535553        std::stack<std::pair<std::string, int>> chunks;
     
    585603        {
    586604                logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
    587                         "Could not convert RPN notation to infix notation");
     605                        "Could not convert RPN notation to infix notation - formula is not complete");
    588606                return -1;
    589607        }
     
    592610        return 0;
    593611}
     612
     613void MathEvaluation::mutateValueOrVariable(MathEvaluation::Number *&currval, bool usetime)
     614{
     615        if (randomN(2) == 0 && varcount > 0) // use variable
     616        {
     617                if (currval && currval->type == TokenType::NUMBER)
     618                {
     619                        delete currval;
     620                }
     621                int var = randomN(varcount + (usetime ? 1 : 0));
     622                if (varcount == var) // time is used
     623                {
     624                        currval = t;
     625                }
     626                else
     627                {
     628                        currval = vars[var];
     629                }
     630        }
     631        else
     632        {
     633                if (!currval || currval->type == TokenType::VARIABLE)
     634                {
     635                        currval = new Number(rnd01);
     636                }
     637                else
     638                {
     639                        currval->value = rnd01;
     640                }
     641        }
     642}
     643
     644MathEvaluation::Operator* MathEvaluation::getRandomOperator(int type)
     645{ // 0 for all, 1 for arithmetic only, 2 for logical only
     646        int randop = type == 2 ? arithmeticoperatorscount : 0;
     647        int count = arithmeticoperatorscount;
     648        if (type == 0)
     649        {
     650                count = operatorstrings.size();
     651        }
     652        else if (type == 2)
     653        {
     654                count = operatorstrings.size() - arithmeticoperatorscount;
     655        }
     656        randop += randomN(count);
     657        return operators[operatorstrings[randop]];
     658}
     659
     660void MathEvaluation::mutateConditional()
     661{
     662        if (varcount > 0)
     663        {
     664                int currsize = postfixlist.size();
     665                int varid = randomN(varcount);
     666                postfixlist.push_back(vars[varid]);
     667                if (randomN(2) == 0 && varcount > 1)
     668                {
     669                        int varid2 = randomN(varcount - 1);
     670                        if (varid2 >= varid) varid2++;
     671                        postfixlist.push_back(vars[varid2]);
     672                }
     673                else
     674                {
     675                        Number *num = new Number(rnd01);
     676                        postfixlist.push_back(num);
     677                }
     678                int opid = arithmeticoperatorscount + randomN(comparisonoperatorscount);
     679                postfixlist.push_back(operators[operatorstrings[opid]]);
     680                if (currsize > 0)
     681                {
     682                        postfixlist.push_back(operators["&"]);
     683                }
     684        }
     685}
     686
     687int MathEvaluation::mutate(bool logical, bool usetime)
     688{
     689        if (postfixlist.size() == 0)
     690        {
     691                Number *val = new Number(rnd01);
     692                postfixlist.push_back(val);
     693                return -1;
     694        }
     695        int method = randomN(postfixlist.size() < MAX_MUT_FORMULA_SIZE ? MATH_MUT_COUNT : MATH_MUT_COUNT - 1);
     696        switch (method)
     697        {
     698        case MATH_MUT_INSERTION:
     699        {
     700                std::list<Token *> insertpair;
     701                Number *val = NULL;
     702                mutateValueOrVariable(val, usetime);
     703                insertpair.push_back(val);
     704                std::list<Token *>::iterator it = postfixlist.begin();
     705                // insertion can be applied from 1st occurrence
     706                int insertlocation = 1 + randomN(postfixlist.size() - 1);
     707                std::advance(it, insertlocation);
     708                Operator *rndop;
     709                if (insertlocation == (int)postfixlist.size() - 1)
     710                {
     711                        rndop = getRandomOperator(logical ? 2 : 1);
     712                }
     713                else
     714                {
     715                        rndop = getRandomOperator(logical ? 0 : 1);
     716
     717                }
     718                insertpair.push_back(rndop);
     719                postfixlist.insert(it, insertpair.begin(), insertpair.end());
     720                break;
     721        }
     722        case MATH_MUT_CHANGEVAL:
     723        {
     724                std::vector<std::list<Token *>::iterator> numbersineval;
     725                int id = 0;
     726                for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
     727                {
     728                        if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
     729                        {
     730                                numbersineval.push_back(it);
     731                        }
     732                        id++;
     733                }
     734                int randid = randomN(numbersineval.size());
     735                Number *numptr = (Number *)(*numbersineval[randid]);
     736                mutateValueOrVariable(numptr, usetime);
     737                (*numbersineval[randid]) = numptr;
     738                break;
     739        }
     740        case MATH_MUT_CHANGEOPER:
     741        {
     742                std::vector<std::list<Token *>::iterator> ops;
     743                for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
     744                {
     745                        if ((*it)->type == TokenType::OPERATOR)
     746                        {
     747                                ops.push_back(it);
     748                        }
     749                }
     750                if (ops.size() > 0)
     751                {
     752                        int randid = randomN(ops.size());
     753                        Operator *rndop;
     754                        if (randid == (int)ops.size() - 1)
     755                        {
     756                                rndop = getRandomOperator(logical ? 2 : 1);
     757                        }
     758                        else
     759                        {
     760                                rndop = getRandomOperator(logical ? 0 : 1);
     761                        }
     762                        (*ops[randid]) = rndop;
     763                }
     764                break;
     765        }
     766        case MATH_MUT_DELETION:
     767        {
     768                std::list<Token *>::iterator it = postfixlist.begin();
     769                std::vector<std::list<Token *>::iterator> firstofpairs;
     770                while (it != postfixlist.end())
     771                {
     772                        if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
     773                        {
     774                                std::list<Token *>::iterator next = it;
     775                                next++;
     776                                if (next != postfixlist.end() && (*next)->type == TokenType::OPERATOR)
     777                                {
     778                                        firstofpairs.push_back(it);
     779                                }
     780                        }
     781                        it++;
     782                }
     783                if (firstofpairs.size() > 0)
     784                {
     785                        int rndid = randomN(firstofpairs.size());
     786                        if ((*firstofpairs[rndid])->type == TokenType::NUMBER)
     787                        {
     788                                delete (*firstofpairs[rndid]);
     789                        }
     790                        firstofpairs[rndid] = postfixlist.erase(firstofpairs[rndid]);
     791                        postfixlist.erase(firstofpairs[rndid]);
     792                }
     793                break;
     794        }
     795        }
     796        return method;
     797}
     798
     799std::string MathEvaluation::getStringifiedRPN()
     800{
     801        std::string res = "";
     802        for (Token *el: postfixlist)
     803        {
     804                res += el->toString();
     805                res += " ";
     806        }
     807        return res;
     808}
  • cpp/frams/genetics/fL/fL_matheval.h

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#ifndef _FL_MATHEVAL_H_
    26#define _FL_MATHEVAL_H_
     
    812
    913#define VARIABLEPREFIX '$'
     14
     15#define MATH_MUT_DELETION   0
     16#define MATH_MUT_CHANGEVAL  1
     17#define MATH_MUT_CHANGEOPER 2
     18#define MATH_MUT_INSERTION  3
     19#define MATH_MUT_COUNT      4
     20
     21#define MAX_MUT_FORMULA_SIZE 7
     22#define XOVER_MAX_MIGRATED_RULES 3
    1023
    1124/** @name Available operators for MathEvaluation */
     
    171184        void registerOperators();
    172185
     186        std::string originalexpression;
    173187        std::unordered_map<std::string, Operator *> operators; ///<map containing available operators for MathEvaluation
    174188        std::list<Token *> postfixlist; ///<list with tokens ordered as postfix (RPN) notation of the given string
     
    176190        std::vector<Variable *> vars; ///<vector of variables, default values are 0
    177191        Variable *t; ///<additional t variable, that can act as time for evaluation
     192        std::vector<std::string> operatorstrings; ///<list of registered operators
     193        int arithmeticoperatorscount; ///<count of arithmetic operators
     194        int comparisonoperatorscount;
    178195public:
    179196
     
    226243
    227244        /**
     245         * Registers new operator for MathEvaluation object.
     246         * @param operation function that needs to be called during evaluation
     247         * @param precedence precedence of operator
     248         * @param assoc associativity of the operator
     249         * @param opsymbol symbol of the operator
     250         */
     251        void registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol);
     252
     253        /**
    228254         * Converts stored RPN list to infix string.
    229255         * @param result reference to variable that will hold the result
     
    231257         */
    232258        int RPNToInfix(std::string &result);
     259
     260        /**
     261         * Mutates formula.
     262         * @param logical if true, method uses logical operators only
     263         * @param usetime if true, method may use time variable during mutation
     264         * @param 0 if mutation could be performed, -1 if postfixlist is empty
     265         */
     266        int mutate(bool logical, bool usetime);
     267
     268        /**
     269         * Mutates formula so it creates conjuctive of comparisons.
     270         */
     271        void mutateConditional();
     272
     273        /**
     274         * Mutates number by using random value or one of variables.
     275         * @param currval current value of number
     276         * @param usetime if true, then time variable may be used
     277         */
     278        void mutateValueOrVariable(Number *&currval, bool usetime);
     279
     280        /**
     281         * Returns formula in RPN notation
     282         * @param RPN notation string
     283         */
     284        std::string getStringifiedRPN();
     285
     286        /**
     287         * Returns random operator available in object.
     288         * @param type 0 for all operators, 1 for arithmetic only, 2 for logical only
     289         * @return pointer to random operator
     290         */
     291        Operator* getRandomOperator(int type);
    233292};
    234293
  • cpp/frams/genetics/fL/fL_oper.cpp

    r780 r797  
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
    15#include "fL_oper.h"
     6#include <common/loggers/loggers.h>
     7#include "../fH/fH_oper.h"
     8#include <algorithm>
     9
     10#define FIELDSTRUCT Geno_fL
     11static ParamEntry GENOfLparam_tab[] =
     12{
     13        {"Genetics: fL", 3, FL_OPCOUNT + FL_MUTGROUPSCOUNT + FL_CHG_COUNT + 2 + FL_ADD_COUNT, },
     14        {"Genetics: fL: Probabilities of mutating axiom and rules", },
     15        {"Genetics: fL: Probabilities of mutation types", },
     16        {"fL_maxdefinedwords", 0, 0, "Maximum number of defined words", "d 0 100 10", FIELD(maxdefinedwords), "Maximum number of words that can be defined in L-System", },
     17
     18        {"fL_axm_mut_prob", 1, 0, "Axiom mutation", "f 0 1 0.2", FIELD(groupprobabilities[FL_AXM_WORD_MUT_PROB]), "Probability of performing mutation operations on axiom", },
     19        {"fL_rul_mut_prob", 1, 0, "Rule's successor mutation", "f 0 1 0.8", FIELD(groupprobabilities[FL_RUL_WORD_MUT_PROB]), "Probability of performing mutation operations on the successor of random rule", },
     20
     21        {"fL_mut_addition", 2, 0, "Addition of word to sequence", "f 0 1 0.2", FIELD(operations[FL_ADD_WORD]), "Probability of adding random existing word to the axiom or one of successors", },
     22
     23        {"fL_mut_add_stick", 2, 0, " - addition of stick", "f 0 1 0.2", FIELD(addtypes[FL_ADD_STICK]), "Probability of adding stick", },
     24        {"fL_mut_add_neuro", 2, 0, " - addition of neuron", "f 0 1 0.2", FIELD(addtypes[FL_ADD_NEURO]), "Probability of adding neuron", },
     25        {"fL_mut_add_conn", 2, 0, " - addition of neuron connection", "f 0 1 0.2", FIELD(addtypes[FL_ADD_CONN]), "Probability of adding connection", },
     26        {"fL_mut_add_rot", 2, 0, " - addition of rotation words", "f 0 1 0.2", FIELD(addtypes[FL_ADD_ROT]), "Probability of adding one of rotation words", },
     27        {"fL_mut_add_branch", 2, 0, " - addition of branched stick", "f 0 1 0.2", FIELD(addtypes[FL_ADD_BRANCH]), "Probability of adding branch with rotation and stick", },
     28        {"fL_mut_add_other", 2, 0, " - addition of defined words", "f 0 1 0.4", FIELD(addtypes[FL_ADD_OTHER]), "Probability of adding other word, defined in genotype", },
     29
     30        {"fL_mut_worddefaddition", 2, 0, "Addition of new word definition", "f 0 1 0.05", FIELD(operations[FL_ADD_WDEF]), "Probability of adding new word definition to the genotype", },
     31        {"fL_mut_ruleaddition", 2, 0, "Addition of new rule definition", "f 0 1 0.1", FIELD(operations[FL_ADD_RULE]), "Probability of adding new rule definition for existing word", },
     32        {"fL_mut_rulecond", 2, 0, "Modification of rule condition", "f 0 1 0.1", FIELD(operations[FL_CHG_COND]), "Probability of modifying random rule condition", },
     33
     34        {"fL_mut_changeword", 2, 0, "Change of random word", "f 0 1 0.3", FIELD(operations[FL_CHG_WORD]), "Probability of changing word name or formula of a random word from axiom or one of successors", },
     35        {"fL_mut_changeword_formula", 2, 0, " - change of formula", "f 0 1 0.7", FIELD(chgoperations[FL_CHG_WORD_FORMULA]), "Probability of changing formula in word", },
     36        {"fL_mut_changeword_name", 2, 0, " - change of name", "f 0 1 0.3", FIELD(chgoperations[FL_CHG_WORD_NAME]), "Probability of changing name in word", },
     37
     38        {"fL_mut_changeiter", 2, 0, "Change of L-System iteration", "f 0 1 0.3", FIELD(operations[FL_CHG_ITER]), "Probability of changing number of iterations of L-Systems", },
     39        {"fL_mut_changeiter_step", 2, 0, "Step of iteration changing", "f 0 1 1.0", FIELD(iterchangestep), "Minimal step that should be used for changing iterations in L-Systems", },
     40        {"fL_mut_deletion", 2, 0, "Deletion of random word", "f 0 1 0.2", FIELD(operations[FL_DEL_WORD]), "Probability of deleting random word from axiom or random successor (also deletes rule if there is only one word in successor)", },
     41        { 0, },
     42};
     43#undef FIELDSTRUCT
    244
    345Geno_fL::Geno_fL()
    446{
    5         //      par.setParamTab(GENOfHparam_tab);
    6         //      par.select(this);
    7         //      par.setDefault();
    8         supported_format = 'H';
    9 }
     47        par.setParamTab(GENOfLparam_tab);
     48        par.select(this);
     49        par.setDefault();
     50        supported_format = 'L';
     51        iterchangestep = 1.0;
     52        maxdefinedwords = 10;
     53}
     54
     55int Geno_fL::checkValidity(const char *geno, const char *genoname)
     56{
     57        LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN);
     58        fL_Builder builder(false, false);
     59
     60        int err = builder.parseGenotype(geno);
     61        if (err != 0)
     62        {
     63                return err;
     64        }
     65
     66        if (builder.countSticksInSequence(builder.genotype) == 0)
     67        {
     68                return GENOPER_OPFAIL;
     69        }
     70        double neededtime = 0;
     71        Model *m = builder.developModel(neededtime);
     72        if (!m)
     73        {
     74                return GENOPER_OPFAIL;
     75        }
     76        if (!m->isValid())
     77        {
     78                delete m;
     79                return GENOPER_OPFAIL;
     80        }
     81        delete m;
     82
     83
     84        return GENOPER_OK;
     85}
     86
     87int Geno_fL::validate(char *&geno, const char *genoname)
     88{
     89        LoggerToMemory eh(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_WARN);
     90        fL_Builder builder(false, false);
     91
     92        int err = builder.parseGenotype(geno);
     93        if (err != 0)
     94        {
     95                return err;
     96        }
     97        double neededtime = 0;
     98        Model *m = builder.developModel(neededtime);
     99        if (!m->isValid())
     100        {
     101                delete m;
     102                return GENOPER_OPFAIL;
     103        }
     104        if (neededtime != builder.time)
     105        {
     106                builder.time = neededtime;
     107                free(geno);
     108                geno = strdup(builder.toString().c_str());
     109                delete m;
     110                return GENOPER_OK;
     111        }
     112        delete m;
     113        return GENOPER_OK;
     114}
     115
     116bool Geno_fL::addWord(std::list<fL_Word *>* list, fL_Word *definition, std::list<fL_Word *>::iterator it)
     117{
     118        fL_Word *newword = new fL_Word();
     119        *newword = *definition;
     120
     121        // if word has parameters
     122        if (newword->npar > 0)
     123        {
     124                // create ParamObject that will hold parameter data
     125                newword->data = ParamObject::makeObject(newword->tab);
     126                Param par(newword->tab);
     127                par.select(newword->data);
     128                par.setDefault();
     129                for (int i = 0; i < par.getPropCount(); i++)
     130                {
     131                        newword->parevals.push_back(NULL);
     132                }
     133                if (newword->name.startsWith("rot"))
     134                {
     135                        double rot = 2 * rnd01;
     136                        MathEvaluation *eval = new MathEvaluation(0);
     137                        eval->convertString(SString::valueOf(rot).c_str());
     138                        newword->parevals[0] = eval;
     139                }
     140                else if (newword->name == "N")
     141                {
     142                        SString det;
     143                        NeuroClass *cls = getRandomNeuroClass();
     144                        if (!cls) cls = Neuro::getClass("N");
     145                        det = cls->getName();
     146                        Geno_fH::mutateNeuronProperties(det);
     147                        par.setStringById(FL_PE_NEURO_DET, det);
     148                }
     149                else if (newword->name == "C")
     150                {
     151                        MathEvaluation *eval = new MathEvaluation(0);
     152                        eval->convertString(SString::valueOf(2 * rnd01 - 1).c_str());
     153                        newword->parevals[0] = eval;
     154                }
     155        }
     156
     157        list->insert(it, newword);
     158        return true;
     159}
     160
     161std::list<fL_Word *>* Geno_fL::selectRandomSequence(fL_Builder *creature, int &numparams, int &ruleid)
     162{
     163        std::list<fL_Word *> *list = NULL;
     164        int axiomorrules = roulette(groupprobabilities, FL_MUTGROUPSCOUNT);
     165        bool axiomused = axiomorrules == FL_AXM_WORD_MUT_PROB || creature->rules.size() == 0;
     166        if (axiomused)
     167        {
     168                list = &creature->genotype;
     169                numparams = 0;
     170                ruleid = -1;
     171        }
     172        else
     173        {
     174                int rid = randomN(creature->rules.size());
     175                list = &creature->rules[rid]->objsucc;
     176                numparams = creature->rules[rid]->objpred->npar;
     177                ruleid = rid;
     178        }
     179        return list;
     180}
     181
     182fL_Word* Geno_fL::randomWordDefinition(fL_Builder *creature, int method)
     183{
     184        if (method == FL_ADD_OTHER && creature->builtincount < (int)creature->words.size())
     185        {
     186                return creature->words[creature->wordnames[creature->builtincount + randomN((int)creature->words.size() - creature->builtincount)]];
     187        }
     188        else
     189        {
     190                if (method == FL_ADD_OTHER) // we should be able to select stick, neuro or conn
     191                {
     192                        double alttypes[FL_ADD_COUNT - 2];
     193                        alttypes[FL_ADD_STICK] = addtypes[FL_ADD_STICK];
     194                        alttypes[FL_ADD_NEURO] = addtypes[FL_ADD_NEURO];
     195                        alttypes[FL_ADD_CONN] = addtypes[FL_ADD_CONN];
     196                        alttypes[FL_ADD_ROT] = addtypes[FL_ADD_ROT];
     197                        method = roulette(alttypes, FL_ADD_COUNT - 2);
     198                }
     199                switch (method)
     200                {
     201                case FL_ADD_STICK:
     202                        return creature->words["S"];
     203                case FL_ADD_NEURO:
     204                        return creature->words["N"];
     205                case FL_ADD_CONN:
     206                        return creature->words["C"];
     207                case FL_ADD_ROT:
     208                {
     209                        int rottype = randomN(3);
     210                        switch (rottype)
     211                        {
     212                        case 0:
     213                                return creature->words["rotX"];
     214                        case 1:
     215                                return creature->words["rotY"];
     216                        case 2:
     217                                return creature->words["rotZ"];
     218                        }
     219                        break;
     220                }
     221                case FL_ADD_BRANCH:
     222                        // return NULL
     223                        break;
     224                }
     225        }
     226        return NULL;
     227}
     228
     229void Geno_fL::deleteBranch(std::list<fL_Word *> *list, std::list<fL_Word *>::iterator openbranchposition)
     230{
     231        fL_Branch *branch = (fL_Branch *)(*openbranchposition);
     232        if (branch->btype == fL_Branch::BranchType::OPEN)
     233        {
     234                int bcount = 1;
     235                delete (*openbranchposition);
     236                openbranchposition = list->erase(openbranchposition);
     237                for (; openbranchposition != list->end(); openbranchposition++)
     238                {
     239                        if ((*openbranchposition)->type == fLElementType::BRANCH)
     240                        {
     241                                branch = (fL_Branch *)(*openbranchposition);
     242                                if (branch->btype == fL_Branch::BranchType::OPEN)
     243                                {
     244                                        bcount++;
     245                                }
     246                                else
     247                                {
     248                                        bcount--;
     249                                        if (bcount == 0)
     250                                        {
     251                                                delete branch;
     252                                                list->erase(openbranchposition);
     253                                                break;
     254                                        }
     255                                }
     256                        }
     257                }
     258        }
     259        else
     260        {
     261                openbranchposition++;
     262                if (openbranchposition != list->end())
     263                {
     264                        delete (*openbranchposition);
     265                        list->erase(openbranchposition);
     266                }
     267        }
     268}
     269
     270int Geno_fL::mutate(char *&geno, float& chg, int &method)
     271{
     272        fL_Builder *creature = new fL_Builder(false, false);
     273
     274        if (creature->parseGenotype(geno) != 0)
     275        {
     276                delete creature;
     277                return GENOPER_OPFAIL;
     278        }
     279
     280        int before = creature->countWordsInLSystem();
     281
     282        method = roulette(operations, FL_OPCOUNT);
     283        switch (method)
     284        {
     285                case FL_CHG_ITER:
     286                {
     287                        if (randomN(2) == 0)
     288                        {
     289                                creature->time = creature->time + iterchangestep <= ExtValue::getDouble(FL_MAXITER) ?
     290                                                creature->time + iterchangestep : creature->time - iterchangestep;
     291                        }
     292                        else
     293                        {
     294                                creature->time = creature->time - iterchangestep >= 0 ?
     295                                                creature->time - iterchangestep : creature->time + iterchangestep;
     296                        }
     297                        break;
     298                }
     299                case FL_CHG_COND:
     300                {
     301                        if (creature->rules.size() > 0)
     302                        {
     303                                int ruleid = randomN(creature->rules.size());
     304                                if (!creature->rules[ruleid]->condeval)
     305                                {
     306                                        creature->rules[ruleid]->condeval = new MathEvaluation(creature->rules[ruleid]->objpred->npar);
     307                                }
     308                                creature->rules[ruleid]->condeval->mutateConditional();
     309                                break;
     310                        }
     311                        // if there are no rules - create one
     312                }
     313                /* no break */
     314                case FL_ADD_RULE:
     315                {
     316                        std::unordered_map<std::string, fL_Word *>::iterator pred = creature->words.begin();
     317                        std::vector<fL_Word *> wordswithnorules;
     318                        for (; pred != creature->words.end(); pred++)
     319                        {
     320                                if (!pred->second->builtin)
     321                                {
     322                                        bool norules = true;
     323                                        for (fL_Rule * r : creature->rules)
     324                                        {
     325                                                if (pred->second->name == r->objpred->name &&
     326                                                                pred->second->npar == r->objpred->npar)
     327                                                {
     328                                                        norules = false;
     329                                                        break;
     330                                                }
     331                                        }
     332                                        if (norules)
     333                                        {
     334                                                wordswithnorules.push_back(pred->second);
     335                                        }
     336                                }
     337                        }
     338                        if (wordswithnorules.size() > 0)
     339                        {
     340                                int predid = randomN(wordswithnorules.size());
     341                                fL_Rule *newrule = new fL_Rule(0,0);
     342                                fL_Word *pred = new fL_Word();
     343                                *pred = *wordswithnorules[predid];
     344                                newrule->objpred = pred;
     345                                fL_Word *initdef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); // -1 to avoid branching
     346                                addWord(&newrule->objsucc, initdef, newrule->objsucc.begin());
     347                                creature->rules.push_back(newrule);
     348                                break;
     349                        }
     350                        else if (creature->rules.size() > 0)
     351                        {
     352                                int ruleid = randomN(creature->rules.size());
     353                                fL_Rule *newrule = new fL_Rule(0, 0);
     354                                fL_Word *pred = new fL_Word();
     355                                *pred = *creature->rules[ruleid]->objpred;
     356                                newrule->objpred = pred;
     357                                if (creature->rules[ruleid]->condeval)
     358                                {
     359                                        std::string formula = "";
     360                                        creature->rules[ruleid]->condeval->RPNToInfix(formula);
     361                                        if (formula.find("1.0-(") != 0)
     362                                        {
     363                                                std::string res = "1.0-(";
     364                                                res += formula;
     365                                                res += ")";
     366                                                newrule->condeval = new MathEvaluation(pred->npar);
     367                                                newrule->condeval->convertString(res);
     368                                        }
     369                                        else
     370                                        {
     371                                                newrule->condeval = new MathEvaluation(pred->npar);
     372                                                newrule->condeval->mutateConditional();
     373                                        }
     374                                }
     375                                else
     376                                {
     377                                        newrule->condeval = new MathEvaluation(pred->npar);
     378                                        newrule->condeval->mutateConditional();
     379                                }
     380                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
     381                                addWord(&newrule->objsucc, worddef, newrule->objsucc.begin());
     382                                creature->rules.push_back(newrule);
     383                                break;
     384                        }
     385                        // if there are no words, from which rules can be formed, then add one
     386                }
     387                /* no break */
     388                case FL_ADD_WDEF:
     389                {
     390                        if (creature->countDefinedWords() <= maxdefinedwords)
     391                        {
     392                                int npar = randomN(ExtValue::getInt(FL_MAXPARAMS, false));
     393                                for (int i = 0; i < maxdefinedwords; i++)
     394                                {
     395                                        std::string name = "w";
     396                                        name += std::to_string(i);
     397                                        if (creature->words.find(name) == creature->words.end())
     398                                        {
     399                                                fL_Word *word = new fL_Word(false, 0, 0);
     400                                                word->npar = npar;
     401                                                word->name = name.c_str();
     402                                                word->processDefinition(creature);
     403                                                break;
     404                                        }
     405                                }
     406                                break;
     407                        }
     408                        //no break at the end of case - if there is too many words, then
     409                        // deletion should be performed
     410                }
     411                /* no break */
     412                case FL_DEL_WORD:
     413                {
     414                        int numpars = 0;
     415                        int ruleid = 0;
     416                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, ruleid);
     417                        if (ruleid == -1 && creature->countSticksInSequence((*list)) == 1)
     418                        {
     419                                if (list->size() > 1)
     420                                {
     421                                        int rndid = randomN(list->size() - 1);
     422                                        int j = 0;
     423                                        std::list<fL_Word *>::iterator it = list->begin();
     424                                        if ((*it)->name == "S")
     425                                        {
     426                                                it++;
     427                                        }
     428                                        while (it != list->end() && j < rndid && ((*it)->name == "S"))
     429                                        {
     430                                                if ((*it)->name != "S")
     431                                                {
     432                                                        j++;
     433                                                }
     434                                                it++;
     435                                        }
     436                                        if (it != list->end())
     437                                        {
     438                                                if ((*it)->type == fLElementType::BRANCH)
     439                                                {
     440                                                        deleteBranch(list, it);
     441                                                }
     442                                                else
     443                                                {
     444                                                        delete (*it);
     445                                                        list->erase(it);
     446                                                }
     447                                                break;
     448                                        }
     449                                        // else add word
     450                                }
     451                                // else add word
     452                        }
     453                        else
     454                        {
     455                                int rndid = randomN(list->size());
     456                                std::list<fL_Word *>::iterator it = list->begin();
     457                                std::advance(it, rndid);
     458                                if ((*it)->type == fLElementType::BRANCH)
     459                                {
     460                                        deleteBranch(list, it);
     461                                }
     462                                else
     463                                {
     464                                        delete (*it);
     465                                        list->erase(it);
     466                                }
     467                                if (ruleid > -1 && creature->rules[ruleid]->objsucc.size() == 0)
     468                                {
     469                                        delete creature->rules[ruleid];
     470                                        creature->rules.erase(creature->rules.begin() + ruleid);
     471                                }
     472                                break;
     473                        }
     474                        // if no words available, then add word
     475                }
     476                /* no break */
     477                case FL_ADD_WORD:
     478                {
     479                        int numpars = 0;
     480                        int tmp = 0;
     481                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
     482                        int rndid = randomN(list->size());
     483                        std::list<fL_Word *>::iterator it = list->begin();
     484                        std::advance(it, rndid);
     485                        int meth = roulette(addtypes, FL_ADD_COUNT);
     486                        if (tmp == -1)
     487                        { // if sequence is axiom and it does not have non-builtin words
     488                                bool hasdefined = false;
     489                                for (std::list<fL_Word *>::iterator elem = list->begin(); elem != list->end(); elem++)
     490                                {
     491                                        if (!(*elem)->builtin)
     492                                        {
     493                                                hasdefined = true;
     494                                                break;
     495                                        }
     496                                }
     497                                if (!hasdefined)
     498                                {
     499                                        meth = FL_ADD_OTHER;
     500                                }
     501
     502                        }
     503                        if (meth != FL_ADD_BRANCH)
     504                        {
     505                                fL_Word *worddef = randomWordDefinition(creature, meth);
     506                                addWord(list, worddef, it);
     507                        }
     508                        else
     509                        {
     510                                fL_Branch *start = new fL_Branch(fL_Branch::BranchType::OPEN, 0, 0);
     511                                list->insert(it, start);
     512                                int rottype = randomN(2);
     513                                switch (rottype)
     514                                {
     515                                case 0:
     516                                        addWord(list, creature->words["rotY"], it);
     517                                case 1:
     518                                        addWord(list, creature->words["rotZ"], it);
     519                                }
     520                                addWord(list, creature->words["S"], it);
     521                                fL_Branch *end = new fL_Branch(fL_Branch::BranchType::CLOSE, 0, 0);
     522                                list->insert(it, end);
     523                        }
     524                        break;
     525                }
     526                case FL_CHG_WORD:
     527                {
     528                        int numpars = 0;
     529                        int tmp = 0;
     530                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
     531                        int rndid = randomN(list->size());
     532                        std::list<fL_Word *>::iterator selectedword = list->begin();
     533                        std::advance(selectedword, rndid);
     534                        if ((*selectedword)->type == fLElementType::BRANCH)
     535                        {
     536                                break;
     537                        }
     538                        int chgtype = roulette(chgoperations, FL_CHG_COUNT);
     539                        if (creature->countSticksInSequence((*list)) == 1 && tmp == -1) // if sequence is axiom
     540                        {
     541                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
     542
     543                                int numpars = 0;
     544                                std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
     545                                int rndid = randomN(list->size());
     546                                std::list<fL_Word *>::iterator it = list->begin();
     547                                std::advance(it, rndid);
     548
     549                                addWord(list, worddef, it);
     550
     551                                break;
     552                        }
     553                        else if (chgtype == FL_CHG_WORD_NAME)
     554                        {
     555                                if ((*selectedword)->builtin)
     556                                {
     557                                        delete (*selectedword);
     558                                        selectedword = list->erase(selectedword);
     559                                        fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
     560                                        addWord(list, worddef, selectedword);
     561                                }
     562                                else
     563                                {
     564                                        std::vector<fL_Word *> available;
     565                                        for (std::unordered_map<std::string, fL_Word *>::iterator wit = creature->words.begin();
     566                                                        wit != creature->words.end(); wit++)
     567                                        {
     568                                                if ((*selectedword)->npar == wit->second->npar &&
     569                                                                (*selectedword)->name != wit->second->name &&
     570                                                                !wit->second->builtin)
     571                                                {
     572                                                        available.push_back(wit->second);
     573                                                }
     574                                        }
     575                                        if (available.size() > 0)
     576                                        {
     577                                                int newnameid = randomN(available.size());
     578                                                (*selectedword)->name = available[newnameid]->name;
     579                                        }
     580                                        else
     581                                        {
     582                                                delete (*selectedword);
     583                                                selectedword = list->erase(selectedword);
     584                                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
     585                                                addWord(list, worddef, selectedword);
     586                                        }
     587                                }
     588                        }
     589                        else
     590                        {
     591                                if ((*selectedword)->npar > 0)
     592                                {
     593                                        int randeval = randomN((*selectedword)->npar);
     594                                        Param par((*selectedword)->tab, (*selectedword)->data);
     595                                        if ((*selectedword)->builtin && (*selectedword)->name == "N"
     596                                                        && strcmp(par.id(randeval), FL_PE_NEURO_DET) == 0)
     597                                        {
     598                                                SString res = par.getStringById(FL_PE_NEURO_DET);
     599                                                Geno_fH::mutateNeuronProperties(res);
     600                                                par.setStringById(FL_PE_NEURO_DET, res);
     601                                        }
     602                                        else if ((*selectedword)->builtin &&
     603                                                        (*selectedword)->name == "C" &&
     604                                                        strcmp(par.id(randeval), FL_PE_CONN_ATTR) == 0)
     605                                        {
     606                                                SString strattractor = par.getStringById(FL_PE_CONN_ATTR);
     607                                                if (strattractor.len() > 0)
     608                                                {
     609                                                        fL_Word *w = NULL;
     610                                                        creature->createWord(strattractor, w, numpars, 0, 0);
     611                                                        // mutate attractor parameter
     612                                                        if (w->npar > 0)
     613                                                        {
     614                                                                int rndattr = randomN(w->npar);
     615                                                                if (!w->parevals[rndattr])
     616                                                                {
     617                                                                        w->parevals[rndattr] = new MathEvaluation(numpars);
     618                                                                }
     619                                                                w->parevals[rndattr]->mutate(false, false);
     620                                                        }
     621                                                        strattractor = w->stringify(true);
     622                                                        par.setStringById(FL_PE_CONN_ATTR, strattractor);
     623                                                        delete w;
     624                                                }
     625                                                else
     626                                                {
     627                                                        if (creature->builtincount < (int)creature->words.size())
     628                                                        {
     629                                                                fL_Word *wdef = randomWordDefinition(creature, FL_ADD_OTHER);
     630                                                                fL_Word *w = new fL_Word();
     631                                                                *w = *wdef;
     632                                                                w->data = ParamObject::makeObject(w->tab);
     633                                                                Param apar(w->tab);
     634                                                                apar.select(w->data);
     635                                                                apar.setDefault();
     636                                                                if (w->npar > 0)
     637                                                                {
     638                                                                        int rndattr = randomN(w->npar);
     639                                                                        for (int i = 0; i < w->npar; i++)
     640                                                                        {
     641                                                                                if (i == rndattr)
     642                                                                                {
     643                                                                                        MathEvaluation *ev = new MathEvaluation(numpars);
     644                                                                                        ev->mutate(false, false);
     645                                                                                        w->parevals.push_back(ev);
     646                                                                                }
     647                                                                                else
     648                                                                                {
     649                                                                                        w->parevals.push_back(NULL);
     650                                                                                }
     651                                                                        }
     652
     653                                                                }
     654                                                                strattractor = w->stringify(false);
     655                                                                par.setStringById(FL_PE_CONN_ATTR, strattractor);
     656                                                                delete w;
     657                                                        }
     658                                                }
     659                                        }
     660                                        else
     661                                        {
     662                                                if (!(*selectedword)->parevals[randeval])
     663                                                {
     664                                                        (*selectedword)->parevals[randeval] = new MathEvaluation(numpars);
     665                                                }
     666                                                (*selectedword)->parevals[randeval]->mutate(false, iterchangestep != 1.0);
     667                                        }
     668                                }
     669                        }
     670                        break;
     671                }
     672        }
     673
     674        free(geno);
     675        geno = strdup(creature->toString().c_str());
     676        chg = (double)abs(before - creature->countWordsInLSystem()) / before;
     677        delete creature;
     678
     679        return GENOPER_OK;
     680}
     681
     682fL_Word* Geno_fL::getAppropriateWord(fL_Builder *from, fL_Builder *to, fL_Word *fromword, std::unordered_map<std::string, std::string> &map)
     683{
     684        if (fromword->name == "[" || fromword->name == "]") // if words are branching words
     685        {
     686                fL_Branch *newword = new fL_Branch(fromword->name == "[" ? fL_Branch::BranchType::OPEN : fL_Branch::BranchType::CLOSE, 0, 0);
     687                return newword;
     688        }
     689        if (fromword->builtin)
     690        {
     691                fL_Word *newword = new fL_Word();
     692                (*newword) = (*to->words[fromword->name.c_str()]);
     693                return newword;
     694        }
     695        if (map.find(fromword->name.c_str()) != map.end()) // if word is already mapped
     696        {
     697                fL_Word *newword = new fL_Word();
     698                (*newword) = (*to->words[map[fromword->name.c_str()]]);
     699                return newword;
     700        }
     701        else if (to->words.find(fromword->name.c_str()) != to->words.end() &&
     702                        to->words[fromword->name.c_str()]->npar == fromword->npar) // if there is already same word with same number of parameters
     703        {
     704                fL_Word *newword = new fL_Word();
     705                map[fromword->name.c_str()] = fromword->name.c_str();
     706                (*newword) = (*to->words[map[fromword->name.c_str()]]);
     707                return newword;
     708        }
     709        for (std::unordered_map<std::string, fL_Word *>::iterator it = to->words.begin();
     710                        it != to->words.end(); it++)
     711        { // find word with same number of parameters
     712                if (fromword->npar == it->second->npar && map.find(fromword->name.c_str()) == map.end() && !it->second->builtin)
     713                { // if there is a word with same number of parameters
     714                        map[fromword->name.c_str()] = it->second->name.c_str();
     715                        fL_Word *newword = new fL_Word();
     716                        (*newword) = (*it->second);
     717                        return newword;
     718                }
     719        }
     720        fL_Word *newworddef = new fL_Word();
     721        (*newworddef) = (*fromword);
     722        newworddef->parevals.clear();
     723        if (to->words.find(newworddef->name.c_str()) != to->words.end())
     724        {
     725                int i = 0;
     726                while (true)
     727                {
     728                        std::string name = "w";
     729                        name += std::to_string(i);
     730                        if (to->words.find(name) == to->words.end())
     731                        {
     732                                newworddef->name = name.c_str();
     733                                break;
     734                        }
     735                        i++;
     736                }
     737        }
     738        newworddef->processDefinition(to);
     739        map[fromword->name.c_str()] = newworddef->name.c_str();
     740        fL_Word *newword = new fL_Word();
     741        (*newword) = (*to->words[map[fromword->name.c_str()]]);
     742        return newword;
     743}
     744
     745void Geno_fL::migrateRandomRules(fL_Builder *from, fL_Builder *to, int numselrules)
     746{
     747        std::unordered_map<std::string, std::string> map;
     748        if (from->rules.size() > 0)
     749        {
     750                for (int i = 0; i < numselrules; i++)
     751                {
     752                        int rulid = randomN(from->rules.size());
     753                        fL_Rule *rul = from->rules[rulid];
     754                        fL_Rule *newrule = new fL_Rule(0, 0);
     755                        newrule->objpred = getAppropriateWord(from, to, rul->objpred, map);
     756                        for (fL_Word *w : rul->objsucc)
     757                        {
     758                                fL_Word *el = getAppropriateWord(from, to, w, map);
     759                                if (el->type == fLElementType::BRANCH)
     760                                {
     761                                        newrule->objsucc.push_back(el);
     762                                        continue;
     763                                }
     764                                Param origpar(w->tab);
     765                                origpar.select(w->data);
     766                                el->data = ParamObject::makeObject(el->tab);
     767                                Param par(el->tab);
     768                                par.select(el->data);
     769                                par.setDefault();
     770                                for (int i = 0; i < el->npar; i++)
     771                                {
     772                                        std::string form;
     773                                        if (w->builtin && w->name == "N"
     774                                                        && strcmp(par.id(i), FL_PE_NEURO_DET) == 0)
     775                                        {
     776                                                SString res = origpar.getStringById(FL_PE_NEURO_DET);
     777                                                par.setStringById(FL_PE_NEURO_DET, res);
     778                                                el->parevals.push_back(NULL);
     779                                        }
     780                                        else if (w->builtin && w->name == "C"
     781                                                        && strcmp(par.id(i), FL_PE_CONN_ATTR) == 0)
     782                                        {
     783                                                SString strattractor = origpar.getStringById(FL_PE_CONN_ATTR);
     784                                                if (strattractor.len() > 0)
     785                                                {
     786                                                        fL_Word *tmp = NULL;
     787                                                        from->createWord(strattractor, tmp, newrule->objpred->npar, 0, 0);
     788                                                        fL_Word *newsuccword = getAppropriateWord(from, to, tmp, map);
     789                                                        newsuccword->data = ParamObject::makeObject(el->tab);
     790                                                        newsuccword->parevals = tmp->parevals;
     791                                                        tmp->parevals.clear();
     792                                                        strattractor = newsuccword->stringify(true);
     793                                                        par.setStringById(FL_PE_CONN_ATTR, strattractor);
     794                                                        delete newsuccword;
     795                                                        delete tmp;
     796                                                }
     797                                                par.setStringById(FL_PE_CONN_ATTR, strattractor);
     798                                                el->parevals.push_back(NULL);
     799                                        }
     800                                        else if (w->parevals[i])
     801                                        {
     802                                                MathEvaluation *eval = new MathEvaluation(newrule->objpred->npar);
     803                                                w->parevals[i]->RPNToInfix(form);
     804                                                eval->convertString(form);
     805                                                el->parevals.push_back(eval);
     806                                        }
     807                                        else
     808                                        {
     809                                                el->parevals.push_back(NULL);
     810                                        }
     811                                }
     812                                newrule->objsucc.push_back(el);
     813                        }
     814                        to->rules.push_back(newrule);
     815                }
     816        }
     817}
     818
     819int Geno_fL::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
     820{
     821        fL_Builder *creature1 = new fL_Builder(false, false);
     822        fL_Builder *creature1template = new fL_Builder(false, false);
     823        fL_Builder *creature2 = new fL_Builder(false, false);
     824        fL_Builder *creature2template = new fL_Builder(false, false);
     825
     826        int count1 = creature1->countWordsInLSystem();
     827        int count2 = creature2->countWordsInLSystem();
     828
     829        if (creature1->parseGenotype(g1) != 0 || creature2->parseGenotype(g2) != 0)
     830        {
     831                delete creature1;
     832                delete creature2;
     833                delete creature1template;
     834                delete creature2template;
     835                return GENOPER_OPFAIL;
     836        }
     837
     838        creature1template->parseGenotype(g1);
     839        creature2template->parseGenotype(g2);
     840
     841        int numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES);
     842        numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size();
     843
     844        migrateRandomRules(creature1template, creature2, numselrules);
     845
     846        numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES);
     847        numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size();
     848
     849        migrateRandomRules(creature2template, creature1, numselrules);
     850
     851        free(g1);
     852        free(g2);
     853
     854        g1 = strdup(creature1->toString().c_str());
     855        g2 = strdup(creature2->toString().c_str());
     856
     857        chg1 = (double)count1 / creature1->countWordsInLSystem();
     858        chg1 = (double)count2 / creature2->countWordsInLSystem();
     859
     860        delete creature1;
     861        delete creature2;
     862        delete creature1template;
     863        delete creature2template;
     864
     865        return GENOPER_OK;
     866}
     867
     868uint32_t Geno_fL::style(const char *geno, int pos)
     869{
     870        char ch = geno[pos];
     871        uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT);
     872        if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character line definition
     873        {
     874                style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD);
     875        }
     876        else if (strchr("()", ch) != NULL)
     877        {
     878                style = GENSTYLE_RGBS(50, 50, 50, GENSTYLE_BOLD);
     879        }
     880        else if (isalpha(ch)) // properties name
     881        {
     882                style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
     883        }
     884        else if (isdigit(ch) || strchr(",.=", ch)) // properties values
     885        {
     886                style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
     887        }
     888        else if (ch == '\"')
     889        {
     890                style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
     891        }
     892
     893        return style;
     894}
  • cpp/frams/genetics/fL/fL_oper.h

    r780 r797  
    1 #ifndef _FL_OPER_
    2 #define _FL_OPER_
     1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
     2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
     3// See LICENSE.txt for details.
     4
     5#ifndef _FL_OPER_H_
     6#define _FL_OPER_H_
    37
    48#include "../genooperators.h"
     9#include "fL_general.h"
     10
     11/** @name Codes for general fL mutation types */
     12//@{
     13#define FL_ADD_WORD 0 ///<probability of adding word to axiom or rule successor
     14#define FL_ADD_WDEF 1 ///<probability of adding word definition
     15#define FL_ADD_RULE 2 ///<probability of adding new rule
     16#define FL_CHG_COND 3 ///<probability of modification or rule condition
     17#define FL_CHG_WORD 4 ///<probability of changing word name or formula in axiom or rule successor
     18#define FL_CHG_ITER 5 ///<probability of changing iteration of genotype
     19#define FL_DEL_WORD 6 ///<probability of deleting word from axiom or rule. Deleting all occurrences of word deletes word definition. Deleting all words in rule deletes this rule
     20#define FL_OPCOUNT 7 ///<count of mutation operators
     21//@}
     22
     23/** @name Codes for probabilities of mutating axiom words or rule words */
     24//@{
     25#define FL_AXM_WORD_MUT_PROB 0 ///<probability of performing addition, substitution or deletion of word in axiom
     26#define FL_RUL_WORD_MUT_PROB 1 ///<probability of performing addition, substitution or deletion of word in rule's successor
     27#define FL_MUTGROUPSCOUNT 2 ///<count of possible groups for mutations
     28//@}
     29
     30/** @name Codes for probabilities of mutating word names or formula during change */
     31//@{
     32#define FL_CHG_WORD_FORMULA 0 ///<probability of changing formula of one of parameters
     33#define FL_CHG_WORD_NAME 1 ///<probability of changing word name to other word name with <= number of parameters
     34#define FL_CHG_COUNT 2 ///<count of possible changes in words
     35//@}
     36
     37/** @name Codes for probabilities of choosing one of word types for addition */
     38//@{
     39#define FL_ADD_STICK  0 ///<probability of adding stick
     40#define FL_ADD_NEURO  1 ///<probability of adding neuron
     41#define FL_ADD_CONN   2 ///<probability of adding connection
     42#define FL_ADD_ROT    3 ///<probability of adding one of rotation words
     43#define FL_ADD_OTHER  4 ///<probability of adding word defined in the genotype
     44#define FL_ADD_BRANCH 5 ///<probability of adding a branch
     45#define FL_ADD_COUNT  6 ///<count of possible additions
     46//@}
    547
    648class Geno_fL : public GenoOperators
    749{
     50private:
     51
     52        /**
     53         * Adds word with a given definition to the list in place pointed by an iterator.
     54         * @param list list, to which new word will be added
     55         * @param definition temporal object that will act as pattern for newly created word
     56         * @param it the iterator pointing to addition point
     57         * @return true
     58         */
     59        bool addWord(std::list<fL_Word *>* list, fL_Word *definition, std::list<fL_Word *>::iterator it);
     60
     61        /**
     62         * Selects axiom or one of rule's successors.
     63         * @param creature the object with defined axiom and rules
     64         * @param numparams reference holding the number of parameters that are available for this list, 0 for axiom
     65         * @param ruleid the index of the rule in rules structure or -1 if selected sequence is the axiom
     66         * @return pointer to a selected sequence
     67         */
     68        std::list<fL_Word *>* selectRandomSequence(fL_Builder *creature, int &numparams, int &ruleid);
     69
     70        /**
     71         * Selects word definition according to a method. Method is one of
     72         * values FL_ADD_STICK, FL_ADD_NEURO, FL_ADD_CONN, FL_ADD_ROT, FL_ADD_OTHER
     73         * etc. If FL_ADD_OTHER is chosen, then one of defined words is chosen. If
     74         * there are no defined words, then one of built-in words is chosen.
     75         * If FL_ADD_BRANCH is selected, then method returns NULL.
     76         * @param creature current genotype
     77         * @param method one of methods of addition
     78         * @return object defining one of genotype words, or NULL if branching method is used
     79         */
     80        fL_Word* randomWordDefinition(fL_Builder *creature, int method);
     81
     82        /**
     83         * Tries to find appropriate word in second creature that matches the word in first creature.
     84         * Firstly, it tries to check if some word is not already assigned to a word in second creature.
     85         * If the searching is successful, then appropriate word is used. Otherwise, method tries to find
     86         * word that matches by name and number of parameters, or at least by number of parameters and hasn't
     87         * been used already for other translation. If this is impossible, method creates new word definition
     88         * for the second creature.
     89         * @param from creature, from rule is taken
     90         * @param to creature, which takes the rule
     91         * @param fromword word from the first creature that needs to be translated
     92         * @param map hashmap for current assignments
     93         * @return word instance that need to be used by generated rule for the second genotype
     94         */
     95        fL_Word* getAppropriateWord(fL_Builder *from, fL_Builder *to, fL_Word *fromword, std::unordered_map<std::string, std::string> &map);
     96
     97        /**
     98         * Migrates random rule from one creature to the other creature.
     99         * @param from creature, from rule is taken
     100         * @param to creature, which takes the rule
     101         * @param numselrules number of rules that need to be moved
     102         */
     103        void migrateRandomRules(fL_Builder *from, fL_Builder *to, int numselrules);
     104
     105        /**
     106         * Deletes branch from a given sequence starting from iterator. The deletion
     107         * removes only braces, not whole branch.
     108         * @param list current list that needs to be modified
     109         * @param openbranchposition the iterator pointing to the open branch word
     110         */
     111        void deleteBranch(std::list<fL_Word *> *list, std::list<fL_Word *>::iterator openbranchposition);
    8112public:
     113        double operations[FL_OPCOUNT]; ///<Relative probabilities of mutation types
     114        double groupprobabilities[FL_MUTGROUPSCOUNT]; ///<Relative probabilities of changing elements in rules or axioms
     115        double chgoperations[FL_CHG_COUNT]; ///<Relative probabilities of changing word names or parameters of word during change mutation
     116        double addtypes[FL_ADD_COUNT]; ///<Relative probabilities of selecting special word types
     117
     118        double iterchangestep; ///<minimal value, by which time of development is modified
     119        int maxdefinedwords; ///<maximal number of defined words for single fL genotype
     120
    9121        Geno_fL();
    10122
    11         //      int checkValidity(const char *geno, const char *genoname);
     123        int checkValidity(const char *geno, const char *genoname);
    12124
    13         //      int validate(char *&geno, const char *genoname);
     125        int validate(char *&geno, const char *genoname);
    14126
    15         //      int mutate(char *&geno, float& chg, int &method);
     127        int mutate(char *&geno, float& chg, int &method);
    16128
    17         //      int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
     129        int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
    18130
    19         //      virtual const char* getSimplest() { return "5\naaazz"; }
     131        const char* getSimplest() { return "i:axiom=\"S()\", time=0, maxwords=300"; }
    20132
    21         //      uint32_t style(const char *geno, int pos);
     133        uint32_t style(const char *geno, int pos);
    22134};
    23135
    24 #endif // _FL_OPER_
     136#endif // _FL_OPER_H_
Note: See TracChangeset for help on using the changeset viewer.