Source code for metaheuristic_designer.analysis.experiment_runner

from typing import Callable, Iterable

import numpy as np
import pandas as pd

from ..objective_function import ObjectiveFunc

from ..benchmarks.ioh_wrapper import IOHObjective

# IOH is optional – only imported if needed (the actual import occurs inside
# the loop if a problem has an IOH logger; the module-level import is safe
# because we only reference ioh when has_logger is True).
try:
    import ioh
except ImportError:
    ioh = None


[docs] def run_experiment( problems: Iterable[ObjectiveFunc], algorithms: Iterable[Callable], max_evals: int, n_runs: int = 30, base_seed: int = 42, output_root: str = "experiment_data", ): """ Run a fair, reproducible comparison of algorithms on a set of problems. Parameters ---------- problems : list of ObjectiveFunc Benchmark functions to solve. IOHObjective instances will produce IOH-compatible log files automatically. algorithms : dict of str -> callable Keys are algorithm names; values are factories ``(objfunc, seed, budget) -> solver``. max_evals : int Common evaluation budget per run. n_runs : int Number of independent repetitions per (problem, algorithm) pair. base_seed : int Master seed for reproducibility. output_root : str Folder where IOH log files are written. Non-IOH problems are silently ignored. Returns ------- pd.DataFrame Columns: ``algorithm``, ``problem_name``, ``fid``, ``dimension``, ``instance``, ``run``, ``best_objective``. """ records = [] seed_sequence = np.random.SeedSequence(base_seed) for p_idx, problem in enumerate(problems): for r in range(n_runs): subsequence = seed_sequence.spawn(key=(p_idx, r))[0] seed = subsequence.generate_state(1, dtype=np.uint32)[0] # Reset the problem to its initial state (counter + IOH transforms) problem.restart() for algo_name, algo_factory in algorithms.items(): # ---- IOH logger (only for IOH-backed problems) --------- if isinstance(problem, IOHObjective): logger = ioh.logger.Analyzer( root=output_root, folder_name=f"{algo_name}/{problem.name}/run_{r}", algorithm_name=algo_name, algorithm_info="", store_positions=False, ) problem.attach_logger(logger) # ---- Build solver and optimize ------------------------- solver = algo_factory(problem, seed, max_evals) solver.optimize() _, best_obj = solver.best_solution() # ---- Detach logger (writes .dat / .info files) --------- if isinstance(problem, IOHObjective): problem.detach_logger() # ---- Record result ------------------------------------- records.append( { "algorithm": algo_name, "problem_name": problem.name, "fid": getattr(problem, "_fid", None), "dimension": problem.dimension, "instance": getattr(problem, "_instance", None), "run": r, "best_objective": best_obj, } ) return pd.DataFrame(records)