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}