372 lines
7.2 KiB
C
372 lines
7.2 KiB
C
#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)
|
|
{
|
|
//_print_params(2, 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(toks->tokens_sz == 0)
|
|
{
|
|
position = 0;
|
|
}
|
|
else if(rpn_rand_limit(toks->tokens_sz, &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<sz; (*res)++)
|
|
{
|
|
if(weights[*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<max; (*res)++)
|
|
{
|
|
if(*res * step >= rnd)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
//*res = max - 1;
|
|
return 0;
|
|
}
|
|
|
|
void _print_params(int fd, rpn_mutation_params_t *params)
|
|
{
|
|
dprintf(fd, "Minlen = %ld w[add=%.2f del=%.2f mut=%.2f msf=%.2f]\n",
|
|
params->min_len, params->w_add, params->w_del,
|
|
params->w_mut, params->w_mut_soft);
|
|
dprintf(fd, "w_add_elt [op=%.2f const=%.2f var=%.2f]\n",
|
|
params->w_add_elt[0], params->w_add_elt[1],
|
|
params->w_add_elt[2]);
|
|
dprintf(fd, "w_mut_elt [op=%.2f const=%.2f var=%.2f]\n",
|
|
params->w_mut_elt[0], params->w_mut_elt[1],
|
|
params->w_mut_elt[2]);
|
|
}
|
|
|