use std::sync::Arc;
use crate::symbolic::core::Expr;
use crate::symbolic::matrix;
use crate::symbolic::simplify_dag::simplify;
use crate::symbolic::solve::solve_system;
use crate::symbolic::stats::covariance;
use crate::symbolic::stats::mean;
use crate::symbolic::stats::variance;
#[must_use]
pub fn simple_linear_regression_symbolic(data: &[(Expr, Expr)]) -> (Expr, Expr) {
let (xs, ys): (Vec<_>, Vec<_>) = data.iter().cloned().unzip();
let mean_x = mean(&xs);
let mean_y = mean(&ys);
let var_x = variance(&xs);
let cov_xy = covariance(&xs, &ys);
let b1 = simplify(&Expr::new_div(cov_xy, var_x));
let b0 = simplify(&Expr::new_sub(mean_y, Expr::new_mul(b1.clone(), mean_x)));
(b0, b1)
}
#[must_use]
pub fn nonlinear_regression_symbolic(
data: &[(Expr, Expr)],
model: &Expr,
vars: &[&str],
params: &[&str],
) -> Option<Vec<(Expr, Expr)>> {
let mut s_expr = Expr::Constant(0.0);
let x_var = vars.first().copied().unwrap_or("x");
for (x_i, y_i) in data {
let mut model_at_point = model.clone();
model_at_point = crate::symbolic::calculus::substitute(&model_at_point, x_var, x_i);
let residual = Expr::new_sub(y_i.clone(), model_at_point);
let residual_sq = Expr::new_pow(residual, Expr::Constant(2.0));
s_expr = Expr::new_add(s_expr, residual_sq);
}
let mut grad_eqs = Vec::new();
for ¶m in params {
let deriv = crate::symbolic::calculus::differentiate(&s_expr, param);
grad_eqs.push(Expr::Eq(Arc::new(deriv), Arc::new(Expr::Constant(0.0))));
}
solve_system(&grad_eqs, params)
}
pub fn polynomial_regression_symbolic(
data: &[(Expr, Expr)],
degree: usize,
) -> Result<Vec<Expr>, String> {
let (xs, ys): (Vec<_>, Vec<_>) = data.iter().cloned().unzip();
let n = data.len();
let mut x_matrix_rows = Vec::with_capacity(n);
for x_i in &xs {
let mut row = Vec::with_capacity(degree + 1);
for j in 0..=degree {
row.push(simplify(&Expr::new_pow(
x_i.clone(),
Expr::Constant(j as f64),
)));
}
x_matrix_rows.push(row);
}
let x_matrix = Expr::Matrix(x_matrix_rows);
let x_matrix_t = matrix::transpose_matrix(&x_matrix);
let xt_x = matrix::mul_matrices(&x_matrix_t, &x_matrix);
let xt_y = matrix::mul_matrices(
&x_matrix_t,
&Expr::Matrix(ys.into_iter().map(|y| vec![y]).collect()),
);
let _coeff_vars: Vec<String> = (0..=degree).map(|i| format!("c{i}")).collect();
let result = matrix::solve_linear_system(&xt_x, &xt_y);
match result {
| Ok(Expr::Matrix(rows)) => Ok(rows.into_iter().map(|row| row[0].clone()).collect()),
| Ok(_) => {
Err("Solver returned a \
non-vector solution."
.to_string())
},
| Err(e) => Err(e),
}
}