Perform migration between islands This should be called periodically to share good solutions between islands
(self)
| 1782 | return (max_generation - self.last_migration_generation) >= self.migration_interval |
| 1783 | |
| 1784 | def migrate_programs(self) -> None: |
| 1785 | """ |
| 1786 | Perform migration between islands |
| 1787 | |
| 1788 | This should be called periodically to share good solutions between islands |
| 1789 | """ |
| 1790 | if len(self.islands) < 2: |
| 1791 | return |
| 1792 | |
| 1793 | logger.info("Performing migration between islands") |
| 1794 | |
| 1795 | for i, island in enumerate(self.islands): |
| 1796 | if len(island) == 0: |
| 1797 | continue |
| 1798 | |
| 1799 | # Select top programs from this island for migration |
| 1800 | island_programs = [self.programs[pid] for pid in island if pid in self.programs] |
| 1801 | if not island_programs: |
| 1802 | continue |
| 1803 | |
| 1804 | # Sort by fitness (using combined_score or average metrics) |
| 1805 | island_programs.sort( |
| 1806 | key=lambda p: get_fitness_score(p.metrics, self.config.feature_dimensions), |
| 1807 | reverse=True, |
| 1808 | ) |
| 1809 | |
| 1810 | # Select top programs for migration |
| 1811 | num_to_migrate = max(1, int(len(island_programs) * self.migration_rate)) |
| 1812 | migrants = island_programs[:num_to_migrate] |
| 1813 | |
| 1814 | # Migrate to adjacent islands (ring topology) |
| 1815 | target_islands = [(i + 1) % len(self.islands), (i - 1) % len(self.islands)] |
| 1816 | |
| 1817 | for migrant in migrants: |
| 1818 | # Prevent re-migration of already migrated programs to avoid exponential duplication. |
| 1819 | # Analysis of actual evolution runs shows this causes severe issues: |
| 1820 | # - Program cb5d07f2 had 183 descendant copies by iteration 850 |
| 1821 | # - Program 5645fbd2 had 31 descendant copies |
| 1822 | # - IDs grow exponentially: program_migrant_2_migrant_3_migrant_4_migrant_0... |
| 1823 | # |
| 1824 | # This is particularly problematic for LongHorizon's MAP-Elites + Island hybrid architecture: |
| 1825 | # 1. All copies have identical code → same complexity/diversity/performance scores |
| 1826 | # 2. They all map to the SAME MAP-Elites cell → only 1 survives, rest discarded |
| 1827 | # 3. Wastes computation evaluating hundreds of identical programs |
| 1828 | # 4. Reduces actual diversity as islands fill with duplicates |
| 1829 | # |
| 1830 | # By preventing already-migrated programs from migrating again, we ensure: |
| 1831 | # - Each program migrates at most once per lineage |
| 1832 | # - True diversity is maintained between islands |
| 1833 | # - Computational resources aren't wasted on duplicates |
| 1834 | # - Aligns with MAP-Elites' one-program-per-cell principle |
| 1835 | if migrant.metadata.get("migrant", False): |
| 1836 | continue |
| 1837 | |
| 1838 | for target_island in target_islands: |
| 1839 | # Skip migration if target island already has a program with identical code |
| 1840 | # Identical code produces identical metrics, so migration would be wasteful |
| 1841 | target_island_programs = [ |
no test coverage detected