lowess/lib.rs
1//! # LOWESS — Locally Weighted Scatterplot Smoothing for Rust
2//!
3//! The fastest, most robust, and most feature-complete language-agnostic
4//! LOWESS (Locally Weighted Scatterplot Smoothing) implementation for **Rust**.
5//!
6//! ## What is LOWESS?
7//!
8//! LOWESS (Locally Weighted Scatterplot Smoothing) is a nonparametric regression
9//! method that fits smooth curves through scatter plots. At each point, it fits
10//! a weighted polynomial (typically linear) using nearby data points, with weights
11//! decreasing smoothly with distance. This creates flexible, data-adaptive curves
12//! without assuming a global functional form.
13//!
14//! ## Documentation
15//!
16//! > 📚 **Full Documentation**: [lowess.readthedocs.io](https://lowess.readthedocs.io/)
17//! >
18//! > Comprehensive guides, API references, and tutorials.
19//!
20//! ## Quick Start
21//!
22//! ### Typical Use
23//!
24//! ```rust
25//! use lowess::prelude::*;
26//!
27//! let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
28//! let y = vec![2.0, 4.1, 5.9, 8.2, 9.8];
29//!
30//! // Build the model
31//! let model = Lowess::new()
32//! .fraction(0.5) // Use 50% of data for each local fit
33//! .iterations(3) // 3 robustness iterations
34//! .adapter(Batch)
35//! .build()?;
36//!
37//! // Fit the model to the data
38//! let result = model.fit(&x, &y)?;
39//!
40//! println!("{}", result);
41//! # Result::<(), LowessError>::Ok(())
42//! ```
43//!
44//! ```text
45//! Summary:
46//! Data points: 5
47//! Fraction: 0.5
48//!
49//! Smoothed Data:
50//! X Y_smooth
51//! --------------------
52//! 1.00 2.00000
53//! 2.00 4.10000
54//! 3.00 5.90000
55//! 4.00 8.20000
56//! 5.00 9.80000
57//! ```
58//!
59//! ### Full Features
60//!
61//! ```rust
62//! use lowess::prelude::*;
63//!
64//! let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
65//! let y = vec![2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7];
66//!
67//! // Build model with all features enabled
68//! let model = Lowess::new()
69//! .fraction(0.5) // Use 50% of data for each local fit
70//! .iterations(3) // 3 robustness iterations
71//! .weight_function(Tricube) // Kernel function
72//! .robustness_method(Bisquare) // Outlier handling
73//! .delta(0.01) // Interpolation optimization
74//! .zero_weight_fallback(UseLocalMean) // Fallback policy
75//! .boundary_policy(Extend) // Boundary handling policy
76//! .scaling_method(MAD) // Robust scale estimation
77//! .auto_converge(1e-6) // Auto-convergence threshold
78//! .confidence_intervals(0.95) // 95% confidence intervals
79//! .prediction_intervals(0.95) // 95% prediction intervals
80//! .return_diagnostics() // Fit quality metrics
81//! .return_residuals() // Include residuals
82//! .return_robustness_weights() // Include robustness weights
83//! .cross_validate(KFold(5, &[0.3, 0.7]).seed(123)) // K-fold CV with 5 folds and 2 fraction options
84//! .adapter(Batch) // Batch adapter
85//! .build()?;
86//!
87//! let result = model.fit(&x, &y)?;
88//! println!("{}", result);
89//! # Result::<(), LowessError>::Ok(())
90//! ```
91//!
92//! ```text
93//! Summary:
94//! Data points: 8
95//! Fraction: 0.5
96//! Robustness: Applied
97//!
98//! LOWESS Diagnostics:
99//! RMSE: 0.191925
100//! MAE: 0.181676
101//! R^2: 0.998205
102//! Residual SD: 0.297750
103//! Effective DF: 8.00
104//! AIC: -10.41
105//! AICc: inf
106//!
107//! Smoothed Data:
108//! X Y_smooth Std_Err Conf_Lower Conf_Upper Pred_Lower Pred_Upper Residual Rob_Weight
109//! ----------------------------------------------------------------------------------------------------------------
110//! 1.00 2.01963 0.389365 1.256476 2.782788 1.058911 2.980353 0.080368 1.0000
111//! 2.00 4.00251 0.345447 3.325438 4.679589 3.108641 4.896386 -0.202513 1.0000
112//! 3.00 5.99959 0.423339 5.169846 6.829335 4.985168 7.014013 0.200410 1.0000
113//! 4.00 8.09859 0.489473 7.139224 9.057960 6.975666 9.221518 -0.198592 1.0000
114//! 5.00 10.03881 0.551687 8.957506 11.120118 8.810073 11.267551 0.261188 1.0000
115//! 6.00 12.02872 0.539259 10.971775 13.085672 10.821364 13.236083 -0.228723 1.0000
116//! 7.00 13.89828 0.371149 13.170829 14.625733 12.965670 14.830892 0.201719 1.0000
117//! 8.00 15.77990 0.408300 14.979631 16.580167 14.789441 16.770356 -0.079899 1.0000
118//! ```
119//!
120//! ### Result and Error Handling
121//!
122//! The `fit` method returns a `Result<LowessResult<T>, LowessError>`.
123//!
124//! - **`Ok(LowessResult<T>)`**: Contains the smoothed data and diagnostics.
125//! - **`Err(LowessError)`**: Indicates a failure (e.g., mismatched input lengths, insufficient data).
126//!
127//! The `?` operator is idiomatic:
128//!
129//! ```rust
130//! use lowess::prelude::*;
131//! # let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
132//! # let y = vec![2.0, 4.1, 5.9, 8.2, 9.8];
133//!
134//! let model = Lowess::new().adapter(Batch).build()?;
135//!
136//! let result = model.fit(&x, &y)?;
137//! // or to be more explicit:
138//! // let result: LowessResult<f64> = model.fit(&x, &y)?;
139//! # Result::<(), LowessError>::Ok(())
140//! ```
141//!
142//! But you can also handle results explicitly:
143//!
144//! ```rust
145//! use lowess::prelude::*;
146//! # let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
147//! # let y = vec![2.0, 4.1, 5.9, 8.2, 9.8];
148//!
149//! let model = Lowess::new().adapter(Batch).build()?;
150//!
151//! match model.fit(&x, &y) {
152//! Ok(result) => {
153//! // result is LowessResult<f64>
154//! println!("Smoothed: {:?}", result.y);
155//! }
156//! Err(e) => {
157//! // e is LowessError
158//! eprintln!("Fitting failed: {}", e);
159//! }
160//! }
161//! # Result::<(), LowessError>::Ok(())
162//! ```
163//!
164//! ## Minimal Usage (no_std / Embedded)
165//!
166//! The crate supports `no_std` environments for embedded devices and resource-constrained systems.
167//! Disable default features to remove the standard library dependency:
168//!
169//! ```toml
170//! [dependencies]
171//! lowess = { version = "0.5", default-features = false }
172//! ```
173//!
174//! **Minimal example for embedded systems:**
175//!
176//! ```rust
177//! # #[cfg(feature = "std")] {
178//! use lowess::prelude::*;
179//!
180//! // In an embedded context (e.g., sensor data processing)
181//! fn smooth_sensor_data() -> Result<(), LowessError> {
182//! // Small dataset from sensor readings
183//! let x = vec![1.0_f32, 2.0, 3.0, 4.0, 5.0];
184//! let y = vec![2.1, 3.9, 6.2, 7.8, 10.1];
185//!
186//! // Build minimal model (no intervals, no diagnostics)
187//! let model = Lowess::new()
188//! .fraction(0.5)
189//! .iterations(2) // Fewer iterations for speed
190//! .adapter(Batch)
191//! .build()?;
192//!
193//! // Fit the model
194//! let result = model.fit(&x, &y)?;
195//!
196//! // Use smoothed values (result.y)
197//! // ...
198//!
199//! Ok(())
200//! }
201//! # smooth_sensor_data().unwrap();
202//! # }
203//! ```
204//!
205//! **Tips for embedded/no_std usage:**
206//! - Use `f32` instead of `f64` to reduce memory footprint
207//! - Keep datasets small (< 1000 points)
208//! - Disable optional features (intervals, diagnostics) to reduce code size
209//! - Use fewer iterations (1-2) to reduce computation time
210//! - Allocate buffers statically when possible to avoid heap fragmentation
211//!
212//! ## References
213//!
214//! - Cleveland, W. S. (1979). "Robust Locally Weighted Regression and Smoothing Scatterplots"
215//! - Cleveland, W. S. (1981). "LOWESS: A Program for Smoothing Scatterplots by Robust Locally Weighted Regression"
216//!
217//! ## srrstats Compliance for rOpenSci Statistical Software Review
218//!
219//! @srrstats {G1.0} Statistical literature references documented above (Cleveland 1979, 1981).
220//! @srrstats {G1.1} This package provides LOWESS smoothing, a nonparametric regression method
221//! for fitting smooth curves to scatterplot data using locally weighted linear regression.
222//! @srrstats {G1.4} All exported functions and types are documented with rustdoc comments.
223//! @srrstats {G1.6} Performance characteristics documented: SIMD-optimized solvers, O(n*k)
224//! complexity where k is the window size, supports streaming and online modes.
225//!
226//! ## License
227//!
228//! See the repository for license information and contribution guidelines.
229
230#![cfg_attr(not(feature = "std"), no_std)]
231
232#[cfg(not(feature = "std"))]
233#[macro_use]
234extern crate alloc;
235
236// Layer 1: Primitives - data structures and basic utilities.
237mod primitives;
238
239// Layer 2: Math - pure mathematical functions.
240mod math;
241
242// Layer 3: Algorithms - core LOWESS algorithms.
243mod algorithms;
244
245// Layer 4: Evaluation - post-processing and diagnostics.
246mod evaluation;
247
248// Layer 5: Engine - orchestration and execution control.
249mod engine;
250
251// Layer 6: Adapters - execution mode adapters.
252mod adapters;
253
254// High-level fluent API for LOWESS smoothing.
255mod api;
256
257// Standard LOWESS prelude.
258pub mod prelude {
259 pub use crate::api::{
260 Adapter::{Batch, Online, Streaming},
261 BoundaryPolicy::Extend,
262 BoundaryPolicy::NoBoundary,
263 BoundaryPolicy::Reflect,
264 BoundaryPolicy::Zero,
265 KFold, LOOCV, LowessBuilder as Lowess, LowessError, LowessResult,
266 MergeStrategy::Average,
267 MergeStrategy::TakeFirst,
268 MergeStrategy::WeightedAverage,
269 RobustnessMethod::Bisquare,
270 RobustnessMethod::Huber,
271 RobustnessMethod::Talwar,
272 ScalingMethod::MAD,
273 ScalingMethod::MAR,
274 ScalingMethod::Mean,
275 UpdateMode::Full,
276 UpdateMode::Incremental,
277 WeightFunction::Biweight,
278 WeightFunction::Cosine,
279 WeightFunction::Epanechnikov,
280 WeightFunction::Gaussian,
281 WeightFunction::Triangle,
282 WeightFunction::Tricube,
283 WeightFunction::Uniform,
284 ZeroWeightFallback::ReturnNone,
285 ZeroWeightFallback::ReturnOriginal,
286 ZeroWeightFallback::UseLocalMean,
287 };
288}
289
290// Internal modules for development and testing.
291//
292// This module re-exports internal modules for development and testing purposes.
293// It is only available with the `dev` feature enabled.
294#[cfg(feature = "dev")]
295pub mod internals {
296 pub mod primitives {
297 pub use crate::primitives::*;
298 }
299 pub mod math {
300 pub use crate::math::*;
301 }
302 pub mod algorithms {
303 pub use crate::algorithms::*;
304 }
305 pub mod engine {
306 pub use crate::engine::*;
307 }
308 pub mod evaluation {
309 pub use crate::evaluation::*;
310 }
311 pub mod adapters {
312 pub use crate::adapters::*;
313 }
314 pub mod api {
315 pub use crate::api::*;
316 }
317}