1#![doc = include_str!("../README.md")]
2
3use std::{
4 fmt,
5 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
6 sync::Arc,
7};
8type Q = rug::Rational;
9type Z = rug::Integer;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12struct QuadraticField {
13 a: Q,
14 b: Q,
15 d: Arc<Z>,
16}
17impl fmt::Display for QuadraticField {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
19 write!(f, "{}+{}√{}", self.a, self.b, self.d)
20 }
21}
22#[auto_impl_ops::auto_ops]
23impl AddAssign<&QuadraticField> for QuadraticField {
24 fn add_assign(&mut self, other: &Self) {
25 assert_eq!(self.d, other.d);
26 self.a += &other.a;
27 self.b += &other.b;
28 }
29}
30#[auto_impl_ops::auto_ops]
31impl SubAssign<&QuadraticField> for QuadraticField {
32 fn sub_assign(&mut self, other: &Self) {
33 assert_eq!(self.d, other.d);
34 self.a -= &other.a;
35 self.b -= &other.b;
36 }
37}
38#[auto_impl_ops::auto_ops]
39impl SubAssign<&Z> for QuadraticField {
40 fn sub_assign(&mut self, other: &Z) {
41 self.a -= other;
42 }
43}
44#[auto_impl_ops::auto_ops]
45impl MulAssign<&QuadraticField> for QuadraticField {
46 fn mul_assign(&mut self, other: &Self) {
47 assert_eq!(self.d, other.d);
48 let new_a = Q::from(&self.a * &other.a) + Q::from(&self.b * &other.b) * &*self.d;
49 self.b = Q::from(&self.a * &other.b) + Q::from(&self.b * &other.a);
50 self.a = new_a;
51 }
52}
53#[auto_impl_ops::auto_ops]
54impl DivAssign<&QuadraticField> for QuadraticField {
55 fn div_assign(&mut self, other: &Self) {
56 assert_eq!(self.d, other.d);
57 let denom = Q::from(other.a.square_ref()) - Q::from(other.b.square_ref()) * &*self.d;
58 let new_a = (Q::from(&self.a * &other.a) - Q::from(&self.b * &other.b) * &*self.d) / &denom;
59 self.b = (Q::from(&self.b * &other.a) - Q::from(&self.a * &other.b)) / denom;
60 self.a = new_a;
61 }
62}
63impl QuadraticField {
64 fn from_integer(v: Z, d: Arc<Z>) -> Self {
65 Self {
66 a: Q::from(v),
67 b: Q::ZERO.clone(),
68 d,
69 }
70 }
71 fn one(d: Arc<Z>) -> Self {
72 Self::from_integer(Z::ONE.clone(), d)
73 }
74 fn recip(&self) -> Self {
75 QuadraticField::one(Arc::clone(&self.d)) / self
76 }
77 fn floor(&self) -> Z {
78 let d = Z::from(self.d.sqrt_ref());
79 let mut left = &self.a + Q::from(&self.b * &d);
80 let mut right = &self.a + Q::from(&self.b * (d + 1));
81 if right < left {
82 std::mem::swap(&mut left, &mut right);
83 }
84 let offset = Q::from(self.b.square_ref()) * &*self.d;
85 while Q::from(left.floor_ref()) != Q::from(right.floor_ref()) {
86 let mid = Q::from(&left + &right) / 2;
87 let y = Q::from(&mid - &self.a).square() - &offset;
88 if y <= *Q::ZERO {
89 left = mid;
90 } else {
91 right = mid;
92 }
93 }
94 left.floor().numer().clone()
95 }
96}
97
98pub fn continued_fraction_of_sqrt(d: Z) -> Vec<Z> {
109 let sd = Z::from(d.sqrt_ref());
110 if Z::from(sd.square_ref()) == d {
111 return vec![sd];
112 }
113 let d = Arc::new(d);
114 let mut v = QuadraticField {
115 a: Q::ZERO.clone(),
116 b: Q::ONE.clone(),
117 d: Arc::clone(&d),
118 };
119 let int = v.floor();
120 v = (v - &int).recip();
121 let v0 = v.clone();
122 let mut a = vec![int];
123 loop {
124 let int = v.floor();
125 v = (v - &int).recip();
126 a.push(int);
127 if v == v0 {
128 return a;
129 }
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
135pub enum Solution {
136 Negative(Z, Z),
138 Positive(Z, Z),
140}
141
142fn solve_pell_aux(a: Vec<Z>, d: Z) -> Solution {
143 let mut p_old = Z::ONE.clone();
144 let mut q_old = Z::ZERO;
145 let mut p_now = a[0].clone();
146 let mut q_now = Z::ONE.clone();
147 let z = Q::from(p_now.square_ref()) - Q::from(q_now.square_ref()) * &d;
150 if z == -Z::ONE.clone() {
151 return Solution::Negative(p_now, q_now);
152 } else if z == *Z::ONE {
153 return Solution::Positive(p_now, q_now);
154 }
155 for a in a.iter().skip(1) {
156 let p_new = a * &p_now + p_old;
157 let q_new = a * &q_now + q_old;
158 p_old = p_now;
159 q_old = q_now;
160 p_now = p_new;
161 q_now = q_new;
162 let z = Q::from(p_now.square_ref()) - Q::from(q_now.square_ref()) * &d;
164 if z == -Z::ONE.clone() {
165 return Solution::Negative(p_now, q_now);
166 } else if z == *Z::ONE {
167 return Solution::Positive(p_now, q_now);
168 }
169 }
170 unreachable!()
171}
172
173pub fn solve_pell(d: Z) -> Solution {
185 let a = continued_fraction_of_sqrt(d.clone());
186 solve_pell_aux(a, d)
187}
188
189pub fn solve_pell_negative(d: Z) -> Option<(Z, Z)> {
201 let a = continued_fraction_of_sqrt(d.clone());
202 if (a.len() - 1) % 2 == 0 {
203 return None;
204 }
205 let Solution::Negative(x, y) = solve_pell_aux(a, d) else {
206 unreachable!()
207 };
208 Some((x, y))
209}
210
211pub fn solve_pell_positive(d: Z) -> (Z, Z) {
222 match solve_pell(d.clone()) {
223 Solution::Positive(x, y) => (x, y),
224 Solution::Negative(x, y) => {
225 let q = QuadraticField {
226 a: Q::from(x),
227 b: Q::from(y),
228 d: d.into(),
229 };
230 let q2 = &q * &q;
231 (q2.a.numer().clone(), q2.b.numer().clone())
232 }
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn test() {
242 let d = Arc::new(Z::from(3));
243 let q = QuadraticField {
244 a: Q::ZERO.clone(),
245 b: Q::ONE.clone(),
246 d: Arc::clone(&d),
247 };
248 let a = q.floor();
249 assert_eq!(&a, Z::ONE);
250 let q = (q - a).recip();
251 let r = QuadraticField {
252 a: Q::from_f64(0.5).unwrap(),
253 b: Q::from_f64(0.5).unwrap(),
254 d: Arc::clone(&d),
255 };
256 assert_eq!(q, r);
257 }
258 fn to_z(v: &[i32]) -> Vec<Z> {
259 v.iter().map(|x| Z::from(*x)).collect()
260 }
261 #[test]
263 fn test_continued_fraction_of_sqrt2() {
264 let v = continued_fraction_of_sqrt(Z::from(2));
265 assert_eq!(v, to_z(&[1, 2]));
266 }
267 #[test]
268 fn test_continued_fraction_of_sqrt3() {
269 let v = continued_fraction_of_sqrt(Z::from(3));
270 assert_eq!(v, to_z(&[1, 1, 2]));
271 }
272 #[test]
273 fn test_continued_fraction_of_sqrt5() {
274 let v = continued_fraction_of_sqrt(Z::from(5));
275 assert_eq!(v, to_z(&[2, 4]));
276 }
277 #[test]
278 fn test_continued_fraction_of_sqrt6() {
279 let v = continued_fraction_of_sqrt(Z::from(6));
280 assert_eq!(v, to_z(&[2, 2, 4]));
281 }
282 #[test]
283 fn test_continued_fraction_of_sqrt7() {
284 let v = continued_fraction_of_sqrt(Z::from(7));
285 assert_eq!(v, to_z(&[2, 1, 1, 1, 4]));
286 }
287 #[test]
288 fn test_continued_fraction_of_sqrt8() {
289 let v = continued_fraction_of_sqrt(Z::from(8));
290 assert_eq!(v, to_z(&[2, 1, 4]));
291 }
292 #[test]
293 fn test_continued_fraction_of_sqrt10() {
294 let v = continued_fraction_of_sqrt(Z::from(10));
295 assert_eq!(v, to_z(&[3, 6]));
296 }
297 #[test]
298 fn test_continued_fraction_of_sqrt11() {
299 let v = continued_fraction_of_sqrt(Z::from(11));
300 assert_eq!(v, to_z(&[3, 3, 6]));
301 }
302 #[test]
303 fn test_continued_fraction_of_sqrt12() {
304 let v = continued_fraction_of_sqrt(Z::from(12));
305 assert_eq!(v, to_z(&[3, 2, 6]));
306 }
307 #[test]
308 fn test_continued_fraction_of_sqrt13() {
309 let v = continued_fraction_of_sqrt(Z::from(13));
310 assert_eq!(v, to_z(&[3, 1, 1, 1, 1, 6]));
311 }
312 #[test]
313 fn test_continued_fraction_of_sqrt31() {
314 let v = continued_fraction_of_sqrt(Z::from(31));
315 assert_eq!(v, to_z(&[5, 1, 1, 3, 5, 3, 1, 1, 10]));
316 }
317 #[test]
318 fn test_continued_fraction_of_sqrt94() {
319 let v = continued_fraction_of_sqrt(Z::from(94));
320 assert_eq!(
321 v,
322 to_z(&[9, 1, 2, 3, 1, 1, 5, 1, 8, 1, 5, 1, 1, 3, 2, 1, 18])
323 );
324 }
325 #[test]
326 fn test_continued_fraction_of_sqrt338() {
327 let v = continued_fraction_of_sqrt(Z::from(338));
328 assert_eq!(v, to_z(&[18, 2, 1, 1, 2, 36]));
329 }
330 #[test]
331 fn test_solve_pell() {
332 let v = solve_pell(Z::from(653));
333 assert_eq!(
334 v,
335 Solution::Negative(Z::from(2291286382u64), Z::from(89664965))
336 );
337 }
338 #[test]
339 fn test_solve_pell2() {
340 let v = solve_pell(Z::from(115));
341 assert_eq!(v, Solution::Positive(Z::from(1126), Z::from(105)));
342 }
343}