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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/PKG-INFO +1 -1
  2. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/pyproject.toml +1 -1
  3. math_spec_mapping-0.1.5/src/Classes/Block.py +338 -0
  4. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/BoundaryAction.py +2 -1
  5. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/ControlAction.py +2 -1
  6. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/MathSpec.py +2 -0
  7. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/Mechanism.py +3 -1
  8. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/Policy.py +1 -0
  9. math_spec_mapping-0.1.5/src/Classes/Space.py +14 -0
  10. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/__init__.py +2 -1
  11. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/action_transmission_channel.py +5 -3
  12. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/boundary_actions.py +4 -1
  13. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/control_actions.py +1 -1
  14. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/general.py +16 -0
  15. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/load.py +4 -2
  16. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/mechanism.py +4 -1
  17. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/policy.py +8 -2
  18. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/spaces.py +4 -1
  19. math_spec_mapping-0.1.5/src/Load/wiring.py +70 -0
  20. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/math_spec_mapping.egg-info/PKG-INFO +1 -1
  21. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/math_spec_mapping.egg-info/SOURCES.txt +1 -0
  22. math_spec_mapping-0.1.3/src/Classes/Block.py +0 -17
  23. math_spec_mapping-0.1.3/src/Classes/Space.py +0 -7
  24. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/LICENSE +0 -0
  25. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/README.md +0 -0
  26. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/setup.cfg +0 -0
  27. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/ActionTransmissionChannel.py +0 -0
  28. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/Entity.py +0 -0
  29. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/Parameter.py +0 -0
  30. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/State.py +0 -0
  31. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/StateUpdateTransmissionChannel.py +0 -0
  32. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Classes/StatefulMetric.py +0 -0
  33. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Convenience/__init__.py +0 -0
  34. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Convenience/starter.py +0 -0
  35. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/__init__.py +0 -0
  36. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/entities.py +0 -0
  37. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/parameters.py +0 -0
  38. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/state_update_transmission_channels.py +0 -0
  39. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/stateful_metrics.py +0 -0
  40. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Load/states.py +0 -0
  41. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/__init__.py +0 -0
  42. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/boundary_actions.py +0 -0
  43. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/control_actions.py +0 -0
  44. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/general.py +0 -0
  45. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/html.py +0 -0
  46. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/mechanisms.py +0 -0
  47. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/node_map.py +0 -0
  48. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/parameters.py +0 -0
  49. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/policies.py +0 -0
  50. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/spaces.py +0 -0
  51. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/state.py +0 -0
  52. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/Reports/tables.py +0 -0
  53. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/__init__.py +0 -0
  54. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/math_spec_mapping.egg-info/dependency_links.txt +0 -0
  55. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/math_spec_mapping.egg-info/requires.txt +0 -0
  56. {math_spec_mapping-0.1.3 → math_spec_mapping-0.1.5}/src/math_spec_mapping.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math_spec_mapping
3
- Version: 0.1.3
3
+ Version: 0.1.5
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
@@ -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.3"
6
+ version = "0.1.5"
7
7
  authors = [
8
8
  { name="Sean McOwen", email="Sean@Block.Science" },
9
9
  ]
