use symplex::prelude::*;
fn check(expr: &Ex, expected: &str) {
let s = format!("{expr}");
assert_eq!(s, expected, "expected '{expected}', got '{s}'");
}
#[test]
fn factorial2_zero() {
let ctx = Context::new();
check(&ctx.int(0).factorial2().eval(), "1");
}
#[test]
fn factorial2_one() {
let ctx = Context::new();
check(&ctx.int(1).factorial2().eval(), "1");
}
#[test]
fn factorial2_neg_one() {
let ctx = Context::new();
check(&ctx.int(-1).factorial2().eval(), "1");
}
#[test]
fn factorial2_small_odd() {
let ctx = Context::new();
check(&ctx.int(5).factorial2().eval(), "15");
}
#[test]
fn factorial2_small_even() {
let ctx = Context::new();
check(&ctx.int(6).factorial2().eval(), "48");
}
#[test]
fn factorial2_ten() {
let ctx = Context::new();
check(&ctx.int(10).factorial2().eval(), "3840");
}
#[test]
fn subfactorial_known_values() {
let ctx = Context::new();
check(&ctx.int(0).subfactorial().eval(), "1");
check(&ctx.int(1).subfactorial().eval(), "0");
check(&ctx.int(2).subfactorial().eval(), "1");
check(&ctx.int(3).subfactorial().eval(), "2");
check(&ctx.int(4).subfactorial().eval(), "9");
check(&ctx.int(5).subfactorial().eval(), "44");
}
#[test]
fn rising_factorial_known_values() {
let ctx = Context::new();
let n0 = ctx.int(0);
let n3 = ctx.int(3);
let n4 = ctx.int(4);
let n5 = ctx.int(5);
check(&n5.rising_factorial(&n0).eval(), "1");
check(&ctx.int(1).rising_factorial(&n4).eval(), "24");
check(&n3.rising_factorial(&n3).eval(), "60");
check(&n5.rising_factorial(&n3).eval(), "210");
}
#[test]
fn falling_factorial_known_values() {
let ctx = Context::new();
let n0 = ctx.int(0);
let n3 = ctx.int(3);
let n5 = ctx.int(5);
check(&n5.falling_factorial(&n0).eval(), "1");
check(&n5.falling_factorial(&n3).eval(), "60");
check(&n3.falling_factorial(&n3).eval(), "6");
check(&ctx.int(7).falling_factorial(&ctx.int(4)).eval(), "840");
}
#[test]
fn fibonacci_known_values() {
let ctx = Context::new();
check(&ctx.int(0).fibonacci().eval(), "0");
check(&ctx.int(1).fibonacci().eval(), "1");
check(&ctx.int(2).fibonacci().eval(), "1");
check(&ctx.int(3).fibonacci().eval(), "2");
check(&ctx.int(4).fibonacci().eval(), "3");
check(&ctx.int(5).fibonacci().eval(), "5");
check(&ctx.int(10).fibonacci().eval(), "55");
check(&ctx.int(20).fibonacci().eval(), "6765");
}
#[test]
fn lucas_known_values() {
let ctx = Context::new();
check(&ctx.int(0).lucas().eval(), "2");
check(&ctx.int(1).lucas().eval(), "1");
check(&ctx.int(2).lucas().eval(), "3");
check(&ctx.int(3).lucas().eval(), "4");
check(&ctx.int(4).lucas().eval(), "7");
check(&ctx.int(5).lucas().eval(), "11");
check(&ctx.int(10).lucas().eval(), "123");
}
#[test]
fn bernoulli_known_values() {
let ctx = Context::new();
check(&ctx.int(0).bernoulli_number().eval(), "1");
check(&ctx.int(1).bernoulli_number().eval(), "-1/2");
check(&ctx.int(2).bernoulli_number().eval(), "1/6");
check(&ctx.int(3).bernoulli_number().eval(), "0");
check(&ctx.int(4).bernoulli_number().eval(), "-1/30");
check(&ctx.int(6).bernoulli_number().eval(), "1/42");
check(&ctx.int(8).bernoulli_number().eval(), "-1/30");
}
#[test]
fn harmonic_known_values() {
let ctx = Context::new();
check(&ctx.int(0).harmonic().eval(), "0");
check(&ctx.int(1).harmonic().eval(), "1");
check(&ctx.int(2).harmonic().eval(), "3/2");
check(&ctx.int(3).harmonic().eval(), "11/6");
check(&ctx.int(4).harmonic().eval(), "25/12");
}
#[test]
fn catalan_known_values() {
let ctx = Context::new();
check(&ctx.int(0).catalan_number().eval(), "1");
check(&ctx.int(1).catalan_number().eval(), "1");
check(&ctx.int(2).catalan_number().eval(), "2");
check(&ctx.int(3).catalan_number().eval(), "5");
check(&ctx.int(4).catalan_number().eval(), "14");
check(&ctx.int(5).catalan_number().eval(), "42");
check(&ctx.int(10).catalan_number().eval(), "16796");
}
#[test]
fn bell_known_values() {
let ctx = Context::new();
check(&ctx.int(0).bell().eval(), "1");
check(&ctx.int(1).bell().eval(), "1");
check(&ctx.int(2).bell().eval(), "2");
check(&ctx.int(3).bell().eval(), "5");
check(&ctx.int(4).bell().eval(), "15");
check(&ctx.int(5).bell().eval(), "52");
check(&ctx.int(6).bell().eval(), "203");
}
#[test]
fn euler_number_known_values() {
let ctx = Context::new();
check(&ctx.int(0).euler_number().eval(), "1");
check(&ctx.int(1).euler_number().eval(), "0");
check(&ctx.int(2).euler_number().eval(), "-1");
check(&ctx.int(3).euler_number().eval(), "0");
check(&ctx.int(4).euler_number().eval(), "5");
check(&ctx.int(6).euler_number().eval(), "-61");
check(&ctx.int(8).euler_number().eval(), "1385");
}
#[test]
fn combinatorial_symbolic_unchanged() {
let ctx = Context::new();
let x = ctx.symbol("x");
let fib = x.fibonacci().eval();
let s = format!("{fib}");
assert!(
s.contains("fibonacci"),
"expected unevaluated fibonacci, got: {s}"
);
let cat = x.catalan_number().eval();
let s = format!("{cat}");
assert!(
s.contains("catalan"),
"expected unevaluated catalan, got: {s}"
);
}
#[test]
fn rising_factorial_from_one_is_factorial() {
let ctx = Context::new();
let one = ctx.int(1);
for n in 0..=7 {
let rf = one.rising_factorial(&ctx.int(n)).eval();
let f = ctx.int(n).factorial().eval();
assert_eq!(format!("{rf}"), format!("{f}"), "(1)_{n} should equal {n}!");
}
}