math-spec-mapping 0.2.2__tar.gz → 0.2.4__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.2.2 → math_spec_mapping-0.2.4}/PKG-INFO +1 -1
  2. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/pyproject.toml +1 -1
  3. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Block.py +90 -10
  4. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/MathSpec.py +6 -0
  5. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Policy.py +1 -0
  6. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Type.py +1 -0
  7. math_spec_mapping-0.2.4/src/Load/displays.py +13 -0
  8. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/general.py +4 -2
  9. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/load.py +23 -2
  10. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/metrics.py +27 -8
  11. math_spec_mapping-0.2.4/src/Load/type.py +100 -0
  12. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/html.py +7 -2
  13. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/markdown.py +116 -13
  14. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/math_spec_mapping.egg-info/PKG-INFO +1 -1
  15. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/math_spec_mapping.egg-info/SOURCES.txt +1 -0
  16. math_spec_mapping-0.2.2/src/Load/type.py +0 -24
  17. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/LICENSE +0 -0
  18. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/README.md +0 -0
  19. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/setup.cfg +0 -0
  20. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/ActionTransmissionChannel.py +0 -0
  21. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/BoundaryAction.py +0 -0
  22. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/ControlAction.py +0 -0
  23. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Entity.py +0 -0
  24. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Mechanism.py +0 -0
  25. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Metric.py +0 -0
  26. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Parameter.py +0 -0
  27. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/Space.py +0 -0
  28. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/State.py +0 -0
  29. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/StateUpdateTransmissionChannel.py +0 -0
  30. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/StatefulMetric.py +0 -0
  31. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Classes/__init__.py +0 -0
  32. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Convenience/__init__.py +0 -0
  33. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Convenience/starter.py +0 -0
  34. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/__init__.py +0 -0
  35. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/action_transmission_channel.py +0 -0
  36. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/boundary_actions.py +0 -0
  37. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/control_actions.py +0 -0
  38. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/entities.py +0 -0
  39. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/mechanism.py +0 -0
  40. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/parameters.py +0 -0
  41. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/policy.py +0 -0
  42. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/spaces.py +0 -0
  43. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/state_update_transmission_channels.py +0 -0
  44. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/stateful_metrics.py +0 -0
  45. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/states.py +0 -0
  46. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Load/wiring.py +0 -0
  47. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/__init__.py +0 -0
  48. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/boundary_actions.py +0 -0
  49. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/control_actions.py +0 -0
  50. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/general.py +0 -0
  51. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/mechanisms.py +0 -0
  52. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/node_map.py +0 -0
  53. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/parameters.py +0 -0
  54. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/policies.py +0 -0
  55. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/spaces.py +0 -0
  56. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/state.py +0 -0
  57. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/tables.py +0 -0
  58. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/Reports/wiring.py +0 -0
  59. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/__init__.py +0 -0
  60. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/math_spec_mapping.egg-info/dependency_links.txt +0 -0
  61. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/math_spec_mapping.egg-info/requires.txt +0 -0
  62. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/math_spec_mapping.egg-info/top_level.txt +0 -0
  63. {math_spec_mapping-0.2.2 → math_spec_mapping-0.2.4}/src/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math_spec_mapping
3
- Version: 0.2.2
3
+ Version: 0.2.4
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.2.2"
6
+ version = "0.2.4"
7
7
  authors = [
8
8
  { name="Sean McOwen", email="Sean@Block.Science" },
9
9
  ]
@@ -21,6 +21,7 @@ class Block:
21
21
  self.called_by = []
22
22
  self.calls = []
23
23
  self.block_type = "Block"
24
+ self.all_updates = []
24
25
  # Will be overwritten in composite blocks to represent individual components
