mxlpy 0.25.0__py3-none-any.whl → 0.26.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.
mxlpy/fit/local_.py DELETED
@@ -1,591 +0,0 @@
1
- """Parameter local fitting Module for Metabolic Models.
2
-
3
- This module provides functions for fitting model parameters to experimental data,
4
- including both steadyd-state and time-series data fitting capabilities.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import logging
10
- from collections.abc import Callable
11
- from copy import deepcopy
12
- from dataclasses import dataclass
13
- from functools import partial
14
- from typing import TYPE_CHECKING, Literal
15
-
16
- from scipy.optimize import minimize
17
-
18
- from mxlpy import parallel
19
- from mxlpy.types import IntegratorType, cast
20
-
21
- from .common import (
22
- Bounds,
23
- CarouselFit,
24
- FitResult,
25
- InitialGuess,
26
- LossFn,
27
- MinResult,
28
- ProtocolResidualFn,
29
- ResidualFn,
30
- SteadyStateResidualFn,
31
- TimeSeriesResidualFn,
32
- _protocol_time_course_residual,
33
- _steady_state_residual,
34
- _time_course_residual,
35
- rmse,
36
- )
37
-
38
- if TYPE_CHECKING:
39
- import pandas as pd
40
-
41
- from mxlpy.carousel import Carousel
42
- from mxlpy.model import Model
43
-
44
- LOGGER = logging.getLogger(__name__)
45
-
46
- __all__ = [
47
- "LOGGER",
48
- "Minimizer",
49
- "ScipyMinimizer",
50
- "carousel_protocol_time_course",
51
- "carousel_steady_state",
52
- "carousel_time_course",
53
- "protocol_time_course",
54
- "steady_state",
55
- "time_course",
56
- ]
57
-
58
-
59
- type Minimizer = Callable[
60
- [
61
- ResidualFn,
62
- InitialGuess,
63
- Bounds,
64
- ],
65
- MinResult | None,
66
- ]
67
-
68
-
69
- @dataclass
70
- class ScipyMinimizer:
71
- """Local multivariate minimization using scipy.optimize.
72
-
73
- See Also
74
- --------
75
- https://docs.scipy.org/doc/scipy/reference/optimize.html#local-multivariate-optimization
76
-
77
- """
78
-
79
- tol: float = 1e-6
80
- method: Literal[
81
- "Nelder-Mead",
82
- "Powell",
83
- "CG",
84
- "BFGS",
85
- "Newton-CG",
86
- "L-BFGS-B",
87
- "TNC",
88
- "COBYLA",
89
- "COBYQA",
90
- "SLSQP",
91
- "trust-constr",
92
- "dogleg",
93
- "trust-ncg",
94
- "trust-exact",
95
- "trust-krylov",
96
- ] = "L-BFGS-B"
97
-
98
- def __call__(
99
- self,
100
- residual_fn: ResidualFn,
101
- p0: dict[str, float],
102
- bounds: Bounds,
103
- ) -> MinResult | None:
104
- """Call minimzer."""
105
- res = minimize(
106
- residual_fn,
107
- x0=list(p0.values()),
108
- bounds=[bounds.get(name, (1e-6, 1e6)) for name in p0],
109
- method=self.method,
110
- tol=self.tol,
111
- )
112
- if res.success:
113
- return MinResult(
114
- parameters=dict(
115
- zip(
116
- p0,
117
- res.x,
118
- strict=True,
119
- ),
120
- ),
121
- residual=res.fun,
122
- )
123
-
124
- LOGGER.warning("Minimisation failed due to %s", res.message)
125
- return None
126
-
127
-
128
- _default_minimizer = ScipyMinimizer()
129
-
130
-
131
- def _carousel_steady_state_worker(
132
- model: Model,
133
- p0: dict[str, float],
134
- data: pd.Series,
135
- y0: dict[str, float] | None,
136
- integrator: IntegratorType | None,
137
- loss_fn: LossFn,
138
- minimizer: Minimizer,
139
- residual_fn: SteadyStateResidualFn,
140
- bounds: Bounds | None,
141
- ) -> FitResult | None:
142
- model_pars = model.get_parameter_values()
143
-
144
- return steady_state(
145
- model,
146
- p0={k: v for k, v in p0.items() if k in model_pars},
147
- y0=y0,
148
- data=data,
149
- minimizer=minimizer,
150
- residual_fn=residual_fn,
151
- integrator=integrator,
152
- loss_fn=loss_fn,
153
- bounds=bounds,
154
- )
155
-
156
-
157
- def _carousel_time_course_worker(
158
- model: Model,
159
- p0: dict[str, float],
160
- data: pd.DataFrame,
161
- y0: dict[str, float] | None,
162
- integrator: IntegratorType | None,
163
- loss_fn: LossFn,
164
- minimizer: Minimizer,
165
- residual_fn: TimeSeriesResidualFn,
166
- bounds: Bounds | None,
167
- ) -> FitResult | None:
168
- model_pars = model.get_parameter_values()
169
- return time_course(
170
- model,
171
- p0={k: v for k, v in p0.items() if k in model_pars},
172
- y0=y0,
173
- data=data,
174
- minimizer=minimizer,
175
- residual_fn=residual_fn,
176
- integrator=integrator,
177
- loss_fn=loss_fn,
178
- bounds=bounds,
179
- )
180
-
181
-
182
- def _carousel_protocol_worker(
183
- model: Model,
184
- p0: dict[str, float],
185
- data: pd.DataFrame,
186
- protocol: pd.DataFrame,
187
- y0: dict[str, float] | None,
188
- integrator: IntegratorType | None,
189
- loss_fn: LossFn,
190
- minimizer: Minimizer,
191
- residual_fn: ProtocolResidualFn,
192
- bounds: Bounds | None,
193
- ) -> FitResult | None:
194
- model_pars = model.get_parameter_values()
195
- return protocol_time_course(
196
- model,
197
- p0={k: v for k, v in p0.items() if k in model_pars},
198
- y0=y0,
199
- protocol=protocol,
200
- data=data,
201
- minimizer=minimizer,
202
- residual_fn=residual_fn,
203
- integrator=integrator,
204
- loss_fn=loss_fn,
205
- bounds=bounds,
206
- )
207
-
208
-
209
- def steady_state(
210
- model: Model,
211
- *,
212
- p0: dict[str, float],
213
- data: pd.Series,
214
- y0: dict[str, float] | None = None,
215
- minimizer: Minimizer = _default_minimizer,
216
- residual_fn: SteadyStateResidualFn = _steady_state_residual,
217
- integrator: IntegratorType | None = None,
218
- loss_fn: LossFn = rmse,
219
- bounds: Bounds | None = None,
220
- ) -> FitResult | None:
221
- """Fit model parameters to steady-state experimental data.
222
-
223
- Examples:
224
- >>> steady_state(model, p0, data)
225
- {'k1': 0.1, 'k2': 0.2}
226
-
227
- Args:
228
- model: Model instance to fit
229
- data: Experimental steady state data as pandas Series
230
- p0: Initial parameter guesses as {parameter_name: value}
231
- y0: Initial conditions as {species_name: value}
232
- minimizer: Function to minimize fitting error
233
- residual_fn: Function to calculate fitting error
234
- integrator: ODE integrator class
235
- loss_fn: Loss function to use for residual calculation
236
- bounds: Mapping of bounds per parameter
237
-
238
- Returns:
239
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
240
-
241
- Note:
242
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
243
-
244
- """
245
- par_names = list(p0.keys())
246
-
247
- # Copy to restore
248
- p_orig = model.get_parameter_values()
249
-
250
- fn = cast(
251
- ResidualFn,
252
- partial(
253
- residual_fn,
254
- data=data,
255
- model=model,
256
- y0=y0,
257
- par_names=par_names,
258
- integrator=integrator,
259
- loss_fn=loss_fn,
260
- ),
261
- )
262
- min_result = minimizer(fn, p0, {} if bounds is None else bounds)
263
- # Restore original model
264
- model.update_parameters(p_orig)
265
- if min_result is None:
266
- return min_result
267
-
268
- return FitResult(
269
- model=deepcopy(model).update_parameters(min_result.parameters),
270
- best_pars=min_result.parameters,
271
- loss=min_result.residual,
272
- )
273
-
274
-
275
- def time_course(
276
- model: Model,
277
- *,
278
- p0: dict[str, float],
279
- data: pd.DataFrame,
280
- y0: dict[str, float] | None = None,
281
- minimizer: Minimizer = _default_minimizer,
282
- residual_fn: TimeSeriesResidualFn = _time_course_residual,
283
- integrator: IntegratorType | None = None,
284
- loss_fn: LossFn = rmse,
285
- bounds: Bounds | None = None,
286
- ) -> FitResult | None:
287
- """Fit model parameters to time course of experimental data.
288
-
289
- Examples:
290
- >>> time_course(model, p0, data)
291
- {'k1': 0.1, 'k2': 0.2}
292
-
293
- Args:
294
- model: Model instance to fit
295
- data: Experimental time course data
296
- p0: Initial parameter guesses as {parameter_name: value}
297
- y0: Initial conditions as {species_name: value}
298
- minimizer: Function to minimize fitting error
299
- residual_fn: Function to calculate fitting error
300
- integrator: ODE integrator class
301
- loss_fn: Loss function to use for residual calculation
302
- bounds: Mapping of bounds per parameter
303
-
304
- Returns:
305
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
306
-
307
- Note:
308
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
309
-
310
- """
311
- par_names = list(p0.keys())
312
- p_orig = model.get_parameter_values()
313
-
314
- fn = cast(
315
- ResidualFn,
316
- partial(
317
- residual_fn,
318
- data=data,
319
- model=model,
320
- y0=y0,
321
- par_names=par_names,
322
- integrator=integrator,
323
- loss_fn=loss_fn,
324
- ),
325
- )
326
-
327
- min_result = minimizer(fn, p0, {} if bounds is None else bounds)
328
- # Restore original model
329
- model.update_parameters(p_orig)
330
- if min_result is None:
331
- return min_result
332
-
333
- return FitResult(
334
- model=deepcopy(model).update_parameters(min_result.parameters),
335
- best_pars=min_result.parameters,
336
- loss=min_result.residual,
337
- )
338
-
339
-
340
- def protocol_time_course(
341
- model: Model,
342
- *,
343
- p0: dict[str, float],
344
- data: pd.DataFrame,
345
- protocol: pd.DataFrame,
346
- y0: dict[str, float] | None = None,
347
- minimizer: Minimizer = _default_minimizer,
348
- residual_fn: ProtocolResidualFn = _protocol_time_course_residual,
349
- integrator: IntegratorType | None = None,
350
- loss_fn: LossFn = rmse,
351
- bounds: Bounds | None = None,
352
- ) -> FitResult | None:
353
- """Fit model parameters to time course of experimental data.
354
-
355
- Time points of protocol time course are taken from the data.
356
-
357
- Examples:
358
- >>> time_course(model, p0, data)
359
- {'k1': 0.1, 'k2': 0.2}
360
-
361
- Args:
362
- model: Model instance to fit
363
- p0: Initial parameter guesses as {parameter_name: value}
364
- data: Experimental time course data
365
- protocol: Experimental protocol
366
- y0: Initial conditions as {species_name: value}
367
- minimizer: Function to minimize fitting error
368
- residual_fn: Function to calculate fitting error
369
- integrator: ODE integrator class
370
- loss_fn: Loss function to use for residual calculation
371
- time_points_per_step: Number of time points per step in the protocol
372
- bounds: Mapping of bounds per parameter
373
-
374
- Returns:
375
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
376
-
377
- Note:
378
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
379
-
380
- """
381
- par_names = list(p0.keys())
382
- p_orig = model.get_parameter_values()
383
-
384
- fn = cast(
385
- ResidualFn,
386
- partial(
387
- residual_fn,
388
- data=data,
389
- model=model,
390
- y0=y0,
391
- par_names=par_names,
392
- integrator=integrator,
393
- loss_fn=loss_fn,
394
- protocol=protocol,
395
- ),
396
- )
397
-
398
- min_result = minimizer(fn, p0, {} if bounds is None else bounds)
399
- # Restore original model
400
- model.update_parameters(p_orig)
401
- if min_result is None:
402
- return min_result
403
-
404
- return FitResult(
405
- model=deepcopy(model).update_parameters(min_result.parameters),
406
- best_pars=min_result.parameters,
407
- loss=min_result.residual,
408
- )
409
-
410
-
411
- def carousel_steady_state(
412
- carousel: Carousel,
413
- *,
414
- p0: dict[str, float],
415
- data: pd.Series,
416
- y0: dict[str, float] | None = None,
417
- minimizer: Minimizer = _default_minimizer,
418
- residual_fn: SteadyStateResidualFn = _steady_state_residual,
419
- integrator: IntegratorType | None = None,
420
- loss_fn: LossFn = rmse,
421
- bounds: Bounds | None = None,
422
- ) -> CarouselFit:
423
- """Fit model parameters to steady-state experimental data over a carousel.
424
-
425
- Examples:
426
- >>> carousel_steady_state(carousel, p0=p0, data=data)
427
-
428
- Args:
429
- carousel: Model carousel to fit
430
- p0: Initial parameter guesses as {parameter_name: value}
431
- data: Experimental time course data
432
- protocol: Experimental protocol
433
- y0: Initial conditions as {species_name: value}
434
- minimizer: Function to minimize fitting error
435
- residual_fn: Function to calculate fitting error
436
- integrator: ODE integrator class
437
- loss_fn: Loss function to use for residual calculation
438
- time_points_per_step: Number of time points per step in the protocol
439
- bounds: Mapping of bounds per parameter
440
-
441
- Returns:
442
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
443
-
444
- Note:
445
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
446
-
447
- """
448
- return CarouselFit(
449
- [
450
- fit
451
- for i in parallel.parallelise(
452
- partial(
453
- _carousel_steady_state_worker,
454
- p0=p0,
455
- data=data,
456
- y0=y0,
457
- integrator=integrator,
458
- loss_fn=loss_fn,
459
- minimizer=minimizer,
460
- residual_fn=residual_fn,
461
- bounds=bounds,
462
- ),
463
- inputs=list(enumerate(carousel.variants)),
464
- )
465
- if (fit := i[1]) is not None
466
- ]
467
- )
468
-
469
-
470
- def carousel_time_course(
471
- carousel: Carousel,
472
- *,
473
- p0: dict[str, float],
474
- data: pd.DataFrame,
475
- y0: dict[str, float] | None = None,
476
- minimizer: Minimizer = _default_minimizer,
477
- residual_fn: TimeSeriesResidualFn = _time_course_residual,
478
- integrator: IntegratorType | None = None,
479
- loss_fn: LossFn = rmse,
480
- bounds: Bounds | None = None,
481
- ) -> CarouselFit:
482
- """Fit model parameters to time course of experimental data over a carousel.
483
-
484
- Time points are taken from the data.
485
-
486
- Examples:
487
- >>> carousel_time_course(carousel, p0=p0, data=data)
488
-
489
- Args:
490
- carousel: Model carousel to fit
491
- p0: Initial parameter guesses as {parameter_name: value}
492
- data: Experimental time course data
493
- protocol: Experimental protocol
494
- y0: Initial conditions as {species_name: value}
495
- minimizer: Function to minimize fitting error
496
- residual_fn: Function to calculate fitting error
497
- integrator: ODE integrator class
498
- loss_fn: Loss function to use for residual calculation
499
- time_points_per_step: Number of time points per step in the protocol
500
- bounds: Mapping of bounds per parameter
501
-
502
- Returns:
503
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
504
-
505
- Note:
506
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
507
-
508
- """
509
- return CarouselFit(
510
- [
511
- fit
512
- for i in parallel.parallelise(
513
- partial(
514
- _carousel_time_course_worker,
515
- p0=p0,
516
- data=data,
517
- y0=y0,
518
- integrator=integrator,
519
- loss_fn=loss_fn,
520
- minimizer=minimizer,
521
- residual_fn=residual_fn,
522
- bounds=bounds,
523
- ),
524
- inputs=list(enumerate(carousel.variants)),
525
- )
526
- if (fit := i[1]) is not None
527
- ]
528
- )
529
-
530
-
531
- def carousel_protocol_time_course(
532
- carousel: Carousel,
533
- *,
534
- p0: dict[str, float],
535
- data: pd.DataFrame,
536
- protocol: pd.DataFrame,
537
- y0: dict[str, float] | None = None,
538
- minimizer: Minimizer = _default_minimizer,
539
- residual_fn: ProtocolResidualFn = _protocol_time_course_residual,
540
- integrator: IntegratorType | None = None,
541
- loss_fn: LossFn = rmse,
542
- bounds: Bounds | None = None,
543
- ) -> CarouselFit:
544
- """Fit model parameters to time course of experimental data over a protocol.
545
-
546
- Time points of protocol time course are taken from the data.
547
-
548
- Examples:
549
- >>> carousel_steady_state(carousel, p0=p0, data=data)
550
-
551
- Args:
552
- carousel: Model carousel to fit
553
- p0: Initial parameter guesses as {parameter_name: value}
554
- data: Experimental time course data
555
- protocol: Experimental protocol
556
- y0: Initial conditions as {species_name: value}
557
- minimizer: Function to minimize fitting error
558
- residual_fn: Function to calculate fitting error
559
- integrator: ODE integrator class
560
- loss_fn: Loss function to use for residual calculation
561
- time_points_per_step: Number of time points per step in the protocol
562
- bounds: Mapping of bounds per parameter
563
-
564
- Returns:
565
- dict[str, float]: Fitted parameters as {parameter_name: fitted_value}
566
-
567
- Note:
568
- Uses L-BFGS-B optimization with bounds [1e-6, 1e6] for all parameters
569
-
570
- """
571
- return CarouselFit(
572
- [
573
- fit
574
- for i in parallel.parallelise(
575
- partial(
576
- _carousel_protocol_worker,
577
- p0=p0,
578
- data=data,
579
- protocol=protocol,
580
- y0=y0,
581
- integrator=integrator,
582
- loss_fn=loss_fn,
583
- minimizer=minimizer,
584
- residual_fn=residual_fn,
585
- bounds=bounds,
586
- ),
587
- inputs=list(enumerate(carousel.variants)),
588
- )
589
- if (fit := i[1]) is not None
590
- ]
591
- )
File without changes