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 | #ifndef _NEUROIMPL_H_
|
---|
6 | #define _NEUROIMPL_H_
|
---|
7 |
|
---|
8 | #include "model.h"
|
---|
9 | #include "param.h"
|
---|
10 | #include "framsg.h"
|
---|
11 | #ifdef NEURO_SIGNALS
|
---|
12 | #include "signals.h"
|
---|
13 | #endif
|
---|
14 |
|
---|
15 | class NeuroImpl;
|
---|
16 | extern ParamEntry neuroimpl_tab[];
|
---|
17 | #ifdef NEURO_SIGNALS
|
---|
18 | extern Param neurosignals_param;
|
---|
19 | #endif
|
---|
20 |
|
---|
21 | class Creature;
|
---|
22 |
|
---|
23 | class NeuroNetConfig
|
---|
24 | {
|
---|
25 | public:
|
---|
26 | NeuroNetConfig();
|
---|
27 |
|
---|
28 | Param par;
|
---|
29 | double randominit;
|
---|
30 | double touchrange;
|
---|
31 |
|
---|
32 | static NeuroNetConfig globalconfig;
|
---|
33 | };
|
---|
34 |
|
---|
35 | #ifdef NEURO_SIGNALS
|
---|
36 | class NeuroSignals: public SignalSet
|
---|
37 | {
|
---|
38 | protected:
|
---|
39 | Creature *cr;
|
---|
40 | NeuroImpl *owner;
|
---|
41 | Creature *getCreature();
|
---|
42 | public:
|
---|
43 |
|
---|
44 | NeuroSignals(NeuroImpl *n):owner(n),cr(0) {}
|
---|
45 |
|
---|
46 | #define STATRICKCLASS NeuroSignals
|
---|
47 | PARAMPROCDEF(p_add);
|
---|
48 | PARAMPROCDEF(p_get);
|
---|
49 | PARAMGETDEF(size);
|
---|
50 | PARAMPROCDEF(p_receive);
|
---|
51 | PARAMPROCDEF(p_receiveSet);
|
---|
52 | PARAMPROCDEF(p_receiveFilter);
|
---|
53 | PARAMPROCDEF(p_receiveSingle);
|
---|
54 | #undef STATRICKCLASS
|
---|
55 | };
|
---|
56 | #endif
|
---|
57 |
|
---|
58 | /// Neuro net implementation
|
---|
59 | class NeuroNetImpl
|
---|
60 | {
|
---|
61 | CallbackNode *cnode;
|
---|
62 | Model &mod;
|
---|
63 | SList neurons[4];
|
---|
64 | NeuroNetConfig& config;
|
---|
65 | int isbuilt,errorcount;
|
---|
66 | STCALLBACKDEFC(NeuroNetImpl,destroyNN);
|
---|
67 | int minorder,maxorder;
|
---|
68 |
|
---|
69 | public:
|
---|
70 | #ifdef NEURO_SIGNALS
|
---|
71 | ChannelSpace *channels;
|
---|
72 | #endif
|
---|
73 | static int mytags_id;
|
---|
74 | static double getStateFromNeuro(Neuro *n);
|
---|
75 | int getErrorCount() {return errorcount;}
|
---|
76 | NeuroNetImpl(Model& model, NeuroNetConfig& conf = NeuroNetConfig::globalconfig
|
---|
77 | #ifdef NEURO_SIGNALS
|
---|
78 | , ChannelSpace *ch=0
|
---|
79 | #endif
|
---|
80 | );
|
---|
81 | ~NeuroNetImpl();
|
---|
82 | void simulateNeuroNet();
|
---|
83 | void simulateNeuroPhysics();
|
---|
84 |
|
---|
85 | static NeuroImpl *getImpl(Neuro* n) {return (NeuroImpl*)n->userdata[mytags_id];}
|
---|
86 | };
|
---|
87 |
|
---|
88 |
|
---|
89 | /**
|
---|
90 | Neuro implementation - this object calculates the Neuron's state
|
---|
91 | (Neuro::state) in each simulation step.
|
---|
92 |
|
---|
93 | SUBCLASSING TUTORIAL
|
---|
94 | ====================
|
---|
95 |
|
---|
96 | 1.Derive your custom neuron from NeuroImpl class. The name must be prefixed with NI_
|
---|
97 |
|
---|
98 | class NI_MyNeuron: public NeuroImpl
|
---|
99 | { ... };
|
---|
100 |
|
---|
101 | 2.Public parameters
|
---|
102 | Create any number of public fields, they will be adjustable from the genotype level.
|
---|
103 | 3 datatypes are supported: long, double and SString
|
---|
104 |
|
---|
105 | public:
|
---|
106 | long intParameter;
|
---|
107 | double fpParameter;
|
---|
108 | SString txtParameter;
|
---|
109 |
|
---|
110 |
|
---|
111 | 3.Required method: "instantiator".
|
---|
112 | It is always the same, just create a new instance of your neuron.
|
---|
113 | public:
|
---|
114 | NeuroImpl* makeNew() { return new NI_MyNeuron(); };
|
---|
115 |
|
---|
116 |
|
---|
117 | 4.Required method: default constructor
|
---|
118 | Set the "paramentries" variable if you need public parameters in your neuron.
|
---|
119 | NI_..._tab is created automatically and should be declared as: extern ParamEntry NI_..._tab[];
|
---|
120 | At this stage the parameter values are not yet available.
|
---|
121 |
|
---|
122 | public:
|
---|
123 | NI_MyNeuron() // no parameters!
|
---|
124 | {
|
---|
125 | paramentries=NI_MyNeuron_tab;
|
---|
126 | // you add here: some general initialization
|
---|
127 | }
|
---|
128 |
|
---|
129 |
|
---|
130 | 5.Optional method: initialization
|
---|
131 | This method is called once before the neuron is actually used in the simulation.
|
---|
132 | The parameter values are already initialized (according to the genotype) and the neuron is bound to the creature (i.e. this->neuro is valid).
|
---|
133 | Return 0 if the neuron cannot be initialized.
|
---|
134 |
|
---|
135 | int lateinit()
|
---|
136 | {
|
---|
137 | // you add here: initialization using full neuron context
|
---|
138 | // example: if (!neuro->joint) return 0; //this neuron must be attached to joint
|
---|
139 | return 1;//OK
|
---|
140 | }
|
---|
141 |
|
---|
142 |
|
---|
143 | 6.Required method: simulation step
|
---|
144 | If it has output: calculate the next neuron state and call setState()
|
---|
145 | If it is an effector: do anything else
|
---|
146 |
|
---|
147 | void go()
|
---|
148 | {
|
---|
149 | // you add here: things called every simulation step
|
---|
150 | }
|
---|
151 |
|
---|
152 | Note: You can make your neuron fire before or after "regular" neurons by changing its "simorder" property (during initialization). The default value is 1, whereas receptors have simorder=0 and effectors have simorder=2.
|
---|
153 |
|
---|
154 |
|
---|
155 | 7.Neuron definition
|
---|
156 | In order to incorporate the new neuron into Framsticks you need to provide some additional information (to be added to "f0.def" file).
|
---|
157 |
|
---|
158 | NEUROCLASS(MyNeuron,MN,This is the name,`Neuron description',-1,1,0)
|
---|
159 | NEUROPROP(int,0,0,name of the int,d,,,,intParameter)
|
---|
160 | NEUROPROP(fp,0,0,name of the floating point,f,,,,fpParameter)
|
---|
161 | NEUROPROP(txt,0,0,name of the text,s,,,,txtParameter)
|
---|
162 | ENDNEUROCLASS
|
---|
163 |
|
---|
164 | NEUROCLASS:
|
---|
165 | - MyNeuron: neuron class name (without the NI_ prefix)
|
---|
166 | - MN: neuron symbol (used in genotypes)
|
---|
167 | - full name and description
|
---|
168 | - -1: preferred number of inputs (special case: -1=any)
|
---|
169 | - 1: provides output: 1=yes/0=no
|
---|
170 | - 0: preferred location: 0=none, 1=part, 2=joint
|
---|
171 |
|
---|
172 | NEUROPROP:
|
---|
173 | - int/fp/txt: parameter names as visible in genotypes and scripting
|
---|
174 | - "name of the ...": descriptive name
|
---|
175 | - d/f/s: type (int/floating point/string)
|
---|
176 | - intParameter/fpParameter/txtParameter: C++ field names
|
---|
177 |
|
---|
178 |
|
---|
179 | */
|
---|
180 | class NeuroImpl
|
---|
181 | {
|
---|
182 | protected:
|
---|
183 | int simorder;
|
---|
184 | int channels;
|
---|
185 | SListTempl<double> chstate;
|
---|
186 | SListTempl<double> chnewstate;
|
---|
187 | Param *fields_param;
|
---|
188 | ExtObject *fields_object;
|
---|
189 | public:
|
---|
190 | static const int ENDDRAWING;
|
---|
191 | static const int MAXDRAWINGXY;
|
---|
192 |
|
---|
193 | enum NeuroImplStats { BeforeInit=0, InitError=1, InitOk=2 };
|
---|
194 | NeuroImplStats status;
|
---|
195 | /** originating neuron object (from the model) */
|
---|
196 | Neuro *neuro;
|
---|
197 | NeuroClass *neuroclass;
|
---|
198 | /** don't access directly */
|
---|
199 | double newstate;
|
---|
200 |
|
---|
201 | #ifdef NEURO_SIGNALS
|
---|
202 | NeuroSignals sigs;
|
---|
203 | #endif
|
---|
204 | NeuroNetImpl *owner;
|
---|
205 | ExtObject sigs_obj;
|
---|
206 |
|
---|
207 | /** "virtual constructor" - NeuroFactory uses this method to create the proper implementation object.
|
---|
208 | subclasses must return new object here. */
|
---|
209 | virtual NeuroImpl* makeNew() {return 0;} //
|
---|
210 | /** will be used by readParam() method, if not null */
|
---|
211 | ParamEntry *paramentries; // no extra properties if ==0
|
---|
212 | /** read additional properties from "moredata" field of the originating Neuro */
|
---|
213 | void readParam();
|
---|
214 | /** called when all other neuro objects were already created and "moredata" transferred to
|
---|
215 | object fields.
|
---|
216 | useful for initialization that cannot be performed in the constructor.
|
---|
217 | @return 1=ok 0=failure
|
---|
218 | */
|
---|
219 | virtual int lateinit() {return 1;}
|
---|
220 | /** calculate 'newstate - implementation dependent */
|
---|
221 | virtual void go(){}
|
---|
222 | /** for neurons doing some physical actions (called each simulation step when nnspeed!=1.0) */
|
---|
223 | virtual void goPhysics(){}
|
---|
224 |
|
---|
225 | int getSimOrder() {return simorder;}
|
---|
226 | virtual int getNeedPhysics() {return 0;}
|
---|
227 |
|
---|
228 | void setChannelCount(int c);
|
---|
229 | int getChannelCount() {return channels;}
|
---|
230 |
|
---|
231 | int getInputCount() {return neuro->getInputCount();}
|
---|
232 | int getInputChannelCount(int i);
|
---|
233 | double getInputState(int i,int channel=0);
|
---|
234 | double getWeightedInputState(int i,int channel=0);
|
---|
235 | double getInputSum(int startwith=0);
|
---|
236 | double getWeightedInputSum(int startwith=0);
|
---|
237 | double getInputWeight(int i) {return neuro->getInputWeight(i);}
|
---|
238 | void setState(double st,int channel);
|
---|
239 | void setState(double st) {validateNeuroState(st); newstate=st;}
|
---|
240 | double getState(int channel);
|
---|
241 | double getState() {return neuro->state;}
|
---|
242 |
|
---|
243 | virtual int getDrawingCount() {return 0;}
|
---|
244 | virtual int* getDrawing(int i) {return 0;}
|
---|
245 |
|
---|
246 | void commit();
|
---|
247 | void validateNeuroState(double& st) {if (st<=-1e10) st=-1e10; else if (st>1e10) st=1e10;}
|
---|
248 |
|
---|
249 | NeuroImpl():owner(0),neuro(0),newstate(0),paramentries(0),simorder(1),status(BeforeInit),channels(1),fields_param(0),fields_object(0)
|
---|
250 | #ifdef NEURO_SIGNALS
|
---|
251 | ,sigs(this),sigs_obj(&neurosignals_param,&sigs)
|
---|
252 | #endif
|
---|
253 | {}
|
---|
254 | virtual ~NeuroImpl();
|
---|
255 | virtual void createFieldsObject();
|
---|
256 |
|
---|
257 | /** usually == "newstate" but will obey the "hold state" */
|
---|
258 | double getNewState(int channel=0);
|
---|
259 |
|
---|
260 | /** don't use! */
|
---|
261 | void setCurrentState(double st,int channel=0);
|
---|
262 |
|
---|
263 | bool getPosition(Pt3D &pos);
|
---|
264 | Creature* getCreature();
|
---|
265 |
|
---|
266 | #define STATRICKCLASS NeuroImpl
|
---|
267 | PARAMGETDEF(count) {arg1->setInt(getInputCount());}
|
---|
268 | PARAMPROCDEF(p_get) {arg2->setDouble(getInputState(arg1->getInt()));}
|
---|
269 | PARAMPROCDEF(p_getweight) {arg2->setDouble(getInputWeight(arg1->getInt()));}
|
---|
270 | PARAMPROCDEF(p_getw) {arg2->setDouble(getWeightedInputState(arg1->getInt()));}
|
---|
271 | PARAMPROCDEF(p_getsum) {arg2->setDouble(getInputSum(arg1->getInt()));}
|
---|
272 | PARAMPROCDEF(p_getwsum) {arg2->setDouble(getWeightedInputSum(arg1->getInt()));}
|
---|
273 | PARAMGETDEF(sum) {arg1->setDouble(getInputSum(0));}
|
---|
274 | PARAMGETDEF(wsum) {arg1->setDouble(getWeightedInputSum(0));}
|
---|
275 | PARAMPROCDEF(p_getchancount) {arg2->setInt(getInputChannelCount(arg1->getInt()));}
|
---|
276 | PARAMPROCDEF(p_getchan) {arg2->setDouble(getInputState(arg1[1].getInt(),arg1[0].getInt()));}
|
---|
277 | PARAMPROCDEF(p_getwchan) {arg2->setDouble(getWeightedInputState(arg1[1].getInt(),arg1[0].getInt()));}
|
---|
278 | PARAMGETDEF(state) {arg1->setDouble(getState());}
|
---|
279 | PARAMSETDEF(state) {setState(arg1->getDouble()); return 0;}
|
---|
280 | PARAMGETDEF(cstate) {arg1->setDouble(neuro->state);}
|
---|
281 | PARAMSETDEF(cstate) {setCurrentState(arg1->getDouble()); return 0;}
|
---|
282 | PARAMGETDEF(hold) {arg1->setInt((neuro->flags&(Neuro::HoldState))?1:0);}
|
---|
283 | PARAMSETDEF(hold) {neuro->flags=(neuro->flags&~Neuro::HoldState)|(arg1->getInt()?Neuro::HoldState:0); return 0;}
|
---|
284 | PARAMGETDEF(channels) {arg1->setInt(getChannelCount());}
|
---|
285 | PARAMSETDEF(channels) {setChannelCount(arg1->getInt()); return 0;}
|
---|
286 | PARAMPROCDEF(p_getstate) {arg2->setDouble(getState(arg1->getInt()));}
|
---|
287 | PARAMPROCDEF(p_setstate) {setState(arg1[0].getDouble(),arg1[1].getInt());}
|
---|
288 | PARAMPROCDEF(p_setcstate) {setCurrentState(arg1[0].getDouble(),arg1[1].getInt());}
|
---|
289 | PARAMGETDEF(creature);
|
---|
290 | PARAMGETDEF(part);
|
---|
291 | PARAMGETDEF(joint);
|
---|
292 | PARAMGETDEF(position_x);
|
---|
293 | PARAMGETDEF(position_y);
|
---|
294 | PARAMGETDEF(position_z);
|
---|
295 | PARAMGETDEF(fields);
|
---|
296 | PARAMGETDEF(neurodef);
|
---|
297 | PARAMGETDEF(classObject);
|
---|
298 | #undef STATRICKCLASS
|
---|
299 | };
|
---|
300 |
|
---|
301 | #endif
|
---|