source: cpp/frams/genetics/f4/f4_general.cpp @ 375

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

Renamed logging functions to more intuitive and simple names

  • Property svn:eol-style set to native
File size: 29.1 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  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
7#include "f4_general.h"
8#include <common/nonstd_stl.h>
9#include <common/log.h>
10#include <frams/model/model.h> // for min and max attributes
11#include "../oper_fx.h" //for GENOPER_ constants
12#include <stdio.h>
13#include <common/nonstd_math.h>
14
15#ifdef DMALLOC
16#include <dmalloc.h>
17#endif
18
19
20f4_Props::f4_Props()
21{
22        len = 1.0;
23        curv = 0.0;
24        mass = 1.0;
25        friction = 0.4;
26        ruch = 0.25; // bio
27        assim = 0.25; // bio
28        odpor = 0.25; // bio
29        ingest = 0.25; // bio
30        twist = 0.0;
31        energ = 1.0;
32        normalizeBiol4();
33}
34
35void f4_Props::normalizeBiol4()
36{
37        // must sum to 1
38        double sum = ruch + assim + odpor + ingest;
39        if (0 == sum)
40        {
41                ruch = assim = odpor = ingest = 0.25;
42        }
43        else {
44                ruch /= sum;
45                assim /= sum;
46                odpor /= sum;
47                ingest /= sum;
48        }
49}
50
51void f4_Props::executeModifier(char modif)
52{
53        switch (modif)
54        {
55        case 'L': len += (2.5 - len) * 0.3;
56                len = min(len, Model::getMaxJoint().d.x); break;
57        case 'l': len += (0.3 - len) * 0.3;
58                len = max(len, Model::getMinJoint().d.x); break;
59        case 'C': curv += (2.0 - curv) * 0.25;  break;
60        case 'c': curv += (-2.0 - curv) * 0.25;  break;
61        case 'Q': twist += (1.58 - twist) * 0.3; break;
62        case 'q': twist += (-1.58 - twist) * 0.3; break;
63        case 'A': assim += (1 - assim) * 0.8; normalizeBiol4(); break;
64        case 'a': assim -= assim * 0.4;       normalizeBiol4(); break;
65        case 'I': ingest += (1 - ingest) * 0.8;   normalizeBiol4(); break;
66        case 'i': ingest -= ingest * 0.4;         normalizeBiol4(); break;
67        case 'S': odpor += (1 - odpor) * 0.8; normalizeBiol4(); break;
68        case 's': odpor -= odpor * 0.4;       normalizeBiol4(); break;
69        case 'M': ruch += (1 - ruch) * 0.8;   normalizeBiol4(); break;
70        case 'm': ruch -= ruch * 0.4;         normalizeBiol4(); break;
71        case 'F': friction += (4 - friction) * 0.2; break;
72        case 'f': friction -= friction * 0.2;       break;
73        case 'W': mass += (2.0 - mass) * 0.3;   break;
74        case 'w': mass += (0.5 - mass) * 0.3;   break;
75        case 'E': energ += (10.0 - energ) * 0.1; break;
76        case 'e': energ -= energ * 0.1;          break;
77        }
78}
79
80void f4_Props::adjust()
81{
82        len = 0.5*len + 0.5*stdProps.len;
83        curv = 0.66 * curv;
84        twist = 0.66 * twist;
85}
86
87f4_Props stdProps;
88
89
90void rolling_dec(double * v) {
91        *v -= 0.7853;  // 0.7853981  45 degrees
92}
93void rolling_inc(double * v) {
94        *v += 0.7853;  // 0.7853981  45 degrees
95}
96
97
98int scanrec(const char * s, unsigned int slen, char stopchar)
99{
100        unsigned int i = 0;
101        //DB( printf("    scan('%s', '%c')\n", s, stopchar); )
102        while (1)
103        {
104                if (i >= slen)  // ran out the string, should never happen with correct string
105                        return 1;
106                if (stopchar == s[i])  // bumped into stopchar
107                        return i;
108                if (i < slen - 1)
109                { // s[i] is not the last char
110                        if (s[i] == '(')
111                        {
112                                i += 2 + scanrec(s + i + 1, slen - i - 1, ')');
113                                continue;
114                        }
115                        if (s[i] == '<')
116                        {
117                                i += 2 + scanrec(s + i + 1, slen - i - 1, '>');
118                                continue;
119                        }
120                        if (s[i] == '#')
121                        {
122                                i += 2 + scanrec(s + i + 1, slen - i - 1, '>');
123                                continue;
124                        }
125                }
126                // s[i] a non-special character
127                i++;
128        }
129        return i;
130}
131
132
133f4_Cell::f4_Cell(int nname,
134        f4_Cell * ndad, int nangle, f4_Props newP)
135{
136        name = nname;
137        type = T_UNDIFF4;
138        dadlink = ndad;
139        org = NULL;
140        genot = NULL;
141        gcur = NULL;
142        active = 1;
143        repeat.null();
144        //genoRange.clear(); -- implicit
145
146        anglepos = nangle;
147        commacount = 0;
148        childcount = 0;
149        P = newP;
150        rolling = 0;
151        xrot = 0;
152        zrot = 0;
153        //OM = Orient_1;
154        ctrl = 0;
155        state = 0;
156        inertia = 0.8;
157        force = 0.04;
158        sigmo = 2;
159        nolink = 0;
160
161        // adjust firstend and OM if there is a stick dad
162        if (ndad != NULL)
163        {
164                // make sure it is a stick (and not a stick f4_Cell!)
165                if (T_STICK4 == ndad->type)
166                {
167                        //firstend = ndad->lastend;
168                        //OM = ndad->OM;
169                        ndad->childcount++;
170                }
171                if (T_NEURON4 == ndad->type)
172                {
173                        state = ndad->state;
174                        inertia = ndad->inertia;
175                        force = ndad->force;
176                        sigmo = ndad->sigmo;
177                }
178        }
179        // adjust lastend
180        //lastend = firstend + ((Orient)OM * (Pt3D(1,0,0) * P.len));
181        mz = 1;
182}
183
184
185f4_Cell::f4_Cell(f4_Cells * nO, int nname, f4_node * ngeno, f4_node * ngcur,
186        f4_Cell * ndad, int nangle, f4_Props newP)
187{
188        name = nname;
189        type = T_UNDIFF4;
190        dadlink = ndad;
191        org = nO;
192        genot = ngeno;
193        gcur = ngcur;
194        active = 1;
195        repeat.null();
196        //genoRange.clear(); -- implicit
197        // preserve geno range of parent cell
198        if (NULL != ndad)
199                genoRange.add(ndad->genoRange);
200
201        anglepos = nangle;
202        commacount = 0;
203        childcount = 0;
204        P = newP;
205        rolling = 0;
206        xrot = 0;
207        zrot = 0;
208        //OM = Orient_1;
209        ctrl = 0;
210        state = 0;
211        inertia = 0.8;
212        force = 0.04;
213        sigmo = 2;
214        nolink = 0;
215
216        // adjust firstend and OM if there is a stick dad
217        if (ndad != NULL)
218        {
219                // make sure it is a stick (and not a stick f4_Cell!)
220                if (T_STICK4 == ndad->type) {
221                        //firstend = ndad->lastend;
222                        //OM = ndad->OM;
223                        ndad->childcount++;
224                }
225                if (T_NEURON4 == ndad->type)
226                {
227                        state = ndad->state;
228                        inertia = ndad->inertia;
229                        force = ndad->force;
230                        sigmo = ndad->sigmo;
231                }
232        }
233        // adjust lastend
234        //lastend = firstend + ((Orient)OM * (Pt3D(1,0,0) * P.len));
235        mz = 1;
236}
237
238
239f4_Cell::~f4_Cell()
240{
241        // remove links
242        if (nolink)
243        {
244                int i;
245                for (i = nolink - 1; i >= 0; i--)
246                        delete links[i];
247                nolink = 0;
248        }
249}
250
251
252/* return codes:
253        >1 error at pos
254        0  halt development for a cycle
255        -1  development finished OK
256        */
257int f4_Cell::onestep()
258{
259        int i, j, k, relfrom, t;
260        double w;
261        f4_Cell * tmp;
262        f4_Cell * tneu;
263        if (gcur == NULL)
264        {
265                active = 0;
266                return 0;  // stop
267        }
268        while (NULL != gcur)
269        {
270                //DB( printf("  %d (%d) executing '%c' %d\n", name, type, gcur->name, gcur->pos); )
271                // currently this is the last one processed
272                // the current genotype code is processed
273                genoRange.add(gcur->pos);
274                switch (gcur->name)
275                {
276                case '<':
277                        // cell division!
278                        //DB( printf("  div! %d\n", name); )
279
280                        // error: sticks cannot divide
281                        if (T_STICK4 == type) {
282                                // cannot fix
283                                org->setError(gcur->pos);
284                                return 1;  // stop
285                        }
286
287                        // undiff divides
288                        if (T_UNDIFF4 == type) {
289                                // commacount is set only when daughter turns into X
290                                // daughter cell
291                                // adjust new len
292                                f4_Props newP = P;
293                                newP.adjust();
294                                tmp = new f4_Cell(org, org->nc, genot, gcur->child2,
295                                        this, commacount, newP);
296                                tmp->repeat = repeat;
297                                repeat.null();
298                                org->addCell(tmp);
299                        }
300                        // a neuron divides: create a new, duplicate links
301                        if (T_NEURON4 == type) {
302                                // daughter cell
303                                tmp = new f4_Cell(org, org->nc, genot, gcur->child2,
304                                        // has the same dadlink
305                                        this->dadlink, commacount, P);
306                                tmp->repeat = repeat;
307                                repeat.null();
308                                // it is a neuron from start
309                                tmp->type = T_NEURON4;
310                                // duplicate links
311                                f4_CellLink * ll;
312                                for (i = 0; i < nolink; i++) {
313                                        ll = links[i];
314                                        tmp->addlink(ll->from, ll->w, ll->t);
315                                }
316                                org->addCell(tmp);
317                        }
318                        // adjustments for this cell
319                        gcur = gcur->child;
320                        // halt development
321                        return 0;
322
323                case '>':
324                        // finish
325                        // see if there is a repet count
326                        if (repeat.top > 0)
327                        { // there is a repeat counter
328                                if (!repeat.first()->isNull())
329                                { // repeat counter is not null
330                                        repeat.first()->dec();
331                                        if (repeat.first()->count > 0)
332                                        {
333                                                // return to repeat
334                                                gcur = repeat.first()->node->child;
335                                        }
336                                        else {
337                                                // continue
338                                                gcur = repeat.first()->node->child2;
339                                                repeat.pop();
340                                        }
341                                        break;
342                                }
343                                else {
344                                        repeat.pop();
345                                }
346                        }
347                        else {
348                                // error: still undiff
349                                if (T_UNDIFF4 == type)
350                                {
351                                        // fix it: insert an 'X'
352                                        f4_node * insertnode = new f4_node('X', NULL, gcur->pos);
353                                        if (org->setRepairInsert(gcur->pos, gcur, insertnode))
354                                                // not in repair mode, release
355                                                delete insertnode;
356                                        return 1;
357                                }
358                                repeat.null();
359                                active = 0;  // stop
360                                // eat up rest
361                                gcur = NULL;
362                                return 0;
363                        }
364
365                case '#':
366                        // repetition marker
367                        if (repeat.top >= repeat_stack::stackSize)
368                        {
369                                // repepeat pointer stack is full, cannot remember this one.
370                                // fix: delete it
371                                org->setRepairRemove(gcur->pos, gcur);
372                                return 1;  // stop
373                        }
374                        repeat.push(repeat_ptr(gcur, gcur->i1));
375                        gcur = gcur->child;
376                        break;
377
378                case ',':
379                        commacount++;
380                        gcur = gcur->child;
381                        break;
382
383                case 'r':  case 'R':
384                        // error: if neuron
385                        if (T_NEURON4 == type) {
386                                // fix: delete it
387                                org->setRepairRemove(gcur->pos, gcur);
388                                return 1;  // stop
389                        }
390                        switch (gcur->name) {
391                        case 'r':   rolling_dec(&rolling); break;
392                        case 'R':   rolling_inc(&rolling); break;
393                        }
394                        gcur = gcur->child;
395                        break;
396
397                case 'l':  case 'L':
398                case 'c':  case 'C':
399                case 'q':  case 'Q':
400                case 'a':  case 'A':
401                case 'i':  case 'I':
402                case 's':  case 'S':
403                case 'm':  case 'M':
404                case 'f':  case 'F':
405                case 'w':  case 'W':
406                case 'e':  case 'E':
407                        // error: if neuron
408                        if (T_NEURON4 == type) {
409                                // fix: delete it
410                                org->setRepairRemove(gcur->pos, gcur);
411                                return 1;  // stop
412                        }
413                        P.executeModifier(gcur->name);
414                        gcur = gcur->child;
415                        break;
416
417                case 'X':
418                        // turn undiff. cell into a stick
419                        // error: already differentiated
420                        if (T_UNDIFF4 != type) {
421                                // fix: delete this node
422                                org->setRepairRemove(gcur->pos, gcur);
423                                return 1;  // stop
424                        }
425                        type = T_STICK4;
426                        // fix dad commacount and own anglepos
427                        if (NULL != dadlink) {
428                                dadlink->commacount++;
429                                anglepos = dadlink->commacount;
430                        }
431                        // change of type halts developments, see comment at 'N'
432                        gcur = gcur->child;
433                        return 0;
434
435                case 'N':
436                        // turn undiff. cell into a neuron
437                        // error: already differentiated
438                        if (T_UNDIFF4 != type) {
439                                // fix: delete this node
440                                org->setRepairRemove(gcur->pos, gcur);
441                                return 1;  // stop
442                        }
443                        // error: if no previous
444                        if (NULL == dadlink) {
445                                // fix: delete it
446                                org->setRepairRemove(gcur->pos, gcur);
447                                return 1;  // stop
448                        }
449                        type = T_NEURON4;
450                        // change of type also halts development, to give other
451                        // cells a chance for adjustment.  Namely, it is important
452                        // to wait for other cells to turn N before adding links
453                        gcur = gcur->child;
454                        return 0;
455
456                case '@':
457                case '|':
458                        // neuron rotating / bending
459                        j = 1;
460                        if ('@' == gcur->name) j = 1; // rot
461                        if ('|' == gcur->name) j = 2; // bend
462                        // error: not a neuron (undiff)
463                        if (T_UNDIFF4 == type) {
464                                // fix: delete it
465                                org->setRepairRemove(gcur->pos, gcur);
466                                return 1;  // stop
467                        }
468                        // error: not a neuron (stick)
469                        if (T_NEURON4 != type) {
470                                // fix: delete it
471                                org->setRepairRemove(gcur->pos, gcur);
472                                return 1;  // stop
473                        }
474                        // error: already has control
475                        if (ctrl != 0) {
476                                // fix: delete it
477                                org->setRepairRemove(gcur->pos, gcur);
478                                return 1;  // stop
479                        }
480                        // make neuron ctrl = 1 or 2
481                        ctrl = j;
482                        gcur = gcur->child;
483                        break;
484
485                case '[':
486                        // link to neuron
487                        // error: not a neuron
488                        if (T_NEURON4 != type) {
489                                // fix: delete it
490                                org->setRepairRemove(gcur->pos, gcur);
491                                return 1;  // stop
492                        }
493                        // input ('*', 'G', 'T', 'S', or %d)
494                        t = gcur->i1;
495                        relfrom = gcur->l1;
496                        w = gcur->f1;
497                        if (t > 0) {
498                                // * or G
499                                tneu = NULL;
500                        }
501                        else {
502                                // input from other neuron
503                                // find neuron at relative i
504                                // find own index
505                                j = 0; k = 0;
506                                for (i = 0; i < org->nc; i++) {
507                                        if (org->C[i]->type == T_NEURON4) k++;
508                                        if (org->C[i] == this) { j = k - 1; break; }
509                                }
510                                // find index of incoming
511                                j = j + relfrom;
512                                if (j < 0) goto wait_link;
513                                if (j >= org->nc) goto wait_link;
514                                // find that neuron
515                                k = 0;
516                                for (i = 0; i < org->nc; i++) {
517                                        if (org->C[i]->type == T_NEURON4) k++;
518                                        if (j == (k - 1)) break;
519                                }
520                                if (i >= org->nc) goto wait_link;
521                                tneu = org->C[i];
522                        }
523                        // add link
524                        // error: could not add link (too many?)
525                        if (addlink(tneu, w, t)) {
526                                // cannot fix
527                                org->setError(gcur->pos);
528                                return 1;  // stop
529                        }
530                        gcur = gcur->child;
531                        break;
532                wait_link:
533                        // wait for other neurons to develop
534                        // if there are others still active
535                        active = 0;
536                        j = 0;
537                        for (i = 0; i<org->nc; i++) {
538                                if (org->C[i]->active) j++;
539                        }
540                        if (j>0)
541                                return 0;  // there is other active, halt, try again
542                        // no more actives, cannot add link, ignore, but treat not as an error
543                        gcur = gcur->child;
544                        break;
545
546                case ':':
547                        // neuron parameter
548                        // error: not a neuron
549                        if (T_NEURON4 != type) {
550                                // fix: delete it
551                                org->setRepairRemove(gcur->pos, gcur);
552                                return 1;  // stop
553                        }
554                        j = (int)gcur->l1;
555                        switch ((char)gcur->i1) {
556                        case '!':
557                                if (j) force += (1.0 - force) * 0.2;
558                                else   force -= force * 0.2; break;
559                        case '=':
560                                if (j) inertia += (1.0 - inertia) * 0.2;
561                                else   inertia -= inertia * 0.2; break;
562                        case '/':
563                                if (j) sigmo *= 1.4;
564                                else   sigmo /= 1.4; break;
565                        default:
566                                org->setRepairRemove(gcur->pos, gcur);
567                                return 1;  // stop
568                        }
569                        gcur = gcur->child;
570                        break;
571
572                case ' ':
573                        // space has no effect, should not occur
574                        // fix: delete it
575                        org->setRepairRemove(gcur->pos, gcur);
576                        gcur = gcur->child;
577                        break;
578
579                default:
580                        // error: unknown code
581                        char buf[40];
582                        sprintf(buf, "unknown code '%c'", gcur->name);
583                        logMessage("f4_Cell", "onestep", 2, buf);
584                        // fix: delete it
585                        org->setRepairRemove(gcur->pos, gcur);
586                        return 1; // stop
587                }
588        }
589        active = 0;  // done
590        return 0;
591}
592
593
594int f4_Cell::addlink(f4_Cell * nfrom, double nw, int nt)
595{
596        if (nolink >= MAXINPUTS - 1) return -1; // full!
597        links[nolink] = new f4_CellLink(nfrom, nw, nt);
598        nolink++;
599        return 0;
600}
601
602
603void f4_Cell::adjustRec()
604{
605        //f4_OrientMat rot;
606        int     i;
607
608        if (recProcessedFlag)
609                // already processed
610                return;
611
612        // mark it processed
613        recProcessedFlag = 1;
614
615        // make sure its parent is processed first
616        if (NULL != dadlink)
617                dadlink->adjustRec();
618
619        // count children
620        childcount = 0;
621        for (i = 0; i < org->nc; i++)
622        {
623                if (org->C[i]->dadlink == this)
624                        if (org->C[i]->type == T_STICK4)
625                                childcount++;
626        }
627
628        if (type == T_STICK4)
629        {
630                if (NULL == dadlink)
631                {
632                        //firstend = Pt3D_0;
633                        // rotation due to rolling
634                        xrot = rolling;
635                        mz = 1;
636                }
637                else {
638                        //firstend = dadlink->lastend;
639                        f4_Props Pdad = dadlink->P;
640                        f4_Props Padj = Pdad;
641                        Padj.adjust();
642
643                        //rot = Orient_1;
644
645                        // rotation due to rolling
646                        xrot = rolling +
647                                // rotation due to twist
648                                Pdad.twist;
649                        if (dadlink->commacount <= 1)
650                        {
651                                // rotation due to curvedness
652                                zrot = Padj.curv;
653                        }
654                        else {
655                                zrot = Padj.curv +
656                                        // SDK uses 3.141 instead of PI!
657                                        (anglepos * 1.0 / (dadlink->commacount + 1) - 0.5) * 3.141 * 2.0;
658                        }
659
660                        //rot = rot * f4_OrientMat(yOz, xrot);
661                        //rot = rot * f4_OrientMat(xOy, zrot);
662                        // rotation relative to parent stick
663                        //OM = rot * OM;
664
665                        // rotation in world coordinates
666                        //OM =  ((f4_OrientMat)dadlink->OM) * OM;
667                        mz = dadlink->mz / dadlink->childcount;
668                }
669                //Pt3D lastoffset = (Orient)OM * (Pt3D(1,0,0)*P.len);
670                //lastend = firstend + lastoffset;
671        }
672}
673
674
675
676f4_CellLink::f4_CellLink(f4_Cell * nfrom, double nw, int nt)
677{
678        from = nfrom;
679        w = nw;
680        t = nt;
681}
682
683
684
685f4_Cells::f4_Cells(f4_node * genome, int nrepair)
686{
687        // create ancestor cell
688        repair = nrepair;
689        error = 0;
690        errorpos = -1;
691        repair_remove = NULL;
692        repair_parent = NULL;
693        repair_insert = NULL;
694        tmpcel = NULL;
695        f4rootnode = NULL;
696
697        C[0] = new f4_Cell(this, 0, genome, genome, NULL, 0, stdProps);
698        nc = 1;
699}
700
701
702f4_Cells::f4_Cells(SString & genome, int nrepair)
703{
704        int res;
705        repair = nrepair;
706        error = 0;
707        errorpos = -1;
708        repair_remove = NULL;
709        repair_parent = NULL;
710        repair_insert = NULL;
711        tmpcel = NULL;
712        f4rootnode = NULL;
713
714        // transform geno from string to nodes
715        f4rootnode = new f4_node();
716        res = f4_processrec(genome.c_str(), (unsigned)0, f4rootnode);
717        if ((res < 0) || (1 != f4rootnode->childCount()))
718        {
719                error = GENOPER_OPFAIL;
720                errorpos = -1;
721        }
722
723        // create ancestor cell
724        C[0] = new f4_Cell(this, 0, f4rootnode->child, f4rootnode->child,
725                NULL, 0, stdProps);
726        nc = 1;
727}
728
729f4_Cells::~f4_Cells()
730{
731        // release cells
732        int i;
733        if (nc)
734        {
735                for (i = nc - 1; i >= 0; i--)
736                        delete C[i];
737                nc = 0;
738        }
739        if (f4rootnode)
740                delete f4rootnode;
741}
742
743
744int f4_Cells::onestep()
745{
746        int i, ret, oldnc, ret2;
747        oldnc = nc;
748        ret = 0;
749        for (i = 0; i<oldnc; i++) {
750                ret2 = C[i]->onestep();
751                if (ret2>0) {
752                        // error
753                        C[i]->active = 0;  // stop
754                        return 0;
755                }
756                // if still active
757                if (C[i]->active)
758                        ret = 1;
759        }
760        return ret;
761}
762
763
764int f4_Cells::simulate()
765{
766        int i;
767        error = GENOPER_OK;
768
769        for (i = 0; i < nc; i++)  C[i]->active = 1;
770
771        // execute onestep() in a cycle
772        while (onestep());
773
774        if (GENOPER_OK != error) return error;
775
776        // fix neuron attachements
777        for (i = 0; i < nc; i++)
778                if (C[i]->type == T_NEURON4) {
779                        while (T_NEURON4 == C[i]->dadlink->type) {
780                                C[i]->dadlink = C[i]->dadlink->dadlink;
781                        }
782                }
783
784        // there should be no undiff. cells
785        // make undifferentiated cells sticks
786        for (i = 0; i < nc; i++)
787                if (C[i]->type == T_UNDIFF4) {
788                        C[i]->type = T_STICK4;
789                        //seterror();
790                }
791
792        // recursive adjust
793        // reset recursive traverse flags
794        for (i = 0; i < nc; i++)
795                C[i]->recProcessedFlag = 0;
796        // process every cell
797        for (i = 0; i < nc; i++)
798                C[i]->adjustRec();
799
800        //DB( printf("Cell simulation done, %d cells. \n", nc); )
801
802        return error;
803}
804
805
806void f4_Cells::addCell(f4_Cell * newcell)
807{
808        if (nc >= MAX4CELLS - 1) {
809                delete newcell;
810                return;
811        }
812        C[nc] = newcell;
813        nc++;
814}
815
816
817void f4_Cells::setError(int nerrpos)
818{
819        error = GENOPER_OPFAIL;
820        errorpos = nerrpos;
821}
822
823void f4_Cells::setRepairRemove(int nerrpos, f4_node * rem)
824{
825        if (!repair) {
826                // not in repair mode, treat as repairable error
827                error = GENOPER_REPAIR;
828                errorpos = nerrpos;
829        }
830        else {
831                error = GENOPER_REPAIR;
832                errorpos = nerrpos;
833                repair_remove = rem;
834        }
835}
836
837int f4_Cells::setRepairInsert(int nerrpos, f4_node * parent, f4_node * insert)
838{
839        if (!repair) {
840                // not in repair mode, treat as repairable error
841                error = GENOPER_REPAIR;
842                errorpos = nerrpos;
843                return -1;
844        }
845        else {
846                error = GENOPER_REPAIR;
847                errorpos = nerrpos;
848                repair_parent = parent;
849                repair_insert = insert;
850                return 0;
851        }
852}
853
854void f4_Cells::repairGeno(f4_node * geno, int whichchild)
855{
856        // assemble repaired geno, if the case
857        if (!repair) return;
858        if ((NULL == repair_remove) && (NULL == repair_insert)) return;
859        // traverse genotype tree, remove / insert node
860        f4_node * g2;
861        if (1 == whichchild) g2 = geno->child;
862        else             g2 = geno->child2;
863        if (NULL == g2)
864                return;
865        if (g2 == repair_remove) {
866                f4_node * oldgeno;
867                geno->removeChild(g2);
868                if (g2->child) {
869                        // add g2->child as child to geno
870                        if (1 == whichchild) geno->child = g2->child;
871                        else             geno->child2 = g2->child;
872                        g2->child->parent = geno;
873                }
874                oldgeno = g2;
875                oldgeno->child = NULL;
876                delete oldgeno;
877                if (NULL == geno->child) return;
878                // check this new
879                repairGeno(geno, whichchild);
880                return;
881        }
882        if (g2 == repair_parent) {
883                geno->removeChild(g2);
884                geno->addChild(repair_insert);
885                repair_insert->parent = geno;
886                repair_insert->child = g2;
887                repair_insert->child2 = NULL;
888                g2->parent = repair_insert;
889        }
890        // recurse
891        if (g2->child)  repairGeno(g2, 1);
892        if (g2->child2) repairGeno(g2, 2);
893}
894
895
896void f4_Cells::toF1Geno(SString &out)
897{
898        if (tmpcel) delete tmpcel;
899        tmpcel = new f4_Cell(-1, NULL, 0, stdProps);
900        out = "";
901        toF1GenoRec(0, out);
902        delete tmpcel;
903}
904
905
906void f4_Cells::toF1GenoRec(int curc, SString &out)
907{
908        int i, j, ccount;
909        f4_Cell * thisti;
910        f4_Cell * thneu;
911        char buf[200];
912
913        if (curc >= nc) return;
914
915        if (T_STICK4 != C[curc]->type) return;
916
917        thisti = C[curc];
918        if (NULL != thisti->dadlink)
919                *tmpcel = *(thisti->dadlink);
920
921        // adjust length, curvedness, etc.
922        tmpcel->P.adjust();
923        while (tmpcel->P.len > thisti->P.len)
924        {
925                tmpcel->P.executeModifier('l');
926                out += "l";
927        }
928        while (tmpcel->P.len < thisti->P.len)
929        {
930                tmpcel->P.executeModifier('L');
931                out += "L";
932        }
933        while (tmpcel->P.curv > thisti->P.curv)
934        {
935                tmpcel->P.executeModifier('c');
936                out += "c";
937        }
938        while (tmpcel->P.curv < thisti->P.curv)
939        {
940                tmpcel->P.executeModifier('C');
941                out += "C";
942        }
943        while (thisti->rolling > 0.0f) {
944                rolling_dec(&(thisti->rolling));
945                out += "R";
946        }
947        while (thisti->rolling < 0.0f) {
948                rolling_inc(&(thisti->rolling));
949                out += "r";
950        }
951
952        // output X for this stick
953        out += "X";
954
955        // neurons attached to it
956        for (i = 0; i < nc; i++)
957                if (C[i]->type == T_NEURON4) {
958                        if (C[i]->dadlink == thisti) {
959                                thneu = C[i];
960                                out += "[";
961                                // ctrl
962                                if (1 == thneu->ctrl) out += "@";
963                                if (2 == thneu->ctrl) out += "|";
964                                // links
965                                for (j = 0; j < thneu->nolink; j++)
966                                {
967                                        if (j) out += ",";
968                                        if (NULL == thneu->links[j]->from)
969                                        {
970                                                // sensory
971                                                if (1 == thneu->links[j]->t) out += "*";
972                                                if (2 == thneu->links[j]->t) out += "G";
973                                                if (3 == thneu->links[j]->t) out += "T";
974                                                if (4 == thneu->links[j]->t) out += "S";
975                                        }
976                                        else {
977                                                sprintf(buf, "%d", thneu->links[j]->from->name - thneu->name);
978                                                out += buf;
979                                        }
980                                        out += ":";
981                                        // weight
982                                        sprintf(buf, "%g", thneu->links[j]->w);
983                                        out += buf;
984                                }
985                                out += "]";
986                        }
987                }
988
989        // sticks connected to it
990        if (thisti->commacount >= 2)
991                out += "(";
992
993        ccount = 1;
994        for (i = 0; i < nc; i++)
995                if (C[i]->type == T_STICK4)
996                        if (C[i]->dadlink == thisti) {
997                                while (ccount < (C[i])->anglepos) {
998                                        ccount++;
999                                        out += ",";
1000                                }
1001                                toF1GenoRec(i, out);
1002                        }
1003        while (ccount < thisti->commacount) {
1004                ccount++;
1005                out += ",";
1006        }
1007
1008        if (thisti->commacount >= 2)
1009                out += ")";
1010}
1011
1012
1013
1014// to organize a f4 genotype in a tree structure
1015
1016f4_node::f4_node()
1017{
1018        name = '?';
1019        parent = NULL;
1020        child = NULL;
1021        child2 = NULL;
1022        pos = -1;
1023}
1024
1025f4_node::f4_node(char nname, f4_node * nparent, int npos)
1026{
1027        name = nname;
1028        parent = nparent;
1029        child = NULL;
1030        child2 = NULL;
1031        pos = npos;
1032        if (parent) parent->addChild(this);
1033}
1034
1035f4_node::~f4_node()
1036{
1037        // (destroy() copied here for efficiency)
1038        // children are destroyed (recursively) through the destructor
1039        if (NULL != child2)  delete child2;
1040        if (NULL != child)   delete child;
1041}
1042
1043int f4_node::addChild(f4_node * nchi)
1044{
1045        if (NULL == child) {
1046                child = nchi;
1047                return 0;
1048        }
1049        if (NULL == child2) {
1050                child2 = nchi;
1051                return 0;
1052        }
1053        return -1;
1054}
1055
1056int f4_node::removeChild(f4_node * nchi)
1057{
1058        if (nchi == child2) {
1059                child2 = NULL;
1060                return 0;
1061        }
1062        if (nchi == child) {
1063                child = NULL;
1064                return 0;
1065        }
1066        return -1;
1067}
1068
1069int f4_node::childCount()
1070{
1071        if (NULL != child) {
1072                if (NULL != child2) return 2;
1073                else return 1;
1074        }
1075        else {
1076                if (NULL != child2) return 1;
1077                else return 0;
1078        }
1079}
1080
1081int f4_node::count()
1082{
1083        int c = 1;
1084        if (NULL != child)  c += child->count();
1085        if (NULL != child2) c += child2->count();
1086        return c;
1087}
1088
1089f4_node * f4_node::ordNode(int n)
1090{
1091        int n1;
1092        if (0 == n) return this;
1093        n--;
1094        if (NULL != child) {
1095                n1 = child->count();
1096                if (n < n1) return child->ordNode(n);
1097                n -= n1;
1098        }
1099        if (NULL != child2) {
1100                n1 = child2->count();
1101                if (n < n1) return child2->ordNode(n);
1102                n -= n1;
1103        }
1104        return NULL;
1105}
1106
1107f4_node * f4_node::randomNode()
1108{
1109        int n = count();
1110        // pick a random node, between 0 and n-1
1111        return ordNode(randomN(n));
1112}
1113
1114f4_node * f4_node::randomNodeWithSize(int min, int max)
1115{
1116        // try random nodes, and accept if size in range
1117        // limit to maxlim tries
1118        int i, n, maxlim;
1119        f4_node * nod = NULL;
1120        maxlim = count();
1121        for (i = 0; i < maxlim; i++) {
1122                nod = randomNode();
1123                n = nod->count();
1124                if ((n >= min) && (n <= max)) return nod;
1125        }
1126        // failed, doesn't matter
1127        return nod;
1128}
1129
1130void f4_node::sprint(SString & out)
1131{
1132        char buf2[20];
1133        // special case: repetition code
1134        if ('#' == name)
1135        {
1136                out += "#";
1137                if (i1 != 1) {
1138                        sprintf(buf2, "%d", i1);
1139                        out += buf2;
1140                }
1141        }
1142        else {
1143                // special case: neuron link
1144                if ('[' == name) {
1145                        out += "[";
1146                        if (i1 > 0) {
1147                                // sensor input
1148                                if (1 == i1) out += "*";
1149                                if (2 == i1) out += "G";
1150                                if (3 == i1) out += "T";
1151                                if (4 == i1) out += "S";
1152                        }
1153                        else {
1154                                sprintf(buf2, "%ld", l1);
1155                                out += buf2;
1156                        }
1157                        sprintf(buf2, ":%g]", f1);
1158                        out += buf2;
1159                }
1160                else if (':' == name) {
1161                        sprintf(buf2, ":%c%c:", l1 ? '+' : '-', (char)i1);
1162                        out += buf2;
1163                }
1164                else {
1165                        buf2[0] = name;
1166                        buf2[1] = 0;
1167                        out += buf2;
1168                }
1169        }
1170        if (NULL != child)     child->sprint(out);
1171        // if two children, make sure last char is a '>'
1172        if (2 == childCount())
1173                if (0 == out[0]) out += ">"; else
1174                        if ('>' != out[out.len() - 1]) out += ">";
1175        if (NULL != child2)    child2->sprint(out);
1176        // make sure last char is a '>'
1177        if (0 == out[0]) out += ">"; else
1178                if ('>' != out[out.len() - 1]) out += ">";
1179}
1180
1181void f4_node::sprintAdj(char *& buf)
1182{
1183        unsigned int len;
1184        // build in a SString, with initial size
1185        SString out(strlen(buf) + 2000);
1186        out = "";
1187
1188        sprint(out);
1189
1190        // very last '>' can be omitted
1191        len = out.len();
1192        if (len > 1)
1193                if ('>' == out[len - 1]) { (out.directWrite())[len - 1] = 0; out.endWrite(); };
1194        // copy back to string
1195        // if new is longer, reallocate buf
1196        if (len + 1 > strlen(buf)) {
1197                buf = (char*)realloc(buf, len + 1);
1198        }
1199        strcpy(buf, out.c_str());
1200}
1201
1202f4_node * f4_node::duplicate()
1203{
1204        f4_node * copy;
1205        copy = new f4_node(*this);
1206        copy->parent = NULL;  // set later
1207        copy->child = NULL;
1208        copy->child2 = NULL;
1209        if (NULL != child) {
1210                copy->child = child->duplicate();
1211                copy->child->parent = copy;
1212        }
1213        if (NULL != child2) {
1214                copy->child2 = child2->duplicate();
1215                copy->child2->parent = copy;
1216        }
1217        return copy;
1218}
1219
1220
1221void f4_node::destroy()
1222{
1223        // children are destroyed (recursively) through the destructor
1224        if (NULL != child2)  delete child2;
1225        if (NULL != child)   delete child;
1226}
1227
1228
1229// scan genotype string and build tree
1230// return >1 for error (errorpos)
1231int f4_processrec(const char * genot, unsigned pos0, f4_node * parent)
1232{
1233        int i, j, t, res;
1234        char tc1, tc2;
1235        int relfrom;
1236        double w;
1237        unsigned gpos, oldpos;
1238        f4_node * node1, *par;
1239
1240        gpos = pos0;
1241        par = parent;
1242        if (gpos >= strlen(genot)) return 1;
1243        while (gpos < strlen(genot)) {
1244                //DB( printf(" processing '%c' %d %s\n", genot[gpos], gpos, genot); )
1245                switch (genot[gpos]) {
1246                case '<':
1247                        // cell division!
1248                        //DB( printf("  div! %d\n", name); )
1249
1250                        // find out genotype start for child
1251                        j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), '>');
1252
1253                        node1 = new f4_node('<', par, gpos);
1254                        par = node1;
1255                        res = f4_processrec(genot, gpos + 1, par);
1256                        if (res) return res;
1257                        if (gpos + j + 2 < strlen(genot)) {
1258                                res = f4_processrec(genot, gpos + j + 2, par);
1259                                if (res) return res;
1260                        }
1261                        else {  // ran out
1262                                node1 = new f4_node('>', par, strlen(genot) - 1);
1263                                par = node1;
1264                        }
1265                        // adjustments
1266                        gpos++;
1267                        return 0;  // OK
1268
1269                case '>':
1270                        node1 = new f4_node('>', par, gpos);
1271                        par = node1;
1272                        gpos = strlen(genot);
1273                        return 0;  // OK
1274
1275                case '#':
1276                        // repetition marker, 1 by default
1277                        if (sscanf(genot + gpos, "#%d", &i) != 1) i = 1;
1278                        // find out genotype start for continuation
1279                        j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), '>');
1280                        // skip number
1281                        oldpos = gpos;
1282                        gpos++;
1283                        while ((genot[gpos] >= '0') && (genot[gpos] <= '9')) gpos++;
1284                        node1 = new f4_node('#', par, oldpos);
1285                        node1->i1 = i;
1286                        par = node1;
1287                        res = f4_processrec(genot, gpos, node1);
1288                        if (res) return res;
1289                        if (oldpos + j + 2 < strlen(genot)) {
1290                                res = f4_processrec(genot, oldpos + j + 2, node1);
1291                                if (res) return res;
1292                        }
1293                        else {  // ran out
1294                                node1 = new f4_node('>', par, strlen(genot) - 1);
1295                        }
1296                        return 0;  // OK
1297
1298                        // 'simple' nodes:
1299                case ',':
1300                case 'l':  case 'L':
1301                case 'c':  case 'C':
1302                case 'q':  case 'Q':
1303                case 'r':  case 'R':
1304                case 'X':  case 'N':
1305                case '@':  case '|':
1306                case 'a':  case 'A':
1307                case 's':  case 'S':
1308                case 'm':  case 'M':
1309                case 'i':  case 'I':
1310                case 'f':  case 'F':
1311                case 'w':  case 'W':
1312                case 'e':  case 'E':
1313                        node1 = new f4_node(genot[gpos], par, gpos);
1314                        par = node1;
1315                        gpos++;
1316                        break;
1317
1318                case '[':
1319                        // link to neuron
1320                        // input (%d, '*', 'G', 'T', 'S')
1321                        t = -1;
1322                        if (sscanf(genot + gpos, "[%ld:%lf]", &relfrom, &w) == 2) t = 0;
1323                        else if (sscanf(genot + gpos, "[*:%lf]", &w) == 1) t = 1;
1324                        else if (sscanf(genot + gpos, "[G:%lf]", &w) == 1) t = 2;
1325                        else if (sscanf(genot + gpos, "[T:%lf]", &w) == 1) t = 3;
1326                        else if (sscanf(genot + gpos, "[S:%lf]", &w) == 1) t = 4;
1327                        // error: no correct format
1328                        if (t < 0) return gpos + 1 + 1;
1329                        node1 = new f4_node('[', par, gpos);
1330                        node1->i1 = t;
1331                        node1->l1 = relfrom;
1332                        node1->f1 = w;
1333                        par = node1;
1334                        j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ']');
1335                        gpos += j + 2;
1336                        break;
1337
1338                case ':':
1339                        // neuron parameter  +! -! += -= +/ or -/
1340                        if (sscanf(genot + gpos, ":%c%c:", &tc1, &tc2) != 2)
1341                                // error: incorrect format
1342                                return gpos + 1 + 1;
1343                        if ('+' == tc1) j = 1;
1344                        else if ('-' == tc1) j = 0;
1345                        else return gpos + 1 + 1;
1346                        switch (tc2) {
1347                        case '!':  case '=':  case '/':  break;
1348                        default:
1349                                return gpos + 1 + 1;
1350                        }
1351                        node1 = new f4_node(':', par, gpos);
1352                        node1->l1 = j;
1353                        node1->i1 = (int)tc2;
1354                        par = node1;
1355                        j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ':');
1356                        gpos += j + 2;
1357                        break;
1358
1359                case ' ':
1360                case '\n':
1361                case '\t':
1362                        // whitespace: ignore
1363                        //node1 = new f4_node(' ', par, gpos );
1364                        //par = node1;
1365                        gpos++;
1366                        break;
1367
1368                default:
1369                        //DB( printf("unknown character '%c' ! \n", genot[gpos]); )
1370                        //add it, build will give the error or repair
1371                        node1 = new f4_node(genot[gpos], par, gpos);
1372                        par = node1;
1373                        gpos++;
1374                        break;
1375                }
1376        }
1377        // should end with a '>'
1378        if (par)
1379                if ('>' != par->name) {
1380                        node1 = new f4_node('>', par, strlen(genot) - 1);
1381                        par = node1;
1382                }
1383        return 0;  // OK
1384}
1385
1386
1387f4_node * f4_processtree(const char * geno)
1388{
1389        f4_node * root;
1390        int res;
1391        root = new f4_node();
1392        res = f4_processrec(geno, 0, root);
1393        if (res) return NULL;
1394        //DB( printf("test f4  "); )
1395        DB(
1396                if (root->child) {
1397                        char * buf = (char*)malloc(300);
1398                        DB(printf("(%d) ", root->child->count());)
1399                                buf[0] = 0;
1400                        root->child->sprintAdj(buf);
1401                        DB(printf("%s\n", buf);)
1402                                free(buf);
1403                }
1404        )
1405                return root->child;
1406}
Note: See TracBrowser for help on using the repository browser.