From 3265f045d1bbbd6b50f474cd1bdb983433001af9 Mon Sep 17 00:00:00 2001 From: Seth Hamilton Date: Sat, 16 Aug 2025 00:41:28 -0500 Subject: [PATCH] add in xorshift rand function. begin reworking job queue to use cell entry pointers instead of just cells so results can be posted directly to the relevant entry --- inc/genetic.h | 14 +++++--------- inc/rand.h | 18 ++++++++++++++++++ src/genetic.cpp | 47 +++++++++++++++++++++++++++++------------------ 3 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 inc/rand.h diff --git a/inc/genetic.h b/inc/genetic.h index 62def79..9a32d83 100644 --- a/inc/genetic.h +++ b/inc/genetic.h @@ -30,12 +30,15 @@ template struct Strategy { bool enable_mutation; // Cells may be mutated // before fitness evaluation float mutation_chance; // Chance to mutate cells before fitness evaluation + uint64_t rand_seed; + bool higher_fitness_is_better; // Sets whether or not to consider higher + // fitness values better or worse. Set this to + // false if fitness is an error function. // User defined functions T (*make_default_cell)(); void (*mutate)(T &cell_to_modify); - void (*crossover)(const ReadonlySpan &parents, - const Span &out_children); + void (*crossover)(const Span parents, const Span out_children); float (*fitness)(const T &cell); }; @@ -44,13 +47,6 @@ template struct Stats { std::vector average_fitness; }; -template struct ReadonlySpan { - T *_data; - int len; - - const T &operator[](int i); -}; - template struct Span { T *_data; int len; diff --git a/inc/rand.h b/inc/rand.h new file mode 100644 index 0000000..fe8c621 --- /dev/null +++ b/inc/rand.h @@ -0,0 +1,18 @@ +// TODO: This file needs a serious audit + +#include + +constexpr uint64_t half_max = UINT64_MAX / 2; + +// From https://en.wikipedia.org/wiki/Xorshift +inline void xorshift64(uint64_t &state) { + state ^= state << 13; + state ^= state >> 7; + state ^= state << 17; +} + +// returns a random value between -1 and 1. modifies seed +inline float norm_rand(uint64_t &state) { + xorshift64(state); + return (state - half_max) / half_max; +} diff --git a/src/genetic.cpp b/src/genetic.cpp index d5778b9..ab923a4 100644 --- a/src/genetic.cpp +++ b/src/genetic.cpp @@ -21,17 +21,17 @@ namespace genetic { template struct CellEntry { float score; - T cell; + T *cell; + bool stale; }; template struct CrossoverJob { - const ReadonlySpan &parents; - const Span &children_out; + Span *> &parents; + Span *> &children_out; }; template struct FitnessJob { - const T &cell; - float &result_out; + CellEntry *cell_entry; }; template struct WorkQueue { @@ -100,6 +100,8 @@ template struct WorkerThreadArgs { bool *stop_flag; }; +template void do_crossover_job(CrossoverJob cj) {} + template void *worker(void *args) { WorkerThreadArgs *work_args = (WorkerThreadArgs *)args; Strategy &strat = work_args->strat; @@ -107,7 +109,10 @@ template void *worker(void *args) { bool *stop_flag = work_args->stop_flag; auto JobDispatcher = overload{ - [strat](FitnessJob fj) { fj.result_out = strat.fitness(fj.cell); }, + [strat](FitnessJob fj) { + fj.cell_entry->result_out = strat.fitness(*(fj.cell_entry->cell)); + fj.cell_entry->stale = true; + }, [strat](CrossoverJob cj) { strat.crossover(cj.parents, cj.children_out); }, @@ -131,21 +136,20 @@ template void *worker(void *args) { template Stats run(Strategy strat) { Stats stats; - WorkQueue queue = make_work_queue(strat.num_cells); + WorkQueue work_queue = make_work_queue(strat.num_cells); - vector> cells_a, cells_b; + T cells[strat.num_cells]; + + // Using a vector so I can use the make_heap, push_heap, etc. + vector> cell_queue; for (int i = 0; i < strat.num_cells; i++) { - T cell = strat.make_default_cell(); - cells_a.push_back({0, cell, true}); - cells_b.push_back({0, cell, true}); + cells[i] = strat.make_default_cell(); + cell_queue.push_back({0, &cells[i], true}); } - std::vector> &cur_cells = cells_a; - std::vector> &next_cells = cells_b; - bool stop_flag = false; WorkerThreadArgs args = { - .strat = strat, .queue = queue, .stop_flag = &stop_flag}; + .strat = strat, .queue = work_queue, .stop_flag = &stop_flag}; // spawn worker threads pthread_t threads[strat.num_threads]; @@ -155,20 +159,27 @@ template Stats run(Strategy strat) { for (int i = 0; i < strat.num_generations; i++) { // generate fitness jobs + if (strat.test_all) { + + } else { + } + // wait for fitness jobs to complete // sort cells on performance // generate crossover jobs - cur_cells = cur_cells == cells_a ? cells_b : cells_a; - next_cells = cur_cells == cells_a ? cells_b : cells_a; } // stop worker threads stop_flag = true; - pthread_cond_broadcast(queue.jobs_available_cond); + pthread_cond_broadcast(work_queue.jobs_available_cond); for (int i = 0; i < strat.num_threads; i++) { pthread_join(threads[i], NULL); } +} +template T &Span::operator[](int i) { + assert(i >= 0 && i < len); + return _data[i]; } } // namespace genetic