Skip to main content

gamlss_formula/
schema.rs

1use gamlss_core::ParameterLayout;
2
3use crate::{Col, FittedTerm};
4
5/// Metadata for all terms belonging to one distribution parameter.
6#[derive(Debug, Clone, PartialEq)]
7pub struct ParameterTerms {
8    /// Distribution parameter name, e.g. `"mu"` or `"sigma"`.
9    pub parameter: &'static str,
10    /// Fitted terms in expression order.
11    pub terms: Vec<FittedTerm>,
12}
13
14/// Schema for a built formula model.
15#[derive(Debug, Clone, PartialEq)]
16pub struct ModelSchema {
17    /// Response column.
18    pub response: ResponseSchema,
19    /// Per-parameter term metadata.
20    pub parameters: Vec<ParameterTerms>,
21}
22
23/// Response metadata.
24#[derive(Debug, Clone, PartialEq)]
25pub struct ResponseSchema {
26    /// Source response column.
27    pub col: Col<f64>,
28    /// Optional observation weights column.
29    pub weights: Option<Col<f64>>,
30    /// Number of training observations.
31    pub nrows: usize,
32}
33
34/// Compiled formula artifact.
35#[derive(Debug, Clone, PartialEq)]
36pub struct BuiltModel<M> {
37    model: M,
38    schema: ModelSchema,
39    layout: ParameterLayout,
40}
41
42/// Reusable prediction design compiled from fitted term metadata.
43#[derive(Debug, Clone, PartialEq)]
44pub struct PredictionDesign<Blocks> {
45    blocks: Blocks,
46}
47
48impl<Blocks> PredictionDesign<Blocks> {
49    pub(crate) fn new(blocks: Blocks) -> Self {
50        Self { blocks }
51    }
52
53    /// Returns typed prediction parameter blocks.
54    #[must_use]
55    #[inline(always)]
56    pub fn blocks(&self) -> &Blocks {
57        &self.blocks
58    }
59
60    /// Consumes the design and returns typed prediction parameter blocks.
61    #[must_use]
62    #[inline]
63    pub fn into_blocks(self) -> Blocks {
64        self.blocks
65    }
66}
67
68impl<M> BuiltModel<M> {
69    pub(crate) fn new(model: M, schema: ModelSchema, layout: ParameterLayout) -> Self {
70        Self {
71            model,
72            schema,
73            layout,
74        }
75    }
76
77    /// Returns the compiled core model.
78    #[must_use]
79    #[inline(always)]
80    pub fn model(&self) -> &M {
81        &self.model
82    }
83
84    /// Returns the compiled core model mutably.
85    #[must_use]
86    #[inline(always)]
87    pub fn model_mut(&mut self) -> &mut M {
88        &mut self.model
89    }
90
91    /// Consumes the artifact and returns the compiled core model.
92    #[must_use]
93    #[inline]
94    pub fn into_model(self) -> M {
95        self.model
96    }
97
98    /// Returns formula schema metadata.
99    #[must_use]
100    #[inline(always)]
101    pub fn schema(&self) -> &ModelSchema {
102        &self.schema
103    }
104
105    /// Returns fitted terms grouped by distribution parameter.
106    #[must_use]
107    #[inline(always)]
108    pub fn terms(&self) -> &[ParameterTerms] {
109        &self.schema.parameters
110    }
111
112    /// Returns fitted terms for one distribution parameter.
113    #[must_use]
114    #[inline]
115    pub fn terms_for(&self, parameter: &str) -> Option<&[FittedTerm]> {
116        self.schema
117            .parameters
118            .iter()
119            .find(|terms| terms.parameter == parameter)
120            .map(|terms| terms.terms.as_slice())
121    }
122
123    /// Returns coefficient names in model layout order.
124    #[must_use]
125    pub fn coefficient_names(&self) -> Vec<&str> {
126        let mut names = Vec::new();
127        for parameter in &self.schema.parameters {
128            for term in &parameter.terms {
129                term.append_coefficient_names(&mut names);
130            }
131        }
132        names
133    }
134
135    /// Returns core parameter layout.
136    #[must_use]
137    #[inline(always)]
138    pub fn layout(&self) -> &ParameterLayout {
139        &self.layout
140    }
141}
142
143pub(crate) fn terms_for<'a>(schema: &'a ModelSchema, parameter: &'static str) -> &'a [FittedTerm] {
144    schema
145        .parameters
146        .iter()
147        .find(|terms| terms.parameter == parameter)
148        .map(|terms| terms.terms.as_slice())
149        .unwrap_or(&[])
150}