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

Last change on this file since 803 was 803, checked in by Maciej Komosinski, 3 years ago

Performance improvements, including avoiding unnecessary passing of objects by value

File size: 26.2 KB
Line 
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#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
44
45Geno_fL::Geno_fL()
46{
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                        //we do not check if this class
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                        if (getActiveNeuroClassCount() == 0)
205                                return creature->words["S"];
206                        else
207                                return creature->words["N"];
208                case FL_ADD_CONN:
209                        return creature->words["C"];
210                case FL_ADD_ROT:
211                {
212                        int rottype = randomN(3);
213                        switch (rottype)
214                        {
215                        case 0:
216                                return creature->words["rotX"];
217                        case 1:
218                                return creature->words["rotY"];
219                        case 2:
220                                return creature->words["rotZ"];
221                        }
222                        break;
223                }
224                case FL_ADD_BRANCH:
225                        // return NULL
226                        break;
227                }
228        }
229        return NULL;
230}
231
232void Geno_fL::deleteBranch(std::list<fL_Word *> *list, std::list<fL_Word *>::iterator openbranchposition)
233{
234        fL_Branch *branch = (fL_Branch *)(*openbranchposition);
235        if (branch->btype == fL_Branch::BranchType::OPEN)
236        {
237                int bcount = 1;
238                delete (*openbranchposition);
239                openbranchposition = list->erase(openbranchposition);
240                for (; openbranchposition != list->end(); openbranchposition++)
241                {
242                        if ((*openbranchposition)->type == fLElementType::BRANCH)
243                        {
244                                branch = (fL_Branch *)(*openbranchposition);
245                                if (branch->btype == fL_Branch::BranchType::OPEN)
246                                {
247                                        bcount++;
248                                }
249                                else
250                                {
251                                        bcount--;
252                                        if (bcount == 0)
253                                        {
254                                                delete branch;
255                                                list->erase(openbranchposition);
256                                                break;
257                                        }
258                                }
259                        }
260                }
261        }
262        else
263        {
264                openbranchposition++;
265                if (openbranchposition != list->end())
266                {
267                        delete (*openbranchposition);
268                        list->erase(openbranchposition);
269                }
270        }
271}
272
273int Geno_fL::mutate(char *&geno, float& chg, int &method)
274{
275        fL_Builder *creature = new fL_Builder(false, false);
276
277        if (creature->parseGenotype(geno) != 0)
278        {
279                delete creature;
280                return GENOPER_OPFAIL;
281        }
282
283        int before = creature->countWordsInLSystem();
284
285        method = roulette(operations, FL_OPCOUNT);
286        switch (method)
287        {
288                case FL_CHG_ITER:
289                {
290                        if (randomN(2) == 0)
291                        {
292                                creature->time = creature->time + iterchangestep <= ExtValue::getDouble(FL_MAXITER) ?
293                                                creature->time + iterchangestep : creature->time - iterchangestep;
294                        }
295                        else
296                        {
297                                creature->time = creature->time - iterchangestep >= 0 ?
298                                                creature->time - iterchangestep : creature->time + iterchangestep;
299                        }
300                        break;
301                }
302                case FL_CHG_COND:
303                {
304                        if (creature->rules.size() > 0)
305                        {
306                                int ruleid = randomN(creature->rules.size());
307                                if (!creature->rules[ruleid]->condeval)
308                                {
309                                        creature->rules[ruleid]->condeval = new MathEvaluation(creature->rules[ruleid]->objpred->npar);
310                                }
311                                creature->rules[ruleid]->condeval->mutateConditional();
312                                break;
313                        }
314                        // if there are no rules - create one
315                }
316                /* no break */
317                case FL_ADD_RULE:
318                {
319                        std::unordered_map<std::string, fL_Word *>::iterator pred = creature->words.begin();
320                        std::vector<fL_Word *> wordswithnorules;
321                        for (; pred != creature->words.end(); pred++)
322                        {
323                                if (!pred->second->builtin)
324                                {
325                                        bool norules = true;
326                                        for (fL_Rule * r : creature->rules)
327                                        {
328                                                if (pred->second->name == r->objpred->name &&
329                                                                pred->second->npar == r->objpred->npar)
330                                                {
331                                                        norules = false;
332                                                        break;
333                                                }
334                                        }
335                                        if (norules)
336                                        {
337                                                wordswithnorules.push_back(pred->second);
338                                        }
339                                }
340                        }
341                        if (wordswithnorules.size() > 0)
342                        {
343                                int predid = randomN(wordswithnorules.size());
344                                fL_Rule *newrule = new fL_Rule(0,0);
345                                fL_Word *pred = new fL_Word();
346                                *pred = *wordswithnorules[predid];
347                                newrule->objpred = pred;
348                                fL_Word *initdef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1)); // -1 to avoid branching
349                                addWord(&newrule->objsucc, initdef, newrule->objsucc.begin());
350                                creature->rules.push_back(newrule);
351                                break;
352                        }
353                        else if (creature->rules.size() > 0)
354                        {
355                                int ruleid = randomN(creature->rules.size());
356                                fL_Rule *newrule = new fL_Rule(0, 0);
357                                fL_Word *pred = new fL_Word();
358                                *pred = *creature->rules[ruleid]->objpred;
359                                newrule->objpred = pred;
360                                if (creature->rules[ruleid]->condeval)
361                                {
362                                        std::string formula = "";
363                                        creature->rules[ruleid]->condeval->RPNToInfix(formula);
364                                        if (formula.find("1.0-(") != 0)
365                                        {
366                                                std::string res = "1.0-(";
367                                                res += formula;
368                                                res += ")";
369                                                newrule->condeval = new MathEvaluation(pred->npar);
370                                                newrule->condeval->convertString(res);
371                                        }
372                                        else
373                                        {
374                                                newrule->condeval = new MathEvaluation(pred->npar);
375                                                newrule->condeval->mutateConditional();
376                                        }
377                                }
378                                else
379                                {
380                                        newrule->condeval = new MathEvaluation(pred->npar);
381                                        newrule->condeval->mutateConditional();
382                                }
383                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
384                                addWord(&newrule->objsucc, worddef, newrule->objsucc.begin());
385                                creature->rules.push_back(newrule);
386                                break;
387                        }
388                        // if there are no words, from which rules can be formed, then add one
389                }
390                /* no break */
391                case FL_ADD_WDEF:
392                {
393                        if (creature->countDefinedWords() <= maxdefinedwords)
394                        {
395                                int npar = randomN(ExtValue::getInt(FL_MAXPARAMS, false));
396                                for (int i = 0; i < maxdefinedwords; i++)
397                                {
398                                        std::string name = "w";
399                                        name += std::to_string(i);
400                                        if (creature->words.find(name) == creature->words.end())
401                                        {
402                                                fL_Word *word = new fL_Word(false, 0, 0);
403                                                word->npar = npar;
404                                                word->name = name.c_str();
405                                                word->processDefinition(creature);
406                                                break;
407                                        }
408                                }
409                                break;
410                        }
411                        //no break at the end of case - if there is too many words, then
412                        // deletion should be performed
413                }
414                /* no break */
415                case FL_DEL_WORD:
416                {
417                        int numpars = 0;
418                        int ruleid = 0;
419                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, ruleid);
420                        if (ruleid == -1 && creature->countSticksInSequence((*list)) == 1)
421                        {
422                                if (list->size() > 1)
423                                {
424                                        int rndid = randomN(list->size() - 1);
425                                        int j = 0;
426                                        std::list<fL_Word *>::iterator it = list->begin();
427                                        if ((*it)->name == "S")
428                                        {
429                                                it++;
430                                        }
431                                        while (it != list->end() && j < rndid && ((*it)->name == "S"))
432                                        {
433                                                if ((*it)->name != "S")
434                                                {
435                                                        j++;
436                                                }
437                                                it++;
438                                        }
439                                        if (it != list->end())
440                                        {
441                                                if ((*it)->type == fLElementType::BRANCH)
442                                                {
443                                                        deleteBranch(list, it);
444                                                }
445                                                else
446                                                {
447                                                        delete (*it);
448                                                        list->erase(it);
449                                                }
450                                                break;
451                                        }
452                                        // else add word
453                                }
454                                // else add word
455                        }
456                        else
457                        {
458                                int rndid = randomN(list->size());
459                                std::list<fL_Word *>::iterator it = list->begin();
460                                std::advance(it, rndid);
461                                if ((*it)->type == fLElementType::BRANCH)
462                                {
463                                        deleteBranch(list, it);
464                                }
465                                else
466                                {
467                                        delete (*it);
468                                        list->erase(it);
469                                }
470                                if (ruleid > -1 && creature->rules[ruleid]->objsucc.size() == 0)
471                                {
472                                        delete creature->rules[ruleid];
473                                        creature->rules.erase(creature->rules.begin() + ruleid);
474                                }
475                                break;
476                        }
477                        // if no words available, then add word
478                }
479                /* no break */
480                case FL_ADD_WORD:
481                {
482                        int numpars = 0;
483                        int tmp = 0;
484                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
485                        int rndid = randomN(list->size());
486                        std::list<fL_Word *>::iterator it = list->begin();
487                        std::advance(it, rndid);
488                        int meth = roulette(addtypes, FL_ADD_COUNT);
489                        if (tmp == -1)
490                        { // if sequence is axiom and it does not have non-builtin words
491                                bool hasdefined = false;
492                                for (std::list<fL_Word *>::iterator elem = list->begin(); elem != list->end(); elem++)
493                                {
494                                        if (!(*elem)->builtin)
495                                        {
496                                                hasdefined = true;
497                                                break;
498                                        }
499                                }
500                                if (!hasdefined)
501                                {
502                                        meth = FL_ADD_OTHER;
503                                }
504
505                        }
506                        if (meth != FL_ADD_BRANCH)
507                        {
508                                fL_Word *worddef = randomWordDefinition(creature, meth);
509                                addWord(list, worddef, it);
510                        }
511                        else
512                        {
513                                fL_Branch *start = new fL_Branch(fL_Branch::BranchType::OPEN, 0, 0);
514                                list->insert(it, start);
515                                int rottype = randomN(2);
516                                switch (rottype)
517                                {
518                                case 0:
519                                        addWord(list, creature->words["rotY"], it);
520                                case 1:
521                                        addWord(list, creature->words["rotZ"], it);
522                                }
523                                addWord(list, creature->words["S"], it);
524                                fL_Branch *end = new fL_Branch(fL_Branch::BranchType::CLOSE, 0, 0);
525                                list->insert(it, end);
526                        }
527                        break;
528                }
529                case FL_CHG_WORD:
530                {
531                        int numpars = 0;
532                        int tmp = 0;
533                        std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
534                        int rndid = randomN(list->size());
535                        std::list<fL_Word *>::iterator selectedword = list->begin();
536                        std::advance(selectedword, rndid);
537                        if ((*selectedword)->type == fLElementType::BRANCH)
538                        {
539                                break;
540                        }
541                        int chgtype = roulette(chgoperations, FL_CHG_COUNT);
542                        if (creature->countSticksInSequence((*list)) == 1 && tmp == -1) // if sequence is axiom
543                        {
544                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
545
546                                int numpars = 0;
547                                std::list<fL_Word *> *list = selectRandomSequence(creature, numpars, tmp);
548                                int rndid = randomN(list->size());
549                                std::list<fL_Word *>::iterator it = list->begin();
550                                std::advance(it, rndid);
551
552                                addWord(list, worddef, it);
553
554                                break;
555                        }
556                        else if (chgtype == FL_CHG_WORD_NAME)
557                        {
558                                if ((*selectedword)->builtin)
559                                {
560                                        delete (*selectedword);
561                                        selectedword = list->erase(selectedword);
562                                        fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
563                                        addWord(list, worddef, selectedword);
564                                }
565                                else
566                                {
567                                        std::vector<fL_Word *> available;
568                                        for (std::unordered_map<std::string, fL_Word *>::iterator wit = creature->words.begin();
569                                                        wit != creature->words.end(); wit++)
570                                        {
571                                                if ((*selectedword)->npar == wit->second->npar &&
572                                                                (*selectedword)->name != wit->second->name &&
573                                                                !wit->second->builtin)
574                                                {
575                                                        available.push_back(wit->second);
576                                                }
577                                        }
578                                        if (available.size() > 0)
579                                        {
580                                                int newnameid = randomN(available.size());
581                                                (*selectedword)->name = available[newnameid]->name;
582                                        }
583                                        else
584                                        {
585                                                delete (*selectedword);
586                                                selectedword = list->erase(selectedword);
587                                                fL_Word *worddef = randomWordDefinition(creature, roulette(addtypes, FL_ADD_COUNT - 1));
588                                                addWord(list, worddef, selectedword);
589                                        }
590                                }
591                        }
592                        else
593                        {
594                                if ((*selectedword)->npar > 0)
595                                {
596                                        int randeval = randomN((*selectedword)->npar);
597                                        Param par((*selectedword)->tab, (*selectedword)->data);
598                                        if ((*selectedword)->builtin && (*selectedword)->name == "N"
599                                                        && strcmp(par.id(randeval), FL_PE_NEURO_DET) == 0)
600                                        {
601                                                SString res = par.getStringById(FL_PE_NEURO_DET);
602                                                Geno_fH::mutateNeuronProperties(res);
603                                                par.setStringById(FL_PE_NEURO_DET, res);
604                                        }
605                                        else if ((*selectedword)->builtin &&
606                                                        (*selectedword)->name == "C" &&
607                                                        strcmp(par.id(randeval), FL_PE_CONN_ATTR) == 0)
608                                        {
609                                                SString strattractor = par.getStringById(FL_PE_CONN_ATTR);
610                                                if (strattractor.len() > 0)
611                                                {
612                                                        fL_Word *w = NULL;
613                                                        creature->createWord(strattractor, w, numpars, 0, 0);
614                                                        // mutate attractor parameter
615                                                        if (w->npar > 0)
616                                                        {
617                                                                int rndattr = randomN(w->npar);
618                                                                if (!w->parevals[rndattr])
619                                                                {
620                                                                        w->parevals[rndattr] = new MathEvaluation(numpars);
621                                                                }
622                                                                w->parevals[rndattr]->mutate(false, false);
623                                                        }
624                                                        strattractor = w->stringify(true);
625                                                        par.setStringById(FL_PE_CONN_ATTR, strattractor);
626                                                        delete w;
627                                                }
628                                                else
629                                                {
630                                                        if (creature->builtincount < (int)creature->words.size())
631                                                        {
632                                                                fL_Word *wdef = randomWordDefinition(creature, FL_ADD_OTHER);
633                                                                fL_Word *w = new fL_Word();
634                                                                *w = *wdef;
635                                                                w->data = ParamObject::makeObject(w->tab);
636                                                                Param apar(w->tab);
637                                                                apar.select(w->data);
638                                                                apar.setDefault();
639                                                                if (w->npar > 0)
640                                                                {
641                                                                        int rndattr = randomN(w->npar);
642                                                                        for (int i = 0; i < w->npar; i++)
643                                                                        {
644                                                                                if (i == rndattr)
645                                                                                {
646                                                                                        MathEvaluation *ev = new MathEvaluation(numpars);
647                                                                                        ev->mutate(false, false);
648                                                                                        w->parevals.push_back(ev);
649                                                                                }
650                                                                                else
651                                                                                {
652                                                                                        w->parevals.push_back(NULL);
653                                                                                }
654                                                                        }
655
656                                                                }
657                                                                strattractor = w->stringify(false);
658                                                                par.setStringById(FL_PE_CONN_ATTR, strattractor);
659                                                                delete w;
660                                                        }
661                                                }
662                                        }
663                                        else
664                                        {
665                                                if (!(*selectedword)->parevals[randeval])
666                                                {
667                                                        (*selectedword)->parevals[randeval] = new MathEvaluation(numpars);
668                                                }
669                                                (*selectedword)->parevals[randeval]->mutate(false, iterchangestep != 1.0);
670                                        }
671                                }
672                        }
673                        break;
674                }
675        }
676
677        free(geno);
678        geno = strdup(creature->toString().c_str());
679        chg = (double)abs(before - creature->countWordsInLSystem()) / before;
680        delete creature;
681
682        return GENOPER_OK;
683}
684
685fL_Word* Geno_fL::getAppropriateWord(fL_Builder *from, fL_Builder *to, fL_Word *fromword, std::unordered_map<std::string, std::string> &map)
686{
687        if (fromword->name == "[" || fromword->name == "]") // if words are branching words
688        {
689                fL_Branch *newword = new fL_Branch(fromword->name == "[" ? fL_Branch::BranchType::OPEN : fL_Branch::BranchType::CLOSE, 0, 0);
690                return newword;
691        }
692        if (fromword->builtin)
693        {
694                fL_Word *newword = new fL_Word();
695                (*newword) = (*to->words[fromword->name.c_str()]);
696                return newword;
697        }
698        if (map.find(fromword->name.c_str()) != map.end()) // if word is already mapped
699        {
700                fL_Word *newword = new fL_Word();
701                (*newword) = (*to->words[map[fromword->name.c_str()]]);
702                return newword;
703        }
704        else if (to->words.find(fromword->name.c_str()) != to->words.end() &&
705                        to->words[fromword->name.c_str()]->npar == fromword->npar) // if there is already same word with same number of parameters
706        {
707                fL_Word *newword = new fL_Word();
708                map[fromword->name.c_str()] = fromword->name.c_str();
709                (*newword) = (*to->words[map[fromword->name.c_str()]]);
710                return newword;
711        }
712        for (std::unordered_map<std::string, fL_Word *>::iterator it = to->words.begin();
713                        it != to->words.end(); it++)
714        { // find word with same number of parameters
715                if (fromword->npar == it->second->npar && map.find(fromword->name.c_str()) == map.end() && !it->second->builtin)
716                { // if there is a word with same number of parameters
717                        map[fromword->name.c_str()] = it->second->name.c_str();
718                        fL_Word *newword = new fL_Word();
719                        (*newword) = (*it->second);
720                        return newword;
721                }
722        }
723        fL_Word *newworddef = new fL_Word();
724        (*newworddef) = (*fromword);
725        newworddef->parevals.clear();
726        if (to->words.find(newworddef->name.c_str()) != to->words.end())
727        {
728                int i = 0;
729                while (true)
730                {
731                        std::string name = "w";
732                        name += std::to_string(i);
733                        if (to->words.find(name) == to->words.end())
734                        {
735                                newworddef->name = name.c_str();
736                                break;
737                        }
738                        i++;
739                }
740        }
741        newworddef->processDefinition(to);
742        map[fromword->name.c_str()] = newworddef->name.c_str();
743        fL_Word *newword = new fL_Word();
744        (*newword) = (*to->words[map[fromword->name.c_str()]]);
745        return newword;
746}
747
748void Geno_fL::migrateRandomRules(fL_Builder *from, fL_Builder *to, int numselrules)
749{
750        std::unordered_map<std::string, std::string> map;
751        if (from->rules.size() > 0)
752        {
753                for (int i = 0; i < numselrules; i++)
754                {
755                        int rulid = randomN(from->rules.size());
756                        fL_Rule *rul = from->rules[rulid];
757                        fL_Rule *newrule = new fL_Rule(0, 0);
758                        newrule->objpred = getAppropriateWord(from, to, rul->objpred, map);
759                        for (fL_Word *w : rul->objsucc)
760                        {
761                                fL_Word *el = getAppropriateWord(from, to, w, map);
762                                if (el->type == fLElementType::BRANCH)
763                                {
764                                        newrule->objsucc.push_back(el);
765                                        continue;
766                                }
767                                Param origpar(w->tab);
768                                origpar.select(w->data);
769                                el->data = ParamObject::makeObject(el->tab);
770                                Param par(el->tab);
771                                par.select(el->data);
772                                par.setDefault();
773                                for (int i = 0; i < el->npar; i++)
774                                {
775                                        std::string form;
776                                        if (w->builtin && w->name == "N"
777                                                        && strcmp(par.id(i), FL_PE_NEURO_DET) == 0)
778                                        {
779                                                SString res = origpar.getStringById(FL_PE_NEURO_DET);
780                                                par.setStringById(FL_PE_NEURO_DET, res);
781                                                el->parevals.push_back(NULL);
782                                        }
783                                        else if (w->builtin && w->name == "C"
784                                                        && strcmp(par.id(i), FL_PE_CONN_ATTR) == 0)
785                                        {
786                                                SString strattractor = origpar.getStringById(FL_PE_CONN_ATTR);
787                                                if (strattractor.len() > 0)
788                                                {
789                                                        fL_Word *tmp = NULL;
790                                                        from->createWord(strattractor, tmp, newrule->objpred->npar, 0, 0);
791                                                        fL_Word *newsuccword = getAppropriateWord(from, to, tmp, map);
792                                                        newsuccword->data = ParamObject::makeObject(el->tab);
793                                                        newsuccword->parevals = tmp->parevals;
794                                                        tmp->parevals.clear();
795                                                        strattractor = newsuccword->stringify(true);
796                                                        par.setStringById(FL_PE_CONN_ATTR, strattractor);
797                                                        delete newsuccword;
798                                                        delete tmp;
799                                                }
800                                                par.setStringById(FL_PE_CONN_ATTR, strattractor);
801                                                el->parevals.push_back(NULL);
802                                        }
803                                        else if (w->parevals[i])
804                                        {
805                                                MathEvaluation *eval = new MathEvaluation(newrule->objpred->npar);
806                                                w->parevals[i]->RPNToInfix(form);
807                                                eval->convertString(form);
808                                                el->parevals.push_back(eval);
809                                        }
810                                        else
811                                        {
812                                                el->parevals.push_back(NULL);
813                                        }
814                                }
815                                newrule->objsucc.push_back(el);
816                        }
817                        to->rules.push_back(newrule);
818                }
819        }
820}
821
822int Geno_fL::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
823{
824        fL_Builder *creature1 = new fL_Builder(false, false);
825        fL_Builder *creature1template = new fL_Builder(false, false);
826        fL_Builder *creature2 = new fL_Builder(false, false);
827        fL_Builder *creature2template = new fL_Builder(false, false);
828
829        int count1 = creature1->countWordsInLSystem();
830        int count2 = creature2->countWordsInLSystem();
831
832        if (creature1->parseGenotype(g1) != 0 || creature2->parseGenotype(g2) != 0)
833        {
834                delete creature1;
835                delete creature2;
836                delete creature1template;
837                delete creature2template;
838                return GENOPER_OPFAIL;
839        }
840
841        creature1template->parseGenotype(g1);
842        creature2template->parseGenotype(g2);
843
844        int numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES);
845        numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size();
846
847        migrateRandomRules(creature1template, creature2, numselrules);
848
849        numselrules = 1 + randomN(XOVER_MAX_MIGRATED_RULES);
850        numselrules = numselrules < (int)creature1->rules.size() ? numselrules : (int)creature1->rules.size();
851
852        migrateRandomRules(creature2template, creature1, numselrules);
853
854        free(g1);
855        free(g2);
856
857        g1 = strdup(creature1->toString().c_str());
858        g2 = strdup(creature2->toString().c_str());
859
860        chg1 = (double)count1 / creature1->countWordsInLSystem();
861        chg1 = (double)count2 / creature2->countWordsInLSystem();
862
863        delete creature1;
864        delete creature2;
865        delete creature1template;
866        delete creature2template;
867
868        return GENOPER_OK;
869}
870
871uint32_t Geno_fL::style(const char *geno, int pos)
872{
873        char ch = geno[pos];
874        uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT);
875        if (pos == 0 || geno[pos - 1] == '\n' || ch == ':') // single-character line definition
876        {
877                style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_BOLD);
878        }
879        else if (strchr("()", ch) != NULL)
880        {
881                style = GENSTYLE_RGBS(50, 50, 50, GENSTYLE_BOLD);
882        }
883        else if (isalpha(ch)) // properties name
884        {
885                style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
886        }
887        else if (isdigit(ch) || strchr(",.=", ch)) // properties values
888        {
889                style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
890        }
891        else if (ch == '\"')
892        {
893                style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
894        }
895
896        return style;
897}
Note: See TracBrowser for help on using the repository browser.