use symplex::prelude::*;
fn main() {
println!("=== Symplex Calculus Example ===\n");
let ctx = Context::new();
symplex::syms!(ctx; x);
let f = expr!(ctx, x ^ 3 - 3 * x ^ 2 + 2 * x);
println!("f(x) = {f}");
let df = f.diff(&x);
println!("f'(x) = {df}");
let d2f = df.diff(&x);
println!("f''(x) = {d2f}");
let g = expr!(ctx, x ^ 6);
let g4 = g.diff_n(&x, 4);
println!("\nd⁴/dx⁴ (x⁶) = {g4}");
println!("\nCritical points (f'(x) = 0):");
let critical = df.solve(&x).unwrap_or_default();
for pt in &critical {
println!(" x = {pt}");
}
println!("\nSecond-derivative test:");
for pt in &critical {
let d2_val = d2f.subs(&x, pt);
println!(" f''({pt}) = {d2_val}");
}
let anti = f.integrate(&x);
println!("\n∫ f(x) dx = {anti}");
let roundtrip = anti.diff(&x);
println!("d/dx(∫ f dx) = {roundtrip}");
println!("\nAdditional integrals:");
println!(" ∫ sin(x) dx = {}", x.sin().integrate(&x));
println!(" ∫ cos(x) dx = {}", x.cos().integrate(&x));
println!(" ∫ exp(x) dx = {}", x.exp().integrate(&x));
println!(" ∫ 1/x dx = {}", (1 / &x).integrate(&x));
let poly = expr!(ctx, 5 * x ^ 4 + 3 * x ^ 2 + 1);
println!(" ∫ ({poly}) dx = {}", poly.integrate(&x));
let zero = ctx.int(0);
let one = ctx.int(1);
let area = f.integrate_definite(&x, &zero, &one);
println!("\n∫₀¹ f(x) dx = {area}");
let pi = ctx.pi();
let sin_area = x.sin().integrate_definite(&x, &zero, &pi);
println!("∫₀^π sin(x) dx = {}", sin_area.eval());
let x_squared_area = expr!(ctx, x ^ 2).integrate_definite(&x, &ctx.int(-1), &one);
println!("∫₋₁¹ x² dx = {x_squared_area}");
let sin_series = x.sin().maclaurin(&x, 5);
println!("\nsin(x) ≈ {}", sin_series.expand().eval());
let cos_series = x.cos().maclaurin(&x, 5);
println!("cos(x) ≈ {}", cos_series.expand().eval());
let exp_series = x.exp().maclaurin(&x, 5);
println!("exp(x) ≈ {}", exp_series.expand().eval());
let trig = expr!(ctx, sin(x) ^ 2 + cos(x) ^ 2);
println!("\n{trig} → {}", trig.simplify());
let exp_ln = x.ln().exp();
println!("exp(ln(x)) → {}", exp_ln.simplify());
let ln_exp = x.exp().ln();
println!("ln(exp(x)) → {}", ln_exp.simplify());
let complicated = &(&x + 1).powi(2) - &x.powi(2) - &x * 2;
println!("(x+1)² - x² - 2x → {}", complicated.simplify());
let limit_expr = &x.sin() / &x;
let lim = limit_expr.limit(&x, &ctx.int(0));
println!("\nlim(x→0) sin(x)/x = {lim}");
let exp_limit = &(&x.exp() - 1) / &x;
let lim2 = exp_limit.limit(&x, &ctx.int(0));
println!("lim(x→0) (exp(x)-1)/x = {lim2}");
let inf = ctx.infinity();
let lim3 = (1 / &x).limit(&x, &inf);
println!("lim(x→∞) 1/x = {lim3}");
let val = expr!(ctx, x ^ 2 + 1).subs_i64(&x, 3);
println!("\nf(3) where f = x² + 1: {val}");
let val2 = f.subs_i64(&x, 5);
println!("f(5) where f = x³ - 3x² + 2x: {val2}");
let float_val = expr!(ctx, sin(x) + cos(x))
.eval_f64_with(&[(&x, 1)])
.unwrap();
println!("sin(1) + cos(1) = {float_val:.8}");
let poly = &x.powi(2) - 1;
let factored = poly.factor(&x);
println!("\nx² - 1 = {factored}");
let quadratic = expr!(ctx, x ^ 2 - 5 * x + 6);
let factored2 = quadratic.factor(&x);
println!("x² - 5x + 6 = {factored2}");
println!("\nSolving x² - 5x + 6 = 0:");
let roots = quadratic.solve(&x).unwrap();
for r in &roots {
println!(" x = {r}");
}
let complicated2 = &(&x + 1).powi(2) - &x.powi(2) - &x * 2;
println!("\n(x+1)² - x² - 2x = {}", complicated2.simplify());
let transcendental = &x - &x.cos();
match transcendental.solve_numeric(&x, 1.0, 50, 1e-12) {
Ok(root) => println!("\nNumerical root of x - cos(x) = 0: x ≈ {root:.10}"),
Err(e) => println!("\nNumerical solve failed: {e}"),
}
match pi.eval_decimal(30) {
Ok(s) => println!("\nπ to 30 digits: {s}"),
Err(e) => println!("\nevalf failed: {e}"),
}
println!("\n--- ODE Solving ---");
symplex::syms!(ctx; y);
let dy = y.formal_diff(&x);
let ode1 = &dy - &x;
println!("\nODE: y' - x = 0");
let sol = ode1.solve_ode(&y, &x);
if !sol.has_unevaluated() {
println!(" Solution: y = {sol}");
let constants = sol.free_symbols();
println!(
" Constants: {:?}",
constants.iter().map(|c| format!("{c}")).collect::<Vec<_>>()
);
}
let ode2 = expr!(ctx, diff(y, x) + 2 * y);
println!("\nODE: y' + 2y = 0");
let sol = ode2.solve_ode(&y, &x);
if !sol.has_unevaluated() {
println!(" Solution: y = {sol}");
}
let dy2 = y.formal_diff(&x);
let d2y2 = dy2.formal_diff(&x);
let ode3 = &d2y2 + &y;
println!("\nODE: y'' + y = 0");
let sol = ode3.solve_ode(&y, &x);
if !sol.has_unevaluated() {
println!(" Solution: y = {sol}");
let constants = sol.free_symbols();
println!(
" Constants: {:?}",
constants.iter().map(|c| format!("{c}")).collect::<Vec<_>>()
);
}
let ode_const = y.formal_diff(&x);
println!("\nODE: y' = 0");
let sol = ode_const.solve_ode(&y, &x);
if !sol.has_unevaluated() {
println!(" Solution: y = {sol}");
}
println!("\n--- ODE Classification ---");
let ode_sep = expr!(ctx, diff(y, x) - x);
println!("y' - x = 0: {:?}", ode_sep.classify_ode(&y, &x));
let ode_lin = expr!(ctx, diff(y, x) + 2 * y);
println!("y' + 2y = 0: {:?}", ode_lin.classify_ode(&y, &x));
println!("\n--- ODE Solution Verification ---");
let ode_check = expr!(ctx, diff(y, x) - x);
let proposed = &x.powi(2) / 2;
let verified = ode_check.check_ode_solution(&proposed, &y, &x);
println!("y' = x, proposed y = x²/2: verified = {verified}");
let ode_check2 = expr!(ctx, diff(y, x) + 2 * y);
let wrong = x.clone();
let verified2 = ode_check2.check_ode_solution(&wrong, &y, &x);
println!("y' + 2y = 0, proposed y = x: verified = {verified2}");
println!("\n--- Implicit Differentiation ---");
let circle = expr!(ctx, x ^ 2 + y ^ 2);
let implicit = circle.diff_with_dependent(&x, &[&y]);
println!("d/dx(x² + y²) with y = y(x):");
println!(" {implicit}");
println!(" (This equals 0, so dy/dx = -x/y)");
println!("\n--- Laplace Transforms ---");
symplex::syms!(ctx; t, s);
let result = ctx.int(1).laplace(&t, &s);
println!("L{{1}} = {result}");
let result = (&t * 2).exp().laplace(&t, &s);
println!("L{{exp(2t)}} = {result}");
let result = t.sin().laplace(&t, &s);
println!("L{{sin(t)}} = {result}");
let result = (1 / &s).inverse_laplace(&s, &t);
println!("L⁻¹{{1/s}} = {result}");
println!("\n--- Code Generation ---");
let df_code = df.to_rust_fn("f_prime", &["x"]).unwrap();
println!("Generated code for f'(x):");
println!("{df_code}");
println!("\n=== Done ===");
}