modelbase2 0.1.79__py3-none-any.whl → 0.3.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 (59) hide show
  1. modelbase2/__init__.py +148 -25
  2. modelbase2/distributions.py +336 -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/nnarchitectures.py +128 -0
  19. modelbase2/npe.py +271 -0
  20. modelbase2/parallel.py +171 -0
  21. modelbase2/parameterise.py +28 -0
  22. modelbase2/paths.py +36 -0
  23. modelbase2/plot.py +832 -0
  24. modelbase2/sbml/__init__.py +14 -0
  25. modelbase2/sbml/_data.py +77 -0
  26. modelbase2/sbml/_export.py +656 -0
  27. modelbase2/sbml/_import.py +585 -0
  28. modelbase2/sbml/_mathml.py +691 -0
  29. modelbase2/sbml/_name_conversion.py +52 -0
  30. modelbase2/sbml/_unit_conversion.py +74 -0
  31. modelbase2/scan.py +616 -0
  32. modelbase2/scope.py +96 -0
  33. modelbase2/simulator.py +635 -0
  34. modelbase2/surrogates/__init__.py +31 -0
  35. modelbase2/surrogates/_poly.py +91 -0
  36. modelbase2/surrogates/_torch.py +191 -0
  37. modelbase2/surrogates.py +316 -0
  38. modelbase2/types.py +352 -11
  39. modelbase2-0.3.0.dist-info/METADATA +93 -0
  40. modelbase2-0.3.0.dist-info/RECORD +43 -0
  41. {modelbase2-0.1.79.dist-info → modelbase2-0.3.0.dist-info}/WHEEL +1 -1
  42. modelbase2/core/__init__.py +0 -29
  43. modelbase2/core/algebraic_module_container.py +0 -130
  44. modelbase2/core/constant_container.py +0 -113
  45. modelbase2/core/data.py +0 -109
  46. modelbase2/core/name_container.py +0 -29
  47. modelbase2/core/reaction_container.py +0 -115
  48. modelbase2/core/utils.py +0 -28
  49. modelbase2/core/variable_container.py +0 -24
  50. modelbase2/ode/__init__.py +0 -13
  51. modelbase2/ode/integrator.py +0 -80
  52. modelbase2/ode/mca.py +0 -270
  53. modelbase2/ode/model.py +0 -470
  54. modelbase2/ode/simulator.py +0 -153
  55. modelbase2/utils/__init__.py +0 -0
  56. modelbase2/utils/plotting.py +0 -372
  57. modelbase2-0.1.79.dist-info/METADATA +0 -44
  58. modelbase2-0.1.79.dist-info/RECORD +0 -22
  59. {modelbase2-0.1.79.dist-info → modelbase2-0.3.0.dist-info/licenses}/LICENSE +0 -0
