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