# es/make_op.h

    00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
    00002
    00003 //-----------------------------------------------------------------------------
    00004 // make_op.h - the real-valued version
    00005 // (c) Maarten Keijzer, Marc Schoenauer and GeNeura Team, 2001
    00006 /*
    00007     This library is free software; you can redistribute it and/or
    00008     modify it under the terms of the GNU Lesser General Public
    00009     License as published by the Free Software Foundation; either
    00010     version 2 of the License, or (at your option) any later version.
    00011
    00012     This library is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015     Lesser General Public License for more details.
    00016
    00017     You should have received a copy of the GNU Lesser General Public
    00018     License along with this library; if not, write to the Free Software
    00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00020
    00021     Contact: todos@geneura.ugr.es, http://geneura.ugr.es
    00022              Marc.Schoenauer@polytechnique.fr
    00023              mkeijzer@dhi.dk
    00024  */
    00025 //-----------------------------------------------------------------------------
    00026
    00027 #ifndef _make_op_h
    00028 #define _make_op_h
    00029
    00030 // the operators
    00031 #include <eoOp.h>
    00032 #include <eoGenOp.h>
    00033 #include <eoCloneOps.h>
    00034 #include <eoOpContainer.h>
    00035 // combinations of simple eoOps (eoMonOp and eoQuadOp)
    00036 #include <eoProportionalCombinedOp.h>
    00037
    00038 // the specialized Real stuff
    00039 #include <es/eoReal.h>
    00040 #include <es/eoRealInitBounded.h>
    00041 #include <es/eoRealOp.h>
    00042 #include <es/eoNormalMutation.h>
    00043   // also need the parser and param includes
    00044 #include <utils/eoParser.h>
    00045 #include <utils/eoState.h>
    00046
    00047
    00048 /*
    00049  * This function builds the operators that will be applied to the eoReal
    00050  *
    00051  * It uses a parser (to get user parameters) and a state (to store the memory)
    00052  * the last argument is an individual, needed for 2 reasons
    00053  *     it disambiguates the call after instanciations
    00054  *     some operator might need some private information about the indis
    00055  *
    00056  * This is why the template is the complete EOT even though only the fitness
    00057  * is actually templatized here: the following only applies to bitstrings
    00058  *
    00059  * Note : the last parameter is an eoInit: if some operator needs some info
    00060  *        about the gneotypes, the init has it all (e.g. bounds, ...)
    00061  *        Simply do
    00062  *        EOT myEO;
    00063  *        _init(myEO);
    00064  *        and myEO is then an ACTUAL object
    00065 */
    00066 template <class EOT>
    00067 eoGenOp<EOT> & do_make_op(eoParameterLoader& _parser, eoState& _state, eoInit<EOT>& _init)
    00068 {
    00069   // First, decide whether the objective variables are bounded
    00070   eoValueParam<eoParamParamType>& boundsParam
    00071       = _parser.getORcreateParam(eoParamParamType("(0,1)"), "objectBounds",
    00072                                  "Bounds for variables (unbounded if absent)",
    00073                                  'B', "Genetic Operators");
    00074
    00075   // get initisalizer size == std::vector size
    00076   //  eoRealInitBounded<EOT> * realInit = (eoRealInitBounded<EOT>*)(&_init);
    00077   //  unsigned vecSize = realInit->theBounds().size();
    00078
    00079   // get std::vector size: safer???
    00080   EOT eoTmp;
    00081   _init(eoTmp);
    00082   unsigned vecSize = eoTmp.size();
    00083
    00084   // the bounds pointer
    00085   eoRealVectorBounds * ptBounds;
    00086   if (_parser.isItThere(boundsParam))   // otherwise, no bounds
    00087     {
    00091       eoParamParamType & ppBounds = boundsParam.value(); // std::pair<std::string,std::vector<std::string> >
    00092       // transform into a std::vector<double>
    00093       std::vector<double> v;
    00094       std::vector<std::string>::iterator it;
    00095       for (it=ppBounds.second.begin(); it<ppBounds.second.end(); it++)
    00096         {
    00097           istrstream is(it->c_str());
    00098           double r;
    00099           is >> r;
    00100           v.push_back(r);
    00101         }
    00102       // now create the eoRealVectorBounds object
    00103       if (v.size() == 2) // a min and a max for all variables
    00104         ptBounds = new eoRealVectorBounds(vecSize, v[0], v[1]);
    00105       else                                 // no time now
    00106         throw std::runtime_error("Sorry, only unique bounds for all variables implemented at the moment. Come back later");
    00107       // we need to give ownership of this pointer to somebody
    00109     }
    00110   else                     // no param for bounds was given
    00111     ptBounds = new eoRealVectorNoBounds(vecSize); // DON'T USE eoDummyVectorNoBounds
    00112                                    // as it does not have any dimension
    00113
    00114   // this is a temporary version(!),
    00115   // while Maarten codes the full tree-structured general operator input
    00116   // BTW we must leave that simple version available somehow, as it is the one
    00117   // that 90% people use!
    00118   eoValueParam<std::string>& operatorParam
    00119       =  _parser.getORcreateParam(std::string("SGA"), "operator",
    00120                                   "Description of the operator (SGA only now)",
    00121                                   'o', "Genetic Operators");
    00122
    00123   if (operatorParam.value() != std::string("SGA"))
    00124     throw std::runtime_error("Sorry, only SGA-like operator available right now\n");
    00125
    00126     // now we read Pcross and Pmut,
    00127     // the relative weights for all crossovers -> proportional choice
    00128     // the relative weights for all mutations -> proportional choice
    00129     // and create the eoGenOp that is exactly
    00130     // crossover with pcross + mutation with pmut
    00131
    00132   eoValueParam<double>& pCrossParam
    00133       = _parser.getORcreateParam(0.6, "pCross", "Probability of Crossover",
    00134                                  'C', "Genetic Operators" );
    00135   // minimum check
    00136   if ( (pCrossParam.value() < 0) || (pCrossParam.value() > 1) )
    00137     throw std::runtime_error("Invalid pCross");
    00138
    00139   eoValueParam<double>& pMutParam
    00140       = _parser.getORcreateParam(0.1, "pMut", "Probability of Mutation",
    00141                                  'M', "Genetic Operators" );
    00142   // minimum check
    00143   if ( (pMutParam.value() < 0) || (pMutParam.value() > 1) )
    00144     throw std::runtime_error("Invalid pMut");
    00145
    00146     // the crossovers
    00148     // the parameters
    00149   eoValueParam<double>& segmentRateParam
    00150       = _parser.getORcreateParam(double(1.0), "segmentRate",
    00151                                  "Relative rate for segment crossover",
    00152                                  's', "Genetic Operators" );
    00153   // minimum check
    00154   if ( (segmentRateParam.value() < 0) )
    00155     throw std::runtime_error("Invalid segmentRate");
    00156
    00157   eoValueParam<double>& arithmeticRateParam
    00158       = _parser.getORcreateParam(double(2.0), "arithmeticRate",
    00159                                  "Relative rate for arithmetic crossover",
    00160                                  'A', "Genetic Operators" );
    00161   // minimum check
    00162   if ( (arithmeticRateParam.value() < 0) )
    00163     throw std::runtime_error("Invalid arithmeticRate");
    00164
    00165     // minimum check
    00166   bool bCross = true;
    00167   if (segmentRateParam.value()+arithmeticRateParam.value()==0)
    00168     {
    00169       std::cerr << "Warning: no crossover" << std::endl;
    00170       bCross = false;
    00171     }
    00172
    00173   // Create the CombinedQuadOp
    00174   eoPropCombinedQuadOp<EOT> *ptCombinedQuadOp = NULL;
    00175   eoQuadOp<EOT> *ptQuad = NULL;
    00176
    00177   if (bCross)
    00178     {
    00179       // segment crossover for bitstring - pass it the bounds
    00180       ptQuad = new eoSegmentCrossover<EOT>(*ptBounds);
    00181       _state.storeFunctor(ptQuad);
    00182       ptCombinedQuadOp = new eoPropCombinedQuadOp<EOT>(*ptQuad, segmentRateParam.value());
    00183
    00184         // arithmetic crossover
    00185       ptQuad = new eoArithmeticCrossover<EOT>(*ptBounds);
    00186       _state.storeFunctor(ptQuad);
    00187       ptCombinedQuadOp->add(*ptQuad, arithmeticRateParam.value());
    00188
    00189       // don't forget to store the CombinedQuadOp
    00190       _state.storeFunctor(ptCombinedQuadOp);
    00191     }
    00192
    00193   // the mutations
    00195   // the parameters
    00196   eoValueParam<double> & epsilonParam
    00197       = _parser.getORcreateParam(0.01, "epsilon", "Half-size of interval for Uniform Mutation",
    00198                                  'e', "Genetic Operators" );
    00199   // minimum check
    00200   if ( (epsilonParam.value() < 0) )
    00201     throw std::runtime_error("Invalid epsilon");
    00202
    00203   eoValueParam<double> & uniformMutRateParam
    00204       = _parser.getORcreateParam(1.0, "uniformMutRate",
    00205                                  "Relative rate for uniform mutation", 'u', "Genetic Operators" );
    00206   // minimum check
    00207   if ( (uniformMutRateParam.value() < 0) )
    00208     throw std::runtime_error("Invalid uniformMutRate");
    00209
    00210   eoValueParam<double> & detMutRateParam
    00211       = _parser.getORcreateParam(1.0, "detMutRate",
    00212                                  "Relative rate for deterministic uniform mutation",
    00213                                  'd', "Genetic Operators" );
    00214   // minimum check
    00215   if ( (detMutRateParam.value() < 0) )
    00216     throw std::runtime_error("Invalid detMutRate");
    00217
    00218   eoValueParam<double> & normalMutRateParam
    00219       = _parser.getORcreateParam(1.0, "normalMutRate",
    00220                                  "Relative rate for Gaussian mutation",
    00221                                  'd', "Genetic Operators" );
    00222   // minimum check
    00223   if ( (normalMutRateParam.value() < 0) )
    00224     throw std::runtime_error("Invalid normalMutRate");
    00225   // and the sigma
    00226   eoValueParam<double> & sigmaParam
    00227       = _parser.getORcreateParam(1.0, "sigma",
    00228                                  "Sigma (fixed) for Gaussian mutation",
    00229                                  'S', "Genetic Operators" );
    00230   // minimum check
    00231   if ( (sigmaParam.value() < 0) )
    00232     throw std::runtime_error("Invalid sigma");
    00233
    00234     // minimum check
    00235   bool bMut = true;
    00236   if (uniformMutRateParam.value()+detMutRateParam.value()+normalMutRateParam.value()==0)
    00237     {
    00238       std::cerr << "Warning: no mutation" << std::endl;
    00239       bMut = false;
    00240     }
    00241   if (!bCross && !bMut)
    00242     throw std::runtime_error("No operator called in SGA operator definition!!!");
    00243
    00244     // Create the CombinedMonOp
    00245   eoPropCombinedMonOp<EOT> *ptCombinedMonOp = NULL;
    00246   eoMonOp<EOT> *ptMon = NULL;
    00247
    00248   if (bMut)
    00249     {
    00250       // uniform mutation on all components:
    00251       // offspring(i) uniformly chosen in [parent(i)-epsilon, parent(i)+epsilon]
    00252       ptMon = new eoUniformMutation<EOT>(*ptBounds, epsilonParam.value());
    00253       _state.storeFunctor(ptMon);
    00254       // create the CombinedMonOp
    00255       ptCombinedMonOp = new eoPropCombinedMonOp<EOT>(*ptMon, uniformMutRateParam.value());
    00256
    00257         // mutate exactly 1 component (uniformly) per individual
    00258       ptMon = new eoDetUniformMutation<EOT>(*ptBounds, epsilonParam.value());
    00259       _state.storeFunctor(ptMon);
    00260       ptCombinedMonOp->add(*ptMon, detMutRateParam.value());
    00261
    00262       // mutate all component using Gaussian mutation
    00263       ptMon = new eoNormalMutation<EOT>(*ptBounds, sigmaParam.value());
    00264       _state.storeFunctor(ptMon);
    00265       ptCombinedMonOp->add(*ptMon, normalMutRateParam.value());
    00266       _state.storeFunctor(ptCombinedMonOp);
    00267     }
    00268
    00269   // now build the eoGenOp:
    00270   // to simulate SGA (crossover with proba pCross + mutation with proba pMut
    00271   // we must construct
    00272   //     a sequential combination of
    00273   //          with proba 1, a proportional combination of
    00274   //                        a QuadCopy and our crossover
    00275   //          with proba pMut, our mutation
    00276
    00277   // the crossover - with probability pCross
    00278   eoProportionalOp<EOT> * cross = new eoProportionalOp<EOT> ;
    00279   _state.storeFunctor(cross);
    00280   ptQuad = new eoQuadCloneOp<EOT>;
    00281   _state.storeFunctor(ptQuad);
    00282   cross->add(*ptCombinedQuadOp, pCrossParam.value()); // user crossover
    00283   cross->add(*ptQuad, 1-pCrossParam.value()); // clone operator
    00284
    00285   // now the sequential
    00286   eoSequentialOp<EOT> *op = new eoSequentialOp<EOT>;
    00287   _state.storeFunctor(op);
    00288   op->add(*cross, 1.0);  // always crossover (but clone with prob 1-pCross
    00289   op->add(*ptCombinedMonOp, pMutParam.value());
    00290
    00291   // that's it!
    00292   return *op;
    00293 }
    00294 #endif