1use super::functions::*;
5
6#[allow(dead_code)]
8#[derive(Debug, Clone)]
9pub struct IntExtContinuedFraction {
10 pub coeffs: Vec<i64>,
12}
13#[allow(dead_code)]
14impl IntExtContinuedFraction {
15 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 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 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 pub fn depth(&self) -> usize {
52 self.coeffs.len()
53 }
54}
55#[allow(dead_code)]
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct IntExtGaussian {
59 pub re: i64,
61 pub im: i64,
63}
64#[allow(dead_code)]
65impl IntExtGaussian {
66 pub fn new(re: i64, im: i64) -> Self {
68 IntExtGaussian { re, im }
69 }
70 pub fn zero() -> Self {
72 IntExtGaussian { re: 0, im: 0 }
73 }
74 pub fn one() -> Self {
76 IntExtGaussian { re: 1, im: 0 }
77 }
78 pub fn i_unit() -> Self {
80 IntExtGaussian { re: 0, im: 1 }
81 }
82 pub fn add(self, other: Self) -> Self {
84 IntExtGaussian {
85 re: self.re + other.re,
86 im: self.im + other.im,
87 }
88 }
89 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 pub fn conj(self) -> Self {
98 IntExtGaussian {
99 re: self.re,
100 im: -self.im,
101 }
102 }
103 pub fn norm(self) -> i64 {
105 self.re * self.re + self.im * self.im
106 }
107 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 pub fn is_unit(self) -> bool {
118 self.norm() == 1
119 }
120 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#[allow(dead_code)]
132#[derive(Debug, Clone, PartialEq, Eq)]
133pub struct IntExtPadicVal {
134 pub prime: i64,
136}
137#[allow(dead_code)]
138impl IntExtPadicVal {
139 pub fn new(prime: i64) -> Self {
141 IntExtPadicVal { prime }
142 }
143 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 pub fn power(&self, k: u32) -> i64 {
159 self.prime.pow(k)
160 }
161 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 pub fn unit_part(&self, n: i64) -> Option<i64> {
171 let v = self.val(n)?;
172 Some(n / self.power(v))
173 }
174}
175#[allow(dead_code)]
179#[derive(Debug, Clone, PartialEq, Eq)]
180pub struct IntExtEuclidResult {
181 pub gcd: i64,
183 pub x: i64,
185 pub y: i64,
187}
188#[allow(dead_code)]
189impl IntExtEuclidResult {
190 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 pub fn verify(&self, a: i64, b: i64) -> bool {
205 a * self.x + b * self.y == self.gcd
206 }
207 pub fn is_coprime(&self) -> bool {
209 self.gcd == 1
210 }
211 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#[allow(dead_code)]
224#[derive(Debug, Clone)]
225pub struct IntCrtSolver {
226 congruences: Vec<(i64, i64)>,
228}
229#[allow(dead_code)]
230impl IntCrtSolver {
231 pub fn new() -> Self {
233 IntCrtSolver {
234 congruences: Vec::new(),
235 }
236 }
237 pub fn add_congruence(&mut self, remainder: i64, modulus: i64) {
239 self.congruences.push((remainder, modulus));
240 }
241 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 pub fn len(&self) -> usize {
264 self.congruences.len()
265 }
266 pub fn is_empty(&self) -> bool {
268 self.congruences.is_empty()
269 }
270}
271#[allow(dead_code)]
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub struct IntExtSternBrocot {
275 pub p: i64,
277 pub q: i64,
279}
280#[allow(dead_code)]
281impl IntExtSternBrocot {
282 pub fn root() -> Self {
284 IntExtSternBrocot { p: 1, q: 1 }
285 }
286 pub fn left_child(self) -> Self {
288 IntExtSternBrocot {
289 p: self.p,
290 q: self.p + self.q,
291 }
292 }
293 pub fn right_child(self) -> Self {
295 IntExtSternBrocot {
296 p: self.p + self.q,
297 q: self.q,
298 }
299 }
300 pub fn mediant(self, other: Self) -> Self {
302 IntExtSternBrocot {
303 p: self.p + other.p,
304 q: self.q + other.q,
305 }
306 }
307 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 pub fn to_f64(self) -> f64 {
334 self.p as f64 / self.q as f64
335 }
336}