modelbase2 0.1.79__py3-none-any.whl → 0.2.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.
Files changed (58) hide show
  1. modelbase2/__init__.py +138 -26
  2. modelbase2/distributions.py +306 -0
  3. modelbase2/experimental/__init__.py +17 -0
  4. modelbase2/experimental/codegen.py +239 -0
  5. modelbase2/experimental/diff.py +227 -0
  6. modelbase2/experimental/notes.md +4 -0
  7. modelbase2/experimental/tex.py +521 -0
  8. modelbase2/fit.py +284 -0
  9. modelbase2/fns.py +185 -0
  10. modelbase2/integrators/__init__.py +19 -0
  11. modelbase2/integrators/int_assimulo.py +146 -0
  12. modelbase2/integrators/int_scipy.py +147 -0
  13. modelbase2/label_map.py +610 -0
  14. modelbase2/linear_label_map.py +301 -0
  15. modelbase2/mc.py +548 -0
  16. modelbase2/mca.py +280 -0
  17. modelbase2/model.py +1621 -0
  18. modelbase2/npe.py +343 -0
  19. modelbase2/parallel.py +171 -0
  20. modelbase2/parameterise.py +28 -0
  21. modelbase2/paths.py +36 -0
  22. modelbase2/plot.py +829 -0
  23. modelbase2/sbml/__init__.py +14 -0
  24. modelbase2/sbml/_data.py +77 -0
  25. modelbase2/sbml/_export.py +656 -0
  26. modelbase2/sbml/_import.py +585 -0
  27. modelbase2/sbml/_mathml.py +691 -0
  28. modelbase2/sbml/_name_conversion.py +52 -0
  29. modelbase2/sbml/_unit_conversion.py +74 -0
  30. modelbase2/scan.py +616 -0
  31. modelbase2/scope.py +96 -0
  32. modelbase2/simulator.py +635 -0
  33. modelbase2/surrogates/__init__.py +32 -0
  34. modelbase2/surrogates/_poly.py +66 -0
  35. modelbase2/surrogates/_torch.py +249 -0
  36. modelbase2/surrogates.py +316 -0
  37. modelbase2/types.py +352 -11
  38. modelbase2-0.2.0.dist-info/METADATA +81 -0
  39. modelbase2-0.2.0.dist-info/RECORD +42 -0
  40. {modelbase2-0.1.79.dist-info → modelbase2-0.2.0.dist-info}/WHEEL +1 -1
  41. modelbase2/core/__init__.py +0 -29
  42. modelbase2/core/algebraic_module_container.py +0 -130
  43. modelbase2/core/constant_container.py +0 -113
  44. modelbase2/core/data.py +0 -109
  45. modelbase2/core/name_container.py +0 -29
  46. modelbase2/core/reaction_container.py +0 -115
  47. modelbase2/core/utils.py +0 -28
  48. modelbase2/core/variable_container.py +0 -24
  49. modelbase2/ode/__init__.py +0 -13
  50. modelbase2/ode/integrator.py +0 -80
  51. modelbase2/ode/mca.py +0 -270
  52. modelbase2/ode/model.py +0 -470
  53. modelbase2/ode/simulator.py +0 -153
  54. modelbase2/utils/__init__.py +0 -0
  55. modelbase2/utils/plotting.py +0 -372
  56. modelbase2-0.1.79.dist-info/METADATA +0 -44
  57. modelbase2-0.1.79.dist-info/RECORD +0 -22
  58. {modelbase2-0.1.79.dist-info → modelbase2-0.2.0.dist-info/licenses}/LICENSE +0 -0
