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

Last change on this file since 674 was 671, checked in by Maciej Komosinski, 7 years ago

Unified property names of f1 and f4; improved docs; 3.141 -> M_PI

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