math-spec-mapping 0.3.21__py3-none-any.whl → 0.4.1__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.
@@ -1,4 +1,4 @@
1
- from typing import Dict, List
1
+ from typing import Dict, List, Literal
2
2
  from .Entity import Entity
3
3
  from .Policy import Policy
4
4
  from .Mechanism import Mechanism
@@ -10,6 +10,16 @@ import shutil
10
10
  import pandas as pd
11
11
  from inspect import signature, getsource, getfile, getsourcelines
12
12
  from IPython.display import display, Markdown
13
+ from copy import copy, deepcopy
14
+
15
+
16
+ class ValidKeyDict(dict):
17
+ def __getitem__(self, key):
18
+ # Add an assertion to check if the key exists
19
+ assert key in self, "Key not valid, valid options are: {}".format(
20
+ ", ".join(self.keys())
21
+ )
22
+ return super().__getitem__(key)
13
23
 
14
24
 
15
25
  class MathSpec:
@@ -54,6 +64,21 @@ class MathSpec:
54
64
  self._crawl_spaces()
55
65
  self._set_source_code()
56
66
 
67
+ self.boundary_actions = ValidKeyDict(self.boundary_actions)
68
+ self.control_actions = ValidKeyDict(self.control_actions)
69
+ self.entities = ValidKeyDict(self.entities)
70
+ self.mechanisms = ValidKeyDict(self.mechanisms)
71
+ self.parameters.parameter_map = ValidKeyDict(self.parameters.parameter_map)
72
+ self.policies = ValidKeyDict(self.policies)
73
+ self.spaces = ValidKeyDict(self.spaces)
74
+ self.state = ValidKeyDict(self.state)
75
+ self.stateful_metrics_map = ValidKeyDict(self.stateful_metrics_map)
76
+ self.wiring = ValidKeyDict(self.wiring)
77
+ self.metrics = ValidKeyDict(self.metrics)
78
+ self.displays = ValidKeyDict(self.displays)
79
+ self.blocks = ValidKeyDict(self.blocks)
80
+ self.components = ValidKeyDict(self.components)
81
+
57
82
  def _check_dictionary_names(self):
58
83
  for key in self.boundary_actions:
59
84
  assert key == self.boundary_actions[key].name
@@ -727,11 +752,13 @@ class MathSpec:
727
752
  state_preperation_functions=None,
728
753
  parameter_preperation_functions=None,
729
754
  metrics_functions=None,
755
+ append_param_change_columns=False,
730
756
  ):
731
757
  state_l = []
732
758
  params_l = []
733
759
  df_l = []
734
760
  metrics_l = []
761
+ param_mods = set()
735
762
  for experiment in experiments:
736
763
  for i in range(experiment["Monte Carlo Runs"]):
737
764
  state, params, msi, df, metrics = self.run_experiment(
@@ -743,6 +770,11 @@ class MathSpec:
743
770
  parameter_preperation_functions=parameter_preperation_functions,
744
771
  metrics_functions=metrics_functions,
745
772
  )
773
+ if append_param_change_columns:
774
+ if experiment["Param Modifications"]:
775
+ for key in experiment["Param Modifications"]:
776
+ df[key] = experiment["Param Modifications"][key]
777
+ param_mods.add(key)
746
778
  df["Monte Carlo Run"] = i + 1
747
779
  df["Experiment"] = experiment["Name"]
748
780
  metrics.loc["Monte Carlo Run"] = i + 1
@@ -753,6 +785,9 @@ class MathSpec:
753
785
  df_l.append(df)
754
786
  metrics_l.append(metrics)
755
787
  df = pd.concat(df_l)
788
+ if append_param_change_columns:
789
+ for key in param_mods:
790
+ df[key] = df[key].fillna(params_base[key])
756
791
  metrics = pd.concat(metrics_l, axis=1).T
757
792
  return df, metrics, state_l, params_l
758
793
 
@@ -976,6 +1011,50 @@ using .Spaces: generate_space_type
976
1011
  self, params, domain_codomain_checking=domain_codomain_checking
977
1012
  )
978
1013
 
