mxlpy 0.20.0__py3-none-any.whl → 0.22.0__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.
@@ -4,15 +4,13 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING, cast
8
8
 
9
9
  import sympy
10
10
 
11
- from mxlpy.meta.source_tools import fn_to_sympy
11
+ from mxlpy.meta.sympy_tools import fn_to_sympy, list_of_symbols
12
12
 
13
13
  if TYPE_CHECKING:
14
- from collections.abc import Iterable
15
-
16
14
  from mxlpy.model import Model
17
15
 
18
16
  __all__ = [
@@ -36,30 +34,44 @@ class SymbolicModel:
36
34
  )
37
35
 
38
36
 
39
- def _list_of_symbols(args: Iterable[str]) -> list[sympy.Symbol]:
40
- return [sympy.Symbol(arg) for arg in args]
41
-
42
-
43
37
  def to_symbolic_model(model: Model) -> SymbolicModel:
44
38
  cache = model._create_cache() # noqa: SLF001
39
+ initial_conditions = model.get_initial_conditions()
45
40
 
46
41
  variables: dict[str, sympy.Symbol] = dict(
47
- zip(model.variables, _list_of_symbols(model.variables), strict=True)
42
+ zip(
43
+ initial_conditions,
44
+ cast(list[sympy.Symbol], list_of_symbols(initial_conditions)),
45
+ strict=True,
46
+ )
48
47
  )
49
48
  parameters: dict[str, sympy.Symbol] = dict(
50
- zip(model.parameters, _list_of_symbols(model.parameters), strict=True)
49
+ zip(
50
+ model.get_parameter_values(),
51
+ cast(list[sympy.Symbol], list_of_symbols(model.get_parameter_values())),
52
+ strict=True,
53
+ )
51
54
  )
52
55
  symbols: dict[str, sympy.Symbol | sympy.Expr] = variables | parameters # type: ignore
53
56
 
54
57
  # Insert derived into symbols
55
- for k, v in model.derived.items():
56
- symbols[k] = fn_to_sympy(v.fn, [symbols[i] for i in v.args])
58
+ for k, v in model.get_raw_derived().items():
59
+ if (
60
+ expr := fn_to_sympy(v.fn, origin=k, model_args=[symbols[i] for i in v.args])
61
+ ) is None:
62
+ msg = f"Unable to parse derived value '{k}'"
63
+ raise ValueError(msg)
64
+ symbols[k] = expr
57
65
 
58
66
  # Insert derived into reaction via args
59
- rxns = {
60
- k: fn_to_sympy(v.fn, [symbols[i] for i in v.args])
61
- for k, v in model.reactions.items()
62
- }
67
+ rxns: dict[str, sympy.Expr] = {}
68
+ for k, v in model.get_raw_reactions().items():
69
+ if (
70
+ expr := fn_to_sympy(v.fn, origin=k, model_args=[symbols[i] for i in v.args])
71
+ ) is None:
72
+ msg = f"Unable to parse reaction '{k}'"
73
+ raise ValueError(msg)
74
+ rxns[k] = expr
63
75
 
64
76
  eqs: dict[str, sympy.Expr] = {}
65
77
  for cpd, stoich in cache.stoich_by_cpds.items():
@@ -80,5 +92,5 @@ def to_symbolic_model(model: Model) -> SymbolicModel:
80
92
  parameters=parameters,
81
93
  eqs=[eqs[i] for i in cache.var_names],
82
94
  initial_conditions=model.get_initial_conditions(),
83
- parameter_values=model.parameters,
95
+ parameter_values=model.get_parameter_values(),
84
96
  )
