qfall_math/integer/poly_over_z/
cmp.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 compare [`PolyOverZ`] with other values.
10//! This uses the traits from [`std::cmp`].
11
12use crate::{integer::Z, traits::CompareBase};
13use flint_sys::fmpz_poly::fmpz_poly_equal;
14
15use super::PolyOverZ;
16
17impl PartialEq for PolyOverZ {
18    /// Checks if two polynomials over [`Z`](crate::integer::Z) are equal. Used by the `==` and `!=` operators.
19    ///
20    /// Parameters:
21    /// - `other`: the other value that is used to compare the elements
22    ///
23    /// Returns `true` if the elements are equal, otherwise `false`.
24    ///
25    /// # Examples
26    /// ```
27    /// use qfall_math::integer::PolyOverZ;
28    /// use std::str::FromStr;
29    /// let a: PolyOverZ = PolyOverZ::from_str("2  42 1").unwrap();
30    /// let b: PolyOverZ = PolyOverZ::from_str("2  24 1").unwrap();
31    ///
32    /// // These are all equivalent and return false.
33    /// let compared: bool = (a == b);
34    /// # assert!(!compared);
35    /// let compared: bool = (&a == &b);
36    /// # assert!(!compared);
37    /// let compared: bool = (a.eq(&b));
38    /// # assert!(!compared);
39    /// let compared: bool = (PolyOverZ::eq(&a, &b));
40    /// # assert!(!compared);
41    /// ```
42    fn eq(&self, other: &Self) -> bool {
43        unsafe { 1 == fmpz_poly_equal(&self.poly, &other.poly) }
44    }
45}
46
47// With the [`Eq`] trait, `a == a` is always true.
48// This is not guaranteed by the [`PartialEq`] trait.
49impl Eq for PolyOverZ {}
50
51impl CompareBase<PolyOverZ> for PolyOverZ {}
52impl<Integer: Into<Z>> CompareBase<Integer> for PolyOverZ {}
53
54/// Test that the [`PartialEq`] trait is correctly implemented.
55#[cfg(test)]
56mod test_partial_eq {
57    // Test case structure:
58    // 1. Different ways to use equal and not equal.
59    // 2. Test different combinations of equal and not equal with different
60    //    parameter length combinations.
61    //    Not equal test are inverted equal tests.
62
63    use super::PolyOverZ;
64    use std::str::FromStr;
65
66    /// Demonstrate the different ways to use equal.
67    /// We assume that they behave the same in the other tests.
68    #[test]
69    #[allow(clippy::op_ref)]
70    fn equal_call_methods() {
71        let one_1 = PolyOverZ::from_str("2  24 1").unwrap();
72        let one_2 = PolyOverZ::from_str("2  24 1").unwrap();
73
74        assert!(one_1 == one_2);
75        assert!(&one_1 == &one_2);
76        assert!(one_1.eq(&one_2));
77        assert!(PolyOverZ::eq(&one_1, &one_2));
78        assert_eq!(one_1, one_2);
79    }
80
81    /// Demonstrate the different ways to use not equal.
82    /// We assume that they behave the same in the other tests.
83    #[test]
84    #[allow(clippy::op_ref)]
85    fn not_equal_call_methods() {
86        let one = PolyOverZ::from_str("2  24 1").unwrap();
87        let two = PolyOverZ::from_str("3  24 1 1").unwrap();
88
89        assert!(one != two);
90        assert!(&one != &two);
91        assert!(one.ne(&two));
92        assert!(PolyOverZ::ne(&one, &two));
93        assert_ne!(one, two);
94    }
95
96    /// Test equal with small positive and negative constant polynomials.
97    #[test]
98    fn equal_small() {
99        let small_1 = PolyOverZ::from(10);
100        let small_2 = PolyOverZ::from(10);
101        let negative = PolyOverZ::from(-1);
102
103        assert!(small_1 == small_2);
104        assert!(small_2 == small_1);
105        assert!(small_1 == small_1);
106        assert!(!(small_1 == negative));
107        assert!(!(negative == small_1));
108    }
109
110    /// Test not equal with small positive and negative constant polynomials.
111    #[test]
112    fn not_equal_small() {
113        let small_1 = PolyOverZ::from(10);
114        let small_2 = PolyOverZ::from(10);
115        let negative = PolyOverZ::from(-1);
116
117        assert!(!(small_1 != small_2));
118        assert!(!(small_2 != small_1));
119        assert!(!(small_1 != small_1));
120        assert!(small_1 != negative);
121        assert!(negative != small_1);
122    }
123
124    /// Test equal with a large [`PolyOverZ`]
125    /// (uses FLINT's pointer representation)
126    #[test]
127    fn equal_large() {
128        let max_1 = PolyOverZ::from(u64::MAX);
129        let max_2 = PolyOverZ::from(u64::MAX);
130        let min = PolyOverZ::from(i64::MIN);
131
132        assert!(max_1 == max_2);
133        assert!(max_2 == max_1);
134        assert!(max_1 == max_1);
135        assert!(min == min);
136        assert!(!(max_1 == min));
137        assert!(!(min == max_1));
138    }
139
140    /// Test not equal with a large [`PolyOverZ`]
141    /// (uses FLINT's pointer representation)
142    #[test]
143    fn not_equal_large() {
144        let max_1 = PolyOverZ::from(u64::MAX);
145        let max_2 = PolyOverZ::from(u64::MAX);
146        let min = PolyOverZ::from(i64::MIN);
147
148        assert!(!(max_1 != max_2));
149        assert!(!(max_2 != max_1));
150        assert!(!(max_1 != max_1));
151        assert!(!(min != min));
152        assert!(max_1 != min);
153        assert!(min != max_1);
154    }
155
156    /// Test equal with a large [`PolyOverZ`] (uses FLINT's pointer representation)
157    /// and small [`PolyOverZ`] (no pointer representation).
158    #[test]
159    fn equal_large_small() {
160        let max = PolyOverZ::from(u64::MAX);
161        let min = PolyOverZ::from(i64::MIN);
162
163        let small_positive = PolyOverZ::from(1);
164        let small_negative = PolyOverZ::from(-1);
165
166        assert!(!(max == small_negative));
167        assert!(!(small_negative == max));
168        assert!(!(max == small_positive));
169        assert!(!(small_positive == max));
170
171        assert!(!(min == small_negative));
172        assert!(!(small_negative == min));
173        assert!(!(min == small_positive));
174        assert!(!(small_positive == min));
175    }
176
177    /// Test not equal with a large [`PolyOverZ`] (uses FLINT's pointer representation)
178    /// and small [`PolyOverZ`] (no pointer representation).
179    #[test]
180    fn not_equal_large_small() {
181        let max = PolyOverZ::from(u64::MAX);
182        let min = PolyOverZ::from(i64::MIN);
183
184        let small_positive = PolyOverZ::from(1);
185        let small_negative = PolyOverZ::from(-1);
186
187        assert!(max != small_negative);
188        assert!(small_negative != max);
189        assert!(max != small_positive);
190        assert!(small_positive != max);
191
192        assert!(min != small_negative);
193        assert!(small_negative != min);
194        assert!(min != small_positive);
195        assert!(small_positive != min);
196    }
197}
198
199/// Test that the [`CompareBase`] trait uses the default implementation.
200#[cfg(test)]
201mod test_compare_base {
202    use crate::{
203        integer::{PolyOverZ, Z},
204        traits::CompareBase,
205    };
206    use std::str::FromStr;
207
208    /// Ensures that the [`CompareBase`] trait uses the default implementation
209    /// and is available for all types it would be checked against.
210    #[test]
211    fn availability() {
212        let one_1 = PolyOverZ::from_str("3  3 1 -7").unwrap();
213
214        assert!(one_1.compare_base(&Z::ONE));
215        assert!(one_1.compare_base(&PolyOverZ::from(1)));
216        assert!(one_1.compare_base(&0_i8));
217        assert!(one_1.compare_base(&0_i16));
218        assert!(one_1.compare_base(&0_i32));
219        assert!(one_1.compare_base(&0_i64));
220        assert!(one_1.compare_base(&0_u8));
221        assert!(one_1.compare_base(&0_u16));
222        assert!(one_1.compare_base(&0_u32));
223        assert!(one_1.compare_base(&0_u64));
224
225        assert!(one_1.call_compare_base_error(&PolyOverZ::from(1)).is_none());
226        assert!(one_1.call_compare_base_error(&Z::ONE).is_none());
227        assert!(one_1.call_compare_base_error(&0_i8).is_none());
228        assert!(one_1.call_compare_base_error(&0_i16).is_none());
229        assert!(one_1.call_compare_base_error(&0_i32).is_none());
230        assert!(one_1.call_compare_base_error(&0_i64).is_none());
231        assert!(one_1.call_compare_base_error(&0_u8).is_none());
232        assert!(one_1.call_compare_base_error(&0_u16).is_none());
233        assert!(one_1.call_compare_base_error(&0_u32).is_none());
234        assert!(one_1.call_compare_base_error(&0_u64).is_none());
235    }
236}