1014
+ def _build_state_space(self):
1015
+ state = self.state["Global State"]
1016
+ state_map = {}
1017
+ for variable in state.variables:
1018
+ if "python" in variable.type.type:
1019
+ state_map[variable.name] = variable.type.type["python"]
1020
+ else:
1021
+ state_map[variable.name] = None
1022
+
1023
+ return state_map
1024
+
1025
+ def _build_parameter_space(self):
1026
+ parameter_space = {}
1027
+ for parameter in self.parameters.all_parameters:
1028
+ parameter = self.parameters.parameter_map[parameter]
1029
+ if "python" in parameter.variable_type.type:
1030
+ parameter_space[parameter.name] = parameter.variable_type.type["python"]
1031
+ else:
1032
+ parameter_space[parameter.name] = None
1033
+ for name in self.functional_parameters.keys():
1034
+ fp = self.functional_parameters[name]
1035
+ fp = tuple(fp.keys())
1036
+ parameter_space[name] = Literal[fp]
1037
+ return parameter_space
1038
+
1039
+ def build_cadCAD(
1040
+ self,
1041
+ blocks,
1042
+ state_preperation_functions=[],
1043
+ parameter_preperation_functions=[],
1044
+ ):
1045
+ out = {}
1046
+ out["StateSpace"] = self._build_state_space()
1047
+ out["ParameterSpace"] = self._build_parameter_space()
1048
+ out["Model"] = cadCADModel(
1049
+ self,
1050
+ out["StateSpace"],
1051
+ out["ParameterSpace"],
1052
+ blocks,
1053
+ state_preperation_functions=state_preperation_functions,
1054
+ parameter_preperation_functions=parameter_preperation_functions,
1055
+ )
1056
+ return out
1057
+
979
1058
  def _set_source_code(self):
980
1059
  if "python" not in self.implementations:
981
1060
  self.source_code = None
@@ -991,6 +1070,126 @@ using .Spaces: generate_space_type
991
1070
  self.source_code[x][y] = getsource(self.source_code[x][y])
992
1071
 
993
1072
 
1073
+ class cadCADModel:
1074
+ def __init__(
1075
+ self,
1076
+ ms,
1077
+ state_space,
1078
+ parameter_space,
1079
+ blocks,
1080
+ state_preperation_functions=[],
1081
+ parameter_preperation_functions=[],
1082
+ ):
1083
+ self.ms = ms
1084
+ self.state_space = state_space
1085
+ self.parameter_space = parameter_space
1086
+ self.blocks = blocks
1087
+ self.state_preperation_functions = state_preperation_functions
1088
+ self.parameter_preperation_functions = parameter_preperation_functions
1089
+
1090
+ def create_experiment(
1091
+ self, state, params, record_trajectory=False, use_deepcopy=True
1092
+ ):
1093
+ return Experiment(
1094
+ self,
1095
+ state,
1096
+ params,
1097
+ self.ms,
1098
+ record_trajectory=record_trajectory,
1099
+ use_deepcopy=use_deepcopy,
1100
+ )
1101
+
1102
+ def create_batch_experiments(
1103
+ self, state, params, record_trajectory=False, use_deepcopy=True
1104
+ ):
1105
+ return BatchExperiments(
1106
+ self,
1107
+ state,
1108
+ params,
1109
+ self.ms,
1110
+ record_trajectory=record_trajectory,
1111
+ use_deepcopy=use_deepcopy,
1112
+ )
1113
+
1114
+ def __repr__(self):
1115
+ return f"Model({self.parameter_space}, {self.state_space}, {self.blocks})"
1116
+
1117
+
1118
+ class Experiment:
1119
+ def __init__(self, model, state, params, ms, record_trajectory, use_deepcopy=True):
1120
+ self.model = model
1121
+ self.state = deepcopy(state)
1122
+ self.params = deepcopy(params)
1123
+ self._use_deepcopy = use_deepcopy
1124
+ self.msi = ms.build_implementation(self.params)
1125
+ self.state, self.params = self.msi.prepare_state_and_params(
1126
+ self.state,
1127
+ self.params,
1128
+ state_preperation_functions=self.model.state_preperation_functions,
1129
+ parameter_preperation_functions=self.model.parameter_preperation_functions,
1130
+ )
1131
+
1132
+ if record_trajectory:
1133
+ if self._use_deepcopy:
1134
+ self.trajectories = [deepcopy(self.state)]
1135
+ else:
1136
+ self.trajectories = [copy(self.state)]
1137
+ self.trajectories[-1].pop("Stateful Metrics")
1138
+ self.trajectories[-1].pop("Metrics")
1139
+ else:
1140
+ self.trajectories = None
1141
+ self._record_trajectory = record_trajectory
1142
+ self._iteration_count = 0
1143
+
1144
+ def step(self):
1145
+ self.msi.execute_blocks(self.state, self.params, self.model.blocks)
1146
+ self._iteration_count += 1
1147
+ if self._record_trajectory:
1148
+ if self._use_deepcopy:
1149
+ self.trajectories.append(deepcopy(self.state))
1150
+ else:
1151
+ self.trajectories.append(copy(self.state))
1152
+ self.trajectories[-1].pop("Stateful Metrics")
1153
+ self.trajectories[-1].pop("Metrics")
1154
+
1155
+ def run(self, t):
1156
+ for _ in range(t):
1157
+ self.step()
1158
+
1159
+
1160
+ class BatchExperiments:
1161
+ def __init__(self, model, state, params, ms, record_trajectory, use_deepcopy=True):
1162
+ assert type(state) == list, "Input for state must be a list of states"
1163
+ assert type(params) == list, "Input for params must be a list of states"
1164
+ assert len(state) == len(
1165
+ params
1166
+ ), "Length of state and parameters has to be the same"
1167
+
1168
+ self.experiments = [
1169
+ Experiment(
1170
+ model,
1171
+ s,
1172
+ p,
1173
+ ms,
1174
+ record_trajectory=record_trajectory,
1175
+ use_deepcopy=use_deepcopy,
1176
+ )
1177
+ for s, p in zip(state, params)
1178
+ ]
1179
+
1180
+ def step(self):
1181
+ for experiment in self.experiments:
1182
+ experiment.step()
1183
+
1184
+ def run(self, t):
1185
+ for experiment in self.experiments:
1186
+ experiment.run(t)
1187
+
1188
+ @property
1189
+ def trajectories(self):
1190
+ return [experiment.trajectories for experiment in self.experiments]
1191
+
1192
+
994
1193
  class MathSpecImplementation:
