1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//! Symbolic VarPro fitting guide.
//!
//! This guide shows the VarPro frontend in the crate:
//! - one nonlinear parameter per basis function,
//! - linear coefficients handled by the solver,
//! - invariant/background terms added separately.
//!
//! run cargo run --example varpro_fitting_guide
use RustedSciThe::numerical::optimization::varpro::symbolic::SymbolicVarProBuilder;
use RustedSciThe::symbolic::symbolic_engine::Expr;
use nalgebra::DVector;
fn main() {
println!("=== VarPro Fitting Guide ===\n");
exponential_with_offset();
}
fn exponential_with_offset() {
println!("Example: exponential decay with a constant offset");
println!("Model: y = a * exp(-x / tau) + b");
println!("Nonlinear parameter: tau");
println!("Linear coefficients: a, b\n");
let x_data = (0..30).map(|i| i as f64 * 0.2).collect::<Vec<_>>();
let y_data = x_data
.iter()
.map(|&x| 2.5 * (-x / 1.7).exp() + 0.8)
.collect::<Vec<_>>();
// VarPro separates nonlinear basis shape from linear coefficients.
let fit = SymbolicVarProBuilder::new("x")
.with_parameters(vec!["tau".to_string()])
.with_initial_parameters(vec![1.2])
.with_data(DVector::from_vec(x_data), DVector::from_vec(y_data))
.with_basis_str("tau", "exp(-x/tau)")
.with_equations(vec![Expr::parse_expression("1")])
.solve()
.expect("VarPro fit should succeed");
let nonlinear = fit.nonlinear_parameters();
let linear = fit
.linear_coefficients()
.expect("VarPro fit should return linear coefficients");
println!("Recovered parameters:");
println!(" tau = {:.6}", nonlinear[0]);
println!(" a = {:.6}", linear[0]);
println!(" b = {:.6}", linear[1]);
println!();
}