diff --git a/src/runtime/python/pgf.pyi b/src/runtime/python/pgf.pyi index 5c0906ba4..c1b9b0bc9 100644 --- a/src/runtime/python/pgf.pyi +++ b/src/runtime/python/pgf.pyi @@ -114,6 +114,15 @@ class PGF: """ ... + def generateRandom(cat : Type, depth : int = 5) -> tuple[Expr,float]: + """ + Generates a random abstract syntax trees of the given type. + The depth parameter specifies the maximal distance between + the root and a leaf in the tree. The float value in + the result is the probability of the tree. + """ + ... + def newTransaction(self) -> Transaction: """ Starts a new transaction which makes it possible to update diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index dec0f2863..2aa1c0eca 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -945,6 +945,54 @@ PGF_functionIsConstructor(PGFObject *self, PyObject *args) return PyBool_FromLong(isCon); } +static PyObject * +PGF_generateRandom(PGFObject *self, PyObject *args, PyObject *keywds) +{ + static char *kwlist[] = {"cat", "depth", NULL}; + + Py_ssize_t depth = 5; + TypeObject *start = NULL; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|n", kwlist, + &pgf_TypeType, &start, &depth)) + return NULL; + + PyObject *py_random = PyImport_ImportModule("random"); + if (py_random == NULL) + return NULL; + + PyObject *py_randint = PyObject_GetAttrString(py_random, "randint"); + Py_DECREF(py_random); + if (py_randint == NULL) + return NULL; + + PyObject *py_seed = PyObject_CallFunction(py_randint, "nn", 0, PY_SSIZE_T_MAX); + Py_DECREF(py_randint); + if (py_seed == NULL) + return NULL; + + size_t seed = PyLong_AsSsize_t(py_seed); + Py_DECREF(py_seed); + + PgfExn err; + prob_t prob; + PgfExpr expr = + pgf_generate_random(self->db, self->revision, + NULL, 0, + (PgfType) start, depth, + &seed, &prob, + &marshaller, &unmarshaller, + &err); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } + + PyObject *res = + Py_BuildValue("Od", (ExprObject *) expr, prob); + Py_DECREF((PyObject *) expr); + + return res; +} + static PyObject * PGF_categoryProbability(PGFObject *self, PyObject *args) { @@ -1490,6 +1538,9 @@ static PyMethodDef PGF_methods[] = { {"functionIsConstructor", (PyCFunction)PGF_functionIsConstructor, METH_VARARGS, "Checks whether a function is a constructor" }, + {"generateRandom", (PyCFunction)PGF_generateRandom, METH_VARARGS | METH_KEYWORDS, + "Generates a random abstract syntax trees of the given type" + }, {"categoryProbability", (PyCFunction)PGF_categoryProbability, METH_VARARGS, "Returns the probability of a category" }, diff --git a/src/runtime/python/setup.py b/src/runtime/python/setup.py index ee5365f56..d87f7e6b8 100644 --- a/src/runtime/python/setup.py +++ b/src/runtime/python/setup.py @@ -35,7 +35,7 @@ pgf_module = Extension( setup( name = 'pgf-majestic', - version = '2.6', + version = '2.7', description = 'Python bindings to the Grammatical Framework\'s PGF runtime', long_description="""\ Grammatical Framework (GF) is a programming language for multilingual grammar applications.