modelbase2/__init__.py CHANGED
@@ -1,36 +1,148 @@
1
+ """modelbase2: A Python Package for Metabolic Modeling and Analysis.
2
+
3
+ This package provides tools for creating, simulating and analyzing metabolic models
4
+ with features including:
5
+
6
+ Key Features:
7
+ - Model creation and manipulation
8
+ - Steady state and time-series simulations
9
+ - Parameter fitting and optimization
10
+ - Monte Carlo analysis
11
+ - Metabolic Control Analysis (MCA)
12
+ - SBML import/export support
13
+ - Visualization tools
14
+
15
+ Core Components:
16
+ Model: Core class for metabolic model representation
17
+ Simulator: Handles model simulation and integration
18
+ DefaultIntegrator: Standard ODE solver implementation
19
+ LabelMapper: Maps between model components and labels
20
+ Cache: Performance optimization through result caching
21
+
22
+ Simulation Features:
23
+ - Steady state calculations
24
+ - Time course simulations
25
+ - Parameter scanning
26
+ - Surrogate modeling with PyTorch
27
+
28
+ Analysis Tools:
29
+ - Parameter fitting to experimental data
30
+ - Monte Carlo methods for uncertainty analysis
31
+ - Metabolic Control Analysis
32
+ - Custom visualization functions
33
+
34
+ """
35
+
1
36
  from __future__ import annotations
2
37
 
3
38
  __all__ = [
4
- "AlgebraicModule",
5
39
  "Assimulo",
6
- "Constant",
7
- "DerivedConstant",
8
- "DerivedStoichiometry",
40
+ "Cache",
41
+ "DefaultIntegrator",
42
+ "Derived",
43
+ "IntegratorProtocol",
44
+ "LabelMapper",
45
+ "LinearLabelMapper",
9
46
  "Model",
10
- "Reaction",
47
+ "Scipy",
11
48
  "Simulator",
12
- "Variable",
49
+ "cartesian_product",
50
+ "distributions",
51
+ "experimental",
52
+ "fit",
53
+ "make_protocol",
54
+ "mc",
13
55
  "mca",
56
+ "plot",
57
+ "sbml",
58
+ "steady_state",
59
+ "surrogates",
60
+ "time_course",
61
+ "time_course_over_protocol",
14
62
  ]
15
63
 
