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 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 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 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 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}