1 | // This file is a part of the Framsticks GDK library.
|
---|
2 | // Copyright (C) 2002-2011 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.h"
|
---|
7 | #include "framsg.h"
|
---|
8 | #include "multirange.h"
|
---|
9 | #include "multimap.h"
|
---|
10 | #include <ctype.h>
|
---|
11 |
|
---|
12 | //#define v1f1COMPATIBLE
|
---|
13 |
|
---|
14 | F1Props stdprops={1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1 };
|
---|
15 |
|
---|
16 | class Builder
|
---|
17 | {
|
---|
18 | public:
|
---|
19 | Builder(const char*g,int mapping=0):genbegin(g),usemapping(mapping),energ(0),energ_div(0),invalid(0) {}
|
---|
20 | char tmp[222];
|
---|
21 | bool invalid;
|
---|
22 | Model model;
|
---|
23 | const char *genbegin;
|
---|
24 | SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
|
---|
25 | Neuro *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) {} };
|
---|
28 | SListTempl<Connection> connections;
|
---|
29 | int usemapping;
|
---|
30 | MultiRange range;
|
---|
31 | double lastjoint_muscle_power;
|
---|
32 | double energ,energ_div;
|
---|
33 | void grow(int part1,const char*g,Pt3D k,F1Props c);
|
---|
34 | int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
|
---|
35 | int growPart(F1Props &c,const char *g);
|
---|
36 | const char *skipNeuro(const char *z);
|
---|
37 | const char* growNeuro(const char* t,F1Props &c,int&);
|
---|
38 | void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
|
---|
39 | int countBranches(const char*g,SList &out);
|
---|
40 | void addClassParam(const SString& newparam);
|
---|
41 | void addClassParam(const char* name,double value);
|
---|
42 |
|
---|
43 | const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
|
---|
44 | const MultiRange* makeRange(const char*g,const char*g2);
|
---|
45 | Part *getLastPart() {return getLastJoint()->part2;}
|
---|
46 | Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
|
---|
47 | Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
|
---|
48 | void addOrRememberInput(int n1,int n2,float w)
|
---|
49 | {
|
---|
50 | //if (!addInput(n1,n2,w,false))
|
---|
51 | connections+=Connection(n1,n2,w);
|
---|
52 | }
|
---|
53 | bool 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 | }
|
---|
66 | void 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 |
|
---|
76 | const MultiRange* Builder::makeRange(const char*g,const char*g2)
|
---|
77 | {
|
---|
78 | if (!usemapping) return 0;
|
---|
79 | range.clear();
|
---|
80 | range.add(g-genbegin,g2-genbegin);
|
---|
81 | return ⦥
|
---|
82 | }
|
---|
83 |
|
---|
84 | void F1Props::wykluczanie()
|
---|
85 | {
|
---|
86 | double s=ruch+asym+odpor+wchl;
|
---|
87 | ruch=ruch/s;
|
---|
88 | asym=asym/s;
|
---|
89 | odpor=odpor/s;
|
---|
90 | wchl=wchl/s;
|
---|
91 | }
|
---|
92 |
|
---|
93 | /** main conversion function - with conversion map support */
|
---|
94 | SString GenoConv_F1::convert(SString &i,MultiMap *map)
|
---|
95 | {
|
---|
96 | const char* g=(const char*)i;
|
---|
97 | Builder builder(g,map?1:0);
|
---|
98 | builder.model.open();
|
---|
99 | builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
|
---|
100 | if (builder.invalid) return SString();
|
---|
101 | builder.addPendingInputs();
|
---|
102 | builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
|
---|
103 | builder.model.close(); // model is ready to use now
|
---|
104 | if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
|
---|
105 | return builder.model.getF0Geno().getGene();
|
---|
106 | }
|
---|
107 |
|
---|
108 | void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
|
---|
109 | {
|
---|
110 | int hasmuscles=0;
|
---|
111 | k+=Pt3D(c.rot,0,c.skr);
|
---|
112 | while(1)
|
---|
113 | {
|
---|
114 | switch(*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 |
|
---|
216 | void Builder::addClassParam(const SString& newparam)
|
---|
217 | {
|
---|
218 | SString allparams=last_f1_neuro->getClassParams();
|
---|
219 | if (allparams.len()) allparams+=',';
|
---|
220 | allparams+=newparam;
|
---|
221 | last_f1_neuro->setClassParams(allparams);
|
---|
222 | }
|
---|
223 | void Builder::addClassParam(const char* name,double value)
|
---|
224 | {
|
---|
225 | SString t;
|
---|
226 | sprintf(t.directWrite(30),"%s=%g",name,value);
|
---|
227 | t.endWrite();
|
---|
228 | addClassParam(t);
|
---|
229 | }
|
---|
230 |
|
---|
231 |
|
---|
232 | int Builder::countBranches(const char*g,SList &out)
|
---|
233 | {
|
---|
234 | int gl=0;
|
---|
235 | out+=(void*)g;
|
---|
236 | while (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 | }
|
---|
247 | return !out;
|
---|
248 | }
|
---|
249 |
|
---|
250 | int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
|
---|
251 | {
|
---|
252 | double len=min(2.0,c.dlug);
|
---|
253 | sprintf(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);
|
---|
255 | lastjoint_muscle_power=c.ruch;
|
---|
256 | return model.singleStepBuild(tmp,makeRange(g));
|
---|
257 | }
|
---|
258 |
|
---|
259 | int Builder::growPart(F1Props &c,const char *g)
|
---|
260 | {
|
---|
261 | sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg",
|
---|
262 | 1.0/c.masa,c.tarcie,c.wchl,c.asym);
|
---|
263 | return model.singleStepBuild(tmp,makeRange(g));
|
---|
264 | }
|
---|
265 |
|
---|
266 | const char *Builder::skipNeuro(const char *z)
|
---|
267 | {
|
---|
268 | for (;*z;z++) if ((*z==']')||(*z==')')) break;
|
---|
269 | return z-1;
|
---|
270 | }
|
---|
271 |
|
---|
272 | const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
|
---|
273 | {
|
---|
274 | const char*neuroend=skipNeuro(t);
|
---|
275 | last_f1_neuro=model.addNewNeuro();
|
---|
276 | last_f1_neuro->attachToPart(getLastPart());
|
---|
277 | const MultiRange *mr=makeRange(t-1,neuroend+1);
|
---|
278 | if (mr) last_f1_neuro->setMapping(*mr);
|
---|
279 | neuro_f1_to_f0+=last_f1_neuro;
|
---|
280 |
|
---|
281 | SString clsname;
|
---|
282 | bool haveclass=0;
|
---|
283 | while(*t && *t<=' ') t++;
|
---|
284 | const char* next=(*t)?(t+1):t;
|
---|
285 | while(*next && *next<=' ') next++;
|
---|
286 | if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
|
---|
287 | switch(*t)
|
---|
288 | {
|
---|
289 | case '@': if (t[1]==':') break;
|
---|
290 | haveclass=1;
|
---|
291 | // if (!(hasmuscles&1))
|
---|
292 | {
|
---|
293 | hasmuscles|=1;
|
---|
294 | Neuro *muscle=model.addNewNeuro();
|
---|
295 | sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
|
---|
296 | muscle->addInput(last_f1_neuro);
|
---|
297 | muscle->setDetails(tmp);
|
---|
298 | muscle->attachToJoint(getLastJoint());
|
---|
299 | if (usemapping) muscle->setMapping(*makeRange(t));
|
---|
300 | }
|
---|
301 | t++;
|
---|
302 | break;
|
---|
303 | case '|': if (t[1]==':') break;
|
---|
304 | haveclass=1;
|
---|
305 | // if (!(hasmuscles&2))
|
---|
306 | {
|
---|
307 | hasmuscles|=2;
|
---|
308 | Neuro *muscle=model.addNewNeuro();
|
---|
309 | sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
|
---|
310 | muscle->addInput(last_f1_neuro);
|
---|
311 | muscle->setDetails(tmp);
|
---|
312 | muscle->attachToJoint(getLastJoint());
|
---|
313 | if (usemapping) muscle->setMapping(*makeRange(t));
|
---|
314 | }
|
---|
315 | t++;
|
---|
316 | break;
|
---|
317 | }
|
---|
318 | while(*t && *t<=' ') t++;
|
---|
319 | bool finished=0;
|
---|
320 | const char *begin=t;
|
---|
321 | const char* colon=0;
|
---|
322 | SString classparams;
|
---|
323 | while(!finished)
|
---|
324 | {
|
---|
325 | switch (*t)
|
---|
326 | {
|
---|
327 | case ':': colon=t; break;
|
---|
328 | case 0: case ']': case ')': finished=1;
|
---|
329 | // NO break!
|
---|
330 | case ',':
|
---|
331 | if ( !haveclass && !colon && t>begin )
|
---|
332 | {
|
---|
333 | haveclass=1;
|
---|
334 | SString clsname(begin,t-begin);
|
---|
335 | clsname=trim(clsname);
|
---|
336 | last_f1_neuro->setClassName(clsname);
|
---|
337 | NeuroClass *cls=last_f1_neuro->getClass();
|
---|
338 | if (cls)
|
---|
339 | {
|
---|
340 | if (cls->getPreferredLocation()==2)
|
---|
341 | last_f1_neuro->attachToJoint(getLastJoint());
|
---|
342 | else if (cls->getPreferredLocation()==1)
|
---|
343 | last_f1_neuro->attachToPart(getLastPart());
|
---|
344 | }
|
---|
345 | }
|
---|
346 | else if (colon && (colon>begin) && (t>colon))
|
---|
347 | growConnection(begin,colon,t,props);
|
---|
348 | if (t[0]!=',') t--;
|
---|
349 | begin=t+1; colon=0;
|
---|
350 | break;
|
---|
351 | }
|
---|
352 | t++;
|
---|
353 | }
|
---|
354 | return t;
|
---|
355 | }
|
---|
356 | void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
|
---|
357 | {
|
---|
358 | while(*begin && *begin<=' ') begin++;
|
---|
359 | int i;
|
---|
360 | if (isdigit(begin[0]) || (begin[0]=='-'))
|
---|
361 | {
|
---|
362 | float weight=atof(colon+1);
|
---|
363 | int relative=atoi(begin);
|
---|
364 | int this_refno=neuro_f1_to_f0.size()-1;
|
---|
365 | addOrRememberInput(this_refno,this_refno+relative,weight);
|
---|
366 | }
|
---|
367 | else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
|
---|
368 | {
|
---|
369 | last_f1_neuro->extraProperties().set(i,colon+1);
|
---|
370 | }
|
---|
371 | else if (isupper(begin[0]) || strchr("*|@",begin[0]))
|
---|
372 | {
|
---|
373 | SString clsname(begin,colon-begin);
|
---|
374 | trim(clsname);
|
---|
375 | Neuro *receptor=model.addNewNeuro();
|
---|
376 | receptor->setClassName(clsname);
|
---|
377 | NeuroClass *cls=receptor->getClass();
|
---|
378 | if (cls)
|
---|
379 | {
|
---|
380 | if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
|
---|
381 | else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
|
---|
382 | }
|
---|
383 | last_f1_neuro->addInput(receptor,atof(colon+1));
|
---|
384 | if (usemapping) receptor->setMapping(*makeRange(begin,end-1));
|
---|
385 | }
|
---|
386 | else if ((begin[0]=='>')&&(begin[1]))
|
---|
387 | {
|
---|
388 | Neuro *out=model.addNewNeuro();
|
---|
389 | out->addInput(last_f1_neuro,atof(colon+1));
|
---|
390 | out->setClassName(SString(begin+1,end-colon-1));
|
---|
391 | if (begin[1]=='@')
|
---|
392 | {
|
---|
393 | sprintf(tmp,"p=%lg",lastjoint_muscle_power);
|
---|
394 | out->setClassParams(tmp);
|
---|
395 | }
|
---|
396 | else if (begin[1]=='|')
|
---|
397 | {
|
---|
398 | sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
|
---|
399 | out->setClassParams(tmp);
|
---|
400 | }
|
---|
401 | NeuroClass *cls=out->getClass();
|
---|
402 | if (cls)
|
---|
403 | {
|
---|
404 | if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
|
---|
405 | else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
|
---|
406 | }
|
---|
407 | if (usemapping) out->setMapping(*makeRange(begin,end-1));
|
---|
408 | }
|
---|
409 | else if (*begin=='!') addClassParam("fo",max(0.0,min(1.0,atof(colon+1))));
|
---|
410 | else if (*begin=='=') addClassParam("in",max(0.0,min(1.0,atof(colon+1))));
|
---|
411 | else if (*begin=='/') addClassParam("si",atof(colon+1));
|
---|
412 | /*else if (*begin=='!') last_f1_neuro->force=max(0.0,min(1.0,atof(colon+1)));
|
---|
413 | else if (*begin=='=') last_f1_neuro->inertia=max(0.0,min(1.0,atof(colon+1)));
|
---|
414 | else if (*begin=='/') last_f1_neuro->sigmo=atof(colon+1);
|
---|
415 | */
|
---|
416 | else if (islower(begin[0]))
|
---|
417 | {
|
---|
418 | SString newparam(begin,end-begin);
|
---|
419 | trim(newparam);
|
---|
420 | newparam.directWrite()[colon-begin]='='; // ':' -> '='
|
---|
421 | addClassParam(newparam);
|
---|
422 | }
|
---|
423 | }
|
---|