16
- import logging
17
- from .core.data import (
18
- AlgebraicModule,
19
- Constant,
20
- DerivedConstant,
21
- DerivedStoichiometry,
22
- Reaction,
23
- Variable,
24
- )
25
- from .ode import Assimulo, Model, Simulator, mca
26
-
27
- logger = logging.getLogger(__name__)
28
- logger.setLevel(logging.WARNING)
29
- formatter = logging.Formatter(
30
- fmt="{asctime} - {levelname} - {message}",
31
- datefmt="%Y-%m-%d %H:%M:%S",
32
- style="{",
64
+ import contextlib
65
+ import itertools as it
66
+ from typing import TYPE_CHECKING
67
+
68
+ import pandas as pd
69
+
70
+ if TYPE_CHECKING:
71
+ from modelbase2.types import ArrayLike
72
+
73
+ from . import distributions, experimental, fit, mc, mca, plot, sbml, surrogates
74
+ from .integrators import DefaultIntegrator, Scipy
75
+ from .label_map import LabelMapper
76
+ from .linear_label_map import LinearLabelMapper
77
+ from .mc import Cache
78
+ from .model import Model
79
+ from .scan import (
80
+ steady_state,
81
+ time_course,
82
+ time_course_over_protocol,
33
83
  )
34
- handler = logging.StreamHandler()
35
- handler.setFormatter(formatter)
36
- logger.addHandler(handler)
84
+ from .simulator import Simulator
85
+ from .types import Derived, IntegratorProtocol
86
+
87
+ with contextlib.suppress(ImportError):
88
+ from .integrators import Assimulo
89
+
90
+
91
+ def cartesian_product(parameters: dict[str, ArrayLike]) -> pd.DataFrame:
92
+ """Generate a cartesian product of the parameter values.
93
+
94
+ Args:
95
+ parameters: Dictionary containing parameter names and values.
96
+
97
+ Returns:
98
+ pd.DataFrame: DataFrame containing the cartesian product of the parameter values.
99
+
100
+ """
101
+ return pd.DataFrame(
102
+ it.product(*parameters.values()),
103
+ columns=list(parameters),
104
+ )
105
+
106
+
107
+ def make_protocol(steps: list[tuple[float, dict[str, float]]]) -> pd.DataFrame:
108
+ """Create protocol DataFrame from a dictionary of steps.
109
+
110
+ Arguments:
111
+ steps: dictionary of steps, where each key is the duration of
112
+ the step in seconds and the value is a dictionary of all
113
+ parameter values during that step.
114
+
115
+ Examples:
116
+ >>> make_protocol([
117
+ ... (1, {"k1": 1.0}),
118
+ ... (2, {"k1": 2.0}),
119
+ ... (3, {"k1": 1.0}),
120
+ ... ])
121
+
122
+ | Timedelta | k1 |
123
+ |:----------------|-----:|
124
+ | 0 days 00:00:01 | 1.0 |
125
+ | 0 days 00:00:03 | 2.0 |
126
+ | 0 days 00:00:06 | 1.0 |
127
+
128
+ >>> make_protocol([
129
+ ... (1, {"k1": 1.0, "k2": 2.0}),
130
+ ... (2, {"k1": 2.0, "k2": 3.0}),
131
+ ... (3, {"k1": 1.0, "k2": 2.0}),
132
+ ... ])
133
+
134
+ | Timedelta | k1 | k2 |
135
+ |:----------------|-----:|-----:|
136
+ | 0 days 00:00:01 | 1 | 2 |
137
+ | 0 days 00:00:03 | 2 | 3 |
138
+ | 0 days 00:00:06 | 1 | 2 |
139
+
140
+ """
141
+ data = {}
142
+ t0 = pd.Timedelta(0)
143
+ for step, pars in steps:
144
+ t0 += pd.Timedelta(seconds=step)
145
+ data[t0] = pars
146
+ protocol = pd.DataFrame(data).T
147
+ protocol.index.name = "Timedelta"
148
+ return protocol
@@ -0,0 +1,306 @@
1
+ """Probability Distribution Classes for Parameter Sampling.
2
+
3
+ This module provides a collection of probability distributions used for parameter sampling
4
+ in metabolic modeling and Monte Carlo simulations.
5
+
6
+ Classes:
7
+ Distribution (Protocol): Base protocol for all distribution classes
8
+ Beta: Beta distribution for parameters bounded between 0 and 1
9
+ Uniform: Uniform distribution for parameters with simple bounds
10
+ Normal: Normal (Gaussian) distribution for unbounded parameters
11
+ LogNormal: Log-normal distribution for strictly positive parameters
12
+ Skewnorm: Skewed normal distribution for asymmetric parameter distributions
13
+
14
+ Each distribution class provides:
15
+ - Consistent interface through the sample() method
16
+ - Optional random number generator (RNG) control
17
+ - Reproducible results via seed parameter
18
+
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from dataclasses import dataclass
24
+ from typing import Protocol, cast
25
+
26
+ import numpy as np
27
+ import pandas as pd
28
+ from scipy import stats
29
+
30
+ from modelbase2.plot import Axes, FigAx, _default_fig_ax
31
+ from modelbase2.types import Array
32
+
33
+ __all__ = [
34
+ "Beta",
35
+ "Distribution",
36
+ "GaussianKde",
37
+ "LogNormal",
38
+ "Normal",
39
+ "RNG",
40
+ "Skewnorm",
41
+ "Uniform",
42
+ "sample",
43
+ ]
44
+
45
+ RNG = np.random.default_rng(seed=42)
46
+
47
+
48
+ class Distribution(Protocol):
49
+ """Protocol defining interface for distribution classes.
50
+
51
+ All distribution classes must implement the sample() method.
52
+ """
53
+
54
+ def sample(
55
+ self,
56
+ num: int,
57
+ rng: np.random.Generator | None = None,
58
+ ) -> Array:
59
+ """Generate random samples from the distribution.
60
+
61
+ Args:
62
+ num: Number of samples to generate
63
+ rng: Random number generator
64
+
65
+ Returns:
66
+ Array of random samples
67
+
68
+ """
69
+ ...
70
+
71
+
72
+ @dataclass
73
+ class Beta:
74
+ """Beta distribution for parameters bounded between 0 and 1.
75
+
76
+ Args:
77
+ a: Alpha shape parameter (>0)
78
+ b: Beta shape parameter (>0)
79
+
80
+ """
81
+
82
+ a: float
83
+ b: float
84
+
85
+ def sample(self, num: int, rng: np.random.Generator | None = None) -> Array:
86
+ """Generate random samples from the beta distribution.
87
+
88
+ Args:
89
+ num: Number of samples to generate
90
+ rng: Random number generator
91
+
92
+ """
93
+ if rng is None:
94
+ rng = RNG
95
+ return rng.beta(self.a, self.b, num)
96
+
97
+
98
+ @dataclass
99
+ class Uniform:
100
+ """Uniform distribution for parameters with simple bounds.
101
+
102
+ Args:
103
+ lower_bound: Minimum value
104
+ upper_bound: Maximum value
105
+
106
+ """
107
+
108
+ lower_bound: float
109
+ upper_bound: float
110
+
111
+ def sample(self, num: int, rng: np.random.Generator | None = None) -> Array:
112
+ """Generate random samples from the uniform distribution.
113
+
114
+ Args:
115
+ num: Number of samples to generate
116
+ rng: Random number generator
117
+
118
+ """
119
+ if rng is None:
120
+ rng = RNG
121
+ return rng.uniform(self.lower_bound, self.upper_bound, num)
122
+
123
+
124
+ @dataclass
125
+ class Normal:
126
+ """Normal (Gaussian) distribution for unbounded parameters.
127
+
128
+ Args:
129
+ loc: Mean of the distribution
130
+ scale: Standard deviation
131
+
132
+ """
133
+
134
+ loc: float
135
+ scale: float
136
+
137
+ def sample(self, num: int, rng: np.random.Generator | None = None) -> Array:
138
+ """Generate random samples from the normal distribution.
139
+
140
+ Args:
141
+ num: Number of samples to generate
142
+ rng: Random number generator
143
+
144
+ """
145
+ if rng is None:
146
+ rng = RNG
147
+ return rng.normal(self.loc, self.scale, num)
148
+
149
+
150
+ @dataclass
151
+ class LogNormal:
152
+ """Log-normal distribution for strictly positive parameters.
153
+
154
+ Args:
155
+ mean: Mean of the underlying normal distribution
156
+ sigma: Standard deviation of the underlying normal distribution
157
+ seed: Random seed for reproducibility
158
+
159
+ """
160
+
161
+ mean: float
162
+ sigma: float
163
+
164
+ def sample(self, num: int, rng: np.random.Generator | None = None) -> Array:
165
+ """Generate random samples from the log-normal distribution.
166
+
167
+ Args:
168
+ num: Number of samples to generate
169
+ rng: Random number generator
170
+
171
+ """
172
+ if rng is None:
173
+ rng = RNG
174
+ return rng.lognormal(self.mean, self.sigma, num)
175
+
176
+
177
+ @dataclass
178
+ class Skewnorm:
179
+ """Skewed normal distribution for asymmetric parameter distributions.
180
+
181
+ Args:
182
+ loc: Mean of the distribution
183
+ scale: Standard deviation
184
+ a: Skewness parameter
185
+
186
+ """
187
+
188
+ loc: float
189
+ scale: float
190
+ a: float
191
+
192
+ def sample(
193
+ self,
194
+ num: int,
195
+ rng: np.random.Generator | None = None, # noqa: ARG002
196
+ ) -> Array:
197
+ """Generate random samples from the skewed normal distribution.
198
+
199
+ Args:
200
+ num: Number of samples to generate
201
+ rng: The random generator argument is unused but required for API compatibility
202
+
203
+ """
204
+ return cast(
205
+ Array, stats.skewnorm(self.a, loc=self.loc, scale=self.scale).rvs(num)
206
+ )
207
+
208
+
209
+ @dataclass
210
+ class GaussianKde:
211
+ """Representation of a kernel-density estimate using Gaussian kernels.
212
+
213
+ Args:
214
+ mean: Mean of the underlying normal distribution
215
+ sigma: Standard deviation of the underlying normal distribution
216
+ seed: Random seed for reproducibility
217
+
218
+ """
219
+
220
+ kde: stats.gaussian_kde
221
+
222
+ @classmethod
223
+ def from_data(cls, data: Array | pd.Series) -> GaussianKde:
224
+ """Create a GaussianKde object from a data array.
225
+
226
+ Args:
227
+ data: Array of data points
228
+
229
+ """
230
+ return cls(stats.gaussian_kde(data))
231
+
232
+ def plot(
233
+ self,
234
+ xmin: float,
235
+ xmax: float,
236
+ n: int = 1000,
237
+ ax: Axes | None = None,
238
+ ) -> FigAx:
239
+ """Plot the kernel-density estimate."""
240
+ fig, ax = _default_fig_ax(ax=ax, grid=True, figsize=(5, 3))
241
+
242
+ x = np.geomspace(xmin, xmax, n)
243
+ y = self.kde(x)
244
+ ax.set_xlim(xmin, xmax)
245
+ ax.set_xscale("log")
246
+ ax.fill_between(x, y, alpha=0.2)
247
+ ax.plot(x, y)
248
+ ax.grid(visible=True)
249
+ ax.set_frame_on(False)
250
+ return fig, ax
251
+
252
+ def sample(
253
+ self,
254
+ num: int,
255
+ rng: np.random.Generator | None = None, # noqa: ARG002
256
+ ) -> Array:
257
+ """Generate random samples from the kde.
258
+
259
+ Args:
260
+ num: Number of samples to generate
261
+ rng: Random number generator. Unused but required for API compatibility
262
+
263
+ """
264
+ return cast(Array, self.kde.resample(num)[0])
265
+
266
+
267
+ def sample(
268
+ parameters: dict[str, Distribution],
269
+ n: int,
270
+ rng: np.random.Generator | None = None,
271
+ ) -> pd.DataFrame:
272
+ """Generate samples from the specified distributions.
273
+
274
+ Examples:
275
+ >>> sample({"beta": Beta(a=1.0, b=1.0),
276
+ ... "uniform": Uniform(lower_bound=0.0, upper_bound=1.0),
277
+ ... "normal": Normal(loc=1.0, scale=0.1),
278
+ ... "log_normal": LogNormal(mean=1.0, sigma=0.1),
279
+ ... "skewnorm": Skewnorm(loc=1.0, scale=0.1, a=5.0),},
280
+ ... n=2,)
281
+ beta uniform normal log_normal skewnorm
282
+ 0 0.253043 0.682496 1.067891 2.798020 1.216259
283
+ 1 0.573357 0.139752 1.006758 2.895416 1.129373
284
+
285
+ Args:
286
+ parameters: Dictionary mapping parameter names to distribution objects.
287
+ n: Number of samples to generate.
288
+ rng: Random number generator.
289
+
290
+ Returns: DataFrame containing the generated samples.
291
+
292
+ """
293
+ return pd.DataFrame({k: v.sample(n, rng) for k, v in parameters.items()})
294
+
295
+
296
+ if __name__ == "__main__":
297
+ _ = sample(
298
+ {
299
+ "beta": Beta(a=1.0, b=1.0),
300
+ "uniform": Uniform(lower_bound=0.0, upper_bound=1.0),
301
+ "normal": Normal(loc=1.0, scale=0.1),
302
+ "log_normal": LogNormal(mean=1.0, sigma=0.1),
303
+ "skewnorm": Skewnorm(loc=1.0, scale=0.1, a=5.0),
304
+ },
305
+ n=1,
306
+ )
@@ -0,0 +1,17 @@
1
+ """Experimental features for modelbase2.
2
+
3
+ APIs should be considered unstable and may change without notice.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from .codegen import generate_model_code_py, generate_modelbase_code
9
+ from .diff import model_diff
10
+ from .tex import to_tex
11
+
12
+ __all__ = [
13
+ "generate_model_code_py",
14
+ "generate_modelbase_code",
15
+ "model_diff",
16
+ "to_tex",
17
+ ]