@@ -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