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

Last change on this file since 771 was 771, checked in by Maciej Komosinski, 6 years ago

Added color and size modifiers in f4; avoided unnecessary conditions in styling; fixes issue 17 and concerns issue 18 [refs #62]

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