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,81 @@
1
+ """Example custom evaluator plugin.
2
+
3
+ Demonstrates how to create a custom evaluator plugin for MorphML.
4
+
5
+ Usage:
6
+ >>> from morphml.plugins import PluginManager
7
+ >>> manager = PluginManager()
8
+ >>> plugin = manager.load_plugin_from_file(
9
+ ... 'morphml/plugins/custom_evaluator_example.py',
10
+ ... config={'latency_weight': 0.5}
11
+ ... )
12
+ >>> fitness = plugin.evaluate(architecture)
13
+ """
14
+
15
+ from morphml.core.graph import ModelGraph
16
+ from morphml.plugins import EvaluatorPlugin
17
+
18
+
19
+ class Plugin(EvaluatorPlugin):
20
+ """
21
+ Example plugin: Multi-objective evaluator combining accuracy and latency.
22
+
23
+ This plugin demonstrates how to:
24
+ 1. Inherit from EvaluatorPlugin
25
+ 2. Implement custom evaluation logic
26
+ 3. Combine multiple objectives
27
+ """
28
+
29
+ def initialize(self, config):
30
+ """
31
+ Initialize plugin with configuration.
32
+
33
+ Args:
34
+ config: Configuration dictionary with keys:
35
+ - latency_weight: Weight for latency objective (default: 0.3)
36
+ - accuracy_weight: Weight for accuracy objective (default: 0.7)
37
+ """
38
+ self.latency_weight = config.get("latency_weight", 0.3)
39
+ self.accuracy_weight = config.get("accuracy_weight", 0.7)
40
+
41
+ # Normalize weights
42
+ total = self.latency_weight + self.accuracy_weight
43
+ self.latency_weight /= total
44
+ self.accuracy_weight /= total
45
+
46
+ print("Initialized Multi-Objective Evaluator plugin:")
47
+ print(f" Accuracy weight: {self.accuracy_weight:.2f}")
48
+ print(f" Latency weight: {self.latency_weight:.2f}")
49
+
50
+ def evaluate(self, architecture: ModelGraph) -> float:
51
+ """
52
+ Evaluate architecture with multi-objective fitness.
53
+
54
+ Combines estimated accuracy and latency into single fitness score.
55
+
56
+ Args:
57
+ architecture: ModelGraph to evaluate
58
+
59
+ Returns:
60
+ Combined fitness score (0-1, higher is better)
61
+ """
62
+ # Estimate accuracy (simplified)
63
+ depth = architecture.estimate_depth()
64
+ width = architecture.estimate_width()
65
+ params = architecture.estimate_parameters()
66
+
67
+ # Heuristic accuracy estimate
68
+ accuracy_score = min(1.0, (depth * width) / 1000.0)
69
+
70
+ # Estimate latency (inverse of parameters, normalized)
71
+ # Lower parameters = lower latency = higher score
72
+ latency_score = 1.0 / (1.0 + params / 1000000.0)
73
+
74
+ # Combine objectives
75
+ fitness = self.accuracy_weight * accuracy_score + self.latency_weight * latency_score
76
+
77
+ return fitness
78
+
79
+ def cleanup(self):
80
+ """Cleanup when plugin is unloaded."""
81
+ print("Multi-Objective Evaluator plugin unloaded")
@@ -0,0 +1,63 @@
1
+ """Example custom optimizer plugin.
2
+
3
+ Demonstrates how to create a custom optimizer plugin for MorphML.
4
+
5
+ Usage:
6
+ >>> from morphml.plugins import PluginManager
7
+ >>> manager = PluginManager()
8
+ >>> plugin = manager.load_plugin_from_file(
9
+ ... 'morphml/plugins/custom_optimizer_example.py',
10
+ ... config={'temperature': 100.0, 'cooling_rate': 0.95}
11
+ ... )
12
+ >>> optimizer = plugin.get_optimizer()
13
+ """
14
+
15
+ from morphml.optimizers.simulated_annealing import SimulatedAnnealing
16
+ from morphml.plugins import OptimizerPlugin
17
+
18
+
19
+ class Plugin(OptimizerPlugin):
20
+ """
21
+ Example plugin: Simulated Annealing optimizer with custom configuration.
22
+
23
+ This plugin demonstrates how to:
24
+ 1. Inherit from OptimizerPlugin
25
+ 2. Initialize with custom configuration
26
+ 3. Return a configured optimizer instance
27
+ """
28
+
29
+ def initialize(self, config):
30
+ """
31
+ Initialize plugin with configuration.
32
+
33
+ Args:
34
+ config: Configuration dictionary with keys:
35
+ - temperature: Initial temperature (default: 100.0)
36
+ - cooling_rate: Cooling rate (default: 0.95)
37
+ - max_iterations: Maximum iterations (default: 1000)
38
+ """
39
+ self.temperature = config.get("temperature", 100.0)
40
+ self.cooling_rate = config.get("cooling_rate", 0.95)
41
+ self.max_iterations = config.get("max_iterations", 1000)
42
+
43
+ print("Initialized SimulatedAnnealing plugin:")
44
+ print(f" Temperature: {self.temperature}")
45
+ print(f" Cooling rate: {self.cooling_rate}")
46
+ print(f" Max iterations: {self.max_iterations}")
47
+
48
+ def get_optimizer(self):
49
+ """
50
+ Return configured SimulatedAnnealing optimizer.
51
+
52
+ Returns:
53
+ SimulatedAnnealing instance
54
+ """
55
+ return SimulatedAnnealing(
56
+ temperature=self.temperature,
57
+ cooling_rate=self.cooling_rate,
58
+ max_iterations=self.max_iterations,
59
+ )
60
+
61
+ def cleanup(self):
62
+ """Cleanup when plugin is unloaded."""
63
+ print("SimulatedAnnealing plugin unloaded")
@@ -0,0 +1,454 @@
1
+ """Plugin system implementation for MorphML.
2
+
3
+ Provides base classes and plugin manager for extending MorphML functionality.
4
+
5
+ Example:
6
+ >>> from morphml.plugins import PluginManager, OptimizerPlugin
7
+ >>>
8
+ >>> class MyPlugin(OptimizerPlugin):
9
+ ... def initialize(self, config):
10
+ ... self.config = config
11
+ ...
12
+ ... def get_optimizer(self):
13
+ ... return MyCustomOptimizer(self.config)
14
+ >>>
15
+ >>> manager = PluginManager()
16
+ >>> manager.register_plugin('my_optimizer', MyPlugin)
17
+ >>> plugin = manager.load_plugin('my_optimizer', config={})
18
+ """
19
+
20
+ import importlib
21
+ import importlib.util
22
+ from abc import ABC, abstractmethod
23
+ from pathlib import Path
24
+ from typing import Any, Dict, List, Optional, Type
25
+
26
+ from morphml.logging_config import get_logger
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ class Plugin(ABC):
32
+ """
33
+ Base class for all MorphML plugins.
34
+
35
+ All plugins must inherit from this class and implement
36
+ the required methods.
37
+
38
+ Example:
39
+ >>> class MyPlugin(Plugin):
40
+ ... def initialize(self, config):
41
+ ... self.config = config
42
+ ...
43
+ ... def execute(self, context):
44
+ ... return self.config['value'] * 2
45
+ """
46
+
47
+ @abstractmethod
48
+ def initialize(self, config: Dict[str, Any]):
49
+ """
50
+ Initialize plugin with configuration.
51
+
52
+ Args:
53
+ config: Plugin configuration dictionary
54
+ """
55
+ pass
56
+
57
+ @abstractmethod
58
+ def execute(self, context: Dict[str, Any]) -> Any:
59
+ """
60
+ Execute plugin logic.
61
+
62
+ Args:
63
+ context: Execution context with relevant data
64
+
65
+ Returns:
66
+ Plugin execution result
67
+ """
68
+ pass
69
+
70
+ def cleanup(self):
71
+ """Optional cleanup method called when plugin is unloaded."""
72
+ pass
73
+
74
+
75
+ class OptimizerPlugin(Plugin):
76
+ """
77
+ Plugin for custom optimizers.
78
+
79
+ Allows users to add custom optimization algorithms.
80
+
81
+ Example:
82
+ >>> class SimulatedAnnealingPlugin(OptimizerPlugin):
83
+ ... def initialize(self, config):
84
+ ... self.temperature = config.get('temperature', 100.0)
85
+ ...
86
+ ... def get_optimizer(self):
87
+ ... return SimulatedAnnealing(temperature=self.temperature)
88
+ """
89
+
90
+ @abstractmethod
91
+ def get_optimizer(self):
92
+ """
93
+ Return optimizer instance.
94
+
95
+ Returns:
96
+ Optimizer instance (subclass of BaseOptimizer)
97
+ """
98
+ pass
99
+
100
+ def execute(self, context: Dict[str, Any]):
101
+ """Execute returns the optimizer."""
102
+ return self.get_optimizer()
103
+
104
+
105
+ class EvaluatorPlugin(Plugin):
106
+ """
107
+ Plugin for custom evaluation metrics.
108
+
109
+ Allows users to define custom architecture evaluation functions.
110
+
111
+ Example:
112
+ >>> class LatencyEvaluatorPlugin(EvaluatorPlugin):
113
+ ... def evaluate(self, architecture):
114
+ ... return estimate_latency(architecture)
115
+ """
116
+
117
+ @abstractmethod
118
+ def evaluate(self, architecture) -> float:
119
+ """
120
+ Evaluate architecture.
121
+
122
+ Args:
123
+ architecture: ModelGraph to evaluate
124
+
125
+ Returns:
126
+ Fitness score
127
+ """
128
+ pass
129
+
130
+ def execute(self, context: Dict[str, Any]) -> float:
131
+ """Execute evaluation."""
132
+ return self.evaluate(context.get("architecture"))
133
+
134
+
135
+ class MutationPlugin(Plugin):
136
+ """
137
+ Plugin for custom mutation operators.
138
+
139
+ Allows users to define custom mutation strategies.
140
+
141
+ Example:
142
+ >>> class LayerSwapMutationPlugin(MutationPlugin):
143
+ ... def mutate(self, architecture):
144
+ ... # Swap two random layers
145
+ ... return mutated_architecture
146
+ """
147
+
148
+ @abstractmethod
149
+ def mutate(self, architecture):
150
+ """
151
+ Mutate architecture.
152
+
153
+ Args:
154
+ architecture: ModelGraph to mutate
155
+
156
+ Returns:
157
+ Mutated ModelGraph
158
+ """
159
+ pass
160
+
161
+ def execute(self, context: Dict[str, Any]):
162
+ """Execute mutation."""
163
+ return self.mutate(context.get("architecture"))
164
+
165
+
166
+ class ObjectivePlugin(Plugin):
167
+ """
168
+ Plugin for custom objectives in multi-objective optimization.
169
+
170
+ Example:
171
+ >>> class EnergyObjectivePlugin(ObjectivePlugin):
172
+ ... def compute(self, architecture):
173
+ ... return estimate_energy_consumption(architecture)
174
+ """
175
+
176
+ @abstractmethod
177
+ def compute(self, architecture) -> float:
178
+ """
179
+ Compute objective value.
180
+
181
+ Args:
182
+ architecture: ModelGraph
183
+
184
+ Returns:
185
+ Objective value
186
+ """
187
+ pass
188
+
189
+ def execute(self, context: Dict[str, Any]) -> float:
190
+ """Execute objective computation."""
191
+ return self.compute(context.get("architecture"))
192
+
193
+
194
+ class VisualizationPlugin(Plugin):
195
+ """
196
+ Plugin for custom visualizations.
197
+
198
+ Example:
199
+ >>> class CustomPlotPlugin(VisualizationPlugin):
200
+ ... def visualize(self, data):
201
+ ... # Create custom plot
202
+ ... return figure
203
+ """
204
+
205
+ @abstractmethod
206
+ def visualize(self, data: Any):
207
+ """
208
+ Create visualization.
209
+
210
+ Args:
211
+ data: Data to visualize
212
+
213
+ Returns:
214
+ Visualization object (e.g., matplotlib Figure)
215
+ """
216
+ pass
217
+
218
+ def execute(self, context: Dict[str, Any]):
219
+ """Execute visualization."""
220
+ return self.visualize(context.get("data"))
221
+
222
+
223
+ class PluginManager:
224
+ """
225
+ Manage and load plugins.
226
+
227
+ Supports loading plugins from:
228
+ - Built-in morphml.plugins module
229
+ - External Python files
230
+ - Installed packages with entry points
231
+
232
+ Example:
233
+ >>> manager = PluginManager()
234
+ >>> manager.register_plugin('my_optimizer', MyOptimizerPlugin)
235
+ >>> plugin = manager.load_plugin('my_optimizer', config={'lr': 0.01})
236
+ >>> optimizer = plugin.get_optimizer()
237
+ """
238
+
239
+ def __init__(self):
240
+ """Initialize plugin manager."""
241
+ self.plugins: Dict[str, Plugin] = {}
242
+ self.plugin_classes: Dict[str, Type[Plugin]] = {}
243
+ logger.info("Initialized PluginManager")
244
+
245
+ def register_plugin(self, name: str, plugin_class: Type[Plugin]):
246
+ """
247
+ Register a plugin class.
248
+
249
+ Args:
250
+ name: Plugin name
251
+ plugin_class: Plugin class (subclass of Plugin)
252
+
253
+ Example:
254
+ >>> manager.register_plugin('my_plugin', MyPlugin)
255
+ """
256
+ if not issubclass(plugin_class, Plugin):
257
+ raise TypeError(f"{plugin_class} must be a subclass of Plugin")
258
+
259
+ self.plugin_classes[name] = plugin_class
260
+ logger.info(f"Registered plugin class: {name}")
261
+
262
+ def load_plugin(self, name: str, config: Optional[Dict[str, Any]] = None) -> Plugin:
263
+ """
264
+ Load and initialize a plugin.
265
+
266
+ Args:
267
+ name: Plugin name
268
+ config: Plugin configuration
269
+
270
+ Returns:
271
+ Initialized plugin instance
272
+
273
+ Example:
274
+ >>> plugin = manager.load_plugin('my_plugin', {'param': 'value'})
275
+ """
276
+ if name in self.plugins:
277
+ logger.warning(f"Plugin {name} already loaded, returning existing instance")
278
+ return self.plugins[name]
279
+
280
+ # Try registered plugins first
281
+ if name in self.plugin_classes:
282
+ plugin_class = self.plugin_classes[name]
283
+ else:
284
+ # Try loading from morphml.plugins module
285
+ plugin_class = self._load_plugin_from_module(name)
286
+
287
+ if plugin_class is None:
288
+ raise ValueError(f"Plugin {name} not found")
289
+
290
+ # Initialize plugin
291
+ plugin = plugin_class()
292
+ plugin.initialize(config or {})
293
+
294
+ self.plugins[name] = plugin
295
+ logger.info(f"Loaded plugin: {name}")
296
+
297
+ return plugin
298
+
299
+ def _load_plugin_from_module(self, name: str) -> Optional[Type[Plugin]]:
300
+ """
301
+ Load plugin from morphml.plugins module.
302
+
303
+ Args:
304
+ name: Plugin name
305
+
306
+ Returns:
307
+ Plugin class or None
308
+ """
309
+ try:
310
+ module = importlib.import_module(f"morphml.plugins.{name}")
311
+
312
+ # Look for Plugin class
313
+ if hasattr(module, "Plugin"):
314
+ return module.Plugin
315
+
316
+ # Look for class with matching name
317
+ class_name = "".join(word.capitalize() for word in name.split("_"))
318
+ if hasattr(module, class_name):
319
+ return getattr(module, class_name)
320
+
321
+ logger.warning(f"No Plugin class found in morphml.plugins.{name}")
322
+ return None
323
+
324
+ except ImportError as e:
325
+ logger.debug(f"Could not import morphml.plugins.{name}: {e}")
326
+ return None
327
+
328
+ def load_plugin_from_file(
329
+ self, filepath: str, name: Optional[str] = None, config: Optional[Dict[str, Any]] = None
330
+ ) -> Plugin:
331
+ """
332
+ Load plugin from Python file.
333
+
334
+ Args:
335
+ filepath: Path to Python file
336
+ name: Optional plugin name (defaults to filename)
337
+ config: Plugin configuration
338
+
339
+ Returns:
340
+ Initialized plugin instance
341
+
342
+ Example:
343
+ >>> plugin = manager.load_plugin_from_file(
344
+ ... 'my_plugin.py',
345
+ ... name='my_plugin',
346
+ ... config={'param': 'value'}
347
+ ... )
348
+ """
349
+ path = Path(filepath)
350
+
351
+ if not path.exists():
352
+ raise FileNotFoundError(f"Plugin file not found: {filepath}")
353
+
354
+ # Use filename as plugin name if not provided
355
+ if name is None:
356
+ name = path.stem
357
+
358
+ # Load module from file
359
+ spec = importlib.util.spec_from_file_location(name, filepath)
360
+ if spec is None or spec.loader is None:
361
+ raise ImportError(f"Could not load module from {filepath}")
362
+
363
+ module = importlib.util.module_from_spec(spec)
364
+ spec.loader.exec_module(module)
365
+
366
+ # Find Plugin class
367
+ if hasattr(module, "Plugin"):
368
+ plugin_class = module.Plugin
369
+ else:
370
+ raise AttributeError(f"No Plugin class found in {filepath}")
371
+
372
+ # Initialize and register
373
+ plugin = plugin_class()
374
+ plugin.initialize(config or {})
375
+
376
+ self.plugins[name] = plugin
377
+ logger.info(f"Loaded plugin from file: {filepath}")
378
+
379
+ return plugin
380
+
381
+ def get_plugin(self, name: str) -> Optional[Plugin]:
382
+ """
383
+ Get loaded plugin by name.
384
+
385
+ Args:
386
+ name: Plugin name
387
+
388
+ Returns:
389
+ Plugin instance or None
390
+
391
+ Example:
392
+ >>> plugin = manager.get_plugin('my_plugin')
393
+ """
394
+ return self.plugins.get(name)
395
+
396
+ def unload_plugin(self, name: str):
397
+ """
398
+ Unload a plugin.
399
+
400
+ Args:
401
+ name: Plugin name
402
+
403
+ Example:
404
+ >>> manager.unload_plugin('my_plugin')
405
+ """
406
+ if name in self.plugins:
407
+ plugin = self.plugins[name]
408
+ plugin.cleanup()
409
+ del self.plugins[name]
410
+ logger.info(f"Unloaded plugin: {name}")
411
+
412
+ def list_plugins(self) -> List[str]:
413
+ """
414
+ List all loaded plugins.
415
+
416
+ Returns:
417
+ List of plugin names
418
+
419
+ Example:
420
+ >>> plugins = manager.list_plugins()
421
+ >>> print(plugins)
422
+ ['optimizer_plugin', 'evaluator_plugin']
423
+ """
424
+ return list(self.plugins.keys())
425
+
426
+ def list_registered_classes(self) -> List[str]:
427
+ """
428
+ List all registered plugin classes.
429
+
430
+ Returns:
431
+ List of registered class names
432
+ """
433
+ return list(self.plugin_classes.keys())
434
+
435
+
436
+ # Global plugin manager instance
437
+ _global_manager = None
438
+
439
+
440
+ def get_plugin_manager() -> PluginManager:
441
+ """
442
+ Get global plugin manager instance.
443
+
444
+ Returns:
445
+ Global PluginManager instance
446
+
447
+ Example:
448
+ >>> manager = get_plugin_manager()
449
+ >>> manager.load_plugin('my_plugin')
450
+ """
451
+ global _global_manager
452
+ if _global_manager is None:
453
+ _global_manager = PluginManager()
454
+ return _global_manager
@@ -0,0 +1,30 @@
1
+ """Report generation tools.
2
+
3
+ This module provides tools to generate comprehensive HTML reports
4
+ for neural architecture search experiments.
5
+
6
+ Example:
7
+ >>> from morphml.reports import ReportGenerator, create_comparison_report
8
+ >>>
9
+ >>> # Quick report
10
+ >>> create_comparison_report(
11
+ ... "My Experiment",
12
+ ... comparison_results,
13
+ ... "report.html"
14
+ ... )
15
+
16
+ >>> # Custom report
17
+ >>> generator = ReportGenerator("Custom Report")
18
+ >>> generator.add_section("Results", content)
19
+ >>> generator.generate("custom_report.html")
20
+ """
21
+
22
+ from morphml.reports.generator import (
23
+ ReportGenerator,
24
+ create_comparison_report,
25
+ )
26
+
27
+ __all__ = [
28
+ "ReportGenerator",
29
+ "create_comparison_report",
30
+ ]