@@ -0,0 +1,338 @@
1
+ from typing import Dict
2
+ from .Space import TerminatingSpace, EmptySpace
3
+
4
+
5
+ class Block:
6
+ def __init__(self, data: Dict):
7
+ self.name = data["name"]
8
+ self.description = data["description"]
9
+ self.constraints = data["constraints"]
10
+ self.domain = data["domain"]
11
+ self.codomain = data["codomain"]
12
+ self.parameters_used = data["parameters_used"]
13
+ if "label" in data:
14
+ self.label = data["label"]
15
+ else:
16
+ self.label = self.name
17
+ self.called_by = []
18
+ self.calls = []
19
+ self.block_type = "Block"
20
+ # Will be overwritten in composite blocks to represent individual components
21
+ self.domain_blocks = tuple(
22
+ [
23
+ self
24
+ for _ in range(
25
+ len(
26
+ [
27
+ x
28
+ for x in self.domain
29
+ if x not in [TerminatingSpace, EmptySpace]
30
+ ]
31
+ )
32
+ )
33
+ ]
34
+ )
35
+ self.codomain_blocks = tuple(
36
+ [
37
+ self
38
+ for _ in range(
39
+ len(
40
+ [
41
+ x
42
+ for x in self.codomain
43
+ if x not in [TerminatingSpace, EmptySpace]
44
+ ]
45
+ )
46
+ )
47
+ ]
48
+ )
49
+ self.domain_blocks_empty = tuple(
50
+ self for _ in range(len([x for x in self.domain if x == EmptySpace]))
51
+ )
52
+ self.codomain_blocks_empty = tuple(
53
+ self for _ in range(len([x for x in self.codomain if x == EmptySpace]))
54
+ )
55
+ self.codomain_blocks_terminating = tuple(
56
+ self
57
+ for _ in range(len([x for x in self.codomain if x == TerminatingSpace]))
58
+ )
59
+
60
+ def render_mermaid(self, i):
61
+ i += 1
62
+ return "X{}[{}]".format(i, self.name), i
63
+
64
+ def render_mermaid_root(self):
65
+ out = """```mermaid\ngraph TB\n"""
66
+ out += self.render_mermaid(0)[0]
67
+ out += "\n```"
68
+ return out
69
+
70
+
71
+ class ParallelBlock(Block):
72
+ def __init__(self, data: Dict):
73
+ self.name = data["name"]
74
+ self.components = data["components"]
75
+ self.description = data["description"]
76
+ self.constraints = data["constraints"]
77
+ self.domain = tuple(
78
+ [
79
+ i
80
+ for x in self.components
81
+ for i in x.domain
82
+ if i not in [TerminatingSpace, EmptySpace]
83
+ ]
84
+ )
85
+ if len(self.domain) == 0:
86
+ self.domain = (EmptySpace,)
87
+
88
+ self.codomain = tuple(
89
+ [
90
+ i
91
+ for x in self.components
92
+ for i in x.codomain
93
+ if i not in [TerminatingSpace, EmptySpace]
94
+ ]
95
+ )
96
+ if len(self.codomain) == 0:
97
+ self.codomain = (EmptySpace,)
98
+ self.parameters_used = list(
99
+ set([i for x in self.components for i in x.parameters_used])
100
+ )
101
+
102
+ self.domain_blocks = tuple(
103
+ [i for x in self.components for i in x.domain_blocks]
104
+ )
105
+ self.codomain_blocks = tuple(
106
+ [i for x in self.components for i in x.codomain_blocks]
107
+ )
108
+
109
+ self.domain_blocks_empty = tuple(
110
+ [i for x in self.components for i in x.domain_blocks_empty]
111
+ )
112
+ self.codomain_blocks_empty = tuple(
113
+ [i for x in self.components for i in x.codomain_blocks_empty]
114
+ )
115
+ self.codomain_blocks_terminating = tuple(
116
+ [i for x in self.components for i in x.codomain_blocks_terminating]
117
+ )
118
+
119
+ self.called_by = []
120
+ self.calls = []
121
+ self.block_type = "Paralell Block"
122
+
123
+ def render_mermaid(self, i):
124
+ multi = None
125
+ if type(i) == list:
126
+ multi = i
127
+ i = i[-1]
128
+ start_i = i
129
+ out = ""
130
+
131
+ nodes = []
132
+
133
+ # Render components
134
+ for component in self.components:
135
+ component, i = component.render_mermaid(i)
136
+ out += component
137
+ out += "\n"
138
+ nodes.append(i)
139
+ end_i = i
140
+
141
+ # Render invisible connections
142
+ for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
143
+ out += "X{} ~~~ X{}".format(ix1, ix2)
144
+ out += "\n"
145
+
146
+ # Subgraph it
147
+ i += 1
148
+ out = "subgraph X{}[{}]\ndirection LR\n".format(i, self.name) + out
149
+
150
+ out += "end"
151
+
152
+ return out, i
153
+
154
+
155
+ class StackBlock(Block):
156
+ def __init__(self, data: Dict):
157
+ self.name = data["name"]
158
+ self.components = data["components"]
159
+ self.description = data["description"]
160
+ self.constraints = data["constraints"]
161
+ self._check_domain_mapping()
162
+ self.domain = self.components[0].domain
163
+ self.codomain = self.components[-1].codomain
164
+ self.parameters_used = list(
165
+ set([i for x in self.components for i in x.parameters_used])
166
+ )
167
+
168
+ self.domain_blocks = self.components[0].domain_blocks
169
+ self.codomain_blocks = self.components[-1].codomain_blocks
170
+ self.domain_blocks_empty = self.components[0].domain_blocks_empty
171
+ self.codomain_blocks_empty = self.components[-1].codomain_blocks_empty
172
+ self.codomain_blocks_terminating = self.components[
173
+ -1
174
+ ].codomain_blocks_terminating
175
+
176
+ self.called_by = []
177
+ self.calls = []
178
+
179
+ self.block_type = "Stack Block"
180
+
181
+ def _check_domain_mapping(self):
182
+ for a, b in zip(self.components[:-1], self.components[1:]):
183
+ assert [
184
+ x for x in a.codomain if x not in [EmptySpace, TerminatingSpace]
185
+ ] == [
186
+ x for x in b.domain if x not in [EmptySpace, TerminatingSpace]
187
+ ], "{} codomain does not match {} domain, {} != {}".format(
188
+ a.name, b.name, a.codomain, b.domain
189
+ )
190
+
191
+ def build_action_transmission_channels(self):
192
+ channels = []
193
+ for a, b in zip(self.components[:-1], self.components[1:]):
194
+ assert len(a.codomain_blocks) == len(b.domain_blocks) and len(
195
+ b.domain_blocks
196
+ ) == len([x for x in b.domain if x not in [EmptySpace, TerminatingSpace]])
197
+ for x, y, z in zip(
198
+ a.codomain_blocks,
199
+ b.domain_blocks,
200
+ [x for x in b.domain if x not in [EmptySpace, TerminatingSpace]],
201
+ ):
202
+ channels.append(
203
+ {
204
+ "origin": x.name,
205
+ "target": y.name,
206
+ "space": z.name,
207
+ "optional": False,
208
+ }
209
+ )
210
+ for x in a.codomain_blocks_empty:
211
+ for y in b.domain_blocks_empty:
212
+ channels.append(
213
+ {
214
+ "origin": x.name,
215
+ "target": y.name,
216
+ "space": "Empty Space",
217
+ "optional": False,
218
+ }
219
+ )
220
+ return channels
221
+
222
+ def render_mermaid(self, i):
223
+ multi = None
224
+ if type(i) == list:
225
+ multi = i
226
+ i = i[-1]
227
+ start_i = i
228
+ out = ""
229
+
230
+ nodes = []
231
+
232
+ # Render components
233
+ for component in self.components:
234
+ component, i = component.render_mermaid(i)
235
+ out += component
236
+ out += "\n"
237
+ nodes.append(i)
238
+ if type(i) == list:
239
+ i = i[-1]
240
+ end_i = i
241
+
242
+ # Render connections
243
+ for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
244
+ if type(ix1) != list:
245
+ ix1 = [ix1]
246
+ if type(ix2) != list:
247
+ ix2 = [ix2]
248
+ for ix3 in ix1:
249
+ for ix4 in ix2:
250
+ out += "X{}-->X{}".format(ix3, ix4)
251
+ out += "\n"
252
+
253
+ # Subgraph it
254
+ i += 1
255
+ out = "subgraph X{}[{}]\ndirection TB\n".format(i, self.name) + out
256
+ out += "end"
257
+
258
+ return out, i
259
+
260
+
261
+ class SplitBlock(Block):
262
+ def __init__(self, data: Dict):
263
+ self.name = data["name"]
264
+ self.components = data["components"]
265
+ self.description = data["description"]
266
+ self.constraints = data["constraints"]
267
+ self.domain = tuple(
268
+ [
269
+ i
270
+ for x in self.components
271
+ for i in x.domain
272
+ if i not in [TerminatingSpace, EmptySpace]
273
+ ]
274
+ )
275
+ if len(self.domain) == 0:
276
+ self.domain = (EmptySpace,)
277
+
278
+ self.codomain = tuple(
279
+ [
280
+ i
281
+ for x in self.components
282
+ for i in x.codomain
283
+ if i not in [TerminatingSpace, EmptySpace]
284
+ ]
285
+ )
286
+ if len(self.codomain) == 0:
287
+ self.codomain = (EmptySpace,)
288
+ self.parameters_used = list(
289
+ set([i for x in self.components for i in x.parameters_used])
290
+ )
291
+
292
+ self.domain_blocks = tuple(
293
+ [i for x in self.components for i in x.domain_blocks]
294
+ )
295
+ self.codomain_blocks = tuple(
296
+ [i for x in self.components for i in x.codomain_blocks]
297
+ )
298
+
299
+ self.domain_blocks_empty = tuple(
300
+ [i for x in self.components for i in x.domain_blocks_empty]
301
+ )
302
+ self.codomain_blocks_empty = tuple(
303
+ [i for x in self.components for i in x.codomain_blocks_empty]
304
+ )
305
+ self.codomain_blocks_terminating = tuple(
306
+ [i for x in self.components for i in x.codomain_blocks_terminating]
307
+ )
308
+
309
+ self.called_by = []
310
+ self.calls = []
311
+
312
+ self.block_type = "Split Block"
313
+
314
+ def render_mermaid(self, i):
315
+ multi = None
316
+ if type(i) == list:
317
+ multi = i
318
+ i = i[-1]
319
+ start_i = i
320
+ out = ""
321
+
322
+ nodes = []
323
+
324
+ # Render components
325
+ for component in self.components:
326
+ component, i = component.render_mermaid(i)
327
+ out += component
328
+ out += "\n"
329
+ nodes.append(i)
330
+ end_i = i
331
+
332
+ # Render invisible connections
333
+ for ix1, ix2 in zip(nodes[:-1], nodes[1:]):
334
+ out += "X{} ~~~ X{}".format(ix1, ix2)
335
+ out += "\n"
336
+ out = out[:-1]
337
+
338
+ return out, nodes
@@ -4,9 +4,10 @@ from .Block import Block
4
4
 
