1515
1616from openevolve .config import DatabaseConfig
1717from openevolve .utils .code_utils import calculate_edit_distance
18+ from openevolve .utils .metrics_utils import safe_numeric_average
1819
1920logger = logging .getLogger (__name__ )
2021
@@ -227,10 +228,10 @@ def get_best_program(self, metric: Optional[str] = None) -> Optional[Program]:
227228 if sorted_programs :
228229 logger .debug (f"Found best program by combined_score: { sorted_programs [0 ].id } " )
229230 else :
230- # Sort by average of all metrics as fallback
231+ # Sort by average of all numeric metrics as fallback
231232 sorted_programs = sorted (
232233 self .programs .values (),
233- key = lambda p : sum (p .metrics . values ()) / max ( 1 , len ( p . metrics ) ),
234+ key = lambda p : safe_numeric_average (p .metrics ),
234235 reverse = True ,
235236 )
236237 if sorted_programs :
@@ -281,10 +282,10 @@ def get_top_programs(self, n: int = 10, metric: Optional[str] = None) -> List[Pr
281282 reverse = True ,
282283 )
283284 else :
284- # Sort by average of all metrics
285+ # Sort by average of all numeric metrics
285286 sorted_programs = sorted (
286287 self .programs .values (),
287- key = lambda p : sum (p .metrics . values ()) / max ( 1 , len ( p . metrics ) ),
288+ key = lambda p : safe_numeric_average (p .metrics ),
288289 reverse = True ,
289290 )
290291
@@ -436,7 +437,7 @@ def _calculate_feature_coords(self, program: Program) -> List[int]:
436437 if not program .metrics :
437438 bin_idx = 0
438439 else :
439- avg_score = sum ( program . metrics . values ()) / len (program .metrics )
440+ avg_score = safe_numeric_average (program .metrics )
440441 bin_idx = min (int (avg_score * self .feature_bins ), self .feature_bins - 1 )
441442 coords .append (bin_idx )
442443 elif dim in program .metrics :
@@ -487,9 +488,9 @@ def _is_better(self, program1: Program, program2: Program) -> bool:
487488 if "combined_score" in program1 .metrics and "combined_score" in program2 .metrics :
488489 return program1 .metrics ["combined_score" ] > program2 .metrics ["combined_score" ]
489490
490- # Fallback to average of all metrics
491- avg1 = sum ( program1 . metrics . values ()) / len (program1 .metrics )
492- avg2 = sum ( program2 . metrics . values ()) / len (program2 .metrics )
491+ # Fallback to average of all numeric metrics
492+ avg1 = safe_numeric_average (program1 .metrics )
493+ avg2 = safe_numeric_average (program2 .metrics )
493494
494495 return avg1 > avg2
495496
@@ -508,7 +509,7 @@ def _update_archive(self, program: Program) -> None:
508509 # Otherwise, find worst program in archive
509510 archive_programs = [self .programs [pid ] for pid in self .archive ]
510511 worst_program = min (
511- archive_programs , key = lambda p : sum (p .metrics . values ()) / max ( 1 , len ( p . metrics ) )
512+ archive_programs , key = lambda p : safe_numeric_average (p .metrics )
512513 )
513514
514515 # Replace if new program is better
@@ -716,7 +717,7 @@ def _enforce_population_limit(self) -> None:
716717 # Sort by average metric (worst first)
717718 sorted_programs = sorted (
718719 all_programs ,
719- key = lambda p : sum (p .metrics . values ()) / max ( 1 , len ( p . metrics )) if p . metrics else 0.0 ,
720+ key = lambda p : safe_numeric_average (p .metrics ) ,
720721 )
721722
722723 # Remove worst programs, but never remove the best program
@@ -812,7 +813,7 @@ def migrate_programs(self) -> None:
812813 # Sort by fitness (using combined_score or average metrics)
813814 island_programs .sort (
814815 key = lambda p : p .metrics .get (
815- "combined_score" , sum (p .metrics . values ()) / max ( 1 , len ( p . metrics ) )
816+ "combined_score" , safe_numeric_average (p .metrics )
816817 ),
817818 reverse = True ,
818819 )
@@ -859,7 +860,7 @@ def get_island_stats(self) -> List[dict]:
859860 if island_programs :
860861 scores = [
861862 p .metrics .get (
862- "combined_score" , sum (p .metrics . values ()) / max ( 1 , len ( p . metrics ) )
863+ "combined_score" , safe_numeric_average (p .metrics )
863864 )
864865 for p in island_programs
865866 ]
0 commit comments