evorobotcomponent.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 "evorobotcomponent.h"
24 #include "evorobotviewer.h"
25 #include "abstracttest.h"
26 #include "tests.h"
27 #include "configurationhelper.h"
28 #include "logger.h"
29 
30 namespace farsa {
31 
34 public:
35  EvolveOperation( Evoga* ga, EvoRobotComponent* evorobot ) :
36  ga(ga),
37  evorobot(evorobot) { };
38  virtual ~EvolveOperation() { };
40  virtual void stop() {
41  ga->stop();
42  };
44  virtual void run() {
45  evorobot->setStatus( "In Evolution ..." );
46  ga->getEvoRobotExperiment()->setActivityPhase( EvoRobotExperiment::INEVOLUTION );
47  ga->evolveAllReplicas();
48  QString message;
49  if ( ga->isStopped() ) {
50  message = "Evolution Stopped";
51  } else {
52  message = "Evolution Finished";
53  }
54  // reset the stopped status
55  ga->resetStop();
56  evorobot->onThreadOperationDone( message );
57  };
58 private:
59  Evoga* ga;
60  EvoRobotComponent* evorobot;
61 };
62 
65 public:
66  TestOperation( AbstractTest* test, Evoga* ga, EvoRobotComponent* evorobot ) :
67  test(test),
68  ga(ga),
69  evorobot(evorobot) { };
70  virtual ~TestOperation() { };
72  virtual void stop() {
73  ga->stop();
74  };
76  virtual void run() {
77  evorobot->setStatus( QString("Running ")+test->menuText()+" ..." );
78  test->runTest();
79  QString message;
80  if ( ga->isStopped() ) {
81  message = "Test Stopped";
82  } else {
83  message = "Test Finished";
84  }
85  // reset the stopped status
86  ga->resetStop();
87  evorobot->onThreadOperationDone( message );
88  };
89 private:
90  AbstractTest* test;
91  Evoga* ga;
92  EvoRobotComponent* evorobot;
93 };
94 
96  : Component()
97  , ga(NULL)
98  , batchRunning(false)
99  , runningOperation(false)
100  , mutex()
101 {
102  gaThread = new WorkerThread( this );
103 
104  connect(gaThread, SIGNAL(exceptionDuringOperation(farsa::BaseException*)), this, SLOT(exceptionDuringOperation(farsa::BaseException*)), Qt::BlockingQueuedConnection);
105 }
106 
108  gaThread->quit();
109  delete gaThread;
110  delete ga;
111 }
112 
114  return new EvoRobotViewer( this );
115 }
116 
118  if ( ga ) {
119  // delete the previous GA
120  gaThread->quit();
121  delete gaThread;
122  delete ga;
123  }
124  batchRunning = ConfigurationHelper::getBool(params, "__INTERNAL__/BatchRunning", batchRunning);
125  ga = params.getObjectFromGroup<Evoga>( prefix+"GA" );
126 
127  // Now we also instantiate all test classes. The configuration file should have subgroups
128  // [TESTS:NN] where NN is a progressive number starting from zero.
129  // Each group describe the test (in particular the group must have a type
130  // parameter corresponding the the type of the Test to run).
131  // The tests indicated by the following boolean flags are added by default if not present on
132  // the configuration file
133 // bool testAllAdded = false;
134  bool testIndividualAdded = false;
135  bool testRandomAdded = false;
136 // bool testZeroAdded = false;
137  bool testCurrentAdded = false;
138  // clear the old content of currentTestName, it will be configured later
139  currentTestName = QString();
140  QStringList testGroups = params.getGroupsWithPrefixList( prefix, "TEST:" );
141  for( int i=0; i<testGroups.size(); i++ ) {
142  if ( i==0 ) {
143  //--- currentTestName is initially setted to contain the name of the first test specified by the user
144  currentTestName = testGroups[i];
145  }
146  AbstractTest* test = params.getObjectFromGroup<AbstractTest>(prefix+testGroups[i]);
147  test->setComponent( this );
148  AvailableTestList::addTest( testGroups[i], test );
149  /*
150  if (dynamic_cast<TestAll *>(test) != NULL) {
151  testAllAdded = true;
152  } else */ if (dynamic_cast<TestIndividual *>(test) != NULL) {
153  testIndividualAdded = true;
154  } else if (dynamic_cast<TestRandom *>(test) != NULL) {
155  testRandomAdded = true;
156  } else if (dynamic_cast<TestCurrent *>(test) != NULL) {
157  testCurrentAdded = true;
158  } /* else if (dynamic_cast<TestZero *>(test) != NULL) {
159  testZeroAdded = true;
160  } */
161  }
162  /*
163  if (!testAllAdded) {
164  // TestAll is not present among tests configured by the user, adding it. We know for sure
165  // TestAll doesn't need to be configured, so we don't
166  AbstractTest* test = new TestAll();
167  test->setComponent( this );
168  AvailableTestList::addTest("TestAll", test);
169  }
170  */
171  if (!testIndividualAdded) {
172  // TestBest is not present among tests configured by the user, adding it. We know for sure
173  // TestBest doesn't need to be configured, so we don't
174  AbstractTest* test = new TestIndividual();
175  test->setComponent( this );
176  AvailableTestList::addTest("TestIndividual", test);
177  }
178  if (!testRandomAdded) {
179  // TestRandom is not present among tests configured by the user, adding it. We know for sure
180  // TestRnadom doesn't need to be configured, so we don't
181  AbstractTest* test = new TestRandom();
182  test->setComponent( this );
183  AvailableTestList::addTest("TestRandom", test);
184  }
185  if (!testCurrentAdded) {
186  // TestRandom is not present among tests configured by the user, adding it. We know for sure
187  // TestRnadom doesn't need to be configured, so we don't
188  AbstractTest* test = new TestCurrent();
189  test->setComponent( this );
190  AvailableTestList::addTest("TestCurrent", test);
191  }
192  /*
193  if(!testZeroAdded) {
194  // TestZero is not present among tests configured by the user, adding it. We know for sure
195  // TestZero doesn't need to be configured, so we don't
196  AbstractTest* test = new TestZero();
197  test->setComponent( this );
198  AvailableTestList::addTest("TestZero", test);
199  }
200  */
201 
202  if ( currentTestName.isEmpty() ) {
203  // there is no tests specified by the user and then the defaul currentTestName in this
204  // case will be the automatically added "TestIndividual"
205  currentTestName = "TestIndividual";
206  }
207  currentTestName = ConfigurationHelper::getString( params, prefix+"testToRun", currentTestName );
208 
209  // start the innerThread
210  gaThread->start();
211 
212  setStatus( "Configured" );
213 }
214 
216  ga->save( params, prefix+"/GA" );
217 }
218 
220 }
221 
223 {
224  stop();
225 }
226 
227 void EvoRobotComponent::describe( QString type ) {
228  Descriptor d = addTypeDescription( type, "This component allow to do evolutionary robotics experiments" );
229  d.describeSubgroup( "GA" ).type( "Evoga" ).props( IsMandatory ).help( "The Genetic Algorithm to use to perform the evolutionary process" );
230  d.describeSubgroup( "TEST" ).type( "AbstractTest" ).props( AllowMultiple ).help( "let to configure a test condition for the evolved individual" );
231 }
232 
234  return ga;
235 }
236 
238  gaThread->stopCurrentOperation(false);
239 }
240 
242 {
243  if ( batchRunning ) {
244  ga->getEvoRobotExperiment()->setActivityPhase( EvoRobotExperiment::INEVOLUTION );
245  ga->evolveAllReplicas();
246  ga->resetStop();
247  } else {
248  mutex.lock();
249  if ( runningOperation ) {
250  mutex.unlock();
251  Logger::error( "EvoRobotComponent - Cannot run evolve because another action is currently running; please wait until it finish, or stop it before run evolve action" );
252  return;
253  }
254  runningOperation = true;
255  mutex.unlock();
256  gaThread->addOperation( new EvolveOperation( ga, this ) );
257  }
258 }
259 
261  AbstractTest* test = AvailableTestList::getTest( currentTestName );
262  if ( !test ) {
263  Logger::error( QString("EvoRobotComponent - Test ") + currentTestName + " is not present into the list of available Tests" );
264  return;
265  }
266  if ( batchRunning ) {
267  test->runTest();
268  ga->resetStop();
269  } else {
270  mutex.lock();
271  if ( runningOperation ) {
272  mutex.unlock();
273  Logger::error( QString("EvoRobotComponent - Cannot run test %1 because another action is currently running; please wait until it finish, or stop it before run test %1").arg(currentTestName) );
274  return;
275  }
276  runningOperation = true;
277  mutex.unlock();
278  gaThread->addOperation( new TestOperation( test, ga, this ) );
279  }
280 }
281 
283  // get the name of the test from the data into QAction
284  QAction* action = dynamic_cast<QAction*>( sender() );
285  if ( !action ) {
286  Logger::error( "EvoRobotComponent - runTestFromQAction can only be called by a QAction" );
287  return;
288  }
289  currentTestName = action->data().toString();
290  runTest();
291 }
292 
294  // This is never called in batch, exception are catched in total99 main
295  Logger::error( QString("EvoRobotComponent - Error while executing the current operation, an exception was thrown. Reason: ") + e->what() );
296 }
297 
299  mutex.lock();
300  runningOperation = false;
301  mutex.unlock();
302  setStatus( message );
303  emit actionFinished();
304 }
305 
306 } // end namespace farsa
void evolve()
Start the evolutionary process (it automatically disable "step-by-step" modality) ...
virtual void configure(farsa::ConfigurationParameters &params, QString prefix)
Configure function.
static QString getString(ConfigurationParameters &params, QString paramPath, QString def=QString())
virtual void save(ConfigurationParameters &params, QString prefix)
Save the actual status of parameters into the ConfigurationParameters object passed.
Definition: evoga.cpp:2880
virtual void run()
do the test process
Test a robot using a random genotype.
Definition: tests.h:34
bool isStopped()
return true if the evolution process has been stopped with stop()
Definition: evoga.cpp:3050
void stopCurrentOperation(bool wait)
void onThreadOperationDone(QString message)
executed when the current thread operation finish
the operation for evolution process
void resetStop()
reset the stopped status to false
Definition: evoga.cpp:3054
ParameterSettableUI * getUIManager()
Return an instance of EvoRobotViewer that manage the viewers.
void stop()
Suspend the evolutionary process.
the operation for testing process
virtual void stop()
stop the operation
void stop()
stop the running evolution process as soon as possible
Definition: evoga.cpp:3035
void runTest()
Run the test associated to the parameter testToRun.
void exceptionDuringOperation(farsa::BaseException *e)
Warns the user about the exception thrown by evolution or tests (only if not in batch running) ...
virtual void stop()
stop the operation
static bool getBool(ConfigurationParameters &params, QString paramPath, bool def=false)
void actionFinished()
emitted when the action (evolve, test, ...) has been finished/stopped
static void error(QString msg)
QString menuText()
the text to show on the menu/toolbar
Definition: abstracttest.h:146
virtual void save(farsa::ConfigurationParameters &params, QString prefix)
Save function.
Genetic algorithm from evorobot more or less (spare parts)
Definition: evoga.h:50
This class setup an evolutionary experiment.
virtual void postConfigureInitialization()
declare resources and initialize sensors
void setStatus(QString newStatus)
used by subclasses to change the status of the experiment
Definition: component.h:61
static Descriptor addTypeDescription(QString type, QString shortHelp, QString longHelp=QString(""))
static void addTest(QString name, AbstractTest *test)
Adds a test to the list of available ones.
static AbstractTest * getTest(QString name)
Returns the test with the given name.
An abstract class for tests of evolved individuals.
Definition: abstracttest.h:50
TypeToCreate * getObjectFromGroup(QString group, bool configure=true, bool forceObjectCreation=false)
The Component is the base (abstract) class for any specific project implementation.
Definition: component.h:45
QStringList getGroupsWithPrefixList(QString group, QString prefix) const
Tests the current individual, i.e.
Definition: tests.h:140
static void describe(QString type)
Description of all parameters.
virtual EvoRobotExperiment * getEvoRobotExperiment()
Returns a pointer to the EvoRobotExperiment object.
Definition: evoga.cpp:3074
virtual void setComponent(EvoRobotComponent *component)
Sets the Component.
Definition: abstracttest.h:125
virtual void run()
do the evolution process
virtual void stopCurrentOperation()
This stops the current running operation.
virtual void runTest()=0
Runs the test.
virtual void evolveAllReplicas()
Evolves all replications of the ga process.
Definition: evoga.cpp:3016
Evoga * getGA()
Return the Evoga.
void addOperation(ThreadOperation *operation, bool deleteAtEnd=true)
void setActivityPhase(Phases newPhase)
set the new activity phase
Test a specific individual taken from evolutionary data.
Definition: tests.h:78
void runTestFromQAction()
Run a Test associated to the QAction whom triggered this slot.