5
5
  class BoundaryAction(Block):
6
6
  def __init__(self, data: Dict):
7
- data["domain"] = None
7
+ data["domain"] = tuple()
8
8
  super().__init__(data)
9
9
  self.boundary_action_options = data["boundary_action_options"]
10
+ self.block_type = "Boundary Action"
10
11
 
11
12
 
12
13
  class BoundaryActionOption:
@@ -4,9 +4,10 @@ from .Block import Block
4
4
 
5
5
  class ControlAction(Block):
6
6
  def __init__(self, data: Dict):
7
- data["domain"] = None
7
+ data["domain"] = tuple()
8
8
  super().__init__(data)
9
9
  self.control_action_options = data["control_action_options"]
10
+ self.block_type = "Control Action"
10
11
 
11
12
 
12
13
  class ControlActionOption:
@@ -24,6 +24,8 @@ class MathSpec:
24
24
  "State Update Transmission Channels"
25
25
  ]
26
26
  self.stateful_metrics = ms_dict["Stateful Metrics"]
27
+ self.wiring = ms_dict["Wiring"]
28
+ self.blocks = ms_dict["Blocks"]
27
29
 
28
30
  self._check_parameters()
29
31
  self._crawl_parameters()
@@ -1,10 +1,12 @@
1
1
  from typing import Dict
