Skip to content

Commit 34fb621

Browse files
authored
Merge pull request algorithmicsuperintelligence#215 from codelion/fix-update-doc-readme
clarify prompt design
2 parents 528a766 + b4e2eee commit 34fb621

File tree

6 files changed

+56
-15
lines changed

6 files changed

+56
-15
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,40 @@ Sample configuration files are available in the `configs/` directory:
337337
- `default_config.yaml`: Comprehensive configuration with all available options
338338
- `island_config_example.yaml`: Advanced island-based evolution setup
339339

340+
### Prompt Engineering Design
341+
342+
OpenEvolve uses a sophisticated prompt engineering approach that separates different types of program examples to optimize LLM learning:
343+
344+
#### Program Selection Strategy
345+
346+
The system distinguishes between three types of program examples shown to the LLM:
347+
348+
1. **Previous Attempts** (`num_top_programs`): Shows only the best performing programs to demonstrate high-quality approaches
349+
- Used for the "Previous Attempts" section in prompts
350+
- Focused on proven successful patterns
351+
- Helps LLM understand what constitutes good performance
352+
353+
2. **Top Programs** (`num_top_programs + num_diverse_programs`): Broader selection including both top performers and diverse approaches
354+
- Used for the "Top Performing Programs" section
355+
- Includes diverse programs to prevent local optima
356+
- Balances exploitation of known good solutions with exploration of novel approaches
357+
358+
3. **Inspirations** (`num_top_programs`): Cross-island program samples for creative inspiration
359+
- Derived from other evolution islands to maintain diversity
360+
- Count automatically configures based on `num_top_programs` setting
361+
- Prevents convergence by exposing LLM to different evolutionary trajectories
362+
363+
#### Design Rationale
364+
365+
This separation is intentional and serves multiple purposes:
366+
367+
- **Focused Learning**: Previous attempts show only the best patterns, helping LLM understand quality standards
368+
- **Diversity Maintenance**: Top programs include diverse solutions to encourage exploration beyond local optima
369+
- **Cross-Pollination**: Inspirations from other islands introduce novel approaches and prevent stagnation
370+
- **Configurable Balance**: Adjust `num_top_programs` and `num_diverse_programs` to control exploration vs exploitation
371+
372+
The inspiration count automatically scales with `num_top_programs` to maintain consistency across different configuration sizes, eliminating the need for a separate configuration parameter.
373+
340374
### Template Customization
341375

342376
OpenEvolve supports advanced prompt template customization to increase diversity in code evolution:

openevolve/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version information for openevolve package."""
22

3-
__version__ = "0.1.2"
3+
__version__ = "0.1.3"

openevolve/database.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,18 +304,23 @@ def get(self, program_id: str) -> Optional[Program]:
304304
"""
305305
return self.programs.get(program_id)
306306

307-
def sample(self) -> Tuple[Program, List[Program]]:
307+
def sample(self, num_inspirations: Optional[int] = None) -> Tuple[Program, List[Program]]:
308308
"""
309309
Sample a program and inspirations for the next evolution step
310310
311+
Args:
312+
num_inspirations: Number of inspiration programs to sample (defaults to 5 for backward compatibility)
313+
311314
Returns:
312315
Tuple of (parent_program, inspiration_programs)
313316
"""
314317
# Select parent program
315318
parent = self._sample_parent()
316319

317320
# Select inspirations
318-
inspirations = self._sample_inspirations(parent, n=5)
321+
if num_inspirations is None:
322+
num_inspirations = 5 # Default for backward compatibility
323+
inspirations = self._sample_inspirations(parent, n=num_inspirations)
319324

320325
logger.debug(f"Sampled parent {parent.id} and {len(inspirations)} inspirations")
321326
return parent, inspirations
@@ -436,10 +441,10 @@ def get_top_programs(
436441
reverse=True,
437442
)
438443
else:
439-
# Sort by average of all numeric metrics
444+
# Sort by combined_score if available, otherwise by average of all numeric metrics
440445
sorted_programs = sorted(
441446
candidates,
442-
key=lambda p: safe_numeric_average(p.metrics),
447+
key=lambda p: p.metrics.get("combined_score", safe_numeric_average(p.metrics)),
443448
reverse=True,
444449
)
445450