modelbase2/ode/model.py DELETED
@@ -1,470 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import numpy as np
4
- import pandas as pd
5
- from ..core import (
6
- AlgebraicModule,
7
- AlgebraicModuleContainer,
8
- Constant,
9
- ConstantContainer,
10
- DerivedConstant,
11
- NameContainer,
12
- Reaction,
13
- ReactionContainer,
14
- Variable,
15
- VariableContainer,
16
- )
17
- from ..core.data import (
18
- DerivedStoichiometry,
19
- ModuleFunction,
20
- RateFunction,
21
- StoichiometryByReaction,
22
- StoichiometryByVariable,
23
- )
24
- from ..types import Array, Series
25
- from dataclasses import dataclass, field
26
- from functools import singledispatchmethod
27
- from modelbase.ode import Model as OldModel
28
- from typing import Iterable, Literal, Optional, Union, overload
29
-
30
-
31
- def _sort_derived_compounds(m: Model, max_iterations: int = 10_000) -> list[str]:
32
- from queue import Empty, SimpleQueue
33
-
34
- available = set(m.constants)
35
- order = []
36
- to_sort: SimpleQueue = SimpleQueue()
37
- for v in m.derived_constants.values():
38
- to_sort.put((v.name, set(v.args)))
39
-
40
- last_name: str | None = None
41
- i = 0
42
- while True:
43
- try:
44
- name, args = to_sort.get_nowait()
45
- except Empty:
46
- break
47
- if args.issubset(available):
48
- available.add(name)
49
- order.append(name)
50
- else:
51
- if last_name == name:
52
- order.append(name)
53
- break
54
- to_sort.put((name, args))
55
- last_name = name
56
- i += 1
57
- if i > max_iterations:
58
- while True:
59
- try:
60
- name, args = to_sort.get_nowait()
61
- print(name, args)
62
- except Empty:
63
- break
64
-
65
- raise ValueError(
66
- "Exceeded max iterations on sorting. Check if there are circular references."
67
- )
68
- return order
69
-
70
-
71
- @dataclass
72
- class Model:
73
- _algebraic_modules: AlgebraicModuleContainer = field(
74
- default_factory=AlgebraicModuleContainer
75
- )
76
- _variables: VariableContainer = field(default_factory=VariableContainer)
77
- _constants: ConstantContainer = field(default_factory=ConstantContainer)
78
- _reactions: ReactionContainer = field(default_factory=ReactionContainer)
79
- _names: NameContainer = field(default_factory=NameContainer)
80
-
81
- def __add__(self, other: "Model") -> "Model":
82
- for name, variable in other.variables.items():
83
- if name in self.variables:
84
- continue
85
- else:
86
- self.add_variable(variable)
87
-
88
- for name, constant in other.constants.items():
89
- if name in self.constants:
90
- self.update_constant(name, constant.value)
91
- else:
92
- self.add_constant(constant)
93
-
94
- # for name, derived_constant in other.derived_constants.items():
95
- for name in other._constants._derived_constant_order:
96
- derived_constant = other.derived_constants[name]
97
- if name in self.derived_constants:
98
- self.update_derived_constant(
99
- name,
100
- derived_constant.function,
101
- derived_constant.args,
102
- derived_constant.unit,
103
- )
104
- else:
105
- self.add_derived_constant(derived_constant)
106
-
107
- # for name, module in other.algebraic_modules.items():
108
- for name in other._algebraic_modules.module_order:
109
- module = other.algebraic_modules[name]
110
- if name in self.algebraic_modules:
111
- self.update_algebraic_module(
112
- name,
113
- module.function,
114
- module.derived_variables,
115
- module.args,
116
- )
117
- else:
118
- self.add_algebraic_module(module)
119
-
120
- for name, reaction in other.reactions.items():
121
- if reaction.name in self.reactions:
122
- self.update_reaction(
123
- reaction.name,
124
- reaction.function,
125
- reaction.stoichiometry,
126
- reaction.derived_stoichiometry,
127
- reaction.args,
128
- )
129
- else:
130
- self.add_reaction(
131
- Reaction(
132
- name=reaction.name,
133
- function=reaction.function,
134
- stoichiometry=reaction.stoichiometry,
135
- derived_stoichiometry=reaction.derived_stoichiometry,
136
- args=reaction.args,
137
- )
138
- )
139
-
140
- return self
141
-
142
- @property
143
- def constants(self) -> dict[str, Constant]:
144
- return self._constants.constants
145
-
146
- @property
147
- def derived_constants(self) -> dict[str, DerivedConstant]:
148
- return self._constants.derived_constants
149
-
150
- @property
151
- def constant_values(self) -> dict[str, float]:
152
- return self._constants.values
153
-
154
- @property
155
- def variables(self) -> dict[str, Variable]:
156
- return self._variables.variables
157
-
158
- @property
159
- def derived_variables(self) -> list[str]:
160
- return self._algebraic_modules.get_derived_variables()
161
-
162
- @property
163
- def all_variables(self) -> list[str]:
164
- return list(self.variables) + self.derived_variables
165
-
166
- @property
167
- def algebraic_modules(self) -> dict[str, AlgebraicModule]:
168
- return self._algebraic_modules.modules
169
-
170
- @property
171
- def reactions(self) -> dict[str, Reaction]:
172
- return self._reactions.reactions
173
-
174
- @property
175
- def stoichiometries(self) -> dict[str, StoichiometryByVariable]:
176
- return self._reactions.stoichiometries_by_variables
177
-
178
- @singledispatchmethod
179
- def add(
180
- self,
181
- element: Union[list, Constant, DerivedConstant, Variable, AlgebraicModule],
182
- ) -> None:
183
- raise NotImplementedError(element.__class__.__name__)
184
-
185
- @add.register
186
- def _add_iterable(self, elements: list) -> None:
187
- for element in elements:
188
- self.add(element)
189
-
190
- ##########################################################################
191
- # Constants
192
- ##########################################################################
193
-
194
- @add.register
195
- def add_constant(self, constant: Constant) -> None:
196
- self._names.add(constant.name, "constant")
197
- self._constants.add_basic(constant)
198
-
199
- def scale_constant(self, name: str, factor: float) -> None:
200
- value = self.constant_values[name]
201
- self.update_constant(name, value * factor)
202
-
203
- def update_constant(self, name: str, value: float) -> None:
204
- self._constants.update_basic(name, value)
205
- self._reactions.update_derived_stoichiometries(self.constant_values)
206
-
207
- def update_constants(self, constants: dict[str, float]) -> None:
208
- for name, value in constants.items():
209
- self.update_constant(name, value)
210
-
211
- def remove_constant(self, name: str) -> None:
212
- self._names.remove(name)
213
- self._constants.remove_basic(name)
214
-
215
- def remove_constants(self, names: Iterable[str]) -> None:
216
- for name in names:
217
- self.remove_constant(name)
218
-
219
- ##########################################################################
220
- # Derived Constants
221
- ##########################################################################
222
-
223
- @add.register
224
- def add_derived_constant(self, constant: DerivedConstant) -> None:
225
- self._names.require_multiple(constant.args)
226
- self._names.add(constant.name, "derived_constant")
227
- self._constants.add_derived(constant)
228
-
229
- def update_derived_constant(
230
- self,
231
- name: str,
232
- function: Optional[RateFunction] = None,
233
- args: Optional[Iterable[str]] = None,
234
- unit: Optional[str] = None,
235
- ) -> None:
236
- old = self.remove_derived_constant(name)
237
- if function is None:
238
- function = old.function
239
- if args is None:
240
- args = old.args
241
- if unit is None:
242
- unit = old.unit
243
- self.add_derived_constant(DerivedConstant(name, function, list(args), unit))
244
- self._reactions.update_derived_stoichiometries(self.constant_values)
245
-
246
- def remove_derived_constant(self, name: str) -> DerivedConstant:
247
- self._names.remove(name)
248
- return self._constants.remove_derived(name)
249
-
250
- def remove_derived_constants(self, names: Iterable[str]) -> None:
251
- for name in names:
252
- self.remove_derived_constant(name)
253
-
254
- ##########################################################################
255
- # Variables
256
- ##########################################################################
257
-
258
- @add.register
259
- def add_variable(self, variable: Variable) -> None:
260
- self._names.add(variable.name, "variable")
261
- self._variables.add(variable)
262
-
263
- def remove_variable(self, name: str) -> None:
264
- self._names.remove(name)
265
- self._variables.remove(name)
266
-
267
- def remove_variables(self, names: Iterable[str]) -> None:
268
- for name in names:
269
- self.remove_variable(name)
270
-
271
- ##########################################################################
272
- # Algebraic Modules
273
- ##########################################################################
274
-
275
- def _get_available_args(self) -> set[str]:
276
- return set(self.all_variables) | set(self._constants.values)
277
-
278
- @add.register
279
- def add_algebraic_module(self, module: AlgebraicModule) -> None:
280
- for name in module.derived_variables:
281
- self._names.add(name, "derived_variable")
282
- self._names.require_multiple(module.args)
283
- self._algebraic_modules.add(
284
- module,
285
- self._get_available_args(),
286
- sort_modules=True,
287
- )
288
-
289
- def remove_algebraic_module(self, name: str) -> AlgebraicModule:
290
- module = self._algebraic_modules.remove(
291
- name,
292
- set(),
293
- sort_modules=False,
294
- )
295
- for name in module.derived_variables:
296
- self._names.remove(name)
297
- return module
298
-
299
- def remove_algebraic_modules(self, names: Iterable[str]) -> None:
300
- for name in names:
301
- self.remove_algebraic_module(name)
302
-
303
- def update_algebraic_module(
304
- self,
305
- name: str,
306
- function: Optional[ModuleFunction] = None,
307
- derived_variables: Optional[list[str]] = None,
308
- args: Optional[list[str]] = None,
309
- ) -> None:
310
- old_module = self.remove_algebraic_module(name)
311
- if function is None:
312
- function = old_module.function
313
- if derived_variables is None:
314
- derived_variables = old_module.derived_variables
315
- if args is None:
316
- args = old_module.args
317
- self.add_algebraic_module(
318
- AlgebraicModule(name, function, derived_variables, args)
319
- )
320
-
321
- self._algebraic_modules.update(
322
- name,
323
- function,
324
- derived_variables,
325
- args,
326
- self._get_available_args(),
327
- )
328
-
329
- ##########################################################################
330
- # Reactions
331
- ##########################################################################
332
-
333
- @add.register
334
- def add_reaction(
335
- self,
336
- reaction: Reaction,
337
- ) -> None:
338
- self._names.require_multiple(reaction.args)
339
- self._reactions.add(reaction, self.constant_values)
340
-
341
- def remove_reaction(self, name: str) -> None:
342
- self._reactions.remove(name=name)
343
-
344
- def remove_reactions(self, names: Iterable[str]) -> None:
345
- for name in names:
346
- self.remove_reaction(name=name)
347
-
348
- def update_reaction(
349
- self,
350
- name: str,
351
- function: Optional[RateFunction] = None,
352
- stoichiometry: Optional[StoichiometryByReaction] = None,
353
- # derived_stoichiometry: Optional[DerivedStoichiometry] = None,
354
- derived_stoichiometry: Optional[dict[str, DerivedStoichiometry]] = None,
355
- args: list[str] | None = None,
356
- ) -> None:
357
- self._reactions.update(
358
- name,
359
- function,
360
- stoichiometry,
361
- derived_stoichiometry,
362
- args,
363
- self.constant_values,
364
- )
365
-
366
- def get_stoichiometries(self) -> pd.DataFrame:
367
- return self._reactions.get_stoichiometries()
368
-
369
- # ##########################################################################
370
- # # Simulation functions
371
- # ##########################################################################
372
-
373
- def _get_problem(self, t: float, y: Iterable[float]) -> list[float]:
374
- """Integration function"""
375
- variables = dict(zip(self.stoichiometries, y)) | {"time": t}
376
- args = variables | self.constant_values
377
- args |= self._algebraic_modules.get_values_float(args)
378
- fluxes = self._reactions.get_fluxes_float(args)
379
- rhs = self._reactions.get_right_hand_side_float(fluxes)
380
- return list(rhs.values())
381
-
382
- def _get_all_args(self, variables: dict[str, float], time: float) -> dict[str, float]:
383
- args = variables | self.constant_values | {"time": time}
384
- args |= self._algebraic_modules.get_values_float(args)
385
- return args
386
-
387
- def get_derived_variables(
388
- self, variables: dict[str, float], time: float = 0.0
389
- ) -> dict[str, float]:
390
- args = variables | self.constant_values | {"time": time}
391
- return self._algebraic_modules.get_values_float(args)
392
-
393
- @overload
394
- def get_fluxes(
395
- self,
396
- variables: dict[str, float],
397
- return_type: Literal["dict"],
398
- time: float = 0,
399
- ) -> dict[str, float]:
400
- ...
401
-
402
- @overload
403
- def get_fluxes(
404
- self,
405
- variables: dict[str, float],
406
- return_type: Literal["array"],
407
- time: float = 0,
408
- ) -> Array:
409
- ...
410
-
411
- @overload
412
- def get_fluxes(
413
- self,
414
- variables: dict[str, float],
415
- return_type: Literal["series"],
416
- time: float = 0,
417
- ) -> Series:
418
- ...
419
-
420
- @overload
421
- def get_fluxes(
422
- self,
423
- variables: dict[str, float],
424
- return_type: Literal["dict"] = "dict",
425
- time: float = 0,
426
- ) -> dict[str, float]:
427
- ...
428
-
429
- def get_fluxes(
430
- self,
431
- variables: dict[str, float],
432
- return_type: Literal["array", "dict", "series"] = "dict",
433
- time: float = 0.0,
434
- ) -> Union[Array, dict[str, float], pd.Series]:
435
- args = self._get_all_args(variables, time)
436
- fluxes_dict = self._reactions.get_fluxes_float(args)
437
- if return_type == "dict":
438
- return fluxes_dict
439
- elif return_type == "series":
440
- return pd.Series(fluxes_dict)
441
- elif return_type == "array":
442
- return np.fromiter(fluxes_dict.values(), dtype="float")
443
- else:
444
- raise NotImplementedError(f"Unknown return type {return_type}")
445
-
446
- def get_right_hand_side(
447
- self, variables: dict[str, float], time: float = 0.0
448
- ) -> dict[str, float]:
449
- fluxes = self.get_fluxes(variables, time=time)
450
- return self._reactions.get_right_hand_side_float(fluxes)
451
-
452
- def to_version_1(self) -> OldModel:
453
- old = OldModel()
454
-
455
- old.add_compounds(list(self.variables))
456
-
457
- old.add_parameters({k: v.value for k, v in self.constants.items()})
458
-
459
- for k in _sort_derived_compounds(self):
460
- dc = self.derived_constants[k]
461
- old.add_derived_parameter(k, dc.function, dc.args)
462
-
463
- for k, am in self.algebraic_modules.items():
464
- old.add_algebraic_module_from_args(
465
- k, am.function, am.derived_variables, am.args
466
- )
467
-
468
- for r in self.reactions.values():
469
- old.add_reaction_from_args(r.name, r.function, r.stoichiometry, r.args)
470
- return old
@@ -1,153 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import logging
4
- import numpy as np
5
- import pandas as pd
6
- from ..types import Array
7
- from .integrator import Assimulo
8
- from .model import Model
9
- from dataclasses import dataclass, field
10
- from typing import Any, Optional, Type
11
-
12
- logger = logging.getLogger()
13
-
14
-
15
- @dataclass(repr=False)
16
- class SimulationResult:
17
- time: Array
18
- values: dict[str, Array]
19
- constants: dict[str, float]
20
-
21
- def __repr__(self) -> str:
22
- return f"Simulation until t={self.time[-1]}"
23
-
24
- def to_frame(self) -> pd.DataFrame:
25
- return pd.DataFrame(
26
- data=self.values,
27
- index=self.time, # type: ignore
28
- )
29
-
30
-
31
- def concatenate_results(results: list[SimulationResult]) -> pd.DataFrame:
32
- df = results[0].to_frame()
33
- if len(results) > 1:
34
- for result in results[1:]:
35
- df = pd.concat((df, result.to_frame().iloc[1:]))
36
- return df
37
-
38
-
39
- @dataclass(init=False)
40
- class Simulator:
41
- model: Model
42
- integrator: Assimulo
43
- y0: list[float] = field(default_factory=list)
44
- # Could also be ResultContainer once you add other model types again
45
- results: list[SimulationResult] = field(default_factory=list)
46
-
47
- def __init__(
48
- self,
49
- model: Model,
50
- integrator: Type[Assimulo],
51
- y0: dict[str, float],
52
- results: Optional[SimulationResult] = None,
53
- ):
54
- self.model = model
55
- self.update_y0(y0)
56
- self.integrator = integrator(rhs=self.model._get_problem, y0=self.y0)
57
- if results is None:
58
- self.results = list()
59
-
60
- def __reduce__(self) -> Any:
61
- return (
62
- self.__class__,
63
- (
64
- self.model,
65
- self.integrator,
66
- self.y0,
67
- ),
68
- (("results", self.results),),
69
- )
70
-
71
- def update_y0(self, y0: dict[str, float]) -> None:
72
- self.y0 = [y0[i] for i in self.model.stoichiometries]
73
-
74
- def clear_results(self) -> None:
75
- self.results = list()
76
- self.integrator.reset()
77
-
78
- def simulate(
79
- self,
80
- t_end: float,
81
- ) -> Optional[SimulationResult]:
82
- if (integration := self.integrator.integrate(t_end, None, None)) is None:
83
- logger.warning("Simulation failed")
84
- return None
85
- res = SimulationResult(
86
- integration.time,
87
- dict(zip(self.model.stoichiometries, integration.values.T)),
88
- self.model.constant_values,
89
- )
90
- self.results.append(res)
91
- return res
92
-
93
- def simulate_to_steady_state(
94
- self, tolerance: float = 1e-6
95
- ) -> Optional[dict[str, float]]:
96
- if (
97
- integration := self.integrator.integrate_to_steady_state(tolerance)
98
- ) is not None:
99
- return dict(zip(self.model.stoichiometries, integration))
100
- else:
101
- logger.warning("Simulation failed")
102
- return None
103
-
104
- def get_results(self) -> pd.DataFrame:
105
- return concatenate_results(self.results)
106
-
107
- def _get_result_constants(self, result: SimulationResult) -> dict[str, Array]:
108
- return {k: np.full(len(result.time), v) for k, v in result.constants.items()}
109
-
110
- def _get_result_derived_variables(
111
- self,
112
- args: dict[str, Array],
113
- ) -> dict[str, Array]:
114
- return self.model._algebraic_modules.get_values_array(args)
115
-
116
- def _get_result_all_variables(
117
- self, result: SimulationResult, constants: dict[str, Array]
118
- ) -> dict[str, Array]:
119
- args = result.values | constants | {"time": result.time}
120
- return result.values | self._get_result_derived_variables(args)
121
-
122
- def _get_result_fluxes(self, result: SimulationResult) -> dict[str, Array]:
123
- constants = self._get_result_constants(result)
124
- all_variables = self._get_result_all_variables(result, constants)
125
- args = all_variables | constants | {"time": result.time}
126
- return self.model._reactions.get_fluxes_array(args)
127
-
128
- def get_full_results(self) -> pd.DataFrame:
129
- full_results: list[SimulationResult] = []
130
- for result in self.results:
131
- full_results.append(
132
- SimulationResult(
133
- values=self._get_result_all_variables(
134
- result, self._get_result_constants(result)
135
- ),
136
- time=result.time,
137
- constants=result.constants,
138
- )
139
- )
140
- return concatenate_results(full_results)
141
-
142
- def get_fluxes(self) -> pd.DataFrame:
143
- fluxes: list[SimulationResult] = []
144
- for result in self.results:
145
- result_fluxes = self._get_result_fluxes(result)
146
- fluxes.append(
147
- SimulationResult(
148
- values=result_fluxes,
149
- time=result.time,
150
- constants=result.constants,
151
- )
152
- )
153
- return concatenate_results(fluxes)
File without changes