Differential Evolution C++ library
|
00001 /* 00002 * Copyright (c) 2011 Adrian Michel 00003 * http://www.amichel.com 00004 * 00005 * Permission to use, copy, modify, distribute and sell this 00006 * software and its documentation for any purpose is hereby 00007 * granted without fee, provided that both the above copyright 00008 * notice and this permission notice appear in all copies and in 00009 * the supporting documentation. 00010 * 00011 * This library is distributed in the hope that it will be 00012 * useful. However, Adrian Michel makes no representations about 00013 * the suitability of this software for any purpose. It is 00014 * provided "as is" without any express or implied warranty. 00015 * 00016 * Should you find this library useful, please email 00017 * info@amichel.com with a link or other reference 00018 * to your work. 00019 */ 00020 00021 #ifndef DE_PROCESSORS_HPP_INCLUDED 00022 #define DE_PROCESSORS_HPP_INCLUDED 00023 00024 // MS compatible compilers support #pragma once 00025 00026 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 00027 #pragma once 00028 #endif 00029 00030 #include <queue> 00031 #include <boost/thread.hpp> 00032 #include <boost/scope_exit.hpp> 00033 #include <boost/shared_ptr.hpp> 00034 #include <boost/utility.hpp> 00035 00036 #include "individual.hpp" 00037 #include "population.hpp" 00038 00039 namespace de 00040 { 00041 00052 class processor_listener 00053 { 00054 public: 00055 virtual ~processor_listener(){} 00064 virtual void start( size_t index ) = 0; 00075 virtual void start_of( size_t index, individual_ptr individual ) = 0; 00088 virtual void end_of( size_t index, individual_ptr individual ) = 0; 00099 virtual void end( size_t index ) = 0; 00109 virtual void error( size_t index, const std::string& message ) = 0; 00110 00111 }; 00112 00122 class null_processor_listener : public processor_listener 00123 { 00124 public: 00133 virtual void start(size_t index) 00134 { 00135 } 00146 virtual void start_of( size_t index, individual_ptr individual ) 00147 { 00148 } 00161 virtual void end_of( size_t index, individual_ptr individual ) 00162 { 00163 } 00174 virtual void end(size_t index) 00175 { 00176 } 00186 virtual void error(size_t index, const std::string& message ) 00187 { 00188 } 00189 }; 00190 00191 00195 typedef boost::shared_ptr< processor_listener > processor_listener_ptr; 00196 00203 class objective_function_exception : public exception 00204 { 00205 public: 00214 objective_function_exception( const std::string& message ) 00215 : exception( message.c_str() ) 00216 { 00217 } 00218 }; 00219 00238 template< typename T >class objective_function_factory 00239 { 00240 public: 00244 typedef boost::shared_ptr< T > T_ptr; 00245 00251 virtual ~objective_function_factory(){} 00252 00261 virtual T_ptr make() = 0; 00262 }; 00263 00270 template< typename T >class processor_traits 00271 { 00272 public: 00273 // \cond 00274 typedef T value_type; 00275 static double run( T t, de::DVectorPtr vars ) { return t( vars); } 00276 static T make( T t ) { return t; } 00277 // \endcond 00278 }; 00279 00286 template< typename T > class processor_traits< T* > 00287 { 00288 public: 00289 // \cond 00290 typedef T* value_type; 00291 static double run( value_type t, de::DVectorPtr vars ) { return (*t)( vars ); } 00292 static value_type make( value_type t ) { return t; } 00293 // \endcond 00294 }; 00295 00302 template< typename T > class processor_traits< boost::shared_ptr< T > > 00303 { 00304 public: 00305 // \cond 00306 typedef boost::shared_ptr< T > value_type; 00307 static double run( value_type t, de::DVectorPtr vars ) { return (*t)( vars); } 00308 static value_type make( value_type t ) { return t; } 00309 // \endcond 00310 }; 00311 00319 template< typename T > class processor_traits< objective_function_factory< T >* > 00320 { 00321 public: 00322 // \cond 00323 typedef boost::shared_ptr< T > value_type; 00324 static double run( value_type t, de::DVectorPtr vars ) { return (*t)( vars); } 00325 static value_type make( objective_function_factory< T >* off ) { return off->make(); } 00326 // \endcond 00327 }; 00335 template< typename T > class processor_traits< boost::shared_ptr< objective_function_factory< T > > > 00336 { 00337 public: 00338 // \cond 00339 typedef boost::shared_ptr< T > value_type; 00340 static double run( value_type t, de::DVectorPtr vars ) { return (*t)( vars); } 00341 static value_type make( boost::shared_ptr< objective_function_factory< T > > off ) { return off->make(); } 00342 // \endcond 00343 }; 00344 00352 template< typename T > class processor_traits< objective_function_factory< T >& > 00353 { 00354 public: 00355 // \cond 00356 typedef boost::shared_ptr< T > value_type; 00357 static double run( value_type t, de::DVectorPtr vars ) { return (*t)( vars ); } 00358 static value_type make( objective_function_factory< T >& off ) { return off.make(); } 00359 // \endcond 00360 }; 00361 00372 template < typename T > class processor : boost::noncopyable 00373 { 00374 private: 00375 typename processor_traits< T >::value_type m_of; 00376 individual_queue& m_indQueue; 00377 processor_listener_ptr m_listener; 00378 size_t m_index; 00379 00380 bool m_result; 00381 00382 public: 00396 processor( size_t index, T of, individual_queue& indQueue, processor_listener_ptr listener ) 00397 : m_of( processor_traits< T >::make( of ) ), m_indQueue( indQueue ), m_result( false ), m_listener( listener ), m_index( index ) 00398 { 00399 assert( listener ); 00400 } 00401 00408 void operator()() 00409 { 00410 m_listener->start( m_index ); 00411 m_result = false; 00412 try 00413 { 00414 for( individual_ptr ind = m_indQueue.pop(); ind; ind = m_indQueue.pop() ) 00415 { 00416 m_listener->start_of( m_index, ind ); 00417 double result = processor_traits< T >::run( m_of, ind->vars() ); 00418 00419 ind->setCost( result ); 00420 m_listener->end_of( m_index, ind ); 00421 } 00422 m_result = true; 00423 00424 BOOST_SCOPE_EXIT_TPL( (&m_index) (&m_listener) ) 00425 { 00426 m_listener->end( m_index ); 00427 } 00428 BOOST_SCOPE_EXIT_END 00429 } 00430 catch( const objective_function_exception& e ) 00431 { 00432 m_result = false; 00433 m_listener->error( m_index, e.what() ); 00434 } 00435 } 00436 00445 bool success() const { return m_result; } 00446 }; 00447 00448 00449 00455 class processors_exception : exception 00456 { 00457 public: 00465 processors_exception( const std::string& message ) 00466 : exception( message.c_str() ) 00467 { 00468 } 00469 }; 00470 00471 00484 template< typename T > class processors 00485 { 00486 private: 00487 typedef boost::shared_ptr< boost::thread_group > thread_group_ptr; 00488 typedef boost::shared_ptr< processor< T > > processor_ptr; 00489 typedef std::vector< processor_ptr > processor_vector; 00490 typedef boost::shared_ptr< T > T_ptr; 00491 00492 private: 00493 individual_queue m_indQueue; 00494 processor_vector m_processors; 00495 thread_group_ptr m_threads; 00496 00497 public: 00508 processors( size_t count, T of, processor_listener_ptr listener ) 00509 { 00510 assert( count > 0 ); 00511 assert( listener ); 00512 00513 for( size_t n = 0; n < count; ++n ) 00514 { 00515 processor_ptr processor( boost::make_shared< processor< T > >( n, of, boost::ref( m_indQueue ), listener ) ); 00516 m_processors.push_back( processors< T >::processor_ptr( processor ) ) ; 00517 } 00518 } 00519 00527 void push( individual_ptr ind ) { m_indQueue.push( ind ); } 00534 void start() 00535 { 00536 // create a new group every time, don't bother removing all individual threads 00537 m_threads = boost::make_shared< boost::thread_group >(); 00538 00539 for( typename processor_vector::size_type n = 0; n < m_processors.size(); ++n ) 00540 { 00541 processor_ptr p( m_processors[ n ] ); 00542 boost::thread* th( new boost::thread( boost::ref( *p ) ) ); 00543 m_threads->add_thread( th ); 00544 } 00545 } 00546 00554 void wait() 00555 { 00556 m_threads->join_all(); 00557 00558 if( !m_indQueue.empty() ) 00559 throw processors_exception( "threads ended before emptying the queue"); 00560 00561 if( !success() ) 00562 throw processors_exception( "objective function error"); 00563 } 00564 00572 bool success() 00573 { 00574 for( typename processor_vector::size_type n = 0; n < m_processors.size(); ++n ) 00575 { 00576 processor_ptr processor( m_processors[ n ] ); 00577 if( !processor->success() ) 00578 return false; 00579 } 00580 00581 return true; 00582 } 00583 00592 void push( population_ptr population ) 00593 { 00594 std::copy( population->begin(), population->end(), std::back_inserter( m_indQueue ) ); 00595 } 00596 00600 typedef boost::shared_ptr< processors< T > > processors_ptr; 00601 00602 }; 00603 00604 } 00605 00606 #endif //DE_PROCESSORS_HPP_INCLUDED