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_CONSTRAINTS_HPP_INCLUDED 00022 #define DE_CONSTRAINTS_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 <set> 00031 #include <boost/tokenizer.hpp> 00032 #include <boost/algorithm/string.hpp> 00033 #include <boost/format.hpp> 00034 #include <boost/make_shared.hpp> 00035 #include <boost/lexical_cast.hpp> 00036 00037 #include "random_generator.hpp" 00038 #include "de_types.hpp" 00039 00040 namespace de 00041 { 00042 00048 class constraints_exception : public exception 00049 { 00050 public: 00058 constraints_exception( const std::string& message ) 00059 : exception( message.c_str() ) 00060 { 00061 } 00062 }; 00063 00072 class constraint 00073 { 00074 public: 00075 virtual ~constraint(){} 00076 00085 virtual double get_rand_value() = 0; 00086 00099 virtual double get_rand_value( double value, double origin ) = 0; 00100 00108 virtual double min() const = 0; 00109 00117 virtual double max() const = 0; 00118 00134 virtual double get_rand_value_in_zone( double origin, double zonePct ) const = 0; 00135 00144 virtual double get_middle_point() = 0; 00145 }; 00146 00150 typedef boost::shared_ptr< constraint > constraint_ptr; 00151 00158 class range_constraint : public constraint 00159 { 00160 private: 00161 double m_min; 00162 double m_max; 00163 00164 public: 00165 00174 range_constraint( double min, double max ) 00175 : m_min( min ), m_max( max ) 00176 { 00177 assert( min <= max ); 00178 } 00179 00187 double min() const { return m_min; } 00188 00196 double max() const { return m_max; } 00197 00198 }; 00199 00206 class real_constraint : public range_constraint 00207 { 00208 public: 00209 00219 real_constraint( double min, double max ) 00220 : range_constraint( min, max ) 00221 { 00222 assert( min <= max ); 00223 } 00224 00233 double get_rand_value() 00234 { 00235 return genrand( range_constraint::min(), range_constraint::max() ); 00236 } 00237 00249 double get_rand_value( double value, double origin ) 00250 { 00251 double ret = value; 00252 00253 while( ret < range_constraint::min() ) 00254 { 00255 ret = range_constraint::min() + genrand() * ( origin - range_constraint::min() ); 00256 } 00257 00258 while( ret > range_constraint::max() ) 00259 { 00260 ret = range_constraint::max() + genrand() * ( origin - range_constraint::max() ); 00261 } 00262 00263 return ret; 00264 } 00265 00266 virtual double get_rand_value_in_zone( double origin, double zonePct ) const 00267 { 00268 if( origin > max() ) 00269 throw constraints_exception( "origin coordinate > max" ); 00270 if( origin < min() ) 00271 throw constraints_exception( "origin coordinate < min" ); 00272 00273 if( zonePct > 100.0 ) 00274 throw constraints_exception( "zonePct > 100%" ); 00275 00276 if( zonePct < 0 ) 00277 throw constraints_exception( "zonePct < 0%" ); 00278 00279 if( zonePct == 0 ) 00280 throw constraints_exception( "zonePct == 0%" ); 00281 00282 double zoneSize = ( max() - min() ) * zonePct / 100.0; 00283 00284 double _min = std::max( min(), origin - zoneSize/2.0 ); 00285 double _max = std::min( max(), origin + zoneSize/2.0 ); 00286 00287 return genrand( _min, _max ); 00288 } 00289 00290 virtual double get_middle_point() 00291 { 00292 return ( max() + min() )/2.0; 00293 } 00294 00295 }; 00296 00303 class int_constraint : public range_constraint 00304 { 00305 public: 00315 int_constraint( double min, double max ) 00316 : range_constraint( min, max ) 00317 { 00318 assert( min <= max ); 00319 } 00320 00329 double get_rand_value() 00330 { 00331 return genintrand( range_constraint::min(), range_constraint::max() ); 00332 } 00333 00345 double get_rand_value( double value, double origin ) 00346 { 00347 double ret = boost::math::round( value ); 00348 00349 while( ret < range_constraint::min() ) 00350 { 00351 ret = range_constraint::min() + genrand() * ( origin - range_constraint::min() ); 00352 ret = boost::math::round( ret ); 00353 } 00354 00355 while( ret > range_constraint::max() ) 00356 { 00357 ret = range_constraint::max() + genrand() * ( origin - range_constraint::max() ); 00358 ret = boost::math::round( ret ); 00359 } 00360 00361 return ret; 00362 } 00363 00364 virtual double get_rand_value_in_zone( double origin, double zonePct ) const 00365 { 00366 if ( origin > max() ) 00367 throw constraints_exception( "origin coordinate > max" ); 00368 if ( origin < min() ) 00369 throw constraints_exception( "origin coordinate < min" ); 00370 00371 if ( zonePct > 100.0 ) 00372 throw constraints_exception( "zonePct > 100%" ); 00373 00374 if( zonePct < 0 ) 00375 throw constraints_exception( "zonePct < 0%" ); 00376 00377 if( zonePct == 0 ) 00378 throw constraints_exception( "zonePct == 0%" ); 00379 00380 double zoneSize = ( max() - min() ) * zonePct/100.0; 00381 00382 double _min = std::max( min(), origin - zoneSize/2.0 ); 00383 double _max = std::min( max(), origin + zoneSize/2.0 ); 00384 00385 double val = boost::math::round( genrand( _min, _max ) ); 00386 00387 for ( ;val < _min || val > _max; val = boost::math::round( genrand( _min, _max ) ) ); 00388 00389 return val; 00390 } 00391 00392 virtual double get_middle_point() 00393 { 00394 return boost::math::round( ( max() - min() )/2.0 ); 00395 } 00396 00397 00398 }; 00399 00408 class set_constraint : public constraint 00409 { 00410 private: 00411 class unique : public std::unary_function < Double, bool > 00412 { 00413 public: 00414 bool operator ()( Double d ) const 00415 { 00416 return m_unique.insert( d ).second; 00417 } 00418 00419 public: 00420 double min() const 00421 { 00422 if( m_unique.size() > 0 ) 00423 return *m_unique.begin(); 00424 else 00425 throw constraints_exception( "could not get the min value of an empty set constraint" ); 00426 } 00427 00428 double max() const 00429 { 00430 if( m_unique.size() > 0 ) 00431 return *m_unique.rbegin(); 00432 else 00433 throw constraints_exception( "could not get the max value of an empty set constraint" ); 00434 } 00435 00436 private: 00437 mutable std::set< Double > m_unique; 00438 }; 00439 private: 00440 unique m_unique; 00441 de::DVector m_values; 00442 00443 public: 00453 set_constraint( const de::DVector& values ) 00454 { 00455 // making sure the values in the "set" are unique 00456 std::remove_copy_if (values.begin (), values.end (), std::back_inserter( m_values ), m_unique ); 00457 } 00458 00467 void add_value( de::Double value ) 00468 { 00469 if( m_unique( value ) ) 00470 m_values.push_back( value ); 00471 } 00472 00481 virtual double get_rand_value() 00482 { 00483 de::DVector::size_type index( genintrand( 0, m_values.size() - 1 ) ); 00484 00485 return m_values[ index ]; 00486 } 00487 00496 virtual double get_rand_value(double value, double origin) 00497 { 00498 return get_rand_value(); 00499 } 00500 00508 double min() const 00509 { 00510 return m_unique.min(); 00511 } 00512 00520 double max() const 00521 { 00522 return m_unique.max(); 00523 } 00524 00525 virtual double get_rand_value_in_zone( double origin, double zonePct ) const 00526 { 00527 throw constraints_exception( "get_rand_value_in_zone only supported for range constraints" ); 00528 } 00529 00530 virtual double get_middle_point() 00531 { 00532 throw constraints_exception( "get_middle_point not supported by set constraint" ); 00533 } 00534 00535 }; 00536 00543 class boolean_constraint : public constraint 00544 { 00545 public: 00553 virtual double get_rand_value() 00554 { 00555 return genrand() < 0.5; 00556 } 00557 00565 virtual double get_rand_value(double value, double origin) 00566 { 00567 return get_rand_value(); 00568 } 00569 00577 double min() const 00578 { 00579 return 0; 00580 } 00581 00589 double max() const 00590 { 00591 return 1; 00592 } 00593 00594 virtual double get_rand_value_in_zone( double origin, double zonePct ) const 00595 { 00596 throw constraints_exception( "get_rand_value_in_zone only supported for range constraints" ); 00597 } 00598 00599 virtual double get_middle_point() 00600 { 00601 throw constraints_exception( "get_middle_point not supported by bool constraint" ); 00602 } 00603 00604 }; 00605 00606 typedef std::vector< constraint_ptr > constraints_base; 00607 00616 class constraints : public constraints_base 00617 { 00618 private: 00619 typedef boost::char_separator< char > separator; 00620 typedef boost::tokenizer< separator > tokenizer; 00621 00622 00623 public: 00635 constraints( size_t varCount, double defMin, double defMax ) 00636 : constraints_base( varCount, boost::make_shared< real_constraint >( defMin, defMax ) ) 00637 { 00638 } 00639 00666 constraints( const std::vector< std::string >& str, size_t var_count , double def_min, double def_max ) 00667 : constraints_base( var_count, boost::make_shared< real_constraint >( def_min, def_max ) ) 00668 { 00669 for( std::vector< std::string >::size_type i = 0; i < str.size(); ++i ) 00670 { 00671 tokenizer tokens( str[ i ], separator( ";," ) ); 00672 00673 std::string type; 00674 double _min; 00675 double _max; 00676 00677 size_t count( 0 ); 00678 00679 for( tokenizer::const_iterator j = tokens.begin(); j != tokens.end(); ++j, ++count ) 00680 { 00681 const std::string token( boost::trim_copy( *j ) ); 00682 00683 try 00684 { 00685 switch( count ) 00686 { 00687 case 0: 00688 type = token; 00689 break; 00690 case 1: 00691 _min = boost::lexical_cast< double >( token.c_str() ); 00692 break; 00693 case 2: 00694 _max = boost::lexical_cast< double >( token.c_str() ); 00695 break; 00696 default: 00697 // too many fields 00698 throw constraints_exception( ( boost::format( "wrong variable format in \"%1%\" - too many fields" ) % str[ i ] ).str() ); 00699 00700 } 00701 } 00702 catch( const boost::bad_lexical_cast& ) 00703 { 00704 throw constraints_exception( ( boost::format( "wrong floating point number format: %1%") % token ).str() ); 00705 } 00706 } 00707 00708 // too few fields 00709 if( count < 3 ) 00710 throw constraints_exception( ( boost::format( "wrong variable format in \"%1%\" - too few fields" ) % str[ i ] ).str() ); 00711 00712 if( i < var_count ) 00713 constraints_base::at( i ) = str_to_constraint( type, _min, _max ); 00714 else 00715 constraints_base::push_back( str_to_constraint( type, _min, _max ) ); 00716 } 00717 } 00718 00727 double get_rand_value( size_t index ) 00728 { 00729 if( index < constraints_base::size() ) 00730 return (*this)[ index ]->get_rand_value(); 00731 else 00732 throw constraints_exception( ( boost::format( "invalid constraint index: %1%, higher than max number of constraints: %2%" ) % index % constraints_base::size() ).str() ); 00733 } 00734 00747 double get_rand_value( size_t index, double value, double origin ) 00748 { 00749 if( index < constraints_base::size() ) 00750 return (*this)[ index ]->get_rand_value( value, origin ); 00751 else 00752 throw constraints_exception( ( boost::format( "invalid constraint index: %1%, higher than max number of constraints: %2%" ) % index % constraints_base::size() ).str() ); 00753 } 00754 00768 DVectorPtr get_square_zone_rand_values( const DVectorPtr origin, double sidePct ) const 00769 { 00770 assert( origin ); 00771 assert( sidePct > 0 && sidePct <= 100 ); 00772 00773 if( origin->size() == constraints_base::size() ) 00774 { 00775 DVectorPtr square( boost::make_shared< DVector >( origin->size() ) ); 00776 00777 for( constraints_base::size_type n = 0; n < constraints_base::size(); ++n ) 00778 (*square)[ n ] = (*this)[ n ]->get_rand_value_in_zone( (*origin)[ n ], sidePct ); 00779 00780 return square; 00781 00782 } 00783 else 00784 throw constraints_exception( "The origin vector must have the same number of elements as there are constraints" ); 00785 } 00786 00787 DVectorPtr get_middle_point() 00788 { 00789 DVectorPtr r( boost::make_shared< DVector >( constraints_base::size() ) ); 00790 00791 for( constraints_base::size_type n = 0; n < constraints_base::size(); ++n ) 00792 (*r)[ n ] = (*this)[ n ]->get_middle_point(); 00793 00794 return r; 00795 00796 } 00797 00806 DVectorPtr get_rand_values() const 00807 { 00808 DVectorPtr r( boost::make_shared< DVector >( constraints_base::size() ) ); 00809 00810 for( constraints_base::size_type n = 0; n < constraints_base::size(); ++n ) 00811 (*r)[ n ] = (*this)[ n ]->get_rand_value(); 00812 00813 return r; 00814 } 00815 00816 00817 private: 00818 constraint_ptr str_to_constraint( const std::string& type, double min, double max ) 00819 { 00820 if( boost::to_lower_copy( type ) == "real" ) 00821 return boost::make_shared< real_constraint >( min, max ); 00822 else if( boost::to_lower_copy( type ) == "int" || boost::to_lower_copy( type ) == "integer" ) 00823 return boost::make_shared< int_constraint >( min, max ); 00824 else 00825 throw constraints_exception( ( boost::format( "invalid constraint type \"%1%\"" ) % type ).str() ); 00826 } 00827 }; 00828 00829 typedef boost::shared_ptr< constraints > constraints_ptr; 00830 00831 } 00832 00833 #endif //DE_CONSTRAINTS_HPP_INCLUDED