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

Last change on this file since 1290 was 952, checked in by Maciej Komosinski, 4 years ago

Added new receptors (Gp:"gyroscope" on a Part, Tp:Touch-proximity and Tc:Touch-contact) and improved existing ones (T, G)

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