From e9c4cb46e6d6a984b1238a3a0f0cb551b4db5a5b Mon Sep 17 00:00:00 2001 From: Fredrik Robertsen Date: Sun, 8 Feb 2026 22:40:53 +0100 Subject: [PATCH] add generic interface for switching selection/operator policies --- src/common.odin | 7 ++++++- src/ga.odin | 45 ++++++++++++++++++++++++++++++++++++--------- src/main.odin | 14 +++++++++++--- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/common.odin b/src/common.odin index f59dccd..b9e74f8 100644 --- a/src/common.odin +++ b/src/common.odin @@ -12,9 +12,14 @@ SKEW :: 0 TOURNAMENT_SIZE :: 5 CROSSOVER_RATE :: 0.7 MUTATION_RATE :: 0.01 + +SURVIVOR_SELECTION_POLICY :: probabilistic_crowding +PARENT_SELECTION_POLICY :: roulette_selection +CROSSOVER_POLICY :: uniform_crossover +MUTATION_POLICY :: bit_flip_mutation + RANDOM_SEED :: u64(42) OUTPUT_FILE :: "output/data.csv" -SURVIVOR_SELECTION_POLICY :: probabilistic_crowding Problem :: struct { name: string, diff --git a/src/ga.odin b/src/ga.odin index bd132bb..84d2253 100644 --- a/src/ga.odin +++ b/src/ga.odin @@ -15,7 +15,17 @@ Survivor_Selection :: proc( maximize: bool, ) -> Population -run_ga :: proc(problem: Problem, survivor_selection: Survivor_Selection) { +Parent_Selection :: proc(pop: ^Population, fitnesses: []f64, maximize: bool) -> Chromosome +Crossover :: proc(parent1, parent2: Chromosome) -> (Chromosome, Chromosome) +Mutation :: proc(chromosome: Chromosome) + +run_ga :: proc( + problem: Problem, + survivor_selection: Survivor_Selection, + parent_selection: Parent_Selection, + crossover: Crossover, + mutation: Mutation, +) { fmt.printfln("=== Running GA: %s ===", problem.name) population := generate_population(problem.chromosome_size) @@ -38,7 +48,14 @@ run_ga :: proc(problem: Problem, survivor_selection: Survivor_Selection) { stats.entropy, ) - offspring := create_offspring_simple(&population) + offspring := create_offspring( + &population, + pop_fitnesses[:], + problem.maximize, + parent_selection, + crossover, + mutation, + ) offspring_fitnesses := evaluate_population(&offspring, problem.fitness_proc) next_gen := survivor_selection( @@ -112,7 +129,6 @@ compute_population_entropy :: proc(pop: ^Population, chromosome_size: int) -> f6 return entropy } -// Modified compute_stats to include entropy compute_stats :: proc(pop: ^Population, fitnesses: []f64, chromosome_size: int, maximize: bool) -> Stats { best := maximize ? -math.F64_MAX : math.F64_MAX worst := maximize ? math.F64_MAX : -math.F64_MAX @@ -251,16 +267,23 @@ clone_chromosome :: proc(chrom: Chromosome) -> Chromosome { return clone } -create_offspring_simple :: proc(pop: ^Population) -> Population { +create_offspring :: proc( + pop: ^Population, + fitnesses: []f64, + maximize: bool, + parent_selection: Parent_Selection, + crossover: Crossover, + mutation: Mutation, +) -> Population { offspring: Population for i := 0; i < POPULATION_SIZE; i += 2 { - p1_idx := rand.int_max(POPULATION_SIZE) - p2_idx := rand.int_max(POPULATION_SIZE) + parent1 := parent_selection(pop, fitnesses, maximize) + parent2 := parent_selection(pop, fitnesses, maximize) - child1, child2 := uniform_crossover(pop[p1_idx], pop[p2_idx]) - bit_flip_mutation(child1) - bit_flip_mutation(child2) + child1, child2 := crossover(parent1, parent2) + mutation(child1) + mutation(child2) offspring[i] = child1 if i + 1 < POPULATION_SIZE { @@ -273,6 +296,10 @@ create_offspring_simple :: proc(pop: ^Population) -> Population { return offspring } +random_selection :: proc(pop: ^Population, fitnesses: []f64, maximize: bool) -> Chromosome { + return pop[rand.int_max(POPULATION_SIZE)] +} + deterministic_crowding :: proc( pop: ^Population, offspring: ^Population, diff --git a/src/main.odin b/src/main.odin index fcd859c..3fbb1c7 100644 --- a/src/main.odin +++ b/src/main.odin @@ -7,8 +7,10 @@ import "base:runtime" main :: proc() { problem_type := "feature_selection" - // state := rand.create(RANDOM_SEED) - // context.random_generator = runtime.default_random_generator(&state) + when RANDOM_SEED != u64(0){ + state := rand.create(RANDOM_SEED) + context.random_generator = runtime.default_random_generator(&state) + } problem: Problem switch problem_type { @@ -33,5 +35,11 @@ main :: proc() { fmt.printfln("RMSE: %.4f\n", baseline) } - run_ga(problem, SURVIVOR_SELECTION_POLICY) + run_ga( + problem, + SURVIVOR_SELECTION_POLICY, + PARENT_SELECTION_POLICY, + CROSSOVER_POLICY, + MUTATION_POLICY + ) }