neuroninterfaces.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #include "neuroninterfaces.h"
24 #include "evonet.h"
25 #include "configurationhelper.h"
26 #include "logger.h"
27 #include "randomgenerator.h"
28 
29 namespace farsa {
30 
32  ParameterSettableInConstructor(params, prefix),
33  noiseType(NoNoise),
34  noiseRange(0.0),
35  noiseParameter(0.0)
36 {
37  QString noiseTypeStr = ConfigurationHelper::getString(params, prefix + "noiseType", "NoNoise").toUpper();
38  if (noiseTypeStr == "NONOISE") {
39  noiseType = NoNoise;
40  } else if (noiseTypeStr == "UNIFORM") {
41  noiseType = Uniform;
42  } else if (noiseTypeStr == "GAUSSIAN") {
43  noiseType = Gaussian;
44  } else {
45  ConfigurationHelper::throwUserConfigError("noiseType", params.getValue(prefix + "noiseType"), "The noiseType must be one of NoNoise, Uniform or Gaussian");
46  }
47  noiseRange = ConfigurationHelper::getDouble(params, prefix + "noiseRange", 0.0);
48  if (noiseRange < 0.0) {
49  ConfigurationHelper::throwUserConfigError("noiseRange", params.getValue(prefix + "noiseRange"), "The noiseRange parameter must be a real value greater or equal to 0");
50  }
51 
52  // Computing the parameter used when applying noise. It depends on the type of noise to apply
53  switch (noiseType) {
54  case NoNoise:
55  noiseParameter = 0.0;
56  break;
57  case Uniform:
58  noiseParameter = noiseRange / 2.0;
59  break;
60  case Gaussian:
61  noiseParameter = (noiseRange * noiseRange) / 16.0; // i.e. (noiseRange/4.0)^2
62  break;
63  }
64 }
65 
67 {
68 }
69 
70 void NoisyDevice::save( ConfigurationParameters& params, QString prefix )
71 {
72  params.startObjectParameters( prefix, "NoisyDevice", this );
73  QString noiseTypeStr;
74  switch (noiseType) {
75  case NoNoise:
76  noiseTypeStr = "NoNoise";
77  break;
78  case Uniform:
79  noiseTypeStr = "Uniform";
80  break;
81  case Gaussian:
82  noiseTypeStr = "Gaussian";
83  break;
84  }
85  params.createParameter(prefix, "noiseType", noiseTypeStr);
86  params.createParameter(prefix, "noiseRange", QString::number(noiseRange));
87 }
88 
89 void NoisyDevice::describe( QString type )
90 {
91  Descriptor d = addTypeDescription( type, "Base class for all noisy devices (sensors and motors)" );
92  d.describeEnum("noiseType").def("NoNoise").values(QStringList() << "NoNoise" << "Uniform" << "Gaussian").help("The type of noise to add to sensor readings", "This must be one of NoNoise, Uniform or Gaussian. Notice that not all sensors respect the value of this parameter (some may never add noise). See sensor description for more information");
93  d.describeReal("noiseRange").def(0.0f).limits(0.0,+Infinity).help("The range of noise", "For uniform noise this is the actual range, (the distribution has zero mean and goes from -noiseRange/2 to noiseRange/2). For gaussian noise, this is four times the standard deviation (the distribution has zero mean and noiseRange/4 standard deviation: this means that about 95% of the values taken from the distribution will be between -noiseRange/2 and noiseRange/2)");
94 }
95 
96 double NoisyDevice::applyNoise(double v, double minValue, double maxValue) const
97 {
98  // Adding noise
99  switch (noiseType) {
100  case NoNoise:
101  // Nothing to do
102  break;
103  case Uniform:
104  v += globalRNG->getDouble(-noiseParameter, noiseParameter);
105  break;
106  case Gaussian:
107  v += globalRNG->getGaussian(noiseParameter, 0.0);
108  break;
109  }
110 
111  // Restricting v between minValue and maxValue if we have to
112  if (minValue <= maxValue) {
113  if (v < minValue) {
114  v = minValue;
115  } else if (v > maxValue) {
116  v = maxValue;
117  }
118  }
119 
120  return v;
121 }
122 
123 Sensor::Sensor( ConfigurationParameters& params, QString prefix ) :
124  NoisyDevice(params, prefix),
125  allNeededResourcesExist(false)
126 {
127  setName( ConfigurationHelper::getString( params, prefix+"name", "unnamed" ) );
128  resourcePrefix = ConfigurationHelper::getString( params, prefix + "__resourcePrefix__", "" );
129 }
130 
132 }
133 
134 void Sensor::save( ConfigurationParameters& params, QString prefix ) {
135  // Calling parent function
136  NoisyDevice::save(params, prefix);
137 
138  params.startObjectParameters( prefix, "Sensor", this );
139  // if Sensor name startsWith "Sensor:" means that the name has been
140  // configured by EvoRobotExperiment automatically
141  if ( sensorName != "unnamed" || !sensorName.startsWith("Sensor:") ) {
142  params.createParameter( prefix, "name", sensorName );
143  }
144 
145  // Here we don't save the __resourcePrefix__ parameter because it is only used internally
146 }
147 
148 void Sensor::describe( QString type ) {
149  // Calling parent function
150  NoisyDevice::describe(type);
151 
152  Descriptor d = addTypeDescription( type, "Base class for all Sensors" );
153  d.describeString( "name" ).help( "The name of the sensor" );
154  // Here we don't describe the __resourcePrefix__ parameter because it is only used internally
155 }
156 
157 QString Sensor::name() {
158  return sensorName;
159 }
160 
161 void Sensor::setName( QString name ) {
162  sensorName = name;
163 }
164 
166  if (allNeededResourcesExist) {
167  return;
168  }
169 
170  // We do the check only if allNeededResourcesExist is false, if it is true we already did the
171  // check and we will be notified when a resource gets deleted
172  QStringList nonExistingResources;
173  if (!usedResourcesExist(&nonExistingResources)) {
174  ConfigurationHelper::throwUserMissingResourceError(nonExistingResources.join(", "), "Some required resource do not exist, cannot use " + sensorName + " anymore");
175  }
176 
177  allNeededResourcesExist = true;
178 }
179 
181 {
182  allNeededResourcesExist = false;
183 }
184 
185 QString Sensor::actualResourceNameForMultirobot(QString resourceName) const
186 {
187  return resourcePrefix + resourceName;
188 }
189 
190 Motor::Motor( ConfigurationParameters& params, QString prefix ) :
191  NoisyDevice(params, prefix),
192  allNeededResourcesExist(false)
193 {
194  setName( ConfigurationHelper::getString( params, prefix+"name", "unnamed" ) );
195  resourcePrefix = ConfigurationHelper::getString( params, prefix + "__resourcePrefix__", "" );
196 }
197 
199 }
200 
201 void Motor::save( ConfigurationParameters& params, QString prefix ) {
202  // Calling parent function
203  NoisyDevice::save(params, prefix);
204 
205  params.startObjectParameters( prefix, "Motor", this );
206  // if Motor name startsWith "Motor:" means that the name has been
207  // configured by EvoRobotExperiment automatically
208  if ( motorName != "unnamed" || !motorName.startsWith("Motor:") ) {
209  params.createParameter( prefix, "name", motorName );
210  }
211  // Here we don't save the __resourcePrefix__ parameter because it is only used internally
212 }
213 
214 void Motor::describe( QString type ) {
215  // Calling parent function
216  NoisyDevice::describe(type);
217 
218  Descriptor d = addTypeDescription( type, "Base class for all Motors" );
219  d.describeString( "name" ).help( "The name of the motor" );
220  // Here we don't describe the __resourcePrefix__ parameter because it is only used internally
221 }
222 
223 QString Motor::name() {
224  return motorName;
225 }
226 
227 void Motor::setName( QString name ) {
228  motorName = name;
229 }
230 
232  if (allNeededResourcesExist) {
233  return;
234  }
235 
236  // We do the check only if allNeededResourcesExist is false, if it is true we already did the
237  // check and we will be notified when a resource gets deleted
238  QStringList nonExistingResources;
239  if (!usedResourcesExist(&nonExistingResources)) {
240  ConfigurationHelper::throwUserMissingResourceError(nonExistingResources.join(", "), "Some required resource do not exist, cannot use " + motorName + " anymore");
241  }
242 
243  allNeededResourcesExist = true;
244 }
245 
247 {
248  allNeededResourcesExist = false;
249 }
250 
251 QString Motor::actualResourceNameForMultirobot(QString resourceName) const
252 {
253  return resourcePrefix + resourceName;
254 }
255 
257  blocks(),
258  currLayer(InputLayer),
259  currStartIndex(-1),
260  currEndIndex(0),
261  currIndex(0),
262  evonet(NULL) {
263 }
264 
266  /* nothing to do */
267 }
268 
270  this->evonet = evonet;
271  blocks.clear();
272  currStartIndex = -1;
273  currEndIndex = 0;
274  currIndex = 0;
275 }
276 
278  return evonet;
279 }
280 
281 void EvonetIterator::defineBlock( QString name, layer_t layer, int startIndex, int size ) {
282  BlockInfo binfo;
283  binfo.layer = layer;
284  binfo.startIndex = startIndex;
285  binfo.endIndex = startIndex + size;
286  blocks[name] = binfo;
287 }
288 
289 bool EvonetIterator::setCurrentBlock( QString blockName ) {
290  if ( !blocks.contains( blockName ) ) {
291  throw EvonetIteratorInvalidStatusException( "setCurrentBlock", QString("EvonetIterator - the block %1 does not exist").arg(blockName).toLatin1().data());
292  }
293  BlockInfo binfo = blocks[blockName];
294  currLayer = binfo.layer;
295  currStartIndex = binfo.startIndex;
296  currEndIndex = binfo.endIndex;
297  currIndex = currStartIndex;
298  return true;
299 }
300 
302  checkCurrentStatus( "nextNeuron" );
303 
304  currIndex++;
305  if ( currIndex >= currEndIndex ) {
306  return false;
307  }
308  return true;
309 }
310 
311 void EvonetIterator::setInput( double value ) {
312  checkCurrentStatus( "setInput" );
313 
314  evonet->setInput( currIndex, value );
315 }
316 
318  checkCurrentStatus( "getInput" );
319 
320  return evonet->getInput( currIndex );
321 }
322 
324  checkCurrentStatus( "getOutput" );
325 
326  return evonet->getOutput( currIndex );
327 }
328 
329 void EvonetIterator::setGraphicProperties( QString label, double minValue, double maxValue, QColor color ) {
330  checkCurrentStatus( "setGraphicProperties" );
331 
332  label.truncate( 9 );
333  int offsetIndex = 0;
334  if ( currLayer == OutputLayer ) {
335  offsetIndex = evonet->getNoInputs() + evonet->getNoHiddens();
336  }
337  sprintf( evonet->neuronl[ offsetIndex+currIndex ], "%s", label.toLatin1().data() );
338  evonet->neuronrange[ offsetIndex+currIndex ][0] = minValue;
339  evonet->neuronrange[ offsetIndex+currIndex ][1] = maxValue;
340  // FIXME: need to change how the color are handled into Evonet
341  evonet->neurondcolor[ offsetIndex+currIndex ] = color;
342  evonet->updateNeuronMonitor = true;
343 }
344 
345 void EvonetIterator::checkCurrentStatus( const QString& funcName ) const {
346  if ( !evonet ) {
347  throw EvonetIteratorInvalidStatusException( funcName.toLatin1().data(), "no Evonet object has ben set");
348  }
349  if ( currStartIndex < 0 ) {
350  throw EvonetIteratorInvalidStatusException( funcName.toLatin1().data(), "you should call setCurrentBlock first");
351  }
352  if ( currIndex >= currEndIndex ) {
353  throw EvonetIteratorInvalidStatusException( funcName.toLatin1().data(), "attempt to access beyond the size of the current block");
354  }
355 }
356 
357 } // end namespace farsa
static void describe(QString type)
Describe all the parameter for configuring the Sensor.
EvonetIterator()
Constructor.
double applyNoise(double v, double minValue, double maxValue) const
Adds noise to the value.
static void throwUserMissingResourceError(QString resourceName, QString description)
int getNoInputs()
return the number of sensory neurons
Definition: evonet.cpp:1196
QString actualResourceNameForMultirobot(QString resourceName) const
Returns the actual resource name to use.
FARSA_UTIL_API RandomGenerator * globalRNG
static QString getString(ConfigurationParameters &params, QString paramPath, QString def=QString())
void save(ConfigurationParameters &params, QString prefix)
Save the parameters into the ConfigurationParameters.
void setName(QString name)
Use this method for changing the name of the Sensor.
bool setCurrentBlock(QString blockName)
Set the current blocks of neurons to iterate.
layer_t
enum the possible layers on which the blocks can be defined
QString name()
Return the name of the Sensor.
static const double Infinity
QString name()
Return the name of the Sensor.
void checkAllNeededResourcesExist()
Checks whether all resources we need are existing and throws an exception if they aren't...
double getInput()
Get the input of the current neuron.
void resetNeededResourcesCheck()
Resets the check on needed resources so that the next call to checkAllNeededResourcesExist() will per...
Motor(ConfigurationParameters &params, QString prefix)
Constructor and Configure.
int setInput(int inp, float value)
set the value of a sensory neuron
Definition: evonet.cpp:1016
static void describe(QString type)
Describe all the parameter for configuring the Sensor.
static void throwUserConfigError(QString paramName, QString paramValue, QString description)
void setGraphicProperties(QString label, double minValue, double maxValue, QColor color)
Set the graphic properties for the current neuron (in case it will be visualized on a GUI) ...
bool updateNeuronMonitor
Set to true if labels or colors have to be updated in the neuron monitor.
Definition: evonet.h:431
The base abstract class for devices (sensors and motors) with noise.
~NoisyDevice()
Destructor.
virtual ~EvonetIterator()
Destructor.
void setEvonet(Evonet *evonet)
Set the Evonet on which iterate.
~Motor()
Destructor.
double getOutput()
Get the output of the current neuron.
Sensor(ConfigurationParameters &params, QString prefix)
Constructor and Configure.
Evonet * getEvonet()
Return the Evonet on which it will iterate on.
void save(ConfigurationParameters &params, QString prefix)
Save the parameters into the ConfigurationParameters.
QColor neurondcolor[MAXN]
the color used to display the actiovation state of each neuron in the neuron monitor widget ...
Definition: evonet.h:419
void resetNeededResourcesCheck()
Resets the check on needed resources so that the next call to checkAllNeededResourcesExist() will per...
bool usedResourcesExist(QStringList *nonExistingResources=NULL) const
bool startObjectParameters(QString groupPath, QString typeName, ParameterSettable *object)
float getInput(int in)
return the value of a sensory neuron
Definition: evonet.cpp:1033
static double getDouble(ConfigurationParameters &params, QString paramPath, double def=0)
static Descriptor addTypeDescription(QString type, QString shortHelp, QString longHelp=QString(""))
void defineBlock(QString name, layer_t layer, int startIndex, int size)
Define a block.
QString getValue(QString path, bool alsoMatchParents=false) const
QString actualResourceNameForMultirobot(QString resourceName) const
Returns the actual resource name to use.
Evonet is the neural network taken from the EvoRobot.
Definition: evonet.h:121
The exception thrown when EvonetIterator is not in a valid status.
int getNoHiddens()
return the number of internal neurons
Definition: evonet.cpp:1201
void setName(QString name)
Use this method for changing the name of the Sensor.
float getOutput(int out)
return the value of a motor neuron (-1 if the specified id is out of range)
Definition: evonet.cpp:1025
double getGaussian(double var, double mean=0.0)
double getDouble(double min, double max)
void save(ConfigurationParameters &params, QString prefix)
Save the parameters into the ConfigurationParameters.
NoisyDevice(ConfigurationParameters &params, QString prefix)
Constructor and Configure.
void checkAllNeededResourcesExist()
Checks whether all resources we need are existing and throws an exception if they aren't...
static void describe(QString type)
Describe all the parameter for configuring the Motor.
bool nextNeuron()
Go to the next neuron of the current block.
void setInput(double value)
Set the input of the current neuron.
~Sensor()
Destructor.
void createParameter(QString groupPath, QString parameter)
double neuronrange[MAXN][2]
the matrix that contain the variation range of neurons used by the neuron monitor graphic widget ...
Definition: evonet.h:415