mxlpy/types.py CHANGED
@@ -36,6 +36,7 @@ __all__ = [
36
36
  "McSteadyStates",
37
37
  "MockSurrogate",
38
38
  "Param",
39
+ "Parameter",
39
40
  "ProtocolByPars",
40
41
  "RateFn",
41
42
  "Reaction",
@@ -45,13 +46,14 @@ __all__ = [
45
46
  "RetType",
46
47
  "SteadyStates",
47
48
  "TimeCourseByPars",
49
+ "Variable",
48
50
  "unwrap",
49
51
  "unwrap2",
50
52
  ]
51
53
 
52
54
  type RateFn = Callable[..., float]
53
55
  type Array = NDArray[np.floating[Any]]
54
- type ArrayLike = NDArray[np.floating[Any]] | list[float]
56
+ type ArrayLike = NDArray[np.floating[Any]] | pd.Index | list[float]
55
57
 
56
58
 
57
59
  Param = ParamSpec("Param")
@@ -59,6 +61,8 @@ RetType = TypeVar("RetType")
59
61
 
60
62
 
61
63
  if TYPE_CHECKING:
64
+ import sympy
65
+
62
66
  from mxlpy.model import Model
63
67
 
64
68
 
@@ -147,34 +151,53 @@ type IntegratorType = Callable[
147
151
  ]
148
152
 
149
153
 
154
+ @dataclass
155
+ class Parameter:
156
+ """Container for parameter meta information."""
157
+
158
+ value: float
159
+ unit: sympy.Expr | None = None
160
+ source: str | None = None
161
+
162
+
163
+ @dataclass
164
+ class Variable:
165
+ """Container for variable meta information."""
166
+
167
+ initial_value: float | Derived
168
+ unit: sympy.Expr | None = None
169
+ source: str | None = None
170
+
171
+
150
172
  @dataclass(kw_only=True, slots=True)
151
173
  class Derived:
152
174
  """Container for a derived value."""
153
175
 
154
176
  fn: RateFn
155
177
  args: list[str]
178
+ unit: sympy.Expr | None = None
156
179
 
157
- def calculate(self, dependent: dict[str, Any]) -> float:
180
+ def calculate(self, args: dict[str, Any]) -> float:
158
181
  """Calculate the derived value.
159
182
 
160
183
  Args:
161
- dependent: Dictionary of dependent variables.
184
+ args: Dictionary of args variables.
162
185
 
163
186
  Returns:
164
187
  The calculated derived value.
165
188
 
166
189
  """
167
- return cast(float, self.fn(*(dependent[arg] for arg in self.args)))
190
+ return cast(float, self.fn(*(args[arg] for arg in self.args)))
168
191
 
169
- def calculate_inpl(self, name: str, dependent: dict[str, Any]) -> None:
192
+ def calculate_inpl(self, name: str, args: dict[str, Any]) -> None:
170
193
  """Calculate the derived value in place.
171
194
 
172
195
  Args:
173
196
  name: Name of the derived variable.
174
- dependent: Dictionary of dependent variables.
197
+ args: Dictionary of args variables.
175
198
 
176
199
  """
177
- dependent[name] = cast(float, self.fn(*(dependent[arg] for arg in self.args)))
200
+ args[name] = cast(float, self.fn(*(args[arg] for arg in self.args)))
178
201
 
179
202
 
180
203
  @dataclass(kw_only=True, slots=True)
@@ -183,28 +206,29 @@ class Readout:
183
206
 
184
207
  fn: RateFn
185
208
  args: list[str]
209
+ unit: sympy.Expr | None = None
186
210
 
187
- def calculate(self, dependent: dict[str, Any]) -> float:
211
+ def calculate(self, args: dict[str, Any]) -> float:
188
212
  """Calculate the derived value.
189
213
 
190
214
  Args:
191
- dependent: Dictionary of dependent variables.
215
+ args: Dictionary of args variables.
192
216
 
193
217
  Returns:
194
218
  The calculated derived value.
195
219
 
196
220
  """
197
- return cast(float, self.fn(*(dependent[arg] for arg in self.args)))
221
+ return cast(float, self.fn(*(args[arg] for arg in self.args)))
198
222
 
199
- def calculate_inpl(self, name: str, dependent: dict[str, Any]) -> None:
223
+ def calculate_inpl(self, name: str, args: dict[str, Any]) -> None:
200
224
  """Calculate the reaction in place.
201
225
 
202
226
  Args:
203
227
  name: Name of the derived variable.
204
- dependent: Dictionary of dependent variables.
228
+ args: Dictionary of args variables.
205
229
 
206
230
  """
207
- dependent[name] = cast(float, self.fn(*(dependent[arg] for arg in self.args)))
231
+ args[name] = cast(float, self.fn(*(args[arg] for arg in self.args)))
208
232
 
209
233
 
210
234
  @dataclass(kw_only=True, slots=True)
@@ -214,35 +238,36 @@ class Reaction:
214
238
  fn: RateFn
215
239
  stoichiometry: Mapping[str, float | Derived]
216
240
  args: list[str]
241
+ unit: sympy.Expr | None = None
217
242
 
218
243
  def get_modifiers(self, model: Model) -> list[str]:
219
244
  """Get the modifiers of the reaction."""
220
- include = set(model.variables)
245
+ include = set(model.get_variable_names())
221
246
  exclude = set(self.stoichiometry)
222
247
 
223
248
  return [k for k in self.args if k in include and k not in exclude]
224
249
 
225
- def calculate(self, dependent: dict[str, Any]) -> float:
250
+ def calculate(self, args: dict[str, Any]) -> float:
226
251
  """Calculate the derived value.
227
252
 
228
253
  Args:
229
- dependent: Dictionary of dependent variables.
254
+ args: Dictionary of args variables.
230
255
 
231
256
  Returns:
232
257
  The calculated derived value.
233
258
 
234
259
  """
235
- return cast(float, self.fn(*(dependent[arg] for arg in self.args)))
260
+ return cast(float, self.fn(*(args[arg] for arg in self.args)))
236
261
 
237
- def calculate_inpl(self, name: str, dependent: dict[str, Any]) -> None:
262
+ def calculate_inpl(self, name: str, args: dict[str, Any]) -> None:
238
263
  """Calculate the reaction in place.
239
264
 
240
265
  Args:
241
266
  name: Name of the derived variable.
242
- dependent: Dictionary of dependent variables.
267
+ args: Dictionary of args variables.
243
268
 
244
269
  """
245
- dependent[name] = cast(float, self.fn(*(dependent[arg] for arg in self.args)))
270
+ args[name] = cast(float, self.fn(*(args[arg] for arg in self.args)))
246
271
 
247
272
 
248
273
  @dataclass(kw_only=True)
mxlpy/units.py ADDED
@@ -0,0 +1,128 @@
1
+ """Unit definitions for MxlPy."""
2
+
3
+ from sympy.physics.units import (
4
+ ampere,
5
+ becquerel,
6
+ candela,
7
+ coulomb,
8
+ farad,
9
+ gram,
10
+ gray,
11
+ henry,
12
+ hertz,
13
+ hour,
14
+ joule,
15
+ katal,
16
+ kelvin,
17
+ kilogram,
18
+ liter,
19
+ lux,
20
+ meter,
21
+ micro,
22
+ milli,
23
+ minute,
24
+ mol,
25
+ nano,
26
+ newton,
27
+ ohm,
28
+ pascal,
29
+ pico,
30
+ radian,
31
+ second,
32
+ siemens,
33
+ steradian,
34
+ tesla,
35
+ volt,
36
+ watt,
37
+ weber,
38
+ )
39
+
40
+ __all__ = [
41
+ "ampere",
42
+ "becquerel",
43
+ "coulomb",
44
+ "dimensionless",
45
+ "farad",
46
+ "gram",
47
+ "gray",
48
+ "henry",
49
+ "hertz",
50
+ "hour",
51
+ "item",
52
+ "joule",
53
+ "katal",
54
+ "kelvin",
55
+ "liter",
56
+ "lumen",
57
+ "lux",
58
+ "micro",
59
+ "milli",
60
+ "minute",
61
+ "mmol",
62
+ "mmol_g",
63
+ "mmol_s",
64
+ "mol",
65
+ "nano",
66
+ "newton",
67
+ "nmol",
68
+ "ohm",
69
+ "pascal",
70
+ "ppfd",
71
+ "radian",
72
+ "second",
73
+ "siemens",
74
+ "sievert",
75
+ "sqm",
76
+ "tesla",
77
+ "volt",
78
+ "watt",
79
+ "weber",
80
+ ]
81
+
82
+ # time unit
83
+ per_second = 1 / second # type: ignore
84
+ per_minute = 1 / minute # type: ignore
85
+ per_hour = 1 / hour # type: ignore
86
+
87
+
88
+ sqm = meter**2
89
+ cbm = meter**3
90
+
91
+ mol_s = mol / second # type: ignore
92
+ mol_m = mol / minute # type: ignore
93
+ mol_h = mol / hour # type: ignore
94
+ mol_g = mol / gram # type: ignore
95
+
96
+ mmol = mol * milli
97
+ mmol_s = mmol / second
98
+ mmol_m = mmol / minute
99
+ mmol_h = mmol / hour
100
+ mmol_g = mmol / gram
101
+
102
+ mumol = mol * micro
103
+ mumol_s = mumol / second
104
+ mumol_m = mumol / minute
105
+ mumol_h = mumol / hour
106
+ mumol_g = mumol / gram
107
+
108
+ nmol = mol * nano
109
+ nmol_s = nmol / second
110
+ nmol_m = nmol / minute
111
+ nmol_h = nmol / hour
112
+ nmol_g = nmol / gram
113
+
114
+ pmol = mol * pico
115
+ pmol_s = pmol / second
116
+ pmol_m = pmol / minute
117
+ pmol_h = pmol / hour
118
+ pmol_g = pmol / gram
119
+
120
+ ppfd = mumol / sqm / second
121
+
122
+
123
+ # SBML units
124
+ avogadro = 6.02214076e23
125
+ sievert = joule / kilogram # type: ignore
126
+ lumen = candela * steradian # type: ignore
127
+ dimensionless = None
128
+ item = 1 # pseudounit for one thing
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mxlpy
3
- Version: 0.20.0
3
+ Version: 0.22.0
4
4
  Summary: A package to build metabolic models
5
5
  Author-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
6
6
  Maintainer-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
@@ -69,6 +69,8 @@ Description-Content-Type: text/markdown
69
69
  [docs-badge]: https://img.shields.io/badge/docs-main-green.svg?style=flat-square
70
70
  [docs]: https://computational-biology-aachen.github.io/mxlpy/
71
71
 
72
+ MxlPy (pronounced "em axe el pie") is a Python package for mechanistic learning (Mxl) - the combination of mechanistic modeling and machine learning to deliver explainable, data-informed solutions.
73
+
72
74
  ## Installation
73
75
 
74
76
  You can install mxlpy using pip: `pip install mxlpy`.
@@ -0,0 +1,58 @@
1
+ mxlpy/__init__.py,sha256=GlBZ-WmSoMgVIeAyVqtEJiRe_jLar84bjbg_FlAr2vw,4477
2
+ mxlpy/carousel.py,sha256=o72YKzfPCDhT5oHhow4oNvIShG-i3-Z0UMEQLt2iE5A,4699
3
+ mxlpy/compare.py,sha256=PJbb_R9GTGrkcEpGNpUfwZpZbUmZHNjsMQ_5qPAxVNo,7746
4
+ mxlpy/distributions.py,sha256=ce6RTqn19YzMMec-u09fSIUA8A92M6rehCuHuXWcX7A,8734
5
+ mxlpy/fit.py,sha256=3hGUqJ2tOOToZLMMaJw5M9b6_UlUJwT_MhUvfPmRBd8,22355
6
+ mxlpy/fns.py,sha256=NLxYwa3ylS7SkISBjw_TgQSKEm7WnkZF9wPigX_ZCAM,13915
7
+ mxlpy/identify.py,sha256=G-Zyr_l-K2mDtIV1xGrQ52QJxoBYqRoNA5RW6GpbNjs,2213
8
+ mxlpy/label_map.py,sha256=kNzqDVp5X6T4uod-y79d6cItOd7_9jmpojDA1TSPRoE,17872
9
+ mxlpy/linear_label_map.py,sha256=6Ye6IziWGKkYD_5z3FmTVwnJ2T9SvVGN3U4CfXjXseo,10320
10
+ mxlpy/mc.py,sha256=AvvnyNIEvaB9gJyd0RtaFs_uVhZ7Xh2FpljHH04YRkc,17217
11
+ mxlpy/mca.py,sha256=BRNbisYijT2SUT6VdIpIh3Id3VgL3NTtycn0VARDWlE,9375
12
+ mxlpy/model.py,sha256=GD1FGppxDJwvEx4ehcQeOx3qkqr8PxDTQ0TwoixBvKI,71617
13
+ mxlpy/parallel.py,sha256=yLQLw5O4vnPVp_Zmtw1UhPWtB3483foimxQB-TwFKPg,5016
14
+ mxlpy/parameterise.py,sha256=IgbvfEnkmaqVq_5GgFjHqApGUN9CJrsVD3Fr7pg9iFA,758
15
+ mxlpy/paths.py,sha256=TK2wO4N9lG-UV1JGfeB64q48JVDbwqIUj63rl55MKuQ,1022
16
+ mxlpy/plot.py,sha256=PA7tAmy2XXACxBLtdnfpxKUFRzi-lnCQjr7gw_nzxKU,32544
17
+ mxlpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ mxlpy/report.py,sha256=v597yzKecgtoNmlNZ_nVhBCa3czNw0tksOK5mLtAQvE,10631
19
+ mxlpy/scan.py,sha256=WARFQgFwOsO2PzC1d2rGDfgDjYV8cYwc196IB2rzrzY,19416
20
+ mxlpy/simulator.py,sha256=so7Dax42EKppeBUTxWWKxYhdAFKS2jAgWzS04fXuFpY,27751
21
+ mxlpy/types.py,sha256=Z697aAiJ3Dp2nvMvdm60Z8rEhQjKKgrYHa1riZpY-QE,12994
22
+ mxlpy/units.py,sha256=WHtP9s90VR8rUpPLsQ_eQeiW3wMPEryMvLpsDfu0tEo,1946
23
+ mxlpy/experimental/__init__.py,sha256=kZTE-92OErpHzNRqmgSQYH4CGXrogGJ5EL35XGZQ81M,206
24
+ mxlpy/experimental/diff.py,sha256=g5hKvFsEUdEk5OGQ_aQuCxLAnenD_jG4G__EcVfKsx4,9104
25
+ mxlpy/integrators/__init__.py,sha256=OLdcNCDIOiD1Z2LO143YtD47cMadNJt0app41nLAx5o,456
26
+ mxlpy/integrators/int_assimulo.py,sha256=8gLR1D4zJ-TnJ9DTkfkqA2uVE0H2w_npZhZ8RoWZOX8,5013
27
+ mxlpy/integrators/int_scipy.py,sha256=82nU6cN4PjPoTEXSK5GuFxG89EnnKBHbjG8A9YDPKnc,4749
28
+ mxlpy/meta/__init__.py,sha256=_Bec5aPJ6YyAkxUXlsQtAy_2VzX0tPGVSj-eGACqrXc,404
29
+ mxlpy/meta/codegen_latex.py,sha256=i4tPvk2-toAYqtf4TynuE9sfUSHUp21AMUgjgFEB0uo,23215
30
+ mxlpy/meta/codegen_model.py,sha256=LT767mzniKgAAtMTbejGcl6YmivNa3J1wZjEsH6iX9M,5067
31
+ mxlpy/meta/codegen_mxlpy.py,sha256=Yx6GtsHUup4bIrEyMw9FYE60Y35xAK81IC-r0EdZDEM,3576
32
+ mxlpy/meta/source_tools.py,sha256=imdNbGfDjmEEI7gLWm3BFUfB1xwhW4Lt6mhKvE0PhLw,20735
33
+ mxlpy/meta/sympy_tools.py,sha256=TJSCFK9yuxwNrUHbZrcayo_g1UQWmiUiw4Z5V_pUye4,2853
34
+ mxlpy/nn/__init__.py,sha256=Qjr-ERsY2lbD75sFBOhCUwEasQDSJKcpBn_kReLZ6oA,633
35
+ mxlpy/nn/_keras.py,sha256=-5zjHRu8OjSiZeuBSIZFyB63uBsNNH5o9y4kBcPnhx8,2263
36
+ mxlpy/nn/_torch.py,sha256=GUJmLU282VU4O-fs3Sz90SEaAnfuXN2MPlBr_tHmvn4,5775
37
+ mxlpy/npe/__init__.py,sha256=hBHCUD2JYDBBGS2kTY8mTCfWB3u1R7m5l--wUupZt6o,1270
38
+ mxlpy/npe/_keras.py,sha256=ytvXMPK9KUCGOzTQm08_SgafiMb-MOIUdZQV7JjAO40,9721
39
+ mxlpy/npe/_torch.py,sha256=v3joh6lFJJxvYJj--wzmKXL9UMTaIN3h6hPNq0uX9NU,11250
40
+ mxlpy/sbml/__init__.py,sha256=Mt97CddpLi3wIrA1b_5cagLmDdNxAVF_S7QV57Pzw8s,226
41
+ mxlpy/sbml/_data.py,sha256=yYli7ZQ1_pnH9kt5EmcuHM0moQoa43rrFVdrseXlG0o,1136
42
+ mxlpy/sbml/_export.py,sha256=DibzxWLsHQeI4rmvhpV0AfbDmud3lIcfcdm5BV51-PE,20538
43
+ mxlpy/sbml/_import.py,sha256=aCxNKEO6qaZRc7XWFwzOLE1PV0hXFstJbD-SkLjef2k,22082
44
+ mxlpy/sbml/_mathml.py,sha256=oaU9q5yb9jvDGxDJrqOkbOiurCB1Vv_P99oUwJ7v1VE,24437
45
+ mxlpy/sbml/_name_conversion.py,sha256=93muW47M7qJoE227HKHmThWpPeWsXDN9eM8cRH2pqPs,1340
46
+ mxlpy/sbml/_unit_conversion.py,sha256=dW_I6_Ou09ccwnp6LIdrPriIQnQUK5lJcjzM2Fawm6U,1927
47
+ mxlpy/surrogates/__init__.py,sha256=cz9qr0ToYSutIK45IvKrMe1mPP7Lj0I_V0HYGixfpZU,916
48
+ mxlpy/surrogates/_keras.py,sha256=r2pR3iTJOaMqtATbsCm5CF94TYG9b-9cKljc8kMOplQ,3852
49
+ mxlpy/surrogates/_poly.py,sha256=z2g3JTdVyQJ8dIiXP4BOun_yMZOrlYpPNvQ0wmFYDTk,3672
50
+ mxlpy/surrogates/_qss.py,sha256=9w-hPPhdcwybkyaSX0sIfYfvcKu1U5j4HHj4SlgZcYQ,723
51
+ mxlpy/surrogates/_torch.py,sha256=gU0secuRBYgewhNqZmSo6_Xf804dSzwWwIYmdKA7y60,6389
52
+ mxlpy/symbolic/__init__.py,sha256=_vM5YM5I6OH0QDbFt9uGYKO8Z5Vly0wbGuvUScVrPRU,258
53
+ mxlpy/symbolic/strikepy.py,sha256=tzo3uvPpXLDex09hWTuitVzuTNwbgl7jWGjD8g6a8iI,20033
54
+ mxlpy/symbolic/symbolic_model.py,sha256=cKfWoktvFmXjuo8egE7gXKrKBq2iBUiy_BcIKIvvz8A,3026
55
+ mxlpy-0.22.0.dist-info/METADATA,sha256=LsEH4wwslk1cTqQzL_JvkHvPlk5zdfnNebzUzPPhHeY,4601
56
+ mxlpy-0.22.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
+ mxlpy-0.22.0.dist-info/licenses/LICENSE,sha256=lHX9Eu70g3Iv1aOxXTWNHa3vq9vaVYSPQx4jOLYmDpw,1096
58
+ mxlpy-0.22.0.dist-info/RECORD,,
mxlpy/meta/codegen_py.py DELETED
@@ -1,115 +0,0 @@
1
- """Module to export models as code."""
2
-
3
- from __future__ import annotations
4
-
5
- import warnings
6
- from typing import TYPE_CHECKING
7
-
8
- import sympy
9
-
10
- from mxlpy.meta.source_tools import fn_to_sympy, sympy_to_inline
11
- from mxlpy.types import Derived
12
-
13
- if TYPE_CHECKING:
14
- from collections.abc import Callable, Generator, Iterable, Iterator
15
-
16
- from mxlpy.model import Model
17
-
18
- __all__ = [
19
- "generate_model_code_py",
20
- ]
21
-
22
-
23
- def _conditional_join[T](
24
- iterable: Iterable[T],
25
- question: Callable[[T], bool],
26
- true_pat: str,
27
- false_pat: str,
28
- ) -> str:
29
- """Join an iterable, applying a pattern to each element based on a condition."""
30
-
31
- def inner(it: Iterator[T]) -> Generator[str, None, None]:
32
- yield str(next(it))
33
- while True:
34
- try:
35
- el = next(it)
36
- if question(el):
37
- yield f"{true_pat}{el}"
38
- else:
39
- yield f"{false_pat}{el}"
40
- except StopIteration:
41
- break
42
-
43
- return "".join(inner(iter(iterable)))
44
-
45
-
46
- def _list_of_symbols(args: list[str]) -> list[sympy.Symbol | sympy.Expr]:
47
- return [sympy.Symbol(arg) for arg in args]
48
-
49
-
50
- # FIXME: generate from SymbolicModel, should be easier?
51
- def generate_model_code_py(model: Model) -> str:
52
- """Transform the model into a single function, inlining the function calls."""
53
- source = [
54
- "from collections.abc import Iterable\n",
55
- "from mxlpy.types import Float\n",
56
- "def model(t: Float, variables: Float) -> Iterable[Float]:",
57
- ]
58
-
59
- # Variables
60
- variables = model.variables
61
- if len(variables) > 0:
62
- source.append(" {} = variables".format(", ".join(variables)))
63
-
64
- # Parameters
65
- parameters = model.parameters
66
- if len(parameters) > 0:
67
- source.append("\n".join(f" {k} = {v}" for k, v in model.parameters.items()))
68
-
69
- # Derived
70
- for name, derived in model.derived.items():
71
- expr = fn_to_sympy(derived.fn, model_args=_list_of_symbols(derived.args))
72
- source.append(f" {name} = {sympy_to_inline(expr)}")
73
-
74
- # Reactions
75
- for name, rxn in model.reactions.items():
76
- expr = fn_to_sympy(rxn.fn, model_args=_list_of_symbols(rxn.args))
77
- source.append(f" {name} = {sympy_to_inline(expr)}")
78
-
79
- # Stoichiometries; FIXME: do this with sympy instead as well?
80
- stoich_srcs = {}
81
- for rxn_name, rxn in model.reactions.items():
82
- for i, (cpd_name, factor) in enumerate(rxn.stoichiometry.items()):
83
- if isinstance(factor, Derived):
84
- expr = fn_to_sympy(factor.fn, model_args=_list_of_symbols(factor.args))
85
- src = f"{sympy_to_inline(expr)} * {rxn_name}"
86
- elif factor == 1:
87
- src = rxn_name
88
- elif factor == -1:
89
- src = f"-{rxn_name}" if i == 0 else f"- {rxn_name}"
90
- else:
91
- src = f"{factor} * {rxn_name}"
92
- stoich_srcs.setdefault(cpd_name, []).append(src)
93
- for variable, stoich in stoich_srcs.items():
94
- source.append(
95
- f" d{variable}dt = {_conditional_join(stoich, lambda x: x.startswith('-'), ' ', ' + ')}"
96
- )
97
-
98
- # Surrogates
99
- if len(model._surrogates) > 0: # noqa: SLF001
100
- warnings.warn(
101
- "Generating code for Surrogates not yet supported.",
102
- stacklevel=1,
103
- )
104
-
105
- # Return
106
- if len(variables) > 0:
107
- source.append(
108
- " return {}".format(
109
- ", ".join(f"d{i}dt" for i in variables),
110
- ),
111
- )
112
- else:
113
- source.append(" return ()")
114
-
115
- return "\n".join(source)
@@ -1,55 +0,0 @@
1
- mxlpy/__init__.py,sha256=4pbDeyLhQjfL76h2oXdodARzKkrkX5wESV7kEjwC3K8,4399
2
- mxlpy/compare.py,sha256=6iIl6yKXP9guSVLgqqnaqILP_BF_oqyx7DTGbdpwAjM,7800
3
- mxlpy/distributions.py,sha256=ce6RTqn19YzMMec-u09fSIUA8A92M6rehCuHuXWcX7A,8734
4
- mxlpy/fit.py,sha256=i1R_2WErNJdHNf6JWPFPBDfbI7-MkY9fTaO6jgL4Pqk,12433
5
- mxlpy/fns.py,sha256=NLxYwa3ylS7SkISBjw_TgQSKEm7WnkZF9wPigX_ZCAM,13915
6
- mxlpy/identify.py,sha256=I136kpczw_WriN-CtTMP3cBN-K4ZKaHW6lWZCWsIQUE,2233
7
- mxlpy/label_map.py,sha256=Zla9tey-7_POTE57XNEuCSeTqdAbMWZdj_j_OwokngY,17823
8
- mxlpy/linear_label_map.py,sha256=5FyD0MMdSGsC3eKeBnpd1LBHyVBqIDWCDjgR8_q6XZo,10289
9
- mxlpy/mc.py,sha256=6uN2fw4W627FoK_yVNIWbphoPa-pBA7-51nIX81CilU,17200
10
- mxlpy/mca.py,sha256=PloMdBtyoPsiyJT-vnB0RUc1aTFkoMYwvYa7WmKA7tY,9359
11
- mxlpy/model.py,sha256=14gncyYft39rwoiJPb5AynL3whXnZrJY3N7SLExH0Qk,62056
12
- mxlpy/parallel.py,sha256=a69Ci7NrCplo4pq7qFQUMtOPD56SfaZ6Vz3JNplJpZ0,5013
13
- mxlpy/parameterise.py,sha256=IgbvfEnkmaqVq_5GgFjHqApGUN9CJrsVD3Fr7pg9iFA,758
14
- mxlpy/paths.py,sha256=TK2wO4N9lG-UV1JGfeB64q48JVDbwqIUj63rl55MKuQ,1022
15
- mxlpy/plot.py,sha256=PA7tAmy2XXACxBLtdnfpxKUFRzi-lnCQjr7gw_nzxKU,32544
16
- mxlpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- mxlpy/report.py,sha256=6V_kH5usFtar2lUGLjG5k7WIJjUi1TD5qIO7V_6V3Gc,8773
18
- mxlpy/scan.py,sha256=AnDSR-ttOjFGBrvOdhMdM04URZSHVoiS049tK0oUwV8,18948
19
- mxlpy/simulator.py,sha256=fXFRJHXvDzhZHIccxH6l5QJEZUcpYrNCeA9DUkvnN-8,21052
20
- mxlpy/types.py,sha256=FXBkwHgQ3v_k4ER49hDqyFMIA6i1BQf8isPma97LJdg,12605
21
- mxlpy/experimental/__init__.py,sha256=kZTE-92OErpHzNRqmgSQYH4CGXrogGJ5EL35XGZQ81M,206
22
- mxlpy/experimental/diff.py,sha256=MoM15rbMAHa7p9Zva8NxIc7K585kHJYKFaD1LnN5e10,9088
23
- mxlpy/integrators/__init__.py,sha256=OLdcNCDIOiD1Z2LO143YtD47cMadNJt0app41nLAx5o,456
24
- mxlpy/integrators/int_assimulo.py,sha256=8gLR1D4zJ-TnJ9DTkfkqA2uVE0H2w_npZhZ8RoWZOX8,5013
25
- mxlpy/integrators/int_scipy.py,sha256=MEwhTNhMMVQE2UFWxv5fifN6TKVjRsyDmyibuuNNiHI,4649
26
- mxlpy/meta/__init__.py,sha256=Z3LnN3a9qDAJTukHZs_nF_G6DrjKXOqBvOb47rSsAsM,314
27
- mxlpy/meta/codegen_latex.py,sha256=ocdn_mrjPXllYBwImOBQcFzjFR6LONnBs3fhRIA0yzs,22875
28
- mxlpy/meta/codegen_modebase.py,sha256=ziUuwod1F10ak7WTj5gcuVL7MLtK65kUhqKGCxgn3mY,3131
29
- mxlpy/meta/codegen_py.py,sha256=bpwXrGUaf8lO81VVcIh0cbtf4cd84CYDZrL3ngf1FHo,3587
30
- mxlpy/meta/source_tools.py,sha256=8kZD0_FnO2t8MTG9FvEFOhhU52uXKNpQJW6xDOGWGck,13540
31
- mxlpy/nn/__init__.py,sha256=Qjr-ERsY2lbD75sFBOhCUwEasQDSJKcpBn_kReLZ6oA,633
32
- mxlpy/nn/_keras.py,sha256=-5zjHRu8OjSiZeuBSIZFyB63uBsNNH5o9y4kBcPnhx8,2263
33
- mxlpy/nn/_torch.py,sha256=GUJmLU282VU4O-fs3Sz90SEaAnfuXN2MPlBr_tHmvn4,5775
34
- mxlpy/npe/__init__.py,sha256=hBHCUD2JYDBBGS2kTY8mTCfWB3u1R7m5l--wUupZt6o,1270
35
- mxlpy/npe/_keras.py,sha256=ytvXMPK9KUCGOzTQm08_SgafiMb-MOIUdZQV7JjAO40,9721
36
- mxlpy/npe/_torch.py,sha256=v3joh6lFJJxvYJj--wzmKXL9UMTaIN3h6hPNq0uX9NU,11250
37
- mxlpy/sbml/__init__.py,sha256=Mt97CddpLi3wIrA1b_5cagLmDdNxAVF_S7QV57Pzw8s,226
38
- mxlpy/sbml/_data.py,sha256=yYli7ZQ1_pnH9kt5EmcuHM0moQoa43rrFVdrseXlG0o,1136
39
- mxlpy/sbml/_export.py,sha256=4tU3SVxfEvl0E1urZWHyphkiAeH5HeRO1cODvvrczAQ,20342
40
- mxlpy/sbml/_import.py,sha256=5odQBdpD93mQJp2bVIabmPo6NK60nxqrdSVB8fEsF_A,22099
41
- mxlpy/sbml/_mathml.py,sha256=oaU9q5yb9jvDGxDJrqOkbOiurCB1Vv_P99oUwJ7v1VE,24437
42
- mxlpy/sbml/_name_conversion.py,sha256=93muW47M7qJoE227HKHmThWpPeWsXDN9eM8cRH2pqPs,1340
43
- mxlpy/sbml/_unit_conversion.py,sha256=dW_I6_Ou09ccwnp6LIdrPriIQnQUK5lJcjzM2Fawm6U,1927
44
- mxlpy/surrogates/__init__.py,sha256=cz9qr0ToYSutIK45IvKrMe1mPP7Lj0I_V0HYGixfpZU,916
45
- mxlpy/surrogates/_keras.py,sha256=r2pR3iTJOaMqtATbsCm5CF94TYG9b-9cKljc8kMOplQ,3852
46
- mxlpy/surrogates/_poly.py,sha256=z2g3JTdVyQJ8dIiXP4BOun_yMZOrlYpPNvQ0wmFYDTk,3672
47
- mxlpy/surrogates/_qss.py,sha256=9w-hPPhdcwybkyaSX0sIfYfvcKu1U5j4HHj4SlgZcYQ,723
48
- mxlpy/surrogates/_torch.py,sha256=gU0secuRBYgewhNqZmSo6_Xf804dSzwWwIYmdKA7y60,6389
49
- mxlpy/symbolic/__init__.py,sha256=_vM5YM5I6OH0QDbFt9uGYKO8Z5Vly0wbGuvUScVrPRU,258
50
- mxlpy/symbolic/strikepy.py,sha256=tzo3uvPpXLDex09hWTuitVzuTNwbgl7jWGjD8g6a8iI,20033
51
- mxlpy/symbolic/symbolic_model.py,sha256=JFzcIdyfJihvKjef748DMXU6WI8nHjgjIk5BwUuB4HQ,2543
52
- mxlpy-0.20.0.dist-info/METADATA,sha256=oZ5kyCjoeUm28YKPxNSf0kTZx977NA3-3BfEd6riQSI,4402
53
- mxlpy-0.20.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
54
- mxlpy-0.20.0.dist-info/licenses/LICENSE,sha256=lHX9Eu70g3Iv1aOxXTWNHa3vq9vaVYSPQx4jOLYmDpw,1096
55
- mxlpy-0.20.0.dist-info/RECORD,,
File without changes