math-spec-mapping 0.1.5__tar.gz → 0.2.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. {math_spec_mapping-0.1.5/src/math_spec_mapping.egg-info → math_spec_mapping-0.2.1}/PKG-INFO +29 -5
  2. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/README.md +28 -4
  3. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/pyproject.toml +1 -1
  4. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Block.py +124 -15
  5. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Entity.py +2 -2
  6. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/MathSpec.py +83 -0
  7. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Parameter.py +5 -0
  8. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Space.py +3 -2
  9. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/State.py +5 -6
  10. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/StatefulMetric.py +2 -0
  11. math_spec_mapping-0.2.1/src/Classes/Type.py +7 -0
  12. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/__init__.py +1 -0
  13. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/boundary_actions.py +10 -4
  14. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/control_actions.py +13 -4
  15. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/entities.py +7 -4
  16. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/general.py +31 -7
  17. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/load.py +8 -3
  18. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/mechanism.py +25 -3
  19. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/parameters.py +9 -3
  20. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/policy.py +14 -2
  21. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/spaces.py +10 -2
  22. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/state_update_transmission_channels.py +4 -2
  23. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/stateful_metrics.py +19 -4
  24. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/states.py +10 -3
  25. math_spec_mapping-0.2.1/src/Load/type.py +24 -0
  26. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/wiring.py +31 -7
  27. math_spec_mapping-0.2.1/src/Reports/__init__.py +28 -0
  28. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/html.py +70 -21
  29. math_spec_mapping-0.2.1/src/Reports/markdown.py +547 -0
  30. math_spec_mapping-0.2.1/src/Reports/parameters.py +15 -0
  31. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/spaces.py +1 -1
  32. math_spec_mapping-0.2.1/src/Reports/state.py +88 -0
  33. math_spec_mapping-0.2.1/src/Reports/wiring.py +40 -0
  34. math_spec_mapping-0.2.1/src/__init__.py +28 -0
  35. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1/src/math_spec_mapping.egg-info}/PKG-INFO +29 -5
  36. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/math_spec_mapping.egg-info/SOURCES.txt +5 -0
  37. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/math_spec_mapping.egg-info/top_level.txt +1 -0
  38. math_spec_mapping-0.2.1/src/schema.py +8 -0
  39. math_spec_mapping-0.1.5/src/Reports/__init__.py +0 -7
  40. math_spec_mapping-0.1.5/src/Reports/parameters.py +0 -11
  41. math_spec_mapping-0.1.5/src/Reports/state.py +0 -38
  42. math_spec_mapping-0.1.5/src/__init__.py +0 -4
  43. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/LICENSE +0 -0
  44. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/setup.cfg +0 -0
  45. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/ActionTransmissionChannel.py +0 -0
  46. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/BoundaryAction.py +0 -0
  47. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/ControlAction.py +0 -0
  48. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Mechanism.py +0 -0
  49. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/Policy.py +0 -0
  50. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Classes/StateUpdateTransmissionChannel.py +0 -0
  51. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Convenience/__init__.py +0 -0
  52. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Convenience/starter.py +0 -0
  53. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/__init__.py +0 -0
  54. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Load/action_transmission_channel.py +0 -0
  55. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/boundary_actions.py +0 -0
  56. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/control_actions.py +0 -0
  57. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/general.py +0 -0
  58. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/mechanisms.py +0 -0
  59. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/node_map.py +0 -0
  60. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/policies.py +0 -0
  61. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/Reports/tables.py +0 -0
  62. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/math_spec_mapping.egg-info/dependency_links.txt +0 -0
  63. {math_spec_mapping-0.1.5 → math_spec_mapping-0.2.1}/src/math_spec_mapping.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math_spec_mapping
3
- Version: 0.1.5
3
+ Version: 0.2.1
4
4
  Summary: A library for easy mapping of mathematical specifications.
