morphml 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of morphml might be problematic. Click here for more details.

Files changed (158) hide show
  1. morphml/__init__.py +14 -0
  2. morphml/api/__init__.py +26 -0
  3. morphml/api/app.py +326 -0
  4. morphml/api/auth.py +193 -0
  5. morphml/api/client.py +338 -0
  6. morphml/api/models.py +132 -0
  7. morphml/api/rate_limit.py +192 -0
  8. morphml/benchmarking/__init__.py +36 -0
  9. morphml/benchmarking/comparison.py +430 -0
  10. morphml/benchmarks/__init__.py +56 -0
  11. morphml/benchmarks/comparator.py +409 -0
  12. morphml/benchmarks/datasets.py +280 -0
  13. morphml/benchmarks/metrics.py +199 -0
  14. morphml/benchmarks/openml_suite.py +201 -0
  15. morphml/benchmarks/problems.py +289 -0
  16. morphml/benchmarks/suite.py +318 -0
  17. morphml/cli/__init__.py +5 -0
  18. morphml/cli/commands/experiment.py +329 -0
  19. morphml/cli/main.py +457 -0
  20. morphml/cli/quickstart.py +312 -0
  21. morphml/config.py +278 -0
  22. morphml/constraints/__init__.py +19 -0
  23. morphml/constraints/handler.py +205 -0
  24. morphml/constraints/predicates.py +285 -0
  25. morphml/core/__init__.py +3 -0
  26. morphml/core/crossover.py +449 -0
  27. morphml/core/dsl/README.md +359 -0
  28. morphml/core/dsl/__init__.py +72 -0
  29. morphml/core/dsl/ast_nodes.py +364 -0
  30. morphml/core/dsl/compiler.py +318 -0
  31. morphml/core/dsl/layers.py +368 -0
  32. morphml/core/dsl/lexer.py +336 -0
  33. morphml/core/dsl/parser.py +455 -0
  34. morphml/core/dsl/search_space.py +386 -0
  35. morphml/core/dsl/syntax.py +199 -0
  36. morphml/core/dsl/type_system.py +361 -0
  37. morphml/core/dsl/validator.py +386 -0
  38. morphml/core/graph/__init__.py +40 -0
  39. morphml/core/graph/edge.py +124 -0
  40. morphml/core/graph/graph.py +507 -0
  41. morphml/core/graph/mutations.py +409 -0
  42. morphml/core/graph/node.py +196 -0
  43. morphml/core/graph/serialization.py +361 -0
  44. morphml/core/graph/visualization.py +431 -0
  45. morphml/core/objectives/__init__.py +20 -0
  46. morphml/core/search/__init__.py +33 -0
  47. morphml/core/search/individual.py +252 -0
  48. morphml/core/search/parameters.py +453 -0
  49. morphml/core/search/population.py +375 -0
  50. morphml/core/search/search_engine.py +340 -0
  51. morphml/distributed/__init__.py +76 -0
  52. morphml/distributed/fault_tolerance.py +497 -0
  53. morphml/distributed/health_monitor.py +348 -0
  54. morphml/distributed/master.py +709 -0
  55. morphml/distributed/proto/README.md +224 -0
  56. morphml/distributed/proto/__init__.py +74 -0
  57. morphml/distributed/proto/worker.proto +170 -0
  58. morphml/distributed/proto/worker_pb2.py +79 -0
  59. morphml/distributed/proto/worker_pb2_grpc.py +423 -0
  60. morphml/distributed/resource_manager.py +416 -0
  61. morphml/distributed/scheduler.py +567 -0
  62. morphml/distributed/storage/__init__.py +33 -0
  63. morphml/distributed/storage/artifacts.py +381 -0
  64. morphml/distributed/storage/cache.py +366 -0
  65. morphml/distributed/storage/checkpointing.py +329 -0
  66. morphml/distributed/storage/database.py +459 -0
  67. morphml/distributed/worker.py +549 -0
  68. morphml/evaluation/__init__.py +5 -0
  69. morphml/evaluation/heuristic.py +237 -0
  70. morphml/exceptions.py +55 -0
  71. morphml/execution/__init__.py +5 -0
  72. morphml/execution/local_executor.py +350 -0
  73. morphml/integrations/__init__.py +28 -0
  74. morphml/integrations/jax_adapter.py +206 -0
  75. morphml/integrations/pytorch_adapter.py +530 -0
  76. morphml/integrations/sklearn_adapter.py +206 -0
  77. morphml/integrations/tensorflow_adapter.py +230 -0
  78. morphml/logging_config.py +93 -0
  79. morphml/meta_learning/__init__.py +66 -0
  80. morphml/meta_learning/architecture_similarity.py +277 -0
  81. morphml/meta_learning/experiment_database.py +240 -0
  82. morphml/meta_learning/knowledge_base/__init__.py +19 -0
  83. morphml/meta_learning/knowledge_base/embedder.py +179 -0
  84. morphml/meta_learning/knowledge_base/knowledge_base.py +313 -0
  85. morphml/meta_learning/knowledge_base/meta_features.py +265 -0
  86. morphml/meta_learning/knowledge_base/vector_store.py +271 -0
  87. morphml/meta_learning/predictors/__init__.py +27 -0
  88. morphml/meta_learning/predictors/ensemble.py +221 -0
  89. morphml/meta_learning/predictors/gnn_predictor.py +552 -0
  90. morphml/meta_learning/predictors/learning_curve.py +231 -0
  91. morphml/meta_learning/predictors/proxy_metrics.py +261 -0
  92. morphml/meta_learning/strategy_evolution/__init__.py +27 -0
  93. morphml/meta_learning/strategy_evolution/adaptive_optimizer.py +226 -0
  94. morphml/meta_learning/strategy_evolution/bandit.py +276 -0
  95. morphml/meta_learning/strategy_evolution/portfolio.py +230 -0
  96. morphml/meta_learning/transfer.py +581 -0
  97. morphml/meta_learning/warm_start.py +286 -0
  98. morphml/optimizers/__init__.py +74 -0
  99. morphml/optimizers/adaptive_operators.py +399 -0
  100. morphml/optimizers/bayesian/__init__.py +52 -0
  101. morphml/optimizers/bayesian/acquisition.py +387 -0
  102. morphml/optimizers/bayesian/base.py +319 -0
  103. morphml/optimizers/bayesian/gaussian_process.py +635 -0
  104. morphml/optimizers/bayesian/smac.py +534 -0
  105. morphml/optimizers/bayesian/tpe.py +411 -0
  106. morphml/optimizers/differential_evolution.py +220 -0
  107. morphml/optimizers/evolutionary/__init__.py +61 -0
  108. morphml/optimizers/evolutionary/cma_es.py +416 -0
  109. morphml/optimizers/evolutionary/differential_evolution.py +556 -0
  110. morphml/optimizers/evolutionary/encoding.py +426 -0
  111. morphml/optimizers/evolutionary/particle_swarm.py +449 -0
  112. morphml/optimizers/genetic_algorithm.py +486 -0
  113. morphml/optimizers/gradient_based/__init__.py +22 -0
  114. morphml/optimizers/gradient_based/darts.py +550 -0
  115. morphml/optimizers/gradient_based/enas.py +585 -0
  116. morphml/optimizers/gradient_based/operations.py +474 -0
  117. morphml/optimizers/gradient_based/utils.py +601 -0
  118. morphml/optimizers/hill_climbing.py +169 -0
  119. morphml/optimizers/multi_objective/__init__.py +56 -0
  120. morphml/optimizers/multi_objective/indicators.py +504 -0
  121. morphml/optimizers/multi_objective/nsga2.py +647 -0
  122. morphml/optimizers/multi_objective/visualization.py +427 -0
  123. morphml/optimizers/nsga2.py +308 -0
  124. morphml/optimizers/random_search.py +172 -0
  125. morphml/optimizers/simulated_annealing.py +181 -0
  126. morphml/plugins/__init__.py +35 -0
  127. morphml/plugins/custom_evaluator_example.py +81 -0
  128. morphml/plugins/custom_optimizer_example.py +63 -0
  129. morphml/plugins/plugin_system.py +454 -0
  130. morphml/reports/__init__.py +30 -0
  131. morphml/reports/generator.py +362 -0
  132. morphml/tracking/__init__.py +7 -0
  133. morphml/tracking/experiment.py +309 -0
  134. morphml/tracking/logger.py +301 -0
  135. morphml/tracking/reporter.py +357 -0
  136. morphml/utils/__init__.py +6 -0
  137. morphml/utils/checkpoint.py +189 -0
  138. morphml/utils/comparison.py +390 -0
  139. morphml/utils/export.py +407 -0
  140. morphml/utils/progress.py +392 -0
  141. morphml/utils/validation.py +392 -0
  142. morphml/version.py +7 -0
  143. morphml/visualization/__init__.py +50 -0
  144. morphml/visualization/analytics.py +423 -0
  145. morphml/visualization/architecture_diagrams.py +353 -0
  146. morphml/visualization/architecture_plot.py +223 -0
  147. morphml/visualization/convergence_plot.py +174 -0
  148. morphml/visualization/crossover_viz.py +386 -0
  149. morphml/visualization/graph_viz.py +338 -0
  150. morphml/visualization/pareto_plot.py +149 -0
  151. morphml/visualization/plotly_dashboards.py +422 -0
  152. morphml/visualization/population.py +309 -0
  153. morphml/visualization/progress.py +260 -0
  154. morphml-1.0.0.dist-info/METADATA +434 -0
  155. morphml-1.0.0.dist-info/RECORD +158 -0
  156. morphml-1.0.0.dist-info/WHEEL +4 -0
  157. morphml-1.0.0.dist-info/entry_points.txt +3 -0
  158. morphml-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,430 @@
