GEPA Native (SkyDiscover)
Stored-parent reflective evolution with an elite pool, rejection history, and LLM-mediated merge.
"""SkyDiscover GEPA Native epsilon-greedy / best / metric-front parent selection."""
from __future__ import annotations
from ...components.selection import SelectionPolicy
from ...records import LoopContext, Selection
from .pareto_utils import select_program_candidate_from_pareto_front
from .population import GepaNativePopulation, genome_score
class GepaNativeSelectionPolicy(SelectionPolicy):
"""Use one seeded RNG for parent selection and merge-pair selection, as upstream does."""
def __init__(
self,
seed: int = 42,
candidate_selection_strategy: str = "epsilon_greedy",
epsilon: float = 0.1,
num_inspirations: int = 4,
):
# SkyDiscover uses ``random_seed or 42``.
super().__init__(int(seed or 42))
self.candidate_selection_strategy = str(candidate_selection_strategy)
self.epsilon = float(epsilon)
self.num_inspirations = int(num_inspirations) or 4
def _parent(self, population: GepaNativePopulation):
if self.candidate_selection_strategy == "best" or not population.elite_pool:
return population.best()
if self.candidate_selection_strategy == "pareto":
if not population.program_at_metric_front or len(population.programs) < 2:
return population.best()
scores = {
program_id: genome_score(genome)
for program_id, genome in population.programs.items()
}
try:
program_id = select_program_candidate_from_pareto_front(
population.program_at_metric_front,
scores,
self.rng,
)
except AssertionError:
return population.best()
return population.programs[program_id]
if self.rng.random() < self.epsilon and len(population.elite_pool) > 1:
return population.programs[self.rng.choice(population.elite_pool)]
return population.best()
def _context(self, population: GepaNativePopulation, parent_id: str) -> list:
seen = {parent_id}
context = []
for program_id in population.elite_pool:
if program_id in seen or program_id not in population.programs:
continue
context.append(population.programs[program_id])
seen.add(program_id)
if len(context) >= self.num_inspirations:
break
for _metric, (program_id, _value) in population.metric_best.items():
if program_id in seen or program_id not in population.programs:
continue
context.append(population.programs[program_id])
seen.add(program_id)
return context[: self.num_inspirations]
def select(
self,
population: GepaNativePopulation,
ctx: LoopContext | None = None,
) -> Selection:
if not population.programs:
raise RuntimeError("cannot select from an empty population")
parent = self._parent(population)
inspirations = self._context(population, parent.id)
return Selection(
parent=parent,
inspirations=inspirations,
pool=population.all(),
details={
"selection_strategy": self.candidate_selection_strategy,
"selection_mode": self.candidate_selection_strategy,
"epsilon": self.epsilon,
"elite_pool_size": len(population.elite_pool),
"context_limit": self.num_inspirations,
},
)
def merge_candidates(self, population: GepaNativePopulation):
"""Select complementary metric leaders, then best + random top-five fallback."""
if len(population.elite_pool) < 2:
best = population.best()
return best, best
leaders: dict[str, str] = {}
for metric_name, (program_id, _score) in population.metric_best.items():
if program_id in population.programs and program_id in population.elite_pool:
leaders[metric_name] = program_id
unique_leaders = sorted(set(leaders.values()))
if len(unique_leaders) >= 2:
first, second = self.rng.sample(unique_leaders, 2)
return population.programs[first], population.programs[second]
best = population.best()
top_five = [
program_id
for program_id in population.elite_pool[:5]
if program_id != best.id
]
if top_five:
other = self.rng.choice(top_five)
return best, population.programs[other]
return best, best