draft complete. debugging
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
// raddbg 0.9.21 project file
|
||||
|
||||
recent_file: path: "inc/genetic.h"
|
||||
recent_file: path: "d:/os/obj/amd64fre/minkernel/crts/ucrt/src/appcrt/misc/mt/objfre/amd64/minkernel/crts/ucrt/src/appcrt/misc/invalid_parameter.cpp"
|
||||
recent_file: path: "src/main.cpp"
|
||||
recent_file: path: "../../../../../Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.42.34433/include/algorithm"
|
||||
recent_file: path: "../../../../../Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.42.34433/include/xutility"
|
||||
recent_file: path: "src/main.cpp"
|
||||
target:
|
||||
{
|
||||
executable: "bin/main.exe"
|
||||
|
||||
217
inc/genetic.h
217
inc/genetic.h
@@ -16,15 +16,17 @@ template <class T> struct Stats;
|
||||
template <class T> struct Strategy;
|
||||
struct CellTracker;
|
||||
|
||||
template <class T> Stats<T> run(Strategy<T>);
|
||||
template <class T> T run(Strategy<T>);
|
||||
|
||||
template <class T> struct Strategy {
|
||||
// Number of worker threads that will be evaluating cell fitness
|
||||
int num_threads;
|
||||
|
||||
float stats_print_period;
|
||||
|
||||
int batch_size; // Number of cells a worker thread tries to work on in a row
|
||||
// before accessing/locking the work queue again.
|
||||
int num_cells; // Size of the population pool
|
||||
int num_cells_per_thread; // Size of the population pool per sim thread
|
||||
int num_generations; // Number of times (epochs) to run the algorithm
|
||||
bool test_all; // Sets whether or not every cell's fitness is evaluated every
|
||||
// generation
|
||||
@@ -60,8 +62,23 @@ template <class T> struct Strategy {
|
||||
template<class T> struct Stats {
|
||||
std::vector<T> best_cell;
|
||||
std::vector<float> best_cell_fitness;
|
||||
TimeSpan setup_time;
|
||||
TimeSpan run_time;
|
||||
int gen;
|
||||
bool done;
|
||||
TimeSpan start, end;
|
||||
|
||||
TimeSpan total_crossover_time;
|
||||
int total_crossovers;
|
||||
|
||||
TimeSpan total_mutate_time;
|
||||
int total_mutates;
|
||||
|
||||
TimeSpan total_fitness_time;
|
||||
int total_evaluations;
|
||||
|
||||
TimeSpan total_sorting_time;
|
||||
int total_sorts;
|
||||
|
||||
Mutex m;
|
||||
};
|
||||
|
||||
struct CellTracker {
|
||||
@@ -83,58 +100,75 @@ template <class T> Array<T> make_array(int len) {
|
||||
};
|
||||
}
|
||||
|
||||
template <class T> Stats<T> run(Strategy<T> strat) {
|
||||
Stats<T> stats;
|
||||
template<class T>
|
||||
struct WorkerThreadArgs {
|
||||
Strategy<T> strat;
|
||||
Array<T> cells;
|
||||
Array<CellTracker> trackers;
|
||||
Stats<T> &stats;
|
||||
};
|
||||
|
||||
// ************* SETUP **************
|
||||
TimeSpan start_setup = now();
|
||||
template<class T> T* _cellp(Array<T> cells, CellTracker tracker) { return &cells[tracker.cellid]; }
|
||||
|
||||
// Create cells
|
||||
Array<T> cells = make_array<T>(strat.num_cells);
|
||||
for (int i = 0; i < cells.len; i++) cells[i] = strat.make_default_cell();
|
||||
template <class T> DWORD worker(LPVOID args) {
|
||||
// Unpack everything...
|
||||
WorkerThreadArgs<T>* worker_args = static_cast<WorkerThreadArgs<T>*>(args);
|
||||
Strategy<T> strat = worker_args->strat;
|
||||
Array<T> cells = worker_args->cells;
|
||||
Array<CellTracker> trackers = worker_args->trackers;
|
||||
Stats<T> &stats = worker_args->stats;
|
||||
|
||||
// Create cell trackers
|
||||
Array<CellTracker> trackers = make_array<CellTracker>(strat.num_cells);
|
||||
for (int i = 0; i < trackers.len; i++) trackers[i] = { .score=0, .cellid=i };
|
||||
|
||||
stats.setup_time = now() - start_setup;
|
||||
|
||||
// *********** ALGORITHM ************
|
||||
TimeSpan start_algo = now();
|
||||
for (int gen = 0; gen < strat.num_generations; gen++) {
|
||||
// 1. mutate
|
||||
for (int i = 0; i < trackers.len; i++) {
|
||||
if (abs(norm_rand(strat.rand_seed)) < strat.mutation_chance) {
|
||||
strat.mutate(cells[trackers[i].cellid]);
|
||||
}
|
||||
}
|
||||
// 2. crossover
|
||||
if (strat.enable_crossover) {
|
||||
// Prepare crossover operations as these will be the same every time except
|
||||
// for the exact cell pointers
|
||||
int npar = strat.crossover_parent_num;
|
||||
int nchild = strat.crossover_children_num;
|
||||
|
||||
int parent_end = npar;
|
||||
int child_begin = trackers.len-nchild;
|
||||
Array<T*> parents = make_array<T*>(npar);
|
||||
Array<T*> children = make_array<T*>(nchild);
|
||||
|
||||
TimeSpan start_algo = now();
|
||||
TimeSpan start;
|
||||
while(stats.gen < strat.num_generations) {
|
||||
|
||||
// 1. crossover
|
||||
start = now();
|
||||
if (strat.enable_crossover) {
|
||||
int parent_end = npar;
|
||||
int child_begin = trackers.len-nchild;
|
||||
while (parent_end <= child_begin) {
|
||||
// Get pointers to all the parent cells
|
||||
for (int i = parent_end-npar; i < parent_end; i++) {
|
||||
parents[i - (parent_end-npar)] = &cells[trackers[i].cellid];
|
||||
parents[i - (parent_end-npar)] = _cellp(cells, trackers[i]);
|
||||
}
|
||||
|
||||
// Get pointers to all the child cells (these will be overwritten)
|
||||
for (int i = child_begin; i < child_begin+nchild; i++) {
|
||||
children[i-child_begin] = &cells[trackers[i].cellid];
|
||||
children[i-child_begin] = _cellp(cells, trackers[i]);
|
||||
}
|
||||
strat.crossover(parents, children);
|
||||
parent_end += strat.crossover_parent_stride;
|
||||
child_begin -= nchild;
|
||||
}
|
||||
free(parents.data);
|
||||
free(children.data);
|
||||
}
|
||||
lock(stats.m);
|
||||
stats.total_crossover_time = stats.total_crossover_time + (now() - start);
|
||||
stats.total_crossovers++;
|
||||
unlock(stats.m);
|
||||
|
||||
|
||||
// 2. mutate
|
||||
start = now();
|
||||
for (int i = 0; i < trackers.len; i++) {
|
||||
if (abs(norm_rand(strat.rand_seed)) < strat.mutation_chance) {
|
||||
strat.mutate(cells[trackers[i].cellid]);
|
||||
}
|
||||
}
|
||||
lock(stats.m);
|
||||
stats.total_mutate_time = stats.total_mutate_time + (now() - start);
|
||||
stats.total_mutates++;
|
||||
unlock(stats.m);
|
||||
|
||||
// 3. evaluate
|
||||
start = now();
|
||||
if (strat.test_all) {
|
||||
for (int i = 0; i < trackers.len; i++) {
|
||||
trackers[i].score = strat.fitness(cells[trackers[i].cellid]);
|
||||
@@ -146,15 +180,118 @@ template <class T> Stats<T> run(Strategy<T> strat) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4. sort
|
||||
std::sort(&trackers[0], &trackers[trackers.len-1], [strat](CellTracker &a, CellTracker &b){ return strat.higher_fitness_is_better ? a.score > b.score : a.score < b.score; });
|
||||
lock(stats.m);
|
||||
stats.total_fitness_time = stats.total_fitness_time + (now() - start);
|
||||
stats.total_evaluations++;
|
||||
unlock(stats.m);
|
||||
|
||||
// 4. sort
|
||||
start = now();
|
||||
std::sort(&trackers[0], &trackers[trackers.len-1], [strat](CellTracker &a, CellTracker &b){ return strat.higher_fitness_is_better ? a.score > b.score : a.score < b.score; });
|
||||
lock(stats.m);
|
||||
stats.total_sorting_time = stats.total_sorting_time + (now() - start);
|
||||
stats.total_sorts++;
|
||||
|
||||
printf("Gen: %d, Best Score: %f\n", gen, trackers[0].score);
|
||||
stats.best_cell.push_back(cells[trackers[0].cellid]);
|
||||
stats.best_cell_fitness.push_back(trackers[0].score);
|
||||
stats.gen++;
|
||||
unlock(stats.m);
|
||||
}
|
||||
stats.run_time = now() - start_algo;
|
||||
return stats;
|
||||
stats.done = true;
|
||||
stats.end = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T> T run(Strategy<T> strat) {
|
||||
Array<Stats<T>> stats = make_array<Stats<T>>(strat.num_threads);
|
||||
Array<Thread> threads = make_array<Thread>(strat.num_threads);
|
||||
Array<T> cells = make_array<T>(strat.num_threads*strat.num_cells_per_thread);
|
||||
Array<CellTracker> trackers = make_array<CellTracker>(cells.len);
|
||||
|
||||
Array<WorkerThreadArgs<T>> args = make_array<WorkerThreadArgs<T>>(strat.num_threads);
|
||||
|
||||
for (int i = 0; i < cells.len; i++) {
|
||||
cells[i] = strat.make_default_cell();
|
||||
trackers[i] = {0, i};
|
||||
}
|
||||
|
||||
for (int i = 0; i < strat.num_threads; i++) {
|
||||
stats[i] = {
|
||||
.gen=0,
|
||||
.m=make_mutex()
|
||||
};
|
||||
Array<T> tcells = { &cells[i*strat.num_cells_per_thread], strat.num_cells_per_thread };
|
||||
Array<CellTracker> ttrackers = { &trackers[i*strat.num_cells_per_thread], strat.num_cells_per_thread };
|
||||
|
||||
args[i].strat=strat;
|
||||
args[i].cells=tcells;
|
||||
args[i].trackers=ttrackers;
|
||||
args[i].stats=stats[i];
|
||||
|
||||
threads[i] = make_thread(worker<T>, &args[i]);
|
||||
}
|
||||
|
||||
// We are the stats thread
|
||||
bool complete = false;
|
||||
while (!complete) {
|
||||
sleep(from_s(strat.stats_print_period));
|
||||
|
||||
printf("**********************\n");
|
||||
float g_avg_crossover_time = 0;
|
||||
float g_avg_mutate_time = 0;
|
||||
float g_avg_fitness_time = 0;
|
||||
float g_avg_sorting_time = 0;
|
||||
float g_progress_per = 0;
|
||||
|
||||
complete = true;
|
||||
|
||||
for (int i = 0; i < stats.len; i++) {
|
||||
lock(stats[i].m);
|
||||
complete &= stats[i].done;
|
||||
|
||||
float avg_crossover_time = to_s(stats[i].total_crossover_time) / static_cast<float>(stats[i].total_crossovers);
|
||||
|
||||
float avg_mutate_time = to_s(stats[i].total_mutate_time) / static_cast<float>(stats[i].total_mutates);
|
||||
|
||||
float avg_fitness_time = to_s(stats[i].total_fitness_time) / static_cast<float>(stats[i].total_evaluations);
|
||||
|
||||
float avg_sorting_time = to_s(stats[i].total_sorting_time) / static_cast<float>(stats[i].total_sorts);
|
||||
|
||||
float progress_per = static_cast<float>(stats[i].gen) / static_cast<float>(strat.num_generations) * 100;
|
||||
|
||||
g_avg_crossover_time += avg_crossover_time;
|
||||
g_avg_mutate_time += avg_mutate_time;
|
||||
g_avg_fitness_time += avg_fitness_time;
|
||||
g_avg_sorting_time += avg_sorting_time;
|
||||
g_progress_per += progress_per;
|
||||
|
||||
printf("THREAD %d, Progress %.1f%, Average Crossover Time/Cell %.5f (s), Average Mutate Time/Cell: %.5f (s), Average Fitness Time/Cell: %.5f (s), Average Sorting Time: %.5f (s)\n", i, progress_per, avg_crossover_time, avg_mutate_time, avg_fitness_time, avg_sorting_time);
|
||||
unlock(stats[i].m);
|
||||
}
|
||||
|
||||
g_avg_crossover_time /= stats.len;
|
||||
g_avg_mutate_time /= stats.len;
|
||||
g_avg_fitness_time /= stats.len;
|
||||
g_avg_sorting_time /= stats.len;
|
||||
g_progress_per /= stats.len;
|
||||
|
||||
printf("OVERALL, Progress %.1f%, Average Crossover Time/Cell %.5f (s), Average Mutate Time/Cell: %.5f (s), Average Fitness Time/Cell: %.5f (s), Average Sorting Time: %.5f (s)\n", g_progress_per, g_avg_crossover_time, g_avg_mutate_time, g_avg_fitness_time, g_avg_sorting_time);
|
||||
|
||||
if (complete) break;
|
||||
}
|
||||
|
||||
T best_cell;
|
||||
// TODO: bad
|
||||
float best_score = strat.higher_fitness_is_better ? 999999999999999999.9 : 0.0;
|
||||
for (int i = 0; i < stats.len; i++) {
|
||||
float score = stats[i].best_cell_fitness.back();
|
||||
if (strat.higher_fitness_is_better ? score > best_score : score < best_score) {
|
||||
best_cell = stats[i].best_cell.back();
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
|
||||
return best_cell;
|
||||
}
|
||||
|
||||
} // namespace genetic
|
||||
|
||||
62
inc/sync.h
62
inc/sync.h
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace sync {
|
||||
@@ -28,6 +28,7 @@ static LARGE_INTEGER freq = _init_freq();
|
||||
|
||||
Thread make_thread(ThreadFunc t, ThreadArg a);
|
||||
void join(Thread t);
|
||||
void sleep(TimeSpan ts);
|
||||
|
||||
Mutex make_mutex();
|
||||
void lock(Mutex &m);
|
||||
@@ -52,11 +53,14 @@ TimeSpan from_min(double minutes);
|
||||
TimeSpan from_hours(double hours);
|
||||
TimeSpan now();
|
||||
TimeSpan operator-(const TimeSpan &a, const TimeSpan &b);
|
||||
TimeSpan operator+(const TimeSpan &a, const TimeSpan &b);
|
||||
TimeSpan operator*(const TimeSpan &a, const TimeSpan &b);
|
||||
TimeSpan operator/(const TimeSpan &a, const TimeSpan &b);
|
||||
|
||||
double to_ms(TimeSpan &sp);
|
||||
double to_s(TimeSpan &sp);
|
||||
double to_min(TimeSpan &sp);
|
||||
double to_hours(TimeSpan &sp);
|
||||
double to_ms(TimeSpan &ts);
|
||||
double to_s(TimeSpan &ts);
|
||||
double to_min(TimeSpan &ts);
|
||||
double to_hours(TimeSpan &ts);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -69,6 +73,10 @@ void join(Thread t) {
|
||||
WaitForSingleObject(t, INFINITE);
|
||||
}
|
||||
|
||||
void sleep(TimeSpan ts) {
|
||||
Sleep(static_cast<DWORD>(to_ms(ts)));
|
||||
}
|
||||
|
||||
Mutex make_mutex() {
|
||||
Mutex m;
|
||||
InitializeCriticalSection(&m);
|
||||
@@ -135,25 +143,25 @@ void dispose(Semaphore &s) {
|
||||
|
||||
TimeSpan from_ms(double milliseconds) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = static_cast<int64_t>(milliseconds/1000.0)*freq.QuadPart;
|
||||
ts.QuadPart = static_cast<LONGLONG>(milliseconds/1000.0)*freq.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
TimeSpan from_s(double seconds) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = static_cast<int64_t>(seconds)*freq.QuadPart;
|
||||
ts.QuadPart = static_cast<LONGLONG>(seconds)*freq.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
TimeSpan from_min(double minutes) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = static_cast<int64_t>(minutes*60.0)*freq.QuadPart;
|
||||
ts.QuadPart = static_cast<LONGLONG>(minutes*60.0)*freq.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
TimeSpan from_hours(double hours) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = static_cast<int64_t>(hours*60.0*60.0)*freq.QuadPart;
|
||||
ts.QuadPart = static_cast<LONGLONG>(hours*60.0*60.0)*freq.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
@@ -163,26 +171,44 @@ TimeSpan now() {
|
||||
return ts;
|
||||
}
|
||||
|
||||
TimeSpan operator-(const TimeSpan &a, TimeSpan &b) {
|
||||
TimeSpan operator-(const TimeSpan &a, const TimeSpan &b) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = a.QuadPart - b.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
double to_ms(TimeSpan &sp) {
|
||||
return static_cast<double>(sp.QuadPart*1000)/static_cast<double>(freq.QuadPart);
|
||||
TimeSpan operator+(const TimeSpan &a, const TimeSpan &b) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = a.QuadPart + b.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
double to_s(TimeSpan &sp) {
|
||||
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart);
|
||||
TimeSpan operator*(const TimeSpan &a, const TimeSpan &b) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = a.QuadPart * b.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
double to_min(TimeSpan &sp) {
|
||||
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart*60);
|
||||
TimeSpan operator/(const TimeSpan &a, const TimeSpan &b) {
|
||||
TimeSpan ts;
|
||||
ts.QuadPart = a.QuadPart / b.QuadPart;
|
||||
return ts;
|
||||
}
|
||||
|
||||
double to_hours(TimeSpan &sp) {
|
||||
return static_cast<double>(sp.QuadPart)/static_cast<double>(freq.QuadPart*60*60);
|
||||
double to_ms(TimeSpan &ts) {
|
||||
return static_cast<double>(ts.QuadPart*1000)/static_cast<double>(freq.QuadPart);
|
||||
}
|
||||
|
||||
double to_s(TimeSpan &ts) {
|
||||
return static_cast<double>(ts.QuadPart)/static_cast<double>(freq.QuadPart);
|
||||
}
|
||||
|
||||
double to_min(TimeSpan &ts) {
|
||||
return static_cast<double>(ts.QuadPart)/static_cast<double>(freq.QuadPart*60);
|
||||
}
|
||||
|
||||
double to_hours(TimeSpan &ts) {
|
||||
return static_cast<double>(ts.QuadPart)/static_cast<double>(freq.QuadPart*60*60);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
11
src/main.cpp
11
src/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
|
||||
Strategy<Array<float>> strat {
|
||||
.num_threads = 1,
|
||||
.batch_size = 1,
|
||||
.num_cells = 100000,
|
||||
.num_cells_per_thread = 100000,
|
||||
.num_generations = num_gens,
|
||||
.test_all = true,
|
||||
.test_chance = 0.0, // doesn't matter
|
||||
@@ -76,13 +76,13 @@ int main(int argc, char **argv) {
|
||||
.fitness=fitness
|
||||
};
|
||||
|
||||
auto res = run(strat);
|
||||
auto best_cell = run(strat);
|
||||
|
||||
float sum = 0;
|
||||
float product = 1;
|
||||
printf("Winning cell: ");
|
||||
for (int i = 0; i < res.best_cell.back().len; i++) {
|
||||
float val = res.best_cell.back()[i];
|
||||
for (int i = 0; i < best_cell.len; i++) {
|
||||
float val = best_cell[i];
|
||||
sum += val;
|
||||
product *= val;
|
||||
printf("%f ", val);
|
||||
@@ -90,7 +90,4 @@ int main(int argc, char **argv) {
|
||||
printf("\n");
|
||||
printf("Final Sum: %f\n", sum);
|
||||
printf("Final Product: %f\n", product);
|
||||
printf("Setup Time (s): %f\n", sync::to_s(res.setup_time));
|
||||
printf("Run Time (s): %f\n", sync::to_s(res.run_time));
|
||||
printf("Average Gen Time (s): %f\n", sync::to_s(res.run_time)/num_gens);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user