Skip to content

Commit e9c2632

Browse files
committed
format
1 parent 0f1f898 commit e9c2632

File tree

3 files changed

+88
-71
lines changed

3 files changed

+88
-71
lines changed

openevolve/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ class DatabaseConfig:
7979
# Feature map dimensions for MAP-Elites
8080
feature_dimensions: List[str] = field(default_factory=lambda: ["score", "complexity"])
8181
feature_bins: int = 10
82-
82+
8383
# Migration parameters for island-based evolution
8484
migration_interval: int = 50 # Migrate every N generations
85-
migration_rate: float = 0.1 # Fraction of population to migrate
85+
migration_rate: float = 0.1 # Fraction of population to migrate
8686

8787

8888
@dataclass

openevolve/controller.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,23 +178,25 @@ async def run(
178178
logger.info(
179179
f"Starting evolution from iteration {start_iteration} for {max_iterations} iterations (total: {total_iterations})"
180180
)
181-
181+
182182
# Island-based evolution variables
183-
programs_per_island = max(1, max_iterations // (self.config.database.num_islands * 10)) # Dynamic allocation
183+
programs_per_island = max(
184+
1, max_iterations // (self.config.database.num_islands * 10)
185+
) # Dynamic allocation
184186
current_island_counter = 0
185-
187+
186188
logger.info(f"Using island-based evolution with {self.config.database.num_islands} islands")
187189
self.database.log_island_status()
188190

189191
for i in range(start_iteration, total_iterations):
190192
iteration_start = time.time()
191-
193+
192194
# Manage island evolution - switch islands periodically
193195
if i > start_iteration and current_island_counter >= programs_per_island:
194196
self.database.next_island()
195197
current_island_counter = 0
196198
logger.debug(f"Switched to island {self.database.current_island}")
197-
199+
198200
current_island_counter += 1
199201

200202
# Sample parent and inspirations from current island
@@ -269,10 +271,10 @@ async def run(
269271

270272
# Add to database (will be added to current island)
271273
self.database.add(child_program, iteration=i + 1)
272-
274+
273275
# Increment generation for current island
274276
self.database.increment_island_generation()
275-
277+
276278
# Check if migration should occur
277279
if self.database.should_migrate():
278280
logger.info(f"Performing migration at iteration {i+1}")

openevolve/database.py

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ def __init__(self, config: DatabaseConfig):
7979
# Island-based evolution tracking
8080
self.current_island: int = 0 # Track which island we're currently evolving
8181
self.island_generations: List[int] = [0] * config.num_islands
82-
82+
8383
# Migration parameters
84-
self.migration_interval: int = getattr(config, 'migration_interval', 50)
85-
self.migration_rate: float = getattr(config, 'migration_rate', 0.1)
84+
self.migration_interval: int = getattr(config, "migration_interval", 50)
85+
self.migration_rate: float = getattr(config, "migration_rate", 0.1)
8686
self.last_migration_generation: int = 0
8787

8888
# Archive of elite programs
@@ -100,7 +100,9 @@ def __init__(self, config: DatabaseConfig):
100100

101101
logger.info(f"Initialized program database with {len(self.programs)} programs")
102102

103-
def add(self, program: Program, iteration: int = None, target_island: Optional[int] = None) -> str:
103+
def add(
104+
self, program: Program, iteration: int = None, target_island: Optional[int] = None
105+
) -> str:
104106
"""
105107
Add a program to the database
106108
@@ -135,9 +137,9 @@ def add(self, program: Program, iteration: int = None, target_island: Optional[i
135137
island_idx = target_island if target_island is not None else self.current_island
136138
island_idx = island_idx % len(self.islands) # Ensure valid island
137139
self.islands[island_idx].add(program.id)
138-
140+
139141
# Track which island this program belongs to
140-
program.metadata['island'] = island_idx
142+
program.metadata["island"] = island_idx
141143

142144
# Update archive
143145
self._update_archive(program)
@@ -340,7 +342,7 @@ def load(self, path: str) -> None:
340342
self.current_island = metadata.get("current_island", 0)
341343
self.island_generations = metadata.get("island_generations", [0] * len(self.islands))
342344
self.last_migration_generation = metadata.get("last_migration_generation", 0)
343-
345+
344346
# Ensure island_generations list has correct length
345347
if len(self.island_generations) != len(self.islands):
346348
self.island_generations = [0] * len(self.islands)
@@ -547,11 +549,12 @@ def _sample_parent(self) -> Program:
547549
if random.random() < self.config.exploitation_ratio and self.archive:
548550
# Even for exploitation, prefer programs from current island
549551
archive_programs_in_island = [
550-
pid for pid in self.archive
551-
if pid in self.programs and
552-
self.programs[pid].metadata.get('island') == self.current_island
552+
pid
553+
for pid in self.archive
554+
if pid in self.programs
555+
and self.programs[pid].metadata.get("island") == self.current_island
553556
]
554-
557+
555558
if archive_programs_in_island:
556559
parent_id = random.choice(archive_programs_in_island)
557560
return self.programs[parent_id]
@@ -569,7 +572,7 @@ def _sample_parent(self) -> Program:
569572
# Clone best program to current island
570573
best_program = self.programs[self.best_program_id]
571574
self.islands[self.current_island].add(self.best_program_id)
572-
best_program.metadata['island'] = self.current_island
575+
best_program.metadata["island"] = self.current_island
573576
logger.debug(f"Initialized empty island {self.current_island} with best program")
574577
return best_program
575578
else:
@@ -652,58 +655,59 @@ def set_current_island(self, island_idx: int) -> None:
652655
"""Set which island is currently being evolved"""
653656
self.current_island = island_idx % len(self.islands)
654657
logger.debug(f"Switched to evolving island {self.current_island}")
655-
658+
656659
def next_island(self) -> int:
657660
"""Move to the next island in round-robin fashion"""
658661
self.current_island = (self.current_island + 1) % len(self.islands)
659662
logger.debug(f"Advanced to island {self.current_island}")
660663
return self.current_island
661-
664+
662665
def increment_island_generation(self, island_idx: Optional[int] = None) -> None:
663666
"""Increment generation counter for an island"""
664667
idx = island_idx if island_idx is not None else self.current_island
665668
self.island_generations[idx] += 1
666669
logger.debug(f"Island {idx} generation incremented to {self.island_generations[idx]}")
667-
670+
668671
def should_migrate(self) -> bool:
669672
"""Check if migration should occur based on generation counters"""
670673
max_generation = max(self.island_generations)
671674
return (max_generation - self.last_migration_generation) >= self.migration_interval
672-
675+
673676
def migrate_programs(self) -> None:
674677
"""
675678
Perform migration between islands
676-
679+
677680
This should be called periodically to share good solutions between islands
678681
"""
679682
if len(self.islands) < 2:
680683
return
681-
684+
682685
logger.info("Performing migration between islands")
683-
686+
684687
for i, island in enumerate(self.islands):
685688
if len(island) == 0:
686689
continue
687-
690+
688691
# Select top programs from this island for migration
689692
island_programs = [self.programs[pid] for pid in island if pid in self.programs]
690693
if not island_programs:
691694
continue
692-
695+
693696
# Sort by fitness (using combined_score or average metrics)
694697
island_programs.sort(
695-
key=lambda p: p.metrics.get('combined_score',
696-
sum(p.metrics.values()) / max(1, len(p.metrics))),
697-
reverse=True
698+
key=lambda p: p.metrics.get(
699+
"combined_score", sum(p.metrics.values()) / max(1, len(p.metrics))
700+
),
701+
reverse=True,
698702
)
699-
703+
700704
# Select top programs for migration
701705
num_to_migrate = max(1, int(len(island_programs) * self.migration_rate))
702706
migrants = island_programs[:num_to_migrate]
703-
707+
704708
# Migrate to adjacent islands (ring topology)
705709
target_islands = [(i + 1) % len(self.islands), (i - 1) % len(self.islands)]
706-
710+
707711
for migrant in migrants:
708712
for target_island in target_islands:
709713
# Create a copy for migration (to avoid removing from source)
@@ -714,74 +718,85 @@ def migrate_programs(self) -> None:
714718
parent_id=migrant.id,
715719
generation=migrant.generation,
716720
metrics=migrant.metrics.copy(),
717-
metadata={**migrant.metadata, 'island': target_island, 'migrant': True}
721+
metadata={**migrant.metadata, "island": target_island, "migrant": True},
718722
)
719-
723+
720724
# Add to target island
721725
self.islands[target_island].add(migrant_copy.id)
722726
self.programs[migrant_copy.id] = migrant_copy
723-
724-
logger.debug(f"Migrated program {migrant.id} from island {i} to island {target_island}")
725-
727+
728+
logger.debug(
729+
f"Migrated program {migrant.id} from island {i} to island {target_island}"
730+
)
731+
726732
# Update last migration generation
727733
self.last_migration_generation = max(self.island_generations)
728734
logger.info(f"Migration completed at generation {self.last_migration_generation}")
729-
735+
730736
def get_island_stats(self) -> List[dict]:
731737
"""Get statistics for each island"""
732738
stats = []
733-
739+
734740
for i, island in enumerate(self.islands):
735741
island_programs = [self.programs[pid] for pid in island if pid in self.programs]
736-
742+
737743
if island_programs:
738-
scores = [p.metrics.get('combined_score',
739-
sum(p.metrics.values()) / max(1, len(p.metrics)))
740-
for p in island_programs]
741-
744+
scores = [
745+
p.metrics.get(
746+
"combined_score", sum(p.metrics.values()) / max(1, len(p.metrics))
747+
)
748+
for p in island_programs
749+
]
750+
742751
best_score = max(scores) if scores else 0.0
743752
avg_score = sum(scores) / len(scores) if scores else 0.0
744753
diversity = self._calculate_island_diversity(island_programs)
745754
else:
746755
best_score = avg_score = diversity = 0.0
747-
748-
stats.append({
749-
'island': i,
750-
'population_size': len(island_programs),
751-
'best_score': best_score,
752-
'average_score': avg_score,
753-
'diversity': diversity,
754-
'generation': self.island_generations[i],
755-
'is_current': i == self.current_island
756-
})
757-
756+
757+
stats.append(
758+
{
759+
"island": i,
760+
"population_size": len(island_programs),
761+
"best_score": best_score,
762+
"average_score": avg_score,
763+
"diversity": diversity,
764+
"generation": self.island_generations[i],
765+
"is_current": i == self.current_island,
766+
}
767+
)
768+
758769
return stats
759-
770+
760771
def _calculate_island_diversity(self, programs: List[Program]) -> float:
761772
"""Calculate diversity within an island"""
762773
if len(programs) < 2:
763774
return 0.0
764-
775+
765776
total_distance = 0
766777
comparisons = 0
767-
778+
768779
# Sample up to 10 programs for efficiency
769780
sample_size = min(10, len(programs))
770-
sample_programs = random.sample(programs, sample_size) if len(programs) > sample_size else programs
771-
781+
sample_programs = (
782+
random.sample(programs, sample_size) if len(programs) > sample_size else programs
783+
)
784+
772785
for i, prog1 in enumerate(sample_programs):
773-
for prog2 in sample_programs[i+1:]:
786+
for prog2 in sample_programs[i + 1 :]:
774787
total_distance += calculate_edit_distance(prog1.code, prog2.code)
775788
comparisons += 1
776-
789+
777790
return total_distance / max(1, comparisons)
778-
791+
779792
def log_island_status(self) -> None:
780793
"""Log current status of all islands"""
781794
stats = self.get_island_stats()
782795
logger.info("Island Status:")
783796
for stat in stats:
784-
current_marker = " *" if stat['is_current'] else " "
785-
logger.info(f"{current_marker} Island {stat['island']}: {stat['population_size']} programs, "
786-
f"best={stat['best_score']:.4f}, avg={stat['average_score']:.4f}, "
787-
f"diversity={stat['diversity']:.2f}, gen={stat['generation']}")
797+
current_marker = " *" if stat["is_current"] else " "
798+
logger.info(
799+
f"{current_marker} Island {stat['island']}: {stat['population_size']} programs, "
800+
f"best={stat['best_score']:.4f}, avg={stat['average_score']:.4f}, "
801+
f"diversity={stat['diversity']:.2f}, gen={stat['generation']}"
802+
)

0 commit comments

Comments
 (0)