diff --git a/eo/src/utils/compatibility.h b/eo/src/utils/compatibility.h new file mode 100644 index 00000000..75479c14 --- /dev/null +++ b/eo/src/utils/compatibility.h @@ -0,0 +1,71 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + compatibility.h + File to store some compiler specific stuff in. Currently handles, or + least tries to handle the min() max() problems when using MSVC + + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +#ifndef COMPAT_H +#define COMPAT_H + +#include +#include + +#ifdef _MSC_VER +/* +Maarten: added this code here because Mirkosoft has the +nasty habit of #define min and max in stdlib.h (and windows.h) +I'm trying to undo this horrible macro magic (microsoft yet macrohard) +here. Sure hope it works +*/ + +#include + +#ifdef min +#undef min +#undef max // as they come in pairs +#endif + +// add min and max to std... +namespace std +{ + template const T& min(const T& a, const T& b) + { + if(a < b) + return a; + // else + return b; + } + + template const T& max(const T& a, const T& b) + { + if(a > b) + return a; + // else + return b; + } +} + +#endif // _MSC_VER + +#endif diff --git a/eo/src/utils/eoData.h b/eo/src/utils/eoData.h new file mode 100644 index 00000000..1ba35860 --- /dev/null +++ b/eo/src/utils/eoData.h @@ -0,0 +1,64 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +----------------------------------------------------------------------------- + eoData.h + Some numeric limits and types and things like that; with #ifdefs to keep + compatibility + (c) GeNeura Team & Maarten Keijzer, 1998, 1999, 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 + */ + +#ifndef EODATA_H +#define EODATA_H + +//----------------------------------------------------------------------------- + +#include // vector +#include // set +#include // string + +using namespace std; + + +#ifdef _MSC_VER + #include // MAXDOUBLE + #define MAXFLOAT numeric_limits::max() + #define MINFLOAT numeric_limits::min() + #define MAXDOUBLE numeric_limits::max() + #define MAXINT numeric_limits::max() +#else + #include + #include +#ifndef _WIN32 // should be the define for UN*X flavours: _POSIX?? + #include +#endif + #ifndef MAXFLOAT + #define MAXFLOAT (float)1e127 + #define MAXDOUBLE (double)1.79769313486231570e+308 + #define MAXINT 2147483647 + #endif +#endif + +#ifndef _MSC_VER +#include +#define _isnan isnan +#endif + +//----------------------------------------------------------------------------- + +#endif EODATA_H + diff --git a/eo/src/utils/eoParam.h b/eo/src/utils/eoParam.h new file mode 100644 index 00000000..1fe4dd27 --- /dev/null +++ b/eo/src/utils/eoParam.h @@ -0,0 +1,192 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// eoParam.h +// (c) Marc Schoenauer, Maarten Keijzer 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@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef eoParam_h +#define eoParam_h + +//----------------------------------------------------------------------------- +#include +#include + +/** + eoParam: Base class for monitoring and parsing parameters +*/ +class eoParam +{ +public: + + /** Empty constructor - called from outside any parser + */ + eoParam () + : repLongName(""), repDescription(""), repDefault(""), + repShortHand(0), repRequired(false){} + + /** + * Construct a Param. + * @param _longName Long name of the argument + * @param _default The default value + * @param _description Description of the parameter. What is useful for. + * @param _shortName Short name of the argument (Optional) + * @param _required If it is a necessary parameter or not + */ + eoParam (std::string _longName, std::string _default, + std::string _description, char _shortName = 0, bool _required = false) + : repShortHand(_shortName), repLongName(_longName), + repDescription(_description ), repDefault(_default), + repRequired( _required) {} + + /** + * Virtual destructor is needed. + */ + virtual ~eoParam () {}; + + /** + * Pure virtual function to get the value out. + */ + virtual std::string getValue ( void ) const = 0; + + /** + * Pure virtual function to set the value + */ + virtual void setValue(std::string _value) = 0 ; + + /** + * Returns the short name. + */ + char shortName ( void ) const { return repShortHand; }; + + /** + * Returns the long name. + */ + const std::string& longName ( void ) const { return repLongName; }; + + /** + * Returns the description of the argument + */ + const std::string& description ( void ) const { return repDescription; }; + + /** + * Returns the default value of the argument + */ + const std::string& defValue ( void ) const { return repDefault; }; + + /** + * Sets the default value of the argument, + */ + void defValue ( std::string str ) { repDefault = str; }; + + /** + * Returns the value of the param as a string + */ + /** + * Returns if required or not. + */ + bool required ( void ) const { return repRequired; }; + +private: + std::string repLongName; + std::string repDefault; + std::string repDescription; + char repShortHand; + bool repRequired; +}; + +/** + eoValueParam: templatized derivation of eoParam. Can be used to contain + any scalar value type. It makes use of std::strstream to get and set values. This + should be changed to std::stringstream when that class is available in g++. +*/ + +template +class eoValueParam : public eoParam +{ +public : + eoValueParam(void) : eoParam() {} + + /** + * Construct a Param. + * @param _defaultValue The default value + * @param _longName Long name of the argument + * @param _description Description of the parameter. What is useful for. + * @param _shortName Short name of the argument (Optional) + * @param _required If it is a necessary parameter or not + */ + eoValueParam (ValueType _defaultValue, + std::string _longName, + std::string _description, + char _shortHand = 0, + bool _required = false) + : repValue(_defaultValue), eoParam(_longName, "", _description, _shortHand, _required) + { + eoParam::defValue(getValue()); + } + + ValueType& value() { return repValue; } + ValueType value() const { return repValue; } + + std::string getValue(void) const + { + std::ostrstream os; + os << repValue; + os << std::ends; + return os.str(); + } + + void setValue(std::string _value) + { + std::istrstream is(_value.c_str()); + is >> repValue; + } + +private : + ValueType repValue; +}; + +/*template +class eoContainerParam : public eoParam +{ +public : + eoContainerParam (ContainerType& value, string _shortName, string _longName, + string _default, + string _description, + bool _required, + bool _change ) + : value(_value), eoParam(_shortName, _longName, _description, _default, _required, _change) + {} + + + // void setValue(const string & _value) + // { + // std::istringstream is(_value); + // copy(istream_iterator(is), istream_iterator(), back_inserter(value)); + // } + +private : + ContainerType& value; +};*/ + + +#endif diff --git a/eo/src/utils/eoParser.cpp b/eo/src/utils/eoParser.cpp new file mode 100644 index 00000000..b6402de8 --- /dev/null +++ b/eo/src/utils/eoParser.cpp @@ -0,0 +1,232 @@ +#include +#include +#include + +#include "eoParser.h" + +using namespace std; + +std::ostream& printSectionHeader(std::ostream& os, std::string section) +{ + os << '\n' << setw(10) << "###### " << setw(20) << section << setw(10) << " ######\n"; + return os; +} + +eoParser::eoParser ( int _argc, char **_argv , string _programDescription, string _lFileParamName, char _shortHand) : + programName( _argv[0]), + programDescription( _programDescription), + parameterFile("", _lFileParamName, "Load using a configuration file", _shortHand), + needHelp(false, "help", "Prints this message", 'h') +{ + strstream stream; + + for (int i = 1; i < _argc; ++i) + { + stream << _argv[i] << '\n'; + } + + readFrom(stream); + + processParam(parameterFile); + processParam(needHelp); + + if (parameterFile.getValue() != parameterFile.defValue()) + { + ifstream is (parameterFile.getValue().c_str()); + + readFrom(is); + } +} + +void eoParser::processParam(eoParam& param, std::string section) +{ + doRegisterParam(param); // plainly register it + params.insert(make_pair(section, ¶m)); +} + +void eoParser::doRegisterParam(eoParam& param) const +{ + if (param.required() && !isItThere(param)) + { + throw runtime_error("required parameter missing"); + } + + pair value = getValue(param); + + if (value.first) + { + if (value.second == "") // it is there, but no value is given, default to "1" + value.second = "1"; // for bool + + param.setValue(value.second); + } +} + +pair eoParser::getValue(eoParam& _param) const +{ + pair result(false, ""); + + if (_param.shortName() != 0) + { + map::const_iterator it = shortNameMap.find(_param.shortName()); + if (it != shortNameMap.end()) + { + result.second = it->second; + result.first = true; + return result; + } + } + + map::const_iterator it = longNameMap.find(_param.longName()); + + if (it != longNameMap.end()) + { + result.second = it->second; + result.first = true; + return result; + } + // else (TODO: check environment, just long names) + + return result; +} + +void eoParser::updateParameters() const +{ + typedef MultiMapType::const_iterator It; + + for (It p = params.begin(); p != params.end(); ++p) + { + doRegisterParam(*p->second); + } +} + +void eoParser::readFrom(istream& is) +{ + string str; + + while (is >> str) + { + if (str[0] == '#') + { // skip the rest of the line + string tempStr; + getline(is, tempStr); + } + if (str[0] == '-') + { + if (str.size() < 2) + { + eoWarning("Missing parameter"); + needHelp.value() = true; + return; + } + + if (str[1] == '-') // two consecutive dashes + { + string::iterator equalLocation = find(str.begin() + 2, str.end(), '='); + string value; + + if (equalLocation == str.end()) + { // TODO: it should be the next string + value = ""; + } + else + { + value = string(equalLocation + 1, str.end()); + } + + string name(str.begin() + 2, equalLocation); + longNameMap[name] = value; + + } + else // it should be a char + { + string value(str.begin() + 2, str.end()); + shortNameMap[str[1]] = value; + } + } + } + + updateParameters(); +} + +void eoParser::printOn(ostream& os) const +{ + typedef MultiMapType::const_iterator It; + + It p = params.begin(); + + std::string section = p->first; + + printSectionHeader(os, section); + + //print every param with its value + for (; p != params.end(); ++p) + { + std::string newSection = p->first; + + if (newSection != section) + { + section = newSection; + printSectionHeader(os, section); + } + + eoParam* param = p->second; + + string str = "--" + param->longName() + "=" + param->getValue(); + + os << left << setw(40) << str; + os << " # " << '-' << param->shortName() << " : " << param->description(); + + if (param->required()) + { + os << " REQUIRED "; + } + + os << '\n'; + } +} + +void eoParser::printHelp(ostream& os) +{ + // print program name and description + os << this->programName <<": "<< programDescription << "\n\n"; + + // print the usage when calling the program from the command line + os << "Usage: "<< programName<<" [Options]\n"; + // only short usage! + os << "Options of the form \"-ShortName value\" or \"--LongName value\"" << endl; + + os << "Where:"<first; + + printSectionHeader(os, section); + + //print every param with its value + for (; p != params.end(); ++p) + { + std::string newSection = p->first; + + if (newSection != section) + { + section = newSection; + printSectionHeader(os, section); + } + + if (p->second->shortName()) + os << "-" << p->second->shortName() << ", "; + + os << "--" <second->longName() <<":\t" + << p->second->description() ; + + os << "\n" << setw(20) << ( (p->second->required())?"Required":"Optional" ); + os <<". By default: "<second->defValue() << '\n'; + } // for p + + os << '\n'; + +} diff --git a/eo/src/utils/eoParser.h b/eo/src/utils/eoParser.h new file mode 100644 index 00000000..17dddcae --- /dev/null +++ b/eo/src/utils/eoParser.h @@ -0,0 +1,136 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// eoParser.h +// (c) Marc Schoenauer, Maarten Keijzer 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@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef eoParser_h +#define eoParser_h + +#include +#include +#include + +#include "eoParam.h" +#include "eoObject.h" +#include "eoPersistent.h" + +/** + eoParameterLoader is an abstract class that can be used as a base for your own + parameter loading and saving. The command line parser eoParser is derived from + this class. +*/ +class eoParameterLoader +{ +public : + + /** Need a virtual destructor */ + virtual ~eoParameterLoader() {} + + /** + * processParam is used to register a parameter and set its value if it is known + * + * @param param the parameter to process + * @param section the section where this parameter belongs + */ + virtual void processParam(eoParam& param, std::string section = "") = 0; +}; + +void eoWarning(std::string str) +{ + cout << str << '\n'; +} + +/** + eoParser: command line parser and configuration file reader + This class is persistent, so it can be stored and reloaded to restore + parameter settings. +*/ +class eoParser : public eoParameterLoader, public eoObject, public eoPersistent +{ + +public: + + /** + * Constructor + * a complete constructor that reads the command line an optionally reads + * a configuration file. + * + * myEo --param-file=param.rc will then load using the parameter file param.rc + * + * @param _argc, _ argv command line arguments + * @param _programDescription Description of the work the program does + * @param _lFileParamName Name of the parameter specifying the configuration file (--param-file) + * @param _shortHand Single charachter shorthand for specifying the configuration file + */ + eoParser ( int _argc, char **_argv , string _programDescription = "", + string _lFileParamName = "param-file", char _shortHand = 'p'); + + /** + Processes the parameter and puts it in the appropriate section for readability + */ + void processParam(eoParam& param, std::string section = ""); + + void readFrom(istream& is); + + void printOn(ostream& os) const; + + /// className for readibility + std::string className(void) const { return "Parser"; } + + /// true if the user made an error or asked for help + bool userNeedsHelp(void) const { return needHelp.value(); } + + /** + * Prints an automatic help in the specified output using the information + * provided by parameters + */ + void printHelp(ostream& os); + + string ProgramName() { return programName; } + +private: + + void doRegisterParam(eoParam& param) const; + + bool isItThere(eoParam& _param) const { return getValue(_param).first; } + + std::pair getValue(eoParam& _param) const; + + void updateParameters() const; + + typedef std::multimap MultiMapType; + + MultiMapType params; + + string programName; + string programDescription; + + map shortNameMap; + map longNameMap; + + eoValueParam parameterFile; + eoValueParam needHelp; +}; + +#endif \ No newline at end of file diff --git a/eo/src/utils/eoRNG.cpp b/eo/src/utils/eoRNG.cpp new file mode 100644 index 00000000..a3950638 --- /dev/null +++ b/eo/src/utils/eoRNG.cpp @@ -0,0 +1,5 @@ +#include +#include "eoRNG.h" + +eoRng rng((uint32) time(0)); + diff --git a/eo/src/utils/eoRNG.h b/eo/src/utils/eoRNG.h new file mode 100644 index 00000000..76f63166 --- /dev/null +++ b/eo/src/utils/eoRNG.h @@ -0,0 +1,452 @@ +/* +* Random number generator adapted from (see comments below) +* +* The random number generator is modified into a class +* by Maarten Keijzer (mak@dhi.dk). Also added the Box-Muller +* transformation to generate normal deviates. +* + 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 +*/ + +/* ************ DOCUMENTATION IN ORIGINAL FILE *********************/ + +// This is the ``Mersenne Twister'' random number generator MT19937, which +// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) +// starting from any odd seed in 0..(2^32 - 1). This version is a recode +// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by +// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in +// July-August 1997). +// +// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha +// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to +// generate 300 million random numbers; after recoding: 24.0 sec. for the same +// (i.e., 46.5% of original time), so speed is now about 12.5 million random +// number generations per second on this machine. +// +// According to the URL +// (and paraphrasing a bit in places), the Mersenne Twister is ``designed +// with consideration of the flaws of various existing generators,'' has +// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally +// equidistributed, and ``has passed many stringent tests, including the +// die-hard test of G. Marsaglia and the load test of P. Hellekalek and +// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 +// to 5012 bytes of static data, depending on data type sizes, and the code +// is quite short as well). It generates random numbers in batches of 624 +// at a time, so the caching and pipelining of modern systems is exploited. +// It is also divide- and mod-free. +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library 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 Library General Public License for more details. You should have +// received a copy of the GNU Library 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. +// +// The code as Shawn received it included the following notice: +// +// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When +// you use this, send an e-mail to with +// an appropriate reference to your work. +// +// It would be nice to CC: when you write. +// + +// +// uint32 must be an unsigned integer type capable of holding at least 32 +// bits; exactly 32 should be fastest, but 64 is better on an Alpha with +// GCC at -O3 optimization so try your options and see what's best for you +// + +/* ************ END DOCUMENTATION IN ORIGINAL FILE *********************/ + + +#ifndef EO_RANDOM_NUMBER_GENERATOR +#define EO_RANDOM_NUMBER_GENERATOR + + +#include +#include + +// TODO: check for various compilers if this is exactly 32 bits +// Unfortunately MSVC's preprocessor does not comprehends sizeof() +// so neat preprocessing tricks will not work + +typedef unsigned long uint32; // Compiler and platform dependent! + +//----------------------------------------------------------------------------- +// eoRng +//----------------------------------------------------------------------------- +/** +eoRng is a persitent class that uses the ``Mersenne Twister'' random number generator MT19937 +for generating random numbers. The various member functions implement useful functions +for evolutionary algorithms. Included are: rand(), random(), flip() and normal(). + +Note for people porting EO to other platforms: please make sure that the typedef +uint32 in the file eoRng.h is exactly 32 bits long. It may be longer, but not +shorter. If it is longer, file compatibility between EO on different platforms +may be broken. +*/ +class eoRng : public eoObject, public eoPersistent +{ +public : + /** + ctor takes a random seed; if you want another seed, use reseed + @see reseed + */ + + eoRng(uint32 s) : state(0), next(0), left(-1), cached(false), N(624), M(397), K(0x9908B0DFU) { + state = new uint32[N+1]; + initialize(s); + } + + ~eoRng(void) + { + delete [] state; + } + + /** + Re-initializes the Random Number Generator. + */ + void reseed(uint32 s) + { + initialize(s); + } + + /** + uniform(m = 1.0) returns a random double in the range [0, m) + */ + double uniform(double m = 1.0) + { // random number between [0, m] + return m * double(rand()) / double(rand_max()); + } + + /** + random() returns a random integer in the range [0, m) + */ + uint32 random(uint32 m) + { + return uint32(uniform() * double(m)); + } + + /** + flip() tosses a biased coin such that flip(x/100.0) will + returns true x% of the time + */ + bool flip(float bias) + { + return uniform() < bias; + } + + /** + normal() zero mean gaussian deviate with standard deviation of 1 + */ + double normal(void); // gaussian mutation, stdev 1 + + /** + normal(stdev) zero mean gaussian deviate with user defined standard deviation + */ + double normal(double stdev) + { + return stdev * normal(); + } + + /** + normal(mean, stdev) user defined mean gaussian deviate with user defined standard deviation + */ + double normal(double mean, double stdev) + { + return mean + normal(stdev); + } + + /** + rand() returns a random number in the range [0, rand_max) + */ + uint32 rand(); + + /** + rand_max() the maximum returned by rand() + */ + uint32 rand_max(void) const { return (uint32) 0xffffffff; } + + /** + roulette_wheel(vec, total = 0) does a roulette wheel selection + on the input vector vec. If the total is not supplied, it is + calculated. It returns an integer denoting the selected argument. + */ + template + int roulette_wheel(const std::vector& vec, T total = 0) + { + if (total == 0) + { // count + for (unsigned i = 0; i < vec.size(); ++i) + total += vec[i]; + } + + float change = uniform() * total; + + int i = 0; + + while (change > 0) + { + change -= vec[i++]; + } + + return --i; + } + + /// + void printOn(ostream& _os) const + { + for (int i = 0; i < N; ++i) + { + _os << state[i] << ' '; + } + _os << int(next - state) << ' '; + _os << left << ' ' << cached << ' ' << cacheValue; + } + + /// + void readFrom(istream& _is) + { + for (int i = 0; i < N; ++i) + { + _is >> state[i]; + } + + int n; + _is >> n; + next = state + n; + + _is >> left; + _is >> cached; + _is >> cacheValue; + } + + +private : + uint32 restart(void); + void initialize(uint32 seed); + + uint32* state; // the array for the state + uint32* next; + int left; + + bool cached; + float cacheValue; + + const int N; + const int M; + const uint32 K; // a magic constant + + /** + Private copy ctor and assignment operator to make sure that + nobody accidentally copies the random number generator. + If you want similar RNG's, make two RNG's and initialize + them with the same seed. + */ + eoRng (const eoRng&); // no implementation + eoRng& operator=(const eoRng&); // dito +}; + +/** + The one and only global eoRng object +*/ +extern eoRng rng; + +/** + The class uniform_generator can be used in the STL generate function + to easily generate random floats and doubles between [0, _max). _max + defaults to 1.0 +*/ +template class uniform_generator +{ + public : + uniform_generator(T _max = T(1.0), eoRng& _rng = rng) : maxim(_max), uniform(_rng) {} + + virtual T operator()(void) { return (T) uniform.uniform(maxim); } + private : + T maxim; + eoRng& uniform; +}; + +/** + The class random_generator can be used in the STL generate function + to easily generate random ints between [0, _max). +*/ +template class random_generator +{ + public : + random_generator(int _max, eoRng& _rng = rng) : maxim(_max), random(_rng) {} + + virtual T operator()(void) { return (T) random.random(max); } + + private : + T maxim; + eoRng& random; +}; + +/** + The class normal_generator can be used in the STL generate function + to easily generate gaussian distributed floats and doubles. The user + can supply a standard deviation which defaults to 1. +*/ +template class normal_generator +{ + public : + normal_generator(T _stdev = T(1.0), eoRng& _rng = rng) : stdev(_stdev), normal(_rng) {} + + virtual T operator()(void) { return (T) normal.normal(stdev); } + + private : + T stdev; + eoRng& normal; +}; + +// Implementation of some eoRng members.... Don't mind the mess, it does work. + + +#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u +#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u +#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u +#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v + +inline void eoRng::initialize(uint32 seed) + { + // + // We initialize state[0..(N-1)] via the generator + // + // x_new = (69069 * x_old) mod 2^32 + // + // from Line 15 of Table 1, p. 106, Sec. 3.3.4 of Knuth's + // _The Art of Computer Programming_, Volume 2, 3rd ed. + // + // Notes (SJC): I do not know what the initial state requirements + // of the Mersenne Twister are, but it seems this seeding generator + // could be better. It achieves the maximum period for its modulus + // (2^30) iff x_initial is odd (p. 20-21, Sec. 3.2.1.2, Knuth); if + // x_initial can be even, you have sequences like 0, 0, 0, ...; + // 2^31, 2^31, 2^31, ...; 2^30, 2^30, 2^30, ...; 2^29, 2^29 + 2^31, + // 2^29, 2^29 + 2^31, ..., etc. so I force seed to be odd below. + // + // Even if x_initial is odd, if x_initial is 1 mod 4 then + // + // the lowest bit of x is always 1, + // the next-to-lowest bit of x is always 0, + // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , + // the 3rd-from-lowest bit of x 4-cycles ... 0 1 1 0 0 1 1 0 ... , + // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 0 1 1 1 1 0 ... , + // ... + // + // and if x_initial is 3 mod 4 then + // + // the lowest bit of x is always 1, + // the next-to-lowest bit of x is always 1, + // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , + // the 3rd-from-lowest bit of x 4-cycles ... 0 0 1 1 0 0 1 1 ... , + // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 1 1 1 1 0 0 ... , + // ... + // + // The generator's potency (min. s>=0 with (69069-1)^s = 0 mod 2^32) is + // 16, which seems to be alright by p. 25, Sec. 3.2.1.3 of Knuth. It + // also does well in the dimension 2..5 spectral tests, but it could be + // better in dimension 6 (Line 15, Table 1, p. 106, Sec. 3.3.4, Knuth). + // + // Note that the random number user does not see the values generated + // here directly since restart() will always munge them first, so maybe + // none of all of this matters. In fact, the seed values made here could + // even be extra-special desirable if the Mersenne Twister theory says + // so-- that's why the only change I made is to restrict to odd seeds. + // + + left = -1; + + register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state; + register int j; + + for(left=0, *s++=x, j=N; --j; + *s++ = (x*=69069U) & 0xFFFFFFFFU); + } + + +inline uint32 eoRng::restart(void) +{ + register uint32 *p0=state, *p2=state+2, *pM=state+M, s0, s1; + register int j; + + left=N-1, next=state+1; + + for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + for(pM=state, j=M; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9D2C5680U; + s1 ^= (s1 << 15) & 0xEFC60000U; + return(s1 ^ (s1 >> 18)); +} + + +inline uint32 eoRng::rand(void) + { + uint32 y; + + if(--left < 0) + return(restart()); + + y = *next++; + y ^= (y >> 11); + y ^= (y << 7) & 0x9D2C5680U; + y ^= (y << 15) & 0xEFC60000U; + return(y ^ (y >> 18)); + } + +inline double eoRng::normal(void) +{ + if (cached) + { + cached = false; + return cacheValue; + } + + float rSquare, factor, var1, var2; + + do + { + var1 = 2.0 * uniform() - 1.0; + var2 = 2.0 * uniform() - 1.0; + + rSquare = var1 * var1 + var2 * var2; + } + while (rSquare >= 1.0 || rSquare == 0.0); + + factor = sqrt(-2.0 * log(rSquare) / rSquare); + + cacheValue = var1 * factor; + cached = true; + + return (var2 * factor); +} + +#endif + diff --git a/eo/src/utils/eoState.cpp b/eo/src/utils/eoState.cpp new file mode 100644 index 00000000..edd4d9ca --- /dev/null +++ b/eo/src/utils/eoState.cpp @@ -0,0 +1,147 @@ + +#ifdef _MSC_VER +#pragma warning(disable:4786) +#endif + +#include +#include +#include + +#include "eoState.h" +#include "eoObject.h" +#include "eoPersistent.h" + +using namespace std; + +void removeComment(string& str, string comment) +{ + string::size_type pos = str.find(comment); + + if (pos != string::npos) + { + str.erase(pos, str.size()); + } +} + +bool is_section(const string& str, string& name) +{ + string::size_type pos = str.find("\\section{"); + + if (pos == string::npos) + return false; + //else + + string::size_type end = str.find("}"); + + if (end == string::npos) + return false; + // else + + name = str.substr(pos + 9, end-9); + + return true; +} + +void eoState::registerObject(eoPersistent& registrant) +{ + string name = createObjectName(dynamic_cast(®istrant)); + + objectMap[name] = ®istrant; +} + +void eoState::load(const string& _filename) +{ + ifstream is (_filename.c_str()); + + if (is.fail()) + { + string str = "Could not open file " + _filename; + throw runtime_error(str); + } + + string str; + string name; + + getline(is, str); + + while(is) + { // parse section header + if (is_section(str, name)) + { + string fullString; + ObjectMap::iterator it = objectMap.find(name); + + if (it == objectMap.end()) + { // ignore + while (getline(is, str)) + { + if (is_section(str, name)) + break; + } + } + else + { + + eoPersistent* object = it->second; + + // now we have the object, get lines, remove comments etc. + + string fullstring; + + while (getline(is, str)) + { + if (is_section(str, name)) + break; + + removeComment(str, getCommentString()); + fullstring += str + "\n"; + } + + istrstream the_stream(fullstring.c_str(), fullstring.size()); + + object->readFrom(the_stream); + } + } + } + +} + +void eoState::save(const string& filename) +{ + ofstream os(filename.c_str()); + + for (ObjectMap::iterator it = objectMap.begin(); it != objectMap.end(); ++it) + { + os << "\\section{" << it->first << "}\n"; + it->second->printOn(os); + os << '\n'; + } +} + +string eoState::createObjectName(eoObject* obj) +{ + if (obj == 0) + { + ostrstream os; + os << objectMap.size(); + return os.str(); + } + // else + + string name = obj->className(); + ObjectMap::const_iterator it = objectMap.find(name); + + unsigned count = 1; + while (it != objectMap.end()) + { + ostrstream os; + os << obj->className().c_str() << count++ << ends; + + name = os.str(); + + it = objectMap.find(name); + } + + return name; +} + diff --git a/eo/src/utils/eoState.h b/eo/src/utils/eoState.h new file mode 100644 index 00000000..9f656a6c --- /dev/null +++ b/eo/src/utils/eoState.h @@ -0,0 +1,84 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// eoState.h +// (c) Marc Schoenauer, Maarten Keijzer 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@polytechnique.fr + mkeijzer@dhi.dk + */ +//----------------------------------------------------------------------------- + +#ifndef eoState_h +#define eoState_h + +#include +#include +#include + +class eoObject; +class eoPersistent; + +/** +* eoState can be used to register derivants of eoPersistent. It will +* then in turn implement the persistence framework through members load +* and save, that will call readFrom and printOn for the registrated objects. +*/ +class eoState +{ +public : + + /** + * Object registration function, note that it does not take ownership! + */ + void registerObject(eoPersistent& registrant); + + /** + * Loading error thrown when nothing seems to work. + */ + struct loading_error : public std::runtime_error + { + loading_error(std::string huh = "Error while loading") : std::runtime_error(huh) {} + }; + + std::string getCommentString(void) const { return "#"; } + + /** + * Reads the file specified + * + * @param _filename the name of the file to load from + */ + void load(const std::string& _filename); + + /** + * Saves the state in file specified + * + * @param _filename the name of the file to save into + */ + void save(const std::string& _filename); + +private : + std::string createObjectName(eoObject* obj); + + // first is Persistent, second is the raw data associated with it. + typedef std::map ObjectMap; + + ObjectMap objectMap; +}; + +#endif //eoState_h