source: cpp/frams/neuro/neuroimpl.h @ 918

Last change on this file since 918 was 721, checked in by Maciej Komosinski, 7 years ago

Code formatting

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