source: cpp/gdk/conv_f1.cpp @ 97

Last change on this file since 97 was 95, checked in by sz, 11 years ago

muscles encoded in a "new" way in f1 genotypes now behave as in "old" f1 (default values of their "power" and "range" properties depend on f1 modifiers)

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