source: cpp/frams/genetics/f4/oper_f4.cpp @ 760

Last change on this file since 760 was 760, checked in by Maciej Komosinski, 2 years ago
  • added support for new API for neuron types and their properties
  • added support for checkpoints
  • Property svn:eol-style set to native
File size: 19.2 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2017  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5// Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
6// Copyright (C) since 2001 Maciej Komosinski
7// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
8
9#include "oper_f4.h"
10#include <frams/util/sstring.h>
11#include <common/log.h>
12
13#include <stdio.h>
14#include <stdlib.h>
15#include "common/nonstd_math.h"
16#include <string.h>
17
18
19//see also modifiers in f1
20#define F4_MODIFIERS_VISUAL "" //not supported in f4
21#define F4_MODIFIERS_RARE "EeWwAaSs" //expdef would need to handle these properly/specifically to ensure reasonable behavior, and hardly any expdef does. Modifying initial energy of a creature as a result of its genes (Ee) is in general not a good idea. Weight (Ww) works only in water, and in water sinking/going up should usually be caused by real "intentional" activity of a creature, not by its inherited weight. For assimilation (Aa), there is a dedicated parameter in CreaturesGroup. Stamina (Ss) is no longer needed as destructive collisions are not supported, and even if they were, some expdef would need to impose reasonable restrictions on the value of this parameter (e.g. similar to normalizeBiol4()) so there is some cost associated with it, and the specific consequences of destructions should be defined as needed.
22#define F4_MODIFIERS "LlRrCcQqFfMmIi" F4_MODIFIERS_RARE F4_MODIFIERS_VISUAL
23const char *Geno_f4::all_modifiers = F4_MODIFIERS;
24
25#define FIELDSTRUCT Geno_f4
26
27static ParamEntry GENO4param_tab[] =
28{
29        { "Genetics: f4", 1, F4_COUNT + F4_ADD_COUNT + 1, },
30        { "f4_mut_add", 0, 0, "Add node", "f 0 100 50", FIELD(prob[F4_ADD]), "mutation: probability of adding a node", },
31        { "f4_mut_add_div", 0, 0, "- add division", "f 0 100 20", FIELD(probadd[F4_ADD_DIV]), "add node mutation: probability of adding a division", },
32        { "f4_mut_add_conn", 0, 0, "- add connection", "f 0 100 15", FIELD(probadd[F4_ADD_CONN]), "add node mutation: probability of adding a neural connection", },
33        { "f4_mut_add_neupar", 0, 0, "- add neuron property", "f 0 100 5", FIELD(probadd[F4_ADD_NEUPAR]), "add node mutation: probability of adding a neuron property/modifier", },
34        { "f4_mut_add_rep", 0, 0, "- add repetition", "f 0 100 10", FIELD(probadd[F4_ADD_REP]), "add node mutation: probability of adding a repetition", },
35        { "f4_mut_add_simp", 0, 0, "- add simple node", "f 0 100 50", FIELD(probadd[F4_ADD_SIMP]), "add node mutation: probability of adding a random, simple gene", },
36        { "f4_mut_del", 0, 0, "Delete node", "f 0 100 20", FIELD(prob[F4_DEL]), "mutation: probability of deleting a node", },
37        { "f4_mut_mod", 0, 0, "Modify node", "f 0 100 30", FIELD(prob[F4_MOD]), "mutation: probability of changing a node", },
38        { "f4_mut_exmod", 1, 0, "Excluded modifiers", "s 0 30", FIELD(excluded_modifiers), "Modifiers that will not be added nor deleted during mutation\n(all: " F4_MODIFIERS ")", },
39        { 0, },
40};
41
42#undef FIELDSTRUCT
43
44
45Geno_f4::Geno_f4()
46{
47        supported_format = '4';
48        par.setParamTab(GENO4param_tab);
49        par.select(this);
50        par.setDefault();
51
52        mutation_method_names = new const char*[F4_COUNT + F4_ADD_COUNT - 1];
53        int index = 0;
54        mutation_method_names[index++] = "added division";
55        mutation_method_names[index++] = "added neural connection";
56        mutation_method_names[index++] = "added neuron property";
57        mutation_method_names[index++] = "added repetition gene";
58        mutation_method_names[index++] = "added a simple node";
59        mutation_method_names[index++] = "deleted a node";
60        mutation_method_names[index++] = "modified a node";
61        if (index != F4_COUNT + F4_ADD_COUNT - 1) logMessage("Geno_f4", "Constructor", 3, "Mutation names init error");
62}
63
64void Geno_f4::setDefaults()
65{
66        excluded_modifiers = F4_MODIFIERS_RARE F4_MODIFIERS_VISUAL;
67}
68
69int Geno_f4::ValidateRec(f4_node * geno, int retrycount) const
70{
71        // ! the genotype is geno->child (not geno) !
72        // build from it with repair on
73
74        f4_Cells cells(geno->child, 1);
75        cells.simulate();  //we should simulate?!
76
77        // errors not fixed:
78        if (GENOPER_OPFAIL == cells.geterror())
79        {
80                if (cells.geterrorpos() >= 0) return 1 + cells.geterrorpos();
81                return GENOPER_OPFAIL;
82        }
83        // errors can be fixed
84        if (GENOPER_REPAIR == cells.geterror())
85        {
86                cells.repairGeno(geno, 1);
87                // note: geno might have been fixed
88                // check again
89                int res2 = GENOPER_OK;
90                if (retrycount > 0)
91                        res2 = ValidateRec(geno, retrycount - 1);
92
93                if (res2 == GENOPER_OK) return GENOPER_REPAIR;
94                return res2;
95        }
96        // no errors:
97        return GENOPER_OK;
98}
99
100
101int Geno_f4::validate(char *& geno, const char *genoname)
102{
103        // convert geno to tree, then try to validate 20 times
104        f4_node root;
105        if (f4_processrec(geno, 0, &root) || root.childCount() != 1) return GENOPER_OK; // cannot repair
106        if (ValidateRec(&root, 20) == GENOPER_REPAIR) // if repaired, make it back to string
107        {
108                geno[0] = 0;
109                root.child->sprintAdj(geno);
110        }
111        return GENOPER_OK;
112}
113
114
115int Geno_f4::checkValidity(const char * geno, const char *genoname)
116{
117        f4_node root;
118        int res = f4_processrec(geno, 0, &root);
119        if (res) return res;  // errorpos, >0
120        if (root.childCount() != 1) return 1; //earlier: GENOPER_OPFAIL
121        f4_Cells cells(root.child, 0);
122        cells.simulate();
123        if (cells.geterror() == GENOPER_OPFAIL || cells.geterror() == GENOPER_REPAIR)
124        {
125                if (cells.geterrorpos() >= 0) return 1 + cells.geterrorpos();
126                else return 1; //earlier: GENOPER_OPFAIL;
127        }
128        else return GENOPER_OK;
129}
130
131
132int Geno_f4::MutateOne(f4_node *& g, int &method) const
133{
134        // ! the genotype is g->child (not g) !
135
136        // codes that can be changed (apart being added/deleted)
137#define MUT_CHAN_CODES "<[#"
138#define ADD_SIMPLE_CODES ",XlLcCrRaAiIsSmMfFwWeEN@|"
139#define REP_MAXCOUNT 19
140
141        // do the mutation
142        // pick a random node
143        f4_node *n1 = g->child->randomNode();
144        vector<NeuroClass*> neulist;
145        //DB( printf("%c\n", n1->name); )
146        int neuronid = -1;
147
148        switch (roulette(prob, F4_COUNT))
149        {
150        case F4_ADD:
151        {
152                // add a node
153                switch (method = roulette(probadd, F4_ADD_COUNT))
154                {
155                case F4_ADD_DIV:
156                {
157                        // add division ('<')
158                        f4_node *n3 = n1->parent;
159                        n3->removeChild(n1);
160                        f4_node *n2 = new f4_node('<', n3, n3->pos);
161                        n2->addChild(n1);
162                        // new cell is stick or neuron
163                        // "X>" or "N>"
164                        f4_node *n5 = NULL;
165                        double pr = rnd01;
166                        pr -= 0.5;
167                        if (pr < 0) n5 = new f4_node('X', n2, n2->pos);
168                        else
169                        {
170                                // make neuron
171                                NeuroClass * rndclass = GenoOperators::getRandomNeuroClass();
172                                if (rndclass == NULL)
173                                {
174                                        n5 = new f4_node('X', n2, n2->pos);
175                                }
176                                else
177                                {
178                                        f4_node *n4 = new f4_node(rndclass->getName().c_str(), n2, n2->pos); //TODO move this above
179                                        if (rndclass->getPreferredInputs() != 0)
180                                        {
181                                                neuronid = -1;
182                                                for (int i = 0; i < g->count(); i++)
183                                                {
184                                                        f4_node * gcur = g->ordNode(i);
185                                                        char * temp = (char*)gcur->name.c_str();
186                                                        NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
187                                                        if (neuclass != NULL)
188                                                        {
189                                                                neulist.push_back(neuclass);
190                                                        }
191                                                        if (g->ordNode(i) == n3)
192                                                        {
193                                                                neuronid = neulist.size()-1;
194                                                        }
195                                                }
196                                                if (neuronid == -1)
197                                                {
198                                                        return GENOPER_OPFAIL;
199                                                }
200                                                n5 = new f4_node('[', n4, n2->pos);
201                                                linkNodeMakeRandom(n5, neuronid, neulist);
202                                        }
203                                        else {
204                                                n5 = n4;
205                                        }
206                                }
207                        }
208                        new f4_node('>', n5, n5->pos);
209                        n1->parent = n2;
210                        // now with 50% chance swap children
211                        if (randomN(2) == 0)
212                        {
213                                n3 = n2->child;
214                                n2->child = n2->child2;
215                                n2->child2 = n3;
216                        }
217                }
218                        break;
219                case F4_ADD_CONN:
220                {
221                        // add link
222                        f4_node * par = n1->parent;
223                        char * temp = (char*)par->name.c_str();
224                        NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
225                        if (neuclass != NULL)
226                        {
227                                n1->parent->removeChild(n1);
228                                f4_node *n2 = new f4_node('[', n1->parent, n1->parent->pos);
229                                n2->addChild(n1);
230                                n1->parent = n2;
231                                neuronid = -1;
232                                for (int i = 0; i < g->count(); i++)
233                                {
234                                        f4_node *gcur = g->ordNode(i);
235                                        temp = (char*)gcur->name.c_str();
236                                        NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
237                                        if (neuclass != NULL)
238                                        {
239                                                neulist.push_back(neuclass);
240                                        }
241                                        if (gcur == par)
242                                        {
243                                                neuronid = neulist.size()-1;
244                                        }
245                                }
246                                if (neuronid == -1)
247                                {
248                                        return GENOPER_OPFAIL;
249                                }
250                                linkNodeMakeRandom(n2, neuronid, neulist);
251                        }
252                }
253                        break;
254                case F4_ADD_NEUPAR:
255                {
256                        // add neuron modifier
257                        n1->parent->removeChild(n1);
258                        f4_node *n2 = new f4_node(':', n1->parent, n1->parent->pos);
259                        nparNodeMakeRandom(n2);
260                        n2->addChild(n1);
261                        n1->parent = n2;
262                }
263                        break;
264                case F4_ADD_REP:
265                {
266                        // add repetition ('#')
267                        // repeated code (left child) is the original, right child is empty, count is 2
268                        f4_node *n3 = n1->parent;
269                        n3->removeChild(n1);
270                        f4_node *n2 = new f4_node('#', n3, n3->pos);
271                        n2->i1 = 2;
272                        n2->addChild(n1);
273                        new f4_node('>', n2, n2->pos);
274                        n1->parent = n2;
275                }
276                        break;
277                case F4_ADD_SIMP:
278                {
279                        // add simple node
280                        // choose a simple node from ADD_SIMPLE_CODES
281                        n1->parent->removeChild(n1);
282                        f4_node *n2 = new f4_node(ADD_SIMPLE_CODES[randomN(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
283                        n2->addChild(n1);
284                        n1->parent = n2;
285                }
286                        break;
287                }
288        }
289                break;
290
291        case F4_DEL:
292        {
293                method = F4_ADD_COUNT - 1 + F4_DEL;
294                // delete a node
295                // must pick a node with parent, and at least one child
296                // already picked a node, but repeat may be needed
297                for (int i = 0; i < 10; i++)
298                {
299                        if ((NULL != n1->parent) && (g != n1->parent))
300                                if (NULL != n1->child)
301                                        break;
302                        // try a new one
303                        n1 = g->child->randomNode();
304                }
305                if ((NULL != n1->parent) && (g != n1->parent))
306                {
307                        switch (n1->childCount())
308                        {
309                        case 0: break;
310                        case 1:  // one child
311                        {
312                                f4_node *n2 = n1->parent;
313                                n2->removeChild(n1);
314                                if (NULL != n1->child)
315                                {
316                                        n1->child->parent = n2;
317                                        n2->addChild(n1->child);
318                                        n1->child = NULL;
319                                }
320                                if (NULL != n1->child2)
321                                {
322                                        n1->child2->parent = n2;
323                                        n2->addChild(n1->child2);
324                                        n1->child2 = NULL;
325                                }
326                                // destroy n1
327                                n1->parent = NULL;
328                                delete n1;
329                        }
330                                break;
331
332                        case 2:  // two children
333                        {
334                                // two children
335                                f4_node *n2 = n1->parent;
336                                n2->removeChild(n1);
337                                // n1 has two children. pick one randomly 50-50, destroy other
338                                if (randomN(2) == 0)
339                                {
340                                        n1->child->parent = n2;
341                                        n2->addChild(n1->child);
342                                        n1->child = NULL;
343                                        n1->child2->parent = NULL;
344                                }
345                                else
346                                {
347                                        n1->child2->parent = n2;
348                                        n2->addChild(n1->child2);
349                                        n1->child2 = NULL;
350                                        n1->child->parent = NULL;
351                                }
352                                // destroy n1
353                                n1->parent = NULL;
354                                delete n1;
355                        }
356                                break;
357                        }
358                }
359                else return GENOPER_OPFAIL;
360        }
361                break;
362        case F4_MOD:
363        {
364                method = F4_ADD_COUNT - 1 + F4_MOD;
365                // change a node
366                // the only nodes that are modifiable are MUT_CHAN_CODES
367                // try to get a modifiable node
368                // already picked a node, but repeat may be needed
369                int i = 0;
370                while (1)
371                {
372                        if (strchr(MUT_CHAN_CODES, n1->name[0])) break;
373                        // try a new one
374                        n1 = g->child->randomNode();
375                        i++;
376                        if (i >= 20) return GENOPER_OPFAIL;
377                }
378                switch (n1->name[0])
379                {
380                case '<':
381                {
382                        // swap children
383                        f4_node *n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
384                }
385                        break;
386                case '[':
387                {
388                        neuronid = -1;
389                        for (int i = 0; i < g->count(); i++)
390                        {
391                                f4_node *gcur = g->ordNode(i);
392                                char *temp = (char*)gcur->name.c_str();
393                                NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
394                                if (neuclass != NULL)
395                                {
396                                        neulist.push_back(neuclass);
397                                }
398                                if (gcur == n1)
399                                {
400                                        neuronid = neulist.size()-1;
401                                }
402                        }
403                        if (neuronid == -1)
404                        {
405                                return GENOPER_OPFAIL;
406                        }
407                        linkNodeChangeRandom(n1, neuronid, neulist);
408                }
409                        break;
410
411                case '#':
412                {
413                        repeatNodeChangeRandom(n1);
414                }
415                        break;
416                }
417        }
418                break;
419
420        default: //no mutations allowed?
421                return GENOPER_OPFAIL;
422        }
423
424        return GENOPER_OK;
425}
426
427// make a random [ node
428void Geno_f4::linkNodeMakeRandom(f4_node *nn, int neuid, vector<NeuroClass*> neulist) const
429{
430        float prob1;
431        NeuroClass *nc = NULL;
432
433        // 35% chance one of *GTS
434        prob1 = rnd01;
435        prob1 -= 0.35f;
436        if (prob1 < 0)
437        {
438                // '*', 'G', 'T', or 'S', 1/4 chance each
439                nc =  GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
440        }
441        if (nc != NULL)
442        {
443                nn->i1 = 1;
444                nn->s1 = nc->getName().c_str();
445                nn->l1 = 0;
446        }
447        else
448        {
449                // relative input link
450                int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
451                int relid = neuid - id;
452                nn->l1 = relid;
453                //nn->l1 = (int)(4.0f * (rnd01 - 0.5f));
454        }
455        // weight
456        nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
457        //nn->f1 = 10.0f * (rnd01 - 0.5f);
458}
459
460// change a [ node
461void Geno_f4::linkNodeChangeRandom(f4_node * nn, int neuid, std::vector<NeuroClass*> neulist) const      //rewritten by M.K. - should work as before (not tested)
462{
463        double probs[3] = { 0.1, 0.3, 0.6 };
464        NeuroClass *cl;
465        // 10% change type
466        // 30% change link
467        // 60% change weight
468
469        switch (roulette(probs, 3))
470        {
471        case 0: // change type
472                // 80% for link, 20% for random sensor
473                if (rnd01 < 0.2f)
474                {
475                        cl = GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
476                        if (cl != NULL)
477                        {
478                                nn->i1 = 1;
479                                nn->s1 = cl->name.c_str();
480                                nn->l1 = 0;
481                        }
482                }
483                break;
484        case 1: // change link
485                if (0 == nn->i1) // relative input link
486                {
487                        int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
488                        nn->l1 = neuid - id;
489                }
490                        //nn->l1 += (int)(2.0f * (rnd01 - 0.5f));
491                break;
492        case 2: // change weight
493                nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
494                //nn->f1 += 1.0f * (rnd01 - 0.5f);
495                break;
496        }
497}
498
499// make a random : node
500void Geno_f4::nparNodeMakeRandom(f4_node * nn) const
501{
502        int sign = (int)(2.0f * rnd01);
503        int param = (int)(3.0f * rnd01);
504        if (param > 2) param = 2;
505        nn->l1 = sign;
506        nn->i1 = "!=/"[param];
507}
508
509// change a repeat # node
510void Geno_f4::repeatNodeChangeRandom(f4_node * nn) const
511{
512        int count;
513        float prob1;
514
515        // change count
516        count = nn->i1;
517        prob1 = rnd01;
518        if (prob1 < 0.5f) count++;
519        else count--;
520        if (count < 1) count = 1;
521        if (count > REP_MAXCOUNT) count = REP_MAXCOUNT;
522        nn->i1 = count;
523}
524
525
526int Geno_f4::MutateOneValid(f4_node *& g, int &method) const
527// mutate one, until a valid genotype is obtained
528{
529        // ! the genotype is g->child (not g) !
530        int i, res;
531        f4_node * gcopy = NULL;
532        // try this max 20 times:
533        //   copy, mutate, then validate
534
535        for (i = 0; i < 20; i++)
536        {
537                gcopy = g->duplicate();
538
539                res = MutateOne(gcopy, method);
540
541                if (GENOPER_OK != res)
542                {
543                        // mutation failed, try again
544                        delete gcopy;
545                        continue;  // for
546                }
547                // try to validate it
548                res = ValidateRec(gcopy, 10);
549                // accept if it is OK, or was repaired
550                if (GENOPER_OK == res)
551                        //(GENOPER_REPAIR == res)
552                {
553                        // destroy the original one
554                        g->destroy();
555                        // make it the new one
556                        *g = *gcopy;
557                        gcopy->child = NULL;
558                        gcopy->child2 = NULL;
559                        delete gcopy;
560                        res = GENOPER_OK;
561                        goto retm1v;
562                }
563                delete gcopy;
564        }
565        // attempts failed
566        res = GENOPER_OPFAIL;
567retm1v:
568        return res;
569}
570
571
572int Geno_f4::mutate(char *& g, float & chg, int &method)
573{
574        f4_node *root = new f4_node;
575        if (f4_processrec(g, 0, root) || root->childCount() != 1)
576        {
577                delete root;
578                return GENOPER_OPFAIL;
579        } // could not convert or bad: fail
580        // mutate one node, set chg as this percent
581        chg = 1.0 / float(root->child->count());
582        if (MutateOneValid(root, method) != GENOPER_OK)
583        {
584                delete root;
585                return GENOPER_OPFAIL;
586        }
587        // OK, convert back to string
588        g[0] = 0;
589        root->child->sprintAdj(g);
590        delete root;
591        return GENOPER_OK;
592}
593
594
595/*
596int Geno_f4::MutateMany(char *& g, float & chg)
597// check if original is valid, then
598// make a number of mutations
599{
600int res, n, i;
601int totNodes = 0;
602int maxToMut = 0;
603
604// convert to tree
605f4_node * root;
606root = new f4_node();
607res = f4_processrec(g, 0, root);
608if (res) {
609// could not convert, fail
610goto retm;
611}
612if (1 != root->childCount()) {
613res = GENOPER_OPFAIL;
614goto retm;
615}
616
617// check if original is valid
618res = ValidateRec( root, 20 );
619// might have been repaired!
620if (GENOPER_REPAIR==res) {
621res = GENOPER_OK;
622}
623if (GENOPER_OK != res) {
624goto retm;
625}
626
627// decide number of nodes to mutate
628// decide maximum number of nodes to mutate: 0.25*nodes, min 2
629totNodes = root->child->count();
630maxToMut = (int)( 0.25f * totNodes);
631if (maxToMut<2) maxToMut=2;
632if (maxToMut>totNodes) maxToMut=totNodes;
633
634// decide number of nodes to mutate
635n = (int)( 0.5f + rnd01 * maxToMut );
636if (n<1) n=1;
637if (n>totNodes) n=totNodes;
638// set chg as this percent
639chg = ((float)n) / ((float)totNodes);
640for (i=0; i<n; i++)
641{
642res = MutateOneValid(root);
643if (GENOPER_OK != res)
644{
645res = GENOPER_OPFAIL;
646goto retm;
647}
648}
649// OK, convert back to string
650g[0]=0;
651root->child->sprintAdj(g);
652retm:
653delete root;
654return res;
655}
656*/
657
658
659int Geno_f4::CrossOverOne(f4_node * g1, f4_node * g2, float chg) const
660{
661        // ! the genotypes are g1->child and g2->child (not g1 g2) !
662        // single offspring in g1
663        int smin, smax;
664        float size;
665        f4_node * n1, *n2, *n1p, *n2p;
666
667        // determine desired size
668        size = (1 - chg) * (float)g1->count();
669        smin = (int)(size*0.9f - 1);
670        smax = (int)(size*1.1f + 1);
671        // get a random node with desired size
672        n1 = g1->child->randomNodeWithSize(smin, smax);
673
674        // determine desired size
675        size = (1 - chg) * (float)g2->count();
676        smin = (int)(size*0.9f - 1);
677        smax = (int)(size*1.1f + 1);
678        // get a random node with desired size
679        n2 = g2->child->randomNodeWithSize(smin, smax);
680
681        // exchange the two nodes:
682        n1p = n1->parent;
683        n2p = n2->parent;
684        n1p->removeChild(n1);
685        n1p->addChild(n2);
686        n2p->removeChild(n2);
687        n2p->addChild(n1);
688        n1->parent = n2p;
689        n2->parent = n1p;
690
691        return GENOPER_OK;
692}
693
694int Geno_f4::crossOver(char *&g1, char *&g2, float &chg1, float &chg2)
695{
696        f4_node root1, root2, *copy1, *copy2;
697
698        // convert genotype strings into tree structures
699        if (f4_processrec(g1, 0, &root1) || (root1.childCount() != 1)) return GENOPER_OPFAIL;
700        if (f4_processrec(g2, 0, &root2) || (root2.childCount() != 1)) return GENOPER_OPFAIL;
701
702        // decide amounts of crossover, 0.25-0.75
703        // adam: seems 0.1-0.9 -- MacKo
704        chg1 = 0.1f + 0.8f*rnd01;
705        chg2 = 0.1f + 0.8f*rnd01;
706
707        copy1 = root1.duplicate();
708        if (CrossOverOne(copy1, &root2, chg1) != GENOPER_OK) { delete copy1; copy1 = NULL; }
709        copy2 = root2.duplicate();
710        if (CrossOverOne(copy2, &root1, chg2) != GENOPER_OK) { delete copy2; copy2 = NULL; }
711
712        g1[0] = 0;
713        g2[0] = 0;
714        if (copy1) { copy1->child->sprintAdj(g1); delete copy1; }
715        if (copy2) { copy2->child->sprintAdj(g2); delete copy2; }
716        if (g1[0] || g2[0]) return GENOPER_OK; else return GENOPER_OPFAIL;
717}
718
719
720
721uint32_t Geno_f4::style(const char *g, int pos)
722{
723        char ch = g[pos];
724        // style categories
725#define STYL4CAT_MODIFIC F4_MODIFIERS ","
726#define STYL4CAT_NEUMOD "[]|@*GTS:+-/!="
727#define STYL4CAT_DIGIT "0123456789."
728#define STYL4CAT_REST "XN<># "
729        if (!strchr(STYL4CAT_MODIFIC STYL4CAT_NEUMOD STYL4CAT_DIGIT STYL4CAT_REST, ch))
730                return GENSTYLE_CS(0, GENSTYLE_INVALID);
731        uint32_t style = GENSTYLE_CS(0, GENSTYLE_STRIKEOUT); //default, should be changed below
732        if (strchr("X ", ch))              style = GENSTYLE_CS(0, GENSTYLE_NONE);
733        if (strchr("N", ch))               style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_NONE);
734        if (strchr("<", ch))               style = GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
735        if (strchr(">", ch))               style = GENSTYLE_RGBS(0, 0, 100, GENSTYLE_NONE);
736        if (strchr(STYL4CAT_DIGIT, ch))     style = GENSTYLE_RGBS(100, 100, 100, GENSTYLE_NONE);
737        if (strchr(STYL4CAT_MODIFIC, ch))   style = GENSTYLE_RGBS(100, 100, 100, GENSTYLE_NONE);
738        if (strchr(STYL4CAT_NEUMOD, ch))    style = GENSTYLE_RGBS(0, 150, 0, GENSTYLE_NONE);
739        return style;
740}
Note: See TracBrowser for help on using the repository browser.