Skip to main content

fdars_core/basis/
basis_system.rs

1//! `BasisSystem` — a basis evaluation matrix bundled with its roughness penalty.
2//!
3//! This struct is the return type for the new basis factories introduced in Phase 35
4//! (`monomial_basis`, `exponential_basis`, `power_basis`, `polygonal_basis`). It bundles:
5//!
6//! - a column-major evaluation matrix over a supplied set of evaluation points, and
7//! - the corresponding roughness-penalty (Gram) matrix for the chosen derivative order.
8//!
9//! ## Column-major layout
10//!
11//! `eval_matrix` is stored in **column-major order**: element (t_i, j) — the value of the
12//! j-th basis function at the i-th evaluation point — is at index `i + j * n_eval`.
13//!
14//! This matches the `bspline_basis` / `fourier_basis` convention used throughout
15//! `fdars-core`.
16//!
17//! ## Penalty matrix
18//!
19//! `penalty_matrix` is the `nbasis × nbasis` Gram matrix of the `lfd_order`-th derivatives
20//! of the basis functions:
21//!
22//! ```text
23//! R[j, k] = ∫ D^lfd_order B_j(t) · D^lfd_order B_k(t) dt
24//! ```
25//!
26//! It is stored column-major: element (j, k) is at index `j + k * nbasis`.
27//! The matrix is symmetric and positive-semi-definite.
28
29/// A basis evaluation matrix bundled with its roughness-penalty (Gram) matrix.
30///
31/// Created by the basis factories (`monomial_basis`, etc.) — never constructed directly
32/// by callers. The `#[non_exhaustive]` attribute allows adding new fields (e.g., `domain`,
33/// `basis_type`) in future versions without breaking existing code.
34///
35/// ## Field layout
36///
37/// - `eval_matrix`: column-major, shape `(n_eval × nbasis)`.
38///   Element (t_i, j) is at index `i + j * n_eval`.
39/// - `penalty_matrix`: column-major, shape `(nbasis × nbasis)`.
40///   Element (j, k) is at index `j + k * nbasis`.
41///
42/// ## Example
43///
44/// ```
45/// use fdars_core::monomial_basis;
46///
47/// let t = vec![0.0, 0.5, 1.0];
48/// let bs = monomial_basis(&t, 3).unwrap();
49/// assert_eq!(bs.nbasis, 3);
50/// assert_eq!(bs.n_eval, 3);
51/// assert_eq!(bs.eval_matrix.len(), 9);
52/// assert_eq!(bs.penalty_matrix.len(), 9);
53/// ```
54#[derive(Debug, Clone, PartialEq)]
55#[non_exhaustive]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub struct BasisSystem {
58    /// Column-major evaluation matrix, shape `(n_eval × nbasis)`.
59    /// Element (t_i, j) is at index `i + j * n_eval`.
60    pub eval_matrix: Vec<f64>,
61    /// Column-major roughness-penalty (Gram) matrix, shape `(nbasis × nbasis)`.
62    /// `R[j,k] = ∫ D^lfd_order B_j(t) · D^lfd_order B_k(t) dt`.
63    /// Symmetric and positive-semi-definite. Element (j, k) at index `j + k * nbasis`.
64    pub penalty_matrix: Vec<f64>,
65    /// Number of basis functions (`nbasis`).
66    pub nbasis: usize,
67    /// Number of evaluation points, i.e. `argvals.len()`.
68    pub n_eval: usize,
69    /// Derivative order used to compute `penalty_matrix` (roughness order).
70    pub lfd_order: usize,
71}