EvolvingObjects
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 
00052 /*
00053  * This function builds the operators that will be applied to the eoReal
00054  *
00055  * It uses a parser (to get user parameters) and a state (to store the memory)
00056  * the last argument is an individual, needed for 2 reasons
00057  *     it disambiguates the call after instanciations
00058  *     some operator might need some private information about the indis
00059  *
00060  * This is why the template is the complete EOT even though only the fitness
00061  * is actually templatized here: the following only applies to bitstrings
00062  *
00063  * Note : the last parameter is an eoInit: if some operator needs some info
00064  *        about the gneotypes, the init has it all (e.g. bounds, ...)
00065  *        Simply do
00066  *        EOT myEO;
00067  *        _init(myEO);
00068  *        and myEO is then an ACTUAL object
00069 */
00070 template <class EOT>
00071 eoGenOp<EOT> & do_make_op(eoParameterLoader& _parser, eoState& _state, eoInit<EOT>& _init)
00072 {
00073   // First, decide whether the objective variables are bounded
00074   eoValueParam<eoParamParamType>& boundsParam
00075       = _parser.getORcreateParam(eoParamParamType("(0,1)"), "objectBounds",
00076                                  "Bounds for variables (unbounded if absent)",
00077                                  'B', "Genetic Operators");
00078 
00079   // get initisalizer size == std::vector size
00080   //  eoRealInitBounded<EOT> * realInit = (eoRealInitBounded<EOT>*)(&_init);
00081   //  unsigned vecSize = realInit->theBounds().size();
00082 
00083   // get std::vector size: safer???
00084   EOT eoTmp;
00085   _init(eoTmp);
00086   unsigned vecSize = eoTmp.size();
00087 
00088   // the bounds pointer
00089   eoRealVectorBounds * ptBounds;
00090   if (_parser.isItThere(boundsParam))   // otherwise, no bounds
00091     {
00095       eoParamParamType & ppBounds = boundsParam.value(); // std::pair<std::string,std::vector<std::string> >
00096       // transform into a std::vector<double>
00097       std::vector<double> v;
00098       std::vector<std::string>::iterator it;
00099       for (it=ppBounds.second.begin(); it<ppBounds.second.end(); it++)
00100         {
00101           istrstream is(it->c_str());
00102           double r;
00103           is >> r;
00104           v.push_back(r);
00105         }
00106       // now create the eoRealVectorBounds object
00107       if (v.size() == 2) // a min and a max for all variables
00108         ptBounds = new eoRealVectorBounds(vecSize, v[0], v[1]);
00109       else                                 // no time now
00110         throw std::runtime_error("Sorry, only unique bounds for all variables implemented at the moment. Come back later");
00111       // we need to give ownership of this pointer to somebody
00113     }
00114   else                     // no param for bounds was given
00115     ptBounds = new eoRealVectorNoBounds(vecSize); // DON'T USE eoDummyVectorNoBounds
00116                                    // as it does not have any dimension
00117 
00118   // this is a temporary version(!),
00119   // while Maarten codes the full tree-structured general operator input
00120   // BTW we must leave that simple version available somehow, as it is the one
00121   // that 90% people use!
00122   eoValueParam<std::string>& operatorParam
00123       =  _parser.getORcreateParam(std::string("SGA"), "operator",
00124                                   "Description of the operator (SGA only now)",
00125                                   'o', "Genetic Operators");
00126 
00127   if (operatorParam.value() != std::string("SGA"))
00128     throw std::runtime_error("Sorry, only SGA-like operator available right now\n");
00129 
00130     // now we read Pcross and Pmut,
00131     // the relative weights for all crossovers -> proportional choice
00132     // the relative weights for all mutations -> proportional choice
00133     // and create the eoGenOp that is exactly
00134     // crossover with pcross + mutation with pmut
00135 
00136   eoValueParam<double>& pCrossParam
00137       = _parser.getORcreateParam(0.6, "pCross", "Probability of Crossover",
00138                                  'C', "Genetic Operators" );
00139   // minimum check
00140   if ( (pCrossParam.value() < 0) || (pCrossParam.value() > 1) )
00141     throw std::runtime_error("Invalid pCross");
00142 
00143   eoValueParam<double>& pMutParam
00144       = _parser.getORcreateParam(0.1, "pMut", "Probability of Mutation",
00145                                  'M', "Genetic Operators" );
00146   // minimum check
00147   if ( (pMutParam.value() < 0) || (pMutParam.value() > 1) )
00148     throw std::runtime_error("Invalid pMut");
00149 
00150     // the crossovers
00152     // the parameters
00153   eoValueParam<double>& segmentRateParam
00154       = _parser.getORcreateParam(double(1.0), "segmentRate",
00155                                  "Relative rate for segment crossover",
00156                                  's', "Genetic Operators" );
00157   // minimum check
00158   if ( (segmentRateParam.value() < 0) )
00159     throw std::runtime_error("Invalid segmentRate");
00160 
00161   eoValueParam<double>& arithmeticRateParam
00162       = _parser.getORcreateParam(double(2.0), "arithmeticRate",
00163                                  "Relative rate for arithmetic crossover",
00164                                  'A', "Genetic Operators" );
00165   // minimum check
00166   if ( (arithmeticRateParam.value() < 0) )
00167     throw std::runtime_error("Invalid arithmeticRate");
00168 
00169     // minimum check
00170   bool bCross = true;
00171   if (segmentRateParam.value()+arithmeticRateParam.value()==0)
00172     {
00173       std::cerr << "Warning: no crossover" << std::endl;
00174       bCross = false;
00175     }
00176 
00177   // Create the CombinedQuadOp
00178   eoPropCombinedQuadOp<EOT> *ptCombinedQuadOp = NULL;
00179   eoQuadOp<EOT> *ptQuad = NULL;
00180 
00181   if (bCross)
00182     {
00183       // segment crossover for bitstring - pass it the bounds
00184       ptQuad = new eoSegmentCrossover<EOT>(*ptBounds);
00185       _state.storeFunctor(ptQuad);
00186       ptCombinedQuadOp = new eoPropCombinedQuadOp<EOT>(*ptQuad, segmentRateParam.value());
00187 
00188         // arithmetic crossover
00189       ptQuad = new eoArithmeticCrossover<EOT>(*ptBounds);
00190       _state.storeFunctor(ptQuad);
00191       ptCombinedQuadOp->add(*ptQuad, arithmeticRateParam.value());
00192 
00193       // don't forget to store the CombinedQuadOp
00194       _state.storeFunctor(ptCombinedQuadOp);
00195     }
00196 
00197   // the mutations
00199   // the parameters
00200   eoValueParam<double> & epsilonParam
00201       = _parser.getORcreateParam(0.01, "epsilon", "Half-size of interval for Uniform Mutation",
00202                                  'e', "Genetic Operators" );
00203   // minimum check
00204   if ( (epsilonParam.value() < 0) )
00205     throw std::runtime_error("Invalid epsilon");
00206 
00207   eoValueParam<double> & uniformMutRateParam
00208       = _parser.getORcreateParam(1.0, "uniformMutRate",
00209                                  "Relative rate for uniform mutation", 'u', "Genetic Operators" );
00210   // minimum check
00211   if ( (uniformMutRateParam.value() < 0) )
00212     throw std::runtime_error("Invalid uniformMutRate");
00213 
00214   eoValueParam<double> & detMutRateParam
00215       = _parser.getORcreateParam(1.0, "detMutRate",
00216                                  "Relative rate for deterministic uniform mutation",
00217                                  'd', "Genetic Operators" );
00218   // minimum check
00219   if ( (detMutRateParam.value() < 0) )
00220     throw std::runtime_error("Invalid detMutRate");
00221 
00222   eoValueParam<double> & normalMutRateParam
00223       = _parser.getORcreateParam(1.0, "normalMutRate",
00224                                  "Relative rate for Gaussian mutation",
00225                                  'd', "Genetic Operators" );
00226   // minimum check
00227   if ( (normalMutRateParam.value() < 0) )
00228     throw std::runtime_error("Invalid normalMutRate");
00229   // and the sigma
00230   eoValueParam<double> & sigmaParam
00231       = _parser.getORcreateParam(1.0, "sigma",
00232                                  "Sigma (fixed) for Gaussian mutation",
00233                                  'S', "Genetic Operators" );
00234   // minimum check
00235   if ( (sigmaParam.value() < 0) )
00236     throw std::runtime_error("Invalid sigma");
00237 
00238     // minimum check
00239   bool bMut = true;
00240   if (uniformMutRateParam.value()+detMutRateParam.value()+normalMutRateParam.value()==0)
00241     {
00242       std::cerr << "Warning: no mutation" << std::endl;
00243       bMut = false;
00244     }
00245   if (!bCross && !bMut)
00246     throw std::runtime_error("No operator called in SGA operator definition!!!");
00247 
00248     // Create the CombinedMonOp
00249   eoPropCombinedMonOp<EOT> *ptCombinedMonOp = NULL;
00250   eoMonOp<EOT> *ptMon = NULL;
00251 
00252   if (bMut)
00253     {
00254       // uniform mutation on all components:
00255       // offspring(i) uniformly chosen in [parent(i)-epsilon, parent(i)+epsilon]
00256       ptMon = new eoUniformMutation<EOT>(*ptBounds, epsilonParam.value());
00257       _state.storeFunctor(ptMon);
00258       // create the CombinedMonOp
00259       ptCombinedMonOp = new eoPropCombinedMonOp<EOT>(*ptMon, uniformMutRateParam.value());
00260 
00261         // mutate exactly 1 component (uniformly) per individual
00262       ptMon = new eoDetUniformMutation<EOT>(*ptBounds, epsilonParam.value());
00263       _state.storeFunctor(ptMon);
00264       ptCombinedMonOp->add(*ptMon, detMutRateParam.value());
00265 
00266       // mutate all component using Gaussian mutation
00267       ptMon = new eoNormalMutation<EOT>(*ptBounds, sigmaParam.value());
00268       _state.storeFunctor(ptMon);
00269       ptCombinedMonOp->add(*ptMon, normalMutRateParam.value());
00270       _state.storeFunctor(ptCombinedMonOp);
00271     }
00272 
00273   // now build the eoGenOp:
00274   // to simulate SGA (crossover with proba pCross + mutation with proba pMut
00275   // we must construct
00276   //     a sequential combination of
00277   //          with proba 1, a proportional combination of
00278   //                        a QuadCopy and our crossover
00279   //          with proba pMut, our mutation
00280 
00281   // the crossover - with probability pCross
00282   eoProportionalOp<EOT> * cross = new eoProportionalOp<EOT> ;
00283   _state.storeFunctor(cross);
00284   ptQuad = new eoQuadCloneOp<EOT>;
00285   _state.storeFunctor(ptQuad);
00286   cross->add(*ptCombinedQuadOp, pCrossParam.value()); // user crossover
00287   cross->add(*ptQuad, 1-pCrossParam.value()); // clone operator
00288 
00289   // now the sequential
00290   eoSequentialOp<EOT> *op = new eoSequentialOp<EOT>;
00291   _state.storeFunctor(op);
00292   op->add(*cross, 1.0);  // always crossover (but clone with prob 1-pCross
00293   op->add(*ptCombinedMonOp, pMutParam.value());
00294 
00295   // that's it!
00296   return *op;
00297 }
00299 #endif
 All Classes Namespaces Files Functions Variables Typedefs Friends