source: cpp/f4/f4_general.cpp @ 97

Last change on this file since 97 was 4, checked in by Maciej Komosinski, 16 years ago

added f4, a genetic representation that describes development of an organism

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