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

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

Renamed all genooper paramtab variables to be consistent with the standard naming convention

  • Property svn:eol-style set to native
File size: 19.0 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5// 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 "f4_oper.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
19const char *Geno_f4::all_modifiers = F14_MODIFIERS ","; //comma in f4 is handled the same way (simple node, F4_ADD_SIMP) as modifiers
20
21// codes that can be changed (apart from being added/deleted)
22#define MUT_CHAN_CODES "<[#"
23#define REP_MAXCOUNT 19
24
25#define FIELDSTRUCT Geno_f4
26
27static ParamEntry geno_f4_paramtab[] =
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: " F14_MODIFIERS ")", },
39        { 0, },
40};
41
42#undef FIELDSTRUCT
43
44
45Geno_f4::Geno_f4()
46{
47        supported_format = '4';
48        par.setParamTab(geno_f4_paramtab);
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 = F14_MODIFIERS_RARE F14_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        // do the mutation
137        // pick a random node
138        f4_node *n1 = g->child->randomNode();
139        vector<NeuroClass*> neulist;
140        //DB( printf("%c\n", n1->name); )
141        int neuronid = -1;
142
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 ('<')
153                        f4_node *n3 = n1->parent;
154                        n3->removeChild(n1);
155                        f4_node *n2 = new f4_node('<', n3, n3->pos);
156                        n2->addChild(n1);
157                        // new cell is stick or neuron
158                        // "X>" or "N>"
159                        f4_node *n5 = NULL;
160                        double pr = rndDouble(1);
161                        pr -= 0.5;
162                        if (pr < 0) n5 = new f4_node('X', n2, n2->pos);
163                        else
164                        {
165                                // make neuron
166                                NeuroClass *rndclass = GenoOperators::getRandomNeuroClass(Model::SHAPE_BALL_AND_STICK);
167                                if (rndclass == NULL)
168                                {
169                                        n5 = new f4_node('X', n2, n2->pos);
170                                }
171                                else
172                                {
173                                        f4_node *n4 = new f4_node(rndclass->getName().c_str(), n2, n2->pos);
174                                        if (rndclass->getPreferredInputs() != 0)
175                                        {
176                                                neuronid = -1;
177                                                for (int i = 0; i < g->count(); i++)
178                                                {
179                                                        f4_node *gcur = g->ordNode(i);
180                                                        char* temp = (char*)gcur->name.c_str();
181                                                        NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
182                                                        if (neuclass != NULL)
183                                                        {
184                                                                neulist.push_back(neuclass);
185                                                        }
186                                                        if (g->ordNode(i) == n3)
187                                                        {
188                                                                neuronid = neulist.size() - 1;
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                                }
202                        }
203                        new f4_node('>', n5, n5->pos);
204                        n1->parent = n2;
205                        // now with 50% chance swap children
206                        if (rndUint(2) == 0)
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
217                        f4_node *par = n1->parent;
218                        char* temp = (char*)par->name.c_str();
219                        NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
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                                        {
238                                                neuronid = neulist.size() - 1;
239                                        }
240                                }
241                                if (neuronid == -1)
242                                {
243                                        return GENOPER_OPFAIL;
244                                }
245                                linkNodeMakeRandom(n2, neuronid, neulist);
246                        }
247                }
248                        break;
249                case F4_ADD_NEUPAR:
250                {
251                        // add neuron modifier
252                        n1->parent->removeChild(n1);
253                        f4_node *n2 = new f4_node(':', n1->parent, n1->parent->pos);
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
263                        f4_node *n3 = n1->parent;
264                        n3->removeChild(n1);
265                        f4_node *n2 = new f4_node('#', n3, n3->pos);
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);
277                        //f4_node *n2 = new f4_node(ADD_SIMPLE_CODES[rndUint(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
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);
280                        n2->addChild(n1);
281                        n1->parent = n2;
282                }
283                        break;
284                }
285        }
286                break;
287
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
294                for (int i = 0; i < 10; i++)
295                {
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                        {
309                                f4_node *n2 = n1->parent;
310                                n2->removeChild(n1);
311                                if (NULL != n1->child)
312                                {
313                                        n1->child->parent = n2;
314                                        n2->addChild(n1->child);
315                                        n1->child = NULL;
316                                }
317                                if (NULL != n1->child2)
318                                {
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;
328
329                        case 2:  // two children
330                        {
331                                // two children
332                                f4_node *n2 = n1->parent;
333                                n2->removeChild(n1);
334                                // n1 has two children. pick one randomly 50-50, destroy other
335                                if (rndUint(2) == 0)
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                {
369                        if (strchr(MUT_CHAN_CODES, n1->name[0])) break;
370                        // try a new one
371                        n1 = g->child->randomNode();
372                        i++;
373                        if (i >= 20) return GENOPER_OPFAIL;
374                }
375                switch (n1->name[0])
376                {
377                case '<':
378                {
379                        // swap children
380                        f4_node *n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
381                }
382                        break;
383                case '[':
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                                {
397                                        neuronid = neulist.size() - 1;
398                                }
399                        }
400                        if (neuronid == -1)
401                        {
402                                return GENOPER_OPFAIL;
403                        }
404                        linkNodeChangeRandom(n1, neuronid, neulist);
405                }
406                        break;
407
408                case '#':
409                {
410                        repeatNodeChangeRandom(n1);
411                }
412                        break;
413                }
414        }
415                break;
416
417        default: //no mutations allowed?
418                return GENOPER_OPFAIL;
419        }
420
421        return GENOPER_OK;
422}
423
424// make a random [ node
425void Geno_f4::linkNodeMakeRandom(f4_node *nn, int neuid, vector<NeuroClass*> neulist) const
426{
427        float prob1;
428        NeuroClass *nc = NULL;
429
430        // 35% chance one of *GTS
431        prob1 = rndDouble(1);
432        prob1 -= 0.35f;
433        if (prob1 < 0)
434        {
435                // '*', 'G', 'T', or 'S', 1/4 chance each
436                nc = GenoOperators::getRandomNeuroClassWithOutputAndNoInputs(Model::SHAPE_BALL_AND_STICK);
437        }
438        if (nc != NULL)
439        {
440                nn->i1 = 1;
441                nn->s1 = nc->getName().c_str();
442                nn->l1 = 0;
443        }
444        else
445        {
446                // relative input link
447                int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
448                int relid = neuid - id;
449                nn->l1 = relid;
450                //nn->l1 = (int)(4.0f * (rndDouble(1) - 0.5f));
451        }
452        // weight
453        nn->f1 = GenoOperators::getMutatedNeuronConnectionWeight(nn->f1);
454        //nn->f1 = 10.0f * (rndDouble(1) - 0.5f);
455}
456
457// change a [ node
458void Geno_f4::linkNodeChangeRandom(f4_node *nn, int neuid, std::vector<NeuroClass*> neulist) const      //rewritten by M.K. - should work as before (not tested)
459{
460        double probs[3] = { 0.1, 0.3, 0.6 };
461        NeuroClass *cl;
462        // 10% change type
463        // 30% change link
464        // 60% change weight
465
466        switch (roulette(probs, 3))
467        {
468        case 0: // change type
469                // 80% for link, 20% for random sensor
470                if (rndDouble(1) < 0.2f)
471                {
472                        cl = GenoOperators::getRandomNeuroClassWithOutputAndNoInputs(Model::SHAPE_BALL_AND_STICK);
473                        if (cl != NULL)
474                        {
475                                nn->i1 = 1;
476                                nn->s1 = cl->name.c_str();
477                                nn->l1 = 0;
478                        }
479                }
480                break;
481        case 1: // change link
482                if (0 == nn->i1) // relative input link
483                {
484                        int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
485                        nn->l1 = neuid - id;
486                }
487                //nn->l1 += (int)(2.0f * (rndDouble(1) - 0.5f));
488                break;
489        case 2: // change weight
490                nn->f1 = GenoOperators::getMutatedNeuronConnectionWeight(nn->f1);
491                //nn->f1 += 1.0f * (rndDouble(1) - 0.5f);
492                break;
493        }
494}
495
496// make a random : node
497void Geno_f4::nparNodeMakeRandom(f4_node *nn) const
498{
499        int sign = (int)rndDouble(2);
500        int param = (int)rndDouble(3);
501        if (param > 2) param = 2;
502        nn->l1 = sign;
503        nn->i1 = "!=/"[param];
504}
505
506// change a repeat # node
507void Geno_f4::repeatNodeChangeRandom(f4_node *nn) const
508{
509        int count;
510        float prob1;
511
512        // change count
513        count = nn->i1;
514        prob1 = rndDouble(1);
515        if (prob1 < 0.5f) count++;
516        else count--;
517        if (count < 1) count = 1;
518        if (count > REP_MAXCOUNT) count = REP_MAXCOUNT;
519        nn->i1 = count;
520}
521
522
523int Geno_f4::MutateOneValid(f4_node *& g, int &method) const
524// mutate one, until a valid genotype is obtained
525{
526        // ! the genotype is g->child (not g) !
527        int i, res;
528        f4_node *gcopy = NULL;
529        // try this max 20 times:
530        //   copy, mutate, then validate
531
532        for (i = 0; i < 20; i++)
533        {
534                gcopy = g->duplicate();
535
536                res = MutateOne(gcopy, method);
537
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;
564retm1v:
565        return res;
566}
567
568
569int Geno_f4::mutate(char *& g, float & chg, int &method)
570{
571        f4_node *root = new f4_node;
572        if (f4_processrec(g, 0, root) || root->childCount() != 1)
573        {
574                delete root;
575                return GENOPER_OPFAIL;
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        {
581                delete root;
582                return GENOPER_OPFAIL;
583        }
584        // OK, convert back to string
585        g[0] = 0;
586        root->child->sprintAdj(g);
587        delete root;
588        return GENOPER_OK;
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{
597int res, n, i;
598int totNodes = 0;
599int maxToMut = 0;
600
601// convert to tree
602f4_node *root;
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}
613
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}
623
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;
630
631// decide number of nodes to mutate
632n = (int)( 0.5f + rndDouble(1) * maxToMut );
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);
649retm:
650delete root;
651return res;
652}
653*/
654
655
656int Geno_f4::CrossOverOne(f4_node *g1, f4_node *g2, float chg) const
657{
658        // ! the genotypes are g1->child and g2->child (not g1 g2) !
659        // single offspring in g1
660        int smin, smax;
661        float size;
662        f4_node *n1, *n2, *n1p, *n2p;
663
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);
670
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);
677
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;
687
688        return GENOPER_OK;
689}
690
691int Geno_f4::crossOver(char *&g1, char *&g2, float &chg1, float &chg2)
692{
693        f4_node root1, root2, *copy1, *copy2;
694
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;
698
699        // decide amounts of crossover, 0.25-0.75
700        // adam: seems 0.1-0.9 -- MacKo
701        chg1 = 0.1 + rndDouble(0.8);
702        chg2 = 0.1 + rndDouble(0.8);
703
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; }
708
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;
714}
715
716uint32_t Geno_f4::style(const char *g, int pos)
717{
718        char ch = g[pos];
719
720        // style categories
721#define STYL4CAT_MODIFIC F14_MODIFIERS ","
722#define STYL4CAT_NEUMOD "[]:+-/!="
723#define STYL4CAT_NEUSPECIAL "|@*"
724#define STYL4CAT_DIGIT "0123456789."
725#define STYL4CAT_REST "XN<># "
726
727        if (!isalpha(ch) && !strchr(STYL4CAT_MODIFIC STYL4CAT_NEUMOD STYL4CAT_NEUSPECIAL STYL4CAT_DIGIT STYL4CAT_REST "\t", ch))
728        {
729                return GENSTYLE_CS(0, GENSTYLE_INVALID);
730        }
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        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);
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);
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);
750                        }
751                }
752        }
753        return style;
754}
Note: See TracBrowser for help on using the repository browser.