Skip to main content

adic/num_adic/int_raw/
trait_impl.rs

1use std::{
2    fmt,
3    iter::{repeat, repeat_n},
4};
5use itertools::Either;
6use num::{rational::Ratio, traits::Pow, Zero};
7use crate::{
8    divisible::{Composite, Divisible, PrimePower},
9    error::AdicResult,
10    local_num::{LocalOne, LocalZero},
11    normed::{Normed, UltraNormed, Valuation},
12    traits::{AdicPrimitive, CanApproximate, CanTruncate, HasApproximateDigits, HasDigitDisplay, HasDigits, PrimedFrom},
13    ZAdic,
14};
15use super::{IAdic, RAdic, Sign, UAdic};
16
17
18macro_rules! impl_display {
19    ( $AdicInt:ty ) => {
20        impl fmt::Display for $AdicInt {
21            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22                let p = self.p();
23                let digits = self.digit_display();
24                if digits.is_empty() {
25                    let zero = p.display_zero();
26                    write!(f, "{zero}._{p}")
27                } else {
28                    write!(f, "{digits}._{p}")
29                }
30            }
31        }
32    }
33}
34
35impl_display!(IAdic);
36impl_display!(RAdic);
37impl_display!(UAdic);
38
39
40
41impl LocalZero for UAdic {
42    fn local_zero(&self) -> Self {
43        Self::zero(self.p())
44    }
45    fn is_local_zero(&self) -> bool {
46        self.d.iter().all(LocalZero::is_local_zero)
47    }
48}
49impl LocalOne for UAdic {
50    fn local_one(&self) -> Self {
51        Self::one(self.p())
52    }
53    fn is_local_one(&self) -> bool {
54        self.d.first().is_some_and(LocalOne::is_local_one)
55            && self.d.iter().skip(1).all(LocalZero::is_local_zero)
56    }
57}
58
59impl LocalZero for IAdic {
60    fn local_zero(&self) -> Self {
61        Self::zero(self.p())
62    }
63    fn is_local_zero(&self) -> bool {
64        matches!(self.sign, Sign::Pos) && self.d.iter().all(LocalZero::is_local_zero)
65    }
66}
67impl LocalOne for IAdic {
68    fn local_one(&self) -> Self {
69        Self::one(self.p())
70    }
71    fn is_local_one(&self) -> bool {
72        matches!(self.sign, Sign::Pos)
73            && self.d.first().is_some_and(LocalOne::is_local_one)
74            && self.d.iter().skip(1).all(LocalZero::is_local_zero)
75    }
76}
77
78impl LocalZero for RAdic {
79    fn local_zero(&self) -> Self {
80        Self::zero(self.p())
81    }
82    fn is_local_zero(&self) -> bool {
83        self.fix_d.iter().all(LocalZero::is_local_zero) && self.rep_d.iter().all(LocalZero::is_local_zero)
84    }
85}
86impl LocalOne for RAdic {
87    fn local_one(&self) -> Self {
88        Self::one(self.p())
89    }
90    fn is_local_one(&self) -> bool {
91        self.fix_d.first().is_some_and(LocalOne::is_local_one)
92            && self.fix_d.iter().skip(1).all(LocalZero::is_local_zero)
93            && self.rep_d.iter().all(LocalZero::is_local_zero)
94    }
95}
96
97
98
99macro_rules! impl_normed_and_ultranormed {
100    ( $AdicInt:ty ) => {
101
102        impl Normed for $AdicInt {
103            type Norm = Ratio<u32>;
104            type Unit = Self;
105            fn norm(&self) -> Ratio<u32> {
106                match self.valuation() {
107                    Valuation::PosInf => Ratio::zero(),
108                    Valuation::Finite(valuation) => {
109                        let v = u32::try_from(valuation).expect("norm usize -> u32 conversion");
110                        let inv_norm = self.p().pow(v);
111                        Ratio::new(1, u32::from(inv_norm))
112                    },
113                }
114            }
115            fn unit(&self) -> Option<Self::Unit> {
116                match self.valuation() {
117                    Valuation::PosInf => None,
118                    Valuation::Finite(valuation) => Some(self.quotient(valuation)),
119                }
120            }
121            fn into_unit(self) -> Option<Self::Unit> {
122                match self.valuation() {
123                    Valuation::PosInf => None,
124                    Valuation::Finite(valuation) => Some(self.into_quotient(valuation)),
125                }
126            }
127            fn from_norm_and_unit(norm: Self::Norm, u: Self::Unit) -> Self {
128                let (numer, denom) = norm.into_raw();
129                if numer == 0 {
130                    u.local_zero()
131                } else if numer == 1 {
132                    let adic_inv_norm = Self::primed_from(u.p(), denom);
133                    adic_inv_norm * u
134                } else {
135                    panic!("Cannot invert norm to adic integer");
136                }
137                }
138            fn from_unit(u: Self::Unit) -> Self {
139                u
140            }
141            fn is_unit(&self) -> bool {
142                self.valuation().is_zero()
143            }
144        }
145
146        impl UltraNormed for $AdicInt {
147            type ValuationRing = usize;
148            fn from_unit_and_valuation(u: Self::Unit, v: Valuation<Self::ValuationRing>) -> Self {
149                let p = u.p();
150                match v {
151                    Valuation::Finite(v) => {
152                        let pp = PrimePower::try_from((p, v)).expect("PrimePower from usize");
153                        u * Self::from_prime_power(pp)
154                    },
155                    Valuation::PosInf => Self::zero(p),
156                }
157            }
158            fn valuation(&self) -> Valuation<usize> {
159                if self.is_local_zero() {
160                    Valuation::PosInf
161                } else {
162                    Valuation::Finite(
163                        self.digits().take_while(Zero::is_zero).count()
164                    )
165                }
166            }
167        }
168
169    }
170}
171
172impl_normed_and_ultranormed!(UAdic);
173impl_normed_and_ultranormed!(IAdic);
174impl_normed_and_ultranormed!(RAdic);
175
176
177macro_rules! impl_can_approximate {
178    ( $AdicInt:ty ) => {
179        impl HasApproximateDigits for $AdicInt {
180            fn certainty(&self) -> Valuation<Self::DigitIndex> {
181                Valuation::PosInf
182            }
183        }
184        impl CanApproximate for $AdicInt {
185            type Approximation = ZAdic;
186            fn approximation(&self, n: usize) -> Self::Approximation {
187                let c = match self.certainty() {
188                    Valuation::PosInf => n,
189                    Valuation::Finite(v) => std::cmp::min(v, n),
190                };
191                ZAdic::new_approx(self.p(), c, self.digits().take(c).collect())
192            }
193            fn into_approximation(self, n: usize) -> Self::Approximation {
194                let c = match self.certainty() {
195                    Valuation::PosInf => n,
196                    Valuation::Finite(v) => std::cmp::min(v, n),
197                };
198                ZAdic::new_approx(self.p(), c, self.digits().take(c).collect())
199            }
200        }
201    }
202}
203impl_can_approximate!(IAdic);
204impl_can_approximate!(RAdic);
205impl_can_approximate!(UAdic);
206
207
208impl HasDigits for IAdic {
209    type DigitIndex = usize;
210    fn base(&self) -> Composite {
211        self.p.into()
212    }
213    fn min_index(&self) -> Valuation<Self::DigitIndex> {
214        0.into()
215    }
216    fn num_digits(&self) -> Valuation<usize> {
217        match self.sign {
218            Sign::Pos => Valuation::Finite(self.d.len()),
219            Sign::Neg => Valuation::PosInf,
220        }
221    }
222    fn digit(&self, n: usize) -> AdicResult<u32> {
223        Ok(self.d.get(n).copied().unwrap_or(match self.sign {
224            Sign::Pos => 0,
225            Sign::Neg => self.p.m1(),
226        }))
227    }
228    fn digits(&self) -> impl Iterator<Item=u32> {
229        // Returns infinite iterator if num_digits PosInf and finite else
230        match self.sign {
231            Sign::Pos => Either::Left(self.d.iter().copied()),
232            Sign::Neg => Either::Right(self.d.iter().copied().chain(repeat(self.p.m1())))
233        }
234    }
235}
236
237impl CanTruncate for IAdic {
238    type Quotient = Self;
239    type Truncation = UAdic;
240    fn split(&self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
241        self.clone().into_split(n)
242    }
243    fn into_split(self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
244        let non_trailing = self.num_non_trailing();
245        if non_trailing > n {
246            let (r, q) = UAdic::new(self.p, self.d).into_split(n);
247            let digit_vec = q.digits().chain(repeat(0)).take(non_trailing - n).collect();
248            (r, Self::new(self.p, digit_vec, self.sign))
249        } else {
250            let trail = self.trailing_digit();
251            let rem = self.d.into_iter().chain(repeat(trail)).take(n).collect();
252            (UAdic::new(self.p, rem), Self::new(self.p, vec![], self.sign))
253        }
254    }
255}
256
257impl HasDigits for RAdic {
258    type DigitIndex = usize;
259    fn base(&self) -> Composite {
260        self.p.into()
261    }
262    fn min_index(&self) -> Valuation<Self::DigitIndex> {
263        0.into()
264    }
265    fn num_digits(&self) -> Valuation<usize> {
266        if self.rep_d.is_empty() {
267            Valuation::Finite(self.fix_d.len())
268        } else {
269            Valuation::PosInf
270        }
271    }
272    fn digit(&self, n: usize) -> AdicResult<u32> {
273        if n < self.fix_d.len() {
274            Ok(self.fix_d.get(n).copied().unwrap_or(0))
275        } else if self.rep_d.is_empty() {
276            Ok(0)
277        } else {
278            let diff = n - self.fix_d.len();
279            let n_phase = diff % self.rep_d.len();
280            Ok(self.rep_d.get(n_phase).copied().unwrap_or(0))
281        }
282
283    }
284    fn digits(&self) -> impl Iterator<Item=u32> {
285        self.fix_d.iter().chain(self.rep_d.iter().cycle()).copied()
286    }
287}
288
289impl CanTruncate for RAdic {
290    type Quotient = Self;
291    type Truncation = UAdic;
292    fn split(&self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
293        self.clone().into_split(n)
294    }
295    fn into_split(self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
296        let p = self.p;
297        let (fix_len, rep_len) = (self.fix_d.len(), self.rep_d.len());
298        if fix_len >= n {
299            let (r, q) = UAdic::new(p, self.fix_d).into_split(n);
300            let qn = q.finite_num_digits();
301            let fix_digit_vec = q.digits().chain(repeat_n(0, fix_len - n - qn)).collect::<Vec<_>>();
302            (r, Self::new(p, fix_digit_vec, self.rep_d))
303        } else if rep_len == 0 {
304            (UAdic::new(p, self.fix_d), Self::zero(p))
305        } else {
306            let rep_clone = self.rep_d.clone();
307            let before = UAdic::new(self.p, self.digits().take(n).collect());
308            let rem_disp = (n - fix_len) % rep_len;
309            let after = Self::new(
310                p, vec![],
311                rep_clone.into_iter().cycle().skip(rem_disp).take(rep_len).collect()
312            );
313            (before, after)
314        }
315    }
316}
317
318impl HasDigits for UAdic {
319    type DigitIndex = usize;
320    fn base(&self) -> Composite {
321        self.p.into()
322    }
323    fn min_index(&self) -> Valuation<Self::DigitIndex> {
324        0.into()
325    }
326    fn num_digits(&self) -> Valuation<usize> {
327        Valuation::Finite(self.d.len())
328    }
329    fn digit(&self, n: usize) -> AdicResult<u32> {
330        Ok(self.d.get(n).copied().unwrap_or(0))
331    }
332    fn digits(&self) -> impl Iterator<Item=u32> {
333        self.d.iter().copied()
334    }
335}
336
337impl CanTruncate for UAdic {
338    type Quotient = Self;
339    type Truncation = UAdic;
340    fn split(&self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
341        self.clone().into_split(n)
342    }
343    fn into_split(self, n: Self::DigitIndex) -> (Self::Truncation, Self::Quotient) {
344        let mut remainder = Vec::with_capacity(n);
345        let mut quotient = Vec::with_capacity(self.finite_num_digits());
346        for (i, d) in self.d.into_iter().enumerate() {
347            if i < n {
348                remainder.push(d);
349            } else {
350                quotient.push(d);
351            }
352        }
353        (UAdic::new(self.p, remainder), Self::new(self.p, quotient))
354    }
355}
356
357
358#[cfg(test)]
359mod test {
360
361    use crate::{traits::{AdicPrimitive, PrimedFrom}, EAdic};
362    use super::UAdic;
363
364
365    #[test]
366    fn display() {
367
368        // UAdic
369        assert_eq!("0._5", uadic!(5, []).to_string());
370        assert_eq!("1._5", UAdic::one(5).to_string());
371        assert_eq!("2._5", uadic!(5, [2]).to_string());
372        assert_eq!("3._5", uadic!(5, [3]).to_string());
373        assert_eq!("4._5", uadic!(5, [4]).to_string());
374        assert_eq!("10._5", uadic!(5, [0, 1]).to_string());
375        assert_eq!("11._5", UAdic::primed_from(5, 6).to_string());
376        assert_eq!("20._5", uadic!(5, [0, 2]).to_string());
377        assert_eq!("44._5", uadic!(5, [4, 4]).to_string());
378        assert_eq!("100._5", uadic!(5, [0, 0, 1]).to_string());
379        assert_eq!("22._5", uadic!(5, [2, 2, 0, 0]).to_string());
380        assert_eq!("1111._5", uadic!(5, [1, 1, 1, 1]).to_string());
381        assert_eq!("4444._5", uadic!(5, [4, 4, 4, 4]).to_string());
382        assert_eq!("1000._5", uadic!(5, [0, 0, 0, 1, 0, 0]).to_string());
383        assert_eq!("1001._5", uadic!(5, [1, 0, 0, 1]).to_string());
384        assert_eq!("uka1._31", uadic!(31, [1, 10, 20, 30]).to_string());
385        assert_eq!("[30][20][10][1]._37", uadic!(37, [1, 10, 20, 30]).to_string());
386
387        // IAdic
388        assert_eq!("0._5", eadic!(5, []).to_string());
389        assert_eq!("1._5", EAdic::one(5).to_string());
390        assert_eq!("2._5", eadic!(5, [2]).to_string());
391        assert_eq!("3._5", eadic!(5, [3]).to_string());
392        assert_eq!("4._5", eadic!(5, [4]).to_string());
393        assert_eq!("10._5", eadic!(5, [0, 1]).to_string());
394        assert_eq!("11._5", EAdic::primed_from(5, 6).to_string());
395        assert_eq!("20._5", eadic!(5, [0, 2]).to_string());
396        assert_eq!("44._5", eadic!(5, [4, 4]).to_string());
397        assert_eq!("100._5", eadic!(5, [0, 0, 1]).to_string());
398        assert_eq!("22._5", eadic!(5, [2, 2, 0, 0]).to_string());
399        assert_eq!("(4)._5", eadic_neg!(5, []).to_string());
400        assert_eq!("(4)3._5", eadic_neg!(5, [3]).to_string());
401        assert_eq!("(4)2._5", (-eadic!(5, [3])).to_string());
402        assert_eq!("(4)0._5", eadic_neg!(5, [0]).to_string());
403        assert_eq!("(4)34._5", EAdic::primed_from(5, -6).to_string());
404        assert_eq!("(4)30._5", eadic_neg!(5, [0, 3]).to_string());
405        assert_eq!("(4)00._5", eadic_neg!(5, [0, 0]).to_string());
406        assert_eq!("(u)ka1._31", eadic_neg!(31, [1, 10, 20]).to_string());
407        assert_eq!("([36])[20][10][1]._37", eadic_neg!(37, [1, 10, 20]).to_string());
408
409        // RAdic
410        assert_eq!("0._5", eadic_rep!(5, [], []).to_string());
411        assert_eq!("1._5", EAdic::one(5).to_string());
412        assert_eq!("2._5", eadic_rep!(5, [2], []).to_string());
413        assert_eq!("3._5", eadic_rep!(5, [3], []).to_string());
414        assert_eq!("4._5", eadic_rep!(5, [4], []).to_string());
415        assert_eq!("10._5", eadic_rep!(5, [0, 1], []).to_string());
416        assert_eq!("11._5", EAdic::primed_from(5, 6).to_string());
417        assert_eq!("20._5", eadic_rep!(5, [0, 2], []).to_string());
418        assert_eq!("22._5", eadic_rep!(5, [2, 2], []).to_string());
419        assert_eq!("100._5", eadic_rep!(5, [0, 0, 1], []).to_string());
420        assert_eq!("(4)._5", eadic_rep!(5, [], [4]).to_string());
421        assert_eq!("(4)3._5", eadic_rep!(5, [3], [4]).to_string());
422        assert_eq!("(4)2._5", (-eadic_rep!(5, [3], [])).to_string());
423        assert_eq!("(4)1._5", eadic_rep!(5, [1], [4]).to_string());
424        assert_eq!("(4)0._5", eadic_rep!(5, [0], [4]).to_string());
425        assert_eq!("(4)30._5", eadic_rep!(5, [0, 3], [4]).to_string());
426        assert_eq!("(1)._5", eadic_rep!(5, [], [1]).to_string());
427        assert_eq!("(3)4._5", (-eadic_rep!(5, [], [1])).to_string());
428        assert_eq!("(1)0._5", eadic_rep!(5, [0], [1]).to_string());
429        assert_eq!("(1)32._5", eadic_rep!(5, [2, 3, 1, 1], [1]).to_string());
430        assert_eq!("(01)._5", eadic_rep!(5, [], [1, 0]).to_string());
431        assert_eq!("(10)._5", (eadic_rep!(5, [0, 1], []) * eadic_rep!(5, [], [1, 0])).to_string());
432        assert_eq!("(004)._5", eadic_rep!(5, [], [4, 0, 0, 4, 0, 0]).to_string());
433        assert_eq!("(04)._5", eadic_rep!(5, [4, 0, 4], [0, 4]).to_string());
434        assert_eq!("(uk)a1._31", eadic_rep!(31, [1, 10], [20, 30]).to_string());
435        assert_eq!("([30][20])[10][1]._37", eadic_rep!(37, [1, 10], [20, 30]).to_string());
436
437    }
438
439}