diff --git a/doc/reference/python/random/random.py b/doc/reference/python/random/random.py index 7e76182e..40a0c690 100644 --- a/doc/reference/python/random/random.py +++ b/doc/reference/python/random/random.py @@ -1,7 +1,7 @@ -from pytriqs.random import * +from pytriqs.random_generator import * from pytriqs.plot.mpl_interface import * r = RandomGenerator("lagged_fibonacci607", 237489) l = [] -for i in range(10000): l += [r.rand(),] -plt.hist(l, 30, normed=True); +for i in range(10000): l += [r(),] +plt.hist(l, 30, normed=True) diff --git a/doc/reference/python/random/random.rst b/doc/reference/python/random/random.rst index c4139f03..0bb303c0 100644 --- a/doc/reference/python/random/random.rst +++ b/doc/reference/python/random/random.rst @@ -1,33 +1,34 @@ .. index:: Random number generator -.. module:: pytriqs.random +.. module:: pytriqs.random_generator .. _random_generator: Random generator class ====================== -TRIQS has a simple random number generator class called ``RandomGenerator``. It is based on boost -just like the C++ random generator provided by TRIQS. +TRIQS exposes to python the random number generators used in C++, +in the module ``RandomGenerator``. +The generators are the boost random generators. Usage ----- -The generator is constructed from a name and a seed:: +The generator is constructed from a name (the name of the boost generator) and a seed:: - from pytriqs.random import * + from pytriqs.random_generator import * r = RandomGenerator("mt19937", 237849) -A list of possible random generator names is obtained with:: +A list of available random generators is obtained with:: - print available_generator_names() + print random_generator_names_list() -Then you can either generate float number on the interval :math:`[0,1[` using -the ``rand()`` method or integer numbers in the inverval :math:`[0,N-1]` using -``int_rand(N)``:: +Then you can either generate float number on the interval :math:`[0,1[` +simply by calling the generator, or integer numbers in the inverval :math:`[0,N-1]` by calling +it with `N` :: - print r.rand() - print r.int_rand(10) + print r() + print r(10) Example ------- @@ -42,7 +43,7 @@ Here's a simple example showing how to use the generator. Complete reference ------------------ -.. autoclass:: pytriqs.random.RandomGenerator +.. autoclass:: pytriqs.random_generator.RandomGenerator :members: -.. autofunction:: pytriqs.random.available_generator_names +.. autofunction:: pytriqs.random_generator.random_generator_names_list diff --git a/pytriqs/random/__init__.py b/pytriqs/random/__init__.py deleted file mode 100644 index ce5e631f..00000000 --- a/pytriqs/random/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ - -from random_generator import RandomGenerator, available_generator_names - -__all__ = ['RandomGenerator','available_generator_names'] - diff --git a/pytriqs/random/random_generator.pyx b/pytriqs/random/random_generator.pyx deleted file mode 100644 index 7d0b7878..00000000 --- a/pytriqs/random/random_generator.pyx +++ /dev/null @@ -1,49 +0,0 @@ -from dcomplex cimport * -from libcpp.string cimport string - -# The c++ random generator class -# We wrap two members only -cdef extern from "triqs/mc_tools/random_generator.hpp": - - cdef cppclass random_generator "triqs::mc_tools::random_generator": - - random_generator(string, long) except + - double operator() () except + - int operator() (int) except + - -# This is the wrapping of the static member random_generator_names -# It is a bit of a hack but there is no notion of ststic members in cython -cdef extern from "triqs/mc_tools/random_generator.hpp" namespace "triqs::mc_tools::random_generator": - - string random_generator_names(string) except + - - -# The python RandomGenerator class -cdef class RandomGenerator: - - cdef random_generator * _c - - def __init__(self, name, seed): - """This is a random number generator class based on boost. - - :param name: (string) Name of the random number generator - :param seed: (int) Random number seed - """ - self._c = new random_generator(name, seed) - - def __dealloc__(self): - del self._c - - def rand(self): - """Generate a float random number in [0,1[""" - return self._c[0]() - - def int_rand(self, N): - """Generate an integer random number in [0,N-1]""" - return self._c[0](N) - -# The list of generator names accessed through the static member -def available_generator_names(): - """Get a list of available random generator names""" - return random_generator_names(",").split(',') - diff --git a/pytriqs/random/CMakeLists.txt b/pytriqs/random_generator/CMakeLists.txt similarity index 53% rename from pytriqs/random/CMakeLists.txt rename to pytriqs/random_generator/CMakeLists.txt index 35ac5dc2..ba2ae123 100644 --- a/pytriqs/random/CMakeLists.txt +++ b/pytriqs/random_generator/CMakeLists.txt @@ -2,7 +2,8 @@ SET(PYTHON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ) -install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST}/random) +install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST}/random_generator) + +# Build C extension module +triqs_python_extension(random_generator random_generator) -# the c++ code -cython_module(random random_generator random) diff --git a/pytriqs/random_generator/__init__.py b/pytriqs/random_generator/__init__.py new file mode 100644 index 00000000..4a1b3405 --- /dev/null +++ b/pytriqs/random_generator/__init__.py @@ -0,0 +1,5 @@ + +from random_generator import RandomGenerator, random_generator_names_list + +__all__ = ['RandomGenerator','random_generator_names_list'] + diff --git a/pytriqs/random_generator/random_generator_desc.py b/pytriqs/random_generator/random_generator_desc.py new file mode 100644 index 00000000..5e894928 --- /dev/null +++ b/pytriqs/random_generator/random_generator_desc.py @@ -0,0 +1,46 @@ +from wrap_generator import * + +module = module_(full_name = "pytriqs.random_generator", doc = "") +module.add_include("") +module.add_using("namespace triqs::mc_tools") +# Not needed. Reorganize the hpp wrapper tool +module.add_include("") +module.add_include("") + +# --------- RandomGenerator ---------------------------------- + +r = class_(py_type = "RandomGenerator", + c_type = "random_generator", + c_type_absolute = "triqs::mc_tools::random_generator", + ) + +r.add_constructor(signature = "(std::string name, int seed)", + doc = + """ + This is a random number generator class based on boost. + + name Name of the random number generator + seed Random number seed + """) + +r.add_call(signature = "int(int N)", doc = """Generate an integer random number in [0,N-1]""") +r.add_call(signature = "double()", doc = """Generate a float random number in [0,1[""") + +module.add_class(r) + +# --------- Module functions ---------------------------------- + +module.add_function(name = "random_generator_names_list", + signature = "std::vector()", + doc = """Get a list of available random generator names""" + ) + +######################## +## Code generation +######################## + +if __name__ == '__main__' : + module.generate_code(mako_template = sys.argv[1], wrap_file = sys.argv[2]) + module.generate_py_converter_header(mako_template = sys.argv[3], wrap_file = sys.argv[4]) + + diff --git a/test/triqs/utility/buffered_function.cpp b/test/triqs/utility/buffered_function.cpp new file mode 100644 index 00000000..953c14e9 --- /dev/null +++ b/test/triqs/utility/buffered_function.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + * + * TRIQS: a Toolbox for Research in Interacting Quantum Systems + * + * Copyright (C) 2014 by O. Parcollet + * + * TRIQS is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * TRIQS 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * TRIQS. If not, see . + * + ******************************************************************************/ +#include +#include + +int main(int argc, char **argv) { + + // a function that generates all the square .... + int x = 0; + auto f = [x]() mutable { return x * (x++); }; + + // C++14 : init-capture + // auto f = [x=0]() mutable { return x*(x++);}; + + auto gen = triqs::utility::buffered_function(f, 5); + + for (int u = 0; u < 22; ++u) + if (gen() != u * u) throw "Error"; +} diff --git a/triqs/mc_tools/generator.hpp b/triqs/mc_tools/generator.hpp deleted file mode 100644 index 6e29c38d..00000000 --- a/triqs/mc_tools/generator.hpp +++ /dev/null @@ -1,96 +0,0 @@ -// (C) Copyright 2008-10 Lukas Gamper -// Brigitte Surer -// Bela Bauer -// -// downgraded by O. Parcollet for compilation with icc11 & boost 1.45 -// -// Use, modification, and distribution are subject to the Boost Software -// License, Version 1.0. (See at .) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost{ - template class generator { - public: - static std::size_t const buffer_size = 1000; - template generator(Generator const & gen, std::size_t size = buffer_size) - : - buf(make_shared(gen, size)) - , cur(buf->cur) - , end(buf->end()) - {} - inline R const operator()() { - if (cur == end) - buf->fill(); - return *cur++; - } - inline R const preview() { - if (cur == end) - buf->fill(); - return *cur; - } - - generator(generator const & rhs) - : - buf(new buffer (*rhs.buf)) - , cur(buf->cur) - , end(buf->end()) - {} - generator & operator=(generator rhs) { - swap(*this, rhs); - return *this; - } - private: - class buffer: public std::vector { - public: - friend class generator; - template buffer(Generator const & gen, std::size_t size) - : std::vector(size) - , engine(make_shared(gen)) - , cur(this->end()) - , fill_helper(lambda::bind(std::generate, lambda::_1, lambda::_2, ref(*reinterpret_cast(engine.get())))) - , clone(lambda::bind(buffer::template type_keeper, lambda::_1, lambda::_2)) - {} - template buffer(reference_wrapper gen, std::size_t size) - : std::vector(size) - , cur(this->end()) - , fill_helper(lambda::bind(std::generate, lambda::_1, lambda::_2, gen)) - {} - buffer(buffer const & rhs) - : std::vector(rhs) - , cur(this->begin() + (rhs.cur - rhs.begin())) - , fill_helper(rhs.fill_helper) - , clone(rhs.clone) - { - if (rhs.engine) - clone(*this, rhs); - } - inline void fill() { - fill_helper(this->begin(), this->end()); - cur = this->begin(); - } - private: - template static void type_keeper(buffer & lhs, buffer const & rhs) { - lhs.engine = make_shared(*reinterpret_cast(rhs.engine.get())); - lhs.fill_helper = lambda::bind(std::generate, lambda::_1, lambda::_2, ref(*reinterpret_cast(lhs.engine.get()))); - } - shared_ptr engine; - typename std::vector::const_iterator cur; - function::iterator, typename std::vector::iterator)> fill_helper; - function clone; - }; - - shared_ptr buf; - typename buffer::const_iterator & cur; - typename buffer::const_iterator end; - }; -} diff --git a/triqs/mc_tools/random_generator.cpp b/triqs/mc_tools/random_generator.cpp index 214235d4..39b8cff7 100644 --- a/triqs/mc_tools/random_generator.cpp +++ b/triqs/mc_tools/random_generator.cpp @@ -1,9 +1,8 @@ - /******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * - * Copyright (C) 2011 by M. Ferrero, O. Parcollet + * Copyright (C) 2011-2014 by M. Ferrero, O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software @@ -19,7 +18,6 @@ * TRIQS. If not, see . * ******************************************************************************/ - #include "random_generator.hpp" #include "./MersenneRNG.hpp" #include @@ -32,50 +30,52 @@ #include #include #include + +// List of All available Boost random number generator +#define RNG_LIST \ + (mt19937)(mt11213b)(lagged_fibonacci607)(lagged_fibonacci1279)(lagged_fibonacci2281)(lagged_fibonacci3217)( \ + lagged_fibonacci4423)(lagged_fibonacci9689)(lagged_fibonacci19937)(lagged_fibonacci23209)(lagged_fibonacci44497)(ranlux3) + +namespace triqs { +namespace mc_tools { + + random_generator::random_generator(std::string const& RandomGeneratorName, uint32_t seed_) { + _name = RandomGeneratorName; + + if (RandomGeneratorName == "") { + gen = utility::buffered_function(mc_tools::RandomGenerators::RandMT(seed_)); + return; + } + + boost::uniform_real<> dis; + #define AS_STRING(X) AS_STRING2(X) #define AS_STRING2(X) #X -// List of All available Boost random number generator -#define RNG_LIST (mt19937)(mt11213b)\ -(lagged_fibonacci607) (lagged_fibonacci1279) (lagged_fibonacci2281) (lagged_fibonacci3217) (lagged_fibonacci4423)\ -(lagged_fibonacci9689) (lagged_fibonacci19937) (lagged_fibonacci23209) (lagged_fibonacci44497) (ranlux3) +// now boost random number generators +#define DRNG(r, data, XX) \ + if (RandomGeneratorName == AS_STRING(XX)) { \ + gen = utility::buffered_function(boost::variate_generator>(boost::XX(seed_), dis)); \ + return; \ + } + BOOST_PP_SEQ_FOR_EACH(DRNG, ~, RNG_LIST) -namespace triqs { - namespace mc_tools { - - typedef boost::generator gen_type; - - inline gen_type * choose_gen(std::string const & RandomGeneratorName, std::size_t seed_, boost::shared_ptr &ptr) { - - if (RandomGeneratorName=="") return new gen_type( mc_tools::RandomGenerators::RandMT (seed_)); - - // now boost random number generators -#define DRNG(r,data,XX) if (RandomGeneratorName==AS_STRING(XX)) { \ - boost::shared_ptr localptr = boost::make_shared(seed_);\ - ptr = localptr; boost::uniform_real<> dis;\ - return new gen_type( boost::variate_generator >(*localptr,dis));} - - BOOST_PP_SEQ_FOR_EACH(DRNG,~,RNG_LIST) - - TRIQS_RUNTIME_ERROR<<"The random generator "< random_generator_names_list() { + std::vector res; +#define PR2(r, sep, p, XX) res.push_back(AS_STRING(XX)); + BOOST_PP_SEQ_FOR_EACH_I(PR2, sep, RNG_LIST); + return res; } } } diff --git a/triqs/mc_tools/random_generator.hpp b/triqs/mc_tools/random_generator.hpp index f3c75557..14ce5c6a 100644 --- a/triqs/mc_tools/random_generator.hpp +++ b/triqs/mc_tools/random_generator.hpp @@ -2,7 +2,7 @@ * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * - * Copyright (C) 2011 by M. Ferrero, O. Parcollet + * Copyright (C) 2011-2014 by M. Ferrero, O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software @@ -18,62 +18,70 @@ * TRIQS. If not, see . * ******************************************************************************/ - -#ifndef POLYMORPH_RANDOM_GENERATOR_H -#define POLYMORPH_RANDOM_GENERATOR_H +#pragma once #include -#include #include "../utility/exceptions.hpp" -#include "./generator.hpp" +#include "../utility/buffered_function.hpp" #include "math.h" #include +#include +#include -namespace triqs { -namespace mc_tools { - - /** - * This is a random generator that take the name of the random generator at construct - * and serve random numbers, buffered with a version boost::generator , - * to hide the cost of dynamical polymorphism. - */ - class random_generator { - boost::shared_ptr rng_ptr; - boost::scoped_ptr< boost::generator > gen; - std::string name; - void operator = ( random_generator const & p); //forbid - std::size_t seed; - public: - - /// Takes the boost name of the generator e.g. mt19937,... - random_generator(std::string const & RandomGeneratorName, std::size_t seed_ ); - - /// - random_generator( random_generator const & p); +namespace triqs { +namespace mc_tools { /// Return a list of the names of available generators, with separator sep - static std::string random_generator_names(std::string const & sep=" "); + std::string random_generator_names(std::string const & sep=" "); + std::vector random_generator_names_list(); + + /** + * Random generator, adapting the boost random generator. + * + * The name of the generator is given at construction, and its type is erased in this class. + * For performance, the call to the generator is bufferized, with chunks of 1000 numbers. + */ + class random_generator { + utility::buffered_function gen; + std::string _name; + + public: + /** Constructor + * @param RandomGeneratorName : Name of a boost generator e.g. mt19937, or "" (another Mersenne Twister). + * @param seed : The seed of the random generator + */ + random_generator(std::string const& RandomGeneratorName, uint32_t seed_); + + random_generator() : random_generator("mt19937", 198) {} + + /// + random_generator(random_generator const& p); + + random_generator(random_generator&&) = default; + + // + random_generator & operator=(random_generator&&) = default; + + /// Name of the random generator + std::string name() const { return _name; } /// Returns a integer in [0,i-1] with flat distribution -#define INTEGER_OVERLOAD(T) T operator()(T i) { return (i==1 ? 0 : T(floor(i*((*gen)()))));} - INTEGER_OVERLOAD(int) - INTEGER_OVERLOAD(size_t) -#undef INTEGER_OVERLOAD + template typename std::enable_if::value, T>::type operator()(T i) { + return (i == 1 ? 0 : T(floor(i * (gen())))); + } /// Returns a double in [0,1[ with flat distribution - double preview() { return gen->preview();} + double preview() { return gen.preview();} - /// Returns a double in [0,1[ with flat distribution - double operator()() { return ((*gen)());} + double operator()() { return gen(); } /// Returns a double in [0,x[ with flat distribution - double operator()(double x) { return x*((*gen)());} + double operator()(double x) { return x * (gen()); } /// Returns a double in [a,b[ with flat distribution - double operator()(double a, double b) { assert (b>a); return a + (b-a)*((*gen)());} - + double operator()(double a, double b) { + assert(b > a); + return a + (b - a) * (gen()); + } }; - } } - -#endif diff --git a/triqs/utility/buffered_function.hpp b/triqs/utility/buffered_function.hpp new file mode 100644 index 00000000..8f9e4f2e --- /dev/null +++ b/triqs/utility/buffered_function.hpp @@ -0,0 +1,74 @@ +/******************************************************************************* + * + * TRIQS: a Toolbox for Research in Interacting Quantum Systems + * + * Copyright (C) 2014 by O. Parcollet + * + * TRIQS is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * TRIQS 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * TRIQS. If not, see . + * + ******************************************************************************/ +#pragma once +#include +#include + +namespace triqs { +namespace utility { + + /** + * A simple buffer for a generator. + * Given a function, it provides a buffer of this function + * Advantage : + * - do not pay the indirection cost at each call, but once every size call. + * - erase the function type + * It is a semi-regular type. + */ + template struct buffered_function { + + /// Default constructor : no function bufferized. () will throw in this state + buffered_function() = default; + + /** Constructor + * + * @tparam Function : type of the function to bufferize + * @param f : function to bufferize + * @param size : size of the buffer [optional] + */ + template buffered_function(Function f, size_t size = 1000) : buffer(size) { + refill = [f](buffered_function *bf) mutable { // without the mutable, the () of the lambda object is const, hence f + for (auto &x : bf->buffer) x = f(); + bf->index = 0; + }; + refill(this); // first filling of the buffer + } + + /// Returns the next element. Refills the buffer if necessary. + R operator()() { + if (index > buffer.size() - 1) refill(this); + return buffer[index++]; + } + + /// Returns the future next element, without increasing the index. Refills the buffer if necessary. + R preview() { + if (index > buffer.size() - 1) refill(this); + return buffer[index]; + } + + private: + size_t index; + std::vector buffer; + std::function refill; // this refills the buffer and reset index of a buffered_function. + // NB : can not capture this in refill because we want the object to be copyable and movable + }; +} +}