use symplex::prelude::*;
#[test]
fn is_even_for_known_even() {
let ctx = Context::new();
let x = ctx.symbol("x").assume(Assumption::Even);
assert_eq!(x.is_even(), Some(true));
assert_eq!(x.is_odd(), Some(false));
}
#[test]
fn is_odd_for_known_odd() {
let ctx = Context::new();
let x = ctx.symbol("x").assume(Assumption::Odd);
assert_eq!(x.is_odd(), Some(true));
assert_eq!(x.is_even(), Some(false));
}
#[test]
fn is_even_odd_for_integer_literals() {
let ctx = Context::new();
assert_eq!(ctx.int(4).is_even(), Some(true));
assert_eq!(ctx.int(4).is_odd(), Some(false));
assert_eq!(ctx.int(7).is_even(), Some(false));
assert_eq!(ctx.int(7).is_odd(), Some(true));
assert_eq!(ctx.int(0).is_even(), Some(true));
assert_eq!(ctx.int(0).is_odd(), Some(false));
}
#[test]
fn is_prime_for_literal() {
let ctx = Context::new();
assert_eq!(ctx.int(7).is_prime(), Some(true));
assert_eq!(ctx.int(4).is_prime(), Some(false));
assert_eq!(ctx.int(2).is_prime(), Some(true));
assert_eq!(ctx.int(1).is_prime(), None);
}
#[test]
fn is_composite_for_literal() {
let ctx = Context::new();
assert_eq!(ctx.int(4).is_composite(), Some(true));
assert_eq!(ctx.int(9).is_composite(), Some(true));
assert_eq!(ctx.int(7).is_composite(), Some(false));
}
#[test]
fn is_transcendental_for_pi() {
let ctx = Context::new();
assert_eq!(ctx.pi().is_transcendental(), Some(true));
assert_eq!(ctx.pi().is_algebraic(), Some(false));
}
#[test]
fn is_irrational_for_pi() {
let ctx = Context::new();
assert_eq!(ctx.pi().is_irrational(), Some(true));
assert_eq!(ctx.pi().is_rational(), Some(false));
}
#[test]
fn is_algebraic_for_rational() {
let ctx = Context::new();
assert_eq!(ctx.rational(1, 3).is_algebraic(), Some(true));
assert_eq!(ctx.rational(1, 3).is_transcendental(), Some(false));
}
#[test]
fn is_algebraic_for_integer() {
let ctx = Context::new();
assert_eq!(ctx.int(5).is_algebraic(), Some(true));
assert_eq!(ctx.int(5).is_irrational(), Some(false));
}
#[test]
fn is_hermitian_for_real_symbol() {
let ctx = Context::new();
let x = ctx.symbol("x").assume(Assumption::Real);
assert_eq!(x.is_hermitian(), Some(true));
}
#[test]
fn is_even_unknown_for_bare_symbol() {
let ctx = Context::new();
let x = ctx.symbol("x");
assert_eq!(x.is_even(), None);
assert_eq!(x.is_odd(), None);
assert_eq!(x.is_prime(), None);
assert_eq!(x.is_composite(), None);
}
#[test]
fn is_hermitian_for_assumed_hermitian() {
let ctx = Context::new();
let x = ctx.symbol("x").assume(Assumption::Hermitian);
assert_eq!(x.is_hermitian(), Some(true));
}
#[test]
fn conjugate_of_real_is_itself() {
let ctx = Context::new();
let x = ctx.symbol("x").assume(Assumption::Real);
let conj = x.conjugate();
let s = format!("{}", conj.simplify());
assert_eq!(s, "x", "conjugate of real should be itself, got: {s}");
}
#[test]
fn conjugate_of_pure_imaginary() {
let ctx = Context::new();
let i = ctx.i_unit();
let three = ctx.int(3);
let z = &three * &i;
let conj = z.conjugate();
let s = format!("{}", conj.simplify());
assert!(
s == "-3*I" || s == "-3I" || s == "-(3*I)" || s == "-3·I",
"conjugate(3i) should be -3i, got: {s}"
);
}
#[test]
fn conjugate_of_complex_literal() {
let ctx = Context::new();
let i = ctx.i_unit();
let three = ctx.int(3);
let four = ctx.int(4);
let z = &three + &(&four * &i);
let conj = z.conjugate();
let s = format!("{}", conj.simplify());
assert!(
s.contains("3") && (s.contains("-4") || s.contains("- 4")),
"conjugate(3+4i) should be 3-4i, got: {s}"
);
}
#[test]
fn arg_of_positive_real() {
let ctx = Context::new();
let one = ctx.int(1);
let a = one.arg().eval();
let s = format!("{a}");
assert!(
s == "0" || s == "atan2(0, 1)",
"arg(1) should be 0, got: {s}"
);
}
#[test]
fn arg_of_one_plus_i() {
let ctx = Context::new();
let one = ctx.int(1);
let i = ctx.i_unit();
let z = &one + &i;
let a = z.arg().eval();
let s = format!("{a}");
assert!(
s.contains("pi/4") || s.contains("π/4") || s.contains("1/4*pi") || s.contains("atan"),
"arg(1+i) should be pi/4, got: {s}"
);
}
#[test]
fn arg_first_quadrant() {
let ctx = Context::new();
let z = &ctx.int(1) + &ctx.i_unit();
let a = z.arg().eval();
let v = a.eval_f64().expect("evalf should succeed for arg(1+i)");
assert!((v - std::f64::consts::FRAC_PI_4).abs() < 1e-10);
}
#[test]
fn arg_second_quadrant() {
let ctx = Context::new();
let z = &ctx.int(-1) + &ctx.i_unit();
let a = z.arg().eval();
let v = a.eval_f64().expect("evalf should succeed for arg(-1+i)");
assert!(
(v - 3.0 * std::f64::consts::FRAC_PI_4).abs() < 1e-10,
"arg(-1+i) should be 3π/4, got {v}"
);
}
#[test]
fn arg_negative_real() {
let ctx = Context::new();
let z = ctx.int(-1);
let a = z.arg().eval();
let v = a.eval_f64().expect("evalf should succeed for arg(-1)");
assert!(
(v - std::f64::consts::PI).abs() < 1e-10,
"arg(-1) should be π, got {v}"
);
}
#[test]
fn atan2_basic() {
let ctx = Context::new();
let one = ctx.int(1);
let result = one.atan2(&one).eval();
let v = result
.eval_f64()
.expect("evalf should succeed for atan2(1,1)");
assert!((v - std::f64::consts::FRAC_PI_4).abs() < 1e-10);
}
#[test]
fn atan2_on_axes() {
let ctx = Context::new();
let zero = ctx.int(0);
let one = ctx.int(1);
let neg_one = ctx.int(-1);
assert_eq!(format!("{}", zero.atan2(&one).eval()), "0");
let r = one.atan2(&zero).eval();
let v = r.eval_f64().expect("evalf should succeed for atan2(1,0)");
assert!(
(v - std::f64::consts::FRAC_PI_2).abs() < 1e-10,
"atan2(1,0) should be π/2, got {v}"
);
let r = zero.atan2(&neg_one).eval();
let v = r.eval_f64().expect("evalf should succeed for atan2(0,-1)");
assert!(
(v - std::f64::consts::PI).abs() < 1e-10,
"atan2(0,-1) should be π, got {v}"
);
}