Commit 57dd5a01 authored by Manuel Günther's avatar Manuel Günther
Browse files

Switched api to use boost::shared_ptr for RNG

parent 13c7c87e
......@@ -9,7 +9,7 @@
#define BOB_CORE_CONFIG_H
/* Macros that define versions and important names */
#define BOB_CORE_API_VERSION 0x0200
#define BOB_CORE_API_VERSION 0x0201
#ifdef BOB_IMPORT_VERSION
......
......@@ -38,7 +38,7 @@ typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
boost::mt19937* rng;
boost::shared_ptr<boost::mt19937> rng;
} PyBoostMt19937Object;
......
......@@ -7,31 +7,24 @@
#define BOB_CORE_RANDOM_MODULE
#include <bob.core/random_api.h>
PyDoc_STRVAR(s_mt19937_str, BOB_EXT_MODULE_PREFIX ".mt19937");
PyDoc_STRVAR(s_mt19937_doc,
"mt19937([seed]) -> new random number generator\n\
\n\
A Mersenne-Twister Random Number Generator (RNG)\n\
\n\
Constructor parameters:\n\
\n\
seed\n\
[optional] A integral value determining the initial seed\n\
\n\
A Random Number Generator (RNG) based on the work \"*Mersenne Twister:\n\
A 623-dimensionally equidistributed uniform pseudo-random number\n\
generator, Makoto Matsumoto and Takuji Nishimura, ACM Transactions\n\
on Modeling and Computer Simulation: Special Issue on Uniform Random\n\
Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30*\"\n\
\n\
Objects of this class support comparison operators such as ``==``\n\
or ``!=`` and setting the seed with the method ``seed(int)``. Two\n\
random number generators are equal if they are at the same state -\n\
i.e. they have been initialized with the same seed and have been\n\
called the same number of times for number generation.\n\
"
#include <bob.blitz/cleanup.h>
#include <bob.extension/documentation.h>
static auto mt19937_doc = bob::extension::ClassDoc(
BOB_EXT_MODULE_PREFIX ".mt19937",
"A Mersenne-Twister Random Number Generator (RNG)",
"A Random Number Generator (RNG) based on the work "
"*Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator, Makoto Matsumoto and Takuji Nishimura, ACM Transactions on Modeling and Computer Simulation: Special Issue on Uniform Random Number Generation, Vol. 8, No. 1, January 1998, pp. 3-30*\n\n"
"Objects of this class support comparison operators such as ``==`` or ``!=`` and setting the seed with the method :py:meth:`seed`. "
"Two random number generators are equal if they are at the same state -- i.e. they have been initialized with the same seed and have been called the same number of times for number generation."
)
.add_constructor(bob::extension::FunctionDoc(
"mt19937",
"Constructs and initializes a random number generator",
"If no ``seed`` is specified, the default seed (http://www.boost.org/doc/libs/1_59_0/doc/html/boost/random/mersenne_twister_engine.html) is used."
)
.add_prototype("[seed]", "")
.add_parameter("seed", "int", "[optional] An integral value determining the initial seed")
);
/* How to create a new PyBoostMt19937Object */
......@@ -40,32 +33,33 @@ static PyObject* PyBoostMt19937_New(PyTypeObject* type, PyObject*, PyObject*) {
/* Allocates the python object itself */
PyBoostMt19937Object* self = (PyBoostMt19937Object*)type->tp_alloc(type, 0);
self->rng = 0;
self->rng.reset();
return reinterpret_cast<PyObject*>(self);
return Py_BuildValue("N", self);
}
PyObject* PyBoostMt19937_SimpleNew () {
BOB_TRY
PyBoostMt19937Object* retval = (PyBoostMt19937Object*)PyBoostMt19937_New(&PyBoostMt19937_Type, 0, 0);
if (!retval) return 0;
retval->rng = new boost::mt19937;
return reinterpret_cast<PyObject*>(retval);
retval->rng.reset(new boost::mt19937);
return Py_BuildValue("N", retval);
BOB_CATCH_FUNCTION("SimpleNew", 0)
}
PyObject* PyBoostMt19937_NewWithSeed (Py_ssize_t seed) {
BOB_TRY
PyBoostMt19937Object* retval = (PyBoostMt19937Object*)PyBoostMt19937_New(&PyBoostMt19937_Type, 0, 0);
if (!retval) return 0;
retval->rng = new boost::mt19937(seed);
retval->rng.reset(new boost::mt19937(seed));
return reinterpret_cast<PyObject*>(retval);
return Py_BuildValue("N", retval);
BOB_CATCH_FUNCTION("NewWithSeed", 0)
}
......@@ -82,19 +76,14 @@ int PyBoostMt19937_Converter(PyObject* o, PyBoostMt19937Object** a) {
}
static void PyBoostMt19937_Delete (PyBoostMt19937Object* o) {
delete o->rng;
o->rng.reset();
Py_TYPE(o)->tp_free((PyObject*)o);
}
/* The __init__(self) method */
static int PyBoostMt19937_Init(PyBoostMt19937Object* self, PyObject *args,
PyObject* kwds) {
/* Parses input arguments in a single shot */
static const char* const_kwlist[] = {"seed", 0};
static char** kwlist = const_cast<char**>(const_kwlist);
static int PyBoostMt19937_Init(PyBoostMt19937Object* self, PyObject *args, PyObject* kwds) {
BOB_TRY
char** kwlist = mt19937_doc.kwlist();
PyObject* seed = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &seed)) return -1;
......@@ -104,60 +93,55 @@ static int PyBoostMt19937_Init(PyBoostMt19937Object* self, PyObject *args,
if (seed) {
Py_ssize_t s_seed = PyNumber_AsSsize_t(seed, PyExc_ValueError);
if (PyErr_Occurred()) return -1;
self->rng = new boost::mt19937(s_seed);
self->rng.reset(new boost::mt19937(s_seed));
}
else {
self->rng = new boost::mt19937;
self->rng.reset(new boost::mt19937);
}
return 0; ///< SUCCESS
BOB_CATCH_MEMBER("constructor", -1)
}
/* Sets the seed on a random number generator */
static auto seed_doc = bob::extension::FunctionDoc(
"seed",
"Sets the seed for this random number generator",
0,
true
)
.add_prototype("seed")
.add_parameter("seed", "int", "A new seed value for this RNG")
;
static PyObject* PyBoostMt19937_seed(PyBoostMt19937Object* self,
PyObject *args, PyObject* kwds) {
BOB_TRY
char** kwlist = seed_doc.kwlist();
/* Parses input arguments in a single shot */
static const char* const_kwlist[] = {"seed", 0};
static char** kwlist = const_cast<char**>(const_kwlist);
int seed;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &seed)) return 0;
PyObject* seed = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &seed)) return 0;
Py_ssize_t s_seed = PyNumber_AsSsize_t(seed, PyExc_ValueError);
if (PyErr_Occurred()) return 0;
self->rng->seed(s_seed);
self->rng->seed(seed);
Py_RETURN_NONE;
BOB_CATCH_MEMBER("seed", 0)
}
PyDoc_STRVAR(s_seed_str, "seed");
PyDoc_STRVAR(s_seed_doc,
"seed(x) -> None\n\
\n\
Sets the seed for this random number generator\n\
\n\
This method sets the seed for this random number generator. The\n\
input value needs to be convertible to a long integer.\n\
"
);
static PyMethodDef PyBoostMt19937_methods[] = {
{
s_seed_str,
seed_doc.name(),
(PyCFunction)PyBoostMt19937_seed,
METH_VARARGS|METH_KEYWORDS,
s_seed_doc,
seed_doc.doc(),
},
{0} /* Sentinel */
};
static PyObject* PyBoostMt19937_RichCompare(PyBoostMt19937Object* self,
PyObject* other, int op) {
BOB_TRY
if (!PyBoostMt19937_Check(other)) {
PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'",
s_seed_str, other->ob_type->tp_name);
PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", seed_doc.name(), other->ob_type->tp_name);
return 0;
}
......@@ -176,50 +160,40 @@ static PyObject* PyBoostMt19937_RichCompare(PyBoostMt19937Object* self,
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
BOB_CATCH_MEMBER("RichCompare", 0)
}
static PyObject* PyBoostMt19937_Repr(PyBoostMt19937Object* self) {
BOB_TRY
return PyUnicode_FromFormat("%s()", Py_TYPE(self)->tp_name);
BOB_CATCH_MEMBER("repr", 0)
}
PyTypeObject PyBoostMt19937_Type = {
PyVarObject_HEAD_INIT(0, 0)
s_mt19937_str, /*tp_name*/
sizeof(PyBoostMt19937Object), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)PyBoostMt19937_Delete, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)PyBoostMt19937_Repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
(reprfunc)PyBoostMt19937_Repr, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
s_mt19937_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)PyBoostMt19937_RichCompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyBoostMt19937_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PyBoostMt19937_Init, /* tp_init */
0, /* tp_alloc */
PyBoostMt19937_New, /* tp_new */
PyVarObject_HEAD_INIT(0,0)
0
};
bool init_BoostMt19937(PyObject* module)
{
// initialize the type struct
PyBoostMt19937_Type.tp_name = mt19937_doc.name();
PyBoostMt19937_Type.tp_basicsize = sizeof(PyBoostMt19937Object);
PyBoostMt19937_Type.tp_flags = Py_TPFLAGS_DEFAULT;
PyBoostMt19937_Type.tp_doc = mt19937_doc.doc();
PyBoostMt19937_Type.tp_str = reinterpret_cast<reprfunc>(PyBoostMt19937_Repr);
PyBoostMt19937_Type.tp_repr = reinterpret_cast<reprfunc>(PyBoostMt19937_Repr);
// set the functions
PyBoostMt19937_Type.tp_new = PyBoostMt19937_New;
PyBoostMt19937_Type.tp_init = reinterpret_cast<initproc>(PyBoostMt19937_Init);
PyBoostMt19937_Type.tp_dealloc = reinterpret_cast<destructor>(PyBoostMt19937_Delete);
PyBoostMt19937_Type.tp_methods = PyBoostMt19937_methods;
PyBoostMt19937_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBoostMt19937_RichCompare);
// check that everything is fine
if (PyType_Ready(&PyBoostMt19937_Type) < 0) return false;
// add the type to the module
return PyModule_AddObject(module, "mt19937", Py_BuildValue("O", &PyBoostMt19937_Type)) >= 0;
}
......@@ -60,10 +60,10 @@ powerful random number generator available within the Boost_ C++ library.
typedef struct {
PyObject_HEAD
boost::mt19937* rng;
boost::shared_ptr<boost::mt19937> rng;
} PyBoostMt19937Object;
.. c:member:: boost::mt19937* rng
.. c:member:: boost::shared_ptr<boost::mt19937> rng
A direct pointer to the boost random number generator. You can use this
pointer in your C/C++ code if required.
......@@ -429,25 +429,25 @@ support a different set of scalar types:
.. cpp:function:: PyObject* PyBoostLogNormal_SimpleNew(int type_num, PyObject* mean, PyObject* sigma)
.. cpp:function:: PyObject* PyBoostGamma_SimpleNew(int type_num, PyObject* alpha, PyObject* beta)
.. cpp:function:: PyObject* PyBoostGamma_SimpleNew(int type_num, PyObject* alpha)
.. cpp:function:: PyObject* PyBoostBinomial_SimpleNew(int type_num, PyObject* t, PyObject* p)
.. cpp:function:: PyObject* PyBoostDiscrete_SimpleNew(int type_num, PyObject* t, PyObject* p)
.. cpp:function:: PyObject* PyBoostDiscrete_SimpleNew(int type_num, PyObject* probs)
Depending on the distribution, which may be one of ``Normal``,
``LogNormal``, ``Gamma`` or ``Binomial``, each of the parameters assume a
``LogNormal``, ``Gamma``, ``Binomial`` or ``Discrete``, each of the parameters assume a
different function:
============== ============= ============================
============== ============= =============
Distribution Parameter 1 Parameter 2
============== ============= ============================
Normal mean sigma (standard deviation)
LogNormal mean sigma (standard deviation)
Gamma alpha beta
============== ============= =============
Normal mean sigma
LogNormal mean sigma
Gamma alpha
Binomial t p
Discrete probs ``None``
============== ============= ============================
Discrete probs
============== ============= =============
The parameter ``type_num`` may be set to one of the supported ``NPY_``
enumeration values (e.g. ``NPY_FLOAT64``).
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment