Skip to main content

oxiz_math/rational/
mod.rs

1//! Arbitrary precision rational arithmetic utilities.
2//!
3//! This module provides utility functions for working with rational numbers
4//! beyond what the `num_rational` crate offers.
5
6#[allow(unused_imports)]
7use crate::prelude::*;
8use core::cmp::Ordering;
9use num_bigint::BigInt;
10use num_integer::Integer;
11use num_rational::BigRational;
12use num_traits::{One, Signed, Zero};
13
14/// Compare two rationals and return their ordering.
15#[inline]
16pub fn cmp(a: &BigRational, b: &BigRational) -> Ordering {
17    a.cmp(b)
18}
19
20/// Compute the absolute value of a rational.
21#[inline]
22pub fn abs(r: &BigRational) -> BigRational {
23    r.abs()
24}
25
26/// Compute the floor of a rational (greatest integer <= r).
27pub fn floor(r: &BigRational) -> BigInt {
28    if r.is_integer() {
29        r.numer().clone()
30    } else if r.is_positive() {
31        r.numer() / r.denom()
32    } else {
33        // For negative non-integers, subtract 1
34        (r.numer() / r.denom()) - BigInt::one()
35    }
36}
37
38/// Compute the ceiling of a rational (smallest integer >= r).
39pub fn ceil(r: &BigRational) -> BigInt {
40    if r.is_integer() {
41        r.numer().clone()
42    } else if r.is_positive() {
43        // For positive non-integers, add 1
44        (r.numer() / r.denom()) + BigInt::one()
45    } else {
46        r.numer() / r.denom()
47    }
48}
49
50/// Round a rational to the nearest integer (ties go to even).
51pub fn round(r: &BigRational) -> BigInt {
52    let floor_val = floor(r);
53    let frac = r - BigRational::from_integer(floor_val.clone());
54
55    let half = BigRational::new(BigInt::one(), BigInt::from(2));
56
57    if frac < half {
58        floor_val
59    } else if frac > half {
60        floor_val + BigInt::one()
61    } else {
62        // Tie: round to even
63        if floor_val.is_even() {
64            floor_val
65        } else {
66            floor_val + BigInt::one()
67        }
68    }
69}
70
71/// Compute the fractional part of a rational (r - floor(r)).
72pub fn frac(r: &BigRational) -> BigRational {
73    r - BigRational::from_integer(floor(r))
74}
75
76/// Check if a rational is an integer.
77#[inline]
78pub fn is_integer(r: &BigRational) -> bool {
79    r.is_integer()
80}
81
82/// Compute the greatest common divisor of two rationals.
83/// Returns the largest positive rational that divides both a and b.
84pub fn gcd(a: &BigRational, b: &BigRational) -> BigRational {
85    if a.is_zero() {
86        return b.abs();
87    }
88    if b.is_zero() {
89        return a.abs();
90    }
91
92    // GCD of rationals: gcd(a/b, c/d) = gcd(a*d, b*c) / (b*d)
93    // But we can simplify using the integer GCD
94    let gcd_num = gcd_bigint(a.numer().clone(), b.numer().clone());
95    let lcm_denom = lcm_bigint(a.denom().clone(), b.denom().clone());
96
97    BigRational::new(gcd_num, lcm_denom)
98}
99
100/// Compute the least common multiple of two rationals.
101pub fn lcm(a: &BigRational, b: &BigRational) -> BigRational {
102    if a.is_zero() || b.is_zero() {
103        return BigRational::zero();
104    }
105
106    let g = gcd(a, b);
107    (a * b / g).abs()
108}
109
110/// Compute GCD of two BigInts using Euclidean algorithm.
111pub fn gcd_bigint(mut a: BigInt, mut b: BigInt) -> BigInt {
112    while !b.is_zero() {
113        let t = &a % &b;
114        a = b;
115        b = t;
116    }
117    a.abs()
118}
119
120/// Extended Euclidean algorithm for BigInts.
121/// Returns (gcd, x, y) such that gcd = a*x + b*y (Bézout's identity).
122///
123/// This is useful for:
124/// - Solving linear Diophantine equations
125/// - Computing modular inverses
126/// - Finding rational solutions to systems
127///
128/// # Examples
129/// ```
130/// use num_bigint::BigInt;
131/// use oxiz_math::rational::gcd_extended;
132///
133/// let a = BigInt::from(240);
134/// let b = BigInt::from(46);
135/// let (gcd, x, y) = gcd_extended(a.clone(), b.clone());
136/// assert_eq!(gcd, BigInt::from(2));
137/// assert_eq!(&a * &x + &b * &y, gcd);
138/// ```
139pub fn gcd_extended(a: BigInt, b: BigInt) -> (BigInt, BigInt, BigInt) {
140    if b.is_zero() {
141        return (
142            a.abs(),
143            if a >= BigInt::zero() {
144                BigInt::one()
145            } else {
146                -BigInt::one()
147            },
148            BigInt::zero(),
149        );
150    }
151
152    let (mut old_r, mut r) = (a, b);
153    let (mut old_s, mut s) = (BigInt::one(), BigInt::zero());
154    let (mut old_t, mut t) = (BigInt::zero(), BigInt::one());
155
156    while !r.is_zero() {
157        let quotient = &old_r / &r;
158        let new_r = &old_r - &quotient * &r;
159        old_r = r;
160        r = new_r;
161
162        let new_s = &old_s - &quotient * &s;
163        old_s = s;
164        s = new_s;
165
166        let new_t = &old_t - &quotient * &t;
167        old_t = t;
168        t = new_t;
169    }
170
171    (old_r, old_s, old_t)
172}
173
174/// Compute LCM of two BigInts.
175pub fn lcm_bigint(a: BigInt, b: BigInt) -> BigInt {
176    if a.is_zero() || b.is_zero() {
177        return BigInt::zero();
178    }
179    let g = gcd_bigint(a.clone(), b.clone());
180    (a * b / g).abs()
181}
182
183/// Compute the power of a rational number with integer exponent.
184pub fn pow_int(base: &BigRational, exp: i32) -> BigRational {
185    if exp == 0 {
186        return BigRational::one();
187    }
188    if exp > 0 {
189        pow_uint(base, exp as u32)
190    } else {
191        let p = pow_uint(base, (-exp) as u32);
192        BigRational::one() / p
193    }
194}
195
196/// Compute the power of a rational number with unsigned integer exponent.
197pub fn pow_uint(base: &BigRational, exp: u32) -> BigRational {
198    if exp == 0 {
199        return BigRational::one();
200    }
201    if exp == 1 {
202        return base.clone();
203    }
204
205    // Binary exponentiation
206    let mut result = BigRational::one();
207    let mut b = base.clone();
208    let mut e = exp;
209
210    while e > 0 {
211        if e & 1 == 1 {
212            result = &result * &b;
213        }
214        b = &b * &b;
215        e >>= 1;
216    }
217
218    result
219}
220
221/// Normalize a rational to have positive denominator.
222pub fn normalize(r: &BigRational) -> BigRational {
223    if r.denom().is_negative() {
224        BigRational::new(-r.numer(), -r.denom())
225    } else {
226        r.clone()
227    }
228}
229
230/// Compare two rationals with a tolerance.
231pub fn approx_eq(a: &BigRational, b: &BigRational, epsilon: &BigRational) -> bool {
232    (a - b).abs() <= *epsilon
233}
234
235/// Compute the sign of a rational: -1, 0, or 1.
236pub fn sign(r: &BigRational) -> i8 {
237    if r.is_positive() {
238        1
239    } else if r.is_negative() {
240        -1
241    } else {
242        0
243    }
244}
245
246/// Clamp a rational to a range [min, max].
247pub fn clamp(val: &BigRational, min: &BigRational, max: &BigRational) -> BigRational {
248    if val < min {
249        min.clone()
250    } else if val > max {
251        max.clone()
252    } else {
253        val.clone()
254    }
255}
256
257/// Compute the minimum of two rationals.
258#[inline]
259pub fn min(a: &BigRational, b: &BigRational) -> BigRational {
260    if a < b { a.clone() } else { b.clone() }
261}
262
263/// Compute the maximum of two rationals.
264#[inline]
265pub fn max(a: &BigRational, b: &BigRational) -> BigRational {
266    if a > b { a.clone() } else { b.clone() }
267}
268
269/// Create a rational from a numerator and denominator.
270#[inline]
271pub fn from_integers(num: i64, den: i64) -> BigRational {
272    BigRational::new(BigInt::from(num), BigInt::from(den))
273}
274
275/// Create a rational from an integer.
276#[inline]
277pub fn from_integer(n: i64) -> BigRational {
278    BigRational::from_integer(BigInt::from(n))
279}
280
281/// Get the numerator of a rational as a reference.
282#[inline]
283pub fn numer(r: &BigRational) -> &BigInt {
284    r.numer()
285}
286
287/// Get the denominator of a rational as a reference.
288#[inline]
289pub fn denom(r: &BigRational) -> &BigInt {
290    r.denom()
291}
292
293/// Convert a rational to f64 (may lose precision).
294pub fn to_f64(r: &BigRational) -> f64 {
295    if r.denom().is_one() {
296        r.numer().to_string().parse().unwrap_or(f64::NAN)
297    } else {
298        let num_f64: f64 = r.numer().to_string().parse().unwrap_or(f64::NAN);
299        let den_f64: f64 = r.denom().to_string().parse().unwrap_or(f64::NAN);
300        num_f64 / den_f64
301    }
302}
303
304/// Compute the mediant of two rationals: (a.num + b.num) / (a.den + b.den).
305/// This is used in continued fraction approximations.
306pub fn mediant(a: &BigRational, b: &BigRational) -> BigRational {
307    let num = a.numer() + b.numer();
308    let den = a.denom() + b.denom();
309    BigRational::new(num, den)
310}
311
312/// Compute the continued fraction representation of a rational number.
313/// Returns a vector of coefficients [a0, a1, a2, ...] such that:
314/// r = a0 + 1/(a1 + 1/(a2 + ...))
315///
316/// # Examples
317/// ```
318/// use num_bigint::BigInt;
319/// use num_rational::BigRational;
320/// use oxiz_math::rational::continued_fraction;
321///
322/// let r = BigRational::new(BigInt::from(22), BigInt::from(7)); // π ≈ 22/7
323/// let cf = continued_fraction(&r);
324/// assert_eq!(cf, vec![BigInt::from(3), BigInt::from(7)]);
325/// ```
326pub fn continued_fraction(r: &BigRational) -> Vec<BigInt> {
327    let mut result = Vec::new();
328    let mut current = r.clone();
329
330    while !current.is_integer() {
331        let int_part = floor(&current);
332        result.push(int_part.clone());
333        current = BigRational::one() / (current - BigRational::from_integer(int_part));
334    }
335
336    // Add the final integer part
337    result.push(current.numer().clone());
338    result
339}
340
341/// Reconstruct a rational from its continued fraction representation.
342/// Takes coefficients [a0, a1, a2, ...] and returns the rational number.
343///
344/// # Examples
345/// ```
346/// use num_bigint::BigInt;
347/// use num_rational::BigRational;
348/// use oxiz_math::rational::{continued_fraction, from_continued_fraction};
349///
350/// let r = BigRational::new(BigInt::from(22), BigInt::from(7));
351/// let cf = continued_fraction(&r);
352/// let reconstructed = from_continued_fraction(&cf);
353/// assert_eq!(r, reconstructed);
354/// ```
355pub fn from_continued_fraction(coeffs: &[BigInt]) -> BigRational {
356    if coeffs.is_empty() {
357        return BigRational::zero();
358    }
359
360    if coeffs.len() == 1 {
361        return BigRational::from_integer(coeffs[0].clone());
362    }
363
364    // Start from the end and work backwards
365    let mut result = BigRational::from_integer(coeffs[coeffs.len() - 1].clone());
366
367    for i in (0..coeffs.len() - 1).rev() {
368        result = BigRational::from_integer(coeffs[i].clone()) + BigRational::one() / result;
369    }
370
371    result
372}
373
374/// Compute the convergents (partial sums) of a continued fraction.
375/// Returns a vector of rationals that increasingly approximate the target.
376///
377/// Convergents provide the best rational approximations with denominators
378/// up to a given size, useful for interval refinement in algebraic number solving.
379///
380/// # Examples
381/// ```
382/// use num_bigint::BigInt;
383/// use num_rational::BigRational;
384/// use oxiz_math::rational::{continued_fraction, convergents};
385///
386/// let r = BigRational::new(BigInt::from(22), BigInt::from(7));
387/// let cf = continued_fraction(&r);
388/// let convs = convergents(&cf);
389/// // First convergent is 3/1, second is 22/7
390/// assert_eq!(convs[0], BigRational::new(BigInt::from(3), BigInt::from(1)));
391/// assert_eq!(convs[1], BigRational::new(BigInt::from(22), BigInt::from(7)));
392/// ```
393pub fn convergents(coeffs: &[BigInt]) -> Vec<BigRational> {
394    if coeffs.is_empty() {
395        return vec![];
396    }
397
398    let mut result = Vec::with_capacity(coeffs.len());
399
400    // Build convergents using the recurrence relation:
401    // p_n = a_n * p_{n-1} + p_{n-2}
402    // q_n = a_n * q_{n-1} + q_{n-2}
403    let mut p_prev2 = BigInt::one();
404    let mut p_prev1 = coeffs[0].clone();
405    let mut q_prev2 = BigInt::zero();
406    let mut q_prev1 = BigInt::one();
407
408    result.push(BigRational::from_integer(coeffs[0].clone()));
409
410    for coeff in coeffs.iter().skip(1) {
411        let p = coeff * &p_prev1 + &p_prev2;
412        let q = coeff * &q_prev1 + &q_prev2;
413
414        result.push(BigRational::new(p.clone(), q.clone()));
415
416        p_prev2 = p_prev1;
417        p_prev1 = p;
418        q_prev2 = q_prev1;
419        q_prev1 = q;
420    }
421
422    result
423}
424
425/// Find the best rational approximation to a number within a given tolerance.
426/// Uses continued fractions to find the simplest fraction within epsilon of the target.
427///
428/// # Examples
429/// ```
430/// use num_bigint::BigInt;
431/// use num_rational::BigRational;
432/// use oxiz_math::rational::best_rational_approximation;
433///
434/// let pi_approx = BigRational::new(BigInt::from(31416), BigInt::from(10000));
435/// let epsilon = BigRational::new(BigInt::from(1), BigInt::from(1000));
436/// let approx = best_rational_approximation(&pi_approx, &epsilon);
437/// // Should give 22/7 or 355/113 depending on tolerance
438/// ```
439pub fn best_rational_approximation(target: &BigRational, epsilon: &BigRational) -> BigRational {
440    let cf = continued_fraction(target);
441    let convs = convergents(&cf);
442
443    // Find the first convergent within epsilon
444    for conv in convs {
445        if (target - &conv).abs() <= *epsilon {
446            return conv;
447        }
448    }
449
450    // Fallback to the target itself
451    target.clone()
452}
453
454/// Modular exponentiation: compute (base^exp) mod m efficiently.
455/// Uses binary exponentiation to avoid overflow.
456///
457/// # Examples
458/// ```
459/// use num_bigint::BigInt;
460/// use oxiz_math::rational::mod_pow;
461///
462/// let base = BigInt::from(2);
463/// let exp = BigInt::from(10);
464/// let m = BigInt::from(1000);
465/// let result = mod_pow(&base, &exp, &m);
466/// assert_eq!(result, BigInt::from(24)); // 2^10 mod 1000 = 1024 mod 1000 = 24
467/// ```
468pub fn mod_pow(base: &BigInt, exp: &BigInt, m: &BigInt) -> BigInt {
469    if m.is_one() {
470        return BigInt::zero();
471    }
472
473    let mut result = BigInt::one();
474    let mut base = base % m;
475    let mut exp = exp.clone();
476
477    while exp > BigInt::zero() {
478        if (&exp % BigInt::from(2)).is_one() {
479            result = (result * &base) % m;
480        }
481        exp >>= 1;
482        base = (&base * &base) % m;
483    }
484
485    result
486}
487
488/// Compute the modular multiplicative inverse of a modulo m.
489/// Returns Some(x) where (a * x) ≡ 1 (mod m), or None if no inverse exists.
490///
491/// The inverse exists if and only if gcd(a, m) = 1.
492///
493/// # Examples
494/// ```
495/// use num_bigint::BigInt;
496/// use oxiz_math::rational::mod_inverse;
497///
498/// let a = BigInt::from(3);
499/// let m = BigInt::from(7);
500/// let inv = mod_inverse(&a, &m).unwrap();
501/// assert_eq!((&a * &inv) % &m, BigInt::from(1));
502/// ```
503pub fn mod_inverse(a: &BigInt, m: &BigInt) -> Option<BigInt> {
504    let (gcd, x, _) = gcd_extended(a.clone(), m.clone());
505
506    if !gcd.is_one() {
507        return None; // No inverse exists
508    }
509
510    // Ensure the result is positive
511    let inv = x % m;
512    Some(if inv < BigInt::zero() { inv + m } else { inv })
513}
514
515/// Chinese Remainder Theorem: solve a system of congruences.
516/// Given pairs (a_i, m_i) where x ≡ a_i (mod m_i), find x.
517///
518/// Returns Some(x, M) where x is the solution and M is the product of all moduli,
519/// or None if the moduli are not pairwise coprime.
520///
521/// # Examples
522/// ```
523/// use num_bigint::BigInt;
524/// use oxiz_math::rational::chinese_remainder;
525///
526/// // Solve: x ≡ 2 (mod 3), x ≡ 3 (mod 5), x ≡ 2 (mod 7)
527/// let remainders = vec![
528///     (BigInt::from(2), BigInt::from(3)),
529///     (BigInt::from(3), BigInt::from(5)),
530///     (BigInt::from(2), BigInt::from(7)),
531/// ];
532/// let (x, _m) = chinese_remainder(&remainders).unwrap();
533/// assert_eq!(&x % BigInt::from(3), BigInt::from(2));
534/// assert_eq!(&x % BigInt::from(5), BigInt::from(3));
535/// assert_eq!(&x % BigInt::from(7), BigInt::from(2));
536/// ```
537pub fn chinese_remainder(congruences: &[(BigInt, BigInt)]) -> Option<(BigInt, BigInt)> {
538    if congruences.is_empty() {
539        return None;
540    }
541
542    // Compute the product of all moduli (M in mathematical notation)
543    let mut prod_moduli = BigInt::one();
544    for (_, m_i) in congruences {
545        prod_moduli = &prod_moduli * m_i;
546    }
547
548    let mut result = BigInt::zero();
549
550    for (a_i, m_i) in congruences {
551        // M_i = M / m_i in mathematical notation
552        let partial_prod = &prod_moduli / m_i;
553
554        // Find the modular inverse of partial_prod mod m_i
555        let inv = mod_inverse(&partial_prod, m_i)?;
556
557        // Add to result: a_i * partial_prod * inv
558        result = (result + a_i * &partial_prod * inv) % &prod_moduli;
559    }
560
561    // Ensure result is positive
562    if result < BigInt::zero() {
563        result += &prod_moduli;
564    }
565
566    Some((result, prod_moduli))
567}
568
569/// Solve a linear Diophantine equation ax + by = c.
570/// Returns Some((x, y)) if a solution exists, or None if no solution exists.
571///
572/// A solution exists if and only if gcd(a, b) divides c.
573///
574/// # Examples
575/// ```
576/// use num_bigint::BigInt;
577/// use oxiz_math::rational::solve_linear_diophantine;
578///
579/// let a = BigInt::from(3);
580/// let b = BigInt::from(5);
581/// let c = BigInt::from(1);
582/// let (x, y) = solve_linear_diophantine(&a, &b, &c).unwrap();
583/// assert_eq!(&a * &x + &b * &y, c);
584/// ```
585pub fn solve_linear_diophantine(a: &BigInt, b: &BigInt, c: &BigInt) -> Option<(BigInt, BigInt)> {
586    let (gcd, x0, y0) = gcd_extended(a.clone(), b.clone());
587
588    // Check if c is divisible by gcd(a, b)
589    if (c % &gcd) != BigInt::zero() {
590        return None; // No solution exists
591    }
592
593    // Scale the solution
594    let factor = c / &gcd;
595    let x = x0 * &factor;
596    let y = y0 * factor;
597
598    Some((x, y))
599}
600
601/// Performs the Miller-Rabin primality test.
602///
603/// Returns `true` if `n` is probably prime, `false` if composite.
604/// The parameter `k` controls the number of rounds (higher = more accurate).
605///
606/// # Examples
607/// ```
608/// use num_bigint::BigInt;
609/// use oxiz_math::rational::is_prime;
610///
611/// assert!(is_prime(&BigInt::from(17), 5));
612/// assert!(is_prime(&BigInt::from(97), 5));
613/// assert!(!is_prime(&BigInt::from(15), 5));
614/// ```
615#[cfg(feature = "std")]
616pub fn is_prime(n: &BigInt, k: usize) -> bool {
617    use num_traits::One;
618    use rand::RngExt;
619
620    // Handle small cases
621    if n <= &BigInt::one() {
622        return false;
623    }
624    if n == &BigInt::from(2) || n == &BigInt::from(3) {
625        return true;
626    }
627    if n.is_even() {
628        return false;
629    }
630
631    // Write n-1 as 2^r * d
632    let n_minus_1 = n - BigInt::one();
633    let mut d = n_minus_1.clone();
634    let mut r = 0u32;
635    while d.is_even() {
636        d >>= 1;
637        r += 1;
638    }
639
640    let two = BigInt::from(2);
641    let n_minus_3 = n - &two - BigInt::one();
642    let mut rng = rand::rng();
643
644    // Miller-Rabin test
645    'witness: for _ in 0..k {
646        // Pick random witness a in [2, n-2]
647        let a = if n_minus_3 <= BigInt::zero() {
648            two.clone()
649        } else {
650            // Generate random number by generating random u64 and taking mod
651            let random_u64 = rng.random_range(0u64..u64::MAX);
652            (BigInt::from(random_u64) % &n_minus_3) + &two
653        };
654
655        let mut x = mod_pow(&a, &d, n);
656
657        if x == BigInt::one() || x == n_minus_1 {
658            continue 'witness;
659        }
660
661        for _ in 0..(r - 1) {
662            x = mod_pow(&x, &two, n);
663            if x == n_minus_1 {
664                continue 'witness;
665            }
666        }
667
668        return false; // Composite
669    }
670
671    true // Probably prime
672}
673
674/// Performs trial division to find small prime factors.
675///
676/// Returns a vector of prime factors found up to the limit.
677/// If the input becomes 1, all factors have been found.
678///
679/// # Examples
680/// ```
681/// use num_bigint::BigInt;
682/// use oxiz_math::rational::trial_division;
683///
684/// let n = BigInt::from(60);
685/// let factors = trial_division(&n, 100);
686/// // 60 = 2^2 * 3 * 5
687/// assert!(factors.contains(&BigInt::from(2)));
688/// assert!(factors.contains(&BigInt::from(3)));
689/// assert!(factors.contains(&BigInt::from(5)));
690/// ```
691pub fn trial_division(n: &BigInt, limit: u64) -> Vec<BigInt> {
692    let mut factors = Vec::new();
693    let mut num = n.clone();
694
695    // Check for factor 2
696    while num.is_even() {
697        factors.push(BigInt::from(2));
698        num >>= 1;
699    }
700
701    // Check odd factors up to limit
702    let mut divisor = BigInt::from(3);
703    let limit_big = BigInt::from(limit);
704    let two = BigInt::from(2);
705
706    while &divisor * &divisor <= num && divisor <= limit_big {
707        while &num % &divisor == BigInt::zero() {
708            factors.push(divisor.clone());
709            num /= &divisor;
710        }
711        divisor += &two;
712    }
713
714    // If num > 1, it's a prime factor
715    if num > BigInt::one() && n != &num {
716        factors.push(num);
717    }
718
719    factors
720}
721
722/// Pollard's rho algorithm for integer factorization.
723///
724/// Attempts to find a non-trivial factor of `n`.
725/// Returns `None` if no factor is found within the iteration limit.
726///
727/// # Examples
728/// ```
729/// use num_bigint::BigInt;
730/// use oxiz_math::rational::pollard_rho;
731///
732/// let n = BigInt::from(8051); // 8051 = 83 * 97
733/// if let Some(factor) = pollard_rho(&n) {
734///     assert!(n.clone() % &factor == BigInt::from(0));
735///     assert!(factor > BigInt::from(1) && factor < n);
736/// }
737/// ```
738#[cfg(feature = "std")]
739pub fn pollard_rho(n: &BigInt) -> Option<BigInt> {
740    use rand::RngExt;
741
742    if n <= &BigInt::one() {
743        return None;
744    }
745    if n.is_even() {
746        return Some(BigInt::from(2));
747    }
748
749    let mut rng = rand::rng();
750
751    // Generate random initial values using u64
752    let random_x0 = rng.random_range(0u64..u64::MAX);
753    let random_c = rng.random_range(1u64..u64::MAX);
754
755    let x0 = BigInt::from(random_x0) % n;
756    let c = BigInt::from(random_c) % n;
757
758    let f = |x: &BigInt| -> BigInt { (x * x + &c) % n };
759
760    let mut x = x0.clone();
761    let mut y = x0;
762    let mut d = BigInt::one();
763
764    let max_iterations = 100000;
765    let mut iterations = 0;
766
767    while d == BigInt::one() && iterations < max_iterations {
768        x = f(&x);
769        y = f(&f(&y));
770
771        let diff = if x >= y { &x - &y } else { &y - &x };
772        d = gcd_bigint(diff, n.clone());
773
774        iterations += 1;
775    }
776
777    if d != *n && d != BigInt::one() {
778        Some(d)
779    } else {
780        None
781    }
782}
783
784/// Computes the Jacobi symbol (a/n).
785///
786/// The Jacobi symbol is a generalization of the Legendre symbol.
787/// Returns -1, 0, or 1.
788///
789/// # Examples
790/// ```
791/// use num_bigint::BigInt;
792/// use oxiz_math::rational::jacobi_symbol;
793///
794/// // (2/5) = -1
795/// assert_eq!(jacobi_symbol(&BigInt::from(2), &BigInt::from(5)), -1);
796/// // (3/5) = -1
797/// assert_eq!(jacobi_symbol(&BigInt::from(3), &BigInt::from(5)), -1);
798/// // (4/5) = 1
799/// assert_eq!(jacobi_symbol(&BigInt::from(4), &BigInt::from(5)), 1);
800/// ```
801pub fn jacobi_symbol(a: &BigInt, n: &BigInt) -> i8 {
802    let mut a = a % n;
803    let mut n = n.clone();
804    let mut result = 1i8;
805
806    while a != BigInt::zero() {
807        // Remove factors of 2
808        while a.is_even() {
809            a >>= 1;
810            let n_mod_8 = &n % BigInt::from(8);
811            if n_mod_8 == BigInt::from(3) || n_mod_8 == BigInt::from(5) {
812                result = -result;
813            }
814        }
815
816        // Swap a and n
817        core::mem::swap(&mut a, &mut n);
818
819        // Quadratic reciprocity
820        if &a % BigInt::from(4) == BigInt::from(3) && &n % BigInt::from(4) == BigInt::from(3) {
821            result = -result;
822        }
823
824        a %= &n;
825    }
826
827    if n == BigInt::one() { result } else { 0 }
828}
829
830/// Computes the Legendre symbol (a/p) for prime p.
831///
832/// Returns -1 if a is a quadratic non-residue mod p,
833/// 0 if a ≡ 0 (mod p), and 1 if a is a quadratic residue mod p.
834///
835/// # Examples
836/// ```
837/// use num_bigint::BigInt;
838/// use oxiz_math::rational::legendre_symbol;
839///
840/// // For p = 5:
841/// // 1^2 = 1, 2^2 = 4, 3^2 = 4, 4^2 = 1 (mod 5)
842/// // So quadratic residues are {1, 4}
843/// assert_eq!(legendre_symbol(&BigInt::from(1), &BigInt::from(5)), 1);
844/// assert_eq!(legendre_symbol(&BigInt::from(4), &BigInt::from(5)), 1);
845/// assert_eq!(legendre_symbol(&BigInt::from(2), &BigInt::from(5)), -1);
846/// ```
847pub fn legendre_symbol(a: &BigInt, p: &BigInt) -> i8 {
848    // For prime p, Legendre symbol equals Jacobi symbol
849    jacobi_symbol(a, p)
850}
851
852/// Computes Euler's totient function φ(n).
853///
854/// φ(n) counts the number of integers from 1 to n that are coprime with n.
855///
856/// # Examples
857/// ```
858/// use num_bigint::BigInt;
859/// use oxiz_math::rational::euler_totient;
860///
861/// assert_eq!(euler_totient(&BigInt::from(1)), BigInt::from(1));
862/// assert_eq!(euler_totient(&BigInt::from(9)), BigInt::from(6)); // φ(9) = 6
863/// assert_eq!(euler_totient(&BigInt::from(10)), BigInt::from(4)); // φ(10) = 4
864/// ```
865#[allow(dead_code)]
866pub fn euler_totient(n: &BigInt) -> BigInt {
867    if n <= &BigInt::one() {
868        return BigInt::one();
869    }
870
871    let mut result = n.clone();
872
873    // Find all prime factors using trial division
874    let factors = trial_division(n, 1000000);
875    let mut seen_primes = crate::prelude::HashSet::new();
876
877    for factor in factors {
878        if seen_primes.insert(factor.clone()) {
879            // φ(n) = n * (1 - 1/p1) * (1 - 1/p2) * ...
880            // = n * (p1 - 1)/p1 * (p2 - 1)/p2 * ...
881            result = result * (&factor - BigInt::one()) / &factor;
882        }
883    }
884
885    // If num is still > 1 after trial division, it's a large prime
886    let mut temp = n.clone();
887    let mut divisor = BigInt::from(2);
888    while &divisor * &divisor <= temp {
889        if &temp % &divisor == BigInt::zero() {
890            while &temp % &divisor == BigInt::zero() {
891                temp /= &divisor;
892            }
893            if seen_primes.insert(divisor.clone()) {
894                result = result * (&divisor - BigInt::one()) / &divisor;
895            }
896        }
897        divisor += BigInt::one();
898    }
899
900    if temp > BigInt::one() && !seen_primes.contains(&temp) {
901        result = result * (&temp - BigInt::one()) / &temp;
902    }
903
904    result
905}
906
907/// Tests if n is a perfect power: n = a^b for some a, b > 1.
908///
909/// Returns `Some((a, b))` if n is a perfect power, `None` otherwise.
910///
911/// # Examples
912/// ```
913/// use num_bigint::BigInt;
914/// use oxiz_math::rational::is_perfect_power;
915///
916/// assert_eq!(is_perfect_power(&BigInt::from(8)), Some((BigInt::from(2), 3)));
917/// assert_eq!(is_perfect_power(&BigInt::from(27)), Some((BigInt::from(3), 3)));
918/// // 16 = 2^4 or 4^2, both are valid
919/// let result = is_perfect_power(&BigInt::from(16));
920/// assert!(result.is_some());
921/// let (base, exp) = result.unwrap();
922/// assert_eq!(base.pow(exp), BigInt::from(16));
923/// assert_eq!(is_perfect_power(&BigInt::from(10)), None);
924/// ```
925pub fn is_perfect_power(n: &BigInt) -> Option<(BigInt, u32)> {
926    if n <= &BigInt::one() {
927        return None;
928    }
929
930    // Check for each possible exponent b from 2 to log2(n)
931    let bit_len = n.bits() as u32;
932
933    for b in 2..=bit_len {
934        // Binary search for a such that a^b = n
935        let mut low = BigInt::one();
936        let mut high = n.clone();
937
938        while low <= high {
939            let mid = (&low + &high) / BigInt::from(2);
940            let power = pow_uint(&BigRational::from_integer(mid.clone()), b);
941
942            if power.is_integer() {
943                let power_int = power.numer().clone();
944
945                match power_int.cmp(n) {
946                    Ordering::Equal => return Some((mid, b)),
947                    Ordering::Less => low = mid + BigInt::one(),
948                    Ordering::Greater => high = mid - BigInt::one(),
949                }
950            } else {
951                break;
952            }
953        }
954    }
955
956    None
957}
958
959/// Tests if n is square-free (not divisible by any perfect square except 1).
960///
961/// # Examples
962/// ```
963/// use num_bigint::BigInt;
964/// use oxiz_math::rational::is_square_free;
965///
966/// assert!(is_square_free(&BigInt::from(6))); // 6 = 2 * 3
967/// assert!(is_square_free(&BigInt::from(10))); // 10 = 2 * 5
968/// assert!(!is_square_free(&BigInt::from(12))); // 12 = 4 * 3, divisible by 4 = 2^2
969/// assert!(!is_square_free(&BigInt::from(18))); // 18 = 9 * 2, divisible by 9 = 3^2
970/// ```
971pub fn is_square_free(n: &BigInt) -> bool {
972    if n <= &BigInt::one() {
973        return n == &BigInt::one();
974    }
975
976    let factors = trial_division(n, 100000);
977    let mut prev: Option<BigInt> = None;
978
979    for factor in factors {
980        if let Some(ref p) = prev
981            && &factor == p
982        {
983            return false; // Found repeated factor
984        }
985        prev = Some(factor);
986    }
987
988    true
989}
990
991/// Computes the number of divisors of n (tau function, τ(n)).
992///
993/// # Examples
994/// ```
995/// use num_bigint::BigInt;
996/// use oxiz_math::rational::divisor_count;
997///
998/// assert_eq!(divisor_count(&BigInt::from(12)), BigInt::from(6)); // 1, 2, 3, 4, 6, 12
999/// assert_eq!(divisor_count(&BigInt::from(28)), BigInt::from(6)); // 1, 2, 4, 7, 14, 28
1000/// assert_eq!(divisor_count(&BigInt::from(1)), BigInt::from(1));
1001/// ```
1002pub fn divisor_count(n: &BigInt) -> BigInt {
1003    if n <= &BigInt::zero() {
1004        return BigInt::zero();
1005    }
1006    if n == &BigInt::one() {
1007        return BigInt::one();
1008    }
1009
1010    let factors = trial_division(n, 1000000);
1011
1012    // If factors is empty, n is prime (has exactly 2 divisors: 1 and n)
1013    if factors.is_empty() {
1014        return BigInt::from(2);
1015    }
1016
1017    let mut count = BigInt::one();
1018    let mut current_prime = None;
1019    let mut current_count = 0u32;
1020
1021    for factor in factors {
1022        if let Some(ref prime) = current_prime {
1023            if &factor == prime {
1024                current_count += 1;
1025            } else {
1026                count *= current_count + 1;
1027                current_prime = Some(factor);
1028                current_count = 1;
1029            }
1030        } else {
1031            current_prime = Some(factor);
1032            current_count = 1;
1033        }
1034    }
1035
1036    if current_count > 0 {
1037        count *= current_count + 1;
1038    }
1039
1040    count
1041}
1042
1043/// Computes the sum of divisors of n (sigma function, σ(n)).
1044///
1045/// # Examples
1046/// ```
1047/// use num_bigint::BigInt;
1048/// use oxiz_math::rational::divisor_sum;
1049///
1050/// assert_eq!(divisor_sum(&BigInt::from(12)), BigInt::from(28)); // 1+2+3+4+6+12
1051/// assert_eq!(divisor_sum(&BigInt::from(6)), BigInt::from(12)); // 1+2+3+6
1052/// assert_eq!(divisor_sum(&BigInt::from(1)), BigInt::from(1));
1053/// ```
1054pub fn divisor_sum(n: &BigInt) -> BigInt {
1055    if n <= &BigInt::zero() {
1056        return BigInt::zero();
1057    }
1058    if n == &BigInt::one() {
1059        return BigInt::one();
1060    }
1061
1062    let factors = trial_division(n, 1000000);
1063
1064    // If factors is empty, n is prime (divisors are 1 and n, so sum = 1 + n)
1065    if factors.is_empty() {
1066        return BigInt::one() + n;
1067    }
1068
1069    let mut sum = BigInt::one();
1070    let mut current_prime = None;
1071    let mut current_count = 0u32;
1072
1073    for factor in factors {
1074        if let Some(ref prime) = current_prime {
1075            if &factor == prime {
1076                current_count += 1;
1077            } else {
1078                // σ(p^k) = (p^(k+1) - 1) / (p - 1)
1079                let p_power =
1080                    pow_uint(&BigRational::from_integer(prime.clone()), current_count + 1);
1081                let numerator = p_power.numer() - BigInt::one();
1082                let denominator = prime - BigInt::one();
1083                sum *= numerator / denominator;
1084
1085                current_prime = Some(factor);
1086                current_count = 1;
1087            }
1088        } else {
1089            current_prime = Some(factor);
1090            current_count = 1;
1091        }
1092    }
1093
1094    if let Some(prime) = current_prime {
1095        let p_power = pow_uint(&BigRational::from_integer(prime.clone()), current_count + 1);
1096        let numerator = p_power.numer() - BigInt::one();
1097        let denominator = prime - BigInt::one();
1098        sum *= numerator / denominator;
1099    }
1100
1101    sum
1102}
1103
1104/// Computes the Möbius function μ(n).
1105///
1106/// Returns:
1107/// - 1 if n is square-free with an even number of prime factors
1108/// - -1 if n is square-free with an odd number of prime factors
1109/// - 0 if n is not square-free
1110///
1111/// # Examples
1112/// ```
1113/// use num_bigint::BigInt;
1114/// use oxiz_math::rational::mobius;
1115///
1116/// assert_eq!(mobius(&BigInt::from(1)), 1);
1117/// assert_eq!(mobius(&BigInt::from(6)), 1); // 6 = 2*3 (2 primes)
1118/// assert_eq!(mobius(&BigInt::from(30)), -1); // 30 = 2*3*5 (3 primes)
1119/// assert_eq!(mobius(&BigInt::from(12)), 0); // 12 = 2^2*3 (not square-free)
1120/// ```
1121pub fn mobius(n: &BigInt) -> i8 {
1122    if n <= &BigInt::zero() {
1123        return 0;
1124    }
1125    if n == &BigInt::one() {
1126        return 1;
1127    }
1128
1129    if !is_square_free(n) {
1130        return 0;
1131    }
1132
1133    let factors = trial_division(n, 1000000);
1134    let mut unique_primes = crate::prelude::HashSet::new();
1135
1136    for factor in factors {
1137        unique_primes.insert(factor);
1138    }
1139
1140    if unique_primes.len() % 2 == 0 { 1 } else { -1 }
1141}
1142
1143/// Computes Carmichael's lambda function λ(n).
1144///
1145/// λ(n) is the exponent of the group (ℤ/nℤ)*.
1146/// For any a coprime to n: a^λ(n) ≡ 1 (mod n).
1147///
1148/// # Examples
1149/// ```
1150/// use num_bigint::BigInt;
1151/// use oxiz_math::rational::carmichael_lambda;
1152///
1153/// assert_eq!(carmichael_lambda(&BigInt::from(1)), BigInt::from(1));
1154/// assert_eq!(carmichael_lambda(&BigInt::from(8)), BigInt::from(2)); // λ(8) = 2
1155/// assert_eq!(carmichael_lambda(&BigInt::from(15)), BigInt::from(4)); // λ(15) = 4
1156/// ```
1157#[allow(dead_code)]
1158pub fn carmichael_lambda(n: &BigInt) -> BigInt {
1159    if n <= &BigInt::one() {
1160        return BigInt::one();
1161    }
1162
1163    let factors = trial_division(n, 1000000);
1164    let mut prime_powers: FxHashMap<BigInt, u32> = FxHashMap::default();
1165
1166    for factor in factors {
1167        *prime_powers.entry(factor).or_insert(0) += 1;
1168    }
1169
1170    let mut result = BigInt::one();
1171
1172    for (prime, exp) in prime_powers {
1173        let lambda_p = if prime == BigInt::from(2) && exp >= 3 {
1174            // λ(2^k) = 2^(k-2) for k ≥ 3
1175            BigInt::from(2).pow(exp - 2)
1176        } else if prime == BigInt::from(2) {
1177            // λ(2) = 1, λ(4) = 2
1178            if exp == 1 {
1179                BigInt::one()
1180            } else {
1181                BigInt::from(2)
1182            }
1183        } else {
1184            // λ(p^k) = φ(p^k) = p^(k-1) * (p-1)
1185            let p_power = pow_uint(&BigRational::from_integer(prime.clone()), exp - 1);
1186            p_power.numer() * (&prime - BigInt::one())
1187        };
1188
1189        result = lcm_bigint(result, lambda_p);
1190    }
1191
1192    result
1193}
1194
1195/// Binary GCD (Stein's algorithm) - more efficient than Euclidean GCD.
1196///
1197/// This algorithm uses bitwise operations instead of division,
1198/// making it faster for large integers.
1199///
1200/// # Examples
1201/// ```
1202/// use num_bigint::BigInt;
1203/// use oxiz_math::rational::gcd_binary;
1204///
1205/// assert_eq!(gcd_binary(BigInt::from(48), BigInt::from(18)), BigInt::from(6));
1206/// assert_eq!(gcd_binary(BigInt::from(100), BigInt::from(35)), BigInt::from(5));
1207/// assert_eq!(gcd_binary(BigInt::from(17), BigInt::from(19)), BigInt::from(1));
1208/// ```
1209pub fn gcd_binary(mut a: BigInt, mut b: BigInt) -> BigInt {
1210    if a == BigInt::zero() {
1211        return b.abs();
1212    }
1213    if b == BigInt::zero() {
1214        return a.abs();
1215    }
1216
1217    a = a.abs();
1218    b = b.abs();
1219
1220    // Count common factors of 2
1221    let mut shift = 0u32;
1222    while a.is_even() && b.is_even() {
1223        a >>= 1;
1224        b >>= 1;
1225        shift += 1;
1226    }
1227
1228    // Remove remaining factors of 2 from a
1229    while a.is_even() {
1230        a >>= 1;
1231    }
1232
1233    loop {
1234        // Remove factors of 2 from b
1235        while b.is_even() {
1236            b >>= 1;
1237        }
1238
1239        // Ensure a <= b
1240        if a > b {
1241            core::mem::swap(&mut a, &mut b);
1242        }
1243
1244        b -= &a;
1245
1246        if b == BigInt::zero() {
1247            break;
1248        }
1249    }
1250
1251    a << shift
1252}
1253
1254/// Tonelli-Shanks algorithm for computing modular square roots.
1255///
1256/// Finds x such that x² ≡ n (mod p) for prime p.
1257/// Returns None if n is not a quadratic residue modulo p.
1258///
1259/// # Examples
1260/// ```
1261/// use num_bigint::BigInt;
1262/// use oxiz_math::rational::tonelli_shanks;
1263///
1264/// // 4 is a quadratic residue mod 7 (2^2 = 4)
1265/// let result = tonelli_shanks(&BigInt::from(4), &BigInt::from(7));
1266/// assert!(result.is_some());
1267/// if let Some(x) = result {
1268///     let p = BigInt::from(7);
1269///     assert_eq!((&x * &x) % &p, BigInt::from(4) % &p);
1270/// }
1271/// ```
1272pub fn tonelli_shanks(n: &BigInt, p: &BigInt) -> Option<BigInt> {
1273    // Check if n is a quadratic residue
1274    if legendre_symbol(n, p) != 1 {
1275        return None;
1276    }
1277
1278    // Handle special cases
1279    if p == &BigInt::from(2) {
1280        return Some(n % p);
1281    }
1282
1283    // Factor out powers of 2 from p-1: p-1 = 2^S * Q
1284    let p_minus_1 = p - BigInt::one();
1285    let mut q = p_minus_1.clone();
1286    let mut s = 0u32;
1287    while q.is_even() {
1288        q >>= 1;
1289        s += 1;
1290    }
1291
1292    // Special case: p ≡ 3 (mod 4)
1293    if s == 1 {
1294        let exp = (p + BigInt::one()) / BigInt::from(4);
1295        return Some(mod_pow(n, &exp, p));
1296    }
1297
1298    // Find a quadratic non-residue z
1299    let mut z = BigInt::from(2);
1300    while legendre_symbol(&z, p) != -1 {
1301        z += BigInt::one();
1302    }
1303
1304    let mut m = s;
1305    let mut c = mod_pow(&z, &q, p);
1306    let mut t = mod_pow(n, &q, p);
1307    let mut r = mod_pow(n, &((&q + BigInt::one()) / BigInt::from(2)), p);
1308
1309    loop {
1310        if t == BigInt::zero() {
1311            return Some(BigInt::zero());
1312        }
1313        if t == BigInt::one() {
1314            return Some(r);
1315        }
1316
1317        // Find the least i such that t^(2^i) = 1
1318        let mut i = 1u32;
1319        let mut temp = (&t * &t) % p;
1320        while temp != BigInt::one() && i < m {
1321            temp = (&temp * &temp) % p;
1322            i += 1;
1323        }
1324
1325        let b = mod_pow(&c, &BigInt::from(2u64).pow(m - i - 1), p);
1326        m = i;
1327        c = (&b * &b) % p;
1328        t = (&t * &c) % p;
1329        r = (&r * &b) % p;
1330    }
1331}
1332
1333/// Computes factorial n!
1334///
1335/// # Examples
1336/// ```
1337/// use num_bigint::BigInt;
1338/// use oxiz_math::rational::factorial;
1339///
1340/// assert_eq!(factorial(0), BigInt::from(1));
1341/// assert_eq!(factorial(5), BigInt::from(120));
1342/// assert_eq!(factorial(10), BigInt::from(3628800));
1343/// ```
1344pub fn factorial(n: u32) -> BigInt {
1345    if n == 0 || n == 1 {
1346        return BigInt::one();
1347    }
1348
1349    let mut result = BigInt::one();
1350    for i in 2..=n {
1351        result *= i;
1352    }
1353    result
1354}
1355
1356/// Computes binomial coefficient C(n, k) = n! / (k! * (n-k)!)
1357///
1358/// # Examples
1359/// ```
1360/// use num_bigint::BigInt;
1361/// use oxiz_math::rational::binomial;
1362///
1363/// assert_eq!(binomial(5, 2), BigInt::from(10));
1364/// assert_eq!(binomial(10, 3), BigInt::from(120));
1365/// assert_eq!(binomial(5, 0), BigInt::from(1));
1366/// assert_eq!(binomial(5, 5), BigInt::from(1));
1367/// ```
1368pub fn binomial(n: u32, k: u32) -> BigInt {
1369    if k > n {
1370        return BigInt::zero();
1371    }
1372    if k == 0 || k == n {
1373        return BigInt::one();
1374    }
1375
1376    // Use symmetry: C(n,k) = C(n,n-k)
1377    let k = core::cmp::min(k, n - k);
1378
1379    let mut result = BigInt::one();
1380    for i in 0..k {
1381        result *= n - i;
1382        result /= i + 1;
1383    }
1384    result
1385}
1386
1387#[cfg(test)]
1388mod tests;