From 4fea57e84d478821c93f86eec644e55aaf556f39 Mon Sep 17 00:00:00 2001 From: evomarc Date: Sat, 9 Feb 2002 04:58:33 +0000 Subject: [PATCH] First instances of the make_xxx_pareto, where xxx is algo, continue and checkpoint --- eo/src/do/make_algo_pareto.h | 203 ++++++++++++++++++++++++++ eo/src/do/make_checkpoint_pareto.h | 225 +++++++++++++++++++++++++++++ eo/src/do/make_continue_pareto.h | 108 ++++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 eo/src/do/make_algo_pareto.h create mode 100644 eo/src/do/make_checkpoint_pareto.h create mode 100644 eo/src/do/make_continue_pareto.h diff --git a/eo/src/do/make_algo_pareto.h b/eo/src/do/make_algo_pareto.h new file mode 100644 index 00000000..223aed6c --- /dev/null +++ b/eo/src/do/make_algo_pareto.h @@ -0,0 +1,203 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// make_algo_pareto.h +// (c) Maarten Keijzer, Marc Schoenauer and GeNeura Team, 2002 +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@inria.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _make_algo_pareto_h +#define _make_algo_pareto_h + +#include "utils/eoData.h" // for eo_is_a_rate +// everything tha's needed for the algorithms - SCALAR fitness + +// Selection +// the eoSelectOne's +#include "eoSelectFromWorth.h" +#include "eoNDSorting.h" + +// Breeders +#include "eoGeneralBreeder.h" + +// Replacement - at the moment limited to eoNDPlusReplacement, locally defined +#include "eoReplacement.h" + +template +class eoNDPlusReplacement : public eoReplacement +{ +public: + eoNDPlusReplacement(eoPerf2Worth& _perf2worth) : perf2worth(_perf2worth) {} + + struct WorthPair : public pair + { + bool operator<(const WorthPair& other) const { return other.first < first; } + }; + + void operator()(eoPop& _parents, eoPop& _offspring) + { + unsigned sz = _parents.size(); + _parents.reserve(_parents.size() + _offspring.size()); + copy(_offspring.begin(), _offspring.end(), back_inserter(_parents)); + + // calculate worths + perf2worth(_parents); + perf2worth.sort_pop(_parents); + perf2worth.resize(_parents, sz); + + _offspring.clear(); + } + +private : + eoPerf2Worth& perf2worth; +}; + + +// Algorithm (only this one needed) +#include "eoEasyEA.h" + + // also need the parser and param includes +#include "utils/eoParser.h" +#include "utils/eoState.h" + + +/* + * This function builds the algorithm (i.e. selection and replacement) + * from existing continue (or checkpoint) and operators + * + * It uses a parser (to get user parameters) and a state (to store the memory) + * the last argument is an individual, needed for 2 reasons + * it disambiguates the call after instanciations + * some operator might need some private information about the indis + * + * This is why the template is the complete EOT even though only the fitness + * is actually templatized here +*/ + +template +eoAlgo & do_make_algo_pareto(eoParser& _parser, eoState& _state, eoEvalFunc& _eval, eoContinue& _continue, eoGenOp& _op) +{ + // the selection + string & selStr = _parser.createParam(string("NSGA-II"), "selCrit", "Pareto Selection Criterion: NSGA, NSGA-II, ParetoRanking", 'S', "Evolution Engine").value(); + double nicheSize = _parser.createParam(1.0, "nicheSize", "Size of niche for NSGA-I", '\0', "Evolution Engine").value(); + eoPerf2Worth *p2w; + if ( (selStr == string("NSGA")) || (selStr == string("NSGA-I") ) ) + p2w = new eoNDSorting_I(nicheSize); + else if (selStr == string("NSGA-II")) + p2w = new eoNDSorting_II(); + else if (selStr == string("ParetoRanking")) + { + eoDominanceMap& dominance = _state.storeFunctor(new eoDominanceMap); + p2w = new eoParetoRanking(dominance); + } + + _state.storeFunctor(p2w); + + // now the selector (from p2w) - cut-and-pasted from make_algo_scalar! + // only all classes are now ...FromWorth ... + // only the ranking is not re-implemented (yet?) + eoValueParam& selectionParam = _parser.createParam(eoParamParamType("DetTour(2)"), "selection", "Selection: Roulette, DetTour(T), StochTour(t) or Random", 'S', "Evolution Engine"); + + eoParamParamType & ppSelect = selectionParam.value(); // pair > + + eoSelectOne* select ; + if (ppSelect.first == string("DetTour")) + { + unsigned detSize; + + if (!ppSelect.second.size()) // no parameter added + { + cerr << "WARNING, no parameter passed to DetTour, using 2" << endl; + detSize = 2; + // put back 2 in parameter for consistency (and status file) + ppSelect.second.push_back(string("2")); + } + else // parameter passed by user as DetTour(T) + detSize = atoi(ppSelect.second[0].c_str()); + select = new eoDetTournamentWorthSelect(*p2w, detSize); + } + else if (ppSelect.first == string("StochTour")) + { + double p; + if (!ppSelect.second.size()) // no parameter added + { + cerr << "WARNING, no parameter passed to StochTour, using 1" << endl; + p = 1; + // put back p in parameter for consistency (and status file) + ppSelect.second.push_back(string("1")); + } + else // parameter passed by user as DetTour(T) + p = atof(ppSelect.second[0].c_str()); + + select = new eoStochTournamentWorthSelect(*p2w, p); + } +// else if (ppSelect.first == string("Sequential")) // one after the other +// { +// bool b; +// if (ppSelect.second.size() == 0) // no argument -> default = ordered +// { +// b=true; +// // put back in parameter for consistency (and status file) +// ppSelect.second.push_back(string("ordered")); +// } +// else +// b = !(ppSelect.second[0] == string("unordered")); +// select = new eoSequentialWorthSelect(b); +// } + else if (ppSelect.first == string("Roulette")) // no argument (yet) + { + select = new eoRouletteWorthSelect(*p2w); + } + else if (ppSelect.first == string("Random")) // no argument, no perf2Worth + { + select = new eoRandomSelect; + } + else + { + string stmp = string("Invalid selection: ") + ppSelect.first; + throw runtime_error(stmp.c_str()); + } + + _state.storeFunctor(select); + + + // the number of offspring + eoValueParam& offspringRateParam = _parser.createParam(eoHowMany(1.0), "nbOffspring", "Nb of offspring (percentage or absolute)", 'O', "Evolution Engine"); + + // the replacement + // actually limited to eoNDPlusReplacement + eoReplacement & replace = _state.storeFunctor( + new eoNDPlusReplacement(*p2w) + ); + + // the general breeder + eoGeneralBreeder *breed = + new eoGeneralBreeder(*select, _op, offspringRateParam.value()); + _state.storeFunctor(breed); + + // now the eoEasyEA + eoAlgo *algo = new eoEasyEA(_continue, _eval, *breed, replace); + _state.storeFunctor(algo); + // that's it! + return *algo; +} + +#endif diff --git a/eo/src/do/make_checkpoint_pareto.h b/eo/src/do/make_checkpoint_pareto.h new file mode 100644 index 00000000..8e325ec3 --- /dev/null +++ b/eo/src/do/make_checkpoint_pareto.h @@ -0,0 +1,225 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// make_checkpoint_pareto.h +// (c) Maarten Keijzer, Marc Schoenauer and GeNeura Team, 2000 +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@inria.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _make_checkpoint_pareto_h +#define _make_checkpoint_pareto_h + +#include + +#include "eoParetoFitness.h" +#include "utils/selectors.h" +#include "EO.h" +#include "eoEvalFuncCounter.h" +#include "utils/checkpointing" + +// at the moment, in utils/make_help.cpp +// this should become some eoUtils.cpp with corresponding eoUtils.h +bool testDirRes(std::string _dirName, bool _erase); +/////////////////// The checkpoint and other I/O ////////////// + +/** Of course, Fitness needs to be an eoParetoFitness!!! + */ +template +eoCheckPoint& do_make_checkpoint_pareto(eoParser& _parser, eoState& _state, eoEvalFuncCounter& _eval, eoContinue& _continue) +{ + // first, create a checkpoint from the eoContinue - and store in _state + eoCheckPoint & checkpoint = + _state.storeFunctor(new eoCheckPoint(_continue)); + + /////// get number of obectives from Fitness - not very elegant + typedef typename EOT::Fitness Fit; + Fit fit; + unsigned nObj = fit.size(); + + /////////////////// + // Counters + ////////////////// + // is nb Eval to be used as counter? + bool useEval = _parser.createParam(true, "useEval", "Use nb of eval. as counter (vs nb of gen.)", '\0', "Output").value(); + + // Create anyway a generation-counter parameter WARNING: not stored anywhere!!! + eoValueParam *generationCounter = new eoValueParam(0, "Gen."); + // Create an incrementor (sub-class of eoUpdater). + eoIncrementor & increment = + _state.storeFunctor(new eoIncrementor(generationCounter->value()) ); + // Add it to the checkpoint, + checkpoint.add(increment); + + // dir for DISK output + string & dirName = _parser.createParam(string("Res"), "resDir", "Directory to store DISK outputs", '\0', "Output - Disk").value(); + // shoudl we empty it if exists + eoValueParam& eraseParam = _parser.createParam(true, "eraseDir", "erase files in dirName if any", '\0', "Output - Disk"); + bool dirOK = false; // not tested yet + + ///////////////////////////////////////// + // now some statistics on the population: + ///////////////////////////////////////// + /** + * existing stats for Pareto as of today, Jan. 31. 2002 + * + * eoSortedPopStat : whole population - type string (!!) + */ + + eoValueParam& fPlotParam = _parser.createParam(eoParamParamType("1(0,1)"), "frontPlot", "Fronts (pairs of comma-separated objectives in 1 single parentheses pair)", '\0', "Output - Graphical"); + + eoParamParamType & fPlot = fPlotParam.value(); // pair > + unsigned frequency = atoi(fPlot.first.c_str()); + if (frequency) // something to plot + { + unsigned nbPlot = fPlot.second.size(); + if ( nbPlot % 2 ) // odd! + throw runtime_error("Odd number of objectives in make_checkpoint_pareto"); + + // only create the necessary stats + std::vector bStat(nObj, false); // track of who's already there + std::vector* > theStats(nObj); + + for (unsigned i=0; i* fStat; + if (!bStat[obj1]) // not already there: create it + { + char s[1024]; + ostrstream os(s, 1022); + os << "Obj. " << obj1 << ends; + fStat = new eoMOFitnessStat(obj1, s); + _state.storeFunctor(fStat); + bStat[obj1]=true; + theStats[obj1]=fStat; + checkpoint.add(*fStat); + } + if (!bStat[obj2]) // not already there: create it + { + char s2[1024]; + ostrstream os2(s2, 1022); + os2 << "Obj. " << obj2 << ends; + fStat = new eoMOFitnessStat(obj2, s2); + _state.storeFunctor(fStat); + bStat[obj2]=true; + theStats[obj2]=fStat; + checkpoint.add(*fStat); + } + +#if !defined(NO_GNUPLOT) + char s3[1024]; + ostrstream os3(s3, 1022); + os3 << "Front." << obj1 << "." << obj2 << "." << ends; + eoGnuplot1DSnapshot & snapshot = _state.storeFunctor(new + eoGnuplot1DSnapshot(dirName, frequency, s3 ) ); + snapshot.pointSize =3; + + checkpoint.add(snapshot); + + snapshot.add(*theStats[obj1]); + snapshot.add(*theStats[obj2]); +#endif + } + } + // Dump of the whole population + //----------------------------- + bool printPop = _parser.createParam(false, "printPop", "Print sorted pop. every gen.", '\0', "Output").value(); + eoSortedPopStat * popStat; + if ( printPop ) // we do want pop dump + { + cout << "On cree printpop\n"; + popStat = & _state.storeFunctor(new eoSortedPopStat); + // add it to the checkpoint + checkpoint.add(*popStat); + } + + /////////////// + // The monitors + /////////////// + // do we want an eoStdoutMonitor? + bool needStdoutMonitor = printPop ; // only this one at the moment + + // The Stdout monitor will print parameters to the screen ... + if ( needStdoutMonitor ) + { + eoStdoutMonitor & monitor = _state.storeFunctor(new eoStdoutMonitor(false)); + + // when called by the checkpoint (i.e. at every generation) + checkpoint.add(monitor); + + // the monitor will output a series of parameters: add them + monitor.add(*generationCounter); + if (useEval) // we want nb of evaluations + monitor.add(_eval); + if ( printPop) + monitor.add(*popStat); + } + + + ////////////////////////////////// + // State savers + ////////////////////////////// + + // feed the state to state savers + // save state every N generation + eoValueParam& saveFrequencyParam = _parser.createParam(unsigned(0), "saveFrequency", "Save every F generation (0 = only final state, absent = never)", '\0', "Persistence" ); + + if (_parser.isItThere(saveFrequencyParam)) + { + // first make sure dirName is OK + if (! dirOK ) + dirOK = testDirRes(dirName, eraseParam.value()); // TRUE + + unsigned freq = (saveFrequencyParam.value()>0 ? saveFrequencyParam.value() : UINT_MAX ); +#ifdef _MSVC + string stmp = dirName + "\generations"; +#else + string stmp = dirName + "/generations"; +#endif + eoCountedStateSaver *stateSaver1 = new eoCountedStateSaver(freq, _state, stmp); + _state.storeFunctor(stateSaver1); + checkpoint.add(*stateSaver1); + } + + // save state every T seconds + eoValueParam& saveTimeIntervalParam = _parser.createParam(unsigned(0), "saveTimeInterval", "Save every T seconds (0 or absent = never)", '\0',"Persistence" ); + if (_parser.isItThere(saveTimeIntervalParam) && saveTimeIntervalParam.value()>0) + { + // first make sure dirName is OK + if (! dirOK ) + dirOK = testDirRes(dirName, eraseParam.value()); // TRUE + +#ifdef _MSVC + string stmp = dirName + "\time"; +#else + string stmp = dirName + "/time"; +#endif + eoTimedStateSaver *stateSaver2 = new eoTimedStateSaver(saveTimeIntervalParam.value(), _state, stmp); + _state.storeFunctor(stateSaver2); + checkpoint.add(*stateSaver2); + } + + // and that's it for the (control and) output + return checkpoint; +} + +#endif diff --git a/eo/src/do/make_continue_pareto.h b/eo/src/do/make_continue_pareto.h new file mode 100644 index 00000000..d5b4400d --- /dev/null +++ b/eo/src/do/make_continue_pareto.h @@ -0,0 +1,108 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// make_continue_pareto.h +// (c) Maarten Keijzer, Marc Schoenauer and GeNeura Team, 2000 +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + Marc.Schoenauer@inria.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef _make_continue_pareto_h +#define _make_continue_pareto_h + +/* +Contains the templatized version of parser-based choice of stopping criterion +for Pareto optimization (e.g. no "... without improvement" criterion +It can then be instantiated, and compiled on its own for a given EOType +(see e.g. in dir ga, ga.cpp) +*/ + +// Continuators - all include eoContinue.h +#include +#include +#include +#include +#ifndef _MSC_VER +#include // CtrlC handling (using 2 global variables!) +#endif + + // also need the parser and param includes +#include +#include + + +/////////////////// helper function //////////////// +template +eoCombinedContinue * make_combinedContinue(eoCombinedContinue *_combined, eoContinue *_cont) +{ + if (_combined) // already exists + _combined->add(*_cont); + else + _combined = new eoCombinedContinue(*_cont); + return _combined; +} + +///////////// The make_continue function +template +eoContinue & do_make_continue_pareto(eoParser& _parser, eoState& _state, eoEvalFuncCounter & _eval) +{ + //////////// Stopping criterion /////////////////// + // the combined continue - to be filled + eoCombinedContinue *continuator = NULL; + + // for each possible criterion, check if wanted, otherwise do nothing + + // First the eoGenContinue - need a default value so you can run blind + // but we also need to be able to avoid it <--> 0 + eoValueParam& maxGenParam = _parser.createParam(unsigned(100), "maxGen", "Maximum number of generations () = none)",'G',"Stopping criterion"); + + if (maxGenParam.value()) // positive: -> define and store + { + eoGenContinue *genCont = new eoGenContinue(maxGenParam.value()); + _state.storeFunctor(genCont); + // and "add" to combined + continuator = make_combinedContinue(continuator, genCont); + } + +#ifndef _MSC_VER + // the CtrlC interception (Linux only I'm afraid) + eoCtrlCContinue *ctrlCCont; + eoValueParam& ctrlCParam = _parser.createParam(true, "CtrlC", "Terminate current generation upon Ctrl C",'C', "Stopping criterion"); + if (_parser.isItThere(ctrlCParam)) + { + ctrlCCont = new eoCtrlCContinue; + // store + _state.storeFunctor(ctrlCCont); + // add to combinedContinue + continuator = make_combinedContinue(continuator, ctrlCCont); + } +#endif + + // now check that there is at least one! + if (!continuator) + throw runtime_error("You MUST provide a stopping criterion"); + // OK, it's there: store in the eoState + _state.storeFunctor(continuator); + + // and return + return *continuator; +} + +#endif