source: cpp/frams/genetics/fL/fL_oper.cpp @ 1298

Last change on this file since 1298 was 1298, checked in by Maciej Komosinski, 3 weeks ago

Introduced overloads for rndUint() with size_t and int arguments to avoid numerous type casts in sources

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