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

Last change on this file since 973 was 973, checked in by Maciej Komosinski, 4 years ago

Increased SString and std::string compatibility: introduced length(), size(), and capacity(), and removed legacy methods that have std::string equivalents

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