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