@@ -877,7 +882,7 @@ def _update_archive(self, program: Program) -> None:
877882
# Find worst program among valid programs
878883
if valid_archive_programs:
879884
worst_program = min(
880-
valid_archive_programs, key=lambda p: safe_numeric_average(p.metrics)
885+
valid_archive_programs, key=lambda p: p.metrics.get("combined_score", safe_numeric_average(p.metrics))
881886
)
882887

883888
# Replace if new program is better
@@ -1279,10 +1284,10 @@ def _enforce_population_limit(self, exclude_program_id: Optional[str] = None) ->
12791284
# Get programs sorted by fitness (worst first)
12801285
all_programs = list(self.programs.values())
12811286

1282-
# Sort by average metric (worst first)
1287+
# Sort by combined_score if available, otherwise by average metric (worst first)
12831288
sorted_programs = sorted(
12841289
all_programs,
1285-
key=lambda p: safe_numeric_average(p.metrics),
1290+
key=lambda p: p.metrics.get("combined_score", safe_numeric_average(p.metrics)),
12861291
)
12871292

12881293
# Remove worst programs, but never remove the best program or excluded program

openevolve/iteration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async def run_iteration_with_shared_db(
4848

4949
try:
5050
# Sample parent and inspirations from database
51-
parent, inspirations = database.sample()
51+
parent, inspirations = database.sample(num_inspirations=config.prompt.num_top_programs)
5252

5353
# Get artifacts for the parent program if available
5454
parent_artifacts = database.get_artifacts(parent.id)

openevolve/process_parallel.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,20 @@ def _run_iteration_worker(
153153
)
154154

155155
# Use config values for limits instead of hardcoding
156-
island_top_programs = island_programs[
156+
# Programs for LLM display (includes both top and diverse for inspiration)
157+
programs_for_prompt = island_programs[
157158
: _worker_config.prompt.num_top_programs + _worker_config.prompt.num_diverse_programs
158159
]
159-
island_previous_programs = island_programs[: _worker_config.prompt.num_top_programs]
160+
# Best programs only (for previous attempts section, focused on top performers)
161+
best_programs_only = island_programs[: _worker_config.prompt.num_top_programs]
160162

161163
# Build prompt
162164
prompt = _worker_prompt_sampler.build_prompt(
163165
current_program=parent.code,
164166
parent_program=parent.code,
165167
program_metrics=parent.metrics,
166-
previous_programs=[p.to_dict() for p in island_previous_programs],
167-
top_programs=[p.to_dict() for p in island_top_programs],
168+
previous_programs=[p.to_dict() for p in best_programs_only],
169+
top_programs=[p.to_dict() for p in programs_for_prompt],
168170
inspirations=[p.to_dict() for p in inspirations],
169171
language=_worker_config.language,
170172
evolution_round=iteration,
@@ -589,7 +591,7 @@ def _submit_iteration(self, iteration: int, island_id: Optional[int] = None) ->
589591

590592
try:
591593
# Sample parent and inspirations from the target island
592-
parent, inspirations = self.database.sample()
594+
parent, inspirations = self.database.sample(num_inspirations=self.config.prompt.num_top_programs)
593595
finally:
594596
# Always restore original island state
595597
self.database.current_island = original_island

tests/test_island_isolation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_island_isolation_during_evolution(self):
109109
# Track which islands were sampled
110110
sampled_islands = []
111111

112-
def mock_sample():
112+
def mock_sample(num_inspirations=None):
113113
# Record which island was sampled
114114
sampled_islands.append(self.database.current_island)
115115
# Return mock parent and inspirations

0 commit comments

Comments
 (0)