Differential Evolution C++ library
C:/dev/de/differentialevolution/processors.hpp
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