add entropy readings and plot
This commit is contained in:
@@ -23,5 +23,5 @@ Problem :: struct {
|
||||
}
|
||||
|
||||
Stats :: struct {
|
||||
best, mean, worst: f64,
|
||||
best, mean, worst, entropy: f64,
|
||||
}
|
||||
|
||||
44
src/ga.odin
44
src/ga.odin
@@ -26,22 +26,21 @@ run_ga :: proc(problem: Problem, survivor_selection: Survivor_Selection) {
|
||||
|
||||
for gen in 0 ..< GENERATIONS {
|
||||
pop_fitnesses := evaluate_population(&population, problem.fitness_proc)
|
||||
stats := compute_stats(pop_fitnesses[:], problem.maximize)
|
||||
stats := compute_stats(&population, pop_fitnesses[:], problem.chromosome_size, problem.maximize)
|
||||
append(&generation_stats, stats)
|
||||
|
||||
fmt.printfln(
|
||||
"Gen %d: Best=%.4f Mean=%.4f Worst=%.4f",
|
||||
"Gen %d: Best=%.4f Mean=%.4f Worst=%.4f Entropy=%.4f",
|
||||
gen,
|
||||
stats.best,
|
||||
stats.mean,
|
||||
stats.worst,
|
||||
stats.entropy,
|
||||
)
|
||||
|
||||
// Create offspring (no selection decisions here)
|
||||
offspring := create_offspring_simple(&population)
|
||||
offspring_fitnesses := evaluate_population(&offspring, problem.fitness_proc)
|
||||
|
||||
// Survivor selection decides who lives
|
||||
next_gen := survivor_selection(
|
||||
&population,
|
||||
&offspring,
|
||||
@@ -86,7 +85,35 @@ evaluate_population :: proc(
|
||||
return fitnesses
|
||||
}
|
||||
|
||||
compute_stats :: proc(fitnesses: []f64, maximize: bool) -> Stats {
|
||||
compute_population_entropy :: proc(pop: ^Population, chromosome_size: int) -> f64 {
|
||||
bit_counts := make([]int, chromosome_size, context.temp_allocator)
|
||||
defer delete(bit_counts, context.temp_allocator)
|
||||
|
||||
// Count 1s at each bit position
|
||||
for i in 0 ..< POPULATION_SIZE {
|
||||
for j in 0 ..< chromosome_size {
|
||||
if bit_array.get(pop[i], j) {
|
||||
bit_counts[j] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate entropy: H = -Σ p_i * log2(p_i)
|
||||
entropy: f64 = 0.0
|
||||
for count in bit_counts {
|
||||
if count == 0 || count == POPULATION_SIZE {
|
||||
continue // Skip if all 0s or all 1s (log(0) undefined)
|
||||
}
|
||||
|
||||
p := f64(count) / f64(POPULATION_SIZE)
|
||||
entropy -= p * math.log2(p)
|
||||
}
|
||||
|
||||
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
|
||||
sum := 0.0
|
||||
@@ -102,7 +129,9 @@ compute_stats :: proc(fitnesses: []f64, maximize: bool) -> Stats {
|
||||
sum += f
|
||||
}
|
||||
|
||||
return {best, sum / f64(len(fitnesses)), worst}
|
||||
entropy := compute_population_entropy(pop, chromosome_size)
|
||||
|
||||
return {best, sum / f64(len(fitnesses)), worst, entropy}
|
||||
}
|
||||
|
||||
tournament_selection :: proc(pop: ^Population, fitnesses: []f64, maximize: bool) -> Chromosome {
|
||||
@@ -360,7 +389,7 @@ write_results :: proc(filename: string, stats: []Stats) -> bool {
|
||||
w: csv.Writer
|
||||
csv.writer_init(&w, os.stream_from_handle(handle))
|
||||
|
||||
csv.write(&w, []string{"Generation", "Best", "Mean", "Worst"})
|
||||
csv.write(&w, []string{"Generation", "Best", "Mean", "Worst", "Entropy"})
|
||||
|
||||
for stat, gen in stats {
|
||||
csv.write(
|
||||
@@ -370,6 +399,7 @@ write_results :: proc(filename: string, stats: []Stats) -> bool {
|
||||
fmt.tprintf("%.6f", stat.best),
|
||||
fmt.tprintf("%.6f", stat.mean),
|
||||
fmt.tprintf("%.6f", stat.worst),
|
||||
fmt.tprintf("%.6f", stat.entropy),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
↥0⋕↘1°csv
|
||||
≡°⊂
|
||||
°⍉≡⊟
|
||||
⍜°⊟₃∩₃Line
|
||||
⍜°⊟₃∩₃Line °⊂⌟
|
||||
°⊸≡°◇°Data~Label {"best" "mean" "worst"}
|
||||
Plot!(
|
||||
°⊸XLabel "generations"
|
||||
)
|
||||
&fwa"output/plot.png"img"png"
|
||||
|
||||
°⊸Data~Label "entropy" Line
|
||||
Plot!(°⊸XLabel "generations")
|
||||
&fwa"output/entropy.png"img"png"
|
||||
|
||||
Reference in New Issue
Block a user