source: cpp/gdk/conv_f1.cpp @ 104

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

introducing object de/serialization - see serialtest.cpp
the core GDK classes can be now used in multiple threads (ifdef MULTITHREADED)

  • 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        {
264        ExtValue e(value);
265        const ExtValue &re(e);
266        neuro_cls_param->setById(name,re);
267        }
268}
269
270int Builder::countBranches(const char*g,SList &out)
271{
272int gl=0;
273out+=(void*)g;
274while (gl>=0)
275        {
276        switch(*g)
277                {
278                case 0: gl=-1; break;
279                case '(': case '[': ++gl; break;
280                case ')': case ']': --gl; break;
281                case ',': if (!gl) out+=(void*)(g+1);
282                }
283        g++;
284        }
285return !out;
286}
287
288int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
289{
290double len=min(2.0,c.dlug);
291sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg,vr=%g,vg=%g,vb=%g",
292        part1,part2,len,angle.x,angle.y,angle.z,c.odpor, c.cred,c.cgreen,c.cblue);
293lastjoint_muscle_power=c.ruch;
294return model.singleStepBuild(tmp,makeRange(g));
295}
296
297int Builder::growPart(F1Props &c,const char *g)
298{
299sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
300        1.0/c.masa,c.tarcie,c.wchl,c.asym, c.grub, c.cred,c.cgreen,c.cblue);
301return model.singleStepBuild(tmp,makeRange(g));
302}
303
304const char *Builder::skipNeuro(const char *z)
305{
306for (;*z;z++) if ((*z==']')||(*z==')')) break;
307return z-1;
308}
309
310const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
311{
312const char*neuroend=skipNeuro(t);
313last_f1_neuro=model.addNewNeuro();
314neuro_cls_param=NULL;
315last_f1_neuro->attachToPart(getLastPart());
316const MultiRange *mr=makeRange(t-1,neuroend+1);
317if (mr) last_f1_neuro->setMapping(*mr);
318neuro_f1_to_f0+=last_f1_neuro;
319
320SString clsname;
321bool haveclass=0;
322while(*t && *t<=' ') t++;
323const char* next=(*t)?(t+1):t;
324while(*next && *next<=' ') next++;
325if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
326switch(*t)
327        {
328        case '@': if (t[1]==':') break;
329                haveclass=1;
330//              if (!(hasmuscles&1))
331                {
332                  hasmuscles|=1;
333                  Neuro *muscle=model.addNewNeuro();
334                  sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
335                  muscle->addInput(last_f1_neuro);
336                  muscle->setDetails(tmp);
337                  muscle->attachToJoint(getLastJoint());
338                  if (usemapping) muscle->setMapping(*makeRange(t));
339                }
340                t++;
341                break;
342        case '|': if (t[1]==':') break;
343                haveclass=1;
344//              if (!(hasmuscles&2))
345                {
346                  hasmuscles|=2;
347                  Neuro *muscle=model.addNewNeuro();
348                  sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
349                  muscle->addInput(last_f1_neuro);
350                  muscle->setDetails(tmp);
351                  muscle->attachToJoint(getLastJoint());
352                  if (usemapping) muscle->setMapping(*makeRange(t));
353                }
354                t++;
355                break;
356        }
357while(*t && *t<=' ') t++;
358bool finished=0;
359const char *begin=t;
360const char* colon=0;
361SString classparams;
362while(!finished)
363        {
364        switch (*t)
365                {
366                case ':': colon=t; break;
367                case 0: case ']': case ')': finished=1;
368                        // NO break!
369                case ',':
370                        if ( !haveclass && !colon && t>begin )
371                                {
372                                haveclass=1;
373                                SString clsname(begin,t-begin);
374                                clsname=trim(clsname);
375                                last_f1_neuro->setClassName(clsname);
376                                NeuroClass *cls=last_f1_neuro->getClass();
377                                if (cls)
378                                        {
379                                        if (cls->getPreferredLocation()==2)
380                                                last_f1_neuro->attachToJoint(getLastJoint());
381                                        else if (cls->getPreferredLocation()==1)
382                                                last_f1_neuro->attachToPart(getLastPart());
383
384                                        lastNeuroClassParam();
385                                        //special handling: muscle properties (can be overwritten by subsequent property assignments)
386                                        if (!strcmp(cls->getName(),"|"))
387                                                {
388                                                neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
389                                                neuro_cls_param->setDoubleById("r",props.bendrange);
390                                                }
391                                        else if (!strcmp(cls->getName(),"@"))
392                                                {
393                                                neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
394                                                }
395                                        }
396                                }
397                        else if (colon && (colon>begin) && (t>colon))
398                                growConnection(begin,colon,t,props);
399                        if (t[0]!=',') t--;
400                        begin=t+1; colon=0;
401                        break;
402                }
403        t++;
404        }
405SAFEDELETE(neuro_cls_param);
406return t;
407}
408void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
409{
410while(*begin && *begin<=' ') begin++;
411int i;
412if (isdigit(begin[0]) || (begin[0]=='-'))
413        {
414        float weight=atof(colon+1);
415        int relative=atoi(begin);
416        int this_refno=neuro_f1_to_f0.size()-1;
417        addOrRememberInput(this_refno,this_refno+relative,weight);
418        }
419else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
420        {
421        last_f1_neuro->extraProperties().set(i,colon+1);
422        }
423else if (isupper(begin[0]) || strchr("*|@",begin[0]))
424        {
425        SString clsname(begin,colon-begin);
426        trim(clsname);
427        Neuro *receptor=model.addNewNeuro();
428        receptor->setClassName(clsname);
429        NeuroClass *cls=receptor->getClass();
430        if (cls)
431                {
432                if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
433                else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
434                }
435        last_f1_neuro->addInput(receptor,atof(colon+1));
436        if (usemapping) receptor->setMapping(*makeRange(begin,end-1));
437        }
438else if ((begin[0]=='>')&&(begin[1]))
439        {
440        Neuro *out=model.addNewNeuro();
441        out->addInput(last_f1_neuro,atof(colon+1));
442        out->setClassName(SString(begin+1,end-colon-1));
443        if (begin[1]=='@')
444                {
445                sprintf(tmp,"p=%lg",lastjoint_muscle_power);
446                out->setClassParams(tmp);
447                }
448        else if (begin[1]=='|')
449                {
450                sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
451                out->setClassParams(tmp);
452                }
453        NeuroClass *cls=out->getClass();
454        if (cls)
455                {
456                if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
457                else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
458                }
459        if (usemapping) out->setMapping(*makeRange(begin,end-1));
460        }
461else if (*begin=='!') addClassParam("fo",atof(colon+1));
462else if (*begin=='=') addClassParam("in",atof(colon+1));
463else if (*begin=='/') addClassParam("si",atof(colon+1));
464else if (islower(begin[0]))
465        {
466        SString name(begin,colon-begin);
467        SString value(colon+1,end-(colon+1));
468        addClassParam(name,value);
469        }
470}
Note: See TracBrowser for help on using the repository browser.