add generic interface for switching selection/operator policies

This commit is contained in:
2026-02-08 22:40:53 +01:00
parent 2e4c05788d
commit e9c4cb46e6
3 changed files with 53 additions and 13 deletions
+6 -1
View File
@@ -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,
+36 -9
View File
@@ -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,
+11 -3
View File
@@ -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
)
}