source: cpp/gdk/conv_f1.cpp @ 5

Last change on this file since 5 was 5, checked in by sz, 15 years ago

added the GDK (Genotype Development Kit)

File size: 12.1 KB
Line 
1// This file is a part of Framsticks GDK library.
2// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.frams.alife.pl/ for further information.
4
5#include "conv_f1.h"
6#include "nonstd.h"
7#include "framsg.h"
8#include "multirange.h"
9#include "multimap.h"
10#include <ctype.h>
11
12//#define v1f1COMPATIBLE
13
14F1Props stdprops={1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1 };
15
16class Builder
17{
18public:
19Builder(const char*g,int mapping=0):genbegin(g),usemapping(mapping),energ(0),energ_div(0),invalid(0) {}
20char tmp[222];
21bool invalid;
22Model model;
23const char *genbegin;
24SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
25Neuro *last_f1_neuro;
26        struct Connection { int n1,n2; double w;
27                Connection(int _n1,int _n2, double _w):n1(_n1),n2(_n2),w(_w) {} };
28SListTempl<Connection> connections;
29int usemapping;
30MultiRange range;
31double lastjoint_muscle_power;
32double energ,energ_div;
33void grow(int part1,const char*g,Pt3D k,F1Props c);
34int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
35int growPart(F1Props &c,const char *g);
36const char *skipNeuro(const char *z);
37const char* growNeuro(const char* t,F1Props &c,int&);
38void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
39int countBranches(const char*g,SList &out);
40void addClassParam(const SString& newparam);
41void addClassParam(const char* name,double value);
42
43const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
44const MultiRange* makeRange(const char*g,const char*g2);
45Part *getLastPart() {return getLastJoint()->part2;}
46Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
47Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
48void addOrRememberInput(int n1,int n2,float w)
49                {
50                if (!addInput(n1,n2,w,false))
51                        connections+=Connection(n1,n2,w);
52                }
53bool addInput(int n1,int n2,float w,bool final)
54                {
55                if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
56                        {
57                        if (final) FMprintf("GenoConvF1","addInput",FMLV_WARN,
58                                            "illegal neuron connection %d <- %d (ignored)",n1,n2);
59                        return 0;
60                        }
61                Neuro *neuro=(Neuro*)neuro_f1_to_f0(n1);
62                Neuro *input=(Neuro*)neuro_f1_to_f0(n2);
63                neuro->addInput(input,w);
64                return 1;
65                }
66void addPendingInputs()
67                {
68                for(int i=0;i<connections.size();i++)
69                        {
70                        Connection *c=&connections(i);
71                        addInput(c->n1,c->n2,c->w,true);
72                        }
73                }
74};
75
76const MultiRange* Builder::makeRange(const char*g,const char*g2)
77{
78if (!usemapping) return 0;
79range.clear();
80range.add(g-genbegin,g2-genbegin);
81return &range;
82}
83
84void F1Props::wykluczanie()
85{
86double s=ruch+asym+odpor+wchl;
87ruch=ruch/s;
88asym=asym/s;
89odpor=odpor/s;
90wchl=wchl/s;
91}
92
93/** main conversion function - with conversion map support */
94SString GenoConv_F1::convert(SString &i,MultiMap *map)
95{
96const char* g=(const char*)i;
97Builder builder(g,map?1:0);
98builder.model.open();
99builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
100if (builder.invalid) return SString();
101builder.addPendingInputs();
102builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
103builder.model.close(); // model is ready to use now
104if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
105return builder.model.getF0Geno().getGene();
106}
107
108void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
109{
110int hasmuscles=0;
111k+=Pt3D(c.rot,0,c.skr);
112while(1)
113{
114switch(*g)
115        {
116        case 0: case ',': case ')': return;
117        case 'R': k.x+=0.7853;  break;
118        case 'r': k.x-=0.7853;  break;
119        case 'Q': c.rot+=(1.58-c.rot)*0.3;      break;
120        case 'q': c.rot+=(-1.58-c.rot)*0.3;     break;
121#ifdef v1f1COMPATIBLE
122        case 'L': c.dlug+=(3.0-c.dlug)*0.3; break;
123#else
124        case 'L': c.dlug+=(2.0-c.dlug)*0.3; break;
125#endif                                       
126        case 'l': c.dlug+=(0.33-c.dlug)*0.3; break;
127        case 'A': c.asym+=(1-c.asym)*0.8;       c.wykluczanie(); break;
128        case 'a': c.asym-=c.asym*0.4;   c.wykluczanie(); break;
129        case 'I': c.wchl+=(1-c.wchl)*0.8;       c.wykluczanie(); break;
130        case 'i': c.wchl-=c.wchl*0.4;   c.wykluczanie(); break;
131        case 'S': c.odpor+=(1-c.odpor)*0.8; c.wykluczanie(); break;
132        case 's': c.odpor-=c.odpor*0.4; c.wykluczanie(); break;
133        case 'M': c.ruch+=(1-c.ruch)*0.8;       c.wykluczanie(); break;
134        case 'm': c.ruch-=c.ruch*0.4;   c.wykluczanie(); break;
135        case 'C': c.skr+=(2.0-c.skr)*0.25;      break;
136        case 'c': c.skr+=(-2.0-c.skr)*0.25;break;
137        case 'F': c.tarcie+=(4-c.tarcie)*0.2;   break;
138        case 'f': c.tarcie-=c.tarcie*0.2;               break;
139        case 'W': c.masa+=(2.0-c.masa)*0.3;     break;
140        case 'w': c.masa+=(0.5-c.masa)*0.3;     break;
141        case 'E': c.energ+=(10.0-c.energ)*0.1;  break;
142        case 'e': c.energ-=c.energ*0.1;         break;
143        case '[': //neuron
144//              setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
145                if (model.getJointCount())
146                        g=growNeuro(g+1,c,hasmuscles);
147                else
148                        {
149                        FramMessage("GenoConv_F1","grow","Illegal neuron position (ignored)",1);
150                        g=skipNeuro(g+1);
151                        }
152                break;
153        case 'X':
154                {
155                int freshpart=0;
156//setdebug(g-(char*)geny,DEBUGEST | !l_est);
157                if (part1<0) //initial grow
158                        {
159                  if (model.getPartCount()>0)
160                            part1=0;
161                    else
162                            {
163                            part1=growPart(c,g);
164                            freshpart=1;
165                            }
166                  }
167                if (!freshpart)
168                        {
169                        Part *part=model.getPart(part1);
170                        part->density=((part->mass*part->density)+1.0/c.masa)/(part->mass+1.0); // v=m*d
171//                      part->volume+=1.0/c.masa;
172                        part->mass+=1.0;
173                        }
174                energ+=0.9*c.energ+0.1;
175                energ_div+=1.0;
176
177                int part2 = growPart(c,g);
178                growJoint(part1,part2,k,c,g);
179//              est* e = new est(*s,*s2,k,c,zz,this);
180
181                // oslabianie cech wzdluz struktury
182                c.dlug=0.5*c.dlug+0.5*stdprops.dlug;
183                c.skr=0.66*c.skr;
184                c.rot=0.66*c.rot;
185                c.tarcie=0.8*c.tarcie+0.2*stdprops.tarcie;
186
187                c.asym=0.8*c.asym+0.2*stdprops.asym;
188                c.odpor=0.8*c.odpor+0.2*stdprops.odpor;
189                c.ruch=0.8*c.ruch+0.2*stdprops.ruch;
190                c.wchl=0.8*c.wchl+0.2*stdprops.wchl;
191                c.masa+=(stdprops.masa-c.masa)*0.5;
192                c.wykluczanie();
193       
194                if (c.resetrange) c.bendrange=1.0; else c.resetrange=1;
195                grow(part2,g+1,Pt3D_0,c);
196                return;
197                }
198        case '(':
199                {
200                SList ga;
201                int i,ile;
202                ile=countBranches(g+1,ga);
203                c.resetrange=0;
204                c.bendrange=1.0/ile;
205                for (i=0;i<ile;i++)
206                        grow(part1,(char*)ga(i),k+Pt3D(0,0,-3.141+(i+1)*(6.282/(ile+1))),c);
207                return;
208                }
209        case ' ': case '\t': case '\n': case '\r': break;
210        default: invalid=1; return;
211        }
212        g++;
213        }
214}
215
216void Builder::addClassParam(const SString& newparam)
217{
218SString allparams=last_f1_neuro->getClassParams();
219if (allparams.len()) allparams+=',';
220allparams+=newparam;
221last_f1_neuro->setClassParams(allparams);
222}
223void Builder::addClassParam(const char* name,double value)
224{
225SString t;
226sprintf(t.directWrite(30),"%s=%g",name,value);
227t.endWrite();
228addClassParam(t);
229}
230
231
232int Builder::countBranches(const char*g,SList &out)
233{
234int gl=0;
235out+=(void*)g;
236while (gl>=0)
237        {
238        switch(*g)
239                {
240                case 0: gl=-1; break;
241                case '(': case '[': ++gl; break;
242                case ')': case ']': --gl; break;
243                case ',': if (!gl) out+=(void*)(g+1);
244                }
245        g++;
246        }
247return !out;
248}
249
250int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
251{
252double len=min(2.0,c.dlug);
253sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg",
254        part1,part2,len,angle.x,angle.y,angle.z,c.odpor);
255lastjoint_muscle_power=c.ruch;
256return model.singleStepBuild(tmp,makeRange(g));
257}
258
259int Builder::growPart(F1Props &c,const char *g)
260{
261sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg",
262        1.0/c.masa,c.tarcie,c.wchl,c.asym);
263return model.singleStepBuild(tmp,makeRange(g));
264}
265
266const char *Builder::skipNeuro(const char *z)
267{
268for (;*z;z++) if ((*z==']')||(*z==')')) break;
269return z-1;
270}
271
272// remove leading & trailing whitespaces
273static void trim(SString& s)
274{
275const char*b=(const char*)s;
276const char*e=b+s.len();
277while((b<e)&&(*b<=' ')) b++;
278while((b<e)&&(e[-1]<=' ')) e--;
279if ((e-b)==s.len()) return;
280char* t=s.directWrite();
281if (t!=b) memmove(t,b,e-b);
282s.endWrite(e-b);
283}
284
285const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
286{
287const char*neuroend=skipNeuro(t);
288last_f1_neuro=model.addNewNeuro();
289last_f1_neuro->attachToPart(getLastPart());
290const MultiRange *mr=makeRange(t-1,neuroend+1);
291if (mr) last_f1_neuro->setMapping(*mr);
292neuro_f1_to_f0+=last_f1_neuro;
293
294SString clsname;
295bool haveclass=0;
296while(*t && *t<=' ') t++;
297const char* next=(*t)?(t+1):t;
298while(*next && *next<=' ') next++;
299if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
300switch(*t)
301        {
302        case '@': if (t[1]==':') break;
303                haveclass=1;
304//              if (!(hasmuscles&1))
305                {
306                  hasmuscles|=1;
307                  Neuro *muscle=model.addNewNeuro();
308                  sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
309                  muscle->addInput(last_f1_neuro);
310                  muscle->setDetails(tmp);
311                  muscle->attachToJoint(getLastJoint());
312                  if (usemapping) muscle->setMapping(*makeRange(t));
313                }
314                t++;
315                break;
316        case '|': if (t[1]==':') break;
317                haveclass=1;
318//              if (!(hasmuscles&2))
319                {
320                  hasmuscles|=2;
321                  Neuro *muscle=model.addNewNeuro();
322                  sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
323                  muscle->addInput(last_f1_neuro);
324                  muscle->setDetails(tmp);
325                  muscle->attachToJoint(getLastJoint());
326                  if (usemapping) muscle->setMapping(*makeRange(t));
327                }
328                t++;
329                break;
330        }
331while(*t && *t<=' ') t++;
332bool finished=0;
333const char *begin=t;
334const char* colon=0;
335SString classparams;
336while(!finished)
337        {
338        switch (*t)
339                {
340                case ':': colon=t; break;
341                case 0: case ']': case ')': finished=1;
342                        // NO break!
343                case ',':
344                        if ( !haveclass && !colon && t>begin )
345                                {
346                                haveclass=1;
347                                SString clsname(begin,t-begin);
348                                trim(clsname);
349                                last_f1_neuro->setClassName(clsname);
350                                NeuroClass *cls=last_f1_neuro->getClass();
351                                if (cls)
352                                        {
353                                        if (cls->getPreferredLocation()==2)
354                                                last_f1_neuro->attachToJoint(getLastJoint());
355                                        else if (cls->getPreferredLocation()==1)
356                                                last_f1_neuro->attachToPart(getLastPart());
357                                        }
358                                }
359                        else if (colon && (colon>begin) && (t>colon))
360                                growConnection(begin,colon,t,props);
361                        if (t[0]!=',') t--;
362                        begin=t+1; colon=0;
363                        break;
364                }
365        t++;
366        }
367return t;
368}
369void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
370{
371while(*begin && *begin<=' ') begin++;
372int i;
373if (isdigit(begin[0]) || (begin[0]=='-'))
374        {
375        float weight=atof(colon+1);
376        int relative=atoi(begin);
377        int this_refno=neuro_f1_to_f0.size()-1;
378        addOrRememberInput(this_refno,this_refno+relative,weight);
379        }
380else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
381        {
382        last_f1_neuro->extraProperties().set(i,colon+1);
383        }
384else if (isupper(begin[0]) || strchr("*|@",begin[0]))
385        {
386        SString clsname(begin,colon-begin);
387        trim(clsname);
388        Neuro *receptor=model.addNewNeuro();
389        receptor->setClassName(clsname);
390        NeuroClass *cls=receptor->getClass();
391        if (cls)
392                {
393                if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
394                else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
395                }
396        last_f1_neuro->addInput(receptor,atof(colon+1));
397        if (usemapping) receptor->setMapping(*makeRange(begin,end-1));
398        }
399else if ((begin[0]=='>')&&(begin[1]))
400        {
401        Neuro *out=model.addNewNeuro();
402        out->addInput(last_f1_neuro,atof(colon+1));
403        out->setClassName(SString(begin+1,end-colon-1));
404        if (begin[1]=='@')
405                {
406                sprintf(tmp,"p=%lg",lastjoint_muscle_power);
407                out->setClassParams(tmp);
408                }
409        else if (begin[1]=='|')
410                {
411                sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
412                out->setClassParams(tmp);
413                }
414        NeuroClass *cls=out->getClass();
415        if (cls)
416                {
417                if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
418                else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
419                }
420        if (usemapping) out->setMapping(*makeRange(begin,end-1));
421        }
422else if (*begin=='!') addClassParam("fo",max(0.0,min(1.0,atof(colon+1))));
423else if (*begin=='=') addClassParam("in",max(0.0,min(1.0,atof(colon+1))));
424else if (*begin=='/') addClassParam("si",atof(colon+1));
425/*else if (*begin=='!') last_f1_neuro->force=max(0.0,min(1.0,atof(colon+1)));
426else if (*begin=='=') last_f1_neuro->inertia=max(0.0,min(1.0,atof(colon+1)));
427else if (*begin=='/') last_f1_neuro->sigmo=atof(colon+1);
428*/
429else if (islower(begin[0]))
430        {
431        SString newparam(begin,end-begin);
432        trim(newparam);
433        newparam.directWrite()[colon-begin]='='; // ':' -> '='
434        addClassParam(newparam);
435        }
436}
Note: See TracBrowser for help on using the repository browser.