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

Last change on this file since 197 was 197, checked in by Maciej Komosinski, 11 years ago

GDK used by developers since 1999, distributed on the web since 2002

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