995
1194
  def __init__(self, ms: MathSpec, params, domain_codomain_checking):
996
1195
  self.ms = deepcopy(ms)
@@ -1006,6 +1205,16 @@ class MathSpecImplementation:
1006
1205
  self.load_components()
1007
1206
  self.load_source_files()
1008
1207
 
1208
+ self.boundary_actions = ValidKeyDict(self.boundary_actions)
1209
+ self.control_actions = ValidKeyDict(self.control_actions)
1210
+ self.mechanisms = ValidKeyDict(self.mechanisms)
1211
+ self.policies = ValidKeyDict(self.policies)
1212
+ self.stateful_metrics = ValidKeyDict(self.stateful_metrics)
1213
+ self.wiring = ValidKeyDict(self.wiring)
1214
+ self.metrics = ValidKeyDict(self.metrics)
1215
+ self.blocks = ValidKeyDict(self.blocks)
1216
+ self.components = ValidKeyDict(self.components)
1217
+
1009
1218
  def load_control_actions(self):
1010
1219
  control_actions = {}
1011
1220
  for ca in self.ms.control_actions:
@@ -1022,6 +1231,12 @@ class MathSpecImplementation:
1022
1231
  ), "No functional parameterization for {}. To fix this error, add {} to the parameters passed to ms.build_implementation. Option can be: {}".format(
1023
1232
  ca.name, "FP " + ca.name, [x.name for x in opts]
1024
1233
  )
1234
+ assert (
1235
+ self.params["FP {}".format(ca.name)]
1236
+ in self.ms.functional_parameters["FP {}".format(ca.name)]
1237
+ ), "{} is not a valid functional parameterization for {}".format(
1238
+ self.params["FP {}".format(ca.name)], ca.name
1239
+ )
1025
1240
  opt = self.ms.functional_parameters["FP {}".format(ca.name)][
1026
1241
  self.params["FP {}".format(ca.name)]
1027
1242
  ]
@@ -1061,6 +1276,13 @@ class MathSpecImplementation:
1061
1276
  ba.name, "FP " + ba.name, [x.name for x in opts]
1062
1277
  )
1063
1278
 
1279
+ assert (
1280
+ self.params["FP {}".format(ba.name)]
1281
+ in self.ms.functional_parameters["FP {}".format(ba.name)]
1282
+ ), "{} is not a valid functional parameterization for {}".format(
1283
+ self.params["FP {}".format(ba.name)], ba.name
1284
+ )
1285
+
1064
1286
  opt = self.ms.functional_parameters["FP {}".format(ba.name)][
1065
1287
  self.params["FP {}".format(ba.name)]
1066
1288
  ]
@@ -1165,6 +1387,12 @@ class MathSpecImplementation:
1165
1387
  ), "No functional parameterization for {}. To fix this error, add {} to the parameters passed to ms.build_implementation. Option can be: {}".format(
1166
1388
  p.name, "FP " + p.name, [x.name for x in opts]
1167
1389
  )
