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

Last change on this file since 770 was 770, checked in by Maciej Komosinski, 2 years ago

Avoided "min" and "max" as variable names, fixes issue 22 [refs #62]

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