qfall_math/integer_mod_q/poly_over_zq/
properties.rs

1// Copyright © 2023 Marvin Beckmann
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to check certain properties of [`PolyOverZq`].
10//! This includes checks such as reducibility.
11
12use super::PolyOverZq;
13use flint_sys::{
14    fmpz_mod_poly::{fmpz_mod_poly_degree, fmpz_mod_poly_is_one},
15    fmpz_mod_poly_factor::fmpz_mod_poly_is_irreducible,
16};
17
18impl PolyOverZq {
19    /// Checks if a [`PolyOverZq`] is irreducible.
20    ///
21    /// Returns `true` if the polynomial is irreducible and `false` otherwise.
22    ///
23    /// # Examples
24    /// ```
25    /// use qfall_math::integer_mod_q::PolyOverZq;
26    /// use std::str::FromStr;
27    ///
28    /// let poly_irr = PolyOverZq::from_str("2  1 1 mod 17").unwrap();
29    /// // returns true, since X + 1 is irreducible
30    /// assert!(poly_irr.is_irreducible());
31    /// ```
32    pub fn is_irreducible(&self) -> bool {
33        1 == unsafe {
34            fmpz_mod_poly_is_irreducible(&self.poly, self.modulus.get_fmpz_mod_ctx_struct())
35        }
36    }
37
38    /// Checks if a [`PolyOverZq`] is the constant polynomial with coefficient `1`.
39    ///
40    /// Returns `true` if there is only one coefficient, which is `1`.
41    ///
42    /// # Examples
43    /// ```
44    /// use qfall_math::integer_mod_q::PolyOverZq;
45    /// use std::str::FromStr;
46    ///
47    /// let value = PolyOverZq::from_str("1  1 mod 4").unwrap();
48    /// assert!(value.is_one());
49    /// ```
50    pub fn is_one(&self) -> bool {
51        1 == unsafe { fmpz_mod_poly_is_one(&self.poly, self.modulus.get_fmpz_mod_ctx_struct()) }
52    }
53
54    /// Checks if every entry of a [`PolyOverZq`] is `0`.
55    ///
56    /// Returns `true` if [`PolyOverZq`] has no coefficients.
57    ///
58    /// # Examples
59    /// ```
60    /// use qfall_math::integer_mod_q::PolyOverZq;
61    /// use std::str::FromStr;
62    ///
63    /// let value = PolyOverZq::from_str("0 mod 7").unwrap();
64    /// assert!(value.is_zero());
65    /// ```
66    pub fn is_zero(&self) -> bool {
67        -1 == unsafe { fmpz_mod_poly_degree(&self.poly, self.modulus.get_fmpz_mod_ctx_struct()) }
68    }
69}
70
71#[cfg(test)]
72mod test_is_irreducible {
73    use crate::integer_mod_q::PolyOverZq;
74    use std::str::FromStr;
75
76    /// Ensure that a irreducible [`PolyOverZq`] returns `true`.
77    #[test]
78    fn poly_is_irreducible() {
79        // 9X^2 + 12X + 10 is irreducible over 17
80        let poly_irr = PolyOverZq::from_str("3  10 12 9 mod 17").unwrap();
81        assert!(poly_irr.is_irreducible());
82    }
83
84    /// Ensure that a reducible [`PolyOverZq`] returns `false`.
85    #[test]
86    fn poly_is_reducible() {
87        let poly_irr = PolyOverZq::from_str("3  1 2 1 mod 17").unwrap();
88        assert!(!poly_irr.is_irreducible());
89    }
90}
91
92#[cfg(test)]
93mod test_is_one {
94    use super::PolyOverZq;
95    use std::str::FromStr;
96
97    /// Ensure that is_one returns `true` for the one polynomial.
98    #[test]
99    fn one_detection() {
100        let one = PolyOverZq::from_str("1  1 mod 7").unwrap();
101        let one_2 = PolyOverZq::from_str("2  1 14 mod 7").unwrap();
102
103        assert!(one.is_one());
104        assert!(one_2.is_one());
105    }
106
107    /// Ensure that is_one returns `false` for other polynomials.
108    #[test]
109    fn one_rejection() {
110        let small = PolyOverZq::from_str("4  1 0 0 1 mod 7").unwrap();
111        let large =
112            PolyOverZq::from_str(&format!("1  {} mod {}", (u128::MAX - 1) / 2 + 2, u128::MAX)) // 2^127 + 1 the last memory entry is `1`
113                .unwrap();
114
115        assert!(!small.is_one());
116        assert!(!large.is_one());
117    }
118}
119
120#[cfg(test)]
121mod test_is_zero {
122    use super::PolyOverZq;
123    use std::str::FromStr;
124
125    /// Ensure that is_zero returns `true` for the zero polynomial.
126    #[test]
127    fn zero_detection() {
128        let zero = PolyOverZq::from_str("0 mod 7").unwrap();
129        let zero_2 = PolyOverZq::from_str("2  7 14 mod 7").unwrap();
130
131        assert!(zero.is_zero());
132        assert!(zero_2.is_zero());
133    }
134
135    /// Ensure that is_zero returns `false` for non-zero polynomials.
136    #[test]
137    fn zero_rejection() {
138        let small = PolyOverZq::from_str("4  0 0 0 1 mod 7").unwrap();
139        let large =
140            PolyOverZq::from_str(&format!("1  {} mod {}", (u128::MAX - 1) / 2 + 1, u128::MAX)) // last 126 bits are 0
141                .unwrap();
142
143        assert!(!small.is_zero());
144        assert!(!large.is_zero());
145    }
146}