Skip to main content

pmcore/algorithms/parametric/
mod.rs

1//! Parametric algorithm implementations.
2//!
3//! Parametric algorithms estimate the population distribution as a parametric model (for
4//! example a multivariate normal) whose parameters are fitted to the data.
5//!
6//! # Algorithm Selection
7//!
8//! Use the [`ParametricAlgorithm`] enum to select and configure an algorithm. Each variant
9//! wraps its algorithm-specific configuration struct (e.g. [`SaemConfig`]).
10//!
11//! Note: the parametric fitting machinery is not yet implemented. Constructing a problem and
12//! calling [`fit_with`](crate::estimation::EstimationProblem::fit_with) with a
13//! [`ParametricAlgorithm`] type-checks today, but running it will panic until the SAEM solver
14//! is implemented.
15
16pub mod saem_config;
17
18pub use saem_config::SaemConfig;
19
20use crate::algorithms::Algorithm;
21use crate::estimation::{EstimationProblem, Parametric};
22use crate::results::ParametricResult;
23use anyhow::Result;
24use pharmsol::prelude::simulator::Equation;
25
26/// The parametric algorithms supported by PMcore.
27///
28/// Use the constructors to select an algorithm with its default configuration:
29///
30/// ```no_run
31/// use pmcore::prelude::*;
32///
33/// // Default SAEM configuration.
34/// let algorithm = ParametricAlgorithm::saem();
35/// ```
36///
37/// To customize an algorithm, build its configuration struct (which exposes only the
38/// setters valid for that algorithm) and pass it directly to
39/// [`fit_with`](crate::estimation::EstimationProblem::fit_with):
40///
41/// ```no_run
42/// use pmcore::prelude::*;
43///
44/// // SAEM with a custom iteration schedule and seed.
45/// let config = SaemConfig::new()
46///     .k1_iterations(500)
47///     .k2_iterations(200)
48///     .seed(42);
49/// // `problem.fit_with(config)` accepts the config directly.
50/// ```
51///
52/// [`SaemConfig`] implements [`Algorithm`] by delegating to the matching enum variant, so
53/// configs can be passed to `fit_with` without converting them first.
54#[derive(Debug, Clone)]
55pub enum ParametricAlgorithm {
56    /// Stochastic Approximation Expectation-Maximization.
57    Saem(SaemConfig),
58}
59
60impl Default for ParametricAlgorithm {
61    fn default() -> Self {
62        Self::saem()
63    }
64}
65
66impl From<SaemConfig> for ParametricAlgorithm {
67    fn from(config: SaemConfig) -> Self {
68        Self::Saem(config)
69    }
70}
71
72impl ParametricAlgorithm {
73    /// The Stochastic Approximation Expectation-Maximization (SAEM) algorithm with its
74    /// default configuration.
75    pub fn saem() -> Self {
76        Self::Saem(SaemConfig::default())
77    }
78}
79
80impl<E: Equation + Send + 'static> Algorithm<E, Parametric> for ParametricAlgorithm {
81    type Output = ParametricResult<E>;
82
83    fn fit(self, _problem: EstimationProblem<E, Parametric>) -> Result<Self::Output> {
84        match self {
85            Self::Saem(_config) => {
86                unimplemented!("SAEM fitting is not yet implemented")
87            }
88        }
89    }
90}
91
92// `SaemConfig` delegates to the matching `ParametricAlgorithm` variant so it can be passed
93// directly to `fit_with`, keeping its setters compile-time checked.
94impl<E: Equation + Send + 'static> Algorithm<E, Parametric> for SaemConfig {
95    type Output = ParametricResult<E>;
96
97    fn fit(self, problem: EstimationProblem<E, Parametric>) -> Result<Self::Output> {
98        ParametricAlgorithm::from(self).fit(problem)
99    }
100}