From 3c593f2a04493a4f3cb19c47e3311a8d79d18b85 Mon Sep 17 00:00:00 2001 From: Yann Weber Date: Wed, 28 Jun 2023 12:08:55 +0200 Subject: [PATCH] Implements mutation & copy for rpnepxr --- python_rpnexpr.c | 243 ++++++++++++++++++++++++++++++++- python_rpnexpr.h | 32 +++++ rpn_mutate.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++ rpn_mutate.h | 101 ++++++++++++++ 4 files changed, 723 insertions(+), 2 deletions(-) create mode 100644 rpn_mutate.c create mode 100644 rpn_mutate.h diff --git a/python_rpnexpr.c b/python_rpnexpr.c index 8de9474..607c037 100644 --- a/python_rpnexpr.c +++ b/python_rpnexpr.c @@ -19,9 +19,15 @@ #include "python_rpnexpr.h" PyMethodDef RPNExpr_methods[] = { - {"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"}, {"random", (PyCFunction)rpnexpr_random, METH_CLASS | METH_VARARGS | METH_KEYWORDS, "Return a new random RPN expression string"}, + {"default_mutation_params", (PyCFunction)rpnexpr_default_mutation_params, + METH_CLASS | METH_FASTCALL, + "Return the default mutation parameters"}, + {"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"}, + {"mutate", (PyCFunction)rpnexpr_mutate, + METH_VARARGS | METH_KEYWORDS, + "Mutate an expression given an RPNMutationParamsTuple instance"}, {"reset_stack", (PyCFunction)rpnexpr_reset_stack, METH_NOARGS, "Reset stack memory storage (set all items to 0)"}, {"__getstate__", (PyCFunction)rpnexpr_getstate, METH_NOARGS, @@ -29,6 +35,8 @@ PyMethodDef RPNExpr_methods[] = { and the stack state."}, {"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O, "Unpickling method"}, + {"__copy__", (PyCFunction)rpnexpr_copy, METH_NOARGS, + "Clone method. Return a new cloned instance"}, {"uid", (PyCFunction)rpnexpr_getexprstate, METH_NOARGS, "Return a base64 uid for expression"}, {NULL} //Sentinel @@ -256,6 +264,7 @@ PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs) Py_DECREF(comp); return res; */ + PyErr_SetString(PyExc_NotImplementedError, "Not implemented..."); return NULL; } @@ -376,7 +385,7 @@ generating exception message !"); if(expr_self->rpn || expr_self->args) /* checking instance state */ { PyErr_SetString(PyExc_ValueError, - "RPNExpr.__getstate__() instance in bad state : \ + "RPNExpr.__setstate__() instance in bad state : \ should not be initialized"); return NULL; } @@ -491,6 +500,35 @@ args buffer : %s", return NULL; } + +PyObject* rpnexpr_copy(PyObject *self, PyObject *noargs) +{ + PyRPNExpr_t *copy; + PyObject *ret, *state, *setret; + + ret = PyObject_CallMethod((PyObject*)&RPNExprType, "__new__", "O", &RPNExprType); + copy = (PyRPNExpr_t*)ret; + + state = PyObject_CallMethod(self, "__getstate__", NULL); + if(PyErr_Occurred()) { + goto err; + } + setret = PyObject_CallMethod(ret, "__setstate__", "O", state); + if(PyErr_Occurred()) { + Py_DECREF(state); + goto err; + } + + Py_DECREF(state); + Py_DECREF(setret); + + return ret; +err: + PyObject_Del(copy); + return NULL; +} + + PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc) { PyRPNExpr_t *expr_self; @@ -536,6 +574,52 @@ PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc) return PyLong_FromUnsignedLong(res); } + +PyObject* rpnexpr_mutate(PyObject* slf, PyObject *args, PyObject *kwds) +{ + PyRPNExpr_t *self = (PyRPNExpr_t*)slf; + + char *str_args = "|OI:RPNIterExpr.mutate"; + char *names[] = {"params", "n_mutations", NULL}; + + PyObject *py_params = NULL; + unsigned int n_mutations = 1; + rpn_mutation_params_t params; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, str_args, names, + &py_params, &n_mutations)) + { + return NULL; + } + + if(!py_params) + { + memcpy(¶ms, &rpn_mutation_params_default, + sizeof(rpn_mutation_params_t)); + } + else + { + if(rpnexpr_pyobj_to_mutation_params(py_params, ¶ms) < 0) + { + PyErr_SetString(PyExc_ValueError, "Bad value for params arguments"); + return NULL; + } + } + + for(size_t i=0; irpn->toks), ¶ms) < 0) + { + PyErr_Format(PyExc_RuntimeError, "Mutation failed : %s", + strerror(errno)); + return NULL; + } + } + + rpn_expr_tokens_updated(self->rpn); + Py_RETURN_NONE; +} + PyObject* rpnexpr_reset_stack(PyObject *self, PyObject *noargs) { rpn_expr_reset_stack(((PyRPNExpr_t*)self)->rpn); @@ -608,3 +692,158 @@ PyObject* rpnexpr_random(PyObject *cls, PyObject *args, PyObject *kwds) return res; } +PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssize_t argc) +{ + PyObject *res, *wtypes; + + if(!(wtypes = PyStructSequence_New(&rpn_token_types_SeqDesc))) + { + return NULL; + } + + if(!(res = PyStructSequence_New(&rpn_mutation_params_SeqDesc))) + { + return NULL; + } + + // wtypes filled with 1.0 + PyObject *one = PyFloat_FromDouble(1.0); + for(size_t i=0; i<3; i++) + { + PyStructSequence_SET_ITEM(wtypes, i, one); + } + + + // max_len + PyStructSequence_SET_ITEM(res, 0, + PyLong_FromLong(rpn_mutation_params_default.min_len)); + // weight_add + PyStructSequence_SET_ITEM(res, 1, + PyFloat_FromDouble(rpn_mutation_params_default.w_add)); + // weight_del + PyStructSequence_SET_ITEM(res, 2, + PyFloat_FromDouble(rpn_mutation_params_default.w_del)); + // weight_mut + PyStructSequence_SET_ITEM(res, 3, + PyFloat_FromDouble(rpn_mutation_params_default.w_mut)); + // weight_mut_soft + PyStructSequence_SET_ITEM(res, 4, + PyFloat_FromDouble(rpn_mutation_params_default.w_mut_soft)); + + /** TODO use rpn_mutation_params_default instead of wtypes [1,1,1] */ + // weight_add_elt + PyStructSequence_SET_ITEM(res, 5, wtypes); + Py_INCREF(wtypes); + // weight_mut_elt + PyStructSequence_SET_ITEM(res, 6, wtypes); + Py_INCREF(wtypes); + + return res; + +} + + +static inline void _parse_float(PyObject *obj, float *res) +{ + double tmp = PyFloat_AsDouble(obj); + if(tmp > FLT_MAX) + { + PyErr_SetString(PyExc_OverflowError, "Float overflows"); + return; + } + *res=tmp; + return; +} + +static inline void _parse_type_weights(PyObject *obj, float w[3]) +{ + PyObject *fast = PySequence_Fast(obj, "Not a RPNTokenTypeTuple nor with a length of 3"); + if(!fast) { return; } + if(PySequence_Length(obj) != 3) + { + PyErr_Format(PyExc_ValueError, "Excpected RPNTokenTypeTuple or 3 elements but got %d elements", PySequence_Length(obj)); + return; + } + + PyObject **elts = PySequence_Fast_ITEMS(fast); + + const char* names[3] = {"op", "const", "var"}; + for(size_t i=0; i<3; i++) + { + _parse_float(elts[i], &w[i]); + if(PyErr_Occurred()) + { + PyErr_Format(PyExc_ValueError, + "Bad value for .%s field", + names[i]); + break; + } + } + return; +} + +int rpnexpr_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params) +{ + if(!PySequence_Check(py_params)) + { + PyErr_SetString(PyExc_TypeError, "The given object is not a a sequence"); + return -1; + } + if(PySequence_Size(py_params) != 7) + { + PyErr_SetString(PyExc_ValueError, "The given object is not a RPNMutationParamsTuple nor of length 7"); + return -1; + } + PyObject *fast = PySequence_Fast(py_params, "The given object is not a RPNMutationParamsTuple nor a sequence ?"); + Py_INCREF(fast); + + PyObject **elts = PySequence_Fast_ITEMS(fast); + + params->min_len = PyLong_AsSize_t(elts[0]); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad type for .minimum_length field"); + return -1; + } + + _parse_float(elts[1], ¶ms->w_add); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add field"); + return -1; + } + _parse_float(elts[2], ¶ms->w_del); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_del field"); + return -1; + } + _parse_float(elts[3], ¶ms->w_mut); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_mut field"); + return -1; + } + _parse_float(elts[4], ¶ms->w_mut_soft); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_mut_soft field"); + return -1; + } + + _parse_type_weights(elts[5], params->w_add_elt); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add_elt field"); + return -1; + } + + _parse_type_weights(elts[6], params->w_mut_elt); + if(PyErr_Occurred()) + { + PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add_elt field"); + return -1; + } + return 0; +} + diff --git a/python_rpnexpr.h b/python_rpnexpr.h index 87de4a0..495b3a9 100644 --- a/python_rpnexpr.h +++ b/python_rpnexpr.h @@ -22,12 +22,14 @@ #include "config.h" #include +#include #define PY_SSIZE_T_CLEAN #include #include "structmember.h" #include "rpn_jit.h" +#include "python_const.h" /**@defgroup python_type RPNExpr Python class * @brief Exposed Python class : RPNExpr @@ -134,6 +136,14 @@ PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs); */ PyObject* rpnexpr_setstate(PyObject *cls, PyObject *state); +/**@brief RPNExpr __copy__ method for cloning + * @param self RPNExpr instance + * @param noargs Not an argument... + * @return A new cloned instance + * @ref rpnexpr_setstate + */ +PyObject* rpnexpr_copy(PyObject *cls, PyObject *noargs); + /**@brief Eval an RPN expression given arguments and return the * value * @param self RPNExpr instance @@ -144,6 +154,13 @@ PyObject* rpnexpr_setstate(PyObject *cls, PyObject *state); */ PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc); +/**@brief Mutate an RPN expression given arguments and return the value + * @param PyObject* RPNExpr instance + * @param PyObject* Positionnal arguments + * @param PyObject* Keyword arguments + */ +PyObject* rpnexpr_mutate(PyObject* self, PyObject *args, PyObject *kwds); + /**@brief Set all stack item to zero * @param self RPNExpr instance * @param noargs Dummy argument for METH_NOARG @@ -172,4 +189,19 @@ PyObject* rpnexpr_str(PyObject *self); */ PyObject* rpnexpr_random(PyObject *cls, PyObject *args, PyObject *kwds); +/**@brief Return a new named tuple containing default mutation parameters + * @param PyObject* The class (class method) + * @param PyObject** The arguments (FASTCALL) + * @param Py_ssize_t The number of arguments + * @return The named tuple + */ +PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssize_t argc); + +/**@brief Try to convert a python object into a rpn_mutation_params_t + * @param PyObject* The python object + * @param rpn_mutation_params_t A pointer on the parameters to initialize + * @return -1 on failure and raise an exception + */ +int rpnexpr_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params); + #endif diff --git a/rpn_mutate.c b/rpn_mutate.c new file mode 100644 index 0000000..9c17640 --- /dev/null +++ b/rpn_mutate.c @@ -0,0 +1,349 @@ +#include "rpn_mutate.h" + +const rnd_t rnd_t_max = -1; + +const rpn_mutation_params_t rpn_default_mutation = { + .min_len = 3, + .w_add = 1.25, + .w_del = 1.0, + .w_mut = 2.0, + .w_mut_soft = 4.0, + .w_add_elt = {1,1,1}, + .w_mut_elt={1,1,1}, +}; + +#define to_weight(total, elt) ((rnd_t)((((long double)elt)*rnd_t_max)/total)) +int rpn_mutation_init_params(rpn_mutation_params_t *params) +{ + long double total; + + if(params->w_add < 0) { goto err; } + if(params->w_del < 0) { goto err; } + if(params->w_mut < 0) { goto err; } + if(params->w_mut_soft < 0) { goto err; } + + total = params->w_add + params->w_del + params->w_mut + params->w_mut_soft; + params->_weights[0] = to_weight(total, params->w_add); + params->_weights[1] = to_weight(total, params->w_del); + params->_weights[2] = to_weight(total, params->w_mut); + params->_weights[3] = to_weight(total, params->w_mut_soft); +#ifdef DEBUG +dprintf(2, "weights : %d %d %d %d\n", + params->_weights[0], + params->_weights[1], + params->_weights[2], + params->_weights[3]); +#endif + for(uint8_t i=1; i<4; i++) + { + params->_weights[i] += params->_weights[i-1]; + } +#ifdef DEBUG +dprintf(2, "summed weights : %d %d %d %d\n", + params->_weights[0], + params->_weights[1], + params->_weights[2], + params->_weights[3]); +#endif + + total = 0; + for(uint8_t i=0; i<3; i++) + { + if(params->w_add_elt[i] < 0) { goto err; } + total += params->w_add_elt[i]; + } + for(uint8_t i=0; i<3; i++) + { + params->_weights[i+4] = to_weight(total, params->w_add_elt[i]); + if(i>0) + { + params->_weights[i+4] += params->_weights[i+3]; + } + } + + total = 0; + for(uint8_t i=0; i<3; i++) + { + if(params->w_mut_elt[i] < 0) { goto err; } + total += params->w_mut_elt[i]; + } + for(uint8_t i=0; i<3; i++) + { + params->_weights[i+7] = to_weight(total, params->w_mut_elt[i]); + if(i>0) + { + params->_weights[i+7] += params->_weights[i+6]; + } + } + + return 0; +err: + errno = EINVAL; + return -1; +} +#undef to_weight + +int rpn_mutation(rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + assert(toks->argc < rnd_t_max); + + if(toks->tokens_sz <= params->min_len) + { + return rpn_mutation_add(toks, params); + } + size_t choice; + if(_rpn_random_choice(4, params->_weights, &choice) < 0) + { + return -1; + } + switch(choice) + { + case 0: + return rpn_mutation_add(toks, params); + case 1: + return rpn_mutation_del(toks, params); + case 2: + return rpn_mutation_mut(toks, params); + case 3: + return rpn_mutation_mut_soft(toks, params); + default: + dprintf(2, "Random error that should never occurs"); + return -1; + } + +} +int rpn_mutation_add(rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + rpn_token_t *new_toks, new_token; + size_t position; + + if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0) + { + return -1; + } + + if(rpn_random_token_type(&(new_token.type), ¶ms->_weights[4]) < 0) + { + return -1; + } + if(rpn_mutation_random_token(&new_token, toks, params) < 0) + { + return -1; + } + + toks->tokens_sz++; + new_toks = realloc(toks->tokens, sizeof(rpn_token_t) * toks->tokens_sz); + if(!new_toks) + { + toks->tokens_sz--; + return -1; + } + toks->tokens = new_toks; + + if(position < toks->tokens_sz - 1) + { + memmove(&(toks->tokens[position+1]), &(toks->tokens[position]), + sizeof(rpn_token_t) * ((toks->tokens_sz-1) - position)); + } + memcpy(&toks->tokens[position], &new_token, sizeof(rpn_token_t)); + + return 0; +} +int rpn_mutation_del(rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + rpn_token_t *new_toks; + size_t position; + + if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0) + { + return -1; + } + + if(position != toks->tokens_sz - 1) + { + memmove(&(toks->tokens[position]), &(toks->tokens[position+1]), + sizeof(rpn_token_t) * ((toks->tokens_sz - 1) - position)); + } + toks->tokens_sz--; + new_toks = realloc(toks->tokens, sizeof(rpn_token_t) * toks->tokens_sz); + if(!new_toks) + { + toks->tokens_sz = 0; + toks->tokens = NULL; + return -1; + } + toks->tokens = new_toks; + return 0; +} +int rpn_mutation_mut(rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + rpn_token_t *tok; + size_t position; + + if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0) + { + return -1; + } + + tok = &toks->tokens[position]; + + if(rpn_random_token_type(&(tok->type), &(params->_weights[7])) < 0) + { + return -1; + } + if(rpn_mutation_random_token(tok, toks, params) < 0) + { + return -1; + } + + return 0; +} +int rpn_mutation_mut_soft(rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + rpn_token_t *tok; + size_t position; + + if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0) + { + return -1; + } + + tok = &(toks->tokens[position]); + + if(rpn_mutation_random_token(tok, toks, params) < 0) + { + return -1; + } + + return 0; +} + + +int rpn_mutation_random_token(rpn_token_t *tok, + rpn_tokenized_t *toks, rpn_mutation_params_t *params) +{ + rnd_t rand; + + if(rpn_getrandom(&rand) < 0) + { + return -1; + } + + unsigned char op_n; + unsigned char *val; + size_t left; + switch(tok->type) + { + case RPN_op: + op_n = rand / (rnd_t_max/RPN_OP_SZ); + op_n %= RPN_OP_SZ; + tok->op_n = op_n; + tok->op = &(rpn_ops[op_n]); + break; + + case RPN_arg: + tok->arg_n = rand / (rnd_t_max/toks->argc); + tok->arg_n %= toks->argc; + break; + case RPN_val: + val =(unsigned char*)&(tok->value); + left = sizeof(tok->value); + do + { + ssize_t ret = getrandom(val, left, GRND_NONBLOCK); + if(ret == -1) + { + if(errno == EAGAIN || errno == EINTR) + { + continue; + } + return -1; + } + left -= ret; + val += ret; + }while(left); + break; + default: + dprintf(2, "Another random error that shouldn't occur\n"); + return -1; + } + return 0; +} + + +int rpn_random_token_type(rpn_token_type_t *type, rnd_t *weights) +{ + const rpn_token_type_t types[3] = { RPN_op, RPN_arg, RPN_val }; + size_t choice; + + if(_rpn_random_choice(3, weights, &choice) < 0) + { + return -1; + } + *type = types[choice]; + return 0; +} + +int rpn_getrandom(rnd_t *rand) +{ + rnd_t seed; + char *seed_ptr = (char*)&seed; + size_t buflen = sizeof(seed); + + do + { + ssize_t ret = getrandom(seed_ptr, buflen, GRND_NONBLOCK); + if(ret == -1) + { + if(errno == EAGAIN || errno == EINTR) + { + continue; + } + return -1; + } + buflen -= ret; + seed_ptr += ret; + }while(buflen); + *rand = seed; + return 0; +} + +int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res) +{ + rnd_t rand; + if(rpn_getrandom(&rand) < 0) { return -1; } + __rpn_random_choice(sz, weights, rand, res); + return 0; +} + +void __rpn_random_choice(size_t sz, rnd_t *weights, rnd_t rand, size_t *res) +{ + for(*res=0; *res= rand) + { + return; + } + } + *res = sz-1; +} + +int rpn_rand_limit(size_t max, size_t *res) +{ + unsigned long int step = rnd_t_max / max; + rnd_t rnd; + + if(rpn_getrandom(&rnd) < 0) + { + return -1; + } + for(*res=0; *res= rnd) + { + return 0; + } + } + //*res = max - 1; + return 0; +} diff --git a/rpn_mutate.h b/rpn_mutate.h new file mode 100644 index 0000000..145fc63 --- /dev/null +++ b/rpn_mutate.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020,2023 Weber Yann + * + * This file is part of pyrpn. + * + * pyrpn 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 + * any later version. + * + * pyrpn 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 pyrpn. If not, see . + */ +#ifndef __rpn_mutate__h__ +#define __rpn_mutate__h__ +#include "config.h" + +#include +#include +#include +#include + +#include "rpn_parse.h" + +typedef struct rpn_mutation_params_s rpn_mutation_params_t; +typedef uint16_t rnd_t; + + +struct rpn_mutation_params_s +{ + /**@brief Minimum expression length */ + size_t min_len; + /**@brief Weight of adding a token*/ + float w_add; + /**@brief Weight of deleting a token*/ + float w_del; + /**@brief Weight of mutating a token*/ + float w_mut; + /**@brief Weight of mutating a token without type change*/ + float w_mut_soft; + /**@brief Weight for each token types (op, const, var) when + * adding a token*/ + float w_add_elt[3]; + /**@brief Weight for each token types (op, const, var) when + * mutating a token*/ + float w_mut_elt[3]; + + /**@brief For internal use, set by @ref rpn_mutation_init_params + * + * weight reported by groups on rnd_t integers + * - [0..3] -> weights mutation + * - [4..6] -> w_add_elt + * - [7..9] -> w_mut_elt + */ + rnd_t _weights[10]; +}; + +/**@brief Initialize mutation parameters + * + * pre-process integers threshold by group + * @param rpn_mutation_params_t* + * @return 0 if no error else -1 and set ERRNO (EINVAL) + */ +int rpn_mutation_init_params(rpn_mutation_params_t *params); + +/**@brief Mutate a tokenized rpn expression */ +int rpn_mutation(rpn_tokenized_t *toks, rpn_mutation_params_t *params); +int rpn_mutation_add(rpn_tokenized_t *toks, rpn_mutation_params_t *params); +int rpn_mutation_del(rpn_tokenized_t *toks, rpn_mutation_params_t *params); +int rpn_mutation_mut(rpn_tokenized_t *toks, rpn_mutation_params_t *params); +int rpn_mutation_mut_soft(rpn_tokenized_t *toks, rpn_mutation_params_t *params); + +/**@brief Change the "value" of a token randomly not it's type */ +int rpn_mutation_random_token(rpn_token_t *tok, + rpn_tokenized_t *toks, rpn_mutation_params_t *params); + + +/**@breif Choose a random token type + * @return -1 on error + */ +int rpn_random_token_type(rpn_token_type_t *type, rnd_t *weights); + +/**@param rnd_t* Is set to a random value + * @return -1 on error else 0 */ +int rpn_getrandom(rnd_t *rand); + +/**@param size_t Maximum value + * @param size_t* Will be set to a value between [..max[ + * @return -1 on error else 0 */ +int rpn_rand_limit(size_t max, size_t *res); + +/**@briref Given a size return an element with regards to given weights */ +int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res); +void __rpn_random_choice(size_t sz, rnd_t *weights, rnd_t rand, size_t *res); + +#endif