gosper/
homographic.rs

1//! Iterative homographic function solver
2//!
3//! # Background
4//!
5//! A homographic function takes the following form:
6//!
7//! ```text
8//!         a * x + b
9//!  f(x) = ---------
10//!         c * x + d
11//! ```
12//!
13//! In general, we wish to compute the output `f(x)`, given the input `x`, so we
14//! initialize the function like:
15//!
16//! ```text
17//!         x
18//!  f(x) = -
19//!         1
20//! ```
21//!
22//! So, `a = 1, d = 1` and all other coefficients `_ = 0`.
23//!
24//! The key property of this type of function is that it can be evaluated
25//! iteratively on the input `x` and output `f(x)`.
26//!
27//! The [`Solver`] will attempt to factor a well-defined output term from its
28//! [`State`]. If it can do so, it will compute a new [`State`] with the output
29//! value factored out. Until such an output term can be determined, the
30//! [`Solver`] will evaluate `x` input terms into the [`State`].
31use crate::extended::{ExtendedInt, Infinity};
32use num::{BigInt, FromPrimitive, One, Zero};
33use std::iter::Peekable;
34
35/// The state of a homographic function
36pub struct State {
37    a: BigInt,
38    b: BigInt,
39    c: BigInt,
40    d: BigInt,
41}
42
43pub mod input {
44    use super::State;
45    use crate::{
46        extended::{ExtendedInt, ExtendedRational, Infinity},
47        rational::Rational,
48    };
49    use num::BigInt;
50    use std::iter::Peekable;
51
52    /// Performs "input" operations on the homographic function state
53    pub trait Input {
54        type Domain: Infinity;
55        fn peek_domain(&mut self) -> Self::Domain;
56        fn update_state(&mut self, state: &State) -> State;
57    }
58
59    /// Inputs regular continued fraction terms
60    pub struct Regular<I>(pub I);
61    impl<I> Input for Regular<Peekable<I>>
62    where
63        I: Iterator<Item = BigInt>,
64    {
65        type Domain = ExtendedInt;
66
67        fn peek_domain(&mut self) -> Self::Domain {
68            ExtendedInt::from(self.0.peek().cloned())
69        }
70
71        fn update_state(&mut self, state: &State) -> State {
72            let State { a, b, c, d } = state;
73            match &ExtendedInt::from(self.0.next()) {
74                ExtendedInt::Infinity => State {
75                    a: a.clone(),
76                    b: a.clone(),
77                    c: c.clone(),
78                    d: c.clone(),
79                },
80                ExtendedInt::Finite(p) => State {
81                    a: b + a * p,
82                    b: a.clone(),
83                    c: d + c * p,
84                    d: c.clone(),
85                },
86            }
87        }
88    }
89
90    /// Inputs generalized continued fraction terms
91    ///
92    /// See [`crate::generalized`]
93    pub struct Generalized<I>(pub I);
94    impl<I> Input for Generalized<Peekable<I>>
95    where
96        I: Iterator<Item = Rational>,
97    {
98        type Domain = ExtendedRational;
99
100        fn peek_domain(&mut self) -> Self::Domain {
101            ExtendedRational::from(self.0.peek().cloned())
102        }
103
104        fn update_state(&mut self, state: &State) -> State {
105            let State { a, b, c, d } = state;
106            match &ExtendedRational::from(self.0.next()) {
107                ExtendedRational::Finite(Rational(num, den)) => State {
108                    a: a * num + b * den,
109                    b: a.clone(),
110                    c: c * num + d * den,
111                    d: c.clone(),
112                },
113                _ => unimplemented!("Only infinite general continued fractions are supported"),
114            }
115        }
116    }
117}
118
119pub mod output {
120    use num::{BigInt, Zero};
121
122    use crate::extended::Infinity;
123
124    use super::State;
125
126    /// Performs "output" operations on the homographic function state
127    pub trait Output {
128        type Range;
129        type Term;
130
131        fn is_done<D: Infinity>(&self, state: &State, domain: &D) -> bool;
132        fn well_defined_range<D: Infinity>(&self, state: &State, domain: &D)
133            -> Option<Self::Range>;
134        fn update_state(&self, state: &State, range: &Self::Range) -> State;
135        fn emit(&self, range: &Self::Range) -> Self::Term;
136    }
137
138    /// Outputs regular continued fraction terms
139    pub struct Regular;
140    impl Output for Regular {
141        type Range = BigInt;
142        type Term = BigInt;
143
144        fn is_done<D: Infinity>(&self, state: &State, domain: &D) -> bool {
145            if domain.is_infinite() {
146                state.c.is_zero()
147            } else {
148                state.c.is_zero() && state.d.is_zero()
149            }
150        }
151
152        fn well_defined_range<D: Infinity>(
153            &self,
154            state: &State,
155            domain: &D,
156        ) -> Option<Self::Range> {
157            state.factor_integer(domain)
158        }
159
160        fn update_state(&self, state: &State, r: &Self::Range) -> State {
161            let State { a, b, c, d } = state;
162            State {
163                a: c.clone(),
164                b: d.clone(),
165                c: a - c * r,
166                d: b - d * r,
167            }
168        }
169
170        fn emit(&self, r: &Self::Range) -> Self::Term {
171            r.clone()
172        }
173    }
174
175    /// Outputs decimal digits
176    pub struct Decimal;
177    impl Output for Decimal {
178        type Range = BigInt;
179        type Term = BigInt;
180
181        fn is_done<D: Infinity>(&self, state: &State, domain: &D) -> bool {
182            if domain.is_infinite() {
183                state.a.is_zero() // not sure if this is correct
184            } else {
185                state.a.is_zero() && state.b.is_zero()
186            }
187        }
188
189        fn well_defined_range<D: Infinity>(
190            &self,
191            state: &State,
192            domain: &D,
193        ) -> Option<Self::Range> {
194            state.factor_integer(domain)
195        }
196
197        fn update_state(&self, state: &State, r: &Self::Range) -> State {
198            let State { a, b, c, d } = state;
199            State {
200                a: (a - c * r) * BigInt::from(10),
201                b: (b - d * r) * BigInt::from(10),
202                c: c.clone(),
203                d: d.clone(),
204            }
205        }
206
207        fn emit(&self, r: &Self::Range) -> Self::Term {
208            r.clone()
209        }
210    }
211}
212
213impl State {
214    pub fn identity() -> State {
215        State {
216            a: BigInt::one(),
217            b: BigInt::zero(),
218            c: BigInt::zero(),
219            d: BigInt::one(),
220        }
221    }
222
223    pub fn from_i8(a: i8, b: i8, c: i8, d: i8) -> State {
224        State {
225            a: BigInt::from_i8(a).unwrap(),
226            b: BigInt::from_i8(b).unwrap(),
227            c: BigInt::from_i8(c).unwrap(),
228            d: BigInt::from_i8(d).unwrap(),
229        }
230    }
231
232    pub fn factor_integer<D: Infinity>(&self, domain: &D) -> Option<BigInt> {
233        let State { a, b, c, d } = self;
234
235        if domain.is_infinite() {
236            let ac = ExtendedInt::divide_ints(a, c);
237            match ac {
238                ExtendedInt::Finite(x) => Some(x),
239                _ => None,
240            }
241        } else {
242            let ac = ExtendedInt::divide_ints(a, c);
243            if matches!(ac, ExtendedInt::Infinity) {
244                return None;
245            }
246
247            let bd = ExtendedInt::divide_ints(b, d);
248            if matches!(bd, ExtendedInt::Infinity) {
249                return None;
250            }
251
252            match (ac, bd) {
253                (ExtendedInt::Finite(x), ExtendedInt::Finite(y)) if x.eq(&y) => Some(x),
254                _ => None,
255            }
256        }
257    }
258}
259
260/// Homographic function solver
261pub struct Solver<I, O> {
262    state: State,
263    input: I,
264    output: O,
265}
266
267impl<I, O> Solver<I, O>
268where
269    I: input::Input,
270    O: output::Output,
271{
272    pub fn identity(input: I, output: O) -> Self {
273        Self {
274            state: State::identity(),
275            input,
276            output,
277        }
278    }
279}
280
281impl<I, O> Iterator for Solver<I, O>
282where
283    I: input::Input,
284    O: output::Output,
285{
286    type Item = O::Term;
287
288    fn next(&mut self) -> Option<Self::Item> {
289        loop {
290            let domain = self.input.peek_domain();
291            if self.output.is_done(&self.state, &domain) {
292                return None;
293            }
294
295            let range = self.output.well_defined_range(&self.state, &domain);
296            if let Some(r) = range {
297                self.state = self.output.update_state(&self.state, &r);
298                return Some(self.output.emit(&r));
299            } else if !domain.is_infinite() {
300                self.state = self.input.update_state(&self.state);
301            } else {
302                // special case where domain in infinite but no well defined range is available
303                // this can occur for 0, for example.
304                return None;
305            }
306        }
307    }
308}
309
310/// Type alias for `regular continued fraction` → `decimal digits`
311pub type DecimalSolver<I> = Solver<input::Regular<Peekable<I>>, output::Decimal>;
312
313/// Type alias for `generalized continued fraction` → `regular continued
314/// fraction`
315pub type GeneralizedSolver<I> = Solver<input::Generalized<Peekable<I>>, output::Regular>;
316
317#[cfg(test)]
318mod tests {
319    use crate::{consts, terms};
320    use num::ToPrimitive;
321
322    #[test]
323    fn it_emits_phi_as_decimal() {
324        let terms::Decimal(iter) = terms::Decimal::from(terms::Regular::from(consts::Phi));
325        assert!(iter
326            .take(10)
327            .map(|i| i.to_i32().unwrap())
328            .eq([1, 6, 1, 8, 0, 3, 3, 9, 8, 8]));
329    }
330
331    #[test]
332    fn it_emits_pi_as_decimal() {
333        let terms::Decimal(iter) = terms::Decimal::from(terms::Regular::from(consts::Pi));
334        assert!(iter
335            .take(11)
336            .map(|i| i.to_i32().unwrap())
337            .eq([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]));
338    }
339
340    #[test]
341    fn it_emits_pi_as_regular_continued_fraction() {
342        let terms::Regular(iter) = terms::Regular::from(consts::Pi);
343        assert!(iter
344            .take(13)
345            .map(|i| i.to_i32().unwrap())
346            .eq([3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14]));
347    }
348}