source: cpp/frams/genetics/f4/f4_oper.cpp @ 906

Last change on this file since 906 was 899, checked in by Maciej Komosinski, 5 years ago

Code formatting

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