use symplex::prelude::*;
fn main() {
println!("=== Symbolic Optimization ===\n");
let ctx = Context::new();
symplex::syms!(ctx; x, y);
let f = expr!(ctx, x ^ 2 + y ^ 2 - 2 * x - 4 * y + 5);
println!("f(x,y) = {f}");
let grad_x = f.diff(&x);
let grad_y = f.diff(&y);
println!("∇f = [{grad_x}, {grad_y}]");
let x_crit = grad_x.solve_or_empty(&x);
let y_crit = grad_y.solve_or_empty(&y);
println!(
"Critical point: x = {}, y = {}",
x_crit.first().map(|v| format!("{v}")).unwrap_or("?".into()),
y_crit.first().map(|v| format!("{v}")).unwrap_or("?".into()),
);
let fxx = f.diff(&x).diff(&x);
let fxy = f.diff(&x).diff(&y);
let fyx = f.diff(&y).diff(&x);
let fyy = f.diff(&y).diff(&y);
let hessian = matrix![ctx, [fxx, fxy], [fyx, fyy]];
println!("Hessian: {hessian}");
println!("det(H) = {}", hessian.det().unwrap());
let det_h = hessian
.det()
.unwrap()
.eval_f64_with(&[(&x, 1), (&y, 2)])
.unwrap();
let fxx = hessian
.get(0, 0)
.eval_f64_with(&[(&x, 1), (&y, 2)])
.unwrap();
println!("At critical point: det(H) = {det_h}, f_xx = {fxx}");
if det_h > 0.0 && fxx > 0.0 {
println!("→ Local MINIMUM");
} else if det_h > 0.0 && fxx < 0.0 {
println!("→ Local MAXIMUM");
} else if det_h < 0.0 {
println!("→ Saddle point");
} else {
println!("→ Inconclusive");
}
println!("\n✓ Done!");
}