evorobotexperiment.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it> *
6  * Gianluca Massera <emmegian@yahoo.it> *
7  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the Free Software *
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
22  ********************************************************************************/
23 
24 #include "evorobotexperiment.h"
25 #include "sensors.h"
26 #include "motors.h"
27 #include "evoga.h"
28 #include "configurationhelper.h"
29 #include "factory.h"
30 #include "logger.h"
31 
32 #include <QFile>
33 #include <QTextStream>
34 #include <QString>
35 #include <QTime>
36 #include <QThread>
37 #include <iostream>
38 #include <cstdlib>
39 
40 // All the suff below is to avoid warnings on Windows about the use of unsafe
41 // functions. This should be only a temporary workaround, the solution is stop
42 // using C string and file functions...
43 #if defined(_MSC_VER)
44  #pragma warning(push)
45  #pragma warning(disable:4996)
46 #endif
47 
48 namespace farsa {
49 
50 /*
51  * Experiment constructor
52  */
54 {
55  ga = NULL;
56  world = NULL;
57  savedConfigurationParameters = NULL;
58  savedPrefix = NULL;
59  ntrial = 0;
60  stopCurrentTrial = false;
61  skipCurrentTrial = false;
62  restartCurrentTrial = false;
63  endCurrentIndividualLife = false;
64  arena = NULL;
65  agentIdSelected = 0;
66 
67  gaPhase = NONE;
68 
69  // fitness and additional fitness components are not displayed by default
70 
71  // By default we don't run in batch mode
72  batchRunning = false;
73 
74  // Stating which resources we use here. This is here in the constructor so that we are sure to
75  // be the first to declare resources (if we did this later we should have used addUsableResources
76  // because child classes could declare they will use resources before us)
77  usableResources( QStringList() << "world" << "arena" << "experiment" << "robot" << "evonet" << "neuronsIterator" );
78 }
79 
81 {
82  // Removing resources
83  try {
84  deleteResource("experiment");
85  deleteResource("arena");
86  deleteResource("world");
87  deleteResource("robot");
88  deleteResource("evonet");
89  deleteResource("neuronsIterator");
90  } catch (...) {
91  // Doing nothing, this is here just to prevent throwing an exception from the destructor
92  }
93 
94  foreach( EmbodiedAgent* agent, eagents ) {
95  delete agent;
96  }
97 
98  delete savedConfigurationParameters;
99  delete savedPrefix;
100  delete arena;
101  delete world;
102 }
103 
105 {
106  // Saving configuration parameters and prefix for cloning
107  delete savedConfigurationParameters;
108  delete savedPrefix;
109  savedConfigurationParameters = new ConfigurationParameters(params);
110  savedConfigurationParameters->shareObserversWith(params);
111  savedPrefix = new QString(prefix);
112  // Setting ourself as resource manager in the configuration parameters object
113  params.setResourcesUser(this);
114  savedConfigurationParameters->setResourcesUser(this);
115 
116  ntrials = 1;
117  nsteps = 1;
118 
119  batchRunning = ConfigurationHelper::getBool(params, "__INTERNAL__/BatchRunning", batchRunning); // If we are running in batch or not
120  ntrials = ConfigurationHelper::getInt(params, prefix + "ntrials", ntrials); // number of trials to do
121  notifyChangesToParam( "ntrials" );
122  nsteps = ConfigurationHelper::getInt(params, prefix + "nsteps", nsteps); // number of step for each trial
123 
124  // create a World by default in order to exit from here with all configured properly
125  // if they are already created it will not destroy and recreate
126  recreateWorld();
127  // Creates the arena (if the group Arena is present)
128  recreateArena();
129  // Creates the Embodied Agents
130  // number of agents to create
131  int nagents = ConfigurationHelper::getInt(params, prefix + "nagents", 1);
132  if ( nagents > 1 ) {
133  // refactor the configuration parameters and create a subgroup foreach agent
134  for( int i=0; i<nagents; i++ ) {
135  QString agentPrefix = prefix + "AGENT:" + QString::number(i) + "/";
136  savedConfigurationParameters->createGroup( agentPrefix );
137  savedConfigurationParameters->copyGroupTree( prefix+"ROBOT", agentPrefix+"ROBOT" );
138  savedConfigurationParameters->copyGroupTree( prefix+"NET", agentPrefix+"NET" );
139  QStringList sensorsList = savedConfigurationParameters->getGroupsWithPrefixList(prefix, "Sensor:");
140  foreach( QString sensorGroup, sensorsList ) {
141  savedConfigurationParameters->copyGroupTree( prefix+sensorGroup, agentPrefix+sensorGroup );
142  }
143  QStringList motorsList = savedConfigurationParameters->getGroupsWithPrefixList(prefix, "Motor:");
144  foreach( QString motorGroup, motorsList ) {
145  savedConfigurationParameters->copyGroupTree( prefix+motorGroup, agentPrefix+motorGroup );
146  }
147  eagents.append( new EmbodiedAgent(i, agentPrefix, this) );
148  eagents.last()->configure();
149  }
150  } else {
151  eagents.append( new EmbodiedAgent(0, prefix, this) );
152  eagents.last()->configure();
153  }
154  selectAgent(0);
155 
156  // Adding robots to the arena (if the arena exists)
157  if (arena != NULL) {
158  QStringList robots;
159  foreach(EmbodiedAgent* e, eagents) {
160  robots.append(e->resourcePrefix+"robot");
161  }
162  arena->addRobots(robots);
163  }
164 
165  // declaring other resources
166  declareResource( "experiment", static_cast<ParameterSettableWithConfigureFunction*>(this) );
167 
168  Logger::info( params.getValue(prefix+"type") + " Configured" );
169 }
170 
172 {
173  Logger::error("NOT IMPLEMENTED (EvoRobotExperiment::save)");
174  abort();
175 }
176 
177 void EvoRobotExperiment::describe( QString type ) {
178  Descriptor d = addTypeDescription( type, "The experimental setup that defines the conditions and the fitness function of the evolutionary experiment" );
179  d.describeInt( "ntrials" ).def(1).limits(1,MaxInteger).runtime( &EvoRobotExperiment::setNTrials, &EvoRobotExperiment::getNTrials ).help("The number of trials the individual will be tested to calculate its fitness");
180  d.describeInt( "nsteps" ).def(1).limits(1,MaxInteger).help("The number of step a trials will last");
181  d.describeInt( "nagents" ).def(1).limits(1,MaxInteger).help("The number of embodied agents to create", "This parameter allow to setup experiments with more than one robot; all agents are clones");
182  d.describeSubgroup( "NET" ).props( IsMandatory ).type( "Evonet" ).help( "The Neural Network controlling the robot");
183  d.describeSubgroup( "ROBOT" ).props( IsMandatory ).type( "Robot" ).help( "The robot");
184  d.describeSubgroup( "Sensor" ).props( AllowMultiple ).type( "Sensor" ).help( "One of the Sensors from which the neural network will receive information about the environment" );
185  d.describeSubgroup( "Motor" ).props( AllowMultiple ).type( "Motor" ).help( "One of the Motors with which the neural network acts on the robot and on the environment" );
186  d.describeSubgroup( "Arena" ).type( "Arena" ).help( "The arena where robots live");
187 
188  SubgroupDescriptor world = d.describeSubgroup( "World" ).help( "Parameters affecting the simulated World" );
189  world.describeReal( "timestep" ).def(0.05).runtime( &EvoRobotExperiment::setWorldTimestep, &EvoRobotExperiment::getWorldTimeStep ).help( "The time in seconds corresponding to one simulated step of the World" );
190 }
191 
193 {
194  if (!batchRunning) {
195  // preventing gas from using multithread, which is not supported if the GUI is present
197  }
198  // Doing evolution by default
199  gaPhase=EvoRobotExperiment::INEVOLUTION;
200 }
201 
202 void EvoRobotExperiment::doTrial()
203 {
204  restartCurrentTrial = false;
205  stopCurrentTrial = false;
206  trialFitnessValue = 0.0;
207  for(nstep = 0; nstep < nsteps; nstep++) {
208  initStep( nstep );
209  if ( ga->commitStep() || restartCurrentTrial ) {
210  break;
211  }
212  doStep();
213  if ( ga->commitStep() ) break;
214  endStep( nstep );
215  if (ga->commitStep() || stopCurrentTrial || restartCurrentTrial) {
216  break;
217  }
218  }
219 }
220 
222 {
223  endCurrentIndividualLife = false;
224  totalFitnessValue = 0.0;
225 
226  initIndividual(individual);
227  if ( ga->commitStep() ) return;
228 
229  for (ntrial = 0; ntrial < ntrials; ntrial++) {
230  skipCurrentTrial = false;
231 
232  initTrial(ntrial);
233  if ( ga->commitStep() ) break;
234  if (skipCurrentTrial) { // && !ga->commitStep()) {
235  continue;
236  }
237  if (!endCurrentIndividualLife) {
238  doTrial();
239  }
240  if ( ga->isStopped() ) break;
241  if (restartCurrentTrial) {
242  ntrial--;
243  continue;
244  }
245  endTrial(ntrial);
246 
247  if (gaPhase == INTEST) {
248  Logger::info("Fitness for trial: " + QString::number(trialFitnessValue));
249  }
250 
251  if ( ga->commitStep() || endCurrentIndividualLife ) {
252  break;
253  }
254 
255  }
256 
257  endIndividual(individual);
258  ga->commitStep();
259 }
260 
262 {
263 }
264 
266 {
267 }
268 
270 {
271  // reset the neural controller
272  ResourcesLocker locker(this);
273  foreach( EmbodiedAgent* agent, eagents ) {
274  agent->evonet->resetNet();
275  }
276 }
277 
279 {
280 }
281 
283 {
284  return totalFitnessValue;
285 }
286 
288 {
289 }
290 
292 {
293 }
294 
296 {
297 }
298 
300 {
302 }
303 
305 {
306 }
307 
309 {
310 }
311 
312 void EvoRobotExperiment::doStep()
313 {
314  // There is no getResource below, but we are actually using resources so we must take the lock.
315  // We don't acquire the lock here, but lock and unlock when needed in the body of the function
316  ResourcesLocker locker(this, false);
317 
318  // update sensors
319  foreach( EmbodiedAgent* agent, eagents ) {
320  for (int s = 0; s < agent->sensors.size(); s++) {
321  agent->sensors[s]->update();
322  }
323  }
325  // update the neural controller
326  locker.lock();
327  foreach( EmbodiedAgent* agent, eagents ) {
328  agent->evonet->updateNet();
329  }
330  locker.unlock();
331  if (!batchRunning) {
332  // To use platform-independent sleep functions we have to do this...
333  class T : public QThread
334  {
335  public:
336  using QThread::sleep;
337  using QThread::msleep;
338  using QThread::usleep;
339  };
340  // We sleep for few milliseconds when the GUI is active to avoid flooding it with
341  // events and freeze it
342  T::msleep(3);
343  }
345  // setting motors
346  foreach( EmbodiedAgent* agent, eagents ) {
347  for (int m = 0; m < agent->motors.size(); m++) {
348  agent->motors[m]->update();
349  }
350  }
352  // advance the world simulation
353  locker.lock();
354  if (arena != NULL) {
356  }
357  world->advance();
358  if (arena != NULL) {
360  }
361  locker.unlock();
362 }
363 
365 {
366  stopCurrentTrial = true;
367 }
368 
370 {
371  skipCurrentTrial = true;
372 }
373 
375 {
376  restartCurrentTrial = true;
377 }
378 
380 {
381  endCurrentIndividualLife = true;
382  stopCurrentTrial = true;
383 }
384 
386 {
387  ResourcesLocker locker(this);
388 
389  return eagents[0]->evonet->freeParameters();
390 }
391 
392 Sensor* EvoRobotExperiment::getSensor( QString name, int id ) {
393  if ( eagents[id]->sensorsMap.contains( name ) ) {
394  return eagents[id]->sensorsMap[name];
395  } else {
396  Logger::error( "getSensor returned NULL pointer because there is no sensor named "+name+" in the agent "+QString::number(id) );
397  return NULL;
398  }
399 }
400 
401 Motor* EvoRobotExperiment::getMotor( QString name, int id ) {
402  if ( eagents[id]->motorsMap.contains( name ) ) {
403  return eagents[id]->motorsMap[name];
404  } else {
405  Logger::error( "getMotor returned NULL pointer because there is no motor named "+name+" in the agent "+QString::number(id) );
406  return NULL;
407  }
408 }
409 
411 {
412  return batchRunning;
413 }
414 
416  return eagents.size();
417 }
418 
420  agentIdSelected = id;
421  declareResource( "robot",
422  eagents[agentIdSelected]->robot,
423  eagents[agentIdSelected]->resourcePrefix+"robot" );
424  declareResource( "evonet",
425  static_cast<farsa::ParameterSettable*>(eagents[agentIdSelected]->evonet),
426  eagents[agentIdSelected]->resourcePrefix+"evonet" );
427  declareResource( "neuronsIterator",
428  eagents[agentIdSelected]->neuronsIterator,
429  eagents[agentIdSelected]->resourcePrefix+"neuronsIterator" );
430 }
431 
433 {
434  return eagents[id]->evonet;
435 }
436 
438 {
439  this->ga = ga;
440 }
441 
443  return ga;
444 }
445 
447 {
448  ResourcesLocker locker(this);
449  foreach( EmbodiedAgent* agent, eagents ) {
450  agent->evonet->getParameters(genes);
451  }
452 }
453 
455 {
456  Logger::error("EvoRobotExperiment::setTestingAgentAndSeed() not yet implemented");
457 }
458 
460  // Saving the old robot, the old arena and world to delete them after the new world has been
461  // created (as world is a resource, we need the old instance to exists during notifications.
462  // It can be safely deleted afterward)
463  World* const old_world = world;
464 
465  // TODO: parametrize the name and the dontUseYarp and all other parameters
466  world = new World( "World", true );
467  world->setTimeStep(0.05f);
468  world->setSize( wVector( -2.0f, -2.0f, -0.50f ), wVector( +2.0f, +2.0f, +2.0f ) );
469  world->setFrictionModel( "exact" );
470  world->setSolverModel( "exact" );
471  world->setMultiThread( 1 );
472 
473  // Removing deleted resources (if they existed) and then re-declaring world
474  if ( arena != NULL ) {
475  deleteResource( "arena" );
476  delete arena;
477  arena = NULL;
478  }
479 
480  if ( eagents.size() > 0 ) {
481  deleteResource( "robot" );
482  for( int i=0; i<eagents.size(); i++ ) {
483  deleteResource( eagents[i]->resourcePrefix+"robot" );
484  delete eagents[i]->robot;
485  eagents[i]->robot = NULL;
486  }
487  }
488 
489  declareResource( "world", world );
490 
491  // Now we can actually free memory
492  delete old_world;
493 }
494 
496  eagents[id]->recreateRobot();
497  if ( id == agentIdSelected ) {
498  // rebind the resource of the robot
499  declareResource( "robot",
500  eagents[agentIdSelected]->robot,
501  eagents[agentIdSelected]->resourcePrefix+"robot" );
502  }
503 }
504 
506  // First of all we need to check whether there is an Arena group or not
507  if (!ConfigurationHelper::hasGroup( *savedConfigurationParameters, (*savedPrefix) + "Arena" ) ) {
508  // This is just to be sure...
509  arena = NULL;
510  return;
511  }
512 
513  // to be sure that a World exist
514  if ( !world ) {
515  recreateWorld();
516  }
517 
518  // Taking lock because we need to use world
519  ResourcesLocker locker(this);
520  // Saving the old arena to delete it after the new arena has been created
521  Arena* const old_arena = arena;
522 
523  // Now creating the arena. We first set ourself as the resouce manager
524  savedConfigurationParameters->setResourcesUser(this);
525  arena = savedConfigurationParameters->getObjectFromGroup<Arena>((*savedPrefix) + "Arena");
526  arena->shareResourcesWith(this);
527  QStringList robots;
528  foreach(EmbodiedAgent* e, eagents) {
529  robots.append(e->resourcePrefix+"robot");
530  }
531  arena->addRobots(robots);
532 
533  // Unlocking before redeclaring the arena resource
534  locker.unlock();
535 
536  declareResource("arena", static_cast<Resource*>(arena), "world");
537  delete old_arena;
538 }
539 
541  eagents[id]->recreateNeuralNetwork();
542  if ( id == agentIdSelected ) {
543  // rebind the resource of the evonet
544  declareResource( "evonet",
545  eagents[agentIdSelected]->robot,
546  eagents[agentIdSelected]->resourcePrefix+"evonet" );
547  }
548 }
549 
550 void EvoRobotExperiment::setWorldTimestep( float timestep ) {
551  ResourcesLocker locker(this);
552  if ( !world ) return;
553  world->setTimeStep( timestep );
554 }
555 
556 float EvoRobotExperiment::getWorldTimeStep() const {
557  ResourcesLocker locker((ConcurrentResourcesUser*)(this));
558  if ( !world ) {
559  return 0.05f;
560  } else {
561  return world->timeStep();
562  }
563 }
564 
565 EvoRobotExperiment::EmbodiedAgent::EmbodiedAgent( int id, QString agentPath, EvoRobotExperiment* exp ) {
566  this->id = id;
567  this->agentPath = agentPath;
568  this->exp = exp;
569  evonet = NULL;
570  neuronsIterator = new EvonetIterator();
571  robot = NULL;
572  resourcePrefix = QString("agent[%1]:").arg(id);
573 }
574 
575 void EvoRobotExperiment::EmbodiedAgent::configure() {
576  exp->savedConfigurationParameters->setResourcesUser(exp);
577  // add to the experiment the resources will create here
578  exp->addUsableResource( resourcePrefix+"evonet" );
579  recreateRobot();
580 
581  // Reading the sensors parameters. For each sensor there must be a subgroup Sensor:NN where NN is a progressive number
582  // (needed to specify the sensors order). Here we also actually create sensors
583  QStringList sensorsList = exp->savedConfigurationParameters->getGroupsWithPrefixList(agentPath, "Sensor:");
584  sensorsList.sort();
585  foreach( QString sensorGroup, sensorsList ) {
586  // Trick for injecting the correct resource names for robot and neuronsIterator
587  // !! WARNING !! this tricks works for some specific group of sensors
588  // if some others will be added, also this trick has to be adapted
589  exp->savedConfigurationParameters->createParameter(
590  agentPath+sensorGroup, "neuronsIterator", resourcePrefix+"neuronsIterator" );
591  exp->savedConfigurationParameters->createParameter(
592  agentPath+sensorGroup, "icub", resourcePrefix+"robot" );
593  exp->savedConfigurationParameters->createParameter(
594  agentPath+sensorGroup, "marxbot", resourcePrefix+"robot" );
595  exp->savedConfigurationParameters->createParameter(
596  agentPath+sensorGroup, "epuck", resourcePrefix+"robot" );
597  // !! END OF TRICK !!
598  Sensor* sensor = exp->savedConfigurationParameters->getObjectFromGroup<Sensor>(agentPath + sensorGroup);
599  if ( sensor == NULL ) {
600  Logger::error("Cannot create the Sensor from group " + *(exp->savedPrefix) + sensorGroup + ". Aborting");
601  abort();
602  }
603  // in order to avoid name clash when using more than one Sensor,
604  // the Sensors are renamed using the same name of the Group when they don't have a name assigned
605  if ( sensor->name() == QString("unnamed") ) {
606  sensor->setName( sensorGroup );
607  }
608  sensors.append( sensor );
609  sensors.last()->shareResourcesWith( exp );
610  Logger::info( "Created a Sensor named "+sensor->name() );
611  // if the user manually set the name and create a name clash, it is only reported as error in Logger
612  if ( sensorsMap.contains( sensor->name() ) ) {
613  Logger::error( "More than one sensor has name "+sensor->name()+" !! The name has to be unique !!" );
614  } else {
615  // add to the map
616  sensorsMap[sensor->name()] = sensor;
617  }
618  }
619 
620  // Now we do for motors what we did for sensors. Motor groups are in the form Motor:NN
621  QStringList motorsList = exp->savedConfigurationParameters->getGroupsWithPrefixList(agentPath, "Motor:");
622  motorsList.sort();
623  foreach( QString motorGroup, motorsList ) {
624  // Trick for injecting the correct resource names for robot and neuronsIterator
625  // !! WARNING !! this tricks works for some specific group of sensors
626  // if some others will be added, also this trick has to be adapted
627  exp->savedConfigurationParameters->createParameter(
628  agentPath+motorGroup, "neuronsIterator", resourcePrefix+"neuronsIterator" );
629  exp->savedConfigurationParameters->createParameter(
630  agentPath+motorGroup, "icub", resourcePrefix+"robot" );
631  exp->savedConfigurationParameters->createParameter(
632  agentPath+motorGroup, "marxbot", resourcePrefix+"robot" );
633  exp->savedConfigurationParameters->createParameter(
634  agentPath+motorGroup, "epuck", resourcePrefix+"robot" );
635  // !! END OF TRICK !!
636  Motor* motor = exp->savedConfigurationParameters->getObjectFromGroup<Motor>(agentPath + motorGroup);
637  if (motor == NULL) {
638  Logger::error("Cannot create the Motor from group " + *(exp->savedPrefix) + motorGroup + ". Aborting");
639  abort();
640  }
641  // in order to avoid name clash when using more than one Motor,
642  // the Motors are renamed using the same name of the Group when they don't have a name assigned
643  if ( motor->name() == QString("unnamed") ) {
644  motor->setName( motorGroup );
645  }
646  motors.append( motor );
647  motors.last()->shareResourcesWith( exp );
648  Logger::info( "Created a Motor named "+motor->name() );
649  // if the user manually set the name and create a name clash, it is only reported as error in Logger
650  if ( motorsMap.contains( motor->name() ) ) {
651  Logger::error( "More than one motor has name "+motor->name()+" !! The name has to be unique !!" );
652  } else {
653  // add to the map
654  motorsMap[motor->name()] = motor;
655  }
656  }
657 
658  recreateNeuralNetwork();
659 
660  exp->declareResource( resourcePrefix+"neuronsIterator", neuronsIterator, resourcePrefix+"evonet" );
661 }
662 
663 EvoRobotExperiment::EmbodiedAgent::~EmbodiedAgent() {
664  delete robot;
665  delete evonet;
666  delete neuronsIterator;
667  for (int i = 0; i < sensors.size(); i++) {
668  delete sensors[i];
669  }
670  for (int i = 0; i < motors.size(); i++) {
671  delete motors[i];
672  }
673 }
674 
675 void EvoRobotExperiment::EmbodiedAgent::recreateRobot() {
676  // to be sure that a World exist
677  if ( !(exp->world) ) {
678  exp->recreateWorld();
679  }
680 
681  // Taking lock because we need to use world
682  ResourcesLocker locker(exp);
683  // Saving the old robot to delete it after the new robot has been created
684  Robot* const old_robot = robot;
685 
686  // Now creating the robot
687  exp->savedConfigurationParameters->setResourcesUser(exp);
688  robot = exp->savedConfigurationParameters->getObjectFromGroup<Robot>(agentPath + "ROBOT");
689 
690  // Unlocking before redeclaring the robot resource
691  locker.unlock();
692 
693  exp->declareResource( resourcePrefix+"robot", robot, "world" );
694  delete old_robot;
695 }
696 
697 void EvoRobotExperiment::EmbodiedAgent::recreateNeuralNetwork() {
698  // Saving the old evonet to delete it after the new evonet has been created
699  Evonet* const old_evonet = evonet;
700 
701  // Check the subgroup [NET]
702  if ( exp->savedConfigurationParameters->getValue( agentPath+"NET/netFile" ).isEmpty() ) {
703  // calculate the number of sensors and motors neurons
704  int nSensors = 0;
705  foreach( Sensor* sensor, sensors ) {
706  nSensors += sensor->size();
707  }
708  int nMotors = 0;
709  foreach( Motor* motor, motors ) {
710  nMotors += motor->size();
711  }
712  // it inject the calculated nSensor and nMotors
713  exp->savedConfigurationParameters->createParameter( agentPath+"NET", "nSensors", QString::number(nSensors) );
714  exp->savedConfigurationParameters->createParameter( agentPath+"NET", "nMotors", QString::number(nMotors) );
715  }
716  // Now creating the neural network. We first set ourself as the resouce manager, then we lock resources (because during configuration
717  // evonet could use resources, but the resource user it will use is not thread safe (SimpleResourceUser))
718  ResourcesLocker locker(exp);
719  exp->savedConfigurationParameters->setResourcesUser(exp);
720  evonet = exp->savedConfigurationParameters->getObjectFromGroup<Evonet>( agentPath+"NET" );
721  locker.unlock();
722 
723  exp->declareResource( resourcePrefix+"evonet", static_cast<farsa::ParameterSettable*>(evonet) );
724 
725  // Here we have to take the lock again because we are going to change neuronsIterator
726  locker.lock();
727  delete old_evonet;
728  neuronsIterator->setEvonet( evonet );
729  // create the blocks associated to the network
730  int startIndex = 0;
731  foreach( Sensor* sensor, sensors ) {
732  neuronsIterator->defineBlock( sensor->name(), EvonetIterator::InputLayer, startIndex, sensor->size() );
733  startIndex += sensor->size();
734  }
735  startIndex = 0;
736  foreach( Motor* motor, motors ) {
737  neuronsIterator->defineBlock( motor->name(), EvonetIterator::OutputLayer, startIndex, motor->size() );
738  startIndex += motor->size();
739  }
740 }
741 
742 } // end namespace farsa
743 
744 // All the suff below is to restore the warning state on Windows
745 #if defined(_MSC_VER)
746  #pragma warning(pop)
747 #endif