use numrs2::symbolic::*;
use std::collections::HashMap;
fn main() {
println!("=== NumRS2 Symbolic Mathematics Examples ===\n");
basic_expressions();
symbolic_differentiation();
gradient_computation();
expression_simplification();
expression_expansion();
latex_output();
symbolic_linear_algebra();
optimization_example();
chain_rule_demo();
taylor_series();
}
fn basic_expressions() {
println!("--- Example 1: Basic Expressions ---");
let x = Expr::var("x");
let y = Expr::var("y");
let expr = x.clone().pow(2.0) + x.clone() * y.clone() * 2.0 + y.clone().pow(2.0);
println!("Expression: {}", expr);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 3.0);
vars.insert("y".to_string(), 4.0);
match expr.eval(&vars) {
Ok(result) => {
println!("f(3, 4) = {}", result); }
Err(e) => println!("Error: {:?}", e),
}
println!();
}
fn symbolic_differentiation() {
println!("--- Example 2: Symbolic Differentiation ---");
let x = Expr::var("x");
let f = x.clone().pow(3.0) - x.clone().pow(2.0) * 2.0 + x.clone() * 3.0 - 5.0;
println!("f(x) = {}", f);
match differentiate(&f, "x") {
Ok(df) => {
println!("f'(x) = {}", df);
let simplified = simplify(&df);
println!("f'(x) simplified = {}", simplified);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 2.0);
match simplified.eval(&vars) {
Ok(result) => {
println!("f'(2) = {}", result); }
Err(e) => println!("Error: {:?}", e),
}
}
Err(e) => println!("Error: {:?}", e),
}
println!();
}
fn gradient_computation() {
println!("--- Example 3: Gradient Computation ---");
let x = Expr::var("x");
let y = Expr::var("y");
let f = x.clone().pow(2.0) + y.clone().pow(2.0);
println!("f(x, y) = {}", f);
match gradient(&f, &["x", "y"]) {
Ok(grad) => {
println!("∇f = [{}, {}]", grad[0], grad[1]);
let grad_simplified: Vec<Expr> = grad.iter().map(simplify).collect();
println!(
"∇f simplified = [{}, {}]",
grad_simplified[0], grad_simplified[1]
);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 3.0);
vars.insert("y".to_string(), 4.0);
match (
grad_simplified[0].eval(&vars),
grad_simplified[1].eval(&vars),
) {
(Ok(dx), Ok(dy)) => {
println!("∇f(3, 4) = [{}, {}]", dx, dy); }
_ => println!("Error evaluating gradient"),
}
}
Err(e) => println!("Error: {:?}", e),
}
println!();
}
fn expression_simplification() {
println!("--- Example 4: Expression Simplification ---");
let x = Expr::var("x");
let expr = (x.clone() + 0.0) * (x.clone() + 1.0) + (x.clone() * 0.0);
println!("Original: {}", expr);
let simplified = simplify(&expr);
println!("Simplified: {}", simplified);
let expr2 = -(-x.clone());
println!("\nOriginal: {}", expr2);
println!("Simplified: {}", simplify(&expr2));
println!();
}
fn expression_expansion() {
println!("--- Example 5: Expression Expansion ---");
let x = Expr::var("x");
let expr = (x.clone() + 1.0) * (x.clone() + 2.0);
println!("Original: {}", expr);
let expanded = expand(&expr);
println!("Expanded: {}", expanded);
let simplified = simplify(&expanded);
println!("Simplified: {}", simplified);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 1.0);
match (expr.eval(&vars), simplified.eval(&vars)) {
(Ok(v1), Ok(v2)) => {
println!("\nVerification at x=1:");
println!("Original value: {}", v1);
println!("Expanded value: {}", v2);
println!("Match: {}", (v1 - v2).abs() < 1e-10);
}
_ => println!("Error in evaluation"),
}
println!();
}
fn latex_output() {
println!("--- Example 6: LaTeX Output ---");
let x = Expr::var("x");
let expr = (x.clone().pow(2.0) + x.clone() * 2.0 + 1.0) / (x.clone() - 1.0);
println!("Expression: {}", expr);
println!("LaTeX: {}", expr.to_latex());
println!("Python: {}", expr.to_python());
let trig_expr = x.clone().sin().pow(2.0) + x.clone().cos().pow(2.0);
println!("\nExpression: {}", trig_expr);
println!("LaTeX: {}", trig_expr.to_latex());
println!();
}
fn symbolic_linear_algebra() {
println!("--- Example 7: Symbolic Linear Algebra ---");
let x = Expr::var("x");
let mat_data = vec![
vec![x.clone(), Expr::constant(1.0)],
vec![Expr::constant(0.0), x.clone()],
];
match SymbolicMatrix::from_vec(mat_data) {
Ok(mat) => {
println!("Matrix:");
for i in 0..mat.nrows() {
print!("[");
for j in 0..mat.ncols() {
if let Some(elem) = mat.get(i, j) {
print!("{}", elem);
if j < mat.ncols() - 1 {
print!(", ");
}
}
}
println!("]");
}
match determinant(&mat) {
Ok(det) => {
println!("\nDeterminant: {}", det);
let det_simplified = simplify(&det);
println!("Simplified: {}", det_simplified);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 3.0);
match det_simplified.eval(&vars) {
Ok(result) => {
println!("det(x=3) = {}", result); }
Err(e) => println!("Error: {:?}", e),
}
}
Err(e) => println!("Error computing determinant: {:?}", e),
}
match trace(&mat) {
Ok(tr) => {
println!("\nTrace: {}", tr);
let tr_simplified = simplify(&tr);
println!("Simplified: {}", tr_simplified);
}
Err(e) => println!("Error computing trace: {:?}", e),
}
}
Err(e) => println!("Error creating matrix: {:?}", e),
}
println!();
}
fn optimization_example() {
println!("--- Example 8: Optimization Example ---");
let x = Expr::var("x");
let f = (x.clone() - 3.0).pow(2.0) + 2.0;
println!("Objective function: f(x) = {}", f);
match differentiate(&f, "x") {
Ok(df) => {
let df_simplified = simplify(&df);
println!("f'(x) = {}", df_simplified);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 3.0);
match (f.eval(&vars), df_simplified.eval(&vars)) {
(Ok(f_val), Ok(df_val)) => {
println!("\nAt x = 3:");
println!("f(3) = {}", f_val); println!("f'(3) = {}", df_val); }
_ => println!("Error in evaluation"),
}
match differentiate(&df, "x") {
Ok(d2f) => {
let d2f_simplified = simplify(&d2f);
println!("f''(x) = {}", d2f_simplified);
match d2f_simplified.eval(&vars) {
Ok(d2f_val) => {
if d2f_val > 0.0 {
println!("f''(3) = {} > 0, so x=3 is a minimum", d2f_val);
}
}
Err(e) => println!("Error: {:?}", e),
}
}
Err(e) => println!("Error computing second derivative: {:?}", e),
}
}
Err(e) => println!("Error: {:?}", e),
}
println!();
}
fn chain_rule_demo() {
println!("--- Example 9: Chain Rule Demonstration ---");
let x = Expr::var("x");
let f = (x.clone().pow(2.0)).sin();
println!("f(x) = {}", f);
match differentiate(&f, "x") {
Ok(df) => {
println!("f'(x) = {}", df);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 0.0);
match df.eval(&vars) {
Ok(result) => {
println!("f'(0) = {}", result); }
Err(e) => println!("Error: {:?}", e),
}
vars.insert("x".to_string(), 1.0);
match df.eval(&vars) {
Ok(result) => {
println!("f'(1) = {}", result); let expected = 1.0_f64.cos() * 2.0;
println!("Expected: {}", expected);
println!("Match: {}", (result - expected).abs() < 1e-10);
}
Err(e) => println!("Error: {:?}", e),
}
}
Err(e) => println!("Error: {:?}", e),
}
println!();
}
fn taylor_series() {
println!("--- Example 10: Taylor Series Approximation ---");
let x = Expr::var("x");
let f = x.clone().exp();
println!("f(x) = {}", f);
let mut vars = HashMap::new();
vars.insert("x".to_string(), 0.0);
let mut current = f.clone();
let mut coeffs = vec![];
for n in 0..5 {
match current.eval(&vars) {
Ok(coeff) => {
coeffs.push(coeff);
println!("f^({})({}) = {}", "′".repeat(n), 0, coeff);
}
Err(e) => {
println!("Error: {:?}", e);
break;
}
}
match differentiate(¤t, "x") {
Ok(deriv) => current = deriv,
Err(e) => {
println!("Error: {:?}", e);
break;
}
}
}
println!("\nTaylor series approximation:");
println!("exp(x) ≈ 1 + x + x²/2 + x³/6 + x⁴/24 + ...");
let test_x = 0.5_f64;
let actual = test_x.exp();
let mut taylor_approx = 0.0;
let mut factorial = 1.0;
let mut x_power = 1.0;
for (n, coeff) in coeffs.iter().enumerate() {
if n > 0 {
factorial *= n as f64;
x_power *= test_x;
}
taylor_approx += coeff * x_power / factorial;
}
println!("\nAt x = {}:", test_x);
println!("Actual exp({}) = {}", test_x, actual);
println!("Taylor approximation = {}", taylor_approx);
println!("Error = {}", (actual - taylor_approx).abs());
println!();
}