source: cpp/gdk/neuroimpl.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: 16.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 "neuroimpl.h"
6#include "neurofactory.h"
7#ifndef NOCREATUREOBJECT
8#include "creature.h"
9#include "creatmechobj.h"
10#include "livegroups.h"
11#include "simul.h"
12#endif
13
14const int NeuroImpl::ENDDRAWING=-9999;
15const int NeuroImpl::MAXDRAWINGXY=0xffff;
16
17int NeuroNetImpl::mytags_id=0;
18
19/////////////////////////////////////////////////////////
20
21#define FIELDSTRUCT NeuroNetConfig
22static ParamEntry nncfg_paramtab[]=
23{
24{"Creature: Neurons",1,2,"nnsim",},
25{"randinit",1,0,"Random initialization","f 0 10 0.01",FIELD(randominit),"Initialize all neuron states with uniform distribution random numbers"},
26{"touchrange",1,0,"T receptor range","f 0 100 1",FIELD(touchrange),},
27{0,0,0,},
28};
29#undef FIELDSTRUCT
30
31NeuroNetConfig::NeuroNetConfig()
32        :par(nncfg_paramtab,this),
33         randominit(0.01),
34         touchrange(1)
35{}
36
37NeuroNetConfig NeuroNetConfig::globalconfig;
38
39/////////////////////////////////////////////////////////////////
40
41NeuroNetImpl::NeuroNetImpl(Model& model, NeuroNetConfig& conf
42#ifdef NEURO_SIGNALS
43, ChannelSpace *ch
44#endif
45)
46        :mod(model),config(conf),
47         isbuilt(1),errorcount(0)
48#ifdef NEURO_SIGNALS
49,channels(ch)
50#endif
51{
52if (!mytags_id) mytags_id=mod.userdata.newID();
53
54Neuro *n;
55NeuroImpl *ni;
56Joint *j;
57int i;
58DB(printf("makeNeuroNet(%p)\n",&mod));
59
60minorder=3; maxorder=0;
61errorcount=0;
62
63for (i=0;j=mod.getJoint(i);i++)
64        j->flags&=~(4+8); // todo: !!!neuroitems shouldn't use model fields!!!
65
66for (i=0;n=mod.getNeuro(i);i++)
67        {
68        ni=NeuroFactory::createNeuroImpl(n);
69        n->userdata[mytags_id]=ni;
70        if (!ni) { errorcount++;
71                FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) implementation not available",
72                         i,(const char*)n->getClassName());
73                continue; } // implementation not available?!
74        ni->owner=this;
75        ni->neuro=n;
76        ni->readParam();
77        }
78
79for (i=0;n=mod.getNeuro(i);i++)
80        {
81        n->state+=(rnd01-0.5)*config.randominit;
82        ni=(NeuroImpl*)n->userdata[mytags_id];
83        if (!ni) continue;
84        if (!ni->lateinit())
85                { ni->status=NeuroImpl::InitError; errorcount++;
86                FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) initialization failed",
87                         i,(const char*)n->getClassName());
88                continue; }
89        ni->status=NeuroImpl::InitOk;
90        int order=ni->getSimOrder();
91        if (order<0) order=0; else if (order>2) order=2;
92        if (order<minorder) minorder=order;
93        if (order>maxorder) maxorder=order;
94        neurons[order]+=ni;
95        if (ni->getNeedPhysics())
96                neurons[3]+=ni;
97        }
98cnode=mod.delmodel_list.add(STATRICKCALLBACK(this,&NeuroNetImpl::destroyNN,0));
99}
100
101void NeuroNetImpl::destroyNN(CALLBACKARGS)
102{
103if (!isbuilt) return;
104DB(printf("destroyNeuroNet(%p)\n",&mod));
105NeuroImpl *ni;
106Neuro *n;
107for (int i=0;n=mod.getNeuro(i);i++)
108        {
109        ni=(NeuroImpl*)n->userdata[mytags_id];
110        delete ni;
111        n->userdata[mytags_id]=0;
112        }
113mod.delmodel_list.remove(cnode);
114isbuilt=0; errorcount=0;
115delete this;
116}
117
118NeuroNetImpl::~NeuroNetImpl()
119{
120destroyNN(0,0);
121}
122
123void NeuroNetImpl::simulateNeuroNet()
124{
125NeuroImpl *ni;
126for (int order=minorder;order<=maxorder;order++)
127        {
128        int i;
129        SList &nlist=neurons[order];
130        for (i=0;ni=(NeuroImpl*)nlist(i);i++)
131                ni->go();
132        for (i=0;ni=(NeuroImpl*)nlist(i);i++)
133                ni->commit();
134        }
135}
136
137void NeuroNetImpl::simulateNeuroPhysics()
138{
139NeuroImpl *ni;
140int i;
141SList &nlist=neurons[3];
142for (i=0;ni=(NeuroImpl*)nlist(i);i++)
143        ni->goPhysics();
144}
145
146///////////////////////////////////////////////
147
148void NeuroImpl::setChannelCount(int c)
149{
150if (c<1) c=1;
151if (c==channels) return;
152if (c<channels) {channels=c; chstate.trim(c-1); chnewstate.trim(c-1); return;}
153double s=getState(channels-1);
154chnewstate.setSize(c-1);
155chstate.setSize(c-1);
156for(int i=channels;i<c;i++)
157        {chstate(i-1)=s; chnewstate(i-1)=s;}
158channels=c;
159}
160
161void NeuroImpl::setState(double st,int channel)
162{
163validateNeuroState(st);
164if (channel>=channels) channel=channels-1;
165if (channel<=0) {newstate=st;return;}
166chnewstate(channel-1)=st;
167}
168
169void NeuroImpl::setCurrentState(double st,int channel)
170{
171validateNeuroState(st);
172if (channel>=channels) channel=channels-1;
173if (channel<=0) {neuro->state=st; return;}
174chstate(channel-1)=st;
175}
176
177double NeuroImpl::getNewState(int channel)
178{
179if (neuro->flags&Neuro::HoldState) return getState(channel);
180if (channel>=channels) channel=channels-1;
181if (channel<=0) {return newstate;}
182return chnewstate(channel-1);
183}
184
185double NeuroImpl::getState(int channel)
186{
187if (channel>=channels) channel=channels-1;
188if (channel<=0) return neuro->state;
189return chstate(channel-1);
190}
191
192void NeuroImpl::commit()
193{
194if (!(neuro->flags&Neuro::HoldState))
195        {
196        if (channels>1)
197                chstate=chnewstate;
198        neuro->state=newstate;
199        }
200}
201
202int NeuroImpl::getInputChannelCount(int i)
203{
204if ((i<0)||(i >= neuro->getInputCount())) return 1;
205Neuro *nu=neuro->getInput(i);
206NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
207if (!ni) return 1;
208return ni->channels;
209}
210
211double NeuroImpl::getInputState(int i,int channel)
212{
213if ((i<0)||(i >= neuro->getInputCount())) return 0;
214Neuro *nu=neuro->getInput(i);
215if (channel<=0) return nu->state;
216NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
217if (!ni) return nu->state;
218if (channel>=ni->channels) channel=ni->channels-1;
219if (!channel) return nu->state;
220return ni->chstate(channel-1);
221}
222
223double NeuroImpl::getWeightedInputState(int i, int channel)
224{
225if ((i<0)||(i >= neuro->getInputCount())) return 0;
226float w;
227Neuro *nu=neuro->getInput(i,w);
228if (channel<=0) return nu->state * w;
229NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
230if (!ni) return nu->state * w;
231if (channel>=ni->channels) channel=ni->channels-1;
232if (!channel) return w * nu->state;
233return w * ni->chstate(channel-1);
234}
235
236double NeuroImpl::getInputSum(int startwith)
237{
238if (startwith<0) return 0;
239Neuro *inp;
240double sum=0.0;
241while(inp=neuro->getInput(startwith++))
242        sum+=inp->state;
243return sum;
244}
245
246double NeuroImpl::getWeightedInputSum(int startwith)
247{
248if (startwith<0) return 0;
249Neuro *inp;
250double sum=0.0;
251float w;
252while(inp=neuro->getInput(startwith++,w))
253        sum+=inp->state*w;
254return sum;
255}
256
257void NeuroImpl::readParam()
258{
259static Param par;
260if (!paramentries) return;
261par.setParamTab(paramentries);
262par.select(this);
263par.setDefault();
264int zero=0;
265par.load2(neuro->getClassParams(),zero);
266}
267
268/////////////////////////////
269
270#ifdef NEURO_SIGNALS
271#define NEUROIMPL_SIGNAL_PROPS 1
272#else
273#define NEUROIMPL_SIGNAL_PROPS 0
274#endif
275
276#define FIELDSTRUCT NeuroImpl
277ParamEntry neuroimpl_tab[]=
278{
279{"Neuro",1,26+NEUROIMPL_SIGNAL_PROPS,"Neuro","Live Neuron object."},
280
281{"getInputState",0,0,"get input signal","p f(d input)",PROCEDURE(p_get),},
282{"getInputWeight",0,0,"get input weight","p f(d input)",PROCEDURE(p_getweight),},
283{"getWeightedInputState",0,0,"get weighted input signal","p f(d input)",PROCEDURE(p_getw),},
284{"getInputSum",0,0,"get signal sum","p f(d input)",PROCEDURE(p_getsum),},
285{"getWeightedInputSum",0,0,"get weighted signal sum","p f(d input)",PROCEDURE(p_getwsum),"uses any number of inputs starting with the specified input. getWeightedInputSum(0)=weightedInputSum"},
286{"getInputCount",0,0,"get input count","d",GETONLY(count),},
287{"inputSum",0,0,"full signal sum","f",GETONLY(sum),},
288{"weightedInputSum",0,0,"full weighted signal sum","f",GETONLY(wsum),},
289{"getInputChannelCount",0,0,"get channel count for input","p d(d input)",PROCEDURE(p_getchancount),},
290{"getInputStateChannel",0,0,"get input signal from channel","p f(d input,d channel)",PROCEDURE(p_getchan),},
291{"getWeightedInputStateChannel",0,0,"get weighted input signal from channel","p f(d input,d channel)",PROCEDURE(p_getwchan),},
292{"state",0,0,"neuron state (channel 0)","f",GETSET(state),"when read, returns the current neuron state.\nWhen written, sets the next neuron state (for use in the neuron definition)"},
293{"channelCount",0,0,"number of output channels","d",GETSET(channels),},
294{"getStateChannel",0,0,"get output state for channel","p f(d channel)",PROCEDURE(p_getstate),},
295{"setStateChannel",0,0,"set output state for channel","p(d channel,f value)",PROCEDURE(p_setstate),},
296{"hold",0,0,"Hold state","d 0 1",GETSET(hold),"",},
297{"currState",0,0,"neuron state (channel 0)","f",GETSET(cstate),"the only difference from the \"state\" field is that currState, when written, changes the internal neuron state immediately (which disturbs the regular synchronous NN operation). This feature should only be used while controlling the neuron 'from outside' (like a neuro probe) and not in the neuron definition.",},
298{"setCurrStateChannel",0,0,"set neuron for channel","p(d channel,f value)",PROCEDURE(p_setcstate),"like \"currState\""},
299{"position_x",0,0,"position x","f",GETONLY(position_x),},
300{"position_y",0,0,"position y","f",GETONLY(position_y),},
301{"position_z",0,0,"position z","f",GETONLY(position_z),},
302{"creature",0,0,"get owner creature","o Creature",GETONLY(creature),},
303{"part",0,0,"the Part object where this neuron is located","o MechPart",GETONLY(part),},
304{"joint",0,0,"the Joint object where this neuron is located","o MechJoint",GETONLY(joint),},
305{"fields",0,0,"custom neuron fields","o Fields",GETONLY(fields),
306"Neurons can have different fields depending on their class. Script neurons have their fields defined using the \"prop:\" syntax. If you develop a custom neuron script you should use the Fields object for accessing your own neuron fields. The Neuro.fields property is meant for accessing the neuron fields from the outside script.\n"
307"Examples:\n"
308"var c=LiveLibrary.createFromString(\"X[N]\");\n"
309"Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).fields.in);\n"
310"c=LiveLibrary.createFromString(\"X[Nn,e:0.1]\");\n"
311"Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).fields.e);\n"
312"\n"
313"The Interface object can be used to discover which fields are available for a certain neuron object:\n"
314"c=LiveLibrary.createFromString(\"X[N]\");\n"
315"var iobj=Interface.makeFrom(c.getNeuro(0).fields);\n"
316"var i;\n"
317"for(i=0;i<iobj.properties;i++)\n"
318" Simulator.print(iobj.getId(i)+\" (\"+iobj.getName(i)+\")\");",},
319{"def",0,0,"Neuron definition from which this live neuron was built","o NeuroDef",GETONLY(neurodef),},
320#ifdef NEURO_SIGNALS
321{"signals",0,PARAM_READONLY,"Signals","o NeuroSignals",FIELD(sigs_obj),},
322#endif
323
324{0,0,0,},
325};
326#undef FIELDSTRUCT
327
328#ifdef NEURO_SIGNALS
329ParamEntry neurosignals_paramtab[]=
330 {
331{"NeuroSignals",1,8,"NeuroSignals","Signals attached to the neuron.\nSee also: Signal, WorldSignals, CreatureSignals.\nscripts/light.neuro and scripts/seelight.neuro are simple custom neuron examples demonstrating how to send/receive signals between creatures.",},
332
333#define FIELDSTRUCT NeuroSignals
334{"add",0,PARAM_NOSTATIC,"add","p(s channel)",PROCEDURE(p_add),"Create a new signal"},
335{"receive",0,PARAM_NOSTATIC,"receive","p f(s channel)",PROCEDURE(p_receive),"Receive the aggregated signal power in a given channel."},
336{"receiveSet",0,PARAM_NOSTATIC,"receive","p oVector(s channel,f max distance)",PROCEDURE(p_receiveSet),"Get all signals in the specified range. Returns a readonly vector object containing Signal objects (individual signals can be accessed as result[0] throught result[result.size-1])."},
337{"receiveFilter",0,PARAM_NOSTATIC,"receive","p f(s channel,f max distance,f flavor,f filter)",PROCEDURE(p_receiveFilter),"Receive the aggregated signal power in a given channel.\n\nAdditional filtering options:\n- Max distance only receives the neighbor signals (based on their physical location)\n- Flavor filtering: only signals having the flavor close to the specified one will be received. The filter value is the maximum allowed difference."},
338{"receiveSingle",0,PARAM_NOSTATIC,"receive","p oSignal(s channel,f range)",PROCEDURE(p_receiveSingle),"Find the signal source having the highest signal power (including the distance)"},
339#undef FIELDSTRUCT
340
341#define FIELDSTRUCT SignalSet
342{"get",0,PARAM_NOSTATIC,"get","p oSignal(d index)",PROCEDURE(p_get),},
343{"size",0,1+PARAM_NOSTATIC,"size","d",GETONLY(size),},
344{"clear",0,1+PARAM_NOSTATIC,"clear","p()",PROCEDURE(p_clear),},
345#undef FIELDSTRUCT
346{0,0,0,},
347 };
348Param neurosignals_param(neurosignals_paramtab,0);
349#endif
350
351Param st_neuroimplparam(neuroimpl_tab,0,"Neuro");
352
353#ifdef NEURO_SIGNALS
354class NeuroSigSource: public SigSource
355{
356  protected:
357NeuroImpl* owner;
358  public:
359NeuroSigSource(NeuroImpl *n,Creature *c):SigSource(0,c),owner(n) {}
360bool update();
361};
362
363bool NeuroSigSource::update()
364{
365Pt3D p;
366if (owner->getPosition(p))
367        {
368        setLocation(p);
369        return true;
370        }
371return false;
372}
373
374Creature *NeuroSignals::getCreature()
375{
376if (!cr)
377        {
378        cr=owner->getCreature();
379        }
380return cr;
381}
382
383void NeuroSignals::p_add(PARAMPROCARGS)
384{
385if (!owner->owner->channels) {ret->setEmpty();return;}
386SigChannel *ch=owner->owner->channels->getChannel(args->getString(),true);
387SigSource *s=new NeuroSigSource(owner,getCreature());
388ch->addSource(s);
389sigs+=s;
390s->setupObject(ret);
391}
392
393void NeuroSignals::p_receive(PARAMPROCARGS)
394{
395SigChannel *ch; Pt3D p;
396if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args->getString(),false)) && owner->getPosition(p))
397        ret->setDouble(ch->receive(&p,getCreature()));
398else
399        ret->setDouble(0);
400}
401
402void NeuroSignals::p_receiveFilter(PARAMPROCARGS)
403{
404SigChannel *ch; Pt3D p;
405if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[3].getString(),false)) && owner->getPosition(p))
406        ret->setDouble(ch->receive(&p,getCreature(),args[2].getDouble(),args[1].getDouble(),args[0].getDouble()));
407else
408        ret->setDouble(0);
409}
410
411void NeuroSignals::p_receiveSet(PARAMPROCARGS)
412{
413SigChannel *ch; Pt3D p;
414SigVector *vec=new SigVector();
415if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
416        ch->receiveSet(vec,&p,getCreature(),args[0].getDouble());
417ret->setObject(vec->makeObject());
418}
419
420void NeuroSignals::p_receiveSingle(PARAMPROCARGS)
421{
422SigChannel *ch; Pt3D p;
423if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
424        {
425        SigSource *src=ch->receiveSingle(&p,getCreature(),args[0].getDouble(),0,1e99);
426        if (src)
427                {
428                src->setupObject(ret);
429                return;
430                }
431        }
432ret->setEmpty();
433}
434#endif
435
436extern ParamEntry creature_paramtab[];
437static Param creature_param(creature_paramtab,0);
438
439Creature* NeuroImpl::getCreature()
440{
441#ifndef NOCREATUREOBJECT
442CreatMechObject *cmo=(CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id];
443return cmo->creature;
444#else
445return 0;
446#endif
447}
448
449void NeuroImpl::get_creature(ExtValue *ret)
450{
451#ifndef NOCREATUREOBJECT
452ret->setObject(ExtObject(&creature_param,getCreature()));
453#endif
454}
455
456void NeuroImpl::get_part(ExtValue *ret)
457{
458#ifndef NOCREATUREOBJECT
459Part *pa;
460if (pa=neuro->getPart())
461        ret->setObject(ExtObject(&mechpart_param,((MechPart *)pa->userdata[CreatMechObject::modeltags_id])));
462else
463        ret->setEmpty();
464#endif
465}
466
467void NeuroImpl::get_joint(ExtValue *ret)
468{
469#ifndef NOCREATUREOBJECT
470Joint *jo;
471if (jo=neuro->getJoint())
472        ret->setObject(ExtObject(&mechjoint_param,((MechJoint*)jo->userdata[CreatMechObject::modeltags_id])));
473else
474        ret->setEmpty();
475#endif
476}
477
478bool NeuroImpl::getPosition(Pt3D &pos)
479{
480#ifndef NOCREATUREOBJECT
481Part *pa; Joint *jo;
482if (pa=neuro->getPart())
483        {pos=((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p; return true;}
484if (jo=neuro->getJoint())
485        {
486        if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart)
487                pos=((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p;
488        else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart)
489                pos=((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p;
490        else pos=(((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p
491                   +((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p)/2;
492        return true;
493        }
494#endif
495return false;
496}
497
498void NeuroImpl::get_position_x(ExtValue *ret)
499{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();}
500void NeuroImpl::get_position_y(ExtValue *ret)
501{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();}
502void NeuroImpl::get_position_z(ExtValue *ret)
503{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();}
504
505
506void NeuroImpl::createFieldsObject()
507{
508fields_param=new Param(paramentries?paramentries:(ParamEntry*)&empty_paramtab,this,"Fields");
509fields_object=new ExtObject(fields_param);
510}
511
512void NeuroImpl::get_fields(ExtValue *ret)
513{
514if (!fields_object)
515        createFieldsObject();
516ret->setObject(*fields_object);
517}
518
519void NeuroImpl::get_neurodef(ExtValue *ret)
520{
521ret->setObject(ExtObject(&st_neuroparam,neuro));
522}
523
524NeuroImpl::~NeuroImpl()
525{
526if (fields_param)
527        {
528        delete fields_param;
529        delete fields_object;
530        }
531}
Note: See TracBrowser for help on using the repository browser.