From e0f66688c432fe70325adff96498ddb1f849c03b Mon Sep 17 00:00:00 2001 From: ZY Liu <236001964+liuzhengyang699@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:21:04 +0800 Subject: [PATCH] fix: fill available inspiration slots in small islands --- openevolve/database.py | 5 ++-- tests/test_small_island_inspirations.py | 40 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/test_small_island_inspirations.py diff --git a/openevolve/database.py b/openevolve/database.py index 0f487c0ec..049899206 100644 --- a/openevolve/database.py +++ b/openevolve/database.py @@ -30,7 +30,7 @@ ProgramState, ) from openevolve.utils.code_utils import calculate_edit_distance -from openevolve.utils.metrics_utils import safe_numeric_average, get_fitness_score +from openevolve.utils.metrics_utils import get_fitness_score, safe_numeric_average logger = logging.getLogger(__name__) @@ -1136,6 +1136,7 @@ def _llm_judge_novelty(self, program: Program, similar_program: Program) -> bool Use LLM to judge if a program is novel compared to a similar existing program """ import asyncio + from openevolve.novelty_judge import NOVELTY_SYSTEM_MSG, NOVELTY_USER_MSG user_msg = NOVELTY_USER_MSG.format( @@ -1791,7 +1792,7 @@ def _sample_inspirations( inspirations.append(program) # Add diverse programs from within the island - if len(island_programs) > n and len(inspirations) < n: + if len(inspirations) < n: remaining_slots = n - len(inspirations) # Try to sample from different feature cells within the island diff --git a/tests/test_small_island_inspirations.py b/tests/test_small_island_inspirations.py new file mode 100644 index 000000000..1bf2c0ee0 --- /dev/null +++ b/tests/test_small_island_inspirations.py @@ -0,0 +1,40 @@ +"""Small islands should still contribute their available inspiration programs.""" + +import unittest + +from openevolve.config import DatabaseConfig +from openevolve.database import Program, ProgramDatabase + + +class TestSmallIslandInspirations(unittest.TestCase): + def setUp(self): + self.db = ProgramDatabase( + DatabaseConfig(in_memory=True, num_islands=2, elite_selection_ratio=0.2) + ) + self.parent = Program(id="parent", code="parent", metrics={"score": 1.0}) + self.best = Program(id="best", code="best", metrics={"score": 3.0}) + self.other = Program(id="other", code="other", metrics={"score": 2.0}) + outsider = Program(id="outsider", code="outsider", metrics={"score": 4.0}) + self.db.programs = {p.id: p for p in [self.parent, self.best, self.other, outsider]} + self.db.islands = [{"parent", "best", "other"}, {"outsider"}] + self.db.island_best_programs = ["best", "outsider"] + + def test_fills_available_slots_when_island_is_no_larger_than_request(self): + for requested in (3, 5): + with self.subTest(requested=requested): + inspirations = self.db._sample_inspirations(self.parent, n=requested, island_id=0) + self.assertEqual([p.id for p in inspirations][0], "best") + self.assertCountEqual([p.id for p in inspirations], ["best", "other"]) + + def test_respects_smaller_request(self): + inspirations = self.db._sample_inspirations(self.parent, n=1, island_id=0) + self.assertEqual([p.id for p in inspirations], ["best"]) + + def test_parent_only_island_has_no_inspirations(self): + self.db.islands[0] = {"parent"} + self.db.island_best_programs[0] = "parent" + self.assertEqual(self.db._sample_inspirations(self.parent, n=5, island_id=0), []) + + +if __name__ == "__main__": + unittest.main()