use std::time::Instant;
use symplex::prelude::*;
fn assert_same(label: &str, got: &Ex, want: &Ex) {
assert_eq!(
(got - want).expand(),
got.context().int(0),
"{label}: got {got}, want {want}"
);
}
#[test]
fn gcdex_matches_sympy_on_the_documentation_example() {
let ctx = Context::new();
let x = ctx.symbol("x");
let f = x.powi(4) - 2 * x.powi(3) - 6 * x.powi(2) + 12 * &x + 15;
let g = x.powi(3) + x.powi(2) - 4 * &x - 4;
let e = f.poly_gcdex(&g, &x).unwrap();
assert_same("gcd", &e.gcd, &(&x + 1));
assert_same("x", &e.x, &(ctx.rational(3, 5) - &x / 5));
assert_same("y", &e.y, &(x.powi(2) / 5 - ctx.rational(6, 5) * &x + 2));
}
#[test]
fn gcdex_with_rational_coefficients_and_lower_degree_first() {
let ctx = Context::new();
let x = ctx.symbol("x");
let f = x.powi(2) / 2 - ctx.rational(1, 2);
let g = ctx.rational(2, 3) * x.powi(3) + ctx.rational(2, 3);
let e = f.poly_gcdex(&g, &x).unwrap();
assert_same("gcd", &e.gcd, &(&x + 1));
assert_same("x", &e.x, &(-2 * &x));
assert_same("y", &e.y, &ctx.rational(3, 2));
}
#[test]
fn gcdex_of_forty_digit_coefficients_is_fast_and_exact() {
let ctx = Context::new();
let x = ctx.symbol("x");
let big = |k: i64| ctx.int(10).pow(&ctx.int(40)) * k + (k * k - 7);
let common = x.powi(3) - 2 * &x + 5;
let a = (0..9).fold(ctx.int(0), |acc, k| acc + big(k + 1) * x.powi(k));
let b = (0..10).fold(ctx.int(0), |acc, k| acc + big(3 * k - 11) * x.powi(k));
let (a, b) = ((a * &common).expand(), (b * &common).expand());
let started = Instant::now();
let e = a.poly_gcdex(&b, &x).unwrap();
let elapsed = started.elapsed();
let bezout = (&e.x * &a + &e.y * &b).expand();
assert_same("bezout", &bezout, &e.gcd);
assert_eq!(
e.gcd.poly_rem(&common, &x).unwrap(),
ctx.int(0),
"{}",
e.gcd
);
assert!(elapsed.as_millis() < 1500, "gcdex took {elapsed:?}");
}