[5] | 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 | #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 | /** don't access directly */ |
---|
| 198 | double newstate; |
---|
| 199 | |
---|
| 200 | #ifdef NEURO_SIGNALS |
---|
| 201 | NeuroSignals sigs; |
---|
| 202 | #endif |
---|
| 203 | NeuroNetImpl *owner; |
---|
| 204 | ExtObject sigs_obj; |
---|
| 205 | |
---|
| 206 | /** "virtual constructor" - NeuroFactory uses this method to create the proper implementation object. |
---|
| 207 | subclasses must return new object here. */ |
---|
| 208 | virtual NeuroImpl* makeNew() {return 0;} // |
---|
| 209 | /** will be used by readParam() method, if not null */ |
---|
| 210 | ParamEntry *paramentries; // no extra properties if ==0 |
---|
| 211 | /** read additional properties from "moredata" field of the originating Neuro */ |
---|
| 212 | void readParam(); |
---|
| 213 | /** called when all other neuro objects were already created and "moredata" transferred to |
---|
| 214 | object fields. |
---|
| 215 | useful for initialization that cannot be performed in the constructor. |
---|
| 216 | @return 1=ok 0=failure |
---|
| 217 | */ |
---|
| 218 | virtual int lateinit() {return 1;} |
---|
| 219 | /** calculate 'newstate - implementation dependent */ |
---|
| 220 | virtual void go(){} |
---|
| 221 | /** for neurons doing some physical actions (called each simulation step when nnspeed!=1.0) */ |
---|
| 222 | virtual void goPhysics(){} |
---|
| 223 | |
---|
| 224 | int getSimOrder() {return simorder;} |
---|
| 225 | virtual int getNeedPhysics() {return 0;} |
---|
| 226 | |
---|
| 227 | void setChannelCount(int c); |
---|
| 228 | int getChannelCount() {return channels;} |
---|
| 229 | |
---|
| 230 | int getInputCount() {return neuro->getInputCount();} |
---|
| 231 | int getInputChannelCount(int i); |
---|
| 232 | double getInputState(int i,int channel=0); |
---|
| 233 | double getWeightedInputState(int i,int channel=0); |
---|
| 234 | double getInputSum(int startwith=0); |
---|
| 235 | double getWeightedInputSum(int startwith=0); |
---|
| 236 | double getInputWeight(int i) {return neuro->getInputWeight(i);} |
---|
| 237 | void setState(double st,int channel); |
---|
| 238 | void setState(double st) {validateNeuroState(st); newstate=st;} |
---|
| 239 | double getState(int channel); |
---|
| 240 | double getState() {return neuro->state;} |
---|
| 241 | |
---|
| 242 | virtual int getDrawingCount() {return 0;} |
---|
| 243 | virtual int* getDrawing(int i) {return 0;} |
---|
| 244 | |
---|
| 245 | void commit(); |
---|
| 246 | void validateNeuroState(double& st) {if (st<=-1e10) st=-1e10; else if (st>1e10) st=1e10;} |
---|
| 247 | |
---|
| 248 | NeuroImpl():owner(0),neuro(0),newstate(0),paramentries(0),simorder(1),status(BeforeInit),channels(1),fields_param(0),fields_object(0) |
---|
| 249 | #ifdef NEURO_SIGNALS |
---|
| 250 | ,sigs(this),sigs_obj(&neurosignals_param,&sigs) |
---|
| 251 | #endif |
---|
| 252 | {} |
---|
| 253 | virtual ~NeuroImpl(); |
---|
| 254 | virtual void createFieldsObject(); |
---|
| 255 | |
---|
| 256 | /** usually == "newstate" but will obey the "hold state" */ |
---|
| 257 | double getNewState(int channel=0); |
---|
| 258 | |
---|
| 259 | /** don't use! */ |
---|
| 260 | void setCurrentState(double st,int channel=0); |
---|
| 261 | |
---|
| 262 | bool getPosition(Pt3D &pos); |
---|
| 263 | Creature* getCreature(); |
---|
| 264 | |
---|
| 265 | #define STATRICKCLASS NeuroImpl |
---|
| 266 | PARAMGETDEF(count) {arg1->setInt(getInputCount());} |
---|
| 267 | PARAMPROCDEF(p_get) {arg2->setDouble(getInputState(arg1->getInt()));} |
---|
| 268 | PARAMPROCDEF(p_getweight) {arg2->setDouble(getInputWeight(arg1->getInt()));} |
---|
| 269 | PARAMPROCDEF(p_getw) {arg2->setDouble(getWeightedInputState(arg1->getInt()));} |
---|
| 270 | PARAMPROCDEF(p_getsum) {arg2->setDouble(getInputSum(arg1->getInt()));} |
---|
| 271 | PARAMPROCDEF(p_getwsum) {arg2->setDouble(getWeightedInputSum(arg1->getInt()));} |
---|
| 272 | PARAMGETDEF(sum) {arg1->setDouble(getInputSum(0));} |
---|
| 273 | PARAMGETDEF(wsum) {arg1->setDouble(getWeightedInputSum(0));} |
---|
| 274 | PARAMPROCDEF(p_getchancount) {arg2->setInt(getInputChannelCount(arg1->getInt()));} |
---|
| 275 | PARAMPROCDEF(p_getchan) {arg2->setDouble(getInputState(arg1[1].getInt(),arg1[0].getInt()));} |
---|
| 276 | PARAMPROCDEF(p_getwchan) {arg2->setDouble(getWeightedInputState(arg1[1].getInt(),arg1[0].getInt()));} |
---|
| 277 | PARAMGETDEF(state) {arg1->setDouble(getState());} |
---|
| 278 | PARAMSETDEF(state) {setState(arg1->getDouble()); return 0;} |
---|
| 279 | PARAMGETDEF(cstate) {arg1->setDouble(neuro->state);} |
---|
| 280 | PARAMSETDEF(cstate) {setCurrentState(arg1->getDouble()); return 0;} |
---|
| 281 | PARAMGETDEF(hold) {arg1->setInt((neuro->flags&(Neuro::HoldState))?1:0);} |
---|
| 282 | PARAMSETDEF(hold) {neuro->flags=(neuro->flags&~Neuro::HoldState)|(arg1->getInt()?Neuro::HoldState:0); return 0;} |
---|
| 283 | PARAMGETDEF(channels) {arg1->setInt(getChannelCount());} |
---|
| 284 | PARAMSETDEF(channels) {setChannelCount(arg1->getInt()); return 0;} |
---|
| 285 | PARAMPROCDEF(p_getstate) {arg2->setDouble(getState(arg1->getInt()));} |
---|
| 286 | PARAMPROCDEF(p_setstate) {setState(arg1[0].getDouble(),arg1[1].getInt());} |
---|
| 287 | PARAMPROCDEF(p_setcstate) {setCurrentState(arg1[0].getDouble(),arg1[1].getInt());} |
---|
| 288 | PARAMGETDEF(creature); |
---|
| 289 | PARAMGETDEF(part); |
---|
| 290 | PARAMGETDEF(joint); |
---|
| 291 | PARAMGETDEF(position_x); |
---|
| 292 | PARAMGETDEF(position_y); |
---|
| 293 | PARAMGETDEF(position_z); |
---|
| 294 | PARAMGETDEF(fields); |
---|
| 295 | PARAMGETDEF(neurodef); |
---|
| 296 | #undef STATRICKCLASS |
---|
| 297 | }; |
---|
| 298 | |
---|
| 299 | #endif |
---|