feat(ga): generation summary stats (median/max/p90/entropy)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def generation_summary(fitnesses: list[float], n_bins: int = 10) -> dict[str, float]:
|
||||||
|
arr = np.asarray(fitnesses, dtype=float)
|
||||||
|
if arr.size == 0:
|
||||||
|
return {"median": 0.0, "max": 0.0, "p90": 0.0, "entropy": 0.0}
|
||||||
|
median = float(np.median(arr))
|
||||||
|
fmax = float(np.max(arr))
|
||||||
|
p90 = float(np.percentile(arr, 90))
|
||||||
|
|
||||||
|
if fmax > 0:
|
||||||
|
normalized = arr / fmax
|
||||||
|
else:
|
||||||
|
normalized = arr
|
||||||
|
|
||||||
|
hist, _ = np.histogram(normalized, bins=n_bins, range=(0.0, 1.0))
|
||||||
|
total = hist.sum()
|
||||||
|
probs = hist / total if total > 0 else hist
|
||||||
|
entropy = float(-sum(p * math.log(p) for p in probs if p > 0))
|
||||||
|
|
||||||
|
return {"median": median, "max": fmax, "p90": p90, "entropy": entropy}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from multi_swarm.ga.summary import generation_summary
|
||||||
|
|
||||||
|
|
||||||
|
def test_summary_basic_stats():
|
||||||
|
fitnesses = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
|
||||||
|
s = generation_summary(fitnesses, n_bins=5)
|
||||||
|
assert s["median"] == pytest.approx(0.45, abs=0.05)
|
||||||
|
assert s["max"] == pytest.approx(0.9)
|
||||||
|
assert 0.0 <= s["entropy"] <= math.log(5) + 0.01
|
||||||
|
|
||||||
|
|
||||||
|
def test_summary_uniform_high_entropy():
|
||||||
|
fitnesses = [0.1 * i for i in range(20)]
|
||||||
|
s_uniform = generation_summary(fitnesses, n_bins=5)
|
||||||
|
s_concentrated = generation_summary([0.5] * 20, n_bins=5)
|
||||||
|
assert s_uniform["entropy"] > s_concentrated["entropy"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_summary_p90():
|
||||||
|
fitnesses = list(range(100))
|
||||||
|
s = generation_summary([float(x) for x in fitnesses], n_bins=10)
|
||||||
|
assert 88.0 <= s["p90"] <= 91.0
|
||||||
Reference in New Issue
Block a user