Evolve an algorithm implemented as a class based on a benchmark function. Args: algorithm_class: The initial class to evolve. benchmark: A function that takes an instance of the class and returns a metrics dictionary. iterations: The number of evolution iterations.
(
algorithm_class: type, benchmark: Callable, iterations: int = 100, **kwargs
)
| 346 | |
| 347 | |
| 348 | def evolve_algorithm( |
| 349 | algorithm_class: type, benchmark: Callable, iterations: int = 100, **kwargs |
| 350 | ) -> EvolutionResult: |
| 351 | """ |
| 352 | Evolve an algorithm implemented as a class based on a benchmark function. |
| 353 | |
| 354 | Args: |
| 355 | algorithm_class: The initial class to evolve. |
| 356 | benchmark: A function that takes an instance of the class and returns a metrics dictionary. |
| 357 | iterations: The number of evolution iterations. |
| 358 | **kwargs: Additional arguments for `run_evolution`. |
| 359 | |
| 360 | Returns: |
| 361 | An EvolutionResult with the optimized algorithm class. |
| 362 | """ |
| 363 | |
| 364 | # Get the source code of the provided class. |
| 365 | class_source = inspect.getsource(algorithm_class) |
| 366 | |
| 367 | # Ensure the class has evolution markers. |
| 368 | if "EVOLVE-BLOCK-START" not in class_source: |
| 369 | lines = class_source.split("\n") |
| 370 | class_def_line = next(i for i, line in enumerate(lines) if line.strip().startswith("class ")) |
| 371 | indent = len(lines[class_def_line]) - len(lines[class_def_line].lstrip()) |
| 372 | lines.insert(class_def_line + 1, " " * (indent + 4) + "# EVOLVE-BLOCK-START") |
| 373 | lines.append(" " * (indent + 4) + "# EVOLVE-BLOCK-END") |
| 374 | class_source = "\n".join(lines) |
| 375 | |
| 376 | # Create a custom evaluator that uses the benchmark function. |
| 377 | def evaluator(program_path): |
| 378 | import importlib.util |
| 379 | |
| 380 | # Load the evolved program. |
| 381 | spec = importlib.util.spec_from_file_location("evolved", program_path) |
| 382 | if spec is None or spec.loader is None: |
| 383 | return {"score": 0.0, "error": "Failed to load program"} |
| 384 | |
| 385 | module = importlib.util.module_from_spec(spec) |
| 386 | try: |
| 387 | spec.loader.exec_module(module) |
| 388 | except Exception as e: |
| 389 | return {"score": 0.0, "error": f"Failed to execute program: {str(e)}"} |
| 390 | |
| 391 | if not hasattr(module, algorithm_class.__name__): |
| 392 | return {"score": 0.0, "error": f"Class '{algorithm_class.__name__}' not found"} |
| 393 | |
| 394 | EvolvedAlgorithmClass = getattr(module, algorithm_class.__name__) |
| 395 | |
| 396 | try: |
| 397 | # Instantiate the evolved class and run the benchmark. |
| 398 | instance = EvolvedAlgorithmClass() |
| 399 | metrics = benchmark(instance) |
| 400 | return metrics if isinstance(metrics, dict) else {"score": metrics} |
| 401 | except Exception as e: |
| 402 | return {"score": 0.0, "error": str(e)} |
| 403 | |
| 404 | # Call the main evolution function. |
| 405 | return run_evolution( |
nothing calls this directly
no test coverage detected