5
5
  Author-email: Sean McOwen <Sean@Block.Science>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -42,7 +42,31 @@ A[JSON Object \n\n Each spec has a repo for tracking changes \n Must conform to
42
42
 
43
43
  ```
44
44
 
45
-
46
-
47
-
48
-
45
+ ## Canonical Examples
46
+
47
+ [Dummy/Starter Repository](https://github.com/BlockScience/MSML/tree/main/examples/StarterRepo)
48
+ [Root Finding Simulation](https://github.com/SeanMcOwen/Root-Finding-Simulation)
49
+
50
+ ### Comparison of Canonical Example Features
51
+
52
+ | Feature | Dummy | Root Finding |
53
+ | --- | --- | --- |
54
+ | Action Transmission Channels | X | X |
55
+ | Stack Block | X | X |
56
+ | Parallel Block | | X |
57
+ | Split Block | | |
58
+ | Boundary Actions | X | |
59
+ | Control Actions | X | X |
60
+ | Entities | X | |
61
+ | Mechanisms | X | X |
62
+ | Parameters | X | X |
63
+ | Policies | X | X |
64
+ | Spaces | X | X |
65
+ | State | X | X |
66
+ | Stateful Metrics | | |
67
+ | State Update Transmission Channels | X | X |
68
+ | Reports | X | X |
69
+
70
+ ## Other Related Repositories
71
+
72
+ [GDS-MSML-cadCAD Repository](https://github.com/BlockScience/GDS-MSML-cadCAD)
@@ -27,7 +27,31 @@ A[JSON Object \n\n Each spec has a repo for tracking changes \n Must conform to
27
27
 
28
28
  ```
29
29
 
30
-
31
-
32
-
33
-
30
+ ## Canonical Examples
31
+
32
+ [Dummy/Starter Repository](https://github.com/BlockScience/MSML/tree/main/examples/StarterRepo)
33
+ [Root Finding Simulation](https://github.com/SeanMcOwen/Root-Finding-Simulation)
34
+
35
+ ### Comparison of Canonical Example Features
36
+
37
+ | Feature | Dummy | Root Finding |
38
+ | --- | --- | --- |
39
+ | Action Transmission Channels | X | X |
40
+ | Stack Block | X | X |
41
+ | Parallel Block | | X |
42
+ | Split Block | | |
43
+ | Boundary Actions | X | |
44
+ | Control Actions | X | X |
45
+ | Entities | X | |
46
+ | Mechanisms | X | X |
47
+ | Parameters | X | X |
48
+ | Policies | X | X |
49
+ | Spaces | X | X |
50
+ | State | X | X |
51
+ | Stateful Metrics | | |
52
+ | State Update Transmission Channels | X | X |
53
+ | Reports | X | X |
54
+
55
+ ## Other Related Repositories
56
+
57
+ [GDS-MSML-cadCAD Repository](https://github.com/BlockScience/GDS-MSML-cadCAD)
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
  [project]
5
5
  name = "math_spec_mapping"
6
- version = "0.1.5"
6
+ version = "0.2.1"
7
7
  authors = [
8
8
  { name="Sean McOwen", email="Sean@Block.Science" },
9
9
  ]
@@ -10,11 +10,15 @@ class Block:
10
10
  self.domain = data["domain"]
11
11
  self.codomain = data["codomain"]
12
12
  self.parameters_used = data["parameters_used"]
13
+ self.metadata = data["metadata"]
13
14
  if "label" in data:
14
15
  self.label = data["label"]
15
16
  else:
16
17
  self.label = self.name
17
- self.called_by = []
18
+ if "called_by" in data:
19
+ self.called_by = data["called_by"]
20
+ else:
21
+ self.called_by = []
18
22
  self.calls = []
19
23
  self.block_type = "Block"
20
24
  # Will be overwritten in composite blocks to represent individual components
@@ -74,6 +78,7 @@ class ParallelBlock(Block):
74
78
  self.components = data["components"]
75
79
  self.description = data["description"]
76
80
  self.constraints = data["constraints"]
81
+ self.mermaid_show_name = data["mermaid_show_name"]
77
82
  self.domain = tuple(
78
83
  [
79
84
  i
@@ -119,6 +124,7 @@ class ParallelBlock(Block):
119
124
  self.called_by = []
120
125
  self.calls = []
121
126
  self.block_type = "Paralell Block"
127
+ self.metadata = data["metadata"]
122
128
 
123
129
  def render_mermaid(self, i):
124
130
  multi = None
@@ -131,21 +137,75 @@ class ParallelBlock(Block):
131
137
  nodes = []
132
138
 
133
139
  # Render components
140
+ domain_map = {}
141
+ codomain_map = {}
134
142
  for component in self.components:
143
+ domain = component.domain
144
+ codomain = component.codomain
145
+ domain = [
146
+ x.name
147
+ for x in domain
148
+ if x.name not in ["Empty Space", "Terminating Space"]
149
+ ]
150
+ codomain = [
151
+ x.name
152
+ for x in codomain
153
+ if x.name not in ["Empty Space", "Terminating Space"]
154
+ ]
155
+
135
156
  component, i = component.render_mermaid(i)
136
157
  out += component
137
158
  out += "\n"
159
+ domain_map[i] = domain
160
+ codomain_map[i] = codomain
138
161
  nodes.append(i)
139
- end_i = i
162
+
163
+ # Add domain and codomain
164
+ i += 1
165
+ out += "X{}[Domain]".format(i)
166
+ out += "\n"
167
+ domain_i = i
168
+ i += 1
169
+ out += "X{}[Codomain]".format(i)
170
+ out += "\n"
171
+ codomain_i = i
172
+
173
+ out += "direction LR\n"
140
174
 
141
175
  # Render invisible connections
142
- for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
143
- out += "X{} ~~~ X{}".format(ix1, ix2)
176
+ # for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
177
+ # out += "X{} ~~~~ X{}".format(ix1, ix2)
178
+ # out += "\n"
179
+
180
+ out += "direction TB\n"
181
+
182
+ for ix1 in nodes:
183
+ d = domain_map[ix1]
184
+ if len(d) > 0:
185
+ d = "\n".join(d)
186
+ d = '"{}"'.format(d)
187
+ out += "X{} --{}--> X{}".format(domain_i, d, ix1)
188
+ else:
189
+ out += "X{} --> X{}".format(domain_i, ix1)
190
+ out += "\n"
191
+
192
+ for ix1 in nodes:
193
+ d = codomain_map[ix1]
194
+ if len(d) > 0:
195
+ d = "\n".join(d)
196
+ d = '"{}"'.format(d)
197
+ out += "X{} --{}--> X{}".format(ix1, d, codomain_i)
198
+ else:
199
+ out += "X{} --> X{}".format(ix1, codomain_i)
144
200
  out += "\n"
145
201
 
146
202
  # Subgraph it
203
+ if self.mermaid_show_name:
204
+ name = self.name
205
+ else:
206
+ name = " "
147
207
  i += 1
148
- out = "subgraph X{}[{}]\ndirection LR\n".format(i, self.name) + out
208
+ out = "subgraph X{}[{}]\ndirection TB\n".format(i, name) + out
149
209
 
150
210
  out += "end"
151
211
 
@@ -158,6 +218,9 @@ class StackBlock(Block):
158
218
  self.components = data["components"]
159
219
  self.description = data["description"]
160
220
  self.constraints = data["constraints"]
221
+ self.mermaid_show_name = data["mermaid_show_name"]
222
+ self.optional_indices = data["optional_indices"]
223
+ self.loop = data["loop"]
161
224
  self._check_domain_mapping()
162
225
  self.domain = self.components[0].domain
163
226
  self.codomain = self.components[-1].codomain
@@ -177,9 +240,15 @@ class StackBlock(Block):
177
240
  self.calls = []
178
241
 
179
242
  self.block_type = "Stack Block"
243
+ self.metadata = data["metadata"]
180
244
 
181
245
  def _check_domain_mapping(self):
182
- for a, b in zip(self.components[:-1], self.components[1:]):
246
+ x = self.components[:-1]
247
+ y = self.components[1:]
248
+ if self.loop:
249
+ x.append(self.components[-1])
250
+ y.append(self.components[0])
251
+ for a, b in zip(x, y):
183
252
  assert [
184
253
  x for x in a.codomain if x not in [EmptySpace, TerminatingSpace]
185
254
  ] == [
@@ -190,10 +259,17 @@ class StackBlock(Block):
190
259
 
191
260
  def build_action_transmission_channels(self):
192
261
  channels = []
193
- for a, b in zip(self.components[:-1], self.components[1:]):
262
+ x = self.components[:-1]
263
+ y = self.components[1:]
264
+ if self.loop:
265
+ x.append(self.components[-1])
266
+ y.append(self.components[0])
267
+ for a, b, c in zip(x, y, range(len(x))):
194
268
  assert len(a.codomain_blocks) == len(b.domain_blocks) and len(
195
269
  b.domain_blocks
196
270
  ) == len([x for x in b.domain if x not in [EmptySpace, TerminatingSpace]])
271
+ global_optional = c in self.optional_indices
272
+
197
273
  for x, y, z in zip(
198
274
  a.codomain_blocks,
199
275
  b.domain_blocks,
@@ -204,7 +280,7 @@ class StackBlock(Block):
204
280
  "origin": x.name,
205
281
  "target": y.name,
206
282
  "space": z.name,
207
- "optional": False,
283
+ "optional": global_optional,
208
284
  }
209
285
  )
210
286
  for x in a.codomain_blocks_empty:
@@ -214,7 +290,7 @@ class StackBlock(Block):
214
290
  "origin": x.name,
215
291
  "target": y.name,
216
292
  "space": "Empty Space",
217
- "optional": False,
293
+ "optional": global_optional,
218
294
  }
219
295
  )
220
296
  return channels
@@ -229,9 +305,17 @@ class StackBlock(Block):
229
305
 
230
306
  nodes = []
231
307
 
308
+ domain_map = {}
232
309
  # Render components
233
310
  for component in self.components:
311
+ domain = component.domain
312
+ domain = [
313
+ x.name
314
+ for x in domain
315
+ if x.name not in ["Empty Space", "Terminating Space"]
316
+ ]
234
317
  component, i = component.render_mermaid(i)
318
+ domain_map[i] = domain
235
319
  out += component
236
320
  out += "\n"
237
321
  nodes.append(i)
@@ -240,19 +324,42 @@ class StackBlock(Block):
240
324
  end_i = i
241
325
 
242
326
  # Render connections
243
- for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
327
+ x = nodes[:-1]
328
+ y = nodes[1:]
329
+ if self.loop:
330
+ x.append(nodes[-1])
331
+ y.append(nodes[0])
332
+ for ix1, ix2, c in zip(x, y, range(len(x))):
333
+ global_optional = c in self.optional_indices
244
334
  if type(ix1) != list:
245
335
  ix1 = [ix1]
246
336
  if type(ix2) != list:
247
337
  ix2 = [ix2]
248
338
  for ix3 in ix1:
249
339
  for ix4 in ix2:
250
- out += "X{}-->X{}".format(ix3, ix4)
340
+ d = domain_map[ix4]
341
+ optional = global_optional
342
+ if len(d) > 0:
343
+ d = "\n".join(d)
344
+ d = '"{}"'.format(d)
345
+ if optional:
346
+ out += "X{}-.{}.->X{}".format(ix3, d, ix4)
347
+ else:
348
+ out += "X{}--{}-->X{}".format(ix3, d, ix4)
349
+ else:
350
+ if optional:
351
+ out += "X{}-.->X{}".format(ix3, ix4)
352
+ else:
353
+ out += "X{}--->X{}".format(ix3, ix4)
251
354
  out += "\n"
252
355
 
253
356
  # Subgraph it
357
+ if self.mermaid_show_name:
358
+ name = self.name
359
+ else:
360
+ name = " "
254
361
  i += 1
255
- out = "subgraph X{}[{}]\ndirection TB\n".format(i, self.name) + out
362
+ out = "subgraph X{}[{}]\ndirection TB\n".format(i, name) + out
256
363
  out += "end"
257
364
 
258
365
  return out, i
@@ -264,6 +371,7 @@ class SplitBlock(Block):
264
371
  self.components = data["components"]
265
372
  self.description = data["description"]
266
373
  self.constraints = data["constraints"]
374
+ self.mermaid_show_name = data["mermaid_show_name"]
267
375
  self.domain = tuple(
268
376
  [
269
377
  i
@@ -310,6 +418,7 @@ class SplitBlock(Block):
310
418
  self.calls = []
311
419
 
312
420
  self.block_type = "Split Block"
421
+ self.metadata = data["metadata"]
313
422
 
314
423
  def render_mermaid(self, i):
315
424
  multi = None
@@ -330,9 +439,9 @@ class SplitBlock(Block):
330
439
  end_i = i
331
440
 
332
441
  # Render invisible connections
333
- for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
334
- out += "X{} ~~~ X{}".format(ix1, ix2)
335
- out += "\n"
442
+ # for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
443
+ # out += "X{} ~~~ X{}".format(ix1, ix2)
444
+ # out += "\n"
336
445
  out = out[:-1]
337
446
 
338
447
  return out, nodes
@@ -9,6 +9,7 @@ class Entity:
9
9
  self.name = data["name"]
10
10
  self.notes = data["notes"]
11
11
  self.state = data["state"]
12
+ self.metadata = data["metadata"]
12
13
 
13
14
  if "label" in data:
14
15
  self.label = data["label"]
@@ -25,7 +26,7 @@ class Entity:
25
26
 
26
27
  def add_boundary_action(self, boundary_action) -> None:
27
28
  self.boundary_actions.append(boundary_action)
28
-
29
+
29
30
  def add_impacted_by_mechanism(self, mechanism) -> None:
30
31
  self.impacted_by_mechanism.append(mechanism)
31
32
  q = [mechanism]
@@ -36,4 +37,3 @@ class Entity:
36
37
  self.impacted_by_actions.append(cur)
37
38
  else:
38
39
  q.extend([x[0] for x in cur.called_by])
39
-
@@ -26,6 +26,7 @@ class MathSpec:
26
26
  self.stateful_metrics = ms_dict["Stateful Metrics"]
27
27
  self.wiring = ms_dict["Wiring"]
28
28
  self.blocks = ms_dict["Blocks"]
29
+ self.types = ms_dict["Types"]
29
30
 
30
31
  self._check_parameters()
31
32
  self._crawl_parameters()
@@ -259,3 +260,85 @@ class MathSpec:
259
260
  out["Spaces"] = list(out["Spaces"])
260
261
  out["Parameters"] = list(out["Parameters"])
261
262
  return out
263
+
264
+ def crawl_wiring(self, wiring_name) -> dict:
265
+ wiring = self.wiring[wiring_name]
266
+ out = {}
267
+
268
+ out["Boundary Actions"] = []
269
+ out["Control Actions"] = []
270
+ out["Policies"] = []
271
+ out["Mechanisms"] = []
272
+ out["State Updates"] = []
273
+ out["Entities2"] = []
274
+ out["Spaces"] = set()
275
+ out["Parameters"] = set()
276
+ out["Wiring"] = []
277
+ q = [wiring.name]
278
+ while len(q) > 0:
279
+ x = q.pop()
280
+ if x in self.wiring:
281
+ if x not in out["Wiring"]:
282
+ x = self.wiring[x]
283
+ out["Wiring"].append(x)
284
+ q.extend([y.name for y in x.components])
285
+ else:
286
+ x = None
287
+ elif x in self.boundary_actions:
288
+ if x not in out["Boundary Actions"]:
289
+ x = self.boundary_actions[x]
290
+ out["Boundary Actions"].append(x)
291
+ else:
292
+ x = None
293
+ elif x in self.control_actions:
294
+ if x not in out["Control Actions"]:
295
+ x = self.control_actions[x]
296
+ out["Control Actions"].append(x)
297
+ else:
298
+ x = None
299
+ elif x in self.policies:
300
+ if x not in out["Policies"]:
301
+ x = self.policies[x]
302
+ out["Policies"].append(x)
303
+ else:
304
+ x = None
305
+ elif x in self.mechanisms:
306
+ if x not in out["Mechanisms"]:
307
+ x = self.mechanisms[x]
308
+ out["Mechanisms"].append(x)
309
+ for y in x.updates:
310
+ if y not in out["State Updates"]:
311
+ out["State Updates"].append(y)
312
+ if y[0] not in out["Entities2"]:
313
+ out["Entities2"].append(y[0])
314
+ else:
315
+ x = None
316
+ else:
317
+ assert False
318
+
319
+ if x:
320
+ out["Spaces"].update(x.codomain)
321
+ out["Spaces"].update(x.domain)
322
+ out["Parameters"].update(x.parameters_used)
323
+
324
+ out["Entities"] = self.find_relevant_entities(
325
+ [x.name for x in out["Boundary Actions"]]
326
+ )
327
+
328
+ out["State"] = [x.state for x in out["Entities"]]
329
+ out["State"] = list(set(out["State"]))
330
+ return out
331
+
332
+ def get_specific_stateful_metrics(self, metric):
333
+ for x in self.stateful_metrics.values():
334
+ for y in x.metrics:
335
+ if metric == y.name:
336
+ return y
337
+ print("Metric not found")
338
+ return None
339
+
340
+ def get_all_stateful_metric_names(self):
341
+ sm = []
342
+ for metrics in self.stateful_metrics.values():
343
+ sm.extend([x.name for x in metrics.metrics])
344
+ return sm
@@ -8,8 +8,11 @@ class ParameterContainer:
8
8
  self.data = data
9
9
 
10
10
  self.all_parameters = []
11
+ self.parameter_map = {}
11
12
  for x in self.data.values():
12
13
  x = x.parameters
14
+ for y in x:
15
+ self.parameter_map[y.name] = y
13
16
  x = [y.name for y in x]
14
17
  self.all_parameters.extend(x)
15
18
  assert len(set(self.all_parameters)) == len(
@@ -25,6 +28,7 @@ class ParameterSet:
25
28
  self.name = data["name"]
26
29
  self.notes = data["notes"]
27
30
  self.parameters = data["parameters"]
31
+ self.metadata = data["metadata"]
28
32
 
29
33
 
30
34
  # Individual Parameter
@@ -40,3 +44,4 @@ class Parameter:
40
44
  self.parameter_class = data[
41
45
  "parameter_class"
42
46
  ] # I.e. behavioral, functional, system
47
+ self.metadata = data["metadata"]
@@ -5,10 +5,11 @@ class Space:
5
5
  def __init__(self, data: Dict):
6
6
  self.name = data["name"]
7
7
  self.schema = data["schema"]
8
+ self.metadata = data["metadata"]
8
9
 
9
10
  def __repr__(self):
10
11
  return self.name
11
12
 
12
13
 
13
- TerminatingSpace = Space({"name": "Terminating Space", "schema": {}})
14
- EmptySpace = Space({"name": "Empty Space", "schema": {}})
14
+ TerminatingSpace = Space({"name": "Terminating Space", "schema": {}, "metadata": {}})
15
+ EmptySpace = Space({"name": "Empty Space", "schema": {}, "metadata": {}})
@@ -14,6 +14,7 @@ class State:
14
14
  self.label = self.name
15
15
  self._write_variable_map()
16
16
  self.updated_by = []
17
+ self.metadata = data["metadata"]
17
18
 
18
19
  def _write_variable_map(self) -> None:
19
20
  """
@@ -27,8 +28,9 @@ class State:
27
28
  key = var.name
28
29
 
29
30
  # Check variable name not repeated
30
- assert var.name not in self.variable_map, "Variable name {} is already present in variables!".format(
31
- key)
31
+ assert (
32
+ var.name not in self.variable_map
33
+ ), "Variable name {} is already present in variables!".format(key)
32
34
 
33
35
  self.variable_map[key] = var
34
36
 
@@ -43,10 +45,7 @@ class StateVariable:
43
45
  self.domain = data["domain"]
44
46
  self.updated_by = []
45
47
 
46
-
47
-
48
48
  # Add check for type of List
49
49
  if hasattr(self.type, "_name"):
50
50
  if self.type._name == "List":
51
- self.type.__name__ = self.type.__repr__().replace("typing.","")
52
-
51
+ self.type.__name__ = self.type.__repr__().replace("typing.", "")
@@ -15,6 +15,7 @@ class StatefulMetric:
15
15
  self.label = data["label"]
16
16
  else:
17
17
  self.label = self.name
18
+ self.metadata = data["metadata"]
18
19
 
19
20
 
20
21
  class StatefulMetricSet:
@@ -23,3 +24,4 @@ class StatefulMetricSet:
23
24
  self.name = data["name"]
24
25
  self.notes = data["notes"]
25
26
  self.metrics = data["metrics"]
27
+ self.metadata = data["metadata"]
@@ -0,0 +1,7 @@
1
+ class Type:
2
+
3
+ def __init__(self, data):
4
+ self.name = data["name"]
5
+ self.type = data["type"]
6
+ self.notes = data["notes"]
7
+ self.metadata = data["metadata"]
@@ -11,3 +11,4 @@ from .StatefulMetric import StatefulMetric, StatefulMetricSet
11
11
  from .ControlAction import ControlAction, ControlActionOption
12
12
  from .Space import Space, TerminatingSpace, EmptySpace
13
13
  from .Block import ParallelBlock, Block, StackBlock, SplitBlock
14
+ from .Type import Type
@@ -13,6 +13,10 @@ def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
13
13
  Returns:
14
14
  BoundaryAction: Boundary action object
15
15
  """
16
+ if "metadata" not in data:
17
+ data["metadata"] = {}
18
+
19
+ data["codomain"] = tuple(data["codomain"])
16
20
 
17
21
  # Check the keys are correct
18
22
  check_json_keys(data, "Boundary Action")
@@ -20,6 +24,9 @@ def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
20
24
  data["name"]
21
25
  )
22
26
 
27
+ if len(data["codomain"]) == 0:
28
+ data["codomain"] = ("Empty Space",)
29
+
23
30
  # Copy
24
31
  data = data.copy()
25
32
 
@@ -53,9 +60,8 @@ def load_boundary_actions(ms: Dict, json: Dict) -> None:
53
60
  """
54
61
 
55
62
  ms["Boundary Actions"] = {}
56
- for key in json["Boundary Actions"]:
57
- ms["Boundary Actions"][key] = convert_boundary_action(
58
- json["Boundary Actions"][key], ms
59
- )
63
+ for ba in json["Boundary Actions"]:
64
+ key = ba["name"]
65
+ ms["Boundary Actions"][key] = convert_boundary_action(ba, ms)
60
66
  for entity in ms["Boundary Actions"][key].called_by:
61
67
  entity.add_boundary_action(ms["Boundary Actions"][key])
@@ -14,8 +14,19 @@ def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
14
14
  ControlAction: Control action object
15
15
  """
16
16
 
17
+ if "metadata" not in data:
18
+ data["metadata"] = {}
19
+
20
+ data["codomain"] = tuple(data["codomain"])
21
+
17
22
  # Check the keys are correct
18
23
  check_json_keys(data, "Control Action")
24
+ assert type(data["codomain"]) == tuple, "{} codomain is not a tuple".format(
25
+ data["name"]
26
+ )
27
+
28
+ if len(data["codomain"]) == 0:
29
+ data["codomain"] = ("Empty Space",)
19
30
 
20
31
  # Copy
21
32
  data = data.copy()
@@ -42,7 +53,5 @@ def load_control_actions(ms: Dict, json: Dict) -> None:
42
53
  """
43
54
 
44
55
  ms["Control Actions"] = {}
45
- for key in json["Control Actions"]:
46
- ms["Control Actions"][key] = convert_control_action(
47
- json["Control Actions"][key], ms
48
- )
56
+ for ca in json["Control Actions"]:
57
+ ms["Control Actions"][ca["name"]] = convert_control_action(ca, ms)
@@ -14,6 +14,8 @@ def convert_entity(data: Dict, ms: Dict) -> Entity:
14
14
  Entity: An entity object
15
15
  """
16
16
 
17
+ if "metadata" not in data:
18
+ data["metadata"] = {}
17
19
  # Check the keys are correct
18
20
  check_json_keys(data, "Entity")
19
21
 
@@ -23,8 +25,7 @@ def convert_entity(data: Dict, ms: Dict) -> Entity:
23
25
  # Assert that the state is in the math spec and assign it here
24
26
  if data["state"]:
25
27
  name = data["state"]
26
- assert name in ms["State"], "{} state not in states dictionary".format(
27
- name)
28
+ assert name in ms["State"], "{} state not in states dictionary".format(name)
28
29
  data["state"] = ms["State"][name]
29
30
 
30
31
  # Build the state object
@@ -40,5 +41,7 @@ def load_entities(ms: Dict, json: Dict) -> None:
40
41
  """
41
42
 
42
43
  ms["Entities"] = {}
43
- for key in json["Entities"]:
44
- ms["Entities"][key] = convert_entity(json["Entities"][key], ms)
44
+
45
+ for e in json["Entities"]:
46
+ ms["Entities"][e["name"]] = convert_entity(e, ms)
47
+ assert "Global" in ms["Entities"], "There must be a global entity"