malachite_q/arithmetic/simplest_rational_in_interval.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::Rational;
10use crate::arithmetic::traits::SimplestRationalInInterval;
11use crate::conversion::continued_fraction::to_continued_fraction::RationalContinuedFraction;
12use crate::conversion::traits::ContinuedFraction;
13use core::cmp::{
14 Ordering::{self, *},
15 max, min,
16};
17use core::mem::swap;
18use malachite_base::num::arithmetic::traits::{AddMul, Ceiling, Floor, UnsignedAbs};
19use malachite_base::num::basic::traits::{One, Two, Zero};
20use malachite_base::num::conversion::traits::IsInteger;
21use malachite_nz::natural::Natural;
22
23fn min_helper_oo<'a>(ox: &'a Option<Natural>, oy: &'a Option<Natural>) -> &'a Natural {
24 if let Some(x) = ox.as_ref() {
25 if let Some(y) = oy.as_ref() {
26 min(x, y)
27 } else {
28 x
29 }
30 } else {
31 oy.as_ref().unwrap()
32 }
33}
34
35fn min_helper_xo<'a>(x: &'a Natural, oy: &'a Option<Natural>) -> &'a Natural {
36 if let Some(y) = oy.as_ref() {
37 min(x, y)
38 } else {
39 x
40 }
41}
42
43fn simplest_rational_one_alt_helper(
44 x: &Natural,
45 oy_n: &Option<Natural>,
46 mut cf_y: RationalContinuedFraction,
47 numerator: &Natural,
48 denominator: &Natural,
49 previous_numerator: &Natural,
50 previous_denominator: &Natural,
51) -> Rational {
52 // use [a_0; a_1, ... a_k - 1, 1] and [b_0; b_1, ... b_k]
53 let (n, d) = if oy_n.is_some() && x - Natural::ONE == *oy_n.as_ref().unwrap() {
54 let next_numerator = previous_numerator.add_mul(numerator, oy_n.as_ref().unwrap());
55 let next_denominator = previous_denominator.add_mul(denominator, oy_n.as_ref().unwrap());
56 let next_oy_n = cf_y.next();
57 if next_oy_n == Some(Natural::ONE) {
58 let next_next_numerator = numerator + &next_numerator;
59 let next_next_denominator = denominator + &next_denominator;
60 // since y_n = 1, cf_y is not exhausted yet
61 let y_n = cf_y.next().unwrap() + Natural::ONE;
62 (
63 next_numerator.add_mul(next_next_numerator, &y_n),
64 next_denominator.add_mul(next_next_denominator, y_n),
65 )
66 } else {
67 (
68 numerator + (next_numerator << 1),
69 denominator + (next_denominator << 1),
70 )
71 }
72 } else {
73 let ox_n_m_1 = x - Natural::ONE;
74 let m = min_helper_xo(&ox_n_m_1, oy_n);
75 let next_numerator = previous_numerator.add_mul(numerator, m);
76 let next_denominator = previous_denominator.add_mul(denominator, m);
77 (
78 numerator + (next_numerator << 1),
79 denominator + (next_denominator << 1),
80 )
81 };
82 Rational {
83 sign: true,
84 numerator: n,
85 denominator: d,
86 }
87}
88
89fn update_best(best: &mut Option<Rational>, x: &Rational, y: &Rational, candidate: Rational) {
90 if best.is_none() && candidate > *x && candidate < *y {
91 *best = Some(candidate);
92 }
93}
94
95impl Rational {
96 /// Compares two [`Rational`]s according to their complexity.
97 ///
98 /// Complexity is defined as follows: If two [`Rational`]s have different denominators, then the
99 /// one with the larger denominator is more complex. If they have the same denominator, then the
100 /// one whose numerator is further from zero is more complex. Finally, if $q > 0$, then $q$ is
101 /// simpler than $-q$.
102 ///
103 /// The [`Rational`]s ordered by complexity look like this:
104 /// $$
105 /// 0, 1, -1, 2, -2, \ldots, 1/2, -1/2, 3/2, -3/2, \ldots, 1/3, -1/3, 2/3, -2/3, \ldots, \ldots.
106 /// $$
107 /// This order is a well-order, and the order type of the [`Rational`]s under this order is
108 /// $\omega^2$.
109 ///
110 /// # Worst-case complexity
111 /// $T(n) = O(n)$
112 ///
113 /// $M(n) = O(1)$
114 ///
115 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
116 ///
117 /// # Examples
118 /// ```
119 /// use malachite_q::Rational;
120 /// use std::cmp::Ordering::*;
121 ///
122 /// assert_eq!(
123 /// Rational::from_signeds(1, 2).cmp_complexity(&Rational::from_signeds(1, 3)),
124 /// Less
125 /// );
126 /// assert_eq!(
127 /// Rational::from_signeds(1, 2).cmp_complexity(&Rational::from_signeds(3, 2)),
128 /// Less
129 /// );
130 /// assert_eq!(
131 /// Rational::from_signeds(1, 2).cmp_complexity(&Rational::from_signeds(-1, 2)),
132 /// Less
133 /// );
134 /// ```
135 pub fn cmp_complexity(&self, other: &Self) -> Ordering {
136 self.denominator_ref()
137 .cmp(other.denominator_ref())
138 .then_with(|| self.numerator_ref().cmp(other.numerator_ref()))
139 .then_with(|| (*self < 0u32).cmp(&(*other < 0u32)))
140 }
141}
142
143impl SimplestRationalInInterval for Rational {
144 /// Finds the simplest [`Rational`] contained in an open interval.
145 ///
146 /// Let $f(x, y) = p/q$, with $p$ and $q$ relatively prime. Then the following properties hold:
147 /// - $x < p/q < y$
148 /// - If $x < m/n < y$, then $n \geq q$
149 /// - If $x < m/q < y$, then $|p| \leq |m|$
150 ///
151 /// # Worst-case complexity
152 /// $T(n) = O(n^2 \log n \log\log n)$
153 ///
154 /// $M(n) = O(n \log n)$
155 ///
156 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(x.significant_bits(),
157 /// y.significant_bits())`.
158 ///
159 /// # Panics
160 /// Panics if $x \geq y$.
161 ///
162 /// # Examples
163 /// ```
164 /// use malachite_base::num::basic::traits::Zero;
165 /// use malachite_q::arithmetic::traits::SimplestRationalInInterval;
166 /// use malachite_q::Rational;
167 ///
168 /// assert_eq!(
169 /// Rational::simplest_rational_in_open_interval(
170 /// &Rational::from_signeds(1, 3),
171 /// &Rational::from_signeds(1, 2)
172 /// ),
173 /// Rational::from_signeds(2, 5)
174 /// );
175 /// assert_eq!(
176 /// Rational::simplest_rational_in_open_interval(
177 /// &Rational::from_signeds(-1, 3),
178 /// &Rational::from_signeds(1, 3)
179 /// ),
180 /// Rational::ZERO
181 /// );
182 /// assert_eq!(
183 /// Rational::simplest_rational_in_open_interval(
184 /// &Rational::from_signeds(314, 100),
185 /// &Rational::from_signeds(315, 100)
186 /// ),
187 /// Rational::from_signeds(22, 7)
188 /// );
189 /// ```
190 fn simplest_rational_in_open_interval(x: &Self, y: &Self) -> Rational {
191 assert!(x < y);
192 if *x < 0u32 && *y > 0u32 {
193 return Self::ZERO;
194 }
195 let neg_x;
196 let neg_y;
197 let (neg, x, y) = if *x < 0u32 {
198 neg_x = -x;
199 neg_y = -y;
200 (true, &neg_y, &neg_x)
201 } else {
202 (false, x, y)
203 };
204 let (floor_x, mut cf_x) = x.continued_fraction();
205 let floor_x = floor_x.unsigned_abs();
206 let (floor_y, mut cf_y) = y.continued_fraction();
207 let floor_y = floor_y.unsigned_abs();
208 let mut best = None;
209 if floor_x == floor_y {
210 let floor = floor_x;
211 let mut previous_numerator = Natural::ONE;
212 let mut previous_denominator = Natural::ZERO;
213 let mut numerator = floor;
214 let mut denominator = Natural::ONE;
215 let mut ox_n = cf_x.next();
216 let mut oy_n = cf_y.next();
217 while ox_n == oy_n {
218 // They are both Some
219 swap(&mut numerator, &mut previous_numerator);
220 swap(&mut denominator, &mut previous_denominator);
221 numerator = (&numerator).add_mul(&previous_numerator, &ox_n.unwrap());
222 denominator = (&denominator).add_mul(&previous_denominator, &oy_n.unwrap());
223 ox_n = cf_x.next();
224 oy_n = cf_y.next();
225 }
226 // use [x_0; x_1, ... x_k] and [y_0; y_1, ... y_k]
227 let m = min_helper_oo(&ox_n, &oy_n) + Natural::ONE;
228 let n = (&previous_numerator).add_mul(&numerator, &m);
229 let d = (&previous_denominator).add_mul(&denominator, &m);
230 let candidate = Self {
231 sign: true,
232 numerator: n,
233 denominator: d,
234 };
235 update_best(&mut best, x, y, candidate);
236 if let Some(x_n) = ox_n.as_ref()
237 && cf_x.is_done()
238 {
239 update_best(
240 &mut best,
241 x,
242 y,
243 simplest_rational_one_alt_helper(
244 x_n,
245 &oy_n,
246 cf_y.clone(),
247 &numerator,
248 &denominator,
249 &previous_numerator,
250 &previous_denominator,
251 ),
252 );
253 }
254 if let Some(y_n) = oy_n.as_ref()
255 && cf_y.is_done()
256 {
257 update_best(
258 &mut best,
259 x,
260 y,
261 simplest_rational_one_alt_helper(
262 y_n,
263 &ox_n,
264 cf_x.clone(),
265 &numerator,
266 &denominator,
267 &previous_numerator,
268 &previous_denominator,
269 ),
270 );
271 }
272 if ox_n.is_some() && oy_n.is_some() && cf_x.is_done() != cf_y.is_done() {
273 if cf_y.is_done() {
274 swap(&mut ox_n, &mut oy_n);
275 swap(&mut cf_y, &mut cf_x);
276 }
277 let x_n = ox_n.unwrap();
278 let y_n = oy_n.unwrap();
279 if y_n == x_n - Natural::ONE {
280 let next_y_n = cf_y.next().unwrap();
281 let next_numerator = (&previous_numerator).add_mul(&numerator, &y_n);
282 let next_denominator = (&previous_denominator).add_mul(&denominator, &y_n);
283 let (n, d) = if cf_y.is_done() && next_y_n == 2u32 {
284 (
285 next_numerator * Natural::from(3u32) + (numerator << 1),
286 next_denominator * Natural::from(3u32) + (denominator << 1),
287 )
288 } else {
289 (
290 previous_numerator + (numerator << 1),
291 previous_denominator + (denominator << 1),
292 )
293 };
294 let candidate = Self {
295 sign: true,
296 numerator: n,
297 denominator: d,
298 };
299 update_best(&mut best, x, y, candidate);
300 }
301 }
302 } else {
303 let candidate = if floor_y - Natural::ONE != floor_x || !cf_y.is_done() {
304 Self::from(floor_x + Natural::ONE)
305 } else {
306 let floor = floor_x;
307 // [f; x_1, x_2, x_3...] and [f + 1]. But to get any good candidates, we need [f;
308 // x_1, x_2, x_3...] and [f; 1]. If x_1 does not exist, the result is [f; 2].
309 let (n, d) = if cf_x.is_done() {
310 ((floor << 1) | Natural::ONE, Natural::TWO)
311 } else {
312 let x_1 = cf_x.next().unwrap();
313 if x_1 > Natural::ONE {
314 if x_1 == 2u32 && cf_x.is_done() {
315 // [f; 1, 1] and [f; 1], so [f; 1, 2] is a candidate.
316 (
317 floor * Natural::from(3u32) + Natural::TWO,
318 Natural::from(3u32),
319 )
320 } else {
321 // If x_1 > 1, we have [f; 2] as a candidate.
322 ((floor << 1) | Natural::ONE, Natural::TWO)
323 }
324 } else {
325 // x_2 exists since x_1 was 1
326 let x_2 = cf_x.next().unwrap();
327 // [f; 1, x_2] and [f; 1], so [f; 1, x_2 + 1] is a candidate. [f; 1, x_2 -
328 // 1, 1] and [f; 1], but [f; 1, x_2] is not in the interval
329 let k = &x_2 + Natural::ONE;
330 (&floor * &k + floor + k, x_2 + Natural::TWO)
331 }
332 };
333 Self {
334 sign: true,
335 numerator: n,
336 denominator: d,
337 }
338 };
339 update_best(&mut best, x, y, candidate);
340 }
341 let best = best.unwrap();
342 if neg { -best } else { best }
343 }
344
345 /// Finds the simplest [`Rational`] contained in a closed interval.
346 ///
347 /// Let $f(x, y) = p/q$, with $p$ and $q$ relatively prime. Then the following properties hold:
348 /// - $x \leq p/q \leq y$
349 /// - If $x \leq m/n \leq y$, then $n \geq q$
350 /// - If $x \leq m/q \leq y$, then $|p| \leq |m|$
351 ///
352 /// # Worst-case complexity
353 /// $T(n) = O(n^2 \log n \log\log n)$
354 ///
355 /// $M(n) = O(n \log n)$
356 ///
357 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(x.significant_bits(),
358 /// y.significant_bits())`.
359 ///
360 /// # Panics
361 /// Panics if $x > y$.
362 ///
363 /// # Examples
364 /// ```
365 /// use malachite_base::num::basic::traits::Zero;
366 /// use malachite_q::arithmetic::traits::SimplestRationalInInterval;
367 /// use malachite_q::Rational;
368 ///
369 /// assert_eq!(
370 /// Rational::simplest_rational_in_closed_interval(
371 /// &Rational::from_signeds(1, 3),
372 /// &Rational::from_signeds(1, 2)
373 /// ),
374 /// Rational::from_signeds(1, 2)
375 /// );
376 /// assert_eq!(
377 /// Rational::simplest_rational_in_closed_interval(
378 /// &Rational::from_signeds(-1, 3),
379 /// &Rational::from_signeds(1, 3)
380 /// ),
381 /// Rational::ZERO
382 /// );
383 /// assert_eq!(
384 /// Rational::simplest_rational_in_closed_interval(
385 /// &Rational::from_signeds(314, 100),
386 /// &Rational::from_signeds(315, 100)
387 /// ),
388 /// Rational::from_signeds(22, 7)
389 /// );
390 /// ```
391 fn simplest_rational_in_closed_interval(x: &Self, y: &Self) -> Rational {
392 assert!(x <= y);
393 if x == y {
394 return x.clone();
395 } else if *x <= 0u32 && *y >= 0u32 {
396 return Self::ZERO;
397 } else if x.is_integer() {
398 return if y.is_integer() {
399 if *x >= 0u32 {
400 min(x, y).clone()
401 } else {
402 max(x, y).clone()
403 }
404 } else if *x >= 0u32 {
405 x.clone()
406 } else {
407 Self::from(y.floor())
408 };
409 } else if y.is_integer() {
410 return if *x >= 0u32 {
411 Self::from(x.ceiling())
412 } else {
413 y.clone()
414 };
415 }
416 let mut best = Self::simplest_rational_in_open_interval(x, y);
417 for q in [x, y] {
418 if q.cmp_complexity(&best) == Less {
419 best = q.clone();
420 }
421 }
422 best
423 }
424}