2
2
  from .Block import Block
3
+ from .Space import TerminatingSpace
3
4
 
4
5
 
5
6
  class Mechanism(Block):
6
7
  def __init__(self, data: Dict):
7
- data["codomain"] = None
8
+ data["codomain"] = (TerminatingSpace,)
8
9
  super().__init__(data)
9
10
  self.logic = data["logic"]
10
11
  self.updates = []
12
+ self.block_type = "Mechanism"
@@ -13,3 +13,4 @@ class Policy(Block):
13
13
  def __init__(self, data: Dict):
14
14
  super().__init__(data)
15
15
  self.policy_options: List[PolicyOption] = data["policy_options"]
16
+ self.block_type = "Policy"
@@ -0,0 +1,14 @@
1
+ from typing import Dict
2
+
3
+
4
+ class Space:
5
+ def __init__(self, data: Dict):
6
+ self.name = data["name"]
7
+ self.schema = data["schema"]
8
+
9
+ def __repr__(self):
10
+ return self.name
11
+
12
+
13
+ TerminatingSpace = Space({"name": "Terminating Space", "schema": {}})
14
+ EmptySpace = Space({"name": "Empty Space", "schema": {}})
@@ -9,4 +9,5 @@ from .Policy import Policy, PolicyOption
9
9
  from .StateUpdateTransmissionChannel import StateUpdateTransmissionChannel
