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 00022 #ifndef DE_MUTATION_STRATEGY_HPP_INCLUDED 00023 #define DE_MUTATION_STRATEGY_HPP_INCLUDED 00024 00025 // MS compatible compilers support #pragma once 00026 00027 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 00028 #pragma once 00029 #endif 00030 00031 #include "population.hpp" 00032 00033 #define URN_DEPTH 5 00034 00035 #include <boost/tuple/tuple.hpp> 00036 00037 namespace de 00038 { 00039 00047 class mutation_strategy_arguments 00048 { 00049 private: 00050 const double m_weight; 00051 const double m_crossover; 00052 const double m_dither; 00053 00054 public: 00071 mutation_strategy_arguments( double weight, double crossover ) 00072 : m_weight( weight ), m_crossover( crossover ), m_dither( weight + genrand() * ( 1.0 - weight ) ) 00073 { 00074 // todo: test or assert that weight and crossover are within bounds (0-1, 0-2 or something) 00075 } 00076 00084 double weight() const { return m_weight; } 00092 double crossover() const { return m_crossover; } 00100 double dither() const { return m_dither; } 00101 }; 00102 00111 class mutation_strategy 00112 { 00113 private: 00114 mutation_strategy_arguments m_args; 00115 size_t m_varCount; 00116 00117 protected: 00127 class Urn 00128 { 00129 size_t m_urn[ URN_DEPTH ]; 00130 00131 public: 00142 Urn( size_t NP, size_t avoid ) 00143 { 00144 do m_urn[ 0 ] = genintrand( 0, NP, true ) ; while( m_urn[ 0 ] == avoid ) ; 00145 do m_urn[ 1 ] = genintrand( 0, NP, true ) ; while( m_urn[ 1 ] == m_urn[ 0 ] || m_urn[ 1 ] == avoid ); 00146 do m_urn[ 2 ] = genintrand( 0, NP, true ) ; while( m_urn[ 2 ] == m_urn[ 1 ] || m_urn[ 2 ] == m_urn[ 0 ] || m_urn[ 2 ] == avoid ); 00147 do m_urn[ 3 ] = genintrand( 0, NP, true ) ; while( m_urn[ 3 ] == m_urn[ 2 ] || m_urn[ 3 ] == m_urn[ 1 ] || m_urn[ 3 ] == m_urn[ 0 ] || m_urn[ 3 ] == avoid ); 00148 } 00149 00160 size_t operator[]( size_t index ) const { assert( index < 4 ); return m_urn[ index ]; } 00161 }; 00162 00163 00164 public: 00165 virtual ~mutation_strategy() 00166 { 00167 } 00168 00177 mutation_strategy( size_t varCount, const mutation_strategy_arguments& args ) 00178 : m_args( args ), m_varCount( varCount ) 00179 { 00180 } 00181 00185 typedef boost::tuple< individual_ptr, de::DVectorPtr > mutation_info; 00186 00202 virtual mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) = 0; 00203 00211 size_t varCount() const { return m_varCount; } 00212 00220 double weight() const { return m_args.weight(); } 00221 00229 double crossover() const { return m_args.crossover(); } 00230 00238 double dither() const { return m_args.dither(); } 00239 }; 00240 00241 typedef boost::shared_ptr< mutation_strategy > mutation_strategy_ptr; 00242 00248 class mutation_strategy_1 : public mutation_strategy 00249 { 00250 public: 00259 mutation_strategy_1( size_t varCount, const mutation_strategy_arguments& args ) 00260 : mutation_strategy( varCount, args ) 00261 { 00262 } 00263 00279 mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) 00280 { 00281 assert( bestIt ); 00282 00283 de::DVectorPtr origin( boost::make_shared< de::DVector >( varCount() ) ); 00284 individual_ptr tmpInd( boost::make_shared< individual >( *pop[ i ]->vars() ) ); 00285 Urn urn( pop.size(), i ); 00286 00287 00288 // make sure j is within bounds 00289 size_t j = genintrand( 0, varCount(), true ); 00290 size_t k = 0; 00291 00292 do 00293 { 00294 (*tmpInd->vars())[ j ] = (*pop[ urn[ 0 ] ]->vars() )[ j ] + weight() * ( (*pop[ urn[ 1 ] ]->vars() )[ j ] - (*pop[ urn[ 2 ] ]->vars())[ j ] ); 00295 00296 j = ++j % varCount(); 00297 ++k; 00298 } while( genrand() < crossover() && k < varCount() ); 00299 00300 origin = pop[ urn[ 0 ] ]->vars(); 00301 00302 return mutation_info( tmpInd, origin ); 00303 } 00304 00305 }; 00306 00312 class mutation_strategy_2 : public mutation_strategy 00313 { 00314 public: 00323 mutation_strategy_2( size_t varCount, const mutation_strategy_arguments& args ) 00324 : mutation_strategy( varCount, args ) 00325 { 00326 } 00327 00343 mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) 00344 { 00345 assert( bestIt ); 00346 00347 de::DVectorPtr origin( boost::make_shared< de::DVector >( varCount() ) ); 00348 individual_ptr tmpInd( boost::make_shared< individual >( *pop[ i ]->vars() ) ); 00349 Urn urn( pop.size(), i ); 00350 00351 00352 // make sure j is within bounds 00353 size_t j = genintrand( 0, varCount(), true ); 00354 size_t k = 0; 00355 00356 do 00357 { 00358 (*tmpInd->vars())[ j ] = (*tmpInd->vars())[ j ] + 00359 weight() * ( (*bestIt->vars() )[ j ] - (*tmpInd->vars())[ j ] ) + 00360 weight() * ( (*pop[ urn[ 1 ] ]->vars() )[ j ] - (*pop[ urn[ 2 ] ]->vars())[ j ] ); 00361 00362 j = ++j % varCount(); 00363 ++k; 00364 } while( genrand() < crossover() && k < varCount() ); 00365 00366 origin = pop[ urn[ 0 ] ]->vars(); 00367 00368 return mutation_info( tmpInd, origin ); 00369 } 00370 00371 }; 00372 00378 class mutation_strategy_3 : public mutation_strategy 00379 { 00380 public: 00389 mutation_strategy_3( size_t varCount, const mutation_strategy_arguments& args ) 00390 : mutation_strategy( varCount, args ) 00391 { 00392 } 00393 00409 mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) 00410 { 00411 assert( bestIt ); 00412 00413 de::DVectorPtr origin( boost::make_shared< de::DVector >( varCount() ) ); 00414 individual_ptr tmpInd( boost::make_shared< individual >( *pop[ i ]->vars() ) ); 00415 Urn urn( pop.size(), i ); 00416 00417 00418 // make sure j is within bounds 00419 size_t j = genintrand( 0, varCount(), true ); 00420 size_t k = 0; 00421 00422 do 00423 { 00424 double jitter = (0.0001* genrand() + weight() ); 00425 00426 (*tmpInd->vars())[ j ] = (*bestIt->vars() )[ j ] + jitter * ( (*pop[ urn[ 1 ] ]->vars() )[ j ] - (*pop[ urn[ 2 ] ]->vars())[ j ] ); 00427 00428 j = ++j % varCount(); 00429 ++k; 00430 } while( genrand() < crossover() && k < varCount() ); 00431 00432 origin = pop[ urn[ 0 ] ]->vars(); 00433 00434 return mutation_info( tmpInd, origin ); 00435 } 00436 }; 00437 00443 class mutation_strategy_4 : public mutation_strategy 00444 { 00445 public: 00454 mutation_strategy_4( size_t varCount, const mutation_strategy_arguments& args ) 00455 : mutation_strategy( varCount, args ) 00456 { 00457 } 00458 00474 mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) 00475 { 00476 assert( bestIt ); 00477 00478 de::DVectorPtr origin( boost::make_shared< de::DVector >( varCount() ) ); 00479 individual_ptr tmpInd( boost::make_shared< individual >( *pop[ i ]->vars() ) ); 00480 Urn urn( pop.size(), i ); 00481 00482 00483 // make sure j is within bounds 00484 size_t j = genintrand( 0, varCount(), true ); 00485 size_t k = 0; 00486 00487 double factor( weight() + genrand() * ( 1.0 - weight() ) ); 00488 00489 do 00490 { 00491 double jitter = (0.0001* genrand() + weight() ); 00492 00493 (*tmpInd->vars())[ j ] = (*pop[ urn[ 0 ] ]->vars() )[ j ] + 00494 factor * ( (*pop[ urn[ 1 ] ]->vars() )[ j ] - (*pop[ urn[ 2 ] ]->vars())[ j ] ); 00495 00496 j = ++j % varCount(); 00497 ++k; 00498 } while( genrand() < crossover() && k < varCount() ); 00499 00500 origin = pop[ urn[ 0 ] ]->vars(); 00501 00502 return mutation_info( tmpInd, origin ); 00503 } 00504 00505 }; 00506 00507 00508 00514 class mutation_strategy_5 : public mutation_strategy 00515 { 00516 00517 public: 00526 mutation_strategy_5( size_t varCount, const mutation_strategy_arguments& args ) 00527 : mutation_strategy( varCount, args ) 00528 { 00529 } 00530 00546 mutation_info operator()( const population& pop, individual_ptr bestIt, size_t i ) 00547 { 00548 assert( bestIt ); 00549 00550 de::DVectorPtr origin( boost::make_shared< de::DVector >( varCount() ) ); 00551 individual_ptr tmpInd( boost::make_shared< individual >( *pop[ i ]->vars() ) ); 00552 Urn urn( pop.size(), i ); 00553 00554 // make sure j is within bounds 00555 size_t j = genintrand( 0, varCount(), true ); 00556 size_t k = 0; 00557 00558 do 00559 { 00560 (*tmpInd->vars())[ j ] = (*pop[ urn[ 0 ] ]->vars() )[ j ] + dither() * ( (*pop[ urn[ 1 ] ]->vars() )[ j ] - (*pop[ urn[ 2 ] ]->vars() )[ j ] ); 00561 00562 j = ++j % varCount(); 00563 ++k; 00564 } while( genrand() < crossover() && k < varCount() ); 00565 00566 origin = pop[ urn[ 0 ] ]->vars(); 00567 return mutation_info( tmpInd, origin ); 00568 } 00569 00570 }; 00571 00572 } 00573 00574 #endif //DE_MUTATION_STRATEGY_HPP_INCLUDED