Skip to main content

oxilean_std/int/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4use super::functions::*;
5
6/// Continued fraction expansion of an integer ratio p/q.
7#[allow(dead_code)]
8#[derive(Debug, Clone)]
9pub struct IntExtContinuedFraction {
10    /// The partial quotients a_0, a_1, a_2, ...
11    pub coeffs: Vec<i64>,
12}
13#[allow(dead_code)]
14impl IntExtContinuedFraction {
15    /// Compute the continued fraction expansion of p/q.
16    pub fn from_ratio(mut p: i64, mut q: i64) -> Self {
17        let mut coeffs = Vec::new();
18        while q != 0 {
19            coeffs.push(p / q);
20            let r = p % q;
21            p = q;
22            q = r;
23        }
24        IntExtContinuedFraction { coeffs }
25    }
26    /// Evaluate back to a rational (p, q) pair.
27    pub fn to_ratio(&self) -> (i64, i64) {
28        if self.coeffs.is_empty() {
29            return (0, 1);
30        }
31        let mut num = 1i64;
32        let mut den = 0i64;
33        for &a in self.coeffs.iter().rev() {
34            let new_num = a * num + den;
35            den = num;
36            num = new_num;
37        }
38        (num, den)
39    }
40    /// Return the n-th convergent as (p_n, q_n).
41    pub fn convergent(&self, n: usize) -> Option<(i64, i64)> {
42        if n >= self.coeffs.len() {
43            return None;
44        }
45        let sub = IntExtContinuedFraction {
46            coeffs: self.coeffs[..=n].to_vec(),
47        };
48        Some(sub.to_ratio())
49    }
50    /// Return the number of partial quotients.
51    pub fn depth(&self) -> usize {
52        self.coeffs.len()
53    }
54}
55/// Representation of a Gaussian integer a + b*i.
56#[allow(dead_code)]
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct IntExtGaussian {
59    /// Real part.
60    pub re: i64,
61    /// Imaginary part.
62    pub im: i64,
63}
64#[allow(dead_code)]
65impl IntExtGaussian {
66    /// Create a new Gaussian integer.
67    pub fn new(re: i64, im: i64) -> Self {
68        IntExtGaussian { re, im }
69    }
70    /// The zero Gaussian integer.
71    pub fn zero() -> Self {
72        IntExtGaussian { re: 0, im: 0 }
73    }
74    /// The unit Gaussian integer.
75    pub fn one() -> Self {
76        IntExtGaussian { re: 1, im: 0 }
77    }
78    /// The imaginary unit i.
79    pub fn i_unit() -> Self {
80        IntExtGaussian { re: 0, im: 1 }
81    }
82    /// Add two Gaussian integers.
83    pub fn add(self, other: Self) -> Self {
84        IntExtGaussian {
85            re: self.re + other.re,
86            im: self.im + other.im,
87        }
88    }
89    /// Multiply two Gaussian integers.
90    pub fn mul(self, other: Self) -> Self {
91        IntExtGaussian {
92            re: self.re * other.re - self.im * other.im,
93            im: self.re * other.im + self.im * other.re,
94        }
95    }
96    /// The complex conjugate.
97    pub fn conj(self) -> Self {
98        IntExtGaussian {
99            re: self.re,
100            im: -self.im,
101        }
102    }
103    /// The norm: N(a+bi) = a^2 + b^2.
104    pub fn norm(self) -> i64 {
105        self.re * self.re + self.im * self.im
106    }
107    /// Returns the four units of the Gaussian integers.
108    pub fn units() -> [Self; 4] {
109        [
110            IntExtGaussian::one(),
111            IntExtGaussian::new(-1, 0),
112            IntExtGaussian::i_unit(),
113            IntExtGaussian::new(0, -1),
114        ]
115    }
116    /// Check if this is a unit (norm = 1).
117    pub fn is_unit(self) -> bool {
118        self.norm() == 1
119    }
120    /// Check if this divides other in the Gaussian integers.
121    pub fn divides(self, other: Self) -> bool {
122        if self.norm() == 0 {
123            return other.re == 0 && other.im == 0;
124        }
125        let n = self.norm();
126        let prod = other.mul(self.conj());
127        prod.re % n == 0 && prod.im % n == 0
128    }
129}
130/// p-adic valuation: the largest power of p dividing n.
131#[allow(dead_code)]
132#[derive(Debug, Clone, PartialEq, Eq)]
133pub struct IntExtPadicVal {
134    /// The prime p.
135    pub prime: i64,
136}
137#[allow(dead_code)]
138impl IntExtPadicVal {
139    /// Create a p-adic valuation for prime p.
140    pub fn new(prime: i64) -> Self {
141        IntExtPadicVal { prime }
142    }
143    /// Compute v_p(n): the p-adic valuation of n.
144    /// Returns None if n = 0 (undefined) or prime <= 1.
145    pub fn val(&self, n: i64) -> Option<u32> {
146        if n == 0 || self.prime <= 1 {
147            return None;
148        }
149        let mut count = 0u32;
150        let mut current = n.abs();
151        while current % self.prime == 0 {
152            count += 1;
153            current /= self.prime;
154        }
155        Some(count)
156    }
157    /// Returns p^k.
158    pub fn power(&self, k: u32) -> i64 {
159        self.prime.pow(k)
160    }
161    /// Check if v_p(a) >= v_p(b), i.e. whether p^v_p(b) divides a.
162    pub fn divides_to_val(&self, a: i64, b: i64) -> bool {
163        match (self.val(a), self.val(b)) {
164            (Some(va), Some(vb)) => va >= vb,
165            (None, _) => false,
166            (_, None) => true,
167        }
168    }
169    /// Return the unit part: n / p^v_p(n).
170    pub fn unit_part(&self, n: i64) -> Option<i64> {
171        let v = self.val(n)?;
172        Some(n / self.power(v))
173    }
174}
175/// Extended Euclidean algorithm result: gcd and Bezout coefficients.
176///
177/// Given integers a and b, stores gcd, x, y such that a*x + b*y = gcd.
178#[allow(dead_code)]
179#[derive(Debug, Clone, PartialEq, Eq)]
180pub struct IntExtEuclidResult {
181    /// The greatest common divisor (always non-negative).
182    pub gcd: i64,
183    /// Bezout coefficient for a.
184    pub x: i64,
185    /// Bezout coefficient for b.
186    pub y: i64,
187}
188#[allow(dead_code)]
189impl IntExtEuclidResult {
190    /// Run the extended Euclidean algorithm on (a, b).
191    pub fn compute(a: i64, b: i64) -> Self {
192        fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
193            if b == 0 {
194                (a.abs(), if a >= 0 { 1 } else { -1 }, 0)
195            } else {
196                let (g, x1, y1) = extended_gcd(b, a % b);
197                (g, y1, x1 - (a / b) * y1)
198            }
199        }
200        let (gcd, x, y) = extended_gcd(a, b);
201        IntExtEuclidResult { gcd, x, y }
202    }
203    /// Verify the Bezout identity: a*x + b*y = gcd.
204    pub fn verify(&self, a: i64, b: i64) -> bool {
205        a * self.x + b * self.y == self.gcd
206    }
207    /// Returns true if a and b are coprime (gcd = 1).
208    pub fn is_coprime(&self) -> bool {
209        self.gcd == 1
210    }
211    /// Returns a modular inverse of a modulo b, if it exists.
212    pub fn modular_inverse(&self, _a: i64, b: i64) -> Option<i64> {
213        if self.gcd != 1 {
214            return None;
215        }
216        let inv = self.x % b;
217        Some(if inv < 0 { inv + b } else { inv })
218    }
219}
220/// Chinese Remainder Theorem solver for a system of congruences.
221///
222/// Solves: x ≡ r_i (mod m_i) for pairwise coprime moduli.
223#[allow(dead_code)]
224#[derive(Debug, Clone)]
225pub struct IntCrtSolver {
226    /// Pairs of (remainder, modulus).
227    congruences: Vec<(i64, i64)>,
228}
229#[allow(dead_code)]
230impl IntCrtSolver {
231    /// Create a new CRT solver with no congruences.
232    pub fn new() -> Self {
233        IntCrtSolver {
234            congruences: Vec::new(),
235        }
236    }
237    /// Add a congruence x ≡ remainder (mod modulus).
238    pub fn add_congruence(&mut self, remainder: i64, modulus: i64) {
239        self.congruences.push((remainder, modulus));
240    }
241    /// Solve the system and return the smallest non-negative x, plus the combined modulus M.
242    /// Returns None if the moduli are not pairwise coprime.
243    pub fn solve(&self) -> Option<(i64, i64)> {
244        if self.congruences.is_empty() {
245            return Some((0, 1));
246        }
247        let (mut x, mut m) = self.congruences[0];
248        x = ((x % m) + m) % m;
249        for &(r, mi) in &self.congruences[1..] {
250            let ext = IntExtEuclidResult::compute(m, mi);
251            if ext.gcd != 1 {
252                return None;
253            }
254            let diff = r - x;
255            let new_m = m * mi;
256            let step = (diff % mi * ext.x % mi + mi) % mi;
257            x = ((x + m * step) % new_m + new_m) % new_m;
258            m = new_m;
259        }
260        Some((x, m))
261    }
262    /// Number of congruences registered.
263    pub fn len(&self) -> usize {
264        self.congruences.len()
265    }
266    /// Returns true if no congruences have been added.
267    pub fn is_empty(&self) -> bool {
268        self.congruences.is_empty()
269    }
270}
271/// Stern-Brocot tree node: a rational number p/q in lowest terms.
272#[allow(dead_code)]
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub struct IntExtSternBrocot {
275    /// Numerator.
276    pub p: i64,
277    /// Denominator (positive).
278    pub q: i64,
279}
280#[allow(dead_code)]
281impl IntExtSternBrocot {
282    /// The root of the Stern-Brocot tree (1/1).
283    pub fn root() -> Self {
284        IntExtSternBrocot { p: 1, q: 1 }
285    }
286    /// The left child (mediant with 0/1).
287    pub fn left_child(self) -> Self {
288        IntExtSternBrocot {
289            p: self.p,
290            q: self.p + self.q,
291        }
292    }
293    /// The right child (mediant with 1/0 ancestor).
294    pub fn right_child(self) -> Self {
295        IntExtSternBrocot {
296            p: self.p + self.q,
297            q: self.q,
298        }
299    }
300    /// The mediant of two fractions.
301    pub fn mediant(self, other: Self) -> Self {
302        IntExtSternBrocot {
303            p: self.p + other.p,
304            q: self.q + other.q,
305        }
306    }
307    /// Approximate pi/4 using the Stern-Brocot tree (returns p/q < target or p/q > target).
308    /// Steps from root, going left if current > target_num/target_den, right otherwise.
309    pub fn approximate(target_num: i64, target_den: i64, steps: usize) -> Self {
310        let mut lo_p = 0i64;
311        let mut lo_q = 1i64;
312        let mut hi_p = 1i64;
313        let mut hi_q = 0i64;
314        let mut current = IntExtSternBrocot { p: 1, q: 1 };
315        for _ in 0..steps {
316            if current.p * target_den < target_num * current.q {
317                lo_p = current.p;
318                lo_q = current.q;
319            } else if current.p * target_den > target_num * current.q {
320                hi_p = current.p;
321                hi_q = current.q;
322            } else {
323                break;
324            }
325            current = IntExtSternBrocot {
326                p: lo_p + hi_p,
327                q: lo_q + hi_q,
328            };
329        }
330        current
331    }
332    /// Convert to a floating-point value.
333    pub fn to_f64(self) -> f64 {
334        self.p as f64 / self.q as f64
335    }
336}