use mathcompile::prelude::*;
fn main() -> Result<()> {
println!("š MathCompile Ergonomic API Demonstration");
println!("=====================================\n");
println!("1ļøā£ Basic Expression Building");
println!("-----------------------------");
let mut math = MathBuilder::new();
let x = math.var("x");
let y = math.var("y");
let expr = math.add(&math.mul(&x, &math.constant(2.0)), &y);
let result = math.eval(&expr, &[("x", 3.0), ("y", 4.0)]);
println!(" Expression: 2*x + y");
println!(" At x=3, y=4: {result}");
println!(" Expected: 2*3 + 4 = 10");
assert_eq!(result, 10.0);
println!(" ā Correct!\n");
println!("2ļøā£ High-Level Mathematical Functions");
println!("------------------------------------");
let x = math.var("x");
let y = math.var("y");
let quadratic = math.poly(&[1.0, -3.0, 2.0], &x);
let result = math.eval(&quadratic, &[("x", 2.0)]);
println!(" Quadratic: 2x² - 3x + 1 (using operator overloading)");
println!(" At x=2: {result}");
println!(" Expected: 2(4) - 3(2) + 1 = 8 - 6 + 1 = 3");
assert_eq!(result, 3.0);
println!(" ā Correct!");
let quadratic_func = math.quadratic(2.0, -3.0, 1.0, &x); let result_func = math.eval(&quadratic_func, &[("x", 2.0)]);
assert_eq!(result, result_func);
println!(" ā Operator overloading matches convenience function!");
let complex = (&x + &y).sin_ref() * (&x * &y).exp_ref() + (-&x).cos_ref();
let result = math.eval(&complex, &[("x", 1.0), ("y", 2.0)]);
println!(" Complex: sin(x + y) * exp(x * y) + cos(-x)");
println!(" At x=1, y=2: {result}");
println!(" ā Natural mathematical syntax works!");
let poly = math.constant(1.0)
+ &x * math.constant(0.0)
+ &x * &x * math.constant(2.0)
+ &x * &x * &x * math.constant(-1.0); let result = math.eval(&poly, &[("x", 2.0)]);
println!(" Polynomial: 1 + 2x² - x³ (using operators)");
println!(" At x=2: {result}");
println!(" Expected: 1 + 2(4) - 8 = 1 + 8 - 8 = 1");
assert_eq!(result, 1.0);
println!(" ā Correct!\n");
println!("3ļøā£ Mathematical Constants");
println!("-------------------------");
let pi = math.math_constant("pi")?;
let e = math.math_constant("e")?;
let x = math.var("x");
let euler_identity_real = math.add(&math.exp(&math.mul(&pi, &x)), &math.constant(1.0));
let result = math.eval(&euler_identity_real, &[("x", 0.0)]);
println!(" Expression: exp(Ļ*x) + 1");
println!(" At x=0: {result}");
println!(" Expected: exp(0) + 1 = 2");
assert!((result - 2.0).abs() < 1e-10);
println!(" ā Correct!");
println!(" Available constants: pi, e, tau, sqrt2, ln2, ln10\n");
println!("4ļøā£ Statistical & Machine Learning Functions");
println!("-------------------------------------------");
let x = math.var("x");
let gaussian = math.gaussian(0.0, 1.0, &x);
let result = math.eval(&gaussian, &[("x", 0.0)]);
println!(" Standard Normal Distribution at x=0:");
println!(" Result: {result:.6}");
println!(" Expected: ~0.398942 (1/ā(2Ļ))");
assert!((result - 0.398942).abs() < 0.001);
println!(" ā Correct!");
let logistic = math.logistic(&x);
let result = math.eval(&logistic, &[("x", 0.0)]);
println!(" Logistic function at x=0:");
println!(" Result: {result}");
println!(" Expected: 0.5");
assert!((result - 0.5).abs() < 1e-10);
println!(" ā Correct!");
let tanh_expr = math.tanh(&x);
let result = math.eval(&tanh_expr, &[("x", 0.0)]);
println!(" Hyperbolic tangent at x=0:");
println!(" Result: {result}");
println!(" Expected: 0.0");
assert!(result.abs() < 1e-10);
println!(" ā Correct!\n");
println!("5ļøā£ Preset Functions");
println!("-------------------");
let x = math.var("x");
let std_normal = presets::standard_normal(&math, &x);
let result = math.eval(&std_normal, &[("x", 0.0)]);
println!(" Standard normal preset at x=0: {result:.6}");
let y_pred = math.var("y_pred");
let y_true = math.var("y_true");
let mse = presets::mse_loss(&math, &y_pred, &y_true);
let result = math.eval(&mse, &[("y_pred", 0.8), ("y_true", 1.0)]);
println!(" MSE Loss (pred=0.8, true=1.0): {result}");
println!(" Expected: (0.8-1.0)² = 0.04");
assert!((result - 0.04).abs() < 1e-10);
println!(" ā Correct!\n");
println!("6ļøā£ Expression Validation");
println!("------------------------");
let valid_expr = &x * &x + &x * math.constant(2.0) + math.constant(3.0); match math.validate(&valid_expr) {
Ok(()) => println!(" ā Valid expression passed validation"),
Err(e) => println!(" ā Unexpected validation error: {e}"),
}
let invalid_expr = math.div(&math.constant(1.0), &math.constant(0.0));
match math.validate(&invalid_expr) {
Ok(()) => println!(" ā Invalid expression incorrectly passed validation"),
Err(_) => println!(" ā Invalid expression correctly caught by validation"),
}
let nan_expr = math.constant(f64::NAN);
match math.validate(&nan_expr) {
Ok(()) => println!(" ā NaN expression incorrectly passed validation"),
Err(_) => println!(" ā NaN expression correctly caught by validation"),
}
println!();
println!("7ļøā£ Integration with Advanced Features");
println!("-------------------------------------");
let mut opt_math = MathBuilder::with_optimization()?;
let x = opt_math.var("x");
let complex_expr = opt_math.add(
&opt_math.mul(&x, &opt_math.constant(0.0)), &opt_math.pow(&x, &opt_math.constant(1.0)), );
println!(" Original expression: x*0 + x^1");
let optimized = opt_math.optimize(&complex_expr)?;
println!(" After optimization: (should be simplified)");
let original_result = opt_math.eval(&complex_expr, &[("x", 5.0)]);
let optimized_result = opt_math.eval(&optimized, &[("x", 5.0)]);
println!(" Original result at x=5: {original_result}");
println!(" Optimized result at x=5: {optimized_result}");
assert_eq!(original_result, optimized_result);
println!(" ā Optimization preserves correctness!");
let derivative = opt_math.derivative(&optimized, "x")?;
let deriv_result = opt_math.eval(&derivative, &[("x", 5.0)]);
println!(" Derivative at x=5: {deriv_result}");
println!(" Expected: 1.0 (since optimized expression should be x)");
println!();
println!("8ļøā£ Comparison: Traditional vs Ergonomic API");
println!("-------------------------------------------");
println!(" Traditional approach (verbose):");
println!(" let expr = ASTEval::add(");
println!(" ASTEval::mul(ASTEval::var(0), ASTEval::constant(2.0)),");
println!(" ASTEval::var(1)");
println!(" );");
println!(" // Need to manage variable indices manually");
println!(" // Need to create variable arrays for evaluation");
println!();
println!(" Ergonomic approach (intuitive):");
println!(" let mut math = MathBuilder::new();");
println!(" let x = math.var(\"x\");");
println!(" let y = math.var(\"y\");");
println!(" let expr = math.add(&math.mul(&x, &math.constant(2.0)), &y);");
println!(" let result = math.eval(&expr, &[(\"x\", 3.0), (\"y\", 4.0)]);");
println!();
println!(" Benefits of the ergonomic API:");
println!(" ā Automatic variable management");
println!(" ā Named variable evaluation");
println!(" ā Built-in validation");
println!(" ā High-level mathematical functions");
println!(" ā Integration with optimization and differentiation");
println!(" ā Preset functions for common use cases");
println!(" ā Better error messages");
println!(" ā Type safety with helpful validation");
println!("\nš Ergonomic API Demo Complete!");
println!("The new MathBuilder API makes MathCompile much more accessible while");
println!("maintaining all the performance benefits of the underlying system.");
println!("\nš API Comparison: Old vs New Syntax");
println!("------------------------------------");
println!(" Old verbose syntax:");
println!(" let expr = math.add(");
println!(" &math.mul(&math.constant(2.0), &x),");
println!(" &math.constant(1.0)");
println!(" );");
let old_expr = math.add(&math.mul(&math.constant(2.0), &x), &math.constant(1.0));
println!(" New natural syntax:");
println!(" let expr = math.constant(2.0) * &x + math.constant(1.0);");
let new_expr = math.constant(2.0) * &x + math.constant(1.0);
let old_result = math.eval(&old_expr, &[("x", 5.0)]);
let new_result = math.eval(&new_expr, &[("x", 5.0)]);
println!(" Results at x=5:");
println!(" Old syntax: {old_result}");
println!(" New syntax: {new_result}");
assert_eq!(old_result, new_result);
println!(" ā Both syntaxes produce identical results!");
println!("\\n Complex expression comparison:");
println!(" Old: math.add(&math.sin(&math.pow(&x, &math.constant(2.0))), &math.exp(&y))");
let old_complex = math.add(&math.sin(&math.pow(&x, &math.constant(2.0))), &math.exp(&y));
println!(" New: (&x * &x).sin_ref() + y.exp_ref()");
let new_complex = (&x * &x).sin_ref() + y.exp_ref();
let old_complex_result = math.eval(&old_complex, &[("x", 1.5), ("y", 0.5)]);
let new_complex_result = math.eval(&new_complex, &[("x", 1.5), ("y", 0.5)]);
println!(" Results at x=1.5, y=0.5:");
println!(" Old syntax: {old_complex_result}");
println!(" New syntax: {new_complex_result}");
assert_eq!(old_complex_result, new_complex_result);
println!(" ā Complex expressions also match!");
println!("\\nš Performance & Optimization Integration");
Ok(())
}