source: cpp/frams/genetics/f1/conv_f1.cpp @ 372

Last change on this file since 372 was 372, checked in by sz, 9 years ago

Renamed some classes and functions to make their purpose more obvious:

All MessageHandlers? must now be given the explicit "Enable" argument if you want them to automatically become active. This makes side effects clearly visible.

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