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,386 @@
1
+ """Search space definition using the MorphML DSL.
2
+
3
+ This module provides the SearchSpace class for defining neural architecture
4
+ search spaces in a Pythonic way.
5
+
6
+ Example:
7
+ >>> from morphml.core.dsl import SearchSpace, Layer
8
+ >>>
9
+ >>> # Define search space
10
+ >>> space = SearchSpace(name="cifar10_cnn")
11
+ >>>
12
+ >>> # Add layers
13
+ >>> space.add_layer(Layer.input(shape=(3, 32, 32)))
14
+ >>> space.add_layer(Layer.conv2d(filters=[32, 64], kernel_size=[3, 5]))
15
+ >>> space.add_layer(Layer.relu())
16
+ >>> space.add_layer(Layer.maxpool(pool_size=2))
17
+ >>> space.add_layer(Layer.dense(units=[128, 256, 512]))
18
+ >>> space.add_layer(Layer.output(units=10))
19
+ >>>
20
+ >>> # Sample architectures
21
+ >>> arch1 = space.sample()
22
+ >>> arch2 = space.sample()
23
+ """
24
+
25
+ from typing import Any, Callable, Dict, List, Optional
26
+
27
+ from morphml.core.dsl.layers import LayerSpec
28
+ from morphml.core.graph import GraphEdge, ModelGraph
29
+ from morphml.exceptions import SearchSpaceError
30
+ from morphml.logging_config import get_logger
31
+
32
+ logger = get_logger(__name__)
33
+
34
+
35
+ class SearchSpace:
36
+ """
37
+ Defines a search space for neural architecture search.
38
+
39
+ A SearchSpace consists of:
40
+ - A sequence of layer specifications
41
+ - Constraints on valid architectures
42
+ - Metadata about the space
43
+
44
+ Architectures are sampled by:
45
+ 1. Sampling parameters for each layer
46
+ 2. Connecting layers sequentially
47
+ 3. Validating the resulting graph
48
+
49
+ Attributes:
50
+ name: Search space name
51
+ layers: List of layer specifications
52
+ constraints: List of constraint functions
53
+ metadata: Additional metadata
54
+
55
+ Example:
56
+ >>> space = SearchSpace("my_space")
57
+ >>> space.add_layer(Layer.conv2d(filters=[32, 64]))
58
+ >>> space.add_layer(Layer.dense(units=10))
59
+ >>> architecture = space.sample()
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ name: str = "search_space",
65
+ metadata: Optional[Dict[str, Any]] = None,
66
+ ):
67
+ """
68
+ Initialize search space.
69
+
70
+ Args:
71
+ name: Search space name
72
+ metadata: Optional metadata
73
+ """
74
+ self.name = name
75
+ self.layers: List[LayerSpec] = []
76
+ self.constraints: List[Callable[[ModelGraph], bool]] = []
77
+ self.metadata = metadata or {}
78
+
79
+ logger.debug(f"Created SearchSpace: {name}")
80
+
81
+ def add_layer(self, layer_spec: LayerSpec) -> "SearchSpace":
82
+ """
83
+ Add a layer specification to the search space.
84
+
85
+ Args:
86
+ layer_spec: Layer specification to add
87
+
88
+ Returns:
89
+ Self (for method chaining)
90
+
91
+ Example:
92
+ >>> space.add_layer(Layer.conv2d(filters=64))
93
+ >>> space.add_layer(Layer.relu())
94
+ """
95
+ self.layers.append(layer_spec)
96
+ logger.debug(f"Added layer: {layer_spec.operation}")
97
+ return self
98
+
99
+ def add_layers(self, *layer_specs: LayerSpec) -> "SearchSpace":
100
+ """
101
+ Add multiple layer specifications.
102
+
103
+ Args:
104
+ *layer_specs: Layer specifications to add
105
+
106
+ Returns:
107
+ Self (for method chaining)
108
+
109
+ Example:
110
+ >>> space.add_layers(
111
+ ... Layer.conv2d(filters=64),
112
+ ... Layer.relu(),
113
+ ... Layer.maxpool()
114
+ ... )
115
+ """
116
+ for layer_spec in layer_specs:
117
+ self.add_layer(layer_spec)
118
+ return self
119
+
120
+ def add_constraint(self, constraint_fn: Callable[[ModelGraph], bool]) -> "SearchSpace":
121
+ """
122
+ Add a constraint function.
123
+
124
+ Constraint functions should take a ModelGraph and return bool.
125
+
126
+ Args:
127
+ constraint_fn: Function that validates a graph
128
+
129
+ Returns:
130
+ Self (for method chaining)
131
+
132
+ Example:
133
+ >>> def max_depth(graph):
134
+ ... return graph.get_depth() <= 20
135
+ >>> space.add_constraint(max_depth)
136
+ """
137
+ self.constraints.append(constraint_fn)
138
+ return self
139
+
140
+ def sample(self, max_attempts: int = 100) -> ModelGraph:
141
+ """
142
+ Sample a random architecture from this search space.
143
+
144
+ Args:
145
+ max_attempts: Maximum sampling attempts before giving up
146
+
147
+ Returns:
148
+ Sampled ModelGraph
149
+
150
+ Raises:
151
+ SearchSpaceError: If unable to sample valid architecture
152
+
153
+ Example:
154
+ >>> arch = space.sample()
155
+ >>> print(arch)
156
+ """
157
+ for attempt in range(max_attempts):
158
+ try:
159
+ # Create graph
160
+ graph = ModelGraph(metadata={"search_space": self.name})
161
+
162
+ # Sample nodes from each layer spec
163
+ nodes = []
164
+ for layer_spec in self.layers:
165
+ node = layer_spec.sample()
166
+ graph.add_node(node)
167
+ nodes.append(node)
168
+
169
+ # Connect sequentially
170
+ for i in range(len(nodes) - 1):
171
+ edge = GraphEdge(nodes[i], nodes[i + 1])
172
+ graph.add_edge(edge)
173
+
174
+ # Validate
175
+ if not graph.is_valid():
176
+ logger.debug(f"Attempt {attempt + 1}: Invalid graph")
177
+ continue
178
+
179
+ # Check constraints
180
+ if not self._check_constraints(graph):
181
+ logger.debug(f"Attempt {attempt + 1}: Constraint violation")
182
+ continue
183
+
184
+ logger.debug(f"Successfully sampled architecture (attempt {attempt + 1})")
185
+ return graph
186
+
187
+ except Exception as e:
188
+ logger.debug(f"Attempt {attempt + 1} failed: {e}")
189
+ continue
190
+
191
+ raise SearchSpaceError(f"Failed to sample valid architecture after {max_attempts} attempts")
192
+
193
+ def sample_batch(self, batch_size: int, max_attempts: int = 100) -> List[ModelGraph]:
194
+ """
195
+ Sample multiple architectures.
196
+
197
+ Args:
198
+ batch_size: Number of architectures to sample
199
+ max_attempts: Max attempts per architecture
200
+
201
+ Returns:
202
+ List of sampled architectures
203
+
204
+ Example:
205
+ >>> architectures = space.sample_batch(10)
206
+ """
207
+ return [self.sample(max_attempts) for _ in range(batch_size)]
208
+
209
+ def _check_constraints(self, graph: ModelGraph) -> bool:
210
+ """
211
+ Check if graph satisfies all constraints.
212
+
213
+ Args:
214
+ graph: Graph to validate
215
+
216
+ Returns:
217
+ True if all constraints satisfied
218
+ """
219
+ for constraint_fn in self.constraints:
220
+ try:
221
+ if not constraint_fn(graph):
222
+ return False
223
+ except Exception as e:
224
+ logger.warning(f"Constraint check failed: {e}")
225
+ return False
226
+
227
+ return True
228
+
229
+ def get_complexity(self) -> Dict[str, Any]:
230
+ """
231
+ Estimate search space complexity.
232
+
233
+ Returns:
234
+ Dictionary with complexity metrics
235
+ """
236
+ total_combinations = 1
237
+ param_counts: Dict[str, int] = {}
238
+
239
+ for layer_spec in self.layers:
240
+ layer_combinations = 1
241
+ for param_name, values in layer_spec.param_ranges.items():
242
+ if isinstance(values, list):
243
+ layer_combinations *= len(values)
244
+ param_counts[param_name] = param_counts.get(param_name, 0) + len(values)
245
+
246
+ total_combinations *= layer_combinations
247
+
248
+ return {
249
+ "total_combinations": total_combinations,
250
+ "num_layers": len(self.layers),
251
+ "param_counts": param_counts,
252
+ }
253
+
254
+ def to_dict(self) -> Dict[str, Any]:
255
+ """Serialize search space to dictionary."""
256
+ return {
257
+ "name": self.name,
258
+ "layers": [layer.to_dict() for layer in self.layers],
259
+ "metadata": self.metadata,
260
+ }
261
+
262
+ @classmethod
263
+ def from_dict(cls, data: Dict[str, Any]) -> "SearchSpace":
264
+ """
265
+ Deserialize search space from dictionary.
266
+
267
+ Args:
268
+ data: Dictionary representation
269
+
270
+ Returns:
271
+ SearchSpace instance
272
+ """
273
+ space = cls(name=data["name"], metadata=data.get("metadata", {}))
274
+
275
+ for layer_data in data["layers"]:
276
+ layer_spec = LayerSpec.from_dict(layer_data)
277
+ space.add_layer(layer_spec)
278
+
279
+ return space
280
+
281
+ def __repr__(self) -> str:
282
+ """String representation."""
283
+ complexity = self.get_complexity()
284
+ return (
285
+ f"SearchSpace(name={self.name}, "
286
+ f"layers={len(self.layers)}, "
287
+ f"combinations={complexity['total_combinations']})"
288
+ )
289
+
290
+ def __len__(self) -> int:
291
+ """Return number of layers."""
292
+ return len(self.layers)
293
+
294
+
295
+ # Convenience functions
296
+ def create_cnn_space(
297
+ num_classes: int = 10,
298
+ input_shape: tuple = (3, 32, 32),
299
+ conv_filters: Optional[List[List[int]]] = None,
300
+ dense_units: Optional[List[List[int]]] = None,
301
+ ) -> SearchSpace:
302
+ """
303
+ Create a standard CNN search space.
304
+
305
+ Args:
306
+ num_classes: Number of output classes
307
+ input_shape: Input shape (C, H, W)
308
+ conv_filters: List of filter options for each conv layer
309
+ dense_units: List of unit options for each dense layer
310
+
311
+ Returns:
312
+ Configured SearchSpace
313
+
314
+ Example:
315
+ >>> space = create_cnn_space(
316
+ ... num_classes=10,
317
+ ... conv_filters=[[32, 64], [64, 128]],
318
+ ... dense_units=[[128, 256]]
319
+ ... )
320
+ """
321
+ from morphml.core.dsl.layers import Layer
322
+
323
+ conv_filters = conv_filters or [[32, 64, 128], [64, 128, 256]]
324
+ dense_units = dense_units or [[128, 256, 512]]
325
+
326
+ space = SearchSpace(name="cnn_space")
327
+
328
+ # Input
329
+ space.add_layer(Layer.input(shape=input_shape))
330
+
331
+ # Conv blocks
332
+ for filters in conv_filters:
333
+ space.add_layer(Layer.conv2d(filters=filters, kernel_size=[3, 5]))
334
+ space.add_layer(Layer.relu())
335
+ space.add_layer(Layer.maxpool(pool_size=2))
336
+
337
+ # Dense layers
338
+ for units in dense_units:
339
+ space.add_layer(Layer.dense(units=units))
340
+ space.add_layer(Layer.relu())
341
+ space.add_layer(Layer.dropout(rate=[0.3, 0.5]))
342
+
343
+ # Output
344
+ space.add_layer(Layer.output(units=num_classes))
345
+
346
+ return space
347
+
348
+
349
+ def create_mlp_space(
350
+ num_classes: int = 10,
351
+ input_shape: tuple = (784,),
352
+ hidden_layers: int = 3,
353
+ units_range: Optional[List[int]] = None,
354
+ ) -> SearchSpace:
355
+ """
356
+ Create a multi-layer perceptron search space.
357
+
358
+ Args:
359
+ num_classes: Number of output classes
360
+ input_shape: Input shape
361
+ hidden_layers: Number of hidden layers
362
+ units_range: Range of units per layer
363
+
364
+ Returns:
365
+ Configured SearchSpace
366
+ """
367
+ from morphml.core.dsl.layers import Layer
368
+
369
+ if units_range is None:
370
+ units_range = [128, 256, 512]
371
+
372
+ space = SearchSpace(name="mlp_space")
373
+
374
+ # Input
375
+ space.add_layer(Layer.input(shape=input_shape))
376
+
377
+ # Hidden layers
378
+ for _ in range(hidden_layers):
379
+ space.add_layer(Layer.dense(units=units_range))
380
+ space.add_layer(Layer.relu())
381
+ space.add_layer(Layer.dropout(rate=[0.3, 0.5]))
382
+
383
+ # Output
384
+ space.add_layer(Layer.output(units=num_classes))
385
+
386
+ return space
@@ -0,0 +1,199 @@
1
+ """Token definitions and grammar for MorphML DSL.
2
+
3
+ This module defines all tokens, keywords, and grammar rules for the
4
+ text-based DSL that allows users to define search spaces using a
5
+ declarative syntax.
6
+
7
+ Grammar (EBNF):
8
+ experiment := search_space_def evolution_def
9
+ search_space_def := "SearchSpace" "(" param_list ")"
10
+ layer_def := "Layer" "." layer_type "(" param_list ")"
11
+ param_list := param ("," param)*
12
+ param := IDENTIFIER "=" value_list
13
+ value_list := "[" value ("," value)* "]" | value
14
+ value := NUMBER | STRING | BOOLEAN | IDENTIFIER
15
+
16
+ Author: Eshan Roy <eshanized@proton.me>
17
+ Organization: TONMOY INFRASTRUCTURE & VISION
18
+ """
19
+
20
+ from enum import Enum, auto
21
+
22
+
23
+ class TokenType(Enum):
24
+ """All token types in the MorphML DSL."""
25
+
26
+ # Literals
27
+ NUMBER = auto()
28
+ STRING = auto()
29
+ BOOLEAN = auto()
30
+
31
+ # Identifiers and keywords
32
+ IDENTIFIER = auto()
33
+ SEARCHSPACE = auto()
34
+ LAYER = auto()
35
+ EVOLUTION = auto()
36
+ EXPERIMENT = auto()
37
+ CONSTRAINT = auto()
38
+
39
+ # Operators and delimiters
40
+ ASSIGN = auto()
41
+ COMMA = auto()
42
+ DOT = auto()
43
+ COLON = auto()
44
+ LPAREN = auto()
45
+ RPAREN = auto()
46
+ LBRACKET = auto()
47
+ RBRACKET = auto()
48
+ LBRACE = auto()
49
+ RBRACE = auto()
50
+
51
+ # Special
52
+ EOF = auto()
53
+ NEWLINE = auto()
54
+ COMMENT = auto()
55
+
56
+
57
+ # Keywords that are recognized as special tokens
58
+ KEYWORDS = {
59
+ "SearchSpace": TokenType.SEARCHSPACE,
60
+ "Layer": TokenType.LAYER,
61
+ "Evolution": TokenType.EVOLUTION,
62
+ "Experiment": TokenType.EXPERIMENT,
63
+ "Constraint": TokenType.CONSTRAINT,
64
+ "True": TokenType.BOOLEAN,
65
+ "False": TokenType.BOOLEAN,
66
+ "true": TokenType.BOOLEAN,
67
+ "false": TokenType.BOOLEAN,
68
+ }
69
+
70
+ # Supported layer types in the DSL
71
+ LAYER_TYPES = [
72
+ "conv2d",
73
+ "conv3d",
74
+ "dense",
75
+ "linear",
76
+ "batch_norm",
77
+ "layer_norm",
78
+ "dropout",
79
+ "max_pool",
80
+ "avg_pool",
81
+ "global_avg_pool",
82
+ "activation",
83
+ "flatten",
84
+ "relu",
85
+ "elu",
86
+ "gelu",
87
+ "tanh",
88
+ "sigmoid",
89
+ "leaky_relu",
90
+ "softmax",
91
+ "input",
92
+ "output",
93
+ ]
94
+
95
+ # Optimizer types
96
+ OPTIMIZER_TYPES = [
97
+ "adam",
98
+ "sgd",
99
+ "rmsprop",
100
+ "adamw",
101
+ "adagrad",
102
+ ]
103
+
104
+ # Activation functions
105
+ ACTIVATION_TYPES = [
106
+ "relu",
107
+ "elu",
108
+ "gelu",
109
+ "tanh",
110
+ "sigmoid",
111
+ "leaky_relu",
112
+ "softmax",
113
+ "selu",
114
+ "swish",
115
+ ]
116
+
117
+ # Evolution strategies
118
+ EVOLUTION_STRATEGIES = [
119
+ "genetic",
120
+ "random_search",
121
+ "hill_climbing",
122
+ "differential_evolution",
123
+ "cma_es",
124
+ "bayesian",
125
+ "nsga2",
126
+ ]
127
+
128
+ # Operator symbols
129
+ OPERATORS = {
130
+ "=": TokenType.ASSIGN,
131
+ ",": TokenType.COMMA,
132
+ ".": TokenType.DOT,
133
+ ":": TokenType.COLON,
134
+ "(": TokenType.LPAREN,
135
+ ")": TokenType.RPAREN,
136
+ "[": TokenType.LBRACKET,
137
+ "]": TokenType.RBRACKET,
138
+ "{": TokenType.LBRACE,
139
+ "}": TokenType.RBRACE,
140
+ }
141
+
142
+
143
+ def is_layer_type(name: str) -> bool:
144
+ """Check if name is a valid layer type."""
145
+ return name in LAYER_TYPES
146
+
147
+
148
+ def is_optimizer_type(name: str) -> bool:
149
+ """Check if name is a valid optimizer type."""
150
+ return name in OPTIMIZER_TYPES
151
+
152
+
153
+ def is_activation_type(name: str) -> bool:
154
+ """Check if name is a valid activation function."""
155
+ return name in ACTIVATION_TYPES
156
+
157
+
158
+ def is_evolution_strategy(name: str) -> bool:
159
+ """Check if name is a valid evolution strategy."""
160
+ return name in EVOLUTION_STRATEGIES
161
+
162
+
163
+ # Grammar documentation
164
+ GRAMMAR_DOCS = """
165
+ MorphML DSL Grammar (Extended Backus-Naur Form)
166
+
167
+ experiment := search_space_def [evolution_def] [constraint_list]
168
+ search_space_def := "SearchSpace" "(" [space_params] ")"
169
+ space_params := "layers" "=" layer_list ["," param_list]
170
+ layer_list := "[" layer_def ("," layer_def)* "]"
171
+ layer_def := "Layer" "." layer_type "(" [param_list] ")"
172
+ evolution_def := "Evolution" "(" param_list ")"
173
+ constraint_list := "Constraint" "(" constraint_expr ("," constraint_expr)* ")"
174
+
175
+ param_list := param ("," param)*
176
+ param := IDENTIFIER "=" value_expr
177
+ value_expr := value | value_list
178
+ value_list := "[" value ("," value)* "]"
179
+ value := NUMBER | STRING | BOOLEAN | IDENTIFIER
180
+
181
+ layer_type := IDENTIFIER # Must be in LAYER_TYPES
182
+ constraint_expr := STRING | function_call
183
+
184
+ Examples:
185
+ SearchSpace(
186
+ layers=[
187
+ Layer.conv2d(filters=[32, 64, 128], kernel_size=3),
188
+ Layer.relu(),
189
+ Layer.maxpool(pool_size=2),
190
+ Layer.dense(units=[128, 256])
191
+ ]
192
+ )
193
+
194
+ Evolution(
195
+ strategy="genetic",
196
+ population_size=50,
197
+ num_generations=100
198
+ )
199
+ """