diff --git a/eo/src/ga/eoStandardBitMutation.h b/eo/src/ga/eoStandardBitMutation.h index fd6e4263e..32ece1342 100644 --- a/eo/src/ga/eoStandardBitMutation.h +++ b/eo/src/ga/eoStandardBitMutation.h @@ -7,6 +7,8 @@ /** Standard bit mutation with mutation rate p: * choose k from the binomial distribution Bin(n,p) and apply flip_k(x). * + * If rate is null (the default), use 1/chrom.size(). + * * @ingroup Bitstrings * @ingroup Variators */ @@ -14,7 +16,11 @@ template class eoStandardBitMutation : public eoMonOp { public: - eoStandardBitMutation(double rate = 0.5) : + /** Constructor. + * + * @param rate mutation rate, 1/chrom.size() if ignored or zero (the default) + */ + eoStandardBitMutation(double rate = 0) : _rate(rate), _nb(1), _bitflip(_nb) @@ -22,9 +28,12 @@ class eoStandardBitMutation : public eoMonOp virtual bool operator()(EOT& chrom) { + assert(chrom.size()>0); + if(_rate == 0) { + _rate = (double) 1/chrom.size(); + } _nb = eo::rng.binomial(chrom.size(),_rate); - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. + _bitflip.number_bits(_nb); return _bitflip(chrom); } @@ -46,8 +55,7 @@ template class eoUniformBitMutation : public eoMonOp { public: - eoUniformBitMutation(double rate = 0.5) : - _rate(rate), + eoUniformBitMutation() : _nb(1), _bitflip(_nb) {} @@ -55,15 +63,13 @@ class eoUniformBitMutation : public eoMonOp virtual bool operator()(EOT& chrom) { _nb = eo::rng.random(chrom.size()); - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. + _bitflip.number_bits(_nb); return _bitflip(chrom); } virtual std::string className() const {return "eoUniformBitMutation";} protected: - double _rate; unsigned _nb; eoDetSingleBitFlip _bitflip; }; @@ -84,17 +90,21 @@ template class eoConditionalBitMutation : public eoStandardBitMutation { public: - eoConditionalBitMutation(double rate = 0.5) : + eoConditionalBitMutation(double rate = 0) : eoStandardBitMutation(rate) {} virtual bool operator()(EOT& chrom) { assert(chrom.size()>0); - this->_nb = eo::rng.binomial(chrom.size()-1,this->_rate); - this->_nb++; - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. + if(this->_rate == 0) { + this->_rate = (double) 1/chrom.size(); + } + this->_nb = 0; + while(this->_nb < 1) { + this->_nb = eo::rng.binomial(chrom.size(),this->_rate); + } + this->_bitflip.number_bits(this->_nb); return this->_bitflip(chrom); } @@ -123,12 +133,14 @@ class eoShiftedBitMutation : public eoStandardBitMutation virtual bool operator()(EOT& chrom) { assert(chrom.size()>0); - this->_nb = eo::rng.binomial(chrom.size()-1,this->_rate); + if(this->_rate == 0) { + this->_rate = (double) 1/chrom.size(); + } + this->_nb = eo::rng.binomial(chrom.size(),this->_rate); if(this->_nb == 0) { this->_nb = 1; } - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. + this->_bitflip.number_bits(this->_nb); return this->_bitflip(chrom); } @@ -142,7 +154,7 @@ class eoShiftedBitMutation : public eoStandardBitMutation * * From: * Furong Ye, Carola Doerr, and Thomas Back. - * Interpolating local and global search by controllingthe variance of standard bit mutation. + * Interpolating local and global search by controlling the variance of standard bit mutation. * In 2019 IEEE Congress on Evolutionary Computation(CEC), pages 2292–2299. * * In contrast to standard bit mutation, this operators allows to scale @@ -152,29 +164,40 @@ class eoShiftedBitMutation : public eoStandardBitMutation * @ingroup Variators */ template -class eoNormalBitMutation : public eoStandardBitMutation +class eoNormalBitMutation : public eoMonOp { public: - eoNormalBitMutation(double rate = 0.5, double variance = 1) : - eoStandardBitMutation(rate), - _variance(variance) + eoNormalBitMutation(double mean = 0, double variance = 0) : + _mean(mean), + _variance(variance), + _nb(1), + _bitflip(_nb) {} virtual bool operator()(EOT& chrom) { - this->_nb = eo::rng.normal(this->_rate * chrom.size(), _variance); - if(this->_nb >= chrom.size()) { - this->_nb = eo::rng.random(chrom.size()); + assert(chrom.size() > 0); + if(_mean == 0) { + _mean = (double) 1/chrom.size(); } - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. - return this->_bitflip(chrom); + if(_variance == 0) { + _variance = std::log(chrom.size()); + } + _nb = eo::rng.normal(_mean, _variance); + if(_nb >= chrom.size()) { + _nb = eo::rng.random(chrom.size()); + } + _bitflip.number_bits(_nb); + return _bitflip(chrom); } virtual std::string className() const {return "eoNormalBitMutation";} protected: + double _mean; double _variance; + unsigned _nb; + eoDetSingleBitFlip _bitflip; }; /** Fast mutation which size is sampled from an adaptive power law. @@ -188,11 +211,10 @@ class eoNormalBitMutation : public eoStandardBitMutation * @ingroup Variators */ template -class eoFastBitMutation : public eoStandardBitMutation +class eoFastBitMutation : public eoMonOp { public: - eoFastBitMutation(double rate = 0.5, double beta = 1.5) : - eoStandardBitMutation(rate), + eoFastBitMutation(double beta = 1.5) : _beta(beta) { assert(beta > 1); @@ -200,74 +222,96 @@ class eoFastBitMutation : public eoStandardBitMutation virtual bool operator()(EOT& chrom) { - this->_nb = powerlaw(chrom.size(),_beta); - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. - return this->_bitflip(chrom); + _nb = powerlaw(chrom.size(),_beta); + _bitflip.number_bits(_nb); + return _bitflip(chrom); } virtual std::string className() const {return "eoFastBitMutation";} protected: - - double powerlaw(unsigned n, double beta) + double powerlaw(unsigned int n, double beta) { double cnb = 0; - for(unsigned i=1; i= trigger) { + rate = static_cast(i) / static_cast(n); + break; + } + } + return eo::rng.binomial(n,rate); } + // double powerlaw(unsigned n, double beta) + // { + // double cnb = 0; + // for(unsigned i=1; i _bitflip; }; /** Bucket mutation which assign probability for each bucket + * + * @warning Highly untested code, use with caution. * * From: - * Carola Doerr, Johann Dréo, Alexis Robbes + * Carola Doerr, Johann Dreo, Alexis Robbes */ template -class eoBucketBitMutation : public eoStandardBitMutation +class eoBucketBitMutation : public eoMonOp { public: - eoBucketBitMutation(std::vector bucketsSizes, std::vector bucketValues) : - _bucketsSizes(bucketsSizes), - _bucketValues(bucketValues) - + eoBucketBitMutation(std::vector> buckets, std::vector bucketsValues) : + _buckets(buckets), + _bucketsValues(bucketsValues) { - assert(bucketsSizes.size() != bucketValues.size()); + assert(buckets.size() == bucketsValues.size()); } virtual bool operator()(EOT& chrom) { - - this->_nb = customlaw(chrom.size(), _bucketsSizes, _bucketValues); - // BitFlip operator is bound to the _nb reference, - // thus one don't need to re-instantiate. - return this->_bitflip(chrom); + _nb = customlaw(chrom.size(), _buckets, _bucketsValues); + _bitflip.number_bits(_nb); + return _bitflip(chrom); } virtual std::string className() const {return "eoBucketBitMutation";} protected: - double customlaw(unsigned n, std::vector bucketsSizes, std::vector bucketValues) + double customlaw(unsigned n, std::vector> buckets, std::vector bucketsValues) { - int targetBucketIndex = eo::rng.roulette_wheel(bucketValues); - int nb = 0; - int bucketIndex = 0; - while (nb < n && bucketIndex <= targetBucketIndex) - { - if (bucketIndex < targetBucketIndex) nb += int(n*bucketsSizes[bucketIndex]); - else nb += int(eo::rng.uniform(1, n*bucketsSizes[targetBucketIndex])); - } - if (nb > n) nb = n; - - return nb; - } + int bucketIndex = eo::rng.roulette_wheel(bucketsValues); + int startBit = buckets[bucketIndex][0]; + int endBit = buckets[bucketIndex][1]; + int gapBit = endBit - startBit; - std::vector _bucketsSizes; - std::vector _bucketValues; + int nbBits; + if (gapBit > 0) { + nbBits = rand() % gapBit + startBit; + } else { + nbBits = endBit; + } + return nbBits; + } + std::vector _bucketsValues; + std::vector> _buckets; + + unsigned _nb; + eoDetSingleBitFlip _bitflip; }; + #endif // _eoStandardBitMutation_h_ diff --git a/eo/test/t-eoFoundryFastGA.cpp b/eo/test/t-eoFoundryFastGA.cpp index 6a6ee0322..24231d639 100644 --- a/eo/test/t-eoFoundryFastGA.cpp +++ b/eo/test/t-eoFoundryFastGA.cpp @@ -30,13 +30,13 @@ eoAlgoFoundryFastGA& make_foundry(eoFunctorStore& store, eoInit& ini foundry.crossovers.add< eo1PtBitXover >(); /***** Mutations ****/ - double p = 1.0; // Probability of flipping eath bit. - foundry.mutations.add< eoUniformBitMutation >(p); // proba of flipping k bits, k drawn in uniform distrib - foundry.mutations.add< eoStandardBitMutation >(p); // proba of flipping k bits, k drawn in binomial distrib - foundry.mutations.add< eoConditionalBitMutation >(p); // proba of flipping k bits, k drawn in binomial distrib, minus zero - foundry.mutations.add< eoShiftedBitMutation >(p); // proba of flipping k bits, k drawn in binomial distrib, changing zeros to one - foundry.mutations.add< eoNormalBitMutation >(p); // proba of flipping k bits, k drawn in normal distrib - foundry.mutations.add< eoFastBitMutation >(p); // proba of flipping k bits, k drawn in powerlaw distrib + // Use defaults for all operators (usually falls back to p=1/chrom.size()). + foundry.mutations.add< eoUniformBitMutation >(); // proba of flipping k bits, k drawn in uniform distrib + foundry.mutations.add< eoStandardBitMutation >(); // proba of flipping k bits, k drawn in binomial distrib + foundry.mutations.add< eoConditionalBitMutation >(); // proba of flipping k bits, k drawn in binomial distrib, minus zero + foundry.mutations.add< eoShiftedBitMutation >(); // proba of flipping k bits, k drawn in binomial distrib, changing zeros to one + foundry.mutations.add< eoNormalBitMutation >(); // proba of flipping k bits, k drawn in normal distrib + foundry.mutations.add< eoFastBitMutation >(); // proba of flipping k bits, k drawn in powerlaw distrib for(size_t i=1; i < 11; i+=1) { foundry.mutations.add< eoDetSingleBitFlip >(i); // mutate k bits without duplicates }