1390
+ assert (
1391
+ self.params["FP {}".format(p.name)]
1392
+ in self.ms.functional_parameters["FP {}".format(p.name)]
1393
+ ), "{} is not a valid functional parameterization for {}".format(
1394
+ self.params["FP {}".format(p.name)], p.name
1395
+ )
1168
1396
  opt = self.ms.functional_parameters["FP {}".format(p.name)][
1169
1397
  self.params["FP {}".format(p.name)]
1170
1398
  ]
@@ -92,6 +92,15 @@ def create_milestone_label_matrix(df, exclude_milestones=None):
92
92
  labels = list(df.columns[4:])
93
93
  labels = sorted([x for x in labels if x not in priority_labels])
94
94
  milestones = sorted(list(df[~pd.isnull(df["Milestone"])]["Milestone"].unique()))
95
+ try:
96
+ milestones = sorted(
97
+ milestones,
98
+ key=lambda x: int(x.split(".")[0][1:]) * 10000
99
+ + int(x.split(".")[1]) * 100
100
+ + int(x.split(".")[2]),
101
+ )
102
+ except:
103
+ pass
95
104
 
96
105
  table = []
97
106
  for label in labels:
@@ -1,7 +1,7 @@
1
1
  from .general import check_json_keys
2
2
  from ..Classes import Type
3
3
  import os
4
- from typing import _UnionGenericAlias
4
+ from typing import _UnionGenericAlias, List, _GenericAlias
5
5
 
6
6
 
7
7
  def convert_type(data, ms):
@@ -36,6 +36,8 @@ def convert_type(data, ms):
36
36
  data["type_name"]["python"] = str(out)
37
37
  elif type(data["type"]["python"]) == _UnionGenericAlias:
38
38
  data["type_name"]["python"] = data["type"]["python"].__repr__()
39
+ elif type(data["type"]["python"]) == _GenericAlias:
40
+ data["type_name"]["python"] = data["type"]["python"].__repr__()
39
41
  else:
40
42
  data["type_name"]["python"] = data["type"]["python"].__name__
41
43
  if "typescript" in ms["Type Keys"]:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: math-spec-mapping
3
- Version: 0.3.21
3
+ Version: 0.4.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
@@ -12,6 +12,10 @@ License-File: LICENSE
12
12
  Requires-Dist: graphviz>=0.20.1
13
13
  Requires-Dist: ipython>=7.7.0
14
14
  Requires-Dist: pandas>=1.4
15
+ Requires-Dist: jsonschema>=4.21.1
16
+ Requires-Dist: PyGithub==2.5.0
17
+ Requires-Dist: dotenv
18
+ Requires-Dist: python-dotenv>=1.0.0
15
19
 
16
20
  # Mathematical Specification Mapping Library (MSML)
17
21
 
@@ -6,7 +6,7 @@ math_spec_mapping/Classes/Block.py,sha256=2VOBTPRafmtaLY847tEw3OJTrWNp2d0aSStC_u
6
6
  math_spec_mapping/Classes/BoundaryAction.py,sha256=_rFvEZ4LNxmlM59js4SuQ9n5CgVmITw4YWKs0-q0r-4,560
7
7
  math_spec_mapping/Classes/ControlAction.py,sha256=4AzMSA8fbnUf-fGlvMJXHJFbz32G1h1QVWf2yzrXrLA,493
8
8
  math_spec_mapping/Classes/Entity.py,sha256=fA0-b128_OHHxfCg4pzqyQV083EYev1HlVpy86S5igg,1226
9
- math_spec_mapping/Classes/MathSpec.py,sha256=nQTesARmLrYagoW2T3G6gbidTsFM-NFC9yl3Li01ey8,55970
9
+ math_spec_mapping/Classes/MathSpec.py,sha256=rXiAWuIxtdo4myvCNq7qkBPycCGErMQzVvBRq97HrJc,64548
10
10
  math_spec_mapping/Classes/Mechanism.py,sha256=2sLm3wYBIeTQaMBcsJ9btqIWsbS895Ra8NY6Y9_G_Dg,379
11
11
  math_spec_mapping/Classes/Metric.py,sha256=iQhH4g8Z60QlM22nPX9ytGmidOsZSiSs0KjqwmsScwU,636
12
12
  math_spec_mapping/Classes/Parameter.py,sha256=ZuJ_w0sChvRElJ4sOnXZ2EV4Ell2xXFulKLjVOpgz2E,1237
@@ -19,7 +19,7 @@ math_spec_mapping/Classes/Type.py,sha256=cA5-5nOfjX6aHzTHM8M6mP5lsS7foumckRu7WDX
19
19
  math_spec_mapping/Classes/__init__.py,sha256=0zxgOqns_9JybD74HKMVh6aw8ij8WVbfQ4Q_1uWzof0,761
