use num_bigint::{BigUint, ToBigUint};
use num_traits::One;
use num_integer::Integer;
use rma::chakravala::chakravala;
#[cfg(test)]
mod prop {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn solves_pell_equation(d in 2u32..1000) {
let sqrt = (d as f64).sqrt() as u32;
prop_assume!(sqrt * sqrt != d);
let d_big = d.to_biguint().unwrap();
let (x, y) = chakravala(&d_big).expect("Expected a solution");
let lhs = &x * &x - &d_big * &y * &y;
prop_assert_eq!(lhs, BigUint::one());
prop_assert_eq!(x.gcd(&y), BigUint::one());
}
}
}
#[test]
fn fundamental_solution_small_d() {
for d in 2u64..=50 {
let sqrt = (d as f64).sqrt() as u64;
if sqrt * sqrt == d { continue; }
let d_big = d.to_biguint().unwrap();
let (x_found, y_found) = chakravala(&d_big).expect("Solution");
let (x_brute, y_brute) = brute_force_pell(d);
assert_eq!(x_found, x_brute.to_biguint().unwrap());
assert_eq!(y_found, y_brute.to_biguint().unwrap());
}
}
#[test]
fn perfect_square_returns_none() {
for s in 1u64..=31 {
let d = s * s;
let d_big = d.to_biguint().unwrap();
assert!(chakravala(&d_big).is_none(), "d = {} should yield None", d);
}
}
fn brute_force_pell(d: u64) -> (u64, u64) {
for y in 1u64.. {
let rhs = d * y * y + 1;
let x = (rhs as f64).sqrt() as u64;
if x * x == rhs { return (x, y); }
}
unreachable!("No solution found for d={}", d)
}