use mathhook_core::prelude::*;
mod arithmetic_laws {
use super::*;
#[test]
fn test_integer_arithmetic_correctness() {
let test_cases = vec![
(vec![2, 3], 5), (vec![10, -3, 7], 14), (vec![-5, -3, -2], -10), (vec![0, 42, 0], 42), (vec![1, 2, 3, 4, 5], 15), ];
for (addends, expected) in test_cases {
let expr = Expression::add(addends.iter().map(|&x| Expression::integer(x)).collect());
let result = expr.simplify();
assert_eq!(
result,
Expression::integer(expected),
"Addition {:?} should equal {}, got {}",
addends,
expected,
result
);
}
}
#[test]
fn test_multiplication_arithmetic_correctness() {
let test_cases = vec![
(vec![2, 3], 6), (vec![2, 3, 4], 24), (vec![-2, 3], -6), (vec![-2, -3], 6), (vec![1, 2, 3, 4], 24), ];
for (factors, expected) in test_cases {
let expr = Expression::mul(factors.iter().map(|&x| Expression::integer(x)).collect());
let result = expr.simplify();
assert_eq!(
result,
Expression::integer(expected),
"Multiplication {:?} should equal {}, got {}",
factors,
expected,
result
);
}
}
#[test]
fn test_large_sum_correctness() {
let large_sum: Vec<Expression> = (1..=100).map(Expression::integer).collect();
let expr = Expression::add(large_sum);
let result = expr.simplify();
assert_eq!(
result,
expr!(5050),
"Sum of integers 1 to 100 should be 5050"
);
}
}
mod algebraic_identities {
use super::*;
#[test]
fn test_additive_identity_law() {
let test_expressions = vec![
(expr!(42), expr!(42)), (expr!(x), expr!(x)), (expr!(2 + 3), expr!(5)),
];
let zero = expr!(0);
for (expr, expected) in test_expressions {
let expr_plus_zero = Expression::add(vec![expr.clone(), zero.clone()]);
assert_eq!(
expr_plus_zero.simplify(),
expected.clone(),
"{} + 0 should equal {} (mathematically correct)",
expr,
expected
);
let zero_plus_expr = Expression::add(vec![zero.clone(), expr.clone()]);
assert_eq!(
zero_plus_expr.simplify(),
expected.clone(),
"0 + {} should equal {} (mathematically correct)",
expr,
expected
);
}
}
#[test]
fn test_multiplicative_identity_law() {
let test_expressions = vec![expr!(42), expr!(x)];
let one = expr!(1);
for expr in test_expressions {
let expr_times_one = Expression::mul(vec![expr.clone(), one.clone()]);
assert_eq!(
expr_times_one.simplify(),
expr.clone(),
"{} * 1 should equal {}",
expr,
expr
);
let one_times_expr = Expression::mul(vec![one.clone(), expr.clone()]);
assert_eq!(
one_times_expr.simplify(),
expr.clone(),
"1 * {} should equal {}",
expr,
expr
);
}
}
#[test]
fn test_multiplicative_zero_law() {
let test_expressions = vec![expr!(42), expr!(x), expr!(2 + y)];
let zero = expr!(0);
for expr in test_expressions {
let expr_times_zero = Expression::mul(vec![expr.clone(), zero.clone()]);
assert_eq!(
expr_times_zero.simplify(),
zero.clone(),
"{} * 0 should equal 0",
expr
);
let zero_times_expr = Expression::mul(vec![zero.clone(), expr.clone()]);
assert_eq!(
zero_times_expr.simplify(),
zero.clone(),
"0 * {} should equal 0",
expr
);
}
}
#[test]
fn test_power_identity_laws() {
let test_bases = vec![expr!(5), expr!(x)];
let zero = expr!(0);
let one = expr!(1);
for base in test_bases {
let base_to_zero = Expression::pow(base.clone(), zero.clone());
assert_eq!(
base_to_zero.simplify(),
one.clone(),
"{}^0 should equal 1",
base
);
let base_to_one = Expression::pow(base.clone(), one.clone());
assert_eq!(
base_to_one.simplify(),
base.clone(),
"{}^1 should equal {}",
base,
base
);
}
for n in [2, 3, 5, 10] {
let one_to_n = Expression::pow(one.clone(), Expression::integer(n));
assert_eq!(one_to_n.simplify(), one.clone(), "1^{} should equal 1", n);
}
for n in [1, 2, 3, 5] {
let zero_to_n = Expression::pow(zero.clone(), Expression::integer(n));
assert_eq!(zero_to_n.simplify(), zero.clone(), "0^{} should equal 0", n);
}
}
#[test]
fn test_distributive_property_verification() {
let test_cases = vec![
(2, 3, 4), (3, 1, 2), (-1, 5, 3), ];
for (a_val, b_val, c_val) in test_cases {
let a = Expression::integer(a_val);
let b = Expression::integer(b_val);
let c = Expression::integer(c_val);
let left =
Expression::mul(vec![a.clone(), Expression::add(vec![b.clone(), c.clone()])])
.simplify();
let right = Expression::add(vec![
Expression::mul(vec![a.clone(), b]),
Expression::mul(vec![a, c]),
])
.simplify();
assert_eq!(
left, right,
"Distributive property failed for a={}, b={}, c={}",
a_val, b_val, c_val
);
}
}
}
mod rational_arithmetic {
use super::*;
use num_bigint::BigInt;
use num_rational::BigRational;
#[test]
fn test_rational_addition_correctness() {
let one_half = Expression::number(Number::rational(BigRational::new(
BigInt::from(1),
BigInt::from(2),
)));
let one_third = Expression::number(Number::rational(BigRational::new(
BigInt::from(1),
BigInt::from(3),
)));
let expected = Expression::number(Number::rational(BigRational::new(
BigInt::from(5),
BigInt::from(6),
)));
let expr = Expression::add(vec![one_half, one_third]);
let result = expr.simplify();
assert_eq!(result, expected, "1/2 + 1/3 should equal 5/6");
}
#[test]
fn test_rational_reduction() {
let unreduced = Expression::number(Number::rational(BigRational::new(
BigInt::from(6),
BigInt::from(9),
)));
let reduced = Expression::number(Number::rational(BigRational::new(
BigInt::from(2),
BigInt::from(3),
)));
assert_eq!(unreduced.simplify(), reduced, "6/9 should reduce to 2/3");
}
#[test]
fn test_mixed_rational_integer_arithmetic() {
let test_cases = vec![
(1, 2, 1, 3, 2), (3, 4, 1, 7, 4), (2, 3, 2, 8, 3), ];
for (r_num, r_den, int_val, exp_num, exp_den) in test_cases {
let rational = Expression::number(Number::rational(BigRational::new(
BigInt::from(r_num),
BigInt::from(r_den),
)));
let integer = Expression::integer(int_val);
let expected = Expression::number(Number::rational(BigRational::new(
BigInt::from(exp_num),
BigInt::from(exp_den),
)));
let result = Expression::add(vec![rational, integer]).simplify();
assert_eq!(
result, expected,
"{}/{} + {} should equal {}/{}",
r_num, r_den, int_val, exp_num, exp_den
);
}
}
#[test]
fn test_rational_arithmetic_properties() {
let quarter = Expression::number(Number::rational(BigRational::new(
BigInt::from(1),
BigInt::from(4),
)));
let half = Expression::number(Number::rational(BigRational::new(
BigInt::from(1),
BigInt::from(2),
)));
let sum = Expression::add(vec![quarter.clone(), quarter.clone()]).simplify();
assert_eq!(sum, half, "1/4 + 1/4 should equal 1/2");
let product = Expression::mul(vec![half, Expression::integer(2)]).simplify();
assert_eq!(product, expr!(1), "1/2 * 2 should equal 1");
}
}
mod edge_cases {
use super::*;
#[test]
fn test_empty_and_single_operations() {
let single_add = Expression::add(vec![expr!(42)]);
assert_eq!(single_add.simplify(), expr!(42));
let single_mul = Expression::mul(vec![expr!(42)]);
assert_eq!(single_mul.simplify(), expr!(42));
}
#[test]
fn test_deeply_nested_expressions() {
let mut expr = expr!(1);
for _ in 0..4 {
expr = Expression::add(vec![expr!(1), expr]);
}
let result = expr.simplify();
assert_eq!(
result,
Expression::integer(5),
"Deeply nested addition should simplify to 5"
);
}
#[test]
fn test_mixed_positive_negative() {
let expr = Expression::add(vec![
Expression::integer(10),
Expression::integer(-3),
Expression::integer(7),
Expression::integer(-4),
]);
let result = expr.simplify();
assert_eq!(
result,
Expression::integer(10),
"10 + (-3) + 7 + (-4) should equal 10"
);
}
#[test]
fn test_zero_cancellation() {
let x = symbol!(x);
let var = Expression::symbol(x.clone());
let expr_with_zeros =
Expression::add(vec![expr!(0), var.clone(), expr!(0), expr!(5), expr!(0)]);
let expected = Expression::add(vec![var.clone(), Expression::integer(5)]);
let result = expr_with_zeros.simplify();
let expected_result = expected.simplify();
assert_eq!(
result, expected_result,
"Zeros should be eliminated in simplification"
);
}
}