code_rs/coding/
galois.rs

1//! Galois field arithmetic for codewords and polynomials.
2
3use std;
4
5use collect_slice::CollectSlice;
6
7/// Codeword in the P25 Galois field.
8pub type P25Codeword = Codeword<P25Field>;
9
10/// GF(2<sup>6</sup>) field characterized by α<sup>6</sup>+α+1, as described in the P25
11/// specification.
12#[derive(Copy, Clone, Debug)]
13pub struct P25Field;
14
15impl GaloisField for P25Field {
16    fn size() -> usize {
17        63
18    }
19    fn valid_codeword(bits: u8) -> bool {
20        bits >> 6 == 0
21    }
22
23    fn codeword(pow: usize) -> u8 {
24        // Each codeword α^i represents the polynomial x^i mod h(x), where P25 uses h(x) =
25        // x^6 + x + 1.
26        const CODEWORDS: [u8; 63] = [
27            0b000001, 0b000010, 0b000100, 0b001000, 0b010000, 0b100000, 0b000011, 0b000110,
28            0b001100, 0b011000, 0b110000, 0b100011, 0b000101, 0b001010, 0b010100, 0b101000,
29            0b010011, 0b100110, 0b001111, 0b011110, 0b111100, 0b111011, 0b110101, 0b101001,
30            0b010001, 0b100010, 0b000111, 0b001110, 0b011100, 0b111000, 0b110011, 0b100101,
31            0b001001, 0b010010, 0b100100, 0b001011, 0b010110, 0b101100, 0b011011, 0b110110,
32            0b101111, 0b011101, 0b111010, 0b110111, 0b101101, 0b011001, 0b110010, 0b100111,
33            0b001101, 0b011010, 0b110100, 0b101011, 0b010101, 0b101010, 0b010111, 0b101110,
34            0b011111, 0b111110, 0b111111, 0b111101, 0b111001, 0b110001, 0b100001,
35        ];
36
37        CODEWORDS[pow]
38    }
39
40    fn power(codeword: usize) -> usize {
41        const POWERS: [usize; 63] = [
42            0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18, 4, 24, 33, 16, 14, 52, 36, 54, 9,
43            45, 49, 38, 28, 41, 19, 56, 5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55,
44            40, 10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58,
45        ];
46
47        POWERS[codeword]
48    }
49}
50
51/// A GF(2<sup>r</sup>) Galois field.
52pub trait GaloisField {
53    /// Number of unique codewords in the field: 2<sup>r</sup> - 1.
54    fn size() -> usize;
55    /// Check if the given bit pattern is a valid codeword in the field.
56    fn valid_codeword(bits: u8) -> bool;
57    /// Map the given power i to codeword α<sup>i</sup>.
58    fn codeword(pow: usize) -> u8;
59    /// Map the given codeword a<sup>i</sup> to its power i.
60    fn power(codeword: usize) -> usize;
61
62    /// Map the given power i to codeword α<sup>m</sup> ≡ α<sup>i</sup> (modulo the size
63    /// of the field.)
64    fn codeword_modded(pow: usize) -> u8 {
65        Self::codeword(pow % Self::size())
66    }
67}
68
69/// Codeword in a Galois field.
70#[derive(Copy, Clone)]
71pub struct Codeword<F: GaloisField> {
72    field: std::marker::PhantomData<F>,
73    bits: u8,
74}
75
76impl<F: GaloisField> Codeword<F> {
77    /// Construct a new `Codeword` α<sup>i</sup> from the given bit pattern. Panic if the
78    /// pattern is invalid in the field.
79    pub fn new(bits: u8) -> Codeword<F> {
80        assert!(F::valid_codeword(bits));
81
82        Codeword {
83            field: std::marker::PhantomData,
84            bits: bits,
85        }
86    }
87
88    /// Construct a new `Codeword` α<sup>m</sup> ≡ α<sup>i</sup> (modulo the field) for
89    /// the given power i.
90    pub fn for_power(power: usize) -> Codeword<F> {
91        Codeword::new(F::codeword_modded(power))
92    }
93
94    /// Retrieve the bit pattern of the codeword.
95    pub fn bits(&self) -> u8 {
96        self.bits
97    }
98
99    /// Check if the codeword is zero.
100    pub fn zero(&self) -> bool {
101        self.bits == 0
102    }
103
104    /// Retrieve the power i of the current codeword α<sup>i</sup>. Return `Some(i)` if
105    /// the power is defined and `None` if the codeword is zero.
106    pub fn power(&self) -> Option<usize> {
107        if self.zero() {
108            None
109        } else {
110            // Convert to zero-based index.
111            Some(F::power(self.bits as usize - 1))
112        }
113    }
114
115    /// Find 1/α<sup>i</sup> for the current codeword α<sup>i</sup>. Panic if the codeword
116    /// is zero.
117    pub fn invert(self) -> Codeword<F> {
118        match self.power() {
119            Some(p) => Codeword::for_power(F::size() - p),
120            None => panic!("invert zero"),
121        }
122    }
123
124    /// Compute (α<sup>i</sup>)<sup>p</sup> for the current codeword α<sup>i</sup> and
125    /// given power p.
126    pub fn pow(&self, pow: usize) -> Codeword<F> {
127        match self.power() {
128            Some(p) => Codeword::for_power(p * pow),
129            None => Codeword::default(),
130        }
131    }
132}
133
134impl<F: GaloisField> Default for Codeword<F> {
135    /// Construct the additive identity codeword α<sup>0</sup> = 1.
136    fn default() -> Self {
137        Codeword::new(0)
138    }
139}
140
141/// Add codewords using Galois addition.
142impl<F: GaloisField> std::ops::Add for Codeword<F> {
143    type Output = Codeword<F>;
144
145    fn add(self, rhs: Codeword<F>) -> Self::Output {
146        Codeword::new(self.bits ^ rhs.bits)
147    }
148}
149
150/// "Subtract" codewords, which is equivalent to addition.
151impl<F: GaloisField> std::ops::Sub for Codeword<F> {
152    type Output = Codeword<F>;
153
154    fn sub(self, rhs: Codeword<F>) -> Self::Output {
155        self + rhs
156    }
157}
158
159/// Mutiply codewords using Galois multiplication.
160impl<F: GaloisField> std::ops::Mul for Codeword<F> {
161    type Output = Codeword<F>;
162
163    fn mul(self, rhs: Codeword<F>) -> Self::Output {
164        match (self.power(), rhs.power()) {
165            (Some(p), Some(q)) => Codeword::for_power(p + q),
166            _ => Codeword::default(),
167        }
168    }
169}
170
171/// Divide codewords using Galois division. Panic if the divisor is zero.
172impl<F: GaloisField> std::ops::Div for Codeword<F> {
173    type Output = Codeword<F>;
174
175    fn div(self, rhs: Codeword<F>) -> Self::Output {
176        match (self.power(), rhs.power()) {
177            // Ensure non-negative power.
178            (Some(p), Some(q)) => Codeword::for_power(F::size() + p - q),
179            (None, Some(_)) => Codeword::default(),
180            (_, None) => panic!("divide by zero"),
181        }
182    }
183}
184
185/// Check equality of two codewords.
186impl<F: GaloisField> std::cmp::PartialEq for Codeword<F> {
187    fn eq(&self, other: &Self) -> bool {
188        self.bits == other.bits
189    }
190}
191
192impl<F: GaloisField> std::cmp::Eq for Codeword<F> {}
193
194/// Check equality of the codeword's bit pattern with raw bits.
195impl<F: GaloisField> std::cmp::PartialEq<u8> for Codeword<F> {
196    fn eq(&self, other: &u8) -> bool {
197        self.bits == *other
198    }
199}
200
201impl<F: GaloisField> std::fmt::Debug for Codeword<F> {
202    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
203        match self.power() {
204            Some(p) => write!(fmt, "Codeword::for_power({})", p),
205            None => write!(fmt, "Codeword::default()"),
206        }
207    }
208}
209
210/// Coefficient storage for a bounded-degree Galois polynomial of a particular code.
211pub trait PolynomialCoefs:
212    Default + Copy + Clone + std::ops::Deref<Target = [P25Codeword]> + std::ops::DerefMut
213{
214    /// The minimum Hamming distance, d, in (n,k,d).
215    fn distance() -> usize;
216
217    /// Maximum number of correctable errors: t.
218    fn errors() -> usize {
219        // Since d is odd, d = 2t+1 ⇒ t = (d-1)/2 = floor(d / 2). Formula taken from [1,
220        // p135-137].
221        Self::distance() / 2
222    }
223
224    /// Number of syndromes: 2t.
225    fn syndromes() -> usize {
226        2 * Self::errors()
227    }
228
229    /// Verify the implementer is well-formed.
230    fn validate(&self) {
231        // Distance must be odd.
232        assert!(Self::distance() % 2 == 1);
233        // Storage must at least be able to hold the polynomials used in the
234        // Berlekamp-Massey algorithm.
235        assert!(self.len() > Self::syndromes());
236    }
237}
238
239/// Create a coefficient storage buffer for the code of given distance. In the first form,
240/// the polynomial is large enough to store the Berlekamp-Massey decoding polynomials. In
241/// the second form, the polynomial has the given size.
242macro_rules! impl_polynomial_coefs {
243    ($name:ident, $dist:expr) => {
244        impl_polynomial_coefs!($name, $dist, $dist + 1);
245    };
246    ($name:ident, $dist:expr, $len:expr) => {
247        #[derive(Copy)]
248        struct $name([P25Codeword; $len]);
249
250        impl PolynomialCoefs for $name {
251            fn distance() -> usize {
252                $dist
253            }
254        }
255
256        impl Default for $name {
257            fn default() -> Self {
258                $name([P25Codeword::default(); $len])
259            }
260        }
261
262        impl Clone for $name {
263            fn clone(&self) -> Self {
264                let mut coefs = [P25Codeword::default(); $len];
265                coefs.copy_from_slice(&self.0[..]);
266                $name(coefs)
267            }
268        }
269
270        impl std::ops::Deref for $name {
271            type Target = [P25Codeword];
272            fn deref(&self) -> &Self::Target {
273                &self.0[..]
274            }
275        }
276
277        impl std::ops::DerefMut for $name {
278            fn deref_mut(&mut self) -> &mut Self::Target {
279                &mut self.0[..]
280            }
281        }
282    };
283}
284
285/// Polynomial with P25's GF(2<sup>6</sup>) codewords as coefficients.
286#[derive(Copy, Clone)]
287pub struct Polynomial<P: PolynomialCoefs> {
288    /// Coefficients of the polynomial. The maximum degree span in the algorithm is [0,
289    /// 2t+1], or 2t+2 coefficients.
290    coefs: P,
291    /// Index into `coefs` of the degree-0 coefficient. Coefficients with a lesser index
292    /// will be zero.
293    start: usize,
294}
295
296impl<P: PolynomialCoefs> Polynomial<P> {
297    /// Construct a new `Polynomial` from the given coefficients c<sub>0</sub>, ...,
298    /// c<sub>k</sub>.
299    ///
300    /// The resulting polynomial has the form p(x) = c<sub>0</sub> + c<sub>1</sub>x + ···
301    /// + c<sub>k</sub>x<sup>k</sup>.
302    pub fn new<T: Iterator<Item = P25Codeword>>(mut init: T) -> Self {
303        // Start with all zero coefficients and add in the given ones.
304        let mut coefs = P::default();
305        init.collect_slice_exhaust(&mut coefs[..]);
306
307        Self::with_coefs(coefs)
308    }
309
310    /// Construct a new `Polynomial` with the single term p(x) = x<sup>n</sup>.
311    pub fn unit_power(n: usize) -> Self {
312        let mut coefs = P::default();
313        coefs[n] = Codeword::for_power(0);
314
315        Self::with_coefs(coefs)
316    }
317
318    /// Construct a new `Polynomial` with the given polynomials.
319    fn with_coefs(coefs: P) -> Self {
320        Polynomial { coefs, start: 0 }
321    }
322
323    /// Retrieve the degree-0 coefficient, c<sub>0</sub>.
324    pub fn constant(&self) -> P25Codeword {
325        self.coefs[self.start]
326    }
327
328    /// Compute deg(p(x)), returned as `Some(deg)` if the polynomial is nonzero, or
329    /// `None` if p(x) = 0.
330    ///
331    /// Note this is a O(n) operation.
332    pub fn degree(&self) -> Option<usize> {
333        for (deg, coef) in self.coefs.iter().enumerate().rev() {
334            if !coef.zero() {
335                // Any coefficients before `start` aren't part of the polynomial.
336                return Some(deg - self.start);
337            }
338        }
339
340        None
341    }
342
343    /// Divide the polynomial by x -- shift all coefficients to a lower degree. Panic if
344    /// c<sub>0</sub> ≠ 0.
345    ///
346    /// This is a O(1) operation.
347    pub fn shift(mut self) -> Polynomial<P> {
348        assert!(self.constant().zero());
349
350        self.coefs[self.start] = P25Codeword::default();
351        self.start += 1;
352        self
353    }
354
355    /// Retrieve the coefficient at the given absolute index into the storage buffer, or 0
356    /// if the index is out of bounds.
357    fn get(&self, idx: usize) -> P25Codeword {
358        match self.coefs.get(idx) {
359            Some(&c) => c,
360            None => P25Codeword::default(),
361        }
362    }
363
364    /// Retrieve the coefficient c<sub>i</sub> associated with the x<sup>i</sup> term.
365    ///
366    /// If i > deg(p(x)), 0 is returned.
367    pub fn coef(&self, i: usize) -> P25Codeword {
368        self.get(self.start + i)
369    }
370
371    /// Evaluate p(x), substituting in the given x.
372    pub fn eval(&self, x: P25Codeword) -> P25Codeword {
373        // This uses Horner's method which, unlike the naive method, doesn't require a
374        // call to `pow()` at each term.
375        self.iter()
376            .rev()
377            .fold(P25Codeword::default(), |s, &coef| s * x + coef)
378    }
379
380    /// Truncate the polynomial so that deg(p(x)) ≤ d, where d is the given degree.
381    ///
382    /// This is a O(n) operation.
383    pub fn truncate(mut self, deg: usize) -> Polynomial<P> {
384        for i in (self.start + deg + 1)..self.coefs.len() {
385            self.coefs[i] = P25Codeword::default();
386        }
387
388        self
389    }
390
391    /// Compute the formal derivative p'(x).
392    pub fn deriv(mut self) -> Polynomial<P> {
393        for i in self.start..self.coefs.len() {
394            self.coefs[i] = if (i - self.start) % 2 == 0 {
395                self.get(i + 1)
396            } else {
397                P25Codeword::default()
398            };
399        }
400
401        self
402    }
403}
404
405impl<P: PolynomialCoefs> Default for Polynomial<P> {
406    /// Construct an empty polynomial, p(x) = 0.
407    fn default() -> Self {
408        Polynomial::new(std::iter::empty())
409    }
410}
411
412/// Provides a slice of coefficients starting at the degree-0 term, [c<sub>0</sub>,
413/// c<sub>1</sub>, ...].
414impl<P: PolynomialCoefs> std::ops::Deref for Polynomial<P> {
415    type Target = [P25Codeword];
416    fn deref(&self) -> &Self::Target {
417        &self.coefs[self.start..]
418    }
419}
420
421impl<P: PolynomialCoefs> std::ops::DerefMut for Polynomial<P> {
422    fn deref_mut(&mut self) -> &mut Self::Target {
423        &mut self.coefs[self.start..]
424    }
425}
426
427/// Add polynomials using Galois addition for coefficients.
428impl<P: PolynomialCoefs> std::ops::Add for Polynomial<P> {
429    type Output = Polynomial<P>;
430
431    fn add(mut self, rhs: Polynomial<P>) -> Self::Output {
432        // Sum the coefficients and reset the degree-0 term back to index 0.
433        //
434        // Since start >= 0 => start+i >= i, so there's no overwriting.
435        for i in 0..self.coefs.len() {
436            self.coefs[i] = self.coef(i) + rhs.coef(i);
437        }
438
439        self.start = 0;
440        self
441    }
442}
443
444/// Scale polynomial by a codeword.
445impl<P: PolynomialCoefs> std::ops::Mul<P25Codeword> for Polynomial<P> {
446    type Output = Polynomial<P>;
447
448    fn mul(mut self, rhs: P25Codeword) -> Self::Output {
449        for coef in self.coefs.iter_mut() {
450            *coef = *coef * rhs;
451        }
452
453        self
454    }
455}
456
457/// Multiply polynomials using Galois multiplication for coefficients.
458///
459/// Note that resulting terms outside the bounds of the polynomial are silently discarded,
460/// effectively computing p(x)q(x) mod x<sup>n+1</sup>, where n is the maximum degree
461/// supported by the polynomial.
462impl<P: PolynomialCoefs> std::ops::Mul<Polynomial<P>> for Polynomial<P> {
463    type Output = Polynomial<P>;
464
465    fn mul(self, rhs: Polynomial<P>) -> Self::Output {
466        let mut out = Polynomial::<P>::default();
467
468        for (i, &coef) in self.iter().enumerate() {
469            for (j, &mult) in rhs.iter().enumerate() {
470                if let Some(c) = out.coefs.get_mut(i + j) {
471                    *c = *c + coef * mult
472                }
473            }
474        }
475
476        out
477    }
478}
479
480impl<P: PolynomialCoefs> std::fmt::Debug for Polynomial<P> {
481    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
482        write!(fmt, "Polynomial({:?})", &self.coefs[..])
483    }
484}
485
486#[cfg(test)]
487mod test {
488    use super::*;
489    use std;
490
491    impl_polynomial_coefs!(TestCoefs, 23);
492    type TestPolynomial = Polynomial<TestCoefs>;
493
494    impl_polynomial_coefs!(ShortCoefs, 5);
495    type ShortPolynomial = Polynomial<ShortCoefs>;
496
497    #[test]
498    fn test_coefs() {
499        assert_eq!(TestCoefs::errors(), 11);
500        assert_eq!(TestCoefs::syndromes(), 22);
501    }
502
503    #[test]
504    fn test_for_power() {
505        assert!(P25Codeword::for_power(0) == 0b000001);
506        assert!(P25Codeword::for_power(62) == 0b100001);
507        assert!(P25Codeword::for_power(63) == 0b000001);
508    }
509
510    #[test]
511    fn test_add_sub() {
512        assert!((P25Codeword::new(0b100000) + P25Codeword::new(0b010000)) == 0b110000);
513        assert!((P25Codeword::new(0b100000) - P25Codeword::new(0b010000)) == 0b110000);
514        assert!((P25Codeword::new(0b100001) + P25Codeword::new(0b100001)) == 0b000000);
515        assert!((P25Codeword::new(0b100001) - P25Codeword::new(0b100001)) == 0b000000);
516        assert!((P25Codeword::new(0b100001) + P25Codeword::new(0b110100)) == 0b010101);
517        assert!((P25Codeword::new(0b100001) - P25Codeword::new(0b110100)) == 0b010101);
518    }
519
520    #[test]
521    fn test_mul() {
522        assert!((P25Codeword::new(0b000110) * P25Codeword::new(0b000101)) == 0b011110);
523        assert!((P25Codeword::new(0b000000) * P25Codeword::new(0b000101)) == 0b000000);
524        assert!((P25Codeword::new(0b000110) * P25Codeword::new(0b000000)) == 0b000000);
525        assert!((P25Codeword::new(0b000000) * P25Codeword::new(0b000000)) == 0b000000);
526        assert!((P25Codeword::new(0b100001) * P25Codeword::new(0b000001)) == 0b100001);
527        assert!((P25Codeword::new(0b100001) * P25Codeword::new(0b000010)) == 0b000001);
528        assert!((P25Codeword::new(0b110011) * P25Codeword::new(0b110011)) == 0b111001);
529        assert!((P25Codeword::new(0b101111) * P25Codeword::new(0b101111)) == 0b100110);
530    }
531
532    #[test]
533    fn test_div() {
534        assert!((P25Codeword::new(0b001000) / P25Codeword::new(0b000101)) == 0b010111);
535        assert!((P25Codeword::new(0b000000) / P25Codeword::new(0b101000)) == 0b000000);
536        assert!((P25Codeword::new(0b011110) / P25Codeword::new(0b000001)) == 0b011110);
537        assert!((P25Codeword::new(0b011110) / P25Codeword::new(0b011110)) == 0b000001);
538    }
539
540    #[test]
541    fn test_cmp() {
542        assert!(P25Codeword::new(0b000000) == P25Codeword::new(0b000000));
543    }
544
545    #[test]
546    fn test_pow() {
547        assert_eq!(P25Codeword::for_power(0).pow(10).power().unwrap(), 0);
548        assert_eq!(P25Codeword::for_power(1).pow(10).power().unwrap(), 10);
549        assert_eq!(P25Codeword::for_power(62).pow(10).power().unwrap(), 53);
550        assert!(P25Codeword::default().pow(20).power().is_none());
551    }
552
553    #[test]
554    fn test_eval() {
555        let p = TestPolynomial::new((0..3).map(|_| P25Codeword::for_power(0)));
556        assert!(p.eval(P25Codeword::for_power(1)) == 0b000111);
557
558        let p = TestPolynomial::new((0..2).map(|_| P25Codeword::for_power(0)));
559        assert_eq!(p.eval(P25Codeword::for_power(1)), 0b000011);
560
561        let p = TestPolynomial::new(
562            [
563                P25Codeword::default(),
564                P25Codeword::default(),
565                P25Codeword::default(),
566                P25Codeword::for_power(0),
567            ]
568            .iter()
569            .cloned(),
570        );
571        assert_eq!(p.eval(P25Codeword::for_power(3)), 0b011000);
572
573        let p = TestPolynomial::new(
574            [
575                P25Codeword::default(),
576                P25Codeword::for_power(0),
577                P25Codeword::default(),
578                P25Codeword::for_power(0),
579            ]
580            .iter()
581            .cloned(),
582        );
583        assert_eq!(p.eval(P25Codeword::for_power(3)), 0b010000);
584
585        let p = TestPolynomial::new(
586            [
587                P25Codeword::default(),
588                P25Codeword::default(),
589                P25Codeword::default(),
590                P25Codeword::default(),
591                P25Codeword::default(),
592                P25Codeword::default(),
593                P25Codeword::default(),
594                P25Codeword::default(),
595                P25Codeword::default(),
596                P25Codeword::default(),
597                P25Codeword::default(),
598                P25Codeword::default(),
599                P25Codeword::default(),
600                P25Codeword::default(),
601                P25Codeword::default(),
602                P25Codeword::default(),
603                P25Codeword::default(),
604                P25Codeword::default(),
605                P25Codeword::default(),
606                P25Codeword::default(),
607                P25Codeword::default(),
608                P25Codeword::default(),
609                P25Codeword::default(),
610                P25Codeword::for_power(5),
611            ]
612            .iter()
613            .cloned(),
614        );
615        assert_eq!(p.eval(P25Codeword::for_power(4)), 0b100100);
616
617        let p = TestPolynomial::new(
618            [
619                P25Codeword::for_power(12),
620                P25Codeword::default(),
621                P25Codeword::default(),
622                P25Codeword::default(),
623                P25Codeword::default(),
624                P25Codeword::default(),
625                P25Codeword::default(),
626                P25Codeword::default(),
627                P25Codeword::default(),
628                P25Codeword::default(),
629                P25Codeword::default(),
630                P25Codeword::default(),
631                P25Codeword::default(),
632                P25Codeword::default(),
633                P25Codeword::default(),
634                P25Codeword::default(),
635                P25Codeword::default(),
636                P25Codeword::default(),
637                P25Codeword::default(),
638                P25Codeword::default(),
639                P25Codeword::default(),
640                P25Codeword::default(),
641                P25Codeword::default(),
642                P25Codeword::for_power(5),
643            ]
644            .iter()
645            .cloned(),
646        );
647        assert_eq!(p.eval(P25Codeword::for_power(4)), 0b100001);
648
649        let p = TestPolynomial::new(
650            [
651                P25Codeword::for_power(0),
652                P25Codeword::for_power(0),
653                P25Codeword::for_power(0),
654                P25Codeword::for_power(0),
655                P25Codeword::for_power(0),
656                P25Codeword::for_power(0),
657                P25Codeword::for_power(0),
658                P25Codeword::for_power(0),
659                P25Codeword::for_power(0),
660                P25Codeword::for_power(0),
661                P25Codeword::for_power(0),
662                P25Codeword::for_power(0),
663                P25Codeword::for_power(0),
664                P25Codeword::for_power(0),
665                P25Codeword::for_power(0),
666                P25Codeword::for_power(0),
667                P25Codeword::for_power(0),
668                P25Codeword::for_power(0),
669                P25Codeword::for_power(0),
670                P25Codeword::for_power(0),
671                P25Codeword::for_power(0),
672                P25Codeword::for_power(0),
673                P25Codeword::for_power(0),
674                P25Codeword::for_power(0),
675            ]
676            .iter()
677            .cloned(),
678        );
679        assert!(p.eval(P25Codeword::for_power(0)).zero());
680    }
681
682    #[test]
683    fn test_truncate() {
684        let p = TestPolynomial::new((0..5).map(|_| P25Codeword::for_power(0)));
685
686        assert_eq!(p.degree().unwrap(), 4);
687        assert_eq!(p.coefs[4].power().unwrap(), 0);
688        assert!(p.coefs[5].power().is_none());
689
690        let p = p.truncate(2);
691        assert_eq!(p.degree().unwrap(), 2);
692        assert_eq!(p.coefs[2].power().unwrap(), 0);
693        assert!(p.coefs[3].power().is_none());
694    }
695
696    #[test]
697    fn test_polynomial() {
698        let p = TestPolynomial::new((0..23).map(P25Codeword::for_power));
699
700        assert!(p.degree().unwrap() == 22);
701        assert!(p.constant() == P25Codeword::for_power(0));
702
703        let p = TestPolynomial::new((1..23).map(P25Codeword::for_power));
704        assert!(p.degree().unwrap() == 21);
705        assert!(p.constant() == P25Codeword::for_power(1));
706
707        let q = p * P25Codeword::for_power(0);
708        assert!(q.degree().unwrap() == 21);
709        assert!(q.constant() == P25Codeword::for_power(1));
710
711        let q = p * P25Codeword::for_power(2);
712        assert!(q.degree().unwrap() == 21);
713        assert!(q.constant() == P25Codeword::for_power(3));
714
715        let q = p + p;
716        assert!(q.constant().zero());
717
718        for coef in q.iter() {
719            assert!(coef.zero());
720        }
721
722        let p = TestPolynomial::new((4..27).map(P25Codeword::for_power));
723
724        let q = TestPolynomial::new((4..26).map(P25Codeword::for_power));
725
726        let r = p + q;
727
728        assert!(r.coefs[0].zero());
729        assert!(r.coefs[1].zero());
730        assert!(r.coefs[2].zero());
731        assert!(r.coefs[3].zero());
732        assert!(r.coefs[4].zero());
733        assert!(!r.coefs[22].zero());
734
735        let p = TestPolynomial::new((0..2).map(|_| P25Codeword::for_power(0)));
736
737        let q = TestPolynomial::new((0..4).map(|_| P25Codeword::for_power(1)));
738
739        let r = p + q;
740
741        assert!(r.coef(0) == P25Codeword::for_power(6));
742    }
743
744    #[test]
745    fn test_poly_mul() {
746        let p = TestPolynomial::new((0..2).map(|_| P25Codeword::for_power(0)));
747
748        let q = p;
749        let r = p * q;
750
751        assert_eq!(r.coef(0).power().unwrap(), 0);
752        assert!(r.coef(1).power().is_none());
753        assert_eq!(r.coef(2).power().unwrap(), 0);
754
755        let p = TestPolynomial::new((0..3).map(P25Codeword::for_power));
756        let q = TestPolynomial::new(
757            [P25Codeword::default(), P25Codeword::for_power(0)]
758                .iter()
759                .cloned(),
760        );
761        let r = p * q;
762
763        assert!(r.coef(0).power().is_none());
764        assert_eq!(r.coef(1).power().unwrap(), 0);
765        assert_eq!(r.coef(2).power().unwrap(), 1);
766        assert_eq!(r.coef(3).power().unwrap(), 2);
767    }
768
769    #[test]
770    fn test_deriv() {
771        let p = TestPolynomial::new(
772            [
773                P25Codeword::for_power(0),
774                P25Codeword::for_power(3),
775                P25Codeword::for_power(58),
776            ]
777            .into_iter(),
778        );
779
780        let q = p.deriv();
781
782        assert!(q.coefs[0] == P25Codeword::for_power(3));
783        assert!(q.coefs[1] == P25Codeword::default());
784        assert!(q.coefs[2] == P25Codeword::default());
785
786        let p = TestPolynomial::new(
787            [
788                P25Codeword::default(),
789                P25Codeword::for_power(5),
790                P25Codeword::for_power(3),
791                P25Codeword::for_power(58),
792            ]
793            .into_iter(),
794        );
795
796        let q = p.shift().deriv();
797
798        assert!(q.coef(0) == P25Codeword::for_power(3));
799        assert!(q.coef(1) == P25Codeword::default());
800        assert!(q.coef(2) == P25Codeword::default());
801
802        let p = TestPolynomial::new(
803            [
804                P25Codeword::for_power(0),
805                P25Codeword::for_power(5),
806                P25Codeword::for_power(3),
807                P25Codeword::for_power(58),
808            ]
809            .into_iter(),
810        )
811        .deriv();
812
813        assert!(p.coef(0) == P25Codeword::for_power(5));
814        assert!(p.coef(1) == P25Codeword::default());
815        assert!(p.coef(2) == P25Codeword::for_power(58));
816        assert!(p.coef(3) == P25Codeword::default());
817        assert!(p.coef(4) == P25Codeword::default());
818
819        let p = TestPolynomial::new(
820            [
821                P25Codeword::for_power(0),
822                P25Codeword::for_power(5),
823                P25Codeword::for_power(3),
824                P25Codeword::for_power(58),
825                P25Codeword::for_power(43),
826            ]
827            .into_iter(),
828        )
829        .deriv();
830
831        assert!(p.coef(0) == P25Codeword::for_power(5));
832        assert!(p.coef(1) == P25Codeword::default());
833        assert!(p.coef(2) == P25Codeword::for_power(58));
834        assert!(p.coef(3) == P25Codeword::default());
835        assert!(p.coef(4) == P25Codeword::default());
836        assert!(p.coef(5) == P25Codeword::default());
837
838        let p = TestPolynomial::new(
839            [
840                P25Codeword::for_power(0),
841                P25Codeword::for_power(5),
842                P25Codeword::for_power(3),
843                P25Codeword::for_power(58),
844                P25Codeword::for_power(43),
845                P25Codeword::for_power(15),
846            ]
847            .into_iter(),
848        )
849        .deriv();
850
851        assert!(p.coef(0) == P25Codeword::for_power(5));
852        assert!(p.coef(1) == P25Codeword::default());
853        assert!(p.coef(2) == P25Codeword::for_power(58));
854        assert!(p.coef(3) == P25Codeword::default());
855        assert!(p.coef(4) == P25Codeword::for_power(15));
856        assert!(p.coef(5) == P25Codeword::default());
857
858        let p = ShortPolynomial::new(
859            [
860                P25Codeword::for_power(0),
861                P25Codeword::for_power(5),
862                P25Codeword::for_power(3),
863                P25Codeword::for_power(58),
864                P25Codeword::for_power(43),
865            ]
866            .into_iter(),
867        )
868        .deriv();
869
870        assert!(p.coef(0) == P25Codeword::for_power(5));
871        assert!(p.coef(1) == P25Codeword::default());
872        assert!(p.coef(2) == P25Codeword::for_power(58));
873        assert!(p.coef(3) == P25Codeword::default());
874        assert!(p.coef(4) == P25Codeword::default());
875
876        let p = TestPolynomial::new(
877            [
878                P25Codeword::for_power(0),
879                P25Codeword::for_power(5),
880                P25Codeword::for_power(3),
881                P25Codeword::for_power(58),
882                P25Codeword::for_power(43),
883                P25Codeword::for_power(15),
884                P25Codeword::for_power(5),
885                P25Codeword::for_power(3),
886                P25Codeword::for_power(58),
887                P25Codeword::for_power(43),
888                P25Codeword::for_power(15),
889                P25Codeword::for_power(5),
890                P25Codeword::for_power(3),
891                P25Codeword::for_power(58),
892                P25Codeword::for_power(43),
893                P25Codeword::for_power(15),
894                P25Codeword::for_power(5),
895                P25Codeword::for_power(3),
896                P25Codeword::for_power(58),
897                P25Codeword::for_power(43),
898                P25Codeword::for_power(15),
899                P25Codeword::for_power(5),
900                P25Codeword::for_power(3),
901                P25Codeword::for_power(58),
902            ]
903            .into_iter(),
904        )
905        .deriv();
906
907        assert!(p.coef(0) == P25Codeword::for_power(5));
908        assert!(p.coef(1) == P25Codeword::default());
909        assert!(p.coef(2) == P25Codeword::for_power(58));
910        assert!(p.coef(3) == P25Codeword::default());
911        assert!(p.coef(4) == P25Codeword::for_power(15));
912        assert!(p.coef(5) == P25Codeword::default());
913        assert!(p.coef(6) == P25Codeword::for_power(3));
914        assert!(p.coef(7) == P25Codeword::default());
915        assert!(p.coef(8) == P25Codeword::for_power(43));
916        assert!(p.coef(9) == P25Codeword::default());
917        assert!(p.coef(10) == P25Codeword::for_power(5));
918        assert!(p.coef(11) == P25Codeword::default());
919        assert!(p.coef(12) == P25Codeword::for_power(58));
920        assert!(p.coef(13) == P25Codeword::default());
921        assert!(p.coef(14) == P25Codeword::for_power(15));
922        assert!(p.coef(15) == P25Codeword::default());
923        assert!(p.coef(16) == P25Codeword::for_power(3));
924        assert!(p.coef(17) == P25Codeword::default());
925        assert!(p.coef(18) == P25Codeword::for_power(43));
926        assert!(p.coef(19) == P25Codeword::default());
927        assert!(p.coef(20) == P25Codeword::for_power(5));
928        assert!(p.coef(21) == P25Codeword::default());
929        assert!(p.coef(22) == P25Codeword::for_power(58));
930        assert!(p.coef(23) == P25Codeword::default());
931        assert!(p.coef(24) == P25Codeword::default());
932    }
933
934    #[test]
935    fn test_unit_power() {
936        let p = TestPolynomial::unit_power(0);
937        assert_eq!(p[0], Codeword::for_power(0));
938        assert_eq!(p.degree().unwrap(), 0);
939
940        let p = TestPolynomial::unit_power(2);
941        assert_eq!(p[0], Codeword::default());
942        assert_eq!(p[1], Codeword::default());
943        assert_eq!(p[2], Codeword::for_power(0));
944        assert_eq!(p.degree().unwrap(), 2);
945
946        let p = TestPolynomial::unit_power(10);
947        assert_eq!(p[0], Codeword::default());
948        assert_eq!(p[1], Codeword::default());
949        assert_eq!(p[2], Codeword::default());
950        assert_eq!(p[3], Codeword::default());
951        assert_eq!(p[4], Codeword::default());
952        assert_eq!(p[5], Codeword::default());
953        assert_eq!(p[6], Codeword::default());
954        assert_eq!(p[7], Codeword::default());
955        assert_eq!(p[8], Codeword::default());
956        assert_eq!(p[9], Codeword::default());
957        assert_eq!(p[10], Codeword::for_power(0));
958        assert_eq!(p.degree().unwrap(), 10);
959    }
960}