Skip to main content

finitely/
lib.rs

1#![doc = include_str!("../readme.md")]
2#![no_std]
3
4use core::{
5    fmt::{Debug, Display, Write},
6    marker::PhantomData,
7    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use packet::Packet;
11
12mod numerics;
13mod packet;
14
15/// A trait to configure the modulus and overflow behaviour of
16/// an instance of a [`FinitePoly`].
17///
18/// Typically a user of this library will rarely interact with
19/// this trait -- an impl for it is automatically generated by
20/// the [`make_ring`] macro.
21pub trait PolySettings<const SIZE: usize, const LOG2: usize>: Sized {
22    /// The modulus of the base ring -- i.e. the `n` in `Z/nZ`
23    ///
24    /// Arithmetic in a `FinitePoly` will only ever be done in
25    /// this modulus.
26    const MODULO: u64;
27
28    /// The degree of `x` which is equivalent to [`Self::OVERFLOW`].
29    ///
30    /// In mathematical terms, if we are building
31    /// `(Z/nZ)[x]/(p(x))`, then this is `deg(p)`.
32    const DEGREE: usize;
33
34    /// This is equivalent to `x` raised to the power of
35    /// [`Self::DEGREE`].
36    ///
37    /// In mathematical terms, if we are building
38    /// `(Z/nZ)[x]/(p(x))` then:
39    /// ```text
40    /// p(x) = x^DEGREE - OVERFLOW(x)
41    /// ```
42    /// So that:
43    /// ```text
44    /// p(x) = 0 ==> x^DEGREE = OVERFLOW(x)
45    /// ```
46    const OVERFLOW: FinitePoly<Self, SIZE, LOG2>;
47}
48
49/// An element of a Quotient Ring Of a Polynomial Ring
50///
51/// This structure implements arithmetic in the ring:
52/// `(Z/nZ)[x]/(p(x))`. Precisely what this means is covered
53/// in the crate docs, written in plain and accessible language.
54///
55/// Generic Parameters:
56/// - `T` is a type which controls the Modulus of coefficients
57///   and Overflow behaviour on `x`.
58/// - `SIZE` is the number of `u64`s required to represent the
59///   first bit of every coefficient in any polynomial. This
60///   value should be `T::DEGREE.div_ceil(64)`.
61/// - `LOG2` is the number of bits required to represent any
62///   coefficient in the polynomial. For example, if the modulus
63///   is 5, `LOG2` is 3, since 4 is a possible coefficient and
64///   is represented as 100 in binary.
65///
66/// Example usage:
67/// ```
68/// use finitely::make_ring;
69/// make_ring! {
70///     F9 = { Z % 3, x^2 = [2] };
71/// }    
72///
73/// let value = F9::from_coeffs(&[1, 2]);
74/// assert_eq!(format!("{value}"), String::from("x + 2"));
75///
76/// // (x + 2) + (x + 2) = 2x + 4 = 2x + 1 (mod 3).
77/// assert_eq!(value + value, F9::from_coeffs(&[2, 1]));
78///
79/// // (x + 2) * (x + 2) = x^2 + 4x + 4 = x^2 + x + 1 (mod 3).
80/// // Since x^2 = 2, we get x + 1 + 2 = x (mod 3).
81/// assert_eq!(value * value, F9::from_coeffs(&[1, 0]));
82/// ```
83pub struct FinitePoly<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> {
84    pub(crate) internal: [Packet<LOG2>; SIZE],
85    pub(crate) _phantom: PhantomData<T>,
86}
87
88impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Eq
89    for FinitePoly<T, SIZE, LOG2>
90{
91}
92
93impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> PartialEq
94    for FinitePoly<T, SIZE, LOG2>
95{
96    fn eq(&self, other: &Self) -> bool {
97        Self::eq(*self, *other)
98    }
99}
100
101impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> PartialEq<u64>
102    for FinitePoly<T, SIZE, LOG2>
103{
104    fn eq(&self, other: &u64) -> bool {
105        self.degree() == 0 && (self.get_nth_coeff(0) % T::MODULO) == *other
106    }
107}
108
109impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Copy
110    for FinitePoly<T, SIZE, LOG2>
111{
112}
113
114impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Clone
115    for FinitePoly<T, SIZE, LOG2>
116{
117    fn clone(&self) -> Self {
118        *self
119    }
120}
121
122/// Throughout the examples in this implementation block,
123/// we will be using the example ring:
124/// ```
125/// use finitely::make_ring;
126/// make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
127/// ```
128impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> FinitePoly<T, SIZE, LOG2> {
129    /// The zero polynomial.
130    pub const ZERO: Self = Self {
131        internal: [Packet::<LOG2>::new(); SIZE],
132        _phantom: PhantomData,
133    };
134
135    const FALSE_ZERO: Packet<LOG2> = Packet::splat(T::MODULO as u64 % (1u64 << LOG2));
136    const OVERFLOW: Packet<LOG2> = Packet::splat((1u64 << LOG2) % T::MODULO as u64);
137    const DEGREE_OVERFLOW_BIT: usize = T::DEGREE - 1 - Self::DEGREE_OVERFLOW_U64 * 64;
138    const DEGREE_OVERFLOW_U64: usize = (T::DEGREE - 1) / 64;
139    const FILTER_EXCESS_BITS: u64 =
140        (1 << Self::DEGREE_OVERFLOW_BIT) | ((1 << Self::DEGREE_OVERFLOW_BIT) - 1);
141
142    /// The one polynomial.
143    pub const ONE: Self = Self::from_int(1);
144
145    /// Creates a polynomial where every coefficient
146    /// is `value`. I.e. `value + value x + value x^2 + ...`.
147    ///
148    /// This runs in *`O(LOG2 * SIZE)`*
149    ///
150    /// Example usage:
151    /// ```
152    /// # use finitely::make_ring;
153    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
154    /// ```
155    pub const fn splat(value: u64) -> Self {
156        Self {
157            internal: [Packet::splat(value); SIZE],
158            _phantom: PhantomData,
159        }
160    }
161
162    /// Is equivalent to representing `value` as a degree-0
163    /// polynomial. Mathematically speaking, this is equivalent
164    /// to adding 1 a total of `value` times.
165    ///
166    /// Note that this is _not_ implemented by adding 1 a total
167    /// of `value` times.
168    ///
169    /// This runs in *`O(LOG2 * SIZE)`*.
170    ///
171    /// Example usage:
172    /// ```
173    /// # use finitely::make_ring;
174    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
175    /// assert_eq!(F25::from_int(2), F25::ONE + F25::ONE);
176    /// assert_eq!(F25::from_int(5), F25::ZERO);
177    /// ```
178    pub const fn from_int(value: u64) -> Self {
179        let mut me = Self::ZERO;
180        me.internal[0] = Packet::from_int(value % T::MODULO);
181
182        me
183    }
184
185    /// A useful function when debugging the internals of this
186    /// library. Unlikely to be useful to a user, if all methods
187    /// on this type have been implemented correctly.
188    ///
189    /// Removes "false zeros" -- coefficients which are equal
190    /// to our modulus and are not zero as a result of arithmetic.
191    ///
192    /// For example, if we are working modulo 5, then we need
193    /// 3 bits. If you ask `finite` to compute `1 + 1 + 1 + 1 + 1`
194    /// modulo 5, then it will represent the coefficient internally
195    /// as `101`, as reduction modulo the modulus is done
196    /// as lazily as possible in the space given. When acquiring
197    /// the coefficient through `get_nth_coeff`, it will
198    /// automatically be reduced modulo the modulus.
199    const fn remove_false_zeros(mut self) -> Self {
200        let mut done = 0;
201
202        while done < SIZE {
203            let temp = self.internal[done];
204
205            // xor detects any differences with a false zero.
206            // or reduction accumulates any differences into a single u64.
207            // where there was a difference is now a 1, where there was
208            // not (i.e. it is a false zero) is now a 0.
209            let zeros_detect = temp.xor(Self::FALSE_ZERO).or_reduce();
210
211            // and-ing will remove elements where zeros_detect is 0
212            // which are places where we have a false zero.
213            self.internal[done] = temp.and_u64(zeros_detect);
214
215            done += 1;
216        }
217
218        self
219    }
220
221    /// Computes the degree of this polynomial.
222    ///
223    /// Mathematically speaking, it computes the smallest degree
224    /// of any representative of the equivalence class after reducing
225    /// modulo `p`.
226    ///
227    /// This runs in *`O(LOG2 * SIZE)`*
228    ///
229    /// Example usage:
230    /// ```
231    /// # use finitely::make_ring;
232    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
233    /// assert_eq!(F25::ZERO.degree(), 0);
234    /// assert_eq!(F25::ONE.degree(), 0);
235    /// assert_eq!(F25::from_coeffs(&[1, 2]).degree(), 1);
236    /// ```
237    pub const fn degree(mut self) -> usize {
238        self = self.remove_false_zeros();
239
240        let mut done = 1;
241
242        while done <= SIZE {
243            let mut to_detect = self.internal[SIZE - done];
244
245            if done == SIZE {
246                to_detect = to_detect.and_u64(Self::FILTER_EXCESS_BITS);
247            }
248
249            let leading = to_detect.leading_zeros();
250            let first_one_idx = 64 - leading;
251
252            if first_one_idx != 0 {
253                let degree_total = first_one_idx + (SIZE - done) as u64 * 64;
254
255                return degree_total as usize - 1;
256            }
257
258            done += 1;
259        }
260
261        0
262    }
263
264    /// Computes whether `self` is equivalent to `other`.
265    ///
266    /// This runs in *`O(?)`*
267    ///
268    /// Example usage:
269    /// ```
270    /// # use finitely::make_ring;
271    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
272    /// let value_1 = F25::from_coeffs(&[2, 1]);
273    /// let value_2 = F25::from_coeffs(&[1, 0]);
274    /// let product = F25::from_coeffs(&[3, 1]);
275    /// assert!((value_1 * value_2).eq(product));
276    /// ```
277    pub const fn eq(self, other: Self) -> bool {
278        let diff = self.sub(other);
279
280        diff.is_zero()
281    }
282
283    /// Computes whether `self` is the zero polynomial.
284    ///
285    /// This runs in *`O(LOG2 * SIZE)`*.
286    ///
287    /// Example usage:
288    /// ```
289    /// # use finitely::make_ring;
290    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
291    /// assert!(F25::ZERO.is_zero());
292    /// assert!(!F25::ONE.is_zero());
293    /// let fake_5 = F25::ONE + F25::ONE + F25::ONE + F25::ONE + F25::ONE;
294    /// assert!(fake_5.is_zero());
295    /// ```
296    pub const fn is_zero(mut self) -> bool {
297        self = self.remove_false_zeros();
298        let mut done = 0;
299
300        while done < SIZE - 1 {
301            if self.internal[done].or_reduce() != 0 {
302                return false;
303            }
304
305            done += 1;
306        }
307
308        if self.internal[SIZE - 1].or_reduce() << (64 - T::DEGREE % 64) != 0 {
309            return false;
310        }
311
312        true
313    }
314
315    /// Runs in at most *`O(LOG2^2)`*.
316    ///
317    /// I need to verify that is the lowest upper bound.
318    const fn add_within(n: Packet<LOG2>, m: Packet<LOG2>) -> Packet<LOG2> {
319        let mut result = n;
320        let mut carry = m;
321        let mut overflow_carry = Packet::new();
322
323        while !carry.is_zero() || !overflow_carry.is_zero() {
324            let add = result.xor(carry).xor(overflow_carry);
325            // new_carry = (result & carry) | (result & overflow_carry) | (carry & overflow_carry).
326            // That simplifies to this:
327            let new_carry = result
328                .and(carry.or(overflow_carry))
329                .or(carry.and(overflow_carry));
330
331            let (bumped, new_carry) = new_carry.left_shift_horizontal();
332
333            let new_overflow = Self::OVERFLOW.and_u64(bumped);
334
335            result = add;
336            carry = new_carry;
337            overflow_carry = new_overflow;
338        }
339
340        result
341    }
342
343    /// Computes the sum of `self` with `other`.
344    ///
345    /// Note: this type implements [`std::ops::Add`].
346    ///
347    /// This adds coefficient-wise.
348    ///
349    /// This runs in *`O(LOG2^2 * SIZE)`*
350    ///
351    /// Example usage:
352    /// ```
353    /// # use finitely::make_ring;
354    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
355    /// assert_eq!(F25::ONE.add(F25::ONE), F25::from_int(2));
356    /// assert_eq!(F25::from_int(4).add(F25::ONE), 0);
357    /// ```
358    pub const fn add(mut self, other: Self) -> Self {
359        let mut i = 0;
360        while i < SIZE {
361            self.internal[i] = Self::add_within(self.internal[i], other.internal[i]);
362            i += 1;
363        }
364
365        self
366    }
367
368    /// Essentially the same thing as add_within.
369    /// This has the same time complexity.
370    const fn sub_within(n: Packet<LOG2>, m: Packet<LOG2>) -> Packet<LOG2> {
371        let mut result = n;
372        let mut carry = m;
373        let mut underflow_carry = Packet::new();
374
375        while !carry.is_zero() || !underflow_carry.is_zero() {
376            let sub = result.xor(carry).xor(underflow_carry);
377
378            let new_carry = result
379                .not()
380                .and(carry.or(underflow_carry))
381                .or(carry.and(underflow_carry));
382
383            let (bumped, new_carry) = new_carry.left_shift_horizontal();
384
385            let new_underflow = Self::OVERFLOW.and_u64(bumped);
386
387            result = sub;
388            carry = new_carry;
389            underflow_carry = new_underflow;
390        }
391
392        result
393    }
394
395    /// Computes the difference between `self` and `other`.
396    ///
397    /// Note: this type implements [`std::ops::Sub`].
398    ///
399    /// This subtracts component-wise.
400    ///
401    /// This runs in *`O(LOG2^2 * SIZE)`*.
402    ///
403    /// Example usage:
404    /// ```
405    /// # use finitely::make_ring;
406    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
407    /// assert_eq!(F25::from_int(3) - 1, 2);
408    /// assert_eq!(F25::ZERO - F25::ONE, 4);
409    /// ```
410    pub const fn sub(mut self, other: Self) -> Self {
411        let mut i = 0;
412        while i < SIZE {
413            self.internal[i] = Self::sub_within(self.internal[i], other.internal[i]);
414            i += 1;
415        }
416
417        self
418    }
419
420    /// Essentially computes `0 - n`.
421    /// This runs in O(LOG2^2) at worst.
422    const fn neg_within(n: Packet<LOG2>) -> Packet<LOG2> {
423        let mut result = n;
424        let mut carry = n;
425        let bumped;
426
427        (bumped, carry) = carry.left_shift_horizontal();
428
429        let mut underflow_carry = Self::OVERFLOW.and_u64(bumped);
430
431        while !carry.is_zero() || !underflow_carry.is_zero() {
432            let sub = result.xor(carry).xor(underflow_carry);
433
434            let new_carry = result
435                .not()
436                .and(carry.or(underflow_carry))
437                .or(carry.and(underflow_carry));
438
439            let (bumped, new_carry) = new_carry.left_shift_horizontal();
440
441            let new_underflow = Self::OVERFLOW.and_u64(bumped);
442
443            result = sub;
444            carry = new_carry;
445            underflow_carry = new_underflow;
446        }
447
448        result
449    }
450
451    /// Computes the negation modulo the modulus of the polynomial.
452    ///
453    /// Note: this type implements [`std::ops::Neg`].
454    ///
455    /// Since all coefficients are positive, a coefficient `c` is
456    /// transformed into `MODULO - c`, which is equivalent to `-c`
457    /// modulo `MODULO`.
458    ///
459    /// This runs in *`O(LOG2^2 * SIZE)`*
460    ///
461    /// Example usage:
462    /// ```
463    /// # use finitely::make_ring;
464    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
465    /// assert_eq!(F25::from_coeffs(&[2, 3]).neg(), F25::from_coeffs(&[3, 2]));
466    /// ```
467    pub const fn neg(mut self) -> Self {
468        let mut i = 0;
469
470        while i < SIZE {
471            self.internal[i] = Self::neg_within(self.internal[i]);
472
473            i += 1;
474        }
475
476        self
477    }
478
479    /// Computes `self` times a constant coefficient.
480    ///
481    /// Note: this type implements [`std::ops::Mul`].
482    ///
483    /// This is faster than multiplying by `FinitePoly::make_int(by)`
484    /// since this can take advantage that the degree of the polynomial
485    /// will not change (unless you set `by = 0`, but that doesn't change
486    /// anything).
487    ///
488    /// This runs in *`O(LOG2^3 * SIZE)`*.
489    ///
490    /// Example usage:
491    /// ```
492    /// # use finitely::make_ring;
493    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
494    /// assert_eq!(
495    ///     F25::from_coeffs(&[2, 4]).mul_modulo(2),
496    ///     F25::from_coeffs(&[4, 3])
497    /// );
498    /// ```
499    pub const fn mul_modulo(self, by: u64) -> Self {
500        let mut by = by % T::MODULO as u64;
501
502        let mut acc = Self::ZERO;
503        let mut power_2 = self;
504
505        while by != 0 {
506            if by & 1 == 1 {
507                acc = acc.add(power_2);
508            }
509
510            by >>= 1;
511            power_2 = power_2.add(power_2);
512        }
513
514        acc
515    }
516
517    /// Computes `self` times `x` and reduces.
518    ///
519    /// This runs in *`O(LOG2^3 * SIZE)`*.
520    ///
521    /// Example usage:
522    /// ```
523    /// # use finitely::make_ring;
524    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
525    /// assert_eq!(F25::ONE.mul_x(), F25::from_coeffs(&[1, 0]));
526    /// assert_eq!(F25::ONE.mul_x().mul_x(), F25::from_coeffs(&[1, 3]));
527    /// assert_eq!(F25::from_coeffs(&[4, 2]).mul_x(), F25::from_coeffs(&[1, 2]));
528    /// ```
529    pub const fn mul_x(mut self) -> Self {
530        let extracted_overflow =
531            self.internal[Self::DEGREE_OVERFLOW_U64].extract_coefficient(Self::DEGREE_OVERFLOW_BIT);
532
533        let overflow = T::OVERFLOW.mul_modulo(extracted_overflow);
534
535        self = self.unchecked_mulx(1);
536
537        self.add(overflow)
538    }
539
540    /// Multiplies `self` by `x` without doing overflow.
541    ///
542    /// This runs in *`O(LOG2 * SIZE)`*.
543    ///
544    /// Example usage:
545    /// ```
546    /// # use finitely::make_ring;
547    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
548    /// assert_eq!(F25::ONE.unchecked_mulx(2), 0);
549    /// ```
550    pub const fn unchecked_mulx(mut self, power: usize) -> Self {
551        if power == 0 {
552            return self;
553        }
554        let mut done = 0;
555
556        let mut carry = Packet::new();
557
558        while done != SIZE {
559            let new_carry = self.internal[done].rsh(64 - power);
560            self.internal[done] = self.internal[done].lsh(power).or(carry);
561
562            carry = new_carry;
563            done += 1;
564        }
565
566        self
567    }
568
569    /// Acquires the nth coefficient of the polynomial.
570    ///
571    /// This runs in *`O(LOG2)`*.
572    ///
573    /// Example usage:
574    /// ```
575    /// # use finitely::make_ring;
576    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
577    /// let value = F25::from_coeffs(&[2, 3]);
578    /// assert_eq!(value.get_nth_coeff(0), 3);
579    /// assert_eq!(value.get_nth_coeff(1), 2);
580    /// ```
581    pub const fn get_nth_coeff(self, coeff: usize) -> u64 {
582        if coeff >= T::DEGREE {
583            return 0;
584        }
585
586        let u64_idx = coeff / 64;
587        let within_u64_idx = coeff % 64;
588
589        self.internal[u64_idx].extract_coefficient(within_u64_idx)
590    }
591
592    /// Sets a coefficient in the polynomial.
593    ///
594    /// This runs in *`O(LOG2)`*.
595    ///
596    /// Example usage:
597    /// ```
598    /// # use finitely::make_ring;
599    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
600    /// let value = F25::ZERO.set_coeff(0, 3).set_coeff(1, 2);
601    /// assert_eq!(value.get_nth_coeff(0), 3);
602    /// assert_eq!(value.get_nth_coeff(1), 2);
603    /// ```
604    #[must_use = "Since this method is const and cannot take &mut, you must assign it to a new variable."]
605    pub const fn set_coeff(mut self, idx: usize, coeff: u64) -> Self {
606        if idx >= T::DEGREE {
607            return self;
608        }
609
610        let u64_idx = idx / 64;
611        let within_u64_idx = idx % 64;
612
613        self.internal[u64_idx] = self.internal[u64_idx].set_coeff(within_u64_idx, coeff);
614
615        self
616    }
617
618    /// Computes the multiplication of `self` with `other`, reducing
619    /// modulo `p(x)` (the overflow is applied), and of course reducing
620    /// modulo `MODULO`.
621    ///
622    /// This runs in *`O(SIZE^2 * LOG2^3)`*.
623    ///
624    /// Example usage:
625    /// ```
626    /// # use finitely::make_ring;
627    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
628    /// let value_1 = F25::from_coeffs(&[1, 4]);
629    /// let value_2 = F25::from_coeffs(&[2, 3]);
630    /// assert_eq!(value_1 * value_2, value_2 * value_1);
631    /// assert_eq!(value_1 * value_2, F25::from_coeffs(&[3, 3]));
632    /// ```
633    pub const fn mul(self, other: Self) -> Self {
634        let mut acc = Self::ZERO;
635        let mut power_x = self;
636
637        let mut powers_done = 0;
638
639        while powers_done < T::DEGREE {
640            let coeff = other.get_nth_coeff(powers_done);
641
642            if coeff != 0 {
643                if coeff == 1 {
644                    acc = acc.add(power_x);
645                } else {
646                    acc = acc.add(power_x.mul_modulo(coeff));
647                }
648            }
649
650            power_x = power_x.mul_x();
651
652            powers_done += 1;
653        }
654
655        acc
656    }
657
658    /// If possible, returns self/other, self - other * self/other.
659    ///
660    /// This is sometimes possible if `MODULO` is not prime.
661    ///
662    /// This runs in *`O(SIZE^2 * LOG2^3)`*.
663    ///
664    /// Example usage:
665    /// ```
666    /// # use finitely::make_ring;
667    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
668    /// let numerator = F25::from_coeffs(&[1, 2]);
669    /// let denominator = F25::from_coeffs(&[1, 4]);
670    ///
671    /// let (division, remainder) = numerator.divide_remainder(denominator).unwrap();
672    /// assert_eq!(division, 1);  
673    /// assert_eq!(remainder, 3);  
674    /// // x + 2 == 1 * (x + 4) + 3
675    /// ```
676    pub const fn divide_remainder(self, other: Self) -> Option<(Self, Self)> {
677        let other_degree = other.degree();
678
679        let mut quotient = Self::ZERO;
680        let mut remainder = self;
681
682        let mut remainder_degree = remainder.degree();
683
684        while other_degree <= remainder_degree && !remainder.is_zero() {
685            let difference_in_degree = remainder_degree - other_degree;
686            // println!("Quotient: {quotient}, Remainder: {remainder}, diff: {difference_in_degree}, self: {self}, other: {other}");
687            let my_coeff = remainder.get_nth_coeff(remainder_degree);
688            let other_coeff = other.get_nth_coeff(other_degree);
689
690            let Some(inverse) = numerics::divide_modulo(T::MODULO, my_coeff, other_coeff) else {
691                return None;
692            };
693
694            let division = Self::from_int(inverse).unchecked_mulx(difference_in_degree);
695            quotient = quotient.add(division);
696
697            let product = other
698                .mul_modulo(inverse)
699                .unchecked_mulx(difference_in_degree);
700
701            remainder = remainder.sub(product);
702
703            remainder_degree = remainder.degree();
704        }
705
706        Some((quotient, remainder))
707    }
708
709    /// Computes the same thing as [`Self::divide_remainder`], however
710    /// the parameters are `(p(x), self)`. Since you cannot represent
711    /// `p(x)` using this ring (it will reduce to `OVERFLOW`), this
712    /// specialized function is necessary.
713    ///
714    /// This runs in *`O(SIZE^2 * LOG2^3)`*.
715    ///
716    /// Example usage:
717    /// ```
718    /// # use finitely::make_ring;
719    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
720    /// // Our quotient poly is x^2 + 4x + 2.
721    /// let denominator = F25::from_coeffs(&[1, 3]);     // x + 3
722    ///
723    /// let (quotient, remainder) = denominator.divide_quotient_poly_by_self().unwrap();
724    /// assert_eq!(quotient, F25::from_coeffs(&[1, 1])); // x + 1
725    /// assert_eq!(remainder, F25::from_coeffs(&[4]));   // 4
726    ///
727    /// // See: (x + 1)(x + 3) + 4 == x^2 + 4x + 2.
728    /// ```
729    pub const fn divide_quotient_poly_by_self(self) -> Option<(Self, Self)> {
730        let my_degree = T::DEGREE;
731        let other_degree = self.degree();
732
733        let difference_in_degree = my_degree - other_degree;
734        let other_coeff = self.get_nth_coeff(other_degree);
735
736        let Some(inverse) = numerics::invert_in_modulo(T::MODULO, other_coeff) else {
737            return None;
738        };
739
740        let division = if difference_in_degree == T::DEGREE {
741            return Some((Self::ZERO.sub(T::OVERFLOW).mul_modulo(inverse), Self::ZERO));
742        } else {
743            Self::from_int(inverse).unchecked_mulx(difference_in_degree)
744        };
745
746        let to_remove = self.set_coeff(other_degree, 0);
747
748        let product = to_remove.mul(division);
749
750        let remainder = Self::ZERO.sub(T::OVERFLOW).sub(product);
751
752        let Some((new_division, remainder)) = remainder.divide_remainder(self) else {
753            return None;
754        };
755
756        Some((division.add(new_division), remainder))
757    }
758
759    /// Tries to find a multiplicative inverse in the ring.
760    ///
761    /// That is, it will (try to) find an element `x` such
762    /// that `self.mul(x) == Self::ONE`.
763    ///
764    /// This will always succeed if `self` is a nonzero element
765    /// of `Self` and `Self` is a field. That is, if `MODULO` is
766    /// a prime number, and `p(x) = x^DEGREE - OVERFLOW(x)` is
767    /// irreducible modulo `MODULO`.
768    ///
769    /// If you are not over a field, this is only guaranteed to work
770    /// for constants, and the results for non-constant members of
771    /// the a non-field is unspecified.
772    ///
773    /// Example usage:
774    /// ```
775    /// # use finitely::make_ring;
776    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
777    /// assert_eq!(F25::from_int(3).invert().unwrap(), 2);
778    /// assert_eq!(F25::ONE.mul_x().invert().unwrap(), F25::from_coeffs(&[2, 3]));
779    /// // Notice: x(2x + 3) = 1.
780    /// ```
781    pub const fn invert(self) -> Option<Self> {
782        let mut t = Self::ZERO;
783        let mut r;
784        let mut new_t = Self::ONE;
785        let mut new_r = self;
786
787        // `r` should actually be x^degree - T::OVERFLOW = p(x).
788        // However, we cannot represent that number, so instead
789        // we use the special case function to compute p(x)/self.
790
791        let Some((quotient, remainder)) = self.divide_quotient_poly_by_self() else {
792            return None;
793        };
794
795        (r, new_r) = (new_r, remainder);
796        (t, new_t) = (new_t, t.sub(quotient.mul(new_t)));
797
798        while !new_r.is_zero() {
799            let Some((quotient, remainder)) = Self::divide_remainder(r, new_r) else {
800                return None;
801            };
802
803            (r, new_r) = (new_r, remainder);
804            (t, new_t) = (new_t, t.sub(quotient.mul(new_t)));
805        }
806
807        if r.degree() > 0 {
808            return None;
809        }
810
811        let r_as_integer = r.get_nth_coeff(0);
812        let Some(inverse) = numerics::invert_in_modulo(T::MODULO, r_as_integer) else {
813            return None;
814        };
815
816        Some(t.mul_modulo(inverse))
817    }
818
819    /// Constructs a polynomial given the specified coefficients.
820    ///
821    /// This runs in *`O(SIZE * LOG2)`*.
822    ///
823    /// Example usage:
824    /// ```
825    /// # use finitely::make_ring;
826    /// # make_ring! { F25 = { Z % 5, x^2 = [1, 3] }; }
827    /// assert_eq!(F25::from_coeffs(&[2, 1]), F25::from_coeffs(&[7, 6]));
828    /// ```
829    pub const fn from_coeffs(mut coeffs: &[u64]) -> Self {
830        let to_do = if coeffs.len() > T::DEGREE {
831            T::DEGREE
832        } else {
833            coeffs.len()
834        };
835
836        (_, coeffs) = coeffs.split_at(coeffs.len() - to_do);
837
838        let last_block_length = coeffs.len() % 64;
839
840        let (last_block, mut coeffs) = coeffs.split_at(last_block_length);
841
842        let last_block = Packet::from_coeffs(last_block);
843
844        let mut acc = Self::ZERO;
845
846        let mut insertion_idx = 0;
847
848        while coeffs.len() != 0 {
849            let (rest, last) = coeffs.split_at(coeffs.len() - 64);
850
851            coeffs = rest;
852
853            acc.internal[insertion_idx] = Packet::from_coeffs(last);
854
855            insertion_idx += 1;
856        }
857
858        acc.internal[insertion_idx] = last_block;
859
860        acc
861    }
862
863    /// Writes a debug version of `self` to `w`.
864    pub fn format_full(self, mut w: impl Write) -> core::fmt::Result {
865        for i in (1..T::DEGREE).rev() {
866            let coeff = self.get_nth_coeff(i) % T::MODULO as u64;
867
868            write!(w, "{coeff}x^{i} + ")?;
869        }
870
871        write!(w, "{}", self.get_nth_coeff(0) % T::MODULO as u64)
872    }
873
874    /// Writes a display version of `self` to `w`.
875    pub fn format_filtered(self, mut w: impl Write) -> core::fmt::Result {
876        if self == Self::ZERO {
877            return write!(w, "0");
878        }
879
880        let mut seen_first = false;
881
882        for i in (1..T::DEGREE).rev() {
883            let coeff = self.get_nth_coeff(i) % T::MODULO as u64;
884
885            if coeff != 0 {
886                if seen_first {
887                    write!(w, " + ")?;
888                } else {
889                    seen_first = true;
890                }
891
892                if coeff != 1 {
893                    write!(w, "{coeff}")?;
894                }
895
896                write!(w, "x")?;
897
898                if i != 1 {
899                    write!(w, "^{i}")?;
900                }
901            }
902        }
903
904        let zeroth = self.get_nth_coeff(0) % T::MODULO as u64;
905
906        if zeroth != 0 {
907            if seen_first {
908                write!(w, " + {zeroth}")?;
909            } else {
910                write!(w, "{zeroth}")?;
911            }
912        }
913
914        Ok(())
915    }
916
917    /// Returns an iterator over all members of the field.
918    pub fn iter() -> FinitePolyIterator<T, SIZE, LOG2> {
919        FinitePolyIterator {
920            coeffs: Some(Self::ZERO),
921            _item: PhantomData,
922        }
923    }
924}
925
926impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Debug
927    for FinitePoly<T, SIZE, LOG2>
928{
929    fn fmt(&self, mut f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
930        self.format_full(&mut f)?;
931        write!(f, " [")?;
932        for val in self.internal[1..].iter().rev() {
933            write!(f, "{val}, ")?;
934        }
935        write!(f, "{}", self.internal[0])?;
936        write!(f, "]")
937    }
938}
939
940impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Display
941    for FinitePoly<T, SIZE, LOG2>
942{
943    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
944        self.format_filtered(f)
945    }
946}
947
948impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Mul<Self>
949    for FinitePoly<T, SIZE, LOG2>
950{
951    type Output = Self;
952
953    fn mul(self, rhs: Self) -> Self {
954        self.mul(rhs)
955    }
956}
957
958impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Mul<u64>
959    for FinitePoly<T, SIZE, LOG2>
960{
961    type Output = Self;
962
963    fn mul(self, rhs: u64) -> Self {
964        self.mul_modulo(rhs)
965    }
966}
967
968impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Div<Self>
969    for FinitePoly<T, SIZE, LOG2>
970{
971    type Output = Self;
972
973    fn div(self, rhs: Self) -> Self {
974        self * rhs.invert().unwrap()
975    }
976}
977
978impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Div<u64>
979    for FinitePoly<T, SIZE, LOG2>
980{
981    type Output = Self;
982
983    fn div(self, rhs: u64) -> Self {
984        self * Self::from_int(rhs).invert().unwrap()
985    }
986}
987
988impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Add<Self>
989    for FinitePoly<T, SIZE, LOG2>
990{
991    type Output = Self;
992
993    fn add(self, rhs: Self) -> Self {
994        self.add(rhs)
995    }
996}
997
998impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Add<u64>
999    for FinitePoly<T, SIZE, LOG2>
1000{
1001    type Output = Self;
1002
1003    fn add(self, rhs: u64) -> Self {
1004        self.add(Self::from_int(rhs))
1005    }
1006}
1007
1008impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Neg
1009    for FinitePoly<T, SIZE, LOG2>
1010{
1011    type Output = Self;
1012
1013    fn neg(self) -> Self {
1014        self.neg()
1015    }
1016}
1017
1018impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Sub<Self>
1019    for FinitePoly<T, SIZE, LOG2>
1020{
1021    type Output = Self;
1022
1023    fn sub(self, rhs: Self) -> Self {
1024        self.sub(rhs)
1025    }
1026}
1027
1028impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Sub<u64>
1029    for FinitePoly<T, SIZE, LOG2>
1030{
1031    type Output = Self;
1032
1033    fn sub(self, rhs: u64) -> Self {
1034        self.sub(Self::from_int(rhs))
1035    }
1036}
1037
1038impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> AddAssign<U>
1039    for FinitePoly<T, SIZE, LOG2>
1040where
1041    Self: Add<U, Output = Self>,
1042{
1043    fn add_assign(&mut self, rhs: U) {
1044        *self = *self + rhs;
1045    }
1046}
1047
1048impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> SubAssign<U>
1049    for FinitePoly<T, SIZE, LOG2>
1050where
1051    Self: Sub<U, Output = Self>,
1052{
1053    fn sub_assign(&mut self, rhs: U) {
1054        *self = *self - rhs;
1055    }
1056}
1057
1058impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> MulAssign<U>
1059    for FinitePoly<T, SIZE, LOG2>
1060where
1061    Self: Mul<U, Output = Self>,
1062{
1063    fn mul_assign(&mut self, rhs: U) {
1064        *self = *self * rhs;
1065    }
1066}
1067
1068impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> DivAssign<U>
1069    for FinitePoly<T, SIZE, LOG2>
1070where
1071    Self: Div<U, Output = Self>,
1072{
1073    fn div_assign(&mut self, rhs: U) {
1074        *self = *self / rhs;
1075    }
1076}
1077
1078/// Iterates over all of the elements of the finite ring.
1079///
1080/// Created by calling [`FinitePoly::iter`].
1081pub struct FinitePolyIterator<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> {
1082    coeffs: Option<FinitePoly<T, SIZE, LOG2>>,
1083    _item: PhantomData<FinitePoly<T, SIZE, LOG2>>,
1084}
1085
1086impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Iterator
1087    for FinitePolyIterator<T, SIZE, LOG2>
1088{
1089    type Item = FinitePoly<T, SIZE, LOG2>;
1090
1091    fn next(&mut self) -> Option<Self::Item> {
1092        let coeffs = self.coeffs?;
1093        let mut new_coeffs = coeffs;
1094
1095        let mut is_zero = true;
1096
1097        for i in 0..T::DEGREE {
1098            let elem = new_coeffs.get_nth_coeff(i);
1099
1100            let mut new_val = elem + 1;
1101
1102            let carry = new_val / T::MODULO as u64;
1103            new_val -= carry * T::MODULO as u64;
1104
1105            new_coeffs = new_coeffs.set_coeff(i, new_val);
1106
1107            is_zero &= new_val == 0;
1108
1109            if carry == 0 {
1110                break;
1111            }
1112        }
1113
1114        if is_zero {
1115            self.coeffs = None;
1116        } else {
1117            self.coeffs = Some(new_coeffs);
1118        }
1119
1120        Some(coeffs)
1121    }
1122}
1123
1124impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> From<u64>
1125    for FinitePoly<T, SIZE, LOG2>
1126{
1127    fn from(value: u64) -> Self {
1128        Self::from_int(value)
1129    }
1130}
1131
1132const fn log2(x: u64) -> usize {
1133    (64 - (x - 1).leading_zeros()) as _
1134}
1135
1136/// Returns the number of `u64`-width packets to represent the
1137/// polynomials given by `T::DEGREE`.
1138pub const fn get_size<T: PolySettings<0, 0>>() -> usize {
1139    T::DEGREE.div_ceil(64)
1140}
1141
1142/// Returns the number of bits required to represent coefficients
1143/// modulo `T::MODULO`.
1144pub const fn get_log2<T: PolySettings<0, 0>>() -> usize {
1145    log2(T::MODULO)
1146}
1147
1148#[doc(hidden)]
1149#[macro_export]
1150#[allow(unused_macros)]
1151macro_rules! forward_const {
1152    (
1153        $view:vis, ($t:ty) :
1154        $(
1155            fn $name:ident($($param_name:ident $(* $idx:literal)? $(: $param_ty:ty)?),*) -> $ret_ty:ident$(<$generics:ident>)?;
1156        )*
1157    ) => {
1158        $(
1159            #[allow(dead_code)]
1160            $view const fn $name($($param_name $(: $param_ty)?),*) -> $ret_ty$(<$generics>)? {
1161                $crate::forward_const!(@result : ($ret_ty) : (<$t>::$name($($crate::forward_const!(@param: $param_name $(* $idx)?)),*)))
1162            }
1163        )*
1164    };
1165
1166    (@param: $n:ident * $idx:literal) => {$n.0};
1167    (@param: $($t:tt)*) => {$($t)*};
1168    (@result: (Self) : ($($t:tt)*)) => {Self($($t)*)};
1169    (@result: (Option) : ($($t:tt)*)) => {match $($t)* { Some(x) => Some(Self(x)), None => None }};
1170    (@result: ($($t0:tt)*) : ($($t:tt)*)) => {$($t)*};
1171}
1172
1173#[doc(hidden)]
1174#[macro_export]
1175#[allow(unused_macros)]
1176macro_rules! forward_op_impl {
1177    (@basic: $on:ty: $($name:ident -- $method:ident ($op:tt) $other:ident $(*$lit:literal)?),*) => {
1178        
$(
1179        
    $crate::forward_op_impl!{@basic_inner: $on ; $name ; $method ; ($op) ; $other $(*$lit)?}
1180        
)*
1181    };
1182    (@basic_inner: $on:ty ; $name:ident ; $method:ident ; ($op:tt) ; $other:ident $(* $lit:literal)?) => {
1183        impl ::core::ops::$name<$other> for $on {
1184            type Output = Self;
1185
1186            fn $method(self, other: $other) -> Self {
1187                Self(self.0 $op $crate::forward_const!(@param: other $(* $lit)?))
1188            }
1189        }
1190    };
1191
1192    (@assign: $on:ty: $($name:ident -- $method:ident $other:ident $(*$lit:literal)?),*) => {
1193        $(
1194            $crate::forward_op_impl!{@assign_inner: $on ; $name ; $method ; $other $(*$lit)?}
1195        )*
1196    };
1197    (@assign_inner: $on:ty ; $name:ident ; $method:ident ; $other:ident $(* $lit:literal)?) => {
1198        impl ::core::ops::$name<$other> for $on {
1199            fn $method(&mut self, other: $other) {
1200                self.0.$method($crate::forward_const!(@param: other $(* $lit)?))
1201            }
1202        }
1203    };
1204}
1205
1206/// Creates a newtype with the necessary trait forwards for ease-of-use.
1207///
1208/// Example usage:
1209/// ```
1210/// use finitely::make_ring;
1211///
1212/// make_ring! {
1213///     // Attributes are supported:
1214///
1215///     #[allow(dead_code)]
1216///     /// The field with 25 elements.
1217///     pub(crate) F25 = { Z % 5, x^2 = [3] };
1218///
1219///     WeirdRing = { Z % 3500, x^5 = [12, 3, 4, 56] };
1220/// }
1221/// ```
1222#[allow(unused_macros)]
1223#[macro_export]
1224macro_rules! make_ring {
1225    ($($(#[$at:meta])* $view:vis $name:ident = { Z % $modulo:literal, x^ $degree:literal = [$($coefficients:literal),+] };)+) => {$(
1226        $(#[$at])*
1227        #[derive(PartialEq, Copy, Clone)]
1228        $view struct $name($crate::FinitePoly<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>);
1229
1230        impl<const SIZE: usize, const LOG2: usize> $crate::PolySettings<SIZE, LOG2> for $name {
1231            const DEGREE: usize = $degree;
1232            const MODULO: u64 = $modulo;
1233
1234            const OVERFLOW: $crate::FinitePoly<Self, SIZE, LOG2> = $crate::FinitePoly::<Self, SIZE, LOG2>::from_coeffs(&[$($coefficients),+]);
1235        }
1236
1237        impl $name {
1238            #[allow(dead_code)]
1239            $view const LOG2: usize = $crate::get_size::<Self>();
1240            #[allow(dead_code)]
1241            $view const SIZE: usize = $crate::get_log2::<Self>();
1242            #[allow(dead_code)]
1243            $view const OVERFLOW: Self = Self(<Self as $crate::PolySettings<{Self::LOG2}, {Self::SIZE}>>::OVERFLOW);
1244
1245            $view const ZERO: Self = Self($crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::ZERO);
1246            $view const ONE: Self = Self($crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::ONE);
1247
1248            $crate::forward_const! {
1249                $view, ($crate::FinitePoly<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>) :
1250                fn splat(value: u64) -> Self;
1251                fn from_int(value: u64) -> Self;
1252                fn degree(self*0) -> usize;
1253                fn eq(self*0, other*0: Self) -> bool;
1254                fn is_zero(self*0) -> bool;
1255                fn add(self*0, other*0: Self) -> Self;
1256                fn sub(self*0, other*0: Self) -> Self;
1257                fn mul(self*0, other*0: Self) -> Self;
1258                fn neg(self*0) -> Self;
1259                fn mul_modulo(self*0, by: u64) -> Self;
1260                fn mul_x(self*0) -> Self;
1261                fn unchecked_mulx(self*0, power: usize) -> Self;
1262                fn get_nth_coeff(self*0, coeff: usize) -> u64;
1263                fn set_coeff(self*0, idx: usize, coeff: u64) -> Self;
1264                fn invert(self*0) -> Option<Self>;
1265                fn from_coeffs(coeffs: &[u64]) -> Self;
1266            }
1267
1268            #[allow(dead_code)]
1269            $view const fn divide_remainder(self, other: Self) -> Option<(Self, Self)> {
1270                match self.0.divide_remainder(other.0) {
1271                    Some((x, y)) => Some((Self(x), Self(y))),
1272                    None => None
1273                }
1274            }
1275
1276            #[allow(dead_code)]
1277            $view const fn divide_quotient_poly_by_self(self) -> Option<(Self, Self)> {
1278                match self.0.divide_quotient_poly_by_self() {
1279                    Some((x, y)) => Some((Self(x), Self(y))),
1280                    None => None
1281                }
1282            }
1283
1284            $view fn iter() -> impl Iterator<Item = Self> {
1285                $crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::iter().map(|x| Self(x))
1286            }
1287        }
1288
1289        const _: () = {
1290            type Poly = $crate::FinitePoly<$name, {$crate::get_size::<$name>()}, {$crate::get_log2::<$name>()}>;
1291            impl From<$name> for Poly {
1292                fn from(other: $name) -> Self {
1293                    other.0
1294                }
1295            }
1296
1297            impl From<Poly> for $name {
1298                fn from(other: Poly) -> Self {
1299                    Self(other)
1300                }
1301            }
1302
1303            impl ::core::fmt::Debug for $name {
1304                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1305                    <Poly as ::core::fmt::Debug>::fmt(&self.0, f)
1306                }
1307            }
1308
1309            impl ::core::fmt::Display for $name {
1310                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1311                    <Poly as ::core::fmt::Display>::fmt(&self.0, f)
1312                }
1313            }
1314
1315            impl ::core::cmp::Eq for $name {}
1316
1317            impl<T> ::core::cmp::PartialEq<T> for $name
1318            where Poly: PartialEq<T> {
1319                fn eq(&self, other: &T) -> bool {
1320                    self.0 == *other
1321                }
1322            }
1323
1324            $crate::forward_op_impl! {
1325                @basic: $name:
1326                Add -- add (+) u64,
1327                Add -- add (+) Poly,
1328                Add -- add (+) $name * 0,
1329                Sub -- sub (-) u64,
1330                Sub -- sub (-) Poly,
1331                Sub -- sub (-) $name * 0,
1332                Mul -- mul (*) u64,
1333                Mul -- mul (*) Poly,
1334                Mul -- mul (*) $name * 0,
1335                Div -- div (/) u64,
1336                Div -- div (/) Poly,
1337                Div -- div (/) $name * 0
1338            }
1339
1340            $crate::forward_op_impl! {
1341                @assign: $name:
1342                AddAssign -- add_assign u64,
1343                AddAssign -- add_assign Poly,
1344                AddAssign -- add_assign $name * 0,
1345                SubAssign -- sub_assign u64,
1346                SubAssign -- sub_assign Poly,
1347                SubAssign -- sub_assign $name * 0,
1348                MulAssign -- mul_assign u64,
1349                MulAssign -- mul_assign Poly,
1350                MulAssign -- mul_assign $name * 0,
1351                DivAssign -- div_assign u64,
1352                DivAssign -- div_assign Poly,
1353                DivAssign -- div_assign $name * 0
1354            }
1355        };
1356    )+};
1357}
1358
1359#[cfg(test)]
1360mod tests {
1361    macro_rules! make_ring_tests {
1362        ($name:ident, $coeffs:literal, $modulo:literal) => {
1363            #[test]
1364            fn integer_to_poly() {
1365                let one_const = $name::ONE;
1366                let one_phi = $name::from_int(1);
1367
1368                assert_eq!(one_const, one_phi);
1369
1370                for i in 0..20 {
1371                    let pre_reduced = i % $modulo;
1372
1373                    let value_1 = $name::from_int(i);
1374                    let value_2 = $name::from_int(pre_reduced);
1375                    let mut value_3 = $name::ZERO;
1376
1377                    for _ in 0..i {
1378                        value_3 = value_3 + $name::ONE;
1379                    }
1380
1381                    let mut value_4 = $name::ZERO;
1382
1383                    for _ in 0..pre_reduced {
1384                        value_4 = value_4 + $name::ONE;
1385                    }
1386
1387                    assert_eq!(value_1, value_2);
1388                    assert_eq!(value_2, value_3);
1389                    assert_eq!(value_3, value_4);
1390                }
1391            }
1392
1393            #[test]
1394            fn coeff_equality() {
1395                for lhs in $name::iter() {
1396                    for rhs in $name::iter() {
1397                        let mut equal = true;
1398                        for power in 0..$coeffs {
1399                            let coeff_left = lhs.get_nth_coeff(power) % $modulo;
1400                            let coeff_right = rhs.get_nth_coeff(power) % $modulo;
1401
1402                            equal &= coeff_left == coeff_right;
1403                        }
1404
1405                        assert_eq!(equal, lhs == rhs, "Lhs: {lhs}, Rhs: {rhs}");
1406                    }
1407                }
1408            }
1409
1410            #[test]
1411            fn equality_is_equality() {
1412                // An equivalence relation ~ satisfies:
1413                // 1. x ~ x
1414                // 2. x ~ y ==> y ~ x
1415                // 3. x ~ y and y ~ z ==> x ~ z
1416
1417                // Test identity.
1418                for x in $name::iter() {
1419                    assert_eq!(x, x);
1420                }
1421
1422                // Test reflexivity.
1423                for x in $name::iter() {
1424                    for y in $name::iter() {
1425                        assert_eq!(x == y, y == x);
1426                    }
1427                }
1428
1429                // Test transitivity.
1430                for x in $name::iter() {
1431                    for y in $name::iter() {
1432                        for z in $name::iter() {
1433                            if x == y && y == z {
1434                                assert_eq!(x, z);
1435                            }
1436                        }
1437                    }
1438                }
1439            }
1440
1441            // We happen to have a field. The field axioms are:
1442            // 1.  Exists `+: F x F -> F` (done.)
1443            // 2.  Exists `*: F x F -> F` (done.)
1444            // 3.  For all: `x + y = y + x`.
1445            // 4.  For all: `x * y = y * x`.
1446            // 5.  For all: `x + (y + z) = (x + y) + z`
1447            // 6.  For all: `x * (y * z) = (x * y) * z`
1448            // 7.  Exists `0 in F`: For all: `x + 0 = x`.
1449            // 8.  Exists `1 in F`: For all: `x * 1 = x`.
1450            // 9.  For all: `x * (y + z) = x * y + x * z`.
1451            // 10. For all `x in F`: Exists `y in F`: `x + y = 0`
1452            // The previous 10 give us a Commutative Unital Ring
1453            // (from now on, this is just a ring). These two extra
1454            // axioms make it a field:
1455            // 11. `0 != 1`.
1456            // 12. For all `x in F`: `x != y` implies Exists `y in F`: `x * y = 1`
1457
1458            #[test]
1459            fn addition_commutes() {
1460                for x in $name::iter() {
1461                    for y in $name::iter() {
1462                        assert_eq!(x + y, y + x);
1463                    }
1464                }
1465            }
1466
1467            #[test]
1468            fn multiplication_commutes() {
1469                for x in $name::iter() {
1470                    for y in $name::iter() {
1471                        assert_eq!(x * y, y * x);
1472                    }
1473                }
1474            }
1475
1476            #[test]
1477            fn addition_associates() {
1478                for x in $name::iter() {
1479                    for y in $name::iter() {
1480                        for z in $name::iter() {
1481                            assert_eq!(x + (y + z), (x + y) + z);
1482                        }
1483                    }
1484                }
1485            }
1486
1487            #[test]
1488            fn multiplication_associates() {
1489                for x in $name::iter() {
1490                    for y in $name::iter() {
1491                        for z in $name::iter() {
1492                            assert_eq!(x * (y * z), (x * y) * z);
1493                        }
1494                    }
1495                }
1496            }
1497
1498            #[test]
1499            fn zero_is_zero() {
1500                for x in $name::iter() {
1501                    assert_eq!(x + $name::ZERO, x);
1502                }
1503            }
1504
1505            #[test]
1506            fn one_is_one() {
1507                for x in $name::iter() {
1508                    assert_eq!(x * $name::ONE, x);
1509                }
1510            }
1511
1512            #[test]
1513            fn multiplication_distributes() {
1514                for x in $name::iter() {
1515                    for y in $name::iter() {
1516                        for z in $name::iter() {
1517                            assert_eq!(x * (y + z), (x * y) + (x * z));
1518                        }
1519                    }
1520                }
1521            }
1522
1523            #[test]
1524            fn additive_inverses() {
1525                'a: for x in $name::iter() {
1526                    for y in $name::iter() {
1527                        if x + y == $name::ZERO {
1528                            continue 'a;
1529                        }
1530                    }
1531
1532                    panic!("Additive inverse for {x} not found!");
1533                }
1534            }
1535
1536            #[test]
1537            fn zero_is_not_one() {
1538                assert_ne!($name::ZERO, $name::ONE);
1539            }
1540        };
1541    }
1542
1543    make_ring! {
1544        F125 = { Z % 5, x^3 = [2, 2] };
1545        BadRingSmall = { Z % 6, x^1 = [0] };
1546        BadRing = { Z % 6, x^2 = [3, 2] };
1547        BadPoly = { Z % 5, x^2 = [4] };
1548    }
1549
1550    mod field {
1551        use super::F125;
1552        make_ring_tests! {F125, 3, 5}
1553
1554        #[test]
1555        fn multiplicative_inverse() {
1556            for x in F125::iter() {
1557                let computed_inverse = x.invert();
1558
1559                let mut found_inverse = None;
1560                for y in F125::iter() {
1561                    if x * y == F125::ONE {
1562                        found_inverse = Some(y);
1563                        break;
1564                    }
1565                }
1566
1567                assert_eq!(computed_inverse, found_inverse, "Poly: {x}");
1568
1569                if !x.is_zero() && computed_inverse.is_none() {
1570                    panic!("Multiplicative inverse for {x} not found!");
1571                }
1572            }
1573        }
1574    }
1575
1576    mod integers_bad {
1577        use super::BadRingSmall;
1578        make_ring_tests! {BadRingSmall, 1, 6}
1579
1580        #[test]
1581        fn integers_mod_bad() {
1582            for (i, val) in BadRingSmall::iter().enumerate() {
1583                assert_eq!(val, BadRingSmall::from_int(i as u64));
1584            }
1585        }
1586    }
1587
1588    mod integers_bad_poly_bad {
1589        use super::BadRing;
1590        make_ring_tests! {BadRing, 2, 6}
1591    }
1592
1593    mod poly_bad {
1594        use super::BadPoly;
1595        make_ring_tests! {BadPoly, 2, 5}
1596    }
1597}