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

Last change on this file since 779 was 779, checked in by Maciej Komosinski, 11 months ago

Unified file names of all files involved in genetic conversions and operations so that they start with "f<format>_"

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