InterruptibleAlgorithmRunner.h
Go to the documentation of this file.
1 /**
2  *
3  * \brief Executes multi-objective optimizers.
4  *
5  * \author T.Voss
6  * \date 2010
7  *
8  *
9  * <BR><HR>
10  * This file is part of Shark. This library is free software;
11  * you can redistribute it and/or modify it under the terms of the
12  * GNU General Public License as published by the Free Software
13  * Foundation; either version 3, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this library; if not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24 
25 #ifndef INTERRUPTIBLE_ALORITHM_RUNNER_H
26 #define INTERRUPTIBLE_ALORITHM_RUNNER_H
27 
29 
31 
33 
34 #include <shark/Core/Exception.h>
35 #include <shark/Core/SignalTrap.h>
36 
37 #include <shark/Core/Logger.h>
40 
42 
43 #include <shark/Rng/GlobalRng.h>
44 
45 #include <boost/bind.hpp>
46 #include <boost/filesystem.hpp>
47 #include <boost/format.hpp>
48 #include <boost/optional.hpp>
49 #include <boost/progress.hpp>
50 #include <boost/property_tree/ptree.hpp>
51 #include <boost/property_tree/json_parser.hpp>
52 #include <boost/signals.hpp>
53 
54 #include <fstream>
55 #include <string>
56 
57 namespace shark {
58 
59 namespace moo {
60 
61 /**
62  * \brief Executes one trial of a multi-objective optimizer for a given
63  * multi-objective fitness function.
64  *
65  * \tparam Algo Models the type of the optimizer.
66  * \tparam Function Models the type of the objective function.
67  */
68 template<typename Algo, typename Function>
70 public:
71 
72  /** \brief Make the algorithm type known to the outside world.*/
73  typedef Algo algo_type;
74 
75  /** \brief Result type announced from this class. */
76  typedef typename algo_type::SolutionSetType result_type;
77 
78  /** \brief Make the function type known to the outside world.*/
79  typedef Function function_type;
80 
81 public:
82 
83  /** \brief Metadata describing actual result data. */
84  struct ResultMetaData {
86  const std::string & optimizerName,
87  const std::string & objectiveFunctionName,
88  std::size_t seed,
89  std::size_t searchSpaceDimension,
90  std::size_t objectiveSpaceDimension,
91  std::size_t evaluationCounter,
92  double timeStamp,
93  bool isFinal)
94  : m_optimizerName( optimizerName ),
95  m_objectiveFunctionName( objectiveFunctionName ),
96  m_seed( seed ),
97  m_searchSpaceDimension( searchSpaceDimension ),
98  m_objectiveSpaceDimension( objectiveSpaceDimension ),
99  m_evaluationCounter( evaluationCounter ),
100  m_timeStamp( timeStamp ),
101  m_isFinal( isFinal )
102  { }
103 
104  std::string m_optimizerName;
106  std::size_t m_seed;
109  std::size_t m_evaluationCounter;
110  double m_timeStamp;
111  bool m_isFinal;
112  };
113 
114  /**
115  * \brief Signal for delivering results to the outside world.
116  */
117  typedef boost::signal<
118  void
119  (
120  SHARK_ARGUMENT( const result_type &, "Actual optimization results" ),
121  SHARK_ARGUMENT( const ResultMetaData & , "Meta data for actual optimization results" )
122  )
123  > event_type;
124 
125  /**
126  * \brief C'tor.
127  */
129  boost::shared_ptr< Algo > algo = boost::shared_ptr< Algo >( new Algo ),
130  boost::shared_ptr< Function > function = boost::shared_ptr< Function >( new Function() ) )
131  : mep_algorithm( algo )
132  , mep_function( function )
133  {
136  this, _1 ) );
137  }
138 
139  /// \brief From INameable: return the class name.
140  std::string name() const
141  { return "InterruptibleAlgorithmRunner<" + mep_algorithm->name() + "," + mep_function->name() + ">"; }
142 
143  /**
144  * \brief Triggered when new results are available.
145  */
146  event_type & signalResultsAvailable() {
147  return( m_signalResultsAvailable );
148  }
149 
150  /**
151  * \brief Executes the optimizer trial for the given parameters.
152  */
153  void run( unsigned int seed,
154  unsigned int interval,
155  unsigned int n,
156  unsigned int m,
157  unsigned int g,
158  unsigned int timeLimit,
159  const boost::optional< boost::property_tree::ptree > & configNode = boost::optional< boost::property_tree::ptree >() )
160  {
161  shark::Rng::seed( seed );
162 
163  m_n = n;
164  m_m = m;
165  m_seed = seed;
166  m_algoName = mep_algorithm->name();
167  m_functionName = mep_function->name();
168 
169 
170  mep_function->setNumberOfVariables( n );
171  //mep_function->setNoObjectives( m );
172  mep_function->init();
173 
174  if( configNode ) {
175  mep_algorithm->configure( *configNode );
176  }
177 
178  mep_algorithm->init( *mep_function.get() );
179 
180  boost::progress_display pd( g, std::clog );
181  m_pt.restart();
182 
183  std::size_t currentEvaluationCount = 0;
184 
185  while( mep_function->evaluationCounter() <= g && m_pt.elapsed() / 3600 < timeLimit ) {
186  mep_algorithm->step( *mep_function.get() );
187  m_front = mep_algorithm->solution();
188 
189  if( mep_function->evaluationCounter() % interval == 0 ) {
190 
192  m_front,
194  m_algoName,
196  m_seed,
197  m_n,
198  m_m,
199  mep_function->evaluationCounter(),
200  m_pt.elapsed(),
201  false));
202  }
203  pd += mep_function->evaluationCounter() - currentEvaluationCount;
204  currentEvaluationCount = mep_function->evaluationCounter();
205  }
206 
208  m_front,
210  m_algoName,
212  m_seed,
213  m_n,
214  m_m,
215  mep_function->evaluationCounter(),
216  m_pt.elapsed(),
217  true ) );
218  }
219 
220  /**
221  * \brief Reports known fitness functions.
222  */
223  DEFINE_SIMPLE_OPTION( ReportFitnessFunctionsTag, reportFitnessFunctions );
224 
225 
226  static int main( int argc, char ** argv ) {
227  // Set up logging.
229  boost::shared_ptr<
231  > plaintTextLogHandler( shark::LogHandlerFactory::instance()[ "ClogLogHandler" ] );
232 
233  plaintTextLogHandler->setFormatter(
234  boost::shared_ptr<
236  >( shark::LogFormatterFactory::instance()[ "PlainTextLogFormatter" ] ) );
237 
238  shark::Shark::logger()->registerHandler( plaintTextLogHandler );
239 
241  options.addDefaultOptions();
242  options.addOption( ReportFitnessFunctionsTag() );
243 
244  if( !options.parse( argc, argv ) ) {
245  SHARK_LOG_ERROR( shark::Shark::logger(), "Problem parsing command line", "InterruptibleAlgorithmRunner::main" );
246  options.printOptions( std::cerr );
247  return( EXIT_FAILURE );
248  }
249 
250  if( options.hasValue( ReportFitnessFunctionsTag() ) ) {
251  shark::moo::RealValuedObjectiveFunctionFactory::instance().print( std::cout );
252  return( EXIT_SUCCESS );
253  }
254 
255  if(options.hasValue( shark::moo::Experiment::Options::DefaultAlgorithmUsageTag()) ) {
256  boost::property_tree::ptree pt;
258  boost::property_tree::write_json(std::cout, pt);
259  return( EXIT_SUCCESS );
260  }
261 
262  if( options.value( shark::moo::Experiment::Options::ObjectiveFunctionTag() ).empty() ) {
263  SHARK_LOG_ERROR( shark::Shark::logger(), "Missing objective function, aborting now.", "InterruptibleAlgorithmRunner::main" );
264  options.printOptions( std::cerr );
265  return( EXIT_FAILURE );
266  }
267 
268  boost::optional< boost::property_tree::ptree > configurationTree;
269 
270  if( !options.value( shark::moo::Experiment::Options::AlgorithmConfigFile() ).empty() ) {
271  try {
272  boost::property_tree::ptree pt;
273  boost::property_tree::read_json( options.value( shark::moo::Experiment::Options::AlgorithmConfigFile() ), pt );
274  configurationTree = pt;
275  } catch( ... ) {
276  SHARK_LOG_ERROR( shark::Shark::logger(), "Problem reading algorithm configuration file.", "InterruptibleAlgorithmRunner::main" );
277  return( EXIT_FAILURE );
278  }
279  }
280 
281  std::string resultFormat = options.value( shark::moo::Experiment::Options::ResultFormatTag());
282 
283  std::string objectiveFunction = options.value( shark::moo::Experiment::Options::ObjectiveFunctionTag() );
284 
285  SHARK_LOG_DEBUG( shark::Shark::logger(), "Considering objective function: " + objectiveFunction, "InterruptibleAlgorithmRunner::main" );
286 
289 
290  front_store_type frontStore;
291  frontStore.m_resultDir = options.value( shark::moo::Experiment::Options::ResultDirTag() );
292  if(resultFormat == "JSON")
293  frontStore.m_format = front_store_type::JSON_FORMAT;
294  else if(resultFormat == "RawText")
295  frontStore.m_format = front_store_type::RAW_TEXT_FORMAT;
296 
299  "Storing results to: " + frontStore.m_resultDir,
300  "InterruptibleAlgorithmRunner::main" );
301 
302  runner_type abstractRunner(
303  boost::shared_ptr<
304  Algo
305  >( new Algo() ),
306  boost::shared_ptr<
307  Function
308  >( shark::Factory< Function, std::string >::instance()[ objectiveFunction ] ) );
309 
310  abstractRunner.signalResultsAvailable().connect(
311  boost::bind(
312  &front_store_type::onNewResult,
313  boost::ref( frontStore ),
314  _1,
315  _2 ) );
316 
317  try {
318  abstractRunner.run(
319  options.value( shark::moo::Experiment::Options::SeedTag() ),
320  options.value( shark::moo::Experiment::Options::StorageIntervalTag() ),
321  options.value( shark::moo::Experiment::Options::SearchSpaceDimensionTag() ),
322  options.value( shark::moo::Experiment::Options::ObjectiveSpaceDimensionTag() ),
323  options.value( shark::moo::Experiment::Options::MaxNoEvaluationsTag() ),
324  options.value( shark::moo::Experiment::Options::TimeLimitTag() ),
325  configurationTree
326  );
327  } catch( const shark::Exception & e ) {
328  SHARK_LOG_ERROR( shark::Shark::logger(), ( boost::format( "Exception while running: %1% [%2%@%3%]" ) % e.what() % e.file() % e.line() ).str(), "InterruptibleAlgorithmRunner::main" );
329  }
330  return( EXIT_SUCCESS );
331  }
332 
333 protected:
334 
335  /**
336  * \brief Stores the current front.
337  */
338  typename algo_type::SolutionSetType m_front;
339 
340  /**
341  * \brief Reference to the optimizer.
342  */
343  boost::shared_ptr< Algo > mep_algorithm;
344 
345  /**
346  * \brief Reference to the objective function.
347  */
348  boost::shared_ptr< Function > mep_function;
349 
350  /**
351  * \brief Stores the name of the optimizer.
352  */
353  std::string m_algoName;
354 
355  /**
356  * \brief Stores the name of the objective function.
357  */
358  std::string m_functionName;
359 
360  /**
361  * \brief Stores the initial seed of the trial.
362  */
363  std::size_t m_seed;
364 
365  /**
366  * \brief Stores the dimension of the search space n.
367  */
368  std::size_t m_n;
369 
370  /**
371  * \brief Store the number of objectives m.
372  */
373  std::size_t m_m;
374 
375  /**
376  * \brief Timer instance for time-limited experiments.
377  */
378  boost::timer m_pt;
379 
380  /**
381  * \brief Signal for delivering results to the outside world.
382  */
384 
385  /**
386  * \brief Slot that is called when a signal is emitted from the
387  * signal trap. Stores the current front.
388  *
389  * \param [in] signal The emitted signal
390  */
392  if( m_front.empty() ) return;
393 
395  m_front,
397  m_algoName,
399  m_seed,
400  m_n,
401  m_m,
402  mep_function->evaluationCounter(),
403  m_pt.elapsed(),
404  true));
405  exit( EXIT_SUCCESS );
406  }
407 };
408 
409 
410 } // namespace moo
411 
412 namespace soo {
413 
414 /**
415  * \brief Executes one trial of a single-objective optimizer for a given
416  * single-objective fitness function.
417  *
418  * \tparam Algo Models the type of the optimizer.
419  * \tparam Function Models the type of the objective function.
420  */
421 template<typename Algo, typename Function>
423  public:
424 
425  /** \brief Make the algorithm type known to the outside world.*/
426  typedef Algo algo_type;
427 
428  /** \brief Result type announced from this class. */
429  typedef typename algo_type::SolutionSetType result_type;
430 
431  /** \brief Make the function type known to the outside world.*/
432  typedef Function function_type;
433 
434  public:
435 
436  /** \brief Metadata describing actual result data. */
437  struct ResultMetaData {
438 
440  const std::string & optimizerName,
441  const std::string & objectiveFunctionName,
442  std::size_t seed,
443  std::size_t searchSpaceDimension,
444  std::size_t evaluationCounter,
445  double timeStamp,
446  bool isFinal
447  ) : m_optimizerName( optimizerName ),
448  m_objectiveFunctionName( objectiveFunctionName ),
449  m_seed( seed ),
450  m_searchSpaceDimension( searchSpaceDimension ),
451  m_evaluationCounter( evaluationCounter ),
452  m_timeStamp( timeStamp ),
453  m_isFinal( isFinal ) {
454  }
455 
456 
457  std::string m_optimizerName;
459  std::size_t m_seed;
461  std::size_t m_evaluationCounter;
462  double m_timeStamp;
463  bool m_isFinal;
464  };
465 
466  /**
467  * \brief Signal for delivering results to the outside world.
468  */
469  typedef boost::signal<
470  void
471  (
472  SHARK_ARGUMENT( const result_type &, "Actual optimization results" ),
473  SHARK_ARGUMENT( const ResultMetaData & , "Meta data for actual optimization results" )
474  )
475  > event_type;
476 
477  /**
478  * \brief C'tor.
479  */
481  boost::shared_ptr< Algo > algo = boost::shared_ptr< Algo >( new Algo ),
482  boost::shared_ptr< Function > function = boost::shared_ptr< Function >( new Function() ) ) : mep_algorithm( algo ),
483  mep_function( function ) {
485  }
486 
487  /**
488  * \brief Triggered when new results are available.
489  */
490  event_type & signalResultsAvailable() {
491  return( m_signalResultsAvailable );
492  }
493  /**
494  * \brief Executes the optimizer trial for the given parameters.
495  */
496  void run( unsigned int seed,
497  unsigned int interval,
498  unsigned int n,
499  unsigned int g,
500  unsigned int timeLimit,
501  double fitnessLimit = 1E-10,
502  const boost::optional< boost::property_tree::ptree > & configNode = boost::optional< boost::property_tree::ptree >()
503  ) {
506  ( boost::format( "run( seed=%1%, interval=%2%, n=%3%, g=%4%, timeLimit=%5%, fitnessLimit=%6% )" ) % seed % interval % n % g % timeLimit % fitnessLimit ).str(),
507  "shark::soo::InterruptibleAlgorithmRunner::run()"
508  );
509  shark::Rng::seed( seed );
510 
511  m_n = n;
512  m_seed = seed;
513  m_algoName = mep_algorithm->name();
514  m_functionName = mep_function->name();
515 
516  //ObjectiveFunctionTraits::setNumberOfVariables( *(mep_function.get()), n )
517  mep_function->setNumberOfVariables( n );
518  mep_function->init();
519 
520  if( configNode ) {
521  mep_algorithm->configure( *configNode );
522  }
523 
524  mep_algorithm->init( *mep_function.get() );
525 
526  boost::progress_display pd( g, std::clog );
527  m_pt.restart();
528 
529  std::size_t currentEvaluationCount = 0;
530 
531  while( mep_function->evaluationCounter() <= g && m_pt.elapsed() / 3600 < timeLimit && mep_algorithm->solution().value > fitnessLimit ) {
532  mep_algorithm->step( *mep_function.get() );
533  m_result = mep_algorithm->solution();
534 
535  if( mep_function->evaluationCounter() % interval == 0 ) {
536 
538  m_result,
540  m_algoName,
542  m_seed,
543  m_n,
544  mep_function->evaluationCounter(),
545  m_pt.elapsed(),
546  false
547  )
548  );
549  }
550  pd += mep_function->evaluationCounter() - currentEvaluationCount;
551  currentEvaluationCount = mep_function->evaluationCounter();
552  }
553 
555  m_result,
557  m_algoName,
559  m_seed,
560  m_n,
561  mep_function->evaluationCounter(),
562  m_pt.elapsed(),
563  true
564  )
565  );
566  }
567 
568  /**
569  * \brief Reports known fitness functions.
570  */
571  DEFINE_SIMPLE_OPTION( ReportFitnessFunctionsTag, reportFitnessFunctions );
572 
573  static int main( int argc, char ** argv ) {
574  // Set up logging.
576  boost::shared_ptr<
578  > plaintTextLogHandler(
579  shark::LogHandlerFactory::instance()[ "CoutLogHandler" ]
580  );
581  plaintTextLogHandler->setFormatter(
582  boost::shared_ptr<
584  >( shark::LogFormatterFactory::instance()[ "PlainTextLogFormatter" ] )
585  );
586  shark::Shark::logger()->registerHandler( plaintTextLogHandler );
587 
589  options.addDefaultOptions();
590  options.addOption( ReportFitnessFunctionsTag() );
591 
592  if( !options.parse( argc, argv ) ) {
593  SHARK_LOG_ERROR( shark::Shark::logger(), "Problem parsing command line", "InterruptibleAlgorithmRunner::main" );
594  options.printOptions( std::cerr );
595  return( EXIT_FAILURE );
596  }
597 
598  if( options.hasValue( ReportFitnessFunctionsTag() ) ) {
599  shark::soo::RealValuedObjectiveFunctionFactory::instance().print( std::cout );
600  return( EXIT_SUCCESS );
601  }
602 
603  if(options.hasValue(
604  shark::soo::Experiment::Options::DefaultAlgorithmUsageTag())) {
605  boost::property_tree::ptree pt;
607  boost::property_tree::write_json(std::cout, pt);
608  return( EXIT_SUCCESS );
609  }
610 
611  if( options.value( shark::moo::Experiment::Options::ObjectiveFunctionTag() ).empty() ) {
612  SHARK_LOG_ERROR( shark::Shark::logger(), "Missing objective function, aborting now.", "InterruptibleAlgorithmRunner::main" );
613  options.printOptions( std::cerr );
614  return( EXIT_FAILURE );
615  }
616 
617  boost::optional< boost::property_tree::ptree > configurationTree;
618 
619  if( !options.value( shark::moo::Experiment::Options::AlgorithmConfigFile() ).empty() ) {
620  try {
621  boost::property_tree::ptree pt;
622  boost::property_tree::read_json( options.value( shark::moo::Experiment::Options::AlgorithmConfigFile() ), pt );
623  configurationTree = pt;
624  } catch( ... ) {
625  SHARK_LOG_ERROR( shark::Shark::logger(), "Problem reading algorithm configuration file.", "InterruptibleAlgorithmRunner::main" );
626  return( EXIT_FAILURE );
627  }
628 
629  }
630 
631  std::string objectiveFunction = options.value( shark::moo::Experiment::Options::ObjectiveFunctionTag() );
632 
633  SHARK_LOG_DEBUG( shark::Shark::logger(), "Considering objective function: " + objectiveFunction, "InterruptibleAlgorithmRunner::main" );
634 
636  Algo,
637  Function
638  > runner_type;
639 
640  /*
641  typedef shark::FrontStore<
642  typename runner_type::result_type,
643  typename runner_type::ResultMetaData
644  > front_store_type;
645 
646  front_store_type frontStore;
647  frontStore.m_resultDir = options.value( shark::moo::Experiment::Options::ResultDirTag() );
648 
649  SHARK_LOG_DEBUG( shark::Shark::logger(), "Storing results to: " + frontStore.m_resultDir, "InterruptibleAlgorithmRunner::main" );
650  */
651 
652  runner_type abstractRunner(
653  boost::shared_ptr<
654  Algo
655  >( new Algo() ),
656  boost::shared_ptr<
657  Function
658  >( shark::Factory< Function, std::string >::instance()[ objectiveFunction ] )
659  );
660 
661  /*
662  abstractRunner.signalResultsAvailable().connect(
663  boost::bind(
664  &front_store_type::onNewResult,
665  boost::ref( frontStore ),
666  _1,
667  _2
668  )
669  );*/
670 
671 
672 
673  try {
674  abstractRunner.run(
675  options.value( shark::moo::Experiment::Options::SeedTag() ),
676  options.value( shark::moo::Experiment::Options::StorageIntervalTag() ),
677  options.value( shark::moo::Experiment::Options::SearchSpaceDimensionTag() ),
678  options.value( shark::moo::Experiment::Options::MaxNoEvaluationsTag() ),
679  options.value( shark::moo::Experiment::Options::TimeLimitTag() ),
680  options.value( shark::moo::Experiment::Options::FitnessLimitTag() ),
681  configurationTree
682  );
683  } catch( const shark::Exception & e ) {
684  SHARK_LOG_ERROR( shark::Shark::logger(), ( boost::format( "Exception while running: %1% [%2%@%3%]" ) % e.what() % e.file() % e.line() ).str(), "InterruptibleAlgorithmRunner::main" );
685  }
686  return( EXIT_SUCCESS );
687  }
688 
689  protected:
690 
691  /**
692  * \brief Stores the current front.
693  */
694  result_type m_result;
695 
696  /**
697  * \brief Reference to the optimizer.
698  */
699  boost::shared_ptr< Algo > mep_algorithm;
700 
701  /**
702  * \brief Reference to the objective function.
703  */
704  boost::shared_ptr< Function > mep_function;
705 
706  /**
707  * \brief Stores the name of the optimizer.
708  */
709  std::string m_algoName;
710 
711  /**
712  * \brief Stores the name of the objective function.
713  */
714  std::string m_functionName;
715 
716  /**
717  * \brief Stores the initial seed of the trial.
718  */
719  std::size_t m_seed;
720 
721  /**
722  * \brief Stores the dimension of the search space n.
723  */
724  std::size_t m_n;
725 
726  /**
727  * \brief Timer instance for time-limited experiments.
728  */
729  boost::timer m_pt;
730 
731  /**
732  * \brief Target fitness function value.
733  */
735 
736  /**
737  * \brief Signal for delivering results to the outside world.
738  */
740 
741  /**
742  * \brief Slot that is called when a signal is emitted from the
743  * signal trap. Stores the current front.
744  *
745  * \param [in] signal The emitted signal
746  */
748 
750  m_result,
752  m_algoName,
754  m_seed,
755  m_n,
756  mep_function->evaluationCounter(),
757  m_pt.elapsed(),
758  true
759  )
760  );
761  exit( EXIT_SUCCESS );
762  }
763 };
764 }
765 }
766 
767 #endif