use symplex::expr::ExprType;
use symplex::prelude::*;
#[test]
fn rootof_is_a_constant_not_unevaluated() {
let ctx = Context::new();
let x = ctx.symbol("x");
let roots = (&x.powi(5) - &x - 1).solve_or_empty(&x);
assert_eq!(roots.len(), 5);
for r in &roots {
assert!(format!("{r}").contains("RootOf"), "{r}");
assert!(!r.has_unevaluated(), "{r} is a complete algebraic value");
assert_ne!(r.expr_type(), ExprType::Unevaluated, "{r}");
assert_eq!(r.expr_type(), ExprType::Constant, "{r}");
assert!(r.free_symbols().is_empty(), "{r}");
}
}
#[test]
fn rootof_inside_expression_is_not_unevaluated() {
let ctx = Context::new();
let x = ctx.symbol("x");
let r = (&x.powi(5) - &x - 1).solve_or_empty(&x).remove(0);
let e = &r * 2 + 1;
assert!(!e.has_unevaluated());
assert_eq!(e.expr_type(), ExprType::Add);
let lim = x.sin().limit(&x, &ctx.int(0));
if lim.has_unevaluated() {
assert_eq!(lim.expr_type(), ExprType::Unevaluated);
}
let integ = x.exp().pow(&x.powi(2)).integrate(&x);
if integ.has_unevaluated() {
assert_eq!(integ.expr_type(), ExprType::Integral);
}
}
#[test]
fn abs_of_3_plus_4i_is_5() {
let ctx = Context::new();
let z = ctx.int(3) + ctx.int(4) * ctx.i_unit();
assert_eq!(z.abs().eval(), ctx.int(5));
assert_eq!(z.abs().simplify(), ctx.int(5));
assert_eq!(z.abs_squared().eval(), ctx.int(25));
}
#[test]
fn abs_of_pure_imaginary_units() {
let ctx = Context::new();
let i = ctx.i_unit();
assert_eq!(i.abs().eval(), ctx.int(1), "abs(i)");
assert_eq!((ctx.int(2) * &i).abs().eval(), ctx.int(2), "abs(2i)");
assert_eq!((ctx.int(-2) * &i).abs().eval(), ctx.int(2), "abs(-2i)");
assert_eq!((-&i).abs().eval(), ctx.int(1), "abs(-i)");
}
#[test]
fn abs_of_complex_constant_with_irrational_modulus() {
let ctx = Context::new();
let i = ctx.i_unit();
assert_eq!(
(ctx.int(1) + &i).abs().eval(),
ctx.int(2).sqrt(),
"abs(1+i)"
);
assert_eq!(
(ctx.rational(1, 2) + ctx.rational(1, 3) * &i).abs().eval(),
ctx.rational(1, 6) * ctx.int(13).sqrt(),
"abs(1/2 + i/3)"
);
}
#[test]
fn abs_of_complex_constant_with_radical_parts() {
let ctx = Context::new();
let i = ctx.i_unit();
assert_eq!(
(ctx.int(1) + ctx.int(3).sqrt() * &i).abs().eval(),
ctx.int(2)
);
assert_eq!((ctx.int(1) + &i).powi(2).abs().eval(), ctx.int(2));
let z = (ctx.e() + ctx.pi() * &i).abs().eval();
let want = (2.0f64.exp() + std::f64::consts::PI.powi(2)).sqrt();
assert!(!format!("{z}").contains("abs"), "{z}");
assert!((z.eval_f64().unwrap() - want).abs() < 1e-14, "{z}");
}
#[test]
fn abs_fold_leaves_symbolic_and_real_arguments_alone() {
let ctx = Context::new();
let i = ctx.i_unit();
let x = ctx.symbol("x");
let z = (&x + &i).abs();
assert_eq!(z.eval(), z, "abs(x + i) must stay symbolic");
assert_eq!(format!("{}", ctx.pi().abs().eval()), "abs(pi)");
assert_eq!(format!("{}", i.exp().abs().eval()), "abs(exp(I))");
}
#[test]
fn rational_with_zero_denominator_is_complex_infinity() {
let ctx = Context::new();
assert_eq!(ctx.rational(1, 0), ctx.complex_infinity());
assert_eq!(ctx.rational(-7, 0), ctx.complex_infinity());
assert_eq!(ctx.rational(i64::MAX, 0), ctx.complex_infinity());
assert_eq!(ctx.rational(5, 0), ctx.int(5) / ctx.int(0));
assert_eq!(
format!("{}", ctx.rational(1, 0)),
format!("{}", ctx.complex_infinity())
);
}
#[test]
fn rational_zero_over_zero_is_nan() {
let ctx = Context::new();
assert_eq!(ctx.rational(0, 0), ctx.nan());
assert_eq!(ctx.rational(0, 0), ctx.int(0) / ctx.int(0));
}
#[test]
fn rational_nonzero_denominator_unchanged() {
let ctx = Context::new();
assert_eq!(format!("{}", ctx.rational(6, -4)), "-3/2");
assert_eq!(ctx.rational(4, 2), ctx.int(2));
assert_eq!(ctx.rational(0, 5), ctx.int(0));
}