1
+ """Optimizer comparison and benchmarking tools.
2
+
3
+ This module provides tools to systematically compare different optimization
4
+ algorithms on the same search space and evaluation budget.
5
+
6
+ Features:
7
+ - Run multiple optimizers with same budget
8
+ - Statistical comparison (mean, std, confidence intervals)
9
+ - Convergence curve comparison
10
+ - Sample efficiency analysis
11
+ - Result visualization
12
+
13
+ Author: Eshan Roy <eshanized@proton.me>
14
+ Organization: TONMOY INFRASTRUCTURE & VISION
15
+ """
16
+
17
+ import time
18
+ from typing import Any, Callable, Dict, List, Optional
19
+
20
+ import numpy as np
21
+
22
+ from morphml.core.dsl import SearchSpace
23
+ from morphml.logging_config import get_logger
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ class OptimizerComparison:
29
+ """
30
+ Compare multiple optimizers on the same problem.
31
+
32
+ Runs each optimizer multiple times and collects statistics for
33
+ rigorous comparison including convergence speed and sample efficiency.
34
+
35
+ Example:
36
+ >>> from morphml.benchmarking import OptimizerComparison
37
+ >>> from morphml.optimizers import GeneticAlgorithm, optimize_with_pso
38
+ >>>
39
+ >>> comparison = OptimizerComparison(
40
+ ... search_space=space,
41
+ ... evaluator=my_evaluator,
42
+ ... budget=100,
43
+ ... num_runs=10
44
+ ... )
45
+ >>>
46
+ >>> comparison.add_optimizer('GA', GeneticAlgorithm(space, config))
47
+ >>> comparison.add_optimizer('PSO', ParticleSwarmOptimizer(space, config))
48
+ >>>
49
+ >>> results = comparison.run()
50
+ >>> comparison.plot_comparison()
51
+ """
52
+
53
+ def __init__(
54
+ self, search_space: SearchSpace, evaluator: Callable, budget: int = 100, num_runs: int = 5
55
+ ):
56
+ """
57
+ Initialize comparison.
58
+
59
+ Args:
60
+ search_space: SearchSpace to search
61
+ evaluator: Fitness evaluation function
62
+ budget: Number of evaluations per run
63
+ num_runs: Number of independent runs per optimizer
64
+ """
65
+ self.search_space = search_space
66
+ self.evaluator = evaluator
67
+ self.budget = budget
68
+ self.num_runs = num_runs
69
+
70
+ self.optimizers: Dict[str, Any] = {}
71
+ self.results: Dict[str, List[Dict]] = {}
72
+ self.statistics: Dict[str, Dict] = {}
73
+
74
+ logger.info(f"Initialized OptimizerComparison: " f"budget={budget}, num_runs={num_runs}")
75
+
76
+ def add_optimizer(self, name: str, optimizer: Any) -> None:
77
+ """
78
+ Add optimizer to comparison.
79
+
80
+ Args:
81
+ name: Name for this optimizer
82
+ optimizer: Optimizer instance or factory function
83
+ """
84
+ self.optimizers[name] = optimizer
85
+ logger.debug(f"Added optimizer: {name}")
86
+
87
+ def run(self) -> Dict[str, Dict]:
88
+ """
89
+ Run all optimizers and collect results.
90
+
91
+ Returns:
92
+ Statistics dictionary with results for each optimizer
93
+
94
+ Example:
95
+ >>> results = comparison.run()
96
+ >>> print(f"GA mean: {results['GA']['mean_best']:.4f}")
97
+ """
98
+ logger.info(
99
+ f"Running comparison with {len(self.optimizers)} optimizers, "
100
+ f"{self.num_runs} runs each"
101
+ )
102
+
103
+ for name, optimizer_template in self.optimizers.items():
104
+ logger.info(f"\nBenchmarking {name}...")
105
+
106
+ run_results = []
107
+
108
+ for run_id in range(self.num_runs):
109
+ logger.info(f" Run {run_id + 1}/{self.num_runs}")
110
+
111
+ # Create fresh optimizer instance
112
+ if callable(optimizer_template):
113
+ optimizer = optimizer_template()
114
+ else:
115
+ optimizer = optimizer_template
116
+
117
+ # Run optimization
118
+ start_time = time.time()
119
+
120
+ try:
121
+ best = optimizer.optimize(self.evaluator)
122
+ elapsed_time = time.time() - start_time
123
+
124
+ # Collect results
125
+ history = optimizer.get_history() if hasattr(optimizer, "get_history") else []
126
+
127
+ run_results.append(
128
+ {
129
+ "run_id": run_id,
130
+ "best_fitness": best.fitness,
131
+ "best_individual": best,
132
+ "time_seconds": elapsed_time,
133
+ "history": history,
134
+ "success": True,
135
+ }
136
+ )
137
+
138
+ logger.info(
139
+ f" Best fitness: {best.fitness:.4f}, " f"Time: {elapsed_time:.2f}s"
140
+ )
141
+
142
+ except Exception as e:
143
+ logger.error(f" Run failed: {e}")
144
+ run_results.append({"run_id": run_id, "success": False, "error": str(e)})
145
+
146
+ self.results[name] = run_results
147
+
148
+ # Compute statistics
149
+ self.statistics = self._compute_statistics()
150
+
151
+ # Print summary
152
+ self._print_summary()
153
+
154
+ return self.statistics
155
+
156
+ def _compute_statistics(self) -> Dict[str, Dict]:
157
+ """
158
+ Compute statistics across runs for each optimizer.
159
+
160
+ Returns:
161
+ Statistics dictionary
162
+ """
163
+ stats = {}
164
+
165
+ for name, runs in self.results.items():
166
+ # Filter successful runs
167
+ successful_runs = [r for r in runs if r.get("success", False)]
168
+
169
+ if not successful_runs:
170
+ stats[name] = {"error": "All runs failed"}
171
+ continue
172
+
173
+ # Extract metrics
174
+ best_fitnesses = [r["best_fitness"] for r in successful_runs]
175
+ times = [r["time_seconds"] for r in successful_runs]
176
+
177
+ # Compute statistics
178
+ stats[name] = {
179
+ "num_successful_runs": len(successful_runs),
180
+ "num_failed_runs": len(runs) - len(successful_runs),
181
+ # Best fitness statistics
182
+ "mean_best": np.mean(best_fitnesses),
183
+ "std_best": np.std(best_fitnesses),
184
+ "min_best": np.min(best_fitnesses),
185
+ "max_best": np.max(best_fitnesses),
186
+ "median_best": np.median(best_fitnesses),
187
+ # Confidence interval (95%)
188
+ "ci_lower": np.percentile(best_fitnesses, 2.5),
189
+ "ci_upper": np.percentile(best_fitnesses, 97.5),
190
+ # Time statistics
191
+ "mean_time": np.mean(times),
192
+ "std_time": np.std(times),
193
+ # All runs data
194
+ "all_best_fitnesses": best_fitnesses,
195
+ "all_times": times,
196
+ }
197
+
198
+ return stats
199
+
200
+ def _print_summary(self) -> None:
201
+ """Print comparison summary."""
202
+ print("\n" + "=" * 70)
203
+ print("OPTIMIZER COMPARISON SUMMARY")
204
+ print("=" * 70)
205
+ print(f"Budget: {self.budget} evaluations")
206
+ print(f"Runs per optimizer: {self.num_runs}")
207
+ print("=" * 70)
208
+
209
+ # Sort by mean best fitness (descending)
210
+ sorted_optimizers = sorted(
211
+ self.statistics.items(), key=lambda x: x[1].get("mean_best", -np.inf), reverse=True
212
+ )
213
+
214
+ print(f"\n{'Optimizer':<20} {'Mean Best':<12} {'Std':<10} {'Time (s)':<10}")
215
+ print("-" * 70)
216
+
217
+ for name, stats in sorted_optimizers:
218
+ if "error" in stats:
219
+ print(f"{name:<20} {'FAILED':<12}")
220
+ else:
221
+ print(
222
+ f"{name:<20} "
223
+ f"{stats['mean_best']:<12.4f} "
224
+ f"{stats['std_best']:<10.4f} "
225
+ f"{stats['mean_time']:<10.2f}"
226
+ )
227
+
228
+ print("=" * 70 + "\n")
229
+
230
+ # Winner
231
+ if sorted_optimizers and "error" not in sorted_optimizers[0][1]:
232
+ winner = sorted_optimizers[0][0]
233
+ print(f"🏆 Best Optimizer: {winner}")
234
+ print(f" Mean Fitness: {sorted_optimizers[0][1]['mean_best']:.4f}")
235
+ print(f" Std: {sorted_optimizers[0][1]['std_best']:.4f}")
236
+ print("=" * 70 + "\n")
237
+
238
+ def plot_comparison(self, save_path: Optional[str] = None) -> None:
239
+ """
240
+ Plot comparison results.
241
+
242
+ Creates box plots showing distribution of best fitnesses.
243
+
244
+ Args:
245
+ save_path: Optional path to save figure
246
+ """
247
+ try:
248
+ import matplotlib.pyplot as plt
249
+ except ImportError:
250
+ logger.warning("matplotlib not available, cannot plot")
251
+ return
252
+
253
+ if not self.statistics:
254
+ logger.warning("No results to plot. Run comparison first.")
255
+ return
256
+
257
+ # Prepare data
258
+ names = []
259
+ data = []
260
+
261
+ for name, stats in self.statistics.items():
262
+ if "all_best_fitnesses" in stats:
263
+ names.append(name)
264
+ data.append(stats["all_best_fitnesses"])
265
+
266
+ if not data:
267
+ logger.warning("No successful runs to plot")
268
+ return
269
+
270
+ # Create box plot
271
+ fig, ax = plt.subplots(figsize=(10, 6))
272
+
273
+ bp = ax.boxplot(data, labels=names, patch_artist=True)
274
+
275
+ # Color boxes
276
+ colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8"]
277
+ for patch, color in zip(bp["boxes"], colors * len(names)):
278
+ patch.set_facecolor(color)
279
+ patch.set_alpha(0.7)
280
+
281
+ ax.set_xlabel("Optimizer", fontsize=12, fontweight="bold")
282
+ ax.set_ylabel("Best Fitness", fontsize=12, fontweight="bold")
283
+ ax.set_title(
284
+ f"Optimizer Comparison ({self.num_runs} runs, {self.budget} evaluations)",
285
+ fontsize=14,
286
+ fontweight="bold",
287
+ )
288
+ ax.grid(True, alpha=0.3, axis="y")
289
+
290
+ plt.xticks(rotation=45, ha="right")
291
+ plt.tight_layout()
292
+
293
+ if save_path:
294
+ plt.savefig(save_path, dpi=300, bbox_inches="tight")
295
+ logger.info(f"Comparison plot saved to {save_path}")
296
+ else:
297
+ plt.show()
298
+
299
+ plt.close()
300
+
301
+ def plot_convergence(self, save_path: Optional[str] = None) -> None:
302
+ """
303
+ Plot convergence curves for all optimizers.
304
+
305
+ Shows how best fitness evolves over iterations.
306
+
307
+ Args:
308
+ save_path: Optional path to save figure
309
+ """
310
+ try:
311
+ import matplotlib.pyplot as plt
312
+ except ImportError:
313
+ logger.warning("matplotlib not available, cannot plot")
314
+ return
315
+
316
+ fig, ax = plt.subplots(figsize=(12, 6))
317
+
318
+ colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", "#C7CEEA"]
319
+
320
+ for (name, runs), color in zip(self.results.items(), colors * len(self.results)):
321
+ # Average convergence across runs
322
+ all_histories = [r["history"] for r in runs if r.get("success") and r.get("history")]
323
+
324
+ if not all_histories:
325
+ continue
326
+
327
+ # Find max length
328
+ max_len = max(len(h) for h in all_histories)
329
+
330
+ # Pad and average
331
+ padded_histories = []
332
+ for hist in all_histories:
333
+ if len(hist) < max_len:
334
+ # Pad with last value
335
+ last_val = hist[-1]["best_fitness"] if hist else 0
336
+ padded = hist + [{"best_fitness": last_val}] * (max_len - len(hist))
337
+ else:
338
+ padded = hist
339
+
340
+ padded_histories.append([h.get("best_fitness", 0) for h in padded])
341
+
342
+ avg_convergence = np.mean(padded_histories, axis=0)
343
+ std_convergence = np.std(padded_histories, axis=0)
344
+
345
+ iterations = range(len(avg_convergence))
346
+
347
+ ax.plot(iterations, avg_convergence, label=name, linewidth=2, color=color)
348
+ ax.fill_between(
349
+ iterations,
350
+ avg_convergence - std_convergence,
351
+ avg_convergence + std_convergence,
352
+ alpha=0.2,
353
+ color=color,
354
+ )
355
+
356
+ ax.set_xlabel("Iteration", fontsize=12, fontweight="bold")
357
+ ax.set_ylabel("Best Fitness", fontsize=12, fontweight="bold")
358
+ ax.set_title("Convergence Comparison", fontsize=14, fontweight="bold")
359
+ ax.legend()
360
+ ax.grid(True, alpha=0.3)
361
+
362
+ plt.tight_layout()
363
+
364
+ if save_path:
365
+ plt.savefig(save_path, dpi=300, bbox_inches="tight")
366
+ logger.info(f"Convergence plot saved to {save_path}")
367
+ else:
368
+ plt.show()
369
+
370
+ plt.close()
371
+
372
+ def get_results(self) -> Dict[str, List[Dict]]:
373
+ """Get raw results."""
374
+ return self.results
375
+
376
+ def get_statistics(self) -> Dict[str, Dict]:
377
+ """Get computed statistics."""
378
+ return self.statistics
379
+
380
+
381
+ # Convenience function
382
+ def compare_optimizers(
383
+ optimizers: Dict[str, Any],
384
+ search_space: SearchSpace,
385
+ evaluator: Callable,
386
+ budget: int = 100,
387
+ num_runs: int = 5,
388
+ plot: bool = True,
389
+ ) -> Dict[str, Dict]:
390
+ """
391
+ Quick comparison of multiple optimizers.
392
+
393
+ Args:
394
+ optimizers: Dictionary of {name: optimizer} pairs
395
+ search_space: SearchSpace to search
396
+ evaluator: Fitness evaluation function
397
+ budget: Number of evaluations per run
398
+ num_runs: Number of runs per optimizer
399
+ plot: Whether to generate plots
400
+
401
+ Returns:
402
+ Statistics dictionary
403
+
404
+ Example:
405
+ >>> from morphml.benchmarking import compare_optimizers
406
+ >>> from morphml.optimizers import GeneticAlgorithm, optimize_with_pso
407
+ >>>
408
+ >>> results = compare_optimizers(
409
+ ... optimizers={
410
+ ... 'GA': GeneticAlgorithm(space, config),
411
+ ... 'PSO': ParticleSwarmOptimizer(space, config)
412
+ ... },
413
+ ... search_space=space,
414
+ ... evaluator=my_evaluator,
415
+ ... budget=100,
416
+ ... num_runs=5
417
+ ... )
418
+ """
419
+ comparison = OptimizerComparison(search_space, evaluator, budget, num_runs)
420
+
421
+ for name, optimizer in optimizers.items():
422
+ comparison.add_optimizer(name, optimizer)
423
+
424
+ results = comparison.run()
425
+
426
+ if plot:
427
+ comparison.plot_comparison()
428
+ comparison.plot_convergence()
429
+
430
+ return results
@@ -0,0 +1,56 @@
1
+ """Benchmark suite for NAS optimizers."""
2
+
3
+ from morphml.benchmarks.comparator import ConvergenceAnalyzer, OptimizerComparator
4
+
5
+ # Phase 2: Extended benchmarking
6
+ from morphml.benchmarks.datasets import DatasetLoader, get_dataset_info
7
+ from morphml.benchmarks.metrics import (
8
+ compare_optimizers,
9
+ compute_all_metrics,
10
+ convergence_rate,
11
+ final_best_fitness,
12
+ sample_efficiency,
13
+ )
14
+ from morphml.benchmarks.problems import (
15
+ ComplexProblem,
16
+ ConstrainedProblem,
17
+ MultiModalProblem,
18
+ SimpleProblem,
19
+ get_all_problems,
20
+ )
21
+ from morphml.benchmarks.suite import BenchmarkResult, BenchmarkSuite
22
+
23
+ # OpenML integration (optional)
24
+ try:
25
+ from morphml.benchmarks.openml_suite import OpenMLSuite, run_openml_benchmark
26
+
27
+ _OPENML_AVAILABLE = True
28
+ except ImportError:
29
+ OpenMLSuite = None
30
+ run_openml_benchmark = None
31
+ _OPENML_AVAILABLE = False
32
+
33
+ __all__ = [
34
+ # Core
35
+ "BenchmarkSuite",
36
+ "BenchmarkResult",
37
+ "OptimizerComparator",
38
+ "ConvergenceAnalyzer",
39
+ "SimpleProblem",
40
+ "ComplexProblem",
41
+ "MultiModalProblem",
42
+ "ConstrainedProblem",
43
+ "get_all_problems",
44
+ # Phase 2: Datasets
45
+ "DatasetLoader",
46
+ "get_dataset_info",
47
+ # Phase 2: Metrics
48
+ "sample_efficiency",
49
+ "convergence_rate",
50
+ "final_best_fitness",
51
+ "compute_all_metrics",
52
+ "compare_optimizers",
53
+ # Phase 2: OpenML (if available)
54
+ "OpenMLSuite",
55
+ "run_openml_benchmark",
56
+ ]