use mathhook_core::prelude::*;
#[test]
fn test_solve_simple_linear() {
let x = symbol!(x);
let equation = Expression::equation(Expression::symbol(x.clone()), expr!(5));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(5));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_linear_with_coefficient() {
let x = symbol!(x);
let equation = Expression::equation(expr!(2 * x), expr!(10));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(5));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_linear_with_constant() {
let x = symbol!(x);
let left = expr!(x + 3);
let right = expr!(8);
let equation = Expression::equation(left, right);
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(5));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_quadratic_simple() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x ^ 2), expr!(4));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
assert!(solutions.contains(&Expression::integer(-2)));
assert!(solutions.contains(&expr!(2)));
}
_ => panic!("Expected multiple solutions"),
}
}
#[test]
fn test_solve_quadratic_one_solution() {
let x = symbol!(x);
let equation = Expression::equation(
Expression::add(vec![
expr!(x ^ 2),
Expression::mul(vec![Expression::integer(-2), Expression::symbol(x.clone())]),
expr!(1),
]),
expr!(0),
);
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(1));
}
SolverResult::Multiple(ref solutions) if solutions.len() == 1 => {
assert_eq!(solutions[0], expr!(1));
}
_ => panic!("Expected single solution or one repeated root"),
}
}
#[test]
fn test_solve_quadratic_formula() {
let x = symbol!(x);
let equation = Expression::equation(expr!((x ^ 2) + (3 * x) + 2), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
assert!(solutions.contains(&Expression::integer(-2)));
assert!(solutions.contains(&Expression::integer(-1)));
}
_ => panic!("Expected multiple solutions"),
}
}
#[test]
#[ignore = "FIXME: Let's find out why"]
fn test_solve_zero_equals_zero() {
let x = symbol!(x);
let equation = Expression::equation(expr!(0), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::InfiniteSolutions => {
}
_ => panic!("Expected infinite solutions"),
}
}
#[test]
fn test_solve_no_solution() {
let x = symbol!(x);
let equation = Expression::equation(expr!(1), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::NoSolution => {
}
_ => panic!("Expected no solution"),
}
}
#[test]
fn test_solve_negative_coefficient() {
let x = symbol!(x);
let equation = Expression::equation(
Expression::mul(vec![Expression::integer(-2), Expression::symbol(x.clone())]),
expr!((-10)),
);
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, Expression::integer(5));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_fraction_result() {
let x = symbol!(x);
let equation = Expression::equation(expr!(2 * x), expr!(1));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, Expression::rational(1, 2));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_cubic_one_real_root() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x ^ 3), expr!(1));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(1));
}
SolverResult::Multiple(solutions) => {
assert!(solutions.contains(&expr!(1)));
}
_ => panic!("Expected at least one solution"),
}
}
#[test]
fn test_solve_higher_order_polynomial() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x ^ 4), expr!(16));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert!(solutions.len() >= 2);
assert!(solutions.contains(&Expression::integer(-2)) || solutions.contains(&expr!(2)));
}
_ => panic!("Expected multiple solutions"),
}
}
#[test]
fn test_solve_with_multiple_variables() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x + y), expr!(5));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
let expected = expr!(5 - y);
assert_eq!(solution, expected);
}
_ => panic!("Expected single solution in terms of y"),
}
}
#[test]
fn test_solve_rational_equation() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x / 2), expr!(3));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(6));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_zero_equals_variable() {
let x = symbol!(x);
let equation = Expression::equation(Expression::symbol(x.clone()), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(0));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_negative_square() {
let x = symbol!(x);
let equation = Expression::equation(expr!((x ^ 2) + 1), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
let solutions_str = format!("{:?}", solutions);
assert!(solutions_str.contains("i") || solutions_str.contains("I"));
}
SolverResult::NoSolution => {
}
_ => panic!("Expected multiple complex solutions or no real solutions"),
}
}
#[test]
fn test_solve_linear_system_simple() {
let x = symbol!(x);
let y = symbol!(y);
let eq1 = Expression::equation(expr!(x + y), expr!(3));
let eq2 = Expression::equation(expr!(x - y), expr!(1));
let solver = MathSolver::new();
let results = solver.solve_system(&[eq1, eq2], &[x.clone(), y.clone()]);
assert_eq!(results.len(), 2);
for result in results {
match result {
SolverResult::Single(_) => {
}
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 1);
}
_ => panic!("Expected solution for each variable"),
}
}
}
#[test]
fn test_solve_quadratic_negative_discriminant() {
let x = symbol!(x);
let equation = Expression::equation(expr!((x ^ 2) + x + 1), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
}
SolverResult::NoSolution => {
}
_ => panic!("Expected complex solutions or no real solutions"),
}
}
#[test]
fn test_solve_exponential_simple() {
let x = symbol!(x);
let equation = Expression::equation(expr!(2 ^ x), expr!(8));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(3));
}
_ => {
}
}
}
#[test]
fn test_solve_absolute_value() {
let x = symbol!(x);
let equation = Expression::equation(function!(abs, Expression::symbol(x.clone())), expr!(5));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
assert!(solutions.contains(&Expression::integer(-5)));
assert!(solutions.contains(&expr!(5)));
}
_ => {
}
}
}
#[test]
fn test_solve_sqrt_equation() {
let x = symbol!(x);
let equation = Expression::equation(function!(sqrt, Expression::symbol(x.clone())), expr!(2));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(4));
}
_ => {
}
}
}
#[test]
#[ignore = "FIXME: Let's find out why"]
fn test_solve_factored_form() {
let x = symbol!(x);
let equation = Expression::equation(expr!((x - 1) * (x - 2)), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
assert!(solutions.contains(&expr!(1)));
assert!(solutions.contains(&expr!(2)));
}
_ => panic!("Expected multiple solutions"),
}
}
#[test]
fn test_solve_cubic_all_real_roots() {
let x = symbol!(x);
let equation = Expression::equation(
Expression::add(vec![
expr!(x ^ 3),
Expression::mul(vec![Expression::integer(-6), expr!(x ^ 2)]),
Expression::mul(vec![Expression::integer(11), Expression::symbol(x.clone())]),
Expression::integer(-6),
]),
expr!(0),
);
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 3);
assert!(solutions.contains(&expr!(1)));
assert!(solutions.contains(&expr!(2)));
assert!(solutions.contains(&expr!(3)));
}
_ => {
}
}
}
#[test]
#[ignore = "FIXME: Let's find out why"]
fn test_solve_variable_on_both_sides() {
let x = symbol!(x);
let equation = Expression::equation(expr!((2 * x) + 3), expr!(x + 8));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, expr!(5));
}
_ => panic!("Expected single solution"),
}
}
#[test]
fn test_solve_multiple_occurrences() {
let x = symbol!(x);
let equation = Expression::equation(
Expression::add(vec![
expr!(x ^ 2),
Expression::mul(vec![Expression::integer(-5), Expression::symbol(x.clone())]),
expr!(6),
]),
expr!(0),
);
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Multiple(solutions) => {
assert_eq!(solutions.len(), 2);
assert!(solutions.contains(&expr!(2)));
assert!(solutions.contains(&expr!(3)));
}
_ => panic!("Expected multiple solutions"),
}
}
#[test]
fn test_solve_negative_result() {
let x = symbol!(x);
let equation = Expression::equation(expr!(x + 10), expr!(0));
let solver = MathSolver::new();
let result = solver.solve(&equation, &x);
match result {
SolverResult::Single(solution) => {
assert_eq!(solution, Expression::integer(-10));
}
_ => panic!("Expected single solution"),
}
}