10
10
  from .StatefulMetric import StatefulMetric, StatefulMetricSet
11
11
  from .ControlAction import ControlAction, ControlActionOption
12
- from .Space import Space
12
+ from .Space import Space, TerminatingSpace, EmptySpace
13
+ from .Block import ParallelBlock, Block, StackBlock, SplitBlock
@@ -57,15 +57,17 @@ def convert_action_transmission_channel(
57
57
  return ActionTransmissionChannel(data)
58
58
 
59
59
 
60
- def load_action_transmission_channels(ms: Dict, json: Dict) -> None:
60
+ def load_action_transmission_channels(
61
+ ms: Dict, action_transmission_channels: list
62
+ ) -> None:
61
63
  """Function to load states into the new dictionary
62
64
 
63
65
  Args:
64
66
  ms (Dict): MathSpec dictionary
65
- json (Dict): JSON version of MathSpec to load
67
+ action_transmission_channels (list): List of action transmission channels
66
68
  """
67
69
 
68
70
  ms["Action Transmission Channels"] = []
69
- for atc in json["Action Transmission Channels"]:
71
+ for atc in action_transmission_channels:
70
72
  atc = convert_action_transmission_channel(atc, ms)
71
73
  ms["Action Transmission Channels"].append(atc)
@@ -16,6 +16,9 @@ def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
16
16
 
17
17
  # Check the keys are correct
18
18
  check_json_keys(data, "Boundary Action")
19
+ assert type(data["codomain"]) == tuple, "{} codomain is not a tuple".format(
20
+ data["name"]
21
+ )
19
22
 
20
23
  # Copy
21
24
  data = data.copy()
@@ -35,7 +38,7 @@ def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
35
38
  ), "{} entity not in entities dictionary".format(name)
36
39
  data["called_by"] = [ms["Entities"][x] for x in data["called_by"]]
37
40
 
38
- data["codomain"] = (ms["Spaces"][x] for x in data["codomain"])
41
+ data["codomain"] = tuple(ms["Spaces"][x] for x in data["codomain"])
39
42
 
40
43
  # Build the boundary action object
41
44
  return BoundaryAction(data)
@@ -27,7 +27,7 @@ def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
27
27
  new_cao.append(ControlActionOption(ca))
28
28
  data["control_action_options"] = new_cao
29
29
 
30
- data["codomain"] = (ms["Spaces"][x] for x in data["codomain"])
30
+ data["codomain"] = tuple(ms["Spaces"][x] for x in data["codomain"])
31
31
 
32
32
  # Build the control action object
33
33
  return ControlAction(data)
@@ -26,6 +26,21 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
26
26
  "State Update Transmission Channels",
27
27
  "Stateful Metrics",
28
28
  "Control Actions",
29
+ "Wiring",
30
+ "Blocks",
31
+ ],
32
+ "JSON": [
33
+ "Boundary Actions",
34
+ "Entities",
35
+ "Mechanisms",
36
+ "Parameters",
37
+ "Policies",
38
+ "Spaces",
39
+ "State",
40
+ "State Update Transmission Channels",
41
+ "Stateful Metrics",
42
+ "Control Actions",
43
+ "Wiring",
29
44
  ],
30
45
  "State": ["name", "label", "notes", "variables"],
31
46
  "State Variable": ["type", "name", "description", "symbol", "domain"],
