math-spec-mapping 0.3.21__py3-none-any.whl → 0.4.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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