Commit 2309f8f5 authored by Vivien Kraus's avatar Vivien Kraus
Browse files

Sample the random moves uniformly

With a barycenter between pure and random, when there are only 2
options (pass vs push, for instance), there is never any random.
parent 63060901
Pipeline #200298 failed with stages
in 32 minutes and 35 seconds
......@@ -2589,9 +2589,8 @@ Create an AI that will give random scores and cannot learn.
#+attr_texinfo: :options {TarotAi *} tarot_ai_alloc_fuzzy (double @var{fuzziness}, size_t @var{seed_size}, const void *@var{seed}, const TarotAi *@var{base})
#+begin_deftypefun
Create an AI that will play as the weighted sum of a uniform random
predictor (with a weight of /fuzziness/) and /base/ (with a weight of
1 - /fuzziness/).
Create an AI that will play perfectly with probability 1 - fuzziness,
and uniformly random with probability fuzziness.
#+end_deftypefun
#+attr_texinfo: :options {TarotAi *} tarot_ai_dup (const TarotAi *@var{ai})
......
......@@ -103,11 +103,9 @@ TarotAi *
tarot_ai_alloc_fuzzy (double fuzziness, size_t seed_size, const void *seed,
const TarotAi * base)
{
TarotAi *ai1 = tarot_ai_alloc_random (seed_size, seed);
TarotAi *ret =
tarot_ai_alloc (NULL, eval_noop, learn_noop, dup_noop, destruct_noop);
ai_construct_barycenter (ret, fuzziness, ai1, 1 - fuzziness, base);
tarot_ai_free (ai1);
ai_construct_fuzzy (ret, fuzziness, seed_size, seed, base);
return ret;
}
......
......@@ -68,9 +68,9 @@ extern "C"
static void ai_perceptron_destruct (void *state);
static void ai_construct_barycenter (TarotAi * ai, double w1,
const TarotAi * ai1, double w2,
const TarotAi * ai2);
static void ai_construct_fuzzy (TarotAi * ai, double fuzziness,
size_t seed_size, const void *seed,
const TarotAi * base);
static void ai_eval (TarotAi * ai, const TarotGame * base,
size_t n_candidates, TarotGameEvent ** candidates,
......
......@@ -153,117 +153,98 @@ ai_perceptron_destruct (void *state)
tarot_perceptron_free (perceptron);
}
struct ai_barycenter_2
struct fuzzy_state
{
double w1;
TarotAi ai1;
double w2;
TarotAi ai2;
TarotAi base;
double fuzziness;
struct yarrow256_ctx prng;
};
static inline void
ai_barycenter_2_eval (void *state, const TarotGame * base,
size_t n_candidates, TarotGameEvent ** candidates,
size_t start, size_t max, double *scores)
ai_fuzzy_eval (void *state, const TarotGame * base,
size_t n_candidates, TarotGameEvent ** candidates,
size_t start, size_t max, double *scores)
{
size_t i;
struct ai_barycenter_2 *couple = (struct ai_barycenter_2 *) state;
double *s1, *s2;
double sum_1 = 0, sum_2 = 0, ssq_1 = 0, ssq_2 = 0;
double mean_1, var_1, mean_2, var_2, n = 0;
double sd_1, sd_2;
s1 = xcalloc (max, sizeof (double));
s2 = xcalloc (max, sizeof (double));
ai_eval (&(couple->ai1), base, n_candidates, candidates, start, max, s1);
ai_eval (&(couple->ai2), base, n_candidates, candidates, start, max, s2);
for (i = 0; i < max && i + start < n_candidates; i++)
{
double val_1 = s1[i];
double val_2 = s2[i];
double sq_1 = val_1 * val_1;
double sq_2 = val_2 * val_2;
sum_1 += val_1;
sum_2 += val_2;
ssq_1 += sq_1;
ssq_2 += sq_2;
n++;
}
mean_1 = sum_1 / n;
mean_2 = sum_2 / n;
var_1 = ssq_1 / n - (mean_1 * mean_1);
var_2 = ssq_2 / n - (mean_2 * mean_2);
/* Something like -1e-16 */
if (var_1 < 0)
{
var_1 = 0;
}
if (var_2 < 0)
{
var_2 = 0;
}
sd_1 = sqrt (var_1);
sd_2 = sqrt (var_2);
/* If we get NaNs in the pure AI, the result will be NaN, and it
* should be that of the random player. */
if (sd_1 == 0)
{
sd_1 = 1;
}
if (sd_2 == 0)
{
sd_2 = 1;
struct fuzzy_state *ai = (struct fuzzy_state *) state;
double max_random = (double) ((size_t) (-1));
double flt_random;
size_t random_value;
uint8_t random_buffer[sizeof (random_value)];
ai_eval (&(ai->base), base, n_candidates, candidates, start, max, scores);
yarrow256_random (&(ai->prng), sizeof (random_buffer), random_buffer);
memcpy (&random_value, random_buffer, sizeof (random_value));
flt_random = random_value / max_random;
/* If the behavior is to play randomly, shuffle the scores. */
if (flt_random < ai->fuzziness)
{
size_t size_shuffled = 1;
size_t position = 0;
for (size_shuffled = 1;
size_shuffled < max && size_shuffled + start < n_candidates;
size_shuffled++)
{
uint8_t position_buffer[sizeof (position)];
double hold = scores[size_shuffled];
yarrow256_random (&(ai->prng), sizeof (position_buffer),
position_buffer);
memcpy (&position, position_buffer, sizeof (position));
position %= (size_shuffled + 1);
scores[size_shuffled] = scores[position];
scores[position] = hold;
}
}
for (i = 0; i < max; i++)
/* In any case, add a faint noise so that we don't always play
* hearts then clubs then diamonds etc */
for (i = 0; i < max && i + start < n_candidates; i++)
{
double s1_i = (s1[i] - mean_1) / sd_1;
double s2_i = (s2[i] - mean_2) / sd_2;
scores[i] = couple->w1 * s1_i + couple->w2 * s2_i;
double noise;
yarrow256_random (&(ai->prng), sizeof (random_buffer), random_buffer);
memcpy (&random_value, random_buffer, sizeof (random_value));
flt_random = random_value / max_random;
noise = ((flt_random - 0.5) * 2) * 1e-6;
scores[i] += noise;
}
free (s1);
free (s2);
}
static inline void
ai_barycenter_2_learn (void *state, const TarotGame * base,
const TarotGameEvent * event, double final_score)
ai_fuzzy_learn (void *state, const TarotGame * base,
const TarotGameEvent * event, double final_score)
{
struct ai_barycenter_2 *couple = (struct ai_barycenter_2 *) state;
ai_learn (&(couple->ai1), base, event, final_score);
ai_learn (&(couple->ai2), base, event, final_score);
struct fuzzy_state *ai = (struct fuzzy_state *) state;
ai_learn (&(ai->base), base, event, final_score);
}
static inline void *
ai_barycenter_2_dup (void *state)
{
struct ai_barycenter_2 *couple = (struct ai_barycenter_2 *) state;
struct ai_barycenter_2 *ret = xmalloc (sizeof (struct ai_barycenter_2));
ret->w1 = couple->w1;
ret->w2 = couple->w2;
ai_copy_fresh (&(ret->ai1), &(couple->ai1));
ai_copy_fresh (&(ret->ai2), &(couple->ai2));
ai_fuzzy_dup (void *state)
{
struct fuzzy_state *ai = (struct fuzzy_state *) state;
struct fuzzy_state *ret = xmalloc (sizeof (struct fuzzy_state));
ai_copy_fresh (&(ret->base), &(ai->base));
ret->fuzziness = ai->fuzziness;
memcpy (&(ret->prng), &(ai->prng), sizeof (struct yarrow256_ctx));
return ret;
}
static inline void
ai_barycenter_2_destruct (void *state)
ai_fuzzy_destruct (void *state)
{
struct ai_barycenter_2 *couple = (struct ai_barycenter_2 *) state;
ai_destruct (&(couple->ai1));
ai_destruct (&(couple->ai2));
free (couple);
struct fuzzy_state *ai = (struct fuzzy_state *) state;
ai_destruct (&(ai->base));
free (ai);
}
static inline void
ai_construct_barycenter (TarotAi * ai, double w1, const TarotAi * ai1,
double w2, const TarotAi * ai2)
{
struct ai_barycenter_2 *state = xmalloc (sizeof (struct ai_barycenter_2));
state->w1 = w1;
state->w2 = w2;
ai_copy_fresh (&(state->ai1), ai1);
ai_copy_fresh (&(state->ai2), ai2);
ai_construct (ai, state, ai_barycenter_2_eval, ai_barycenter_2_learn,
ai_barycenter_2_dup, ai_barycenter_2_destruct);
ai_construct_fuzzy (TarotAi * ai, double fuzziness, size_t seed_size,
const void *seed, const TarotAi * base)
{
struct fuzzy_state *state = xmalloc (sizeof (struct fuzzy_state));
ai_copy_fresh (&(state->base), base);
state->fuzziness = fuzziness;
yarrow256_init (&(state->prng), 0, NULL);
yarrow256_seed (&(state->prng), sizeof (seed), seed);
ai_construct (ai, state, ai_fuzzy_eval, ai_fuzzy_learn,
ai_fuzzy_dup, ai_fuzzy_destruct);
}
static inline void
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment