Preparing implementation & python API for IFS mutation
This commit is contained in:
parent
5b2b9844e8
commit
30c6c92493
20 changed files with 1865 additions and 307 deletions
|
@ -68,6 +68,7 @@ static PyStructSequence_Field token_types_fields[] = {
|
|||
{ .name = "var",
|
||||
.doc = "Variable (argument)",
|
||||
},
|
||||
{ NULL, NULL },
|
||||
};
|
||||
PyStructSequence_Desc rpn_token_types_desc = {
|
||||
.name = "RPNTokenTypes",
|
||||
|
@ -77,51 +78,6 @@ PyStructSequence_Desc rpn_token_types_desc = {
|
|||
};
|
||||
PyTypeObject rpn_token_types_SeqDesc;
|
||||
|
||||
/**@brief @ref pymod_pyrpn_RPNMutationParams field definition
|
||||
* @ingroup pymod_pyrpn_RPNMutationParams */
|
||||
static PyStructSequence_Field mutation_params_fields[] = {
|
||||
{ .name = "minimum_length",
|
||||
.doc = "Expression minimum length",
|
||||
},
|
||||
{ .name = "weight_add",
|
||||
.doc = "The weight for 'add token' mutation",
|
||||
},
|
||||
{ .name = "weight_del",
|
||||
.doc = "The weight for 'delete token' mutation",
|
||||
},
|
||||
{ .name = "weight_mut",
|
||||
.doc = "The weight for 'mutate token' mutation",
|
||||
},
|
||||
{ .name = "weight_mut_soft",
|
||||
.doc = "The weight for 'mutate soft (value not type) token' mutation",
|
||||
},
|
||||
{
|
||||
.name = "weight_add_elt",
|
||||
.doc = "The weights for each token types when adding a token",
|
||||
},
|
||||
{
|
||||
.name = "weight_del_elt",
|
||||
.doc= "The weights for each token types when deleting a token",
|
||||
}
|
||||
};
|
||||
PyStructSequence_Desc rpn_mutation_params_desc = {
|
||||
.name = "RPNMutationParams",
|
||||
.doc = "Named tuple for mutation parameters",
|
||||
.n_in_sequence = (sizeof(mutation_params_fields) / sizeof(*mutation_params_fields)),
|
||||
.fields = mutation_params_fields,
|
||||
};
|
||||
PyTypeObject rpn_mutation_params_SeqDesc;
|
||||
|
||||
|
||||
rpn_mutation_params_t rpn_mutation_params_default = {
|
||||
.min_len = 3,
|
||||
.w_add = 1.25,
|
||||
.w_del = 1.0,
|
||||
.w_mut = 2.0,
|
||||
.w_mut_soft = 4.0,
|
||||
.w_add_elt = {1.0,1.0,1.0},
|
||||
.w_mut_elt = {1.0,1.0,1.0},
|
||||
};
|
||||
|
||||
/**@brief Adds a constant to @ref pymod_pyrpn_const module
|
||||
* @param mod The @ref pymod_pyrpn_const module
|
||||
|
@ -150,8 +106,6 @@ PyObject *rpnconst_init(void)
|
|||
mod = PyModule_Create(&rpnconstmodule);
|
||||
if(mod == NULL) { return NULL; }
|
||||
|
||||
rpn_mutation_init_params(&rpn_mutation_params_default);
|
||||
|
||||
if(Py_rpnconst_add(mod, "POS_LINEAR", RPN_IF_POSITION_LINEAR) ||
|
||||
Py_rpnconst_add(mod, "POS_XY", RPN_IF_POSITION_XY) ||
|
||||
Py_rpnconst_add(mod, "POS_XDIM", RPN_IF_POSITION_XDIM) ||
|
||||
|
@ -169,4 +123,46 @@ PyObject *rpnconst_init(void)
|
|||
return mod;
|
||||
}
|
||||
|
||||
PyObject *pyrpn_PyErr_ReraiseFormat(PyObject *exception, const char *fmt, ...)
|
||||
{
|
||||
va_list vargs;
|
||||
PyObject *exc, *val, *val2, *tb;
|
||||
|
||||
va_start(vargs, fmt);
|
||||
|
||||
// we ay trigger a warning when in debug mode ?
|
||||
#ifdef NDEBUG
|
||||
assert(PyErr_Occurred());
|
||||
#else
|
||||
if(!PyErr_Occurred())
|
||||
{
|
||||
PyErr_WarnEx(PyExc_SyntaxWarning,
|
||||
"Warning, reraising but PyErr_Occurred() not set", 1);
|
||||
PyErr_FormatV(exception, fmt, vargs);
|
||||
va_end(vargs);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
PyErr_NormalizeException(&exc, &val, &tb);
|
||||
if(tb != NULL)
|
||||
{
|
||||
PyException_SetTraceback(val, tb);
|
||||
Py_DECREF(tb);
|
||||
}
|
||||
Py_DECREF(exc);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
PyErr_FormatV(exception, fmt, vargs);
|
||||
|
||||
PyErr_Fetch(&exc, &val2, &tb);
|
||||
PyErr_NormalizeException(&exc, &val2, &tb);
|
||||
Py_INCREF(val);
|
||||
PyException_SetCause(val2, val);
|
||||
PyException_SetContext(val2, val);
|
||||
PyErr_Restore(exc, val2, tb);
|
||||
|
||||
va_end(vargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,15 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "rpn_mutate.h"
|
||||
#include "rpn_if_mutate.h"
|
||||
#include "rpn_ifs_mutate.h"
|
||||
#include "rpn_if_default.h"
|
||||
|
||||
/**@file python_const.h
|
||||
|
@ -66,20 +69,11 @@ extern PyTypeObject rpn_token_types_SeqDesc;
|
|||
/**@brief @ref rpn_token_types_SeqDesc named tuple description */
|
||||
extern PyStructSequence_Desc rpn_token_types_desc;
|
||||
|
||||
/**@defgroup pymod_pyrpn_RPNMutationParams pyrpn.RPNMutationParams
|
||||
* @brief namedtuple storing mutation parameters
|
||||
* @ingroup pymod_pyrpn */
|
||||
/**@brief RPNMutationParams named tuple with mutation parameters */
|
||||
extern PyTypeObject rpn_mutation_params_SeqDesc;
|
||||
/**@brief @ref rpn_mutation_params_SeqDesc named tuple description */
|
||||
extern PyStructSequence_Desc rpn_mutation_params_desc;
|
||||
|
||||
/**@brief Default values for mutations parameters */
|
||||
extern rpn_mutation_params_t rpn_mutation_params_default;
|
||||
|
||||
/**@brief pyrpn.const module initialisation function
|
||||
* @return The initialized module
|
||||
* @ingroup pymod_pyrpn */
|
||||
PyObject *rpnconst_init(void);
|
||||
|
||||
PyObject *pyrpn_PyErr_ReraiseFormat(PyObject *exception, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
|
63
python_if.c
63
python_if.c
|
@ -529,7 +529,14 @@ PyObject* rpnif_mutate(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
PyObject *py_params = NULL, *py_weights = NULL;
|
||||
unsigned int n_mutations = 1;
|
||||
rpn_mutation_params_t params;
|
||||
rnd_t *weights = malloc(sizeof(rnd_t)*rpn_sz);
|
||||
rnd_t *weights;
|
||||
if(!if_mutation_alloc_weights(expr_self->rif, &weights))
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Unable to allocate weights : %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwargs, str_args, names,
|
||||
&n_mutations, &py_params, &py_weights))
|
||||
|
@ -565,36 +572,36 @@ PyObject* rpnif_mutate(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
goto err;
|
||||
|
||||
}
|
||||
long double total = 0;
|
||||
|
||||
float *fweights;
|
||||
if(!if_mutation_alloc_weights(expr_self->rif, &fweights))
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Unable to allocate memory : %s",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
for(size_t i=0; i<rpn_sz; i++)
|
||||
{
|
||||
PyObject *elt = PySequence_Fast_GET_ITEM(seq, i);
|
||||
if(!PyNumber_Check(elt))
|
||||
{
|
||||
Py_DECREF(seq);
|
||||
free(fweights);
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"weights must contains float values");
|
||||
goto err;
|
||||
}
|
||||
total += PyFloat_AsDouble(elt);
|
||||
fweights[i] = (float)PyFloat_AsDouble(elt);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
Py_DECREF(seq);
|
||||
free(fweights);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
for(size_t i=0; i<rpn_sz; i++)
|
||||
{
|
||||
if(total == 0)
|
||||
{
|
||||
weights[i] = (rnd_t)((rnd_t_max / rpn_sz)*(i+1));
|
||||
continue;
|
||||
}
|
||||
PyObject *py_elt = PySequence_Fast_GET_ITEM(seq, i);
|
||||
long double elt = PyFloat_AsDouble(py_elt);
|
||||
weights[i] = (elt*rnd_t_max)/total;
|
||||
weights[i] += i>0? weights[i-1] : 0;
|
||||
}
|
||||
rpnifs_fast_rnd_weights(rpn_sz, fweights, weights);
|
||||
free(fweights);
|
||||
Py_DECREF(seq);
|
||||
}
|
||||
|
||||
|
@ -606,7 +613,7 @@ PyObject* rpnif_mutate(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(rpnexpr_pyobj_to_mutation_params(py_params, ¶ms) < 0)
|
||||
if(pyrpn_pyobj_to_mutation_params(py_params, ¶ms) < 0)
|
||||
{
|
||||
if(!PyErr_Occurred())
|
||||
{
|
||||
|
@ -618,25 +625,13 @@ PyObject* rpnif_mutate(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
}
|
||||
}
|
||||
|
||||
for(size_t i=0; i<n_mutations; i++)
|
||||
if(if_mutation(expr_self->rif, weights, n_mutations, ¶ms) < 0)
|
||||
{
|
||||
size_t rpn_num;
|
||||
if(_rpn_random_choice(rpn_sz, weights, &rpn_num) < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Unable to choose an expression \
|
||||
randomly : %s", strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if(rpn_mutation(&(expr_self->rif->rpn[rpn_num].toks),
|
||||
¶ms) < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Mutation failed : %s",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
rpn_expr_tokens_updated(&(expr_self->rif->rpn[rpn_num]));
|
||||
free(weights);
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Error during mutations : %s",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
free(weights);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "rpn_if.h"
|
||||
#include "rpn_if_default.h"
|
||||
#include "rpn_if_mutate.h"
|
||||
#include "python_mutation.h"
|
||||
#include "python_rpnexpr.h"
|
||||
#include "python_const.h"
|
||||
|
||||
|
|
203
python_ifs.c
203
python_ifs.c
|
@ -44,10 +44,25 @@ in the system."),
|
|||
METH_O,
|
||||
"self, position, /",
|
||||
"Return a coordinates tuple from given position."),
|
||||
PYRPN_method("set_mutation_params", rpnifs_set_mutation_params,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"self, params=None, /, weight_type=None, \
|
||||
mutation_weight_range=None, if_weights=None, if_component_weights=None, \
|
||||
if_mut_params=None",
|
||||
"Set mutation parameters. \n\
|
||||
The first argument 'params' is for giving an IFSMutationParams \
|
||||
(self.ifs_mutation_weights) instance.\n\
|
||||
Keywords arguments corresponds to IFSMutationParams writable fields \
|
||||
(see help(pyrpn.IFSMutationParams)).\n\n\
|
||||
Note : if params and keywords arguments are given, params is used and \
|
||||
then overwrited by given keywords arguments."),
|
||||
{NULL} // Sentinel
|
||||
};
|
||||
|
||||
static PyMemberDef RPNIFS_members[] = {
|
||||
{"mutation_params", T_OBJECT,
|
||||
offsetof(PyRPNIFS_t, py_ifs_mut_weights), READONLY,
|
||||
"The mutation weights & parameters for mutating the IFS"},
|
||||
{"expressions", T_OBJECT, offsetof(PyRPNIFS_t, rpn_if), READONLY,
|
||||
"The tuple with RPNIterExpr instances"},
|
||||
{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
|
||||
|
@ -104,6 +119,52 @@ PyObject *rpnifs_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**@brief Initialize internal fields */
|
||||
static int _rpnifs_init_weights(PyObject *self)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
ifs_mutation_weights_t *imw = &ifs_self->ifs_mut_weights;
|
||||
|
||||
if(ifs_mutation_weights_alloc(imw, ifs_self->ifs, 0, 0) < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Error allocating ifs mutation weights : %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
imw->w_mut_type[0] = imw->w_mut_type[1] = 0.5;
|
||||
imw->w_weight_range[0] = 0.01;
|
||||
imw->w_weight_range[1] = 0.1;
|
||||
|
||||
for(size_t i=0; i < ifs_self->ifs->if_sz; i++)
|
||||
{
|
||||
imw->w_mut_if[i] = 1.0/ifs_self->ifs->if_sz;
|
||||
}
|
||||
for(size_t i=0; i < imw->w_comp_if_sz; i++)
|
||||
{
|
||||
imw->w_comp_if[i] = 1.0/imw->w_comp_if_sz;
|
||||
}
|
||||
|
||||
memcpy(imw->if_mut_params, &rpn_mutation_params_default,
|
||||
sizeof(rpn_mutation_params_default));
|
||||
|
||||
if(ifs_mutation_weights_update(imw) < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Error while updating mutation weights : '%s'\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pyrpn_ifs_mut_weight_to_pyobj(imw,
|
||||
&ifs_self->py_ifs_mut_weights) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
@ -191,6 +252,11 @@ length %ld provided",
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(_rpnifs_init_weights(self) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -230,13 +296,11 @@ PyObject *rpnifs_from_pos(PyObject *self, PyObject* _pos)
|
|||
}
|
||||
|
||||
|
||||
|
||||
PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
PyObject *iter;
|
||||
unsigned int *weights;
|
||||
|
||||
if(nargs == 1 && args[0] != Py_None)
|
||||
{
|
||||
// Try to update weights
|
||||
|
@ -278,6 +342,9 @@ PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs
|
|||
Py_DECREF(item);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"\
|
||||
Weights sequence element #%ld invalid", i);
|
||||
goto err_weights;
|
||||
}
|
||||
weights[i] = w;
|
||||
|
@ -287,7 +354,7 @@ PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs
|
|||
free(weights);
|
||||
}
|
||||
|
||||
// return weights in a new tuple
|
||||
// construct returned weights in a new tuple
|
||||
PyObject *ret = PyTuple_New(ifs_self->ifs->if_sz);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
|
@ -305,6 +372,20 @@ PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
if(ifs_mutation_weights_if_count_update(&ifs_self->ifs_mut_weights,
|
||||
ifs_self->ifs->if_sz) < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Error reallocating mutation weights : %s",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(ifs_self->py_ifs_mut_weights);
|
||||
if(pyrpn_ifs_mut_weight_to_pyobj(&ifs_self->ifs_mut_weights,
|
||||
&ifs_self->py_ifs_mut_weights) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
|
||||
err_weights:
|
||||
|
@ -393,6 +474,122 @@ err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyObject *rpnifs_set_mutation_params(PyObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
|
||||
char *names[] = {"params", "weight_type", "mutation_weight_range",
|
||||
"if_weights", "if_component_weights", "if_mut_params", NULL};
|
||||
|
||||
PyObject *params = NULL;
|
||||
PyObject *mut_type_weight = NULL, \
|
||||
*weight_range = NULL, \
|
||||
*mut_if_weight = NULL, \
|
||||
*if_comp_weight = NULL, \
|
||||
*mutation_params = NULL;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds,
|
||||
"|OOOOOO:RPNIFS.set_mutation_weight",
|
||||
names,
|
||||
¶ms, &mut_type_weight,
|
||||
&weight_range, &mut_if_weight, &if_comp_weight,
|
||||
&mutation_params))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(params && params != Py_None)
|
||||
{
|
||||
ifs_mutation_weights_t tmp;
|
||||
if(pyrpn_pyobj_to_ifs_mutation_weights(params, &tmp) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"params argument invalid");
|
||||
return NULL;
|
||||
}
|
||||
if(tmp.if_count != ifs_self->ifs->if_sz)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Expected params for %ld IF but given \
|
||||
params is for %ld IF.", ifs_self->ifs->if_sz, tmp.if_count);
|
||||
|
||||
}
|
||||
ifs_mutation_weights_dealloc(&ifs_self->ifs_mut_weights);
|
||||
memcpy(&ifs_self->ifs_mut_weights, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
// handling kwds, overwriting optional params argument value
|
||||
if(mut_type_weight && mut_type_weight != Py_None)
|
||||
{
|
||||
if(pyrpn_ifs_mut_params_mut_type_weight(
|
||||
&ifs_self->ifs_mut_weights,
|
||||
mut_type_weight) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with weight_type argument");
|
||||
return NULL; // TODO check if nothing to clean
|
||||
}
|
||||
}
|
||||
if(weight_range && weight_range != Py_None)
|
||||
{
|
||||
if(pyrpn_ifs_mut_params_weight_range(
|
||||
&ifs_self->ifs_mut_weights,
|
||||
weight_range) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with mutation_weight_range argument");
|
||||
return NULL; // TODO check if nothing to clean
|
||||
}
|
||||
}
|
||||
|
||||
if(mut_if_weight && mut_if_weight != Py_None)
|
||||
{
|
||||
if(pyrpn_ifs_mut_params_weight_mut_if(&ifs_self->ifs_mut_weights,
|
||||
mut_if_weight, 0) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with if_weights parameters");
|
||||
return NULL; // TODO howto clean ?
|
||||
}
|
||||
}
|
||||
|
||||
if(if_comp_weight && if_comp_weight != Py_None)
|
||||
{
|
||||
if(pyrpn_ifs_mut_params_if_comp_weight(&ifs_self->ifs_mut_weights,
|
||||
if_comp_weight) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with if_comp_weight parameter");
|
||||
return NULL; // TODO hwoto clean ?
|
||||
}
|
||||
}
|
||||
|
||||
if(mutation_params && mutation_params != Py_None)
|
||||
{
|
||||
if(pyrpn_ifs_mut_params_mutation_params(&ifs_self->ifs_mut_weights,
|
||||
mutation_params) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with mutation_params argument");
|
||||
return NULL; // TODO howto clean ?
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the python repr of the params
|
||||
Py_DECREF(ifs_self->py_ifs_mut_weights);
|
||||
ifs_self->py_ifs_mut_weights = NULL;
|
||||
|
||||
if(pyrpn_ifs_mut_weight_to_pyobj(&ifs_self->ifs_mut_weights,
|
||||
&ifs_self->py_ifs_mut_weights) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *rpnifs_str(PyObject *self)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
|
|
13
python_ifs.h
13
python_ifs.h
|
@ -63,6 +63,11 @@ typedef struct
|
|||
rpn_if_t **rifs;
|
||||
|
||||
|
||||
PyObject *py_ifs_mut_weights;
|
||||
|
||||
ifs_mutation_weights_t ifs_mut_weights;
|
||||
|
||||
|
||||
/**@brief Python mmap.mmap instance representing rif memory map
|
||||
* @note NULL if unpickled instance */
|
||||
PyObject *mmap;
|
||||
|
@ -82,13 +87,17 @@ int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds);
|
|||
void rpnifs_del(PyObject *self);
|
||||
|
||||
|
||||
PyObject *rpnifs_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc);
|
||||
PyObject *rpnifs_from_pos(PyObject *self, PyObject* _pos);
|
||||
|
||||
PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
PyObject *rpnifs_position(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
PyObject *rpnifs_run(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
|
||||
PyObject *rpnifs_set_mutation_params(PyObject *self, PyObject *args,
|
||||
PyObject *kwargs);
|
||||
|
||||
PyObject *rpnifs_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc);
|
||||
PyObject *rpnifs_from_pos(PyObject *self, PyObject* _pos);
|
||||
|
||||
PyObject *rpnifs_str(PyObject *self);
|
||||
PyObject *rpnifs_repr(PyObject *self);
|
||||
|
||||
|
|
702
python_mutation.c
Normal file
702
python_mutation.c
Normal file
|
@ -0,0 +1,702 @@
|
|||
#include "python_mutation.h"
|
||||
|
||||
|
||||
/**@brief @ref pymod_pyrpn_RPNMutationParams field definition
|
||||
* @ingroup pymod_pyrpn_RPNMutationParams */
|
||||
static PyStructSequence_Field mutation_params_fields[] = {
|
||||
{ .name = "minimum_length",
|
||||
.doc = "Expression minimum length",
|
||||
},
|
||||
{ .name = "weight_add",
|
||||
.doc = "The weight for 'add token' mutation",
|
||||
},
|
||||
{ .name = "weight_del",
|
||||
.doc = "The weight for 'delete token' mutation",
|
||||
},
|
||||
{ .name = "weight_mut",
|
||||
.doc = "The weight for 'mutate token' mutation",
|
||||
},
|
||||
{ .name = "weight_mut_soft",
|
||||
.doc = "The weight for 'mutate soft (value not type) token' mutation",
|
||||
},
|
||||
{
|
||||
.name = "weight_add_elt",
|
||||
.doc = "The weights for each token types when adding a token",
|
||||
},
|
||||
{
|
||||
.name = "weight_del_elt",
|
||||
.doc= "The weights for each token types when deleting a token",
|
||||
},
|
||||
{ NULL, NULL},
|
||||
};
|
||||
PyStructSequence_Desc rpn_mutation_params_desc = {
|
||||
.name = "RPNMutationParams",
|
||||
.doc = "Named tuple for mutation parameters",
|
||||
.n_in_sequence = (sizeof(mutation_params_fields) / \
|
||||
sizeof(*mutation_params_fields)) - 1,
|
||||
.fields = mutation_params_fields,
|
||||
};
|
||||
PyTypeObject rpn_mutation_params_SeqDesc;
|
||||
|
||||
|
||||
static PyStructSequence_Field ifs_mutation_weights_fields[] = {
|
||||
{ .name = "weight_type",
|
||||
.doc = "Two element defining weight for random choice of \
|
||||
mutation type : (Weight_Mutation_weight, IF_Mutation_weight).",
|
||||
},
|
||||
{ .name = "mutation_weight_range",
|
||||
.doc = "Min & max values for weight modifications. A random \
|
||||
float will be choosen in [min..max] and will be randomly \
|
||||
added/substracted to a randomly choosen weight",
|
||||
},
|
||||
{ .name = "if_count",
|
||||
.doc = "Stores the number of IF in the system to mutate",
|
||||
},
|
||||
{ .name = "if_weights",
|
||||
.doc = "Indicate weights (chance) for each IF to be mutated",
|
||||
},
|
||||
{ .name = "if_component_weights",
|
||||
.doc = "Can be an array of weight, indicating the chance \
|
||||
for an IF component to be mutated. Else can be an array of array of weight, \
|
||||
allowing custom component weights for each expression.",
|
||||
},
|
||||
{ .name = "if_mut_params",
|
||||
.doc = "Stores 1 global mutation params or a list of mutation \
|
||||
params named tuple (one per IF)",
|
||||
},
|
||||
{ NULL, NULL},
|
||||
};
|
||||
|
||||
PyStructSequence_Desc ifs_mutation_weights_desc = {
|
||||
.name = "IFSMutationParams",
|
||||
.doc = "Named tuple for mutation parameters",
|
||||
.n_in_sequence = (sizeof(ifs_mutation_weights_fields) / \
|
||||
sizeof(*ifs_mutation_weights_fields)) - 1,
|
||||
.fields = ifs_mutation_weights_fields,
|
||||
};
|
||||
PyTypeObject ifs_mutation_weights_SeqDesc;
|
||||
|
||||
|
||||
int pyrpn_python_mutation_init(PyObject *pyrpn_mod)
|
||||
{
|
||||
rpn_mutation_init_params(&rpn_mutation_params_default);
|
||||
|
||||
// Named tuple for mutation parameters
|
||||
PyStructSequence_InitType(&rpn_mutation_params_SeqDesc,
|
||||
&rpn_mutation_params_desc);
|
||||
if(PyErr_Occurred()) { return -1; }
|
||||
Py_INCREF(&rpn_mutation_params_SeqDesc);
|
||||
if(PyModule_AddObject(pyrpn_mod, "RPNMutationParamsTuple",
|
||||
(PyObject*)&rpn_mutation_params_SeqDesc) < 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Named tuple for ifs mutation parameters
|
||||
PyStructSequence_InitType(&ifs_mutation_weights_SeqDesc,
|
||||
&ifs_mutation_weights_desc);
|
||||
if(PyErr_Occurred()) {
|
||||
dprintf(2, "FAILED SEQUENCE INITTYPE %d '%s'\n",
|
||||
ifs_mutation_weights_desc.n_in_sequence,
|
||||
ifs_mutation_weights_desc.fields[5].doc);
|
||||
goto err;
|
||||
}
|
||||
Py_INCREF(&ifs_mutation_weights_SeqDesc);
|
||||
if(PyModule_AddObject(pyrpn_mod, "IFSMutationParams",
|
||||
(PyObject*)&ifs_mutation_weights_SeqDesc) < 0)
|
||||
{
|
||||
goto err2;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
Py_DECREF(&ifs_mutation_weights_SeqDesc);
|
||||
err:
|
||||
Py_DECREF(&rpn_mutation_params_SeqDesc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**@brief Parse given object to float
|
||||
* @param obj The python object to parse
|
||||
* @param res Points on result
|
||||
* @note Raise python exception on error
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/** Parse weights python parameter
|
||||
* @param obj The python object
|
||||
* @param w Points on the 3 weights to parse
|
||||
* @note Raise python exception on error
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void _parse_floats(PyObject *obj, float *w, size_t len)
|
||||
{
|
||||
PyObject *fast;
|
||||
fast = PySequence_Fast(obj, "A sequence is expected");
|
||||
if(!fast || PyErr_Occurred()) { return; }
|
||||
|
||||
Py_INCREF(fast);
|
||||
if((size_t)PySequence_Length(obj) != len)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Expected %ld element but %ld given",
|
||||
len, PySequence_Length(fast));
|
||||
goto ret;
|
||||
}
|
||||
PyObject **elt = PySequence_Fast_ITEMS(fast);
|
||||
|
||||
for(size_t i=0; i<len; i++)
|
||||
{
|
||||
_parse_float(elt[i], &w[i]);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret:
|
||||
Py_DECREF(fast);
|
||||
return;
|
||||
}
|
||||
|
||||
int pyrpn_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 ?");
|
||||
if(PyErr_Occurred()) { return -1; }
|
||||
Py_INCREF(fast);
|
||||
|
||||
PyObject **elts = PySequence_Fast_ITEMS(fast);
|
||||
if(!elts || PyErr_Occurred())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
rpn_mutation_init_params(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_pyobj_to_ifs_mutation_weights(PyObject *py_params,
|
||||
ifs_mutation_weights_t *w)
|
||||
{
|
||||
bzero(w, sizeof(*w));
|
||||
if(!PySequence_Check(py_params))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"The given object is not a sequence");
|
||||
return -1;
|
||||
}
|
||||
if(PySequence_Size(py_params) != 6)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Expect a sequence of 5 elements but given sequence \
|
||||
contains %ld elements", PySequence_Size(py_params));
|
||||
return -1;
|
||||
}
|
||||
PyObject *fast = PySequence_Fast(py_params,
|
||||
"Unable to use as IFSMutationWeightsTuple");
|
||||
if(PyErr_Occurred()) { return -1; }
|
||||
Py_INCREF(fast);
|
||||
|
||||
PyObject **elts = PySequence_Fast_ITEMS(fast);
|
||||
|
||||
if(pyrpn_ifs_mut_params_mut_type_weight(w, elts[0]) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with weight_type field #0");
|
||||
return -1;
|
||||
}
|
||||
if(pyrpn_ifs_mut_params_weight_range(w, elts[1]) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with weight_type field #1");
|
||||
return -1;
|
||||
}
|
||||
w->if_count = PyLong_AsSize_t(elts[2]);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with IF count field #2");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pyrpn_ifs_mut_params_weight_mut_if(w, elts[3], 1) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with IFS IF mutation weights field #3");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pyrpn_ifs_mut_params_if_comp_weight(w, elts[4]) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with IFS IF component mutation \
|
||||
weight field #4");
|
||||
goto err_free_w_mut_if;
|
||||
}
|
||||
|
||||
if(pyrpn_ifs_mut_params_mutation_params(w, elts[5]) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(PyExc_ValueError,
|
||||
"Error with IFS RPN mutation params field #5");
|
||||
goto err_free_comp_weight;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_comp_weight:
|
||||
free(w->w_comp_if);
|
||||
w->w_comp_if = NULL;
|
||||
w->w_comp_if_sz = 0;
|
||||
err_free_w_mut_if:
|
||||
free(w->w_mut_if);
|
||||
w->w_mut_if = NULL;
|
||||
w->if_count = 0;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_mutation_params_to_pyobj(const rpn_mutation_params_t *params,
|
||||
PyObject **res)
|
||||
{
|
||||
PyObject *val;
|
||||
Py_ssize_t pos;
|
||||
|
||||
*res = PyStructSequence_New(&rpn_mutation_params_SeqDesc);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
Py_INCREF(*res);
|
||||
|
||||
pos = 0;
|
||||
val = PyLong_FromSize_t(params->min_len);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyFloat_FromDouble(params->w_add);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyFloat_FromDouble(params->w_del);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyFloat_FromDouble(params->w_mut);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyFloat_FromDouble(params->w_mut_soft);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = Py_BuildValue("(f,f,f)",
|
||||
params->w_add_elt[0],
|
||||
params->w_add_elt[1],
|
||||
params->w_add_elt[2]);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = Py_BuildValue("(f,f,f)",
|
||||
params->w_mut_elt[0],
|
||||
params->w_mut_elt[1],
|
||||
params->w_mut_elt[2]);
|
||||
if(PyErr_Occurred()) { goto err_ref; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
// add elt & del elt
|
||||
|
||||
return 0;
|
||||
err_ref:
|
||||
Py_DECREF(*res);
|
||||
err:
|
||||
*res = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_ifs_mut_weight_to_pyobj(const ifs_mutation_weights_t *w,
|
||||
PyObject **res)
|
||||
{
|
||||
PyObject *val;
|
||||
Py_ssize_t pos;
|
||||
|
||||
*res = PyStructSequence_New(&ifs_mutation_weights_SeqDesc);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
Py_INCREF(*res);
|
||||
|
||||
pos = 0;
|
||||
val = Py_BuildValue("(f, f)", w->w_mut_type[0], w->w_mut_type[1]);
|
||||
if(PyErr_Occurred()) { goto ref_err; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = Py_BuildValue("(f, f)", w->w_weight_range[0],
|
||||
w->w_weight_range[1]);
|
||||
if(PyErr_Occurred()) { goto ref_err; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyLong_FromSize_t(w->if_count);
|
||||
if(PyErr_Occurred()) { goto ref_err; }
|
||||
Py_INCREF(val);
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyTuple_New(w->if_count);
|
||||
if(PyErr_Occurred()) { goto ref_err; }
|
||||
Py_INCREF(val);
|
||||
for(size_t i=0; i<w->if_count; i++)
|
||||
{
|
||||
PyObject *elt = PyFloat_FromDouble(w->w_mut_if[i]);
|
||||
if(PyErr_Occurred()) { goto err_val; }
|
||||
Py_INCREF(elt);
|
||||
PyTuple_SET_ITEM(val, i, elt);
|
||||
}
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
val = PyTuple_New(w->w_comp_if_sz);
|
||||
if(PyErr_Occurred()) { goto ref_err; }
|
||||
Py_INCREF(val);
|
||||
for(size_t i=0; i < w->w_comp_if_sz; i++)
|
||||
{
|
||||
PyObject *elt = PyFloat_FromDouble(w->w_comp_if[i]);
|
||||
if(PyErr_Occurred()) { goto err_val; }
|
||||
Py_INCREF(elt);
|
||||
PyTuple_SET_ITEM(val, i, elt);
|
||||
}
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
pos++;
|
||||
if(!w->custom_params)
|
||||
{
|
||||
if(pyrpn_mutation_params_to_pyobj(w->if_mut_params, &val) < 0)
|
||||
{
|
||||
goto ref_err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = PyTuple_New(w->if_count);
|
||||
for(size_t i=0; i<w->if_count; i++)
|
||||
{
|
||||
PyObject *elt;
|
||||
if(pyrpn_mutation_params_to_pyobj(&(w->if_mut_params[i]),
|
||||
&elt) < 0)
|
||||
{
|
||||
goto err_val;
|
||||
}
|
||||
PyTuple_SET_ITEM(val, i, elt);
|
||||
}
|
||||
}
|
||||
PyStructSequence_SetItem(*res, pos, val);
|
||||
|
||||
return 0;
|
||||
|
||||
err_val:
|
||||
Py_DECREF(val);
|
||||
ref_err:
|
||||
Py_DECREF(*res);
|
||||
err:
|
||||
*res = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_ifs_mut_params_mut_type_weight(ifs_mutation_weights_t *w,
|
||||
PyObject *mut_type_weight)
|
||||
{
|
||||
_parse_floats(mut_type_weight, w->w_mut_type, 2);
|
||||
return PyErr_Occurred() ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_ifs_mut_params_weight_range(ifs_mutation_weights_t *w,
|
||||
PyObject *weight_range)
|
||||
{
|
||||
_parse_floats(weight_range, w->w_weight_range, 2);
|
||||
return PyErr_Occurred() ? -1 : 0;
|
||||
}
|
||||
|
||||
int pyrpn_ifs_mut_params_weight_mut_if(ifs_mutation_weights_t *w,
|
||||
PyObject *mut_if_weight, short do_realloc)
|
||||
{
|
||||
const size_t len = PySequence_Length(mut_if_weight);
|
||||
short alloc = 0;
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(len != w->if_count)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Trying to set IF mutation weight in a system \
|
||||
with %ld expression with a sequence of %ld weights", w->if_count, len);
|
||||
return -1;
|
||||
}
|
||||
if(!w->w_mut_if)
|
||||
{
|
||||
alloc = 1;
|
||||
if(!(w->w_mut_if = malloc(sizeof(*w->w_mut_if) * len)))
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Unable to allocate IFS IF mutation \
|
||||
weights for %ld expressions", len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if(do_realloc)
|
||||
{
|
||||
alloc = 1;
|
||||
void *tmp = realloc(w->w_mut_if, sizeof(*w->w_mut_if) * len);
|
||||
if(!tmp)
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Unable to reallocate IFS IF mutation \
|
||||
weights for %ld expressiosn", len);
|
||||
return -1;
|
||||
}
|
||||
w->w_mut_if = tmp;
|
||||
}
|
||||
_parse_floats(mut_if_weight, w->w_mut_if, len);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
if(alloc)
|
||||
{
|
||||
// TODO not good when realloc
|
||||
free(w->w_mut_if);
|
||||
w->if_count = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pyrpn_ifs_mut_params_if_comp_weight(ifs_mutation_weights_t *w,
|
||||
PyObject *if_comp_weight)
|
||||
{
|
||||
const size_t len = PySequence_Length(if_comp_weight);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!len)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Invalid IFS IF component mutation weights :\
|
||||
empty sequence");
|
||||
return -1;
|
||||
}
|
||||
if_mutation_weight_t *old = NULL;
|
||||
size_t old_len = w->w_comp_if_sz;
|
||||
if(len != w->w_comp_if_sz)
|
||||
{
|
||||
old = w->w_comp_if;
|
||||
if(!(w->w_comp_if = malloc(sizeof(*w->w_comp_if) * len)))
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Unable to allocate IFS IF component \
|
||||
mutation weights : %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
w->w_comp_if_sz = len;
|
||||
}
|
||||
_parse_floats(if_comp_weight, w->w_comp_if, w->w_comp_if_sz);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
if(old)
|
||||
{
|
||||
free(w->w_comp_if);
|
||||
w->w_comp_if = old;
|
||||
w->w_comp_if_sz = old_len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pyrpn_ifs_mut_params_mutation_params(ifs_mutation_weights_t *w,
|
||||
PyObject *mutation_params)
|
||||
{
|
||||
rpn_mutation_params_t tmp_params;
|
||||
// Try
|
||||
if(pyrpn_pyobj_to_mutation_params(mutation_params, &tmp_params) == 0)
|
||||
{
|
||||
// single RPNMutationParams converted
|
||||
void *tmp = realloc(w->if_mut_params,
|
||||
sizeof(*w->if_mut_params));
|
||||
if(!tmp)
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Enable to reallocate IFS RPN \
|
||||
mutation params for a single parameter");
|
||||
return -1;
|
||||
}
|
||||
w->if_mut_params = tmp;
|
||||
|
||||
w->custom_params = 0;
|
||||
memcpy(w->if_mut_params, &tmp_params, sizeof(tmp_params));
|
||||
return 0;
|
||||
}
|
||||
// Except
|
||||
// A sequence of RPNMutationParams is given
|
||||
if(PyErr_Occurred()) { PyErr_Clear(); }
|
||||
|
||||
const size_t len = (size_t)PySequence_Length(mutation_params);
|
||||
if(PyErr_Occurred()) { return -1; }
|
||||
|
||||
if(len != w->if_count && len != 1)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Invalid lenght for IFS RPN mutation \
|
||||
params sequence lenght : should be 1 or %ld or a valid RPNMutationParams, \
|
||||
but a sequence of length %ld given.", w->if_count, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *tmp = realloc(w->if_mut_params,
|
||||
sizeof(*w->if_mut_params) * len);
|
||||
if(!tmp)
|
||||
{
|
||||
PyErr_Format(PyExc_MemoryError,
|
||||
"Enable to reallocate IFS RPN \
|
||||
mutation params array : %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
w->if_mut_params = tmp;
|
||||
|
||||
PyObject *fast_params = PySequence_Fast(mutation_params,
|
||||
"IFS RPN Mutation parameters \
|
||||
should be a sequence");
|
||||
if(!fast_params) { return -1; }
|
||||
Py_INCREF(fast_params);
|
||||
|
||||
PyObject **mut_params = PySequence_Fast_ITEMS(fast_params);
|
||||
|
||||
for(size_t i=0; i < len; i++)
|
||||
{
|
||||
if(pyrpn_pyobj_to_mutation_params(mut_params[i],
|
||||
&w->if_mut_params[i]) < 0)
|
||||
{
|
||||
pyrpn_PyErr_ReraiseFormat(
|
||||
PyExc_ValueError,
|
||||
"\
|
||||
Error with IFS RPN mutation params #%ld that is not a valid RPNMutationParams");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
w->custom_params = len == 1 ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
130
python_mutation.h
Normal file
130
python_mutation.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _PYTHON_MUTATION_H__
|
||||
#define _PYTHON_MUTATION_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "python_const.h"
|
||||
#include "rpn_mutate.h"
|
||||
#include "rpn_if_mutate.h"
|
||||
#include "rpn_ifs_mutate.h"
|
||||
|
||||
/**@file python_mutation.h
|
||||
* @brief Python types (named tuple) & utility to manipulate mutation
|
||||
* parameters
|
||||
* @ingroup python_ext
|
||||
*/
|
||||
|
||||
|
||||
/**@defgroup pymod_pyrpn_RPNMutationParams pyrpn.RPNMutationParams
|
||||
* @brief namedtuple storing mutation parameters
|
||||
* @ingroup pymod_pyrpn */
|
||||
/**@brief RPNMutationParams named tuple with mutation parameters */
|
||||
extern PyTypeObject rpn_mutation_params_SeqDesc;
|
||||
/**@brief @ref rpn_mutation_params_SeqDesc named tuple description */
|
||||
extern PyStructSequence_Desc rpn_mutation_params_desc;
|
||||
|
||||
|
||||
extern PyTypeObject ifs_mutation_weights_SeqDesc;
|
||||
extern PyStructSequence_Desc ifs_mutation_weights_desc;
|
||||
|
||||
|
||||
/**@brief Initialize mutation related types & stuff. Adds references
|
||||
* to pyrpn module given in argument
|
||||
* @param pyrpn_mod pyrpn python module instance
|
||||
* @return 0 if no error else -1 */
|
||||
int pyrpn_python_mutation_init(PyObject *pyrpn_mod);
|
||||
|
||||
/**@brief Try to convert a python object into a rpn_mutation_params_t
|
||||
* @param py_params The python object
|
||||
* @param params A pointer on the parameters to initialize
|
||||
* @return -1 on failure and raise an exception
|
||||
* @ingroup pymod_pyrpn_RPNExpr
|
||||
*/
|
||||
int pyrpn_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params);
|
||||
|
||||
int pyrpn_mutation_params_to_pyobj(const rpn_mutation_params_t *params,
|
||||
PyObject **res);
|
||||
|
||||
|
||||
int pyrpn_pyobj_to_ifs_mutation_weights(PyObject *py_params,
|
||||
ifs_mutation_weights_t *w);
|
||||
|
||||
int pyrpn_ifs_mut_weight_to_pyobj(const ifs_mutation_weights_t *w,
|
||||
PyObject **mut_weights);
|
||||
|
||||
/**@brief Set the mutation type weight from a PyObject* sequence
|
||||
* @param w The IFS mutation weight structure to edit
|
||||
* @param mut_type_weight Should be a sequence of 2 float values
|
||||
* @return 0 if OK -1 on error (and PyErr_Occurred() == true)
|
||||
*/
|
||||
int pyrpn_ifs_mut_params_mut_type_weight(ifs_mutation_weights_t *w,
|
||||
PyObject *mut_type_weight);
|
||||
|
||||
/**@brief Set the mutation weight range from a PyObject* sequence
|
||||
* @param w The IFS mutation weight structure to edit
|
||||
* @param weight_range Should be a sequence of 2 float values
|
||||
* @return 0 if OK -1 on error (and PyErr_Occurred() == true)
|
||||
*/
|
||||
int pyrpn_ifs_mut_params_weight_range(ifs_mutation_weights_t *w,
|
||||
PyObject *weight_range);
|
||||
|
||||
/**@brief Set the IF mutation weight from a PyObject* sequence
|
||||
* @note Check that the sequence length correspond to the if_count
|
||||
* in the ifs_mutation_weights_t struct
|
||||
* @note If current w_mut_if field is NULL allocate it
|
||||
* @param w The IFS mutation weight structure to edit
|
||||
* @param weight_range Should be a sequence of if_count float values
|
||||
* @param do_realloc If != 0 reallocate the w_mut_if field to correspond to
|
||||
* if_count
|
||||
* @return 0 if OK -1 on error (and PyErr_Occurred() == true)
|
||||
*/
|
||||
int pyrpn_ifs_mut_params_weight_mut_if(ifs_mutation_weights_t *w,
|
||||
PyObject *mut_if_weight, short do_realloc);
|
||||
|
||||
/**@brief Set the IF component weights from a PyObject* sequence
|
||||
* @note The function cannot check the length validity of the given
|
||||
* sequence (except that empty sequence are invalid).
|
||||
* @param w The IFS mutation weight structure to edit
|
||||
* @param mut_type_weight Should be a sequence of 2 float values
|
||||
* @return 0 if OK -1 on error (and PyErr_Occurred() == true)
|
||||
*/
|
||||
int pyrpn_ifs_mut_params_if_comp_weight(ifs_mutation_weights_t *w,
|
||||
PyObject *if_comp_weight);
|
||||
|
||||
/**@brief Set the RPN mutation parameters from a PyObject*
|
||||
* @param w The IFS mutation weight structure to edit
|
||||
* @param mutation_params Can be a valid value for a RPNMutationParams
|
||||
* or a sequence of valid values for a RPNMutationParams
|
||||
* of len w->if_count
|
||||
* @return 0 if OK -1 on error (and PyErr_Occurred() == true)
|
||||
*/
|
||||
int pyrpn_ifs_mut_params_mutation_params(ifs_mutation_weights_t *w,
|
||||
PyObject *mutation_params);
|
||||
|
||||
#endif
|
||||
|
|
@ -167,19 +167,14 @@ PyInit_pyrpn(void)
|
|||
goto fail_add_token_types_tuple;
|
||||
}
|
||||
|
||||
// Named tuple for mutation parameters
|
||||
PyStructSequence_InitType(&rpn_mutation_params_SeqDesc,
|
||||
&rpn_mutation_params_desc);
|
||||
Py_INCREF(&rpn_mutation_params_SeqDesc);
|
||||
if(PyModule_AddObject(mod, "RPNMutationParamsTuple",
|
||||
(PyObject*)&rpn_mutation_params_SeqDesc) < 0)
|
||||
if(pyrpn_python_mutation_init(mod) < 0)
|
||||
{
|
||||
goto fail_add_mutation_params_tuple;
|
||||
goto fail_init_mutation;
|
||||
}
|
||||
|
||||
return mod;
|
||||
|
||||
fail_add_mutation_params_tuple:
|
||||
fail_init_mutation:
|
||||
Py_DECREF(&rpn_token_types_SeqDesc);
|
||||
fail_add_token_types_tuple:
|
||||
Py_DECREF(&rpnif_params_SeqDesc);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "python_rpnexpr.h"
|
||||
#include "python_if.h"
|
||||
#include "python_ifs.h"
|
||||
#include "python_mutation.h"
|
||||
|
||||
/**@file python_pyrpn.h
|
||||
* @brief Python module & type headers
|
||||
|
|
118
python_rpnexpr.c
118
python_rpnexpr.c
|
@ -569,7 +569,7 @@ PyObject* rpnexpr_mutate(PyObject* slf, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(rpnexpr_pyobj_to_mutation_params(py_params, ¶ms) < 0)
|
||||
if(pyrpn_pyobj_to_mutation_params(py_params, ¶ms) < 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Bad value for params arguments");
|
||||
return NULL;
|
||||
|
@ -736,119 +736,3 @@ PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssi
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**@brief Parse given object to float
|
||||
* @param obj The python object to parse
|
||||
* @param res Points on result
|
||||
* @note Raise python exception on error
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/** Parse weights python parameter
|
||||
* @param obj The python object
|
||||
* @param w Points on the 3 weights to parse
|
||||
* @note Raise python exception on error
|
||||
*/
|
||||
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;
|
||||
}
|
||||
rpn_mutation_init_params(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "rpn_jit.h"
|
||||
#include "python_rpntoken.h"
|
||||
#include "python_mutation.h"
|
||||
#include "python_const.h"
|
||||
|
||||
/**@file python_rpnexpr.h
|
||||
|
@ -247,12 +248,4 @@ PyObject* rpnexpr_random(PyObject *cls, PyObject *args, PyObject *kwds);
|
|||
*/
|
||||
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 py_params The python object
|
||||
* @param params A pointer on the parameters to initialize
|
||||
* @return -1 on failure and raise an exception
|
||||
* @ingroup pymod_pyrpn_RPNExpr
|
||||
*/
|
||||
int rpnexpr_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params);
|
||||
|
||||
#endif
|
||||
|
|
45
rpn_if_mutate.c
Normal file
45
rpn_if_mutate.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rpn_if_mutate.h"
|
||||
|
||||
|
||||
int if_mutation(rpn_if_t *rif, rnd_t *weights, size_t n_mut,
|
||||
rpn_mutation_params_t *mut_params)
|
||||
{
|
||||
for(size_t i=0; i<n_mut; i++)
|
||||
{
|
||||
size_t rpn_num;
|
||||
if(_rpn_random_choice(rif->params->rpn_sz, weights,
|
||||
&rpn_num) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(rpn_mutation(&(rif->rpn[rpn_num].toks),
|
||||
mut_params) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for(size_t i=0; i<rif->params->rpn_sz; i++)
|
||||
{
|
||||
rpn_expr_tokens_updated(&(rif->rpn[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
58
rpn_if_mutate.h
Normal file
58
rpn_if_mutate.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __rpn_if_mutate__h__
|
||||
#define __rpn_if_mutate__h__
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
#include "rpn_mutate.h"
|
||||
#include "rpn_if.h"
|
||||
|
||||
|
||||
/**@file rpn_if_mutate.h
|
||||
* @brief rpn_if_t mutation headers
|
||||
*/
|
||||
|
||||
/**@brief IF mutation weight type */
|
||||
typedef float if_mutation_weight_t;
|
||||
|
||||
/**@brief Allocate some weights for an IF
|
||||
* @param rif rpn_if_t to allocate weights for
|
||||
* @param to_alloc is a **SOMETYPE, *to_alloc will be set to the
|
||||
* weights array
|
||||
* @return NULL on error */
|
||||
#define if_mutation_alloc_weights(rif, to_alloc) (*to_alloc = \
|
||||
malloc(sizeof(**to_alloc)*rif->params->rpn_sz))
|
||||
|
||||
|
||||
/**@brief Mutate the IF given weights array
|
||||
* @param if the IF we want to mutate
|
||||
* @param weights Array of weights initialized by
|
||||
* @ref rpnifs_fast_rnd_weights()
|
||||
* @param n_mut Number of mutation to execute
|
||||
* @param mut_params Mutation parameters for IF expressions
|
||||
* @return 0 if no error else -1 and sets errno */
|
||||
int if_mutation(rpn_if_t *rif, rnd_t *weights, size_t n_mut,
|
||||
rpn_mutation_params_t *mut_params);
|
||||
|
||||
#endif
|
|
@ -71,7 +71,8 @@ struct rpn_ifs_s
|
|||
/**@brief Stores the original chance of choosing corresponding IF */
|
||||
unsigned int *weight;
|
||||
/** @brief Stores an array of 256 pointers on IF allowing fast
|
||||
* random choice.*/
|
||||
* random choice
|
||||
* @todo replace with rpnifs_random_*functions */
|
||||
rpn_if_t *if_proba[256];
|
||||
|
||||
/**@brief Stores the RPN expressions pointer of the IF contained in
|
||||
|
|
319
rpn_ifs_mutate.c
Normal file
319
rpn_ifs_mutate.c
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rpn_ifs_mutate.h"
|
||||
|
||||
int ifs_mutation_weights_alloc(ifs_mutation_weights_t *res,
|
||||
rpn_ifs_t *ifs, short custom_params, short custom_comp_if)
|
||||
{
|
||||
#if DEBUG
|
||||
if(!res || !ifs)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
res->if_count = ifs->if_sz;
|
||||
res->w_mut_if = malloc(sizeof(*res->w_mut_if)*ifs->if_sz);
|
||||
if(!res->w_mut_if) { goto err; }
|
||||
|
||||
res->_w_if = malloc(sizeof(*res->_w_if)*ifs->if_sz);
|
||||
if(!res->_w_if) { goto err_w_if; }
|
||||
|
||||
res->w_comp_if_sz = ifs->params.rpn_sz;
|
||||
if(custom_comp_if)
|
||||
{
|
||||
res->w_comp_if_sz *= ifs->if_sz;
|
||||
}
|
||||
res->w_comp_if = malloc(sizeof(*res->w_comp_if)*res->w_comp_if_sz);
|
||||
if(!res->w_comp_if)
|
||||
{
|
||||
goto err_comp_if;
|
||||
}
|
||||
res->_w_comp_if = malloc(sizeof(*res->_w_comp_if)*res->w_comp_if_sz);
|
||||
if(!res->_w_comp_if)
|
||||
{
|
||||
goto err__comp_if;
|
||||
}
|
||||
|
||||
size_t p_sz = sizeof(*res->if_mut_params);
|
||||
p_sz *= custom_params?res->if_count:1;
|
||||
res->if_mut_params = malloc(p_sz);
|
||||
if(!res->if_mut_params) { goto err_if_mut_params; }
|
||||
bzero(res->if_mut_params, p_sz);
|
||||
|
||||
return 0;
|
||||
|
||||
err_if_mut_params:
|
||||
free(res->_w_comp_if);
|
||||
err__comp_if:
|
||||
free(res->w_comp_if);
|
||||
res->w_comp_if_sz = 0;
|
||||
err_comp_if:
|
||||
free(res->_w_if);
|
||||
err_w_if:
|
||||
free(res->w_mut_if);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ifs_mutation_weights_if_count_update(ifs_mutation_weights_t *res,
|
||||
size_t new_if_count)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if(!res)
|
||||
{
|
||||
errno=EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if(new_if_count == 0)
|
||||
{
|
||||
res->if_count = 0;
|
||||
ifs_mutation_weights_dealloc(res);
|
||||
res->w_mut_if = NULL;
|
||||
res->_w_if = NULL;
|
||||
res->if_mut_params = NULL;
|
||||
return 0;
|
||||
}
|
||||
else if(new_if_count == res->if_count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ifs_mutation_weights_t tmp;
|
||||
|
||||
tmp.w_mut_if = realloc(res->w_mut_if,
|
||||
sizeof(*res->w_mut_if)*new_if_count);
|
||||
if(!tmp.w_mut_if) { goto err; }
|
||||
res->w_mut_if = tmp.w_mut_if;
|
||||
|
||||
if(res->if_count < new_if_count)
|
||||
{
|
||||
// When needed new weights are weights average
|
||||
double sum = 0.0;
|
||||
for(size_t i=0; i<res->if_count; i++) { sum += res->w_mut_if[i]; }
|
||||
sum = sum == 0.0 ? 1.0 : sum;
|
||||
for(size_t i=res->if_count; i<new_if_count; i++)
|
||||
{
|
||||
if(res->if_count != 0)
|
||||
{
|
||||
res->w_mut_if[i] = sum / res->if_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
res->w_mut_if[i] = sum / new_if_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp._w_if = realloc(res->_w_if,
|
||||
sizeof(*res->_w_if) * new_if_count);
|
||||
if(!tmp._w_if) { goto err; }
|
||||
res->_w_if = tmp._w_if;
|
||||
|
||||
if(res->custom_params)
|
||||
{
|
||||
tmp.if_mut_params = realloc(res->if_mut_params,
|
||||
sizeof(*res->if_mut_params)*new_if_count);
|
||||
if(!tmp.if_mut_params)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
res->if_mut_params = tmp.if_mut_params;
|
||||
|
||||
// mutations parameters should be allready initialized
|
||||
// and are not reinit after copy
|
||||
if(res->if_count == 0)
|
||||
{
|
||||
// adds default mutation parameters
|
||||
memcpy(res->if_mut_params,
|
||||
&rpn_mutation_params_default,
|
||||
sizeof(*res->if_mut_params));
|
||||
}
|
||||
const size_t start = res->if_count > 0 ? res->if_count : 1;
|
||||
for(size_t i=start; i<new_if_count; i++)
|
||||
{
|
||||
memcpy(&(res->if_mut_params[i]),
|
||||
&(res->if_mut_params[i-1]),
|
||||
sizeof(*res->if_mut_params));
|
||||
}
|
||||
}
|
||||
|
||||
res->if_count = new_if_count;
|
||||
|
||||
return ifs_mutation_weights_update(res);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ifs_mutation_weights_dealloc(ifs_mutation_weights_t *w)
|
||||
{
|
||||
if(w->w_mut_if) { free(w->w_mut_if); }
|
||||
if(w->_w_if) { free(w->_w_if); }
|
||||
if(w->if_mut_params) { free(w->if_mut_params); }
|
||||
}
|
||||
|
||||
int ifs_mutation_weights_update(ifs_mutation_weights_t *w)
|
||||
{
|
||||
if(w->if_count == 0) { return 0; }
|
||||
#if DEBUG
|
||||
if(w->w_mut_if == NULL)
|
||||
{ errno = EINVAL; return -1; }
|
||||
if(w->_w_if == NULL) { errno = EINVAL; return -1; }
|
||||
if(w->_w_comp_if == NULL) { errno = EINVAL; return -1; }
|
||||
#endif
|
||||
if(rpnifs_fast_rnd_weights(2, w->w_mut_type, w->_w_type) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(w->custom_params)
|
||||
{
|
||||
for(size_t i=0; i < w->if_count; i++)
|
||||
{
|
||||
if(rpn_mutation_init_params(&(w->if_mut_params[i])) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rpn_mutation_init_params(w->if_mut_params) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(rpnifs_fast_rnd_weights(w->if_count, w->w_mut_if, w->_w_if) < 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(rpnifs_fast_rnd_weights(w->w_comp_if_sz, w->w_comp_if,
|
||||
w->_w_comp_if) < 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ifs_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut)
|
||||
{
|
||||
size_t choices[2] = {0, 0};
|
||||
size_t ret;
|
||||
|
||||
for(size_t i=0; i<n_mut; i++)
|
||||
{
|
||||
if(_rpn_random_choice(2, w->_w_type, &ret) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
choices[ret]++;
|
||||
}
|
||||
if(choices[0])
|
||||
{
|
||||
if(ifs_weight_mutation(ifs, w, choices[0]) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(choices[1])
|
||||
{
|
||||
if(ifs_if_mutation(ifs, w, choices[1]) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ifs_weight_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut)
|
||||
{
|
||||
for(size_t i=0; i<n_mut; i++)
|
||||
{
|
||||
size_t ret;
|
||||
if(_rpn_random_choice(ifs->if_sz, NULL, &ret) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
float mod;
|
||||
if(rpnifs_rnd_float(w->w_weight_range, &mod) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ifs->weight[ret] += mod;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ifs_if_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut)
|
||||
{
|
||||
size_t *muts;
|
||||
|
||||
if(!(muts = malloc(sizeof(*muts)*ifs->if_sz)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
bzero(muts, sizeof(*muts)*ifs->if_sz);
|
||||
|
||||
for(size_t i=0; i<n_mut; i++)
|
||||
{
|
||||
size_t ret;
|
||||
if(_rpn_random_choice(ifs->if_sz, w->_w_if, &ret) < 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
muts[ret]++;
|
||||
}
|
||||
for(size_t i=0; i<n_mut; i++)
|
||||
{
|
||||
rnd_t *weights;
|
||||
if(w->w_comp_if_sz == ifs->if_sz)
|
||||
{
|
||||
weights = w->_w_comp_if;
|
||||
}
|
||||
else
|
||||
{
|
||||
weights = &(w->_w_comp_if[i*ifs->if_sz]);
|
||||
}
|
||||
rpn_mutation_params_t *params;
|
||||
if(w->custom_params)
|
||||
{
|
||||
params = &(w->if_mut_params[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
params = w->if_mut_params;
|
||||
}
|
||||
if(if_mutation(ifs->rpn_if[i], weights, muts[i], params) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(muts);
|
||||
return 0;
|
||||
err:
|
||||
free(muts);
|
||||
return -1;
|
||||
}
|
134
rpn_ifs_mutate.h
Normal file
134
rpn_ifs_mutate.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __rpn_ifs_mutate__h__
|
||||
#define __rpn_ifs_mutate__h__
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
#include "rpn_mutate.h"
|
||||
#include "rpn_if_mutate.h"
|
||||
#include "rpn_ifs.h"
|
||||
|
||||
|
||||
/**@file rpn_ifs_mutate.h
|
||||
* @brief rpn_ifs_t mutation headers
|
||||
* @todo implement function to mutate IF (in another file ? : yep)
|
||||
*/
|
||||
|
||||
|
||||
/**@brief IFS mutation parameters */
|
||||
typedef struct ifs_mutation_weights_s ifs_mutation_weights_t;
|
||||
|
||||
/**@brief IFS mutation parameters
|
||||
* @todo add weights for mutations of IF (weights for component mutation in IF)
|
||||
*/
|
||||
struct ifs_mutation_weights_s
|
||||
{
|
||||
/**@brief Weight for mutation type : expr, weight */
|
||||
float w_mut_type[2];
|
||||
|
||||
/**@brief internal use fast random choice for mutation type */
|
||||
rnd_t _w_type[2];
|
||||
|
||||
/**@brief Minimum & maximum weight variation (considering weights
|
||||
* in [0.0 .. 1.0] and sum(weights) == 1.0 */
|
||||
float w_weight_range[2];
|
||||
|
||||
/**@brief Number of IF in the system */
|
||||
size_t if_count;
|
||||
|
||||
/**@brief Weight for each IF (chance to mutate) */
|
||||
float *w_mut_if;
|
||||
|
||||
/**@brief internal use fast random choice for if mutation */
|
||||
rnd_t *_w_if;
|
||||
|
||||
/**@brief IF component mutation weights */
|
||||
if_mutation_weight_t *w_comp_if;
|
||||
rnd_t *_w_comp_if;
|
||||
/**@brief Can be if->rpn_sz (number of component in an IF) or
|
||||
* if_count * if->rpn_sz (one weight for each component of each IF) */
|
||||
size_t w_comp_if_sz;
|
||||
|
||||
/**@brief If 1 if_mut_params will countain if_count params else 1 */
|
||||
short custom_params;
|
||||
|
||||
/**@brief Optionnal (or NULL) array for custom parameters for
|
||||
* each IF */
|
||||
rpn_mutation_params_t *if_mut_params;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**@brief Allocate internal fields according to the number of IF in the
|
||||
* system
|
||||
* @param res The struct to allocate in
|
||||
* @param sz The number of if in the system
|
||||
* @param custom_params If 0 do not allocate
|
||||
* @ref ifs_mutation_weights_s::if_mut_params
|
||||
* @param custom_comp_if Determine the value in
|
||||
* @ref ifs_mutation_weights_s::w_comp_if_sz. If 0 allocate
|
||||
* one weight per IF component, else allocate one weight for
|
||||
* each component in each IF.
|
||||
* @return 0 if no error else -1 and sets errno */
|
||||
int ifs_mutation_weights_alloc(ifs_mutation_weights_t *res,
|
||||
rpn_ifs_t *ifs, short custom_params, short custom_comp_if);
|
||||
|
||||
/**@brief When needed reallocate internal fields to match the number of IF in
|
||||
* the system.
|
||||
* @note Weights added by reallocation will be the weights average
|
||||
* @note New if_mut_params added by reallocation will be copies of previous
|
||||
* mutation params
|
||||
* @param res The struct to reallocate in
|
||||
* @param if_count The new IF count to addapt to
|
||||
* @return 0 if no error else -1 and sets errno */
|
||||
int ifs_mutation_weights_if_count_update(ifs_mutation_weights_t *res,
|
||||
size_t new_if_count);
|
||||
|
||||
/**@brief Deallocate internal fields
|
||||
* @param res The struct to cleanup */
|
||||
void ifs_mutation_weights_dealloc(ifs_mutation_weights_t *w);
|
||||
|
||||
/**@brief Once allocate and all values set use this function to
|
||||
* update internal fast random indexes
|
||||
* @param w the ifs weights to update
|
||||
* @return 0 if no error else -1 and sets errno */
|
||||
int ifs_mutation_weights_update(ifs_mutation_weights_t *w);
|
||||
|
||||
/**@brief Use updated weights to mutate an IFS
|
||||
* @param ifs The system to mutate
|
||||
* @param w The mutation weights & parameters
|
||||
* @param n_mut The number of mutations
|
||||
* @param default_mut_params If custom
|
||||
* @ref ifs_mutation_weights_s::if_mut_params params for each IF in
|
||||
* the system not set, this argument must be not NULL and is used
|
||||
* as IF mutation parameter
|
||||
*/
|
||||
int ifs_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut);
|
||||
|
||||
int ifs_weight_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut);
|
||||
|
||||
int ifs_if_mutation(rpn_ifs_t *ifs, ifs_mutation_weights_t *w, size_t n_mut);
|
||||
|
||||
#endif
|
||||
|
158
rpn_mutate.c
158
rpn_mutate.c
|
@ -2,7 +2,7 @@
|
|||
|
||||
const rnd_t rnd_t_max = -1;
|
||||
|
||||
const rpn_mutation_params_t rpn_default_mutation = {
|
||||
rpn_mutation_params_t rpn_mutation_params_default = {
|
||||
.min_len = 3,
|
||||
.w_add = 1.25,
|
||||
.w_del = 1.0,
|
||||
|
@ -12,33 +12,13 @@ const rpn_mutation_params_t rpn_default_mutation = {
|
|||
.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++)
|
||||
float mut_weights[4] = {params->w_add, params->w_del,
|
||||
params->w_mut, params->w_mut_soft};
|
||||
if(rpnifs_fast_rnd_weights(4, mut_weights, params->_weights)<0)
|
||||
{
|
||||
params->_weights[i] += params->_weights[i-1];
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
#ifdef DEBUG
|
||||
|
@ -49,61 +29,21 @@ dprintf(2, "summed weights : %d %d %d %d\n",
|
|||
params->_weights[3]);
|
||||
#endif
|
||||
*/
|
||||
|
||||
total = 0;
|
||||
for(uint8_t i=0; i<3; i++)
|
||||
/**@todo test this */
|
||||
if(rpnifs_fast_rnd_weights(3, params->w_add_elt,
|
||||
&(params->_weights[4])) < 0)
|
||||
{
|
||||
if(params->w_add_elt[i] < 0) { goto err; }
|
||||
total += params->w_add_elt[i];
|
||||
}
|
||||
for(uint8_t i=0; i<3; i++)
|
||||
{
|
||||
rnd_t w;
|
||||
if(total > 0)
|
||||
{
|
||||
w = to_weight(total, params->w_add_elt[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
w = to_weight(3,1);
|
||||
}
|
||||
params->_weights[i+4] = w;
|
||||
if(i>0)
|
||||
{
|
||||
params->_weights[i+4] += params->_weights[i+3];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
total = 0;
|
||||
for(uint8_t i=0; i<3; i++)
|
||||
if(rpnifs_fast_rnd_weights(3, params->w_mut_elt,
|
||||
&(params->_weights[7])) < 0)
|
||||
{
|
||||
if(params->w_mut_elt[i] < 0) { goto err; }
|
||||
total += params->w_mut_elt[i];
|
||||
}
|
||||
for(uint8_t i=0; i<3; i++)
|
||||
{
|
||||
rnd_t w;
|
||||
if(total > 0)
|
||||
{
|
||||
w = to_weight(total, params->w_mut_elt[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
w = to_weight(3, 1);
|
||||
}
|
||||
params->_weights[i+7] = w;
|
||||
if(i>0)
|
||||
{
|
||||
params->_weights[i+7] += params->_weights[i+6];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#undef to_weight
|
||||
|
||||
int rpn_mutation(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
|
||||
{
|
||||
|
@ -335,11 +275,83 @@ int rpn_getrandom(rnd_t *rand)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rpnifs_fast_rnd_weights(size_t sz, const float *weights,
|
||||
rnd_t *fast_weights)
|
||||
{
|
||||
long double total = 0;
|
||||
for(size_t i=0; i<sz; i++)
|
||||
{
|
||||
if(weights[i] < 0)
|
||||
{
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
total += weights[i];
|
||||
}
|
||||
for(size_t i=0; i<sz; i++)
|
||||
{
|
||||
rnd_t w;
|
||||
if(total == 0)
|
||||
{
|
||||
w = (rnd_t)((rnd_t_max / sz)*(i+1));
|
||||
}
|
||||
else
|
||||
{
|
||||
w = ((((long double)weights[i]) * rnd_t_max)/total);
|
||||
if(i>0)
|
||||
{
|
||||
w += fast_weights[i-1];
|
||||
}
|
||||
}
|
||||
fast_weights[i] = w;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpnifs_rnd_float(float range[2], float *res)
|
||||
{
|
||||
#if DEBUG
|
||||
if(range[0] >= range[1])
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
const rnd_t mid = rnd_t_max / 2;
|
||||
rnd_t rand;
|
||||
short neg;
|
||||
|
||||
if(rpn_getrandom(&rand) < 0) { return -1; }
|
||||
if(rand >= mid)
|
||||
{
|
||||
neg = 1;
|
||||
rand -= mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
neg = 0;
|
||||
}
|
||||
*res = ((rand*(range[1]-range[0]))/mid) + range[0];
|
||||
*res *= neg?-1:1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res)
|
||||
{
|
||||
if(weights)
|
||||
{
|
||||
rnd_t rand;
|
||||
if(rpn_getrandom(&rand) < 0) { return -1; }
|
||||
__rpn_random_choice(sz, weights, rand, res);
|
||||
return 0;
|
||||
}
|
||||
// unweighted choice
|
||||
rnd_t rand;
|
||||
unsigned long long div = rnd_t_max;
|
||||
div++;
|
||||
div /= sz;
|
||||
if(rpn_getrandom(&rand) < 0) { return -1; }
|
||||
__rpn_random_choice(sz, weights, rand, res);
|
||||
*res = (rnd_t)(((unsigned long long)rand)/div);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
26
rpn_mutate.h
26
rpn_mutate.h
|
@ -31,14 +31,18 @@
|
|||
* @brief Expression mutation headers
|
||||
*/
|
||||
|
||||
/**@brief Mutation parameters */
|
||||
/**@brief RPN expression mutation parameters */
|
||||
typedef struct rpn_mutation_params_s rpn_mutation_params_t;
|
||||
/**@brief Type of random values used by mutations */
|
||||
typedef uint16_t rnd_t;
|
||||
|
||||
/**@brief maximum value for rnd_t */
|
||||
extern const rnd_t rnd_t_max;
|
||||
|
||||
/** @brief Mutation parameters */
|
||||
/**@brief Default values for mutations parameters */
|
||||
extern rpn_mutation_params_t rpn_mutation_params_default;
|
||||
|
||||
/**@brief RPN expression mutation parameters */
|
||||
struct rpn_mutation_params_s
|
||||
{
|
||||
/**@brief Minimum expression length */
|
||||
|
@ -71,6 +75,7 @@ struct rpn_mutation_params_s
|
|||
rnd_t _weights[10];
|
||||
};
|
||||
|
||||
|
||||
/**@brief Initialize mutation parameters
|
||||
*
|
||||
* pre-process integers threshold by group
|
||||
|
@ -135,11 +140,26 @@ int rpn_getrandom(rnd_t *rand);
|
|||
* @return -1 on error else 0 */
|
||||
int rpn_rand_limit(size_t max, size_t *res);
|
||||
|
||||
/**@brief Conver an array of float weights to an array for fast random
|
||||
* choices (see @ref _rpn_random_choices() )
|
||||
* @param sz The number of items in to choose from
|
||||
* @param weights Array of size sz with items weights (positive values)
|
||||
* @param fast_weights Array of size sz pointing on result
|
||||
* @return -1 on error else 0 */
|
||||
int rpnifs_fast_rnd_weights(size_t sz, const float *weights,
|
||||
rnd_t *fast_weights);
|
||||
|
||||
/**
|
||||
* @return A float between [-range[1] .. -range[0]] or [range[0] .. range[1]]
|
||||
*/
|
||||
int rpnifs_rnd_float(float range[2], float *res);
|
||||
|
||||
/**@brief Given a size return an random element with regards to given weights
|
||||
* @param sz The given size
|
||||
* @param weights Weights coming from @ref rpn_mutation_params_s._weights
|
||||
* @param res Points on result
|
||||
* @return 0 or -1 on error */
|
||||
* @return 0 or -1 on error
|
||||
* @todo refactor rename without rpn prefix */
|
||||
int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res);
|
||||
|
||||
/**@brief Given a size and a (random) value, returns an element with regards
|
||||
|
|
|
@ -288,3 +288,74 @@ class TestRPNIFSCoordinates(unittest.TestCase):
|
|||
self.assertEqual(result, pos)
|
||||
|
||||
|
||||
class TestRPNIFSMutation(unittest.TestCase):
|
||||
""" Testing mutation of IFS """
|
||||
|
||||
def test_set_params_empty(self):
|
||||
""" Testing set_mutation_params() method giving 'params' argument
|
||||
only without any existing IFS
|
||||
"""
|
||||
ifs=pyrpn.RPNIFS(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (100,100,))
|
||||
params = list(ifs.mutation_params)
|
||||
# Note : precision loss using float avoided using "exact" float values
|
||||
params[0] = (.25,.75)
|
||||
|
||||
ifs.set_mutation_params(params)
|
||||
|
||||
self.assertEqual(params, list(ifs.mutation_params))
|
||||
|
||||
def test_set_params(self):
|
||||
""" Testing set_mutation_params() method giving 'params' argument
|
||||
only without any existing IFS
|
||||
"""
|
||||
ifs=pyrpn.RPNIFS(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (100,100,))
|
||||
ifs.weights([1,3])
|
||||
|
||||
params = list(ifs.mutation_params)
|
||||
params[0] = (.25,.75)
|
||||
params[5] = tuple([params[5]] * 2)
|
||||
|
||||
ifs.set_mutation_params(params)
|
||||
self.assertEqual(params, list(ifs.mutation_params))
|
||||
|
||||
def test_set_params_kwds(self):
|
||||
""" Testing set_mutation_params() method giving keywords arguments
|
||||
"""
|
||||
|
||||
kwds = {
|
||||
'weight_type': (0, (0.25, 0.75)),
|
||||
'mutation_weight_range': (1, (.5,.75)),
|
||||
'if_weights': (3, (.125, .75)),
|
||||
'if_component_weights': (4, (.125,.25,.75,.375,1/16)),
|
||||
'if_mut_params': (5, (1,1,0,0,0,(1/16,1/32,1/64), (1/64,1/16,1/4)))
|
||||
}
|
||||
|
||||
for name, elts in kwds.items():
|
||||
idx, value = elts
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB,
|
||||
(100,100))
|
||||
ifs.weights([1,3])
|
||||
params = list(ifs.mutation_params)
|
||||
with self.subTest(arg_name=name, value=value):
|
||||
arg = {name:value}
|
||||
ifs.set_mutation_params(**arg)
|
||||
|
||||
params[idx] = value
|
||||
self.assertEqual(params, list(ifs.mutation_params))
|
||||
|
||||
|
||||
def test_set_params_override(self):
|
||||
""" Testing that params argument of set_mutation_params() is overwritten
|
||||
by keywords argument values
|
||||
"""
|
||||
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (100,100))
|
||||
ifs.weights([1,3])
|
||||
|
||||
params = list(ifs.mutation_params)
|
||||
params[0] = (.25,.75)
|
||||
wanted = (.75,.25)
|
||||
|
||||
ifs.set_mutation_params(params, weight_type=wanted)
|
||||
params[0] = wanted
|
||||
self.assertEqual(params, list(ifs.mutation_params))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue