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,361 @@
1
+ """Serialization utilities for model graphs.
2
+
3
+ Provides functions to save and load ModelGraph objects in various formats:
4
+ - JSON: Human-readable, good for inspection
5
+ - Pickle: Python-native, preserves exact state
6
+ - YAML: Configuration-friendly format
7
+
8
+ Author: Eshan Roy <eshanized@proton.me>
9
+ Organization: TONMOY INFRASTRUCTURE & VISION
10
+ """
11
+
12
+ import json
13
+ import pickle
14
+ from pathlib import Path
15
+ from typing import Any, Dict, Optional, Union
16
+
17
+ from morphml.core.graph.graph import ModelGraph
18
+ from morphml.exceptions import GraphError
19
+ from morphml.logging_config import get_logger
20
+
21
+ logger = get_logger(__name__)
22
+
23
+
24
+ def save_graph(
25
+ graph: ModelGraph,
26
+ path: Union[str, Path],
27
+ format: str = "json",
28
+ indent: int = 2,
29
+ metadata: Optional[Dict[str, Any]] = None,
30
+ ) -> None:
31
+ """
32
+ Save model graph to file.
33
+
34
+ Args:
35
+ graph: ModelGraph to save
36
+ path: Output file path
37
+ format: Format ('json', 'pickle', 'yaml')
38
+ indent: JSON indentation (for readability)
39
+ metadata: Additional metadata to save with graph
40
+
41
+ Raises:
42
+ GraphError: If save fails
43
+
44
+ Example:
45
+ >>> graph = ModelGraph()
46
+ >>> save_graph(graph, 'model.json')
47
+ >>> save_graph(graph, 'model.pkl', format='pickle')
48
+ """
49
+ path = Path(path)
50
+ path.parent.mkdir(parents=True, exist_ok=True)
51
+
52
+ try:
53
+ if format == "json":
54
+ _save_json(graph, path, indent, metadata)
55
+ elif format == "pickle":
56
+ _save_pickle(graph, path, metadata)
57
+ elif format == "yaml":
58
+ _save_yaml(graph, path, metadata)
59
+ else:
60
+ raise GraphError(f"Unknown format: {format}. Use 'json', 'pickle', or 'yaml'")
61
+
62
+ logger.info(f"Saved graph to {path} (format: {format})")
63
+
64
+ except Exception as e:
65
+ logger.error(f"Failed to save graph: {e}")
66
+ raise GraphError(f"Failed to save graph to {path}: {e}") from e
67
+
68
+
69
+ def load_graph(path: Union[str, Path], format: Optional[str] = None) -> ModelGraph:
70
+ """
71
+ Load model graph from file.
72
+
73
+ Args:
74
+ path: Input file path
75
+ format: Format ('json', 'pickle', 'yaml'). If None, infers from extension
76
+
77
+ Returns:
78
+ Loaded ModelGraph
79
+
80
+ Raises:
81
+ GraphError: If load fails
82
+
83
+ Example:
84
+ >>> graph = load_graph('model.json')
85
+ >>> graph = load_graph('model.pkl', format='pickle')
86
+ """
87
+ path = Path(path)
88
+
89
+ if not path.exists():
90
+ raise GraphError(f"File not found: {path}")
91
+
92
+ # Infer format from extension if not specified
93
+ if format is None:
94
+ format = _infer_format(path)
95
+
96
+ try:
97
+ if format == "json":
98
+ graph = _load_json(path)
99
+ elif format == "pickle":
100
+ graph = _load_pickle(path)
101
+ elif format == "yaml":
102
+ graph = _load_yaml(path)
103
+ else:
104
+ raise GraphError(f"Unknown format: {format}")
105
+
106
+ logger.info(f"Loaded graph from {path} (format: {format})")
107
+ return graph
108
+
109
+ except Exception as e:
110
+ logger.error(f"Failed to load graph: {e}")
111
+ raise GraphError(f"Failed to load graph from {path}: {e}") from e
112
+
113
+
114
+ def _save_json(
115
+ graph: ModelGraph, path: Path, indent: int, metadata: Optional[Dict[str, Any]]
116
+ ) -> None:
117
+ """Save graph as JSON."""
118
+ data = graph.to_dict()
119
+
120
+ # Add metadata if provided
121
+ if metadata:
122
+ data["_metadata"] = metadata
123
+
124
+ with open(path, "w") as f:
125
+ json.dump(data, f, indent=indent, sort_keys=False)
126
+
127
+
128
+ def _load_json(path: Path) -> ModelGraph:
129
+ """Load graph from JSON."""
130
+ with open(path, "r") as f:
131
+ data = json.load(f)
132
+
133
+ # Remove metadata if present
134
+ data.pop("_metadata", None)
135
+
136
+ return ModelGraph.from_dict(data)
137
+
138
+
139
+ def _save_pickle(graph: ModelGraph, path: Path, metadata: Optional[Dict[str, Any]]) -> None:
140
+ """Save graph as pickle."""
141
+ data = {"graph": graph, "metadata": metadata}
142
+
143
+ with open(path, "wb") as f:
144
+ pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
145
+
146
+
147
+ def _load_pickle(path: Path) -> ModelGraph:
148
+ """Load graph from pickle."""
149
+ with open(path, "rb") as f:
150
+ data = pickle.load(f)
151
+
152
+ # Handle both old and new formats
153
+ if isinstance(data, ModelGraph):
154
+ return data
155
+ elif isinstance(data, dict) and "graph" in data:
156
+ return data["graph"]
157
+ else:
158
+ raise GraphError("Invalid pickle format")
159
+
160
+
161
+ def _save_yaml(graph: ModelGraph, path: Path, metadata: Optional[Dict[str, Any]]) -> None:
162
+ """Save graph as YAML."""
163
+ try:
164
+ import yaml
165
+ except ImportError:
166
+ raise GraphError("PyYAML not installed. Install with: pip install pyyaml")
167
+
168
+ data = graph.to_dict()
169
+
170
+ # Add metadata if provided
171
+ if metadata:
172
+ data["_metadata"] = metadata
173
+
174
+ with open(path, "w") as f:
175
+ yaml.dump(data, f, default_flow_style=False, sort_keys=False)
176
+
177
+
178
+ def _load_yaml(path: Path) -> ModelGraph:
179
+ """Load graph from YAML."""
180
+ try:
181
+ import yaml
182
+ except ImportError:
183
+ raise GraphError("PyYAML not installed. Install with: pip install pyyaml")
184
+
185
+ with open(path, "r") as f:
186
+ data = yaml.safe_load(f)
187
+
188
+ # Remove metadata if present
189
+ data.pop("_metadata", None)
190
+
191
+ return ModelGraph.from_dict(data)
192
+
193
+
194
+ def _infer_format(path: Path) -> str:
195
+ """Infer format from file extension."""
196
+ suffix = path.suffix.lower()
197
+
198
+ format_map = {
199
+ ".json": "json",
200
+ ".pkl": "pickle",
201
+ ".pickle": "pickle",
202
+ ".yaml": "yaml",
203
+ ".yml": "yaml",
204
+ }
205
+
206
+ format = format_map.get(suffix)
207
+ if format is None:
208
+ logger.warning(f"Unknown extension {suffix}, assuming JSON")
209
+ return "json"
210
+
211
+ return format
212
+
213
+
214
+ def graph_to_json_string(graph: ModelGraph, indent: int = 2) -> str:
215
+ """
216
+ Convert graph to JSON string.
217
+
218
+ Args:
219
+ graph: ModelGraph to convert
220
+ indent: Indentation level
221
+
222
+ Returns:
223
+ JSON string representation
224
+
225
+ Example:
226
+ >>> json_str = graph_to_json_string(graph)
227
+ >>> print(json_str)
228
+ """
229
+ return json.dumps(graph.to_dict(), indent=indent, sort_keys=False)
230
+
231
+
232
+ def graph_from_json_string(json_str: str) -> ModelGraph:
233
+ """
234
+ Create graph from JSON string.
235
+
236
+ Args:
237
+ json_str: JSON string representation
238
+
239
+ Returns:
240
+ ModelGraph instance
241
+
242
+ Example:
243
+ >>> graph = graph_from_json_string(json_str)
244
+ """
245
+ data = json.loads(json_str)
246
+ return ModelGraph.from_dict(data)
247
+
248
+
249
+ def export_graph_summary(graph: ModelGraph, path: Union[str, Path]) -> None:
250
+ """
251
+ Export human-readable graph summary.
252
+
253
+ Creates a text file with graph statistics and structure.
254
+
255
+ Args:
256
+ graph: ModelGraph to summarize
257
+ path: Output file path
258
+
259
+ Example:
260
+ >>> export_graph_summary(graph, 'model_summary.txt')
261
+ """
262
+ path = Path(path)
263
+ path.parent.mkdir(parents=True, exist_ok=True)
264
+
265
+ lines = []
266
+ lines.append("=" * 60)
267
+ lines.append("MODEL GRAPH SUMMARY")
268
+ lines.append("=" * 60)
269
+ lines.append("")
270
+
271
+ # Basic info
272
+ lines.append(f"Nodes: {len(graph.nodes)}")
273
+ lines.append(f"Edges: {len(graph.edges)}")
274
+ lines.append(f"Depth: {graph.get_depth()}")
275
+ lines.append(f"Width: {graph.get_max_width()}")
276
+ lines.append(f"Params: {graph.estimate_parameters():,}")
277
+ lines.append("")
278
+
279
+ # Nodes
280
+ lines.append("NODES:")
281
+ lines.append("-" * 60)
282
+ for node_id, node in graph.nodes.items():
283
+ lines.append(f" {node_id[:8]}... | {node.operation:15s} | {node.params}")
284
+
285
+ lines.append("")
286
+
287
+ # Edges
288
+ lines.append("EDGES:")
289
+ lines.append("-" * 60)
290
+ for _edge_id, edge in graph.edges.items():
291
+ src = edge.source.id[:8] if edge.source else "None"
292
+ tgt = edge.target.id[:8] if edge.target else "None"
293
+ lines.append(f" {src}... -> {tgt}...")
294
+
295
+ lines.append("")
296
+ lines.append("=" * 60)
297
+
298
+ with open(path, "w") as f:
299
+ f.write("\n".join(lines))
300
+
301
+ logger.info(f"Exported graph summary to {path}")
302
+
303
+
304
+ def batch_save_graphs(
305
+ graphs: Dict[str, ModelGraph], output_dir: Union[str, Path], format: str = "json"
306
+ ) -> None:
307
+ """
308
+ Save multiple graphs to directory.
309
+
310
+ Args:
311
+ graphs: Dictionary mapping names to graphs
312
+ output_dir: Output directory
313
+ format: Save format
314
+
315
+ Example:
316
+ >>> graphs = {'model1': graph1, 'model2': graph2}
317
+ >>> batch_save_graphs(graphs, 'models/', format='json')
318
+ """
319
+ output_dir = Path(output_dir)
320
+ output_dir.mkdir(parents=True, exist_ok=True)
321
+
322
+ for name, graph in graphs.items():
323
+ ext = {"json": ".json", "pickle": ".pkl", "yaml": ".yaml"}[format]
324
+ path = output_dir / f"{name}{ext}"
325
+ save_graph(graph, path, format=format)
326
+
327
+ logger.info(f"Saved {len(graphs)} graphs to {output_dir}")
328
+
329
+
330
+ def batch_load_graphs(
331
+ input_dir: Union[str, Path], format: Optional[str] = None
332
+ ) -> Dict[str, ModelGraph]:
333
+ """
334
+ Load all graphs from directory.
335
+
336
+ Args:
337
+ input_dir: Input directory
338
+ format: Load format (None to infer from extensions)
339
+
340
+ Returns:
341
+ Dictionary mapping filenames to graphs
342
+
343
+ Example:
344
+ >>> graphs = batch_load_graphs('models/')
345
+ """
346
+ input_dir = Path(input_dir)
347
+
348
+ if not input_dir.exists():
349
+ raise GraphError(f"Directory not found: {input_dir}")
350
+
351
+ graphs = {}
352
+
353
+ # Find all graph files
354
+ patterns = ["*.json", "*.pkl", "*.pickle", "*.yaml", "*.yml"]
355
+ for pattern in patterns:
356
+ for path in input_dir.glob(pattern):
357
+ name = path.stem
358
+ graphs[name] = load_graph(path, format=format)
359
+
360
+ logger.info(f"Loaded {len(graphs)} graphs from {input_dir}")
361
+ return graphs