20
20
  math_spec_mapping/Convenience/__init__.py,sha256=BEZr1rXohKAknOa3wjNVx3EvSVxDcfftJsvtSw5mvmQ,264
21
21
  math_spec_mapping/Convenience/documentation.py,sha256=1ziWVJznbCUxeAAt03nAdEYtMlXNo5TeedHfgs0vSBU,1625
22
- math_spec_mapping/Convenience/github.py,sha256=Wddr1FCxcIxaFeiKyvx3mvVDbzjcgTxs4rU8ulc4qXk,3539
22
+ math_spec_mapping/Convenience/github.py,sha256=JMFJWyA3nRIMNYGvn9831BolnBthoa48HhgeZuENZm8,3772
23
23
  math_spec_mapping/Convenience/starter.py,sha256=dD1R9wcVFZV-BCTflxNkR6Ay6NF1TlVBdIaWmbJwMGE,17379
24
24
  math_spec_mapping/Load/__init__.py,sha256=QfHMLatZAKqj4up-LkDL_r42tO7Mo_-qdqPQYLYY5l0,49
25
25
  math_spec_mapping/Load/action_transmission_channel.py,sha256=oTYCi7as4LWKZLxfRckuWpfLsAPZXjp-VBYmyLBN3yk,2781
@@ -39,7 +39,7 @@ math_spec_mapping/Load/spec_tree.py,sha256=cRSvb3vHPJIJ7pS6KKH3yJLJXPQXMMPt-ciX9
39
39
  math_spec_mapping/Load/state_update_transmission_channels.py,sha256=FJWp5n4HdtHAfof5BUQ6BnRakljatL2h8dWCapaVSc0,2238
40
40
  math_spec_mapping/Load/stateful_metrics.py,sha256=eNXIsNmezVN75L3zMXUl8_JORShm_ovJuM7vkiODs7s,2599
41
41
  math_spec_mapping/Load/states.py,sha256=3YurI7eTNkN6nrXRFVrc58wH0VfM22XOuWE07HVpR7Y,1365
42
- math_spec_mapping/Load/type.py,sha256=FbViE3wV1o1JTx7mUYyUpAvgIxDKDQYc6Iw50FrZ4nY,4808
42
+ math_spec_mapping/Load/type.py,sha256=pIo3lYAP6sxukvbFTDvaun1lslgShksZy2froNnwAfA,4973
43
43
  math_spec_mapping/Load/wiring.py,sha256=l1FhHNFRMKorn1oiRhsuMDsExcXnUmTjqQt5ElE-Bbk,3258
44
44
  math_spec_mapping/Reports/__init__.py,sha256=P3IuE1wiM1EO_yCSD73D4O0O6j7aVWmiwpKJM58ISEs,1121
45
45
  math_spec_mapping/Reports/boundary_actions.py,sha256=45BPp4QjWdD-3E9ZWwqgj_nI2-YdcI2ZZ19_Qv_K7Qk,1410
@@ -55,8 +55,8 @@ math_spec_mapping/Reports/spaces.py,sha256=-76hR5wQBv4lsG000ypBJ-OprjsNjI-rNRMYd
55
55
  math_spec_mapping/Reports/state.py,sha256=QYeCvX5cHeZBrbvMeDsTqJcUDTuDFJSLvPbasjLspk8,3643
56
56
  math_spec_mapping/Reports/tables.py,sha256=O0CNuqh3LMECq5uLjBOoxMUk5hUvkUK660FNnwWUxDY,1505
57
57
  math_spec_mapping/Reports/wiring.py,sha256=u9SvKWy6T-WJUEgFI6-zgZanoOaTTs_2YwmEceDLsV8,1618
58
- math_spec_mapping-0.3.21.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
59
- math_spec_mapping-0.3.21.dist-info/METADATA,sha256=R7kkn8miJCyVczVY_3EknmGt2utf5-uJtAOH6rl5Npw,6850
60
- math_spec_mapping-0.3.21.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
61
- math_spec_mapping-0.3.21.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
62
- math_spec_mapping-0.3.21.dist-info/RECORD,,
58
+ math_spec_mapping-0.4.1.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
59
+ math_spec_mapping-0.4.1.dist-info/METADATA,sha256=UqNOOafGIeJY_gp-mgFXNK2TF6lE_dR8TI-GKGy3i4g,6972
60
+ math_spec_mapping-0.4.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
61
+ math_spec_mapping-0.4.1.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
62
+ math_spec_mapping-0.4.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5