@@ -99,6 +114,7 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
99
114
  "parameter_class",
100
115
  ],
101
116
  "Space": ["name", "schema"],
117
+ "Block": ["name", "components", "description", "constraints"],
102
118
  }
103
119
 
104
120
  check_set = check_sets[check_set_key]
@@ -12,6 +12,7 @@ from .parameters import load_parameters
12
12
  from .policy import load_policies
13
13
  from .spaces import load_spaces
14
14
  from .stateful_metrics import load_stateful_metrics
15
+ from .wiring import load_wiring
15
16
 
16
17
 
17
18
  def load_from_json(json: Dict) -> MathSpec:
@@ -25,7 +26,7 @@ def load_from_json(json: Dict) -> MathSpec:
25
26
  """
26
27
 
27
28
  # Assert the keys are correct in the json
28
- check_json_keys(json, "Math Spec")
29
+ check_json_keys(json, "JSON")
29
30
 
30
31
  ms = {}
31
32
 
@@ -39,7 +40,8 @@ def load_from_json(json: Dict) -> MathSpec:
39
40
  load_parameters(ms, json)
40
41
  load_policies(ms, json)
41
42
  load_stateful_metrics(ms, json)
42
- load_action_transmission_channels(ms, json)
43
+ action_transmission_channels = load_wiring(ms, json)
44
+ load_action_transmission_channels(ms, action_transmission_channels)
43
45
  load_state_update_transmission_channels(ms, json)
44
46
 
45
47
  # Assert all keys are correct for the ms version
@@ -15,11 +15,14 @@ def convert_mechanism(data: Dict, ms: Dict) -> Mechanism:
15
15
 
16
16
  # Check the keys are correct
17
17
  check_json_keys(data, "Mechanism")
18
+ assert type(data["domain"]) == tuple, "{} domain is not a tuple".format(
19
+ data["name"]
20
+ )
18
21
 
19
22
  # Copy
20
23
  data = data.copy()
21
24
 
22
- data["domain"] = (ms["Spaces"][x] for x in data["domain"])
25
+ data["domain"] = tuple(ms["Spaces"][x] for x in data["domain"])
23
26
 
24
27
  # Build the action transmission channel object
25
28
  return Mechanism(data)
@@ -37,6 +37,12 @@ def convert_policy(data: Dict, ms: Dict) -> Policy:
37
37
 
38
38
  # Check the keys are correct
39
39
  check_json_keys(data, "Policy")
40
+ assert type(data["codomain"]) == tuple, "{} codomain is not a tuple".format(
41
+ data["name"]
42
+ )
43
+ assert type(data["domain"]) == tuple, "{} domain is not a tuple".format(
44
+ data["name"]
45
+ )
40
46
 
41
47
  # Copy
42
48
  data = data.copy()
@@ -47,8 +53,8 @@ def convert_policy(data: Dict, ms: Dict) -> Policy:
47
53
  policy_options.append(convert_policy_options(po))
48
54
  data["policy_options"] = policy_options
49
55
 
50
- data["codomain"] = (ms["Spaces"][x] for x in data["codomain"])
51
- data["domain"] = (ms["Spaces"][x] for x in data["domain"])
56
+ data["codomain"] = tuple(ms["Spaces"][x] for x in data["codomain"])
57
+ data["domain"] = tuple(ms["Spaces"][x] for x in data["domain"])
52
58
 
53
59
  # Build the policy object
54
60
  return Policy(data)
@@ -1,5 +1,5 @@
1
1
  from typing import Dict
2
- from ..Classes import Space
2
+ from ..Classes import Space, TerminatingSpace, EmptySpace
3
3
  from .general import check_json_keys
4
4
 
5
5
 
@@ -24,6 +24,9 @@ def load_spaces(ms: Dict, json: Dict) -> None:
24
24
 
25
25
  # Placeholder for now
26
26
  ms["Spaces"] = {}
27
+ ms["Spaces"]["Terminating Space"] = TerminatingSpace
28
+ ms["Spaces"]["Empty Space"] = EmptySpace
27
29
 
28
30
  for space in json["Spaces"]:
31
+ assert space["name"] not in ms["Spaces"], "{} repeated"
29
32
  ms["Spaces"][space["name"]] = convert_space(space)
@@ -0,0 +1,70 @@
1
+ from typing import Dict
2
+ from ..Classes import Block, StackBlock, ParallelBlock, SplitBlock
3
+ from .general import check_json_keys
4
+
5
+
6
+ def load_single_wiring(data, ms):
7
+ block_type = data.pop("type")
8
+ # Check the keys are correct
9
+ check_json_keys(data, "Block")
10
+ assert block_type in [
11
+ "Stack",
12
+ "Parallel",
13
+ "Split",
14
+ ], "{} not a valid block type".format(block_type)
15
+
16
+ # Map components
17
+ data["components"] = [ms["Blocks"][x] for x in data["components"]]
18
+
19
+ # Map to the correct block
20
+ if block_type == "Stack":
21
+ block = StackBlock(data)
22
+ elif block_type == "Parallel":
23
+ block = ParallelBlock(data)
24
+ elif block_type == "Split":
25
+ block = SplitBlock(data)
26
+ else:
27
+ assert False
28
+
29
+ return block
30
+
31
+
32
+ def check_repeat(d, blocks):
33
+ for x in blocks:
34
+ assert x not in d, "{} was a repeated block".format(x)
35
+
36
+
37
+ def filter_atc(action_transmission_channels):
38
+ seen = []
39
+ out = []
40
+ for x in action_transmission_channels:
41
+ key = frozenset(x.items())
42
+ if key not in seen:
43
+ seen.append(key)
44
+ out.append(x)
45
+ return out
46
+
47
+
48
+ def load_wiring(ms, json):
49
+ ms["Blocks"] = {}
50
+ check_repeat(ms["Blocks"], ms["Boundary Actions"])
51
+ ms["Blocks"].update(ms["Boundary Actions"])
52
+ check_repeat(ms["Blocks"], ms["Control Actions"])
53
+ ms["Blocks"].update(ms["Control Actions"])
54
+ check_repeat(ms["Blocks"], ms["Policies"])
55
+ ms["Blocks"].update(ms["Policies"])
56
+ check_repeat(ms["Blocks"], ms["Mechanisms"])
57
+ ms["Blocks"].update(ms["Mechanisms"])
58
+
59
+ ms["Wiring"] = {}
60
+ action_transmission_channels = []
61
+ for w in json["Wiring"]:
62
+ w = load_single_wiring(w, ms)
63
+ assert w.name not in ms["Blocks"], "{} was a repeated block".format(w.name)
64
+ ms["Wiring"][w.name] = w
65
+ ms["Blocks"][w.name] = w
66
+ if w.block_type == "Stack Block":
67
+ action_transmission_channels.extend(w.build_action_transmission_channels())
68
+ action_transmission_channels = filter_atc(action_transmission_channels)
69
+
70
+ return action_transmission_channels
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math_spec_mapping
3
- Version: 0.1.3
3
+ Version: 0.1.5
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
@@ -32,6 +32,7 @@ src/Load/spaces.py
32
32
  src/Load/state_update_transmission_channels.py
33
33
  src/Load/stateful_metrics.py
34
34
  src/Load/states.py
35
+ src/Load/wiring.py
35
36
  src/Reports/__init__.py
36
37
  src/Reports/boundary_actions.py
37
38
  src/Reports/control_actions.py
@@ -1,17 +0,0 @@
1
- from typing import Dict
2
-
3
-
4
- class Block:
5
- def __init__(self, data: Dict):
6
- self.name = data["name"]
7
- self.description = data["description"]
8
- self.constraints = data["constraints"]
9
- self.domain = data["domain"]
10
- self.codomain = data["codomain"]
11
- self.parameters_used = data["parameters_used"]
12
- if "label" in data:
13
- self.label = data["label"]
14
- else:
15
- self.label = self.name
16
- self.called_by = []
17
- self.calls = []
@@ -1,7 +0,0 @@
1
- from typing import Dict
2
-
3
-
4
- class Space:
5
- def __init__(self, data: Dict):
6
- self.name = data["name"]
7
- self.schema = data["schema"]