rpnifs/rpn_mutate.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), &params->_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]);
}