ga/src/core/mutation.cpp

00001 /********************************************************************************
00002  *  FARSA Genetic Algorithm Library                                             *
00003  *  Copyright (C) 2007-2008 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #include "core/mutation.h"
00021 #include "core/geneticalgo.h"
00022 #include "configurationparameters.h"
00023 #include "configurationhelper.h"
00024 
00025 namespace farsa {
00026 
00027 Mutation::Mutation() {
00028     genomev = 0;
00029     ga = 0;
00030     lastGenMutaRatesChange = 0;
00031 
00032     // We put at least one element in the map to avoid crashes
00033     mutaRates[0] = MutationRate();
00034 }
00035 
00036 Mutation::~Mutation() {
00037     //--- nothing to do
00038 }
00039 
00040 void Mutation::setMutationRate( double rate, int start, int length) {
00041     // This simply calls the other setMutationRate function with equal initial and final rate
00042     setMutationRate(rate, rate, 0.0, start, length);
00043 }
00044 
00045 void Mutation::setMutationRate( double initialRate, double finalRate, double variation, int start, int length) {
00046     // Create a mutex locker to make this method thread-safe
00047     QMutexLocker locker(&mutaRatesMutex);
00048 
00049     // First of all we have to change variation sign depending on whether initialMutaRate is
00050     // greater than finalMutaRate or not
00051     if (((initialRate > finalRate) && (variation > 0.0)) || ((initialRate < finalRate) && (variation < 0.0))) {
00052         variation = -variation;
00053     }
00054 
00055     // Iterate over the map to see what we have to do
00056     QMap<int, MutationRate>::iterator iter = mutaRates.begin();
00057     MutationRate current;
00058     while (iter != mutaRates.end()) {
00059         if (iter.key() <= start) {
00060             // Found a value before the start
00061             current = iter.value();
00062 
00063             iter++;
00064         } else if ((length <= 0) || (iter.key() <= (start + length))) {
00065             // Overwrite all the values in the range
00066             // If length is smaller than one, the range is open-ended and we
00067             // have to remove all the values after start
00068             current = iter.value();
00069 
00070             QMap<int, MutationRate>::iterator tmp = iter;
00071             iter++;
00072             mutaRates.erase(tmp);
00073         } else {
00074             // Passed the end of the range, can stop iterating
00075             break;
00076         }
00077     }
00078 
00079     // Set the new rate at the start
00080     MutationRate newRate;
00081     newRate.initial = initialRate;
00082     newRate.final = finalRate;
00083     newRate.variation = variation;
00084     if (ga != NULL) {
00085         newRate.rateForGeneration(ga->generation());
00086     } else {
00087         newRate.mutaRate = initialRate;
00088     }
00089     mutaRates[start] = newRate;
00090     if (length > 0) {
00091         // If the list has a fixed end, set the value that was there before
00092         mutaRates[start + length] = current;
00093     }
00094 }
00095 
00096 double Mutation::mutationRate( int bit ) {
00097     // Create a mutex locker to make this method thread-safe
00098     QMutexLocker locker(&mutaRatesMutex);
00099 
00100     if ((ga != NULL) && (ga->generation() != lastGenMutaRatesChange)) {
00101         lastGenMutaRatesChange = ga->generation();
00102         updateMutationRates();
00103     }
00104 
00105     return getMutationRateForBit(bit).mutaRate;
00106 }
00107 
00108 double Mutation::initialMutationRate( int bit ) {
00109     return getMutationRateForBit(bit).initial;
00110 }
00111 
00112 double Mutation::finalMutationRate( int bit ) {
00113     return getMutationRateForBit(bit).final;
00114 }
00115 
00116 double Mutation::variationMutationRate( int bit ) {
00117     return getMutationRateForBit(bit).variation;
00118 }
00119 
00120 #ifdef __GNUC__
00121     #warning IN Mutation: WE SHOULD ALLOW SETTING MUTATION RATES FOR VARIOUS BITS FROM CONFIGURATION FILE
00122 #endif
00123 
00124 void Mutation::configure( ConfigurationParameters& params, QString prefix ) {
00125     double initial_mutation_rate, final_mutation_rate, variation_mutation_rate;
00126 
00127     // The mutation_rate parameter simply sets both initial_mutation_rate and final_mutation_rate
00128     // to the same value. The value of initial_mutation_rate and final_mutation_rate, however,
00129     // overwrites the one of mutation_rate
00130     initial_mutation_rate = final_mutation_rate = ConfigurationHelper::getDouble(params, prefix + "mutation_rate", 0.0);
00131     initial_mutation_rate = ConfigurationHelper::getDouble(params, prefix + "initial_mutation_rate", initial_mutation_rate);
00132     final_mutation_rate = ConfigurationHelper::getDouble(params, prefix + "final_mutation_rate", final_mutation_rate);
00133     variation_mutation_rate = ConfigurationHelper::getDouble(params, prefix + "variation_mutation_rate", 0.01);
00134     setMutationRate(initial_mutation_rate, final_mutation_rate, variation_mutation_rate);
00135     if ( mutationRate(0) == 0 ) {
00136         qWarning( "Setting mutation Rate to ZERO!! Check your config file" );
00137     }
00138 }
00139 
00140 void Mutation::save( ConfigurationParameters& params, QString prefix ) {
00141     // Here we set only mutation_rate if initial_mutation_rate and final_mutation_rate are equal, otherwise we
00142     // set both initial_mutation_rate and final_mutation_rate and variation_mutation_rate. Also we only write the
00143     // mutation rate for the bit 0
00144     params.createParameter( prefix, QString("type"), "Mutation" );
00145     if (initialMutationRate(0) == finalMutationRate(0)) {
00146         params.createParameter( prefix, QString("mutation_rate"), QString("%1").arg(mutationRate(0)) );
00147     } else {
00148         params.createParameter( prefix, QString("initial_mutation_rate"), QString("%1").arg(initialMutationRate(0)) );
00149         params.createParameter( prefix, QString("final_mutation_rate"), QString("%1").arg(finalMutationRate(0)) );
00150         params.createParameter( prefix, QString("variation_mutation_rate"), QString("%1").arg(variationMutationRate(0)) );
00151     }
00152 }
00153 
00154 void Mutation::describe( QString type ) {
00155     Descriptor d = addTypeDescription( type, "Mutation operator" );
00156     d.describeReal( "mutation_rate" ).limits( 0, 1 ).def( 0.05 ).props( IsMandatory ).help( "The probability to apply the mutation operator" );
00157     d.describeReal( "initial_mutation_rate" ).limits( 0, 1 ).def( 0.05 ).help( "The initial probability to apply the mutation operator; this has to be used in combination with final_mutation_rate and variation_mutation_rate to implement a probability of mutation that vary over generations" );
00158     d.describeReal( "final_mutation_rate" ).limits( 0, 1 ).def( 0.05 ).help( "The final probability to apply the mutation operator; this has to be used in combination with initial_mutation_rate and variation_mutation_rate to implement a probability of mutation that vary over generations" );
00159     d.describeReal( "variation_mutation_rate" ).limits( 0, 1 ).def( 0.05 ).help( "The amount of change applied to the current probability to apply the mutation operator in the next generation; this has to be used in combination with initial_mutation_rate and final_mutation_rate to implement a probability of mutation that vary over generations" );
00160 }
00161 
00162 void Mutation::updateMutationRates() {
00163     for (QMap<int, MutationRate>::iterator iter = mutaRates.begin(); iter != mutaRates.end(); iter++) {
00164         if (ga != NULL) {
00165             iter.value().rateForGeneration(ga->generation());
00166         } else {
00167             iter.value().mutaRate = iter.value().initial;
00168         }
00169     }
00170 }
00171 
00172 void Mutation::MutationRate::rateForGeneration(unsigned int gen) {
00173     mutaRate = initial + variation * double(gen);
00174     if (((initial > final) && (mutaRate < final)) || ((initial < final) && (mutaRate > final))) {
00175         mutaRate = final;
00176     }
00177 }
00178 
00179 #ifdef __GNUC__
00180     #warning WE SHOULD TRY TO MAKE Mutation::getMutationRateForBit MORE EFFICIENT
00181 #endif
00182 
00183 const Mutation::MutationRate& Mutation::getMutationRateForBit( int bit ) const {
00184     // This is to avoid problems with negative values (which are invalid anyway)
00185     if (bit < 0) {
00186         bit = 0;
00187     }
00188 
00189     // Find the last entry in the map before the given bit
00190     QMap<int, MutationRate>::const_iterator iter = mutaRates.constBegin();
00191     for (; (iter != mutaRates.constEnd()) && (iter.key() <= bit); iter++);
00192 
00193     // There is at least one element in the map, so we can safely move backward one step
00194     iter--;
00195     return iter.value();
00196 }
00197 
00198 } // end namespace farsa