25
26
  self.domain_blocks = tuple(
26
27
  [
@@ -61,16 +62,85 @@ class Block:
61
62
  for _ in range(len([x for x in self.codomain if x == TerminatingSpace]))
62
63
  )
63
64
 
65
+ self.find_all_spaces_used(data)
66
+
64
67
  def render_mermaid(self, i):
65
68
  i += 1
66
- return "X{}[{}]".format(i, self.name), i
69
+ out = 'X{}["{}"]'.format(i, self.name)
70
+ if self.block_type == "Mechanism":
71
+ for u in self.updates:
72
+ out += "\n"
73
+ out += "X{} --> {}".format(
74
+ i,
75
+ (u[0].name + "-" + u[1].name).replace(" ", "-"),
76
+ )
77
+ return out, i
78
+
79
+ def render_ending_entities(self):
80
+ if self.block_type == "Mechanism":
81
+ updates = self.updates
82
+ elif self.block_type in ["Parallel Block", "Stack Block", "Split Block"]:
83
+ updates = self.all_updates
84
+ else:
85
+ return "\n", {}
86
+
87
+ out = "\n"
88
+ out += 'subgraph SVS["State Variables"]\n'
89
+
90
+ # Render the entities
91
+ entity_mapping = {}
92
+ entities = set([x[0] for x in updates])
93
+ for i, x in enumerate(entities):
94
+ entity_mapping[x.name] = "EE{}".format(i)
95
+ out += '{}[("{}")]'.format(entity_mapping[x.name], x.name)
96
+ out += "\n"
97
+
98
+ entity_variable_mapping = {}
99
+ # Render the state variables
100
+ for i, x in enumerate(updates):
101
+ entity_variable_mapping[(x[0].name + "-" + x[1].name).replace(" ", "-")] = (
102
+ "EES{}".format(i)
103
+ )
104
+ out += '{}(["{}"])'.format("EES{}".format(i), x[1].name)
105
+ out += "\n"
106
+
107
+ out += "{} --- {}".format("EES{}".format(i), entity_mapping[x[0].name])
108
+ out += "\n"
109
+ out += "end\n"
110
+ out += "\n"
111
+ return out, entity_variable_mapping
67
112
 
68
113
  def render_mermaid_root(self):
69
114
  out = """```mermaid\ngraph TB\n"""
115
+ add, entity_variable_mapping = self.render_ending_entities()
116
+ out += add
70
117
  out += self.render_mermaid(0)[0]
118
+
119
+ for key in entity_variable_mapping:
120
+ out = out.replace(key, entity_variable_mapping[key])
71
121
  out += "\n```"
122
+
72
123
  return out
73
124
 
125
+ def find_all_spaces_used(self, data):
126
+ self.all_spaces_used = []
127
+ self.all_spaces_used.extend(self.domain)
128
+ self.all_spaces_used.extend(self.codomain)
129
+ if "components" in data:
130
+ for x in data["components"]:
131
+ self.all_spaces_used.extend(x.all_spaces_used)
132
+ self.all_spaces_used = list(set(self.all_spaces_used))
133
+
134
+ def find_all_updates(self, data):
135
+ self.all_updates = []
136
+ if "components" in data:
137
+ for x in data["components"]:
138
+ if x.block_type == "Mechanism":
139
+ self.all_updates.extend(x.updates)
140
+ else:
141
+ self.all_updates.extend(x.all_updates)
142
+ self.all_updates = list(set(self.all_updates))
143
+
74
144
 
75
145
  class ParallelBlock(Block):
76
146
  def __init__(self, data: Dict):
@@ -123,8 +193,9 @@ class ParallelBlock(Block):
123
193
 
124
194
  self.called_by = []
125
195
  self.calls = []
126
- self.block_type = "Paralell Block"
196
+ self.block_type = "Parallel Block"
127
197
  self.metadata = data["metadata"]
198
+ self.find_all_spaces_used(data)
128
199
 
129
200
  def render_mermaid(self, i):
130
201
  multi = None
@@ -139,6 +210,7 @@ class ParallelBlock(Block):
139
210
  # Render components
140
211
  domain_map = {}
141
212
  codomain_map = {}
213
+
142
214
  for component in self.components:
143
215
  domain = component.domain
144
216
  codomain = component.codomain
@@ -182,22 +254,27 @@ class ParallelBlock(Block):
182
254
  for ix1 in nodes:
183
255
  d = domain_map[ix1]
184
256
  if len(d) > 0:
257
+ d_length = len(d)
185
258
  d = "\n".join(d)
186
259
  d = '"{}"'.format(d)
187
- out += "X{} --{}--> X{}".format(domain_i, d, ix1)
260
+ out += "X{} --{}{}-> X{}".format(domain_i, d, "-" * d_length, ix1)
188
261
  else:
189
262
  out += "X{} --> X{}".format(domain_i, ix1)
190
263
  out += "\n"
191
264
 
265
+ codomain_connections = 0
192
266
  for ix1 in nodes:
193
267
  d = codomain_map[ix1]
194
268
  if len(d) > 0:
195
269
  d = "\n".join(d)
196
270
  d = '"{}"'.format(d)
197
271
  out += "X{} --{}--> X{}".format(ix1, d, codomain_i)
198
- else:
199
- out += "X{} --> X{}".format(ix1, codomain_i)
200
- out += "\n"
272
+ codomain_connections += 1
273
+ out += "\n"
274
+ # else:
275
+ # out += "X{} --> X{}".format(ix1, codomain_i)
276
+ if codomain_connections == 0:
277
+ out = out.replace("X{}[Codomain]".format(codomain_i), "")
201
278
 
202
279
  # Subgraph it
203
280
  if self.mermaid_show_name:
@@ -205,7 +282,7 @@ class ParallelBlock(Block):
205
282
  else:
206
283
  name = " "
207
284
  i += 1
208
- out = "subgraph X{}[{}]\ndirection TB\n".format(i, name) + out
285
+ out = 'subgraph X{}["{}"]\ndirection TB\n'.format(i, name) + out
209
286
 
210
287
  out += "end"
211
288
 
@@ -241,6 +318,7 @@ class StackBlock(Block):
241
318
 
242
319
  self.block_type = "Stack Block"
243
320
  self.metadata = data["metadata"]
321
+ self.find_all_spaces_used(data)
244
322
 
245
323
  def _check_domain_mapping(self):
246
324
  x = self.components[:-1]
@@ -340,12 +418,13 @@ class StackBlock(Block):
340
418
  d = domain_map[ix4]
341
419
  optional = global_optional
342
420
  if len(d) > 0:
421
+ d_length = len(d)
343
422
  d = "\n".join(d)
344
423
  d = '"{}"'.format(d)
345
424
  if optional:
346
- out += "X{}-.{}.->X{}".format(ix3, d, ix4)
425
+ out += "X{}-.{}.{}->X{}".format(ix3, d, "." * d_length, ix4)
347
426
  else:
348
- out += "X{}--{}-->X{}".format(ix3, d, ix4)
427
+ out += "X{}--{}-{}->X{}".format(ix3, d, "-" * d_length, ix4)
349
428
  else:
350
429
  if optional:
351
430
  out += "X{}-.->X{}".format(ix3, ix4)
@@ -359,7 +438,7 @@ class StackBlock(Block):
359
438
  else:
360
439
  name = " "
361
440
  i += 1
362
- out = "subgraph X{}[{}]\ndirection TB\n".format(i, name) + out
441
+ out = 'subgraph X{}["{}"]\ndirection TB\n'.format(i, name) + out
363
442
  out += "end"
364
443
 
365
444
  return out, i
@@ -419,6 +498,7 @@ class SplitBlock(Block):
419
498
 
420
499
  self.block_type = "Split Block"
421
500
  self.metadata = data["metadata"]
501
+ self.find_all_spaces_used(data)
422
502
 
423
503
  def render_mermaid(self, i):
424
504
  multi = None
@@ -11,6 +11,7 @@ class MathSpec:
11
11
  # Internal variables to keep track
12
12
  self._ms_dict = ms_dict
13
13
  self._json = json
14
+ self.type_keys = ms_dict["Type Keys"]
14
15
  self.action_transmission_channels = ms_dict["Action Transmission Channels"]
15
16
  self.boundary_actions = ms_dict["Boundary Actions"]
16
17
  self.control_actions = ms_dict["Control Actions"]
@@ -28,6 +29,11 @@ class MathSpec:
28
29
  self.blocks = ms_dict["Blocks"]
29
30
  self.types = ms_dict["Types"]
30
31
  self.metrics = ms_dict["Metrics"]
32
+ self.displays = ms_dict["Displays"]
33
+ self.stateful_metrics_map = {}
34
+ for x in self.stateful_metrics:
35
+ for y in self.stateful_metrics[x].metrics:
36
+ self.stateful_metrics_map[y.name] = y
31
37
 
32
38
  self._check_parameters()
33
39
  self._crawl_parameters()
@@ -14,3 +14,4 @@ class Policy(Block):
14
14
  super().__init__(data)
15
15
  self.policy_options: List[PolicyOption] = data["policy_options"]
16
16
  self.block_type = "Policy"
17
+ self.metrics_used = data["metrics_used"]
@@ -3,5 +3,6 @@ class Type:
3
3
  def __init__(self, data):
4
4
  self.name = data["name"]
5
5
  self.type = data["type"]
6
+ self.type_name = data["type_name"]
6
7
  self.notes = data["notes"]
7
8
  self.metadata = data["metadata"]
@@ -0,0 +1,13 @@
1
+ def load_displays(ms, json) -> None:
2
+ ms["Displays"] = {}
3
+ load_wiring(ms, json)
4
+
5
+
6
+ def load_wiring(ms, json):
7
+ ms["Displays"]["Wiring"] = []
8
+ for display in json["Displays"]["wiring"]:
9
+ for component in display["components"]:
10
+ assert component in ms["Blocks"], "{} is not a valid block".format(
11
+ component
12
+ )
13
+ ms["Displays"]["Wiring"].append(display)
@@ -4,6 +4,7 @@ from ..schema import schema
4
4
 
5
5
 
6
6
  def check_json_keys(json: Dict, check_set_key: str) -> None:
7
+ pass
7
8
  """Function to check the correct keys are in the json dictionary
8
9
 
9
10
  Args:
@@ -11,7 +12,7 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
11
12
  check_set_key (str): The key for what checking set to use
12
13
  """
13
14
 
14
- # Get a temporary list of keys
15
+ """# Get a temporary list of keys
15
16
  keys = list(json.keys())
16
17
 
17
18
  # Pick the correct checking set
@@ -46,6 +47,7 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
46
47
  "Wiring",
47
48
  "Types",
48
49
  "Metrics",
50
+ "Displays",
49
51
  ],
50
52
  "State": ["name", "label", "notes", "variables", "metadata"],
51
53
  "State Variable": ["type", "name", "description", "symbol", "domain"],
@@ -152,7 +154,7 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
152
154
  keys.remove(k)
153
155
 
154
156
  # Make sure there are no extra keys in the json
155
- assert len(keys) == 0, "There are extra keys in json: {}".format(", ".join(keys))
157
+ assert len(keys) == 0, "There are extra keys in json: {}".format(", ".join(keys))"""
156
158
 
157
159
 
158
160
  def validate_json_schema(json):
@@ -13,8 +13,9 @@ from .policy import load_policies
13
13
  from .spaces import load_spaces
14
14
  from .stateful_metrics import load_stateful_metrics
15
15
  from .wiring import load_wiring
16
- from .type import load_types
16
+ from .type import load_types, load_type_keys
17
17
  from .metrics import load_metrics
18
+ from .displays import load_displays
18
19
 
19
20
 
20
21
  def load_from_json(json: Dict) -> MathSpec:
@@ -36,6 +37,8 @@ def load_from_json(json: Dict) -> MathSpec:
36
37
  ms = {}
37
38
 
38
39
  # Do loading one by one to transfer the json
40
+
41
+ load_type_keys(ms)
39
42
  load_types(ms, json)
40
43
  load_spaces(ms, json)
41
44
  load_states(ms, json)
@@ -46,10 +49,28 @@ def load_from_json(json: Dict) -> MathSpec:
46
49
  load_parameters(ms, json)
47
50
  load_policies(ms, json)
48
51
  load_stateful_metrics(ms, json)
52
+
53
+ stateful_metrics_map = {}
54
+ for x in ms["Stateful Metrics"]:
55
+ for y in ms["Stateful Metrics"][x].metrics:
56
+ stateful_metrics_map[y.name] = y
57
+
49
58
  action_transmission_channels = load_wiring(ms, json)
50
59
  load_action_transmission_channels(ms, action_transmission_channels)
51
60
  load_state_update_transmission_channels(ms, state_update_transmission_channels)
52
- load_metrics(ms, json)
61
+
62
+ temp = {}
63
+ for w in json["Wiring"]:
64
+ temp[w["name"]] = w
65
+ for w in ms["Wiring"]:
66
+ w = temp[w]
67
+ ms["Wiring"][w["name"]].find_all_updates(w)
68
+
69
+ load_metrics(ms, json, stateful_metrics_map)
70
+ if "Displays" in json:
71
+ load_displays(ms, json)
72
+ else:
73
+ ms["Displays"] = None
53
74
 
54
75
  # Assert all keys are correct for the ms version
55
76
  check_json_keys(ms, "Math Spec")
@@ -3,7 +3,7 @@ from ..Classes import Metric
3
3
  from .general import check_json_keys
4
4
 
5
5
 
6
- def convert_metric(ms, data: Dict) -> Metric:
6
+ def convert_metric(ms, data: Dict, stateful_metrics_map) -> Metric:
7
7
  """Function to convert metric
8
8
 
9
9
  Args:
@@ -33,7 +33,7 @@ def convert_metric(ms, data: Dict) -> Metric:
33
33
  x[1]
34
34
  )
35
35
  for x in data["parameters_used"]:
36
- assert x in ms["Parameters"].all_parameters
36
+ assert x in ms["Parameters"].all_parameters, "{} not in parameters".format(x)
37
37
 
38
38
  data["domain"] = tuple(data["domain"])
39
39
  for x in data["domain"]:
@@ -41,15 +41,20 @@ def convert_metric(ms, data: Dict) -> Metric:
41
41
  data["domain"] = tuple(ms["Spaces"][x] for x in data["domain"])
42
42
 
43
43
  for x in data["metrics_used"]:
44
- assert x in ms["Metrics"], "{} not a valid metric".format(x)
44
+ assert (
45
+ x in ms["Metrics"] or x in stateful_metrics_map
46
+ ), "{} not a valid metric".format(x)
45
47
 
46
- data["metrics_used"] = tuple(ms["Metrics"][x] for x in data["metrics_used"])
48
+ data["metrics_used"] = tuple(
49
+ ms["Metrics"][x] if x in ms["Metrics"] else stateful_metrics_map[x]
50
+ for x in data["metrics_used"]
51
+ )
47
52
 
48
53
  # Build the metric object
49
54
  return Metric(data)
50
55
 
51
56
 
52
- def load_metrics(ms: Dict, json: Dict) -> None:
57
+ def load_metrics(ms: Dict, json: Dict, stateful_metrics_map) -> None:
53
58
  """Function to load metrics into the new dictionary
54
59
 
55
60
  Args:
@@ -65,9 +70,14 @@ def load_metrics(ms: Dict, json: Dict) -> None:
65
70
  i = 0
66
71
  hold = []
67
72
  for metric in metrics:
68
- if all([x in ms["Metrics"] for x in metric["metrics_used"]]):
73
+ if all(
74
+ [
75
+ x in ms["Metrics"] or x in stateful_metrics_map
76
+ for x in metric["metrics_used"]
77
+ ]
78
+ ):
69
79
  i += 1
70
- metric = convert_metric(ms, metric)
80
+ metric = convert_metric(ms, metric, stateful_metrics_map)
71
81
  assert (
72
82
  metric.name not in ms["Metrics"]
73
83
  ), "{} was a repeated metric".format(metric.name)
@@ -80,6 +90,15 @@ def load_metrics(ms: Dict, json: Dict) -> None:
80
90
  for y in metrics:
81
91
  for z in y["metrics_used"]:
82
92
  assert (
83
- z in ms["Metrics"] or z in names
93
+ z in ms["Metrics"] or z in names or z in stateful_metrics_map
84
94
  ), "{} is not defined in the spec".format(z)
85
95
  assert len(metrics) == 0, "There are circular references"
96
+
97
+ # Load the metrics into the policies
98
+ for key in ms["Policies"]:
99
+ policy = ms["Policies"][key]
100
+ hold = policy.metrics_used[:]
101
+ policy.metrics_used = []
102
+ for x in hold:
103
+ assert x in ms["Metrics"], "{} not a valid metric".format(x)
104
+ policy.metrics_used.append(ms["Metrics"][x])
@@ -0,0 +1,100 @@
1
+ from .general import check_json_keys
2
+ from ..Classes import Type
3
+ import os
4
+ from typing import _UnionGenericAlias
5
+
6
+
7
+ def convert_type(data, ms):
8
+
9
+ if "metadata" not in data:
10
+ data["metadata"] = {}
11
+
12
+ # Check the keys are correct
13
+ check_json_keys(data, "Type")
14
+
15
+ # Copy
16
+ data = data.copy()
17
+
18
+ type_name = data["type"]
19
+ data["type"] = {}
20
+ data["type_name"] = {}
21
+
22
+ if "python" in ms["Type Keys"]:
23
+
24
+ if type_name in ms["Type Keys"]["python"]:
25
+ data["type"]["python"] = ms["Type Keys"]["python"][type_name]
26
+ if type(data["type"]["python"]) == dict:
27
+ out = {}
28
+ for key in data["type"]["python"]:
29
+ val = data["type"]["python"][key]
30
+ if type(val) == str:
31
+ val = ms["Types"][val].name
32
+ else:
33
+ val = val.__name__
34
+ out[key] = val
35
+ data["type_name"]["python"] = str(out)
36
+ elif type(data["type"]["python"]) == _UnionGenericAlias:
37
+ data["type_name"]["python"] = data["type"]["python"].__repr__()
38
+ else:
39
+ data["type_name"]["python"] = data["type"]["python"].__name__
40
+ if type_name in ms["Type Keys"]["typescript"]:
41
+ data["type"]["typescript"] = ms["Type Keys"]["typescript"][type_name]
42
+ data["type_name"]["typescript"] = ms["Type Keys"]["typescript"][type_name]
43
+
44
+ # Build the type object
45
+ return Type(data)
46
+
47
+
48
+ def load_types(ms, json) -> None:
49
+
50
+ ms["Types"] = {}
51
+ for data in json["Types"]:
52
+ ms["Types"][data["name"]] = convert_type(data, ms)
53
+
54
+
55
+ def load_python_type_key():
56
+ from src.TypeMappings.types import mapping
57
+
58
+ return mapping
59
+
60
+
61
+ def load_typescript_type_key(path):
62
+ with open(path, "r") as file:
63
+ type_definitions = file.read()
64
+ type_definitions = type_definitions.split("\n")
65
+ type_definitions = [x for x in type_definitions if len(x) > 0]
66
+ hold = type_definitions[:]
67
+ type_definitions = []
68
+ type_definitions.append(hold.pop(0))
69
+ while len(hold) > 0:
70
+ curr = hold.pop(0)
71
+ if "type" in curr or "interface" in curr:
72
+ type_definitions.append(curr)
73
+ else:
74
+ type_definitions[-1] += "\n" + curr
75
+
76
+ hold = type_definitions[:]
77
+ type_definitions = {}
78
+ for x in hold:
79
+ name = x
80
+ if x.startswith("type"):
81
+ name = name[5:]
82
+ elif x.startswith("interface"):
83
+ name = name[10:]
84
+ else:
85
+ assert False
86
+ name = name[: name.index("=")].strip()
87
+ type_definitions[name] = x
88
+ return type_definitions
89
+
90
+
91
+ def load_type_keys(ms) -> dict:
92
+ type_keys = {}
93
+ python_path = "src/TypeMappings/types.py"
94
+ typescript_path = "src/TypeMappings/types.ts"
95
+ if os.path.exists(python_path):
96
+ type_keys["python"] = load_python_type_key()
97
+ if os.path.exists(typescript_path):
98
+ type_keys["typescript"] = load_typescript_type_key(typescript_path)
99
+
100
+ ms["Type Keys"] = type_keys
@@ -111,7 +111,9 @@ def write_entity_reports(ms: MathSpec, directory: str, entities: List[str]) -> N
111
111
  f.write(out)
112
112
 
113
113
 
114
- def write_spec_tree(ms: MathSpec, path=None, linking=False, add_tabbing=False) -> str:
114
+ def write_spec_tree(
115
+ ms: MathSpec, path=None, linking=False, add_tabbing=False, readme=False
116
+ ) -> str:
115
117
  """Write the tree of the specification structure
116
118
 
117
119
  Args:
@@ -198,6 +200,9 @@ def write_spec_tree(ms: MathSpec, path=None, linking=False, add_tabbing=False) -
198
200
  out = out.split("\n")
199
201
  out = ["\t" + x for x in out]
200
202
  out = "\n".join(out)
203
+ if readme:
204
+ out = "\n\n```\n{}\n```".format(out)
205
+ out = out.replace("**", "")
201
206
 
202
207
  if path:
203
208
  with open("{}/Spec Tree.md".format(path), "w") as f:
@@ -211,6 +216,6 @@ def write_overview(ms: MathSpec, name: str, file_path: str, summary: str = None)
211
216
  out += "<h2>Summary</h2>"
212
217
  out += "<p>{}</p>".format(summary)
213
218
  out += "<h2>Specification Tree</h2>"
214
- out += write_spec_tree(ms)
219
+ out += write_spec_tree(ms, readme=True)
215
220
  with open(file_path, "w") as f:
216
221
  f.write(out)
@@ -90,8 +90,16 @@ def write_types_markdown_report(ms, path, t, add_metadata=True):
90
90
 
91
91
  out += "## Type"
92
92
  out += "\n"
93
- out += str(t.type)
94
- out += "\n\n"
93
+
94
+ if "python" in t.type:
95
+ out += "### Python Type\n"
96
+ out += t.type_name["python"]
97
+ out += "\n"
98
+ if "typescript" in t.type:
99
+ out += "### Typescript Type\n"
100
+ out += t.type_name["typescript"]
101
+ out += "\n"
102
+ out += "\n"
95
103
  out += "## Notes"
96
104
  out += "\n\n"
97
105
  out += t.notes
@@ -204,6 +212,16 @@ def write_policy_markdown_report(ms, path, policy, add_metadata=True):
204
212
  out += "{}. {}".format(i + 1, x)
205
213
  out += "\n"
206
214
 
215
+ out += "## Parameters Used\n"
216
+ for i, x in enumerate(policy.parameters_used):
217
+ out += "{}. [[{}]]".format(i + 1, x)
218
+ out += "\n"
219
+
220
+ out += "## Metrics Used\n"
221
+ for i, x in enumerate(policy.metrics_used):
222
+ out += "{}. [[{}]]".format(i + 1, x.name)
223
+ out += "\n"
224
+
207
225
  if policy.policy_options:
208
226
  out += "## Policy Options\n"
209
227
  for i, x in enumerate(policy.policy_options):
@@ -292,7 +310,9 @@ def write_space_markdown_report(ms, path, space, add_metadata=True):
292
310
  out += "\n"
293
311
  out += "\n"
294
312
  d = space.schema
295
- d = ",\n".join(["{}: {}".format(a, b.name) for a, b in zip(d.keys(), d.values())])
313
+ d = ",\n".join(
314
+ ["{}: [[{}]]".format(a, b.name) for a, b in zip(d.keys(), d.values())]
315
+ )
296
316
  d = "{" + d + "}"
297
317
  out += d
298
318
  out += "\n"
@@ -337,18 +357,14 @@ def write_control_action_markdown_report(ms, path, control_action, add_metadata=
337
357
  if control_action.control_action_options:
338
358
  out += "## Control Action Options:\n"
339
359
  for i, x in enumerate(control_action.control_action_options):
340
- out += "<details>"
341
- out += "<summary><b>{}. {}</b></summary>".format(i + 1, x.name)
342
- out += "<p>"
360
+ out += "### {}. {}\n".format(i + 1, x.name)
361
+ out += "#### Description\n"
343
362
  out += x.description
344
- out += "</p>"
345
-
346
- out += "<p>"
347
- out += "Logic: {}".format(x.logic)
348
- out += "</p>"
363
+ out += "\n"
349
364
 
350
- out += "</details>"
351
- out += "<br/>"
365
+ out += "#### Logic\n"
366
+ out += x.logic
367
+ out += "\n\n"
352
368
 
353
369
  with open("{}/Control Actions/{}.md".format(path, control_action.label), "w") as f:
354
370
  f.write(out)
@@ -408,6 +424,12 @@ def write_wiring_markdown_report(ms, path, wiring, add_metadata=True):
408
424
  out += "\n"
409
425
  out += "\n"
410
426
 
427
+ out += "## All Spaces Used\n"
428
+ for i, x in enumerate(wiring.all_spaces_used):
429
+ out += "{}. [[{}]]".format(i + 1, x.name)
430
+ out += "\n"
431
+ out += "\n"
432
+
411
433
  out += "## Parameters Used\n"
412
434
  for i, x in enumerate(wiring.parameters_used):
413
435
  out += "{}. [[{}]]".format(i + 1, x)
@@ -426,6 +448,12 @@ def write_wiring_markdown_report(ms, path, wiring, add_metadata=True):
426
448
  out += "\n"
427
449
  out += "\n"
428
450
 
451
+ out += "## All State Updates\n"
452
+ for i, x in enumerate(wiring.all_updates):
453
+ out += "{}. [[{}]].{}".format(i + 1, x[0].name, x[1].name)
454
+ out += "\n"
455
+ out += "\n"
456
+
429
457
  with open("{}/Wiring/{}.md".format(path, wiring.name), "w") as f:
430
458
  f.write(out)
431
459
 
@@ -539,6 +567,77 @@ def write_metrics_markdown_report(ms, path, metric, add_metadata=True):
539
567
  f.write(out)
540
568
 
541
569
 
570
+ def write_displays_markdown_reports(ms, path, add_metadata=True):
571
+ if "Displays" not in os.listdir(path):
572
+ os.makedirs(path + "/Displays")
573
+ if "Wiring" not in os.listdir(path + "/Displays"):
574
+ os.makedirs(path + "/Displays/Wiring")
575
+
576
+ for wiring in ms.displays["Wiring"]:
577
+ write_wiring_display_markdown_report(
578
+ ms, path, wiring, add_metadata=add_metadata
579
+ )
580
+
581
+
582
+ def write_wiring_display_markdown_report(ms, path, wiring, add_metadata=True):
583
+ wirings = [ms.wiring[w] for w in wiring["components"]]
584
+ out = ""
585
+
586
+ out += "## Wiring Diagrams"
587
+ out += "\n"
588
+ out += "\n"
589
+ for w in wirings:
590
+ out += w.render_mermaid_root()
591
+ out += "\n"
592
+ out += "\n"
593
+ out += "## Description"
594
+ out += "\n"
595
+ out += "\n"
596
+ out += wiring["description"]
597
+ out += "\n"
598
+
599
+ out += "## Wirings\n"
600
+ for i, x in enumerate(wiring["components"]):
601
+ out += "{}. [[{}]]".format(i + 1, x)
602
+ out += "\n"
603
+ out += "\n"
604
+
605
+ out += "## Unique Components Used\n"
606
+ components = [set(x.components) for x in wirings]
607
+ components = set().union(*components)
608
+ for i, x in enumerate(components):
609
+ out += "{}. [[{}]]".format(i + 1, x.name)
610
+ out += "\n"
611
+ out += "\n"
612
+
613
+ """domain = [set(x.domain) for x in wirings]
614
+ domain = set().union(*domain)
615
+ out += "## Unique Domain Spaces\n"
616
+ for i, x in enumerate(domain):
617
+ out += "{}. [[{}]]".format(i + 1, x.name)
618
+ out += "\n"
619
+ out += "\n"
620
+
621
+ codomain = [set(x.codomain) for x in wirings]
622
+ codomain = set().union(*codomain)
623
+ out += "## Unique Codomain Spaces\n"
624
+ for i, x in enumerate(codomain):
625
+ out += "{}. [[{}]]".format(i + 1, x.name)
626
+ out += "\n"
627
+ out += "\n"""
628
+
629
+ parameters = [set(x.parameters_used) for x in wirings]
630
+ parameters = set().union(*parameters)
631
+ out += "## Unique Parameters Used\n"
632
+ for i, x in enumerate(parameters):
633
+ out += "{}. [[{}]]".format(i + 1, x)
634
+ out += "\n"
635
+ out += "\n"
636
+
637
+ with open("{}/Displays/Wiring/{}.md".format(path, wiring["name"]), "w") as f:
638
+ f.write(out)
639
+
640
+
542
641
  def write_all_markdown_reports(ms, path):
543
642
 
544
643
  # Write entities
@@ -598,3 +697,7 @@ def write_all_markdown_reports(ms, path):
598
697
  # Write metrics
599
698
  for x in ms.metrics:
600
699
  write_metrics_markdown_report(ms, path, x)
700
+
701
+ # Write displays
702
+ if ms.displays:
703
+ write_displays_markdown_reports(ms, path, add_metadata=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math_spec_mapping
3
- Version: 0.2.2
3
+ Version: 0.2.4
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
@@ -25,6 +25,7 @@ src/Load/__init__.py
25
25
  src/Load/action_transmission_channel.py
26
26
  src/Load/boundary_actions.py
27
27
  src/Load/control_actions.py
28
+ src/Load/displays.py
28
29
  src/Load/entities.py
29
30
  src/Load/general.py
30
31
  src/Load/load.py
@@ -1,24 +0,0 @@
1
- from .general import check_json_keys
2
- from ..Classes import Type
3
-
4
-
5
- def convert_type(data, ms):
6
-
7
- if "metadata" not in data:
8
- data["metadata"] = {}
9
-
10
- # Check the keys are correct
11
- check_json_keys(data, "Type")
12
-
13
- # Copy
14
- data = data.copy()
15
-
16
- # Build the type object
17
- return Type(data)
18
-
19
-
20
- def load_types(ms, json) -> None:
21
-
22
- ms["Types"] = {}
23
- for data in json["Types"]:
24
- ms["Types"][data["name"]] = convert_type(data, ms)