#include #include #include #include #include namespace py = boost::python; template struct Generator { typedef T rng_type; typedef typename T::result_type result_type; static void seed(result_type value) { get_rng().seed(value); } static PyObject* uniform_smallint(int min, int max, py::object size) { boost::uniform_smallint dist(min, max); return generate(dist, size, NPY_LONG); } static PyObject* uniform_int(int min, int max, py::object size) { boost::uniform_int dist(min, max); return generate(dist, size, NPY_LONG); } #if 0 static PyObject* uniform_01(py::object size) { boost::uniform_01 dist; return generate(dist, size, NPY_LONG); } #endif static PyObject* uniform_real(double min, double max, py::object size) { boost::uniform_real dist(min, max); return generate(dist, size, NPY_DOUBLE); } static PyObject* bernoulli(double p, py::object size) { boost::bernoulli_distribution dist(p); return generate(dist, size, NPY_DOUBLE); } static PyObject* geometric(double p, py::object size) { boost::geometric_distribution dist(p); return generate(dist, size, NPY_DOUBLE); } static PyObject* triangle(double a, double b, double c, py::object size) { boost::triangle_distribution dist(a, b, c); return generate(dist, size, NPY_DOUBLE); } static PyObject* exponential(double lambda, py::object size) { boost::exponential_distribution dist(lambda); return generate(dist, size, NPY_DOUBLE); } static PyObject* normal(double mean, double sigma, py::object size) { boost::normal_distribution dist(mean, sigma); return generate(dist, size, NPY_DOUBLE); } static PyObject* lognormal(double mean, double sigma, py::object size) { boost::lognormal_distribution dist(mean, sigma); return generate(dist, size, NPY_DOUBLE); } static PyObject* uniform_on_sphere(int dim, py::object size) { boost::uniform_on_sphere dist(dim); return generate(dist, size, NPY_DOUBLE); } template static PyObject* generate(DistType dist, py::object size, int typenum) { PyArray_Dims dims; if (!PyArray_IntpConverter(size.ptr(), &dims)) { throw py::error_already_set(); } PyObject* arr = PyArray_SimpleNew(dims.len, dims.ptr, typenum); if (!arr) { throw py::error_already_set(); } rng_type& rng = get_rng(); boost::variate_generator generator(rng, dist); double* data = (double*)PyArray_DATA(arr); std::generate(data, data + PyArray_SIZE(arr), generator); return arr; } static rng_type& get_rng() { static T rng; return rng; } }; template void wrap_generator(const char* name) { py::class_(name, py::no_init) .def("seed", &Generator::seed) .def("uniform_smallint", &Generator::uniform_smallint, (py::arg("min"), py::arg("max"), py::arg("size")=py::handle<>(Py_None))) .def("uniform_int", &Generator::uniform_int, (py::arg("min")=0, py::arg("max")=9, py::arg("size")=py::handle<>(Py_None))) #if 0 .def("uniform_01", &Generator::uniform_01, py::arg("size")=py::handle<>(Py_None)) #endif .def("uniform_real", &Generator::uniform_real, (py::arg("min")=0.0, py::arg("max")=1.0, py::arg("size")=py::handle<>(Py_None))) .def("bernoulli", &Generator::bernoulli, (py::arg("p")=0.5, py::arg("size")=py::handle<>(Py_None))) .def("geometric", &Generator::geometric, (py::arg("p")=0.5, py::arg("size")=py::handle<>(Py_None))) .def("triangle", &Generator::triangle, (py::arg("a"), py::arg("b"), py::arg("c"), py::arg("size")=py::handle<>(Py_None))) .def("exponential", &Generator::exponential, (py::arg("lambda")=1.0, py::arg("size")=py::handle<>(Py_None))) .def("normal", &Generator::normal, (py::arg("mean")=0.0, py::arg("sigma")=1.0, py::arg("size")=py::handle<>(Py_None))) .def("lognormal", &Generator::lognormal, (py::arg("mean")=1.0, py::arg("sigma")=1.0, py::arg("size")=py::handle<>(Py_None))) #if 0 .def("uniform_on_sphere", &Generator::uniform_on_sphere, (py::arg("dim")=2, py::arg("size")=py::handle<>(Py_None))) #endif .staticmethod("seed") .staticmethod("uniform_smallint") .staticmethod("uniform_int") #if 0 .staticmethod("uniform_01") #endif .staticmethod("uniform_real") .staticmethod("bernoulli") .staticmethod("geometric") .staticmethod("triangle") .staticmethod("exponential") .staticmethod("normal") .staticmethod("lognormal") #if 0 .staticmethod("uniform_on_sphere") #endif ; } BOOST_PYTHON_MODULE(_pyspkrec_random) { import_array(); wrap_generator("minstd_rand"); wrap_generator("minstd_rand0"); wrap_generator("rand48"); #if 0 wrap_generator("ecuyer1988"); #endif wrap_generator("kreutzer1986"); wrap_generator("hellekalek1995"); wrap_generator("mt11213b"); wrap_generator("mt19937"); #if 0 wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); wrap_generator(""); #endif }