qfall_math/integer_mod_q/modulus/cmp.rs
1// Copyright © 2023 Marcel Luca Schmidt, Niklas Siemer
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//! This module contains implementations of functions
10//! important for comparison such as the [`PartialEq`] trait.
11//!
12//! The explicit functions contain the documentation.
13
14use super::Modulus;
15use crate::{
16 integer::Z,
17 macros::for_others::{implement_for_others, implement_trait_reverse},
18};
19use flint_sys::fmpz::{fmpz, fmpz_cmp, fmpz_equal};
20use std::cmp::Ordering;
21
22impl PartialEq for Modulus {
23 /// Compares the two [`fmpz`](flint_sys::fmpz::fmpz) structs hiding behind the
24 /// given [`Modulus`] instances to check whether the given [`Modulus`] instances
25 /// have the same value.
26 ///
27 /// Parameters:
28 /// - `other`: holds another [`Modulus`] object which `self` is compared to
29 ///
30 /// # Examples
31 /// ```
32 /// use qfall_math::integer_mod_q::Modulus;
33 /// use std::str::FromStr;
34 ///
35 /// let a = Modulus::from(3);
36 /// let b = Modulus::from(3);
37 /// let c = Modulus::from(4);
38 ///
39 /// assert_eq!(a, b);
40 /// assert_ne!(a, c);
41 /// ```
42 fn eq(&self, other: &Self) -> bool {
43 unsafe {
44 1 == flint_sys::fmpz::fmpz_equal(
45 &self.get_fmpz_mod_ctx_struct().to_owned().n[0],
46 &other.get_fmpz_mod_ctx_struct().to_owned().n[0],
47 )
48 }
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 Modulus {}
55
56impl PartialEq<Z> for Modulus {
57 /// Checks if an integer and a modulus are equal. Used by the `==` and `!=` operators.
58 /// [`PartialEq`] is also implemented for [`Z`] using [`Modulus`].
59 ///
60 /// Parameters:
61 /// - `other`: the other value that is used to compare the elements
62 ///
63 /// Returns `true` if the elements are equal, otherwise `false`.
64 ///
65 /// # Examples
66 /// ```
67 /// use qfall_math::integer::Z;
68 /// use qfall_math::integer_mod_q::Modulus;
69 /// let a: Modulus = Modulus::from(42);
70 /// let b: Z = Z::from(42);
71 ///
72 /// // These are all equivalent and return true.
73 /// let compared: bool = (a == b);
74 /// # assert!(compared);
75 /// let compared: bool = (b == a);
76 /// # assert!(compared);
77 /// let compared: bool = (&a == &b);
78 /// # assert!(compared);
79 /// let compared: bool = (&b == &a);
80 /// # assert!(compared);
81 /// let compared: bool = (a.eq(&b));
82 /// # assert!(compared);
83 /// let compared: bool = (b.eq(&a));
84 /// # assert!(compared);
85 /// let compared: bool = (Z::eq(&b, &a));
86 /// # assert!(compared);
87 /// let compared: bool = (Modulus::eq(&a, &b));
88 /// # assert!(compared);
89 /// ```
90 fn eq(&self, other: &Z) -> bool {
91 unsafe { 1 == fmpz_equal(&other.value, &self.modulus.n[0]) }
92 }
93}
94
95implement_trait_reverse!(PartialEq, eq, Z, Modulus, bool);
96
97implement_for_others!(Z, Modulus, PartialEq for fmpz i8 i16 i32 i64 u8 u16 u32 u64);
98
99impl PartialOrd for Modulus {
100 /// Compares two [`Modulus`] values. Used by the `<`, `<=`, `>`, and `>=` operators.
101 ///
102 /// Parameters:
103 /// - `other`: the other value that is used to compare the elements
104 ///
105 /// Returns the [`Ordering`] of the elements.
106 ///
107 /// # Examples
108 /// ```
109 /// use qfall_math::integer_mod_q::Modulus;
110 ///
111 /// let a: Modulus = Modulus::from(10);
112 /// let b: Modulus = Modulus::from(42);
113 ///
114 /// assert!(a < b);
115 /// assert!(a <= b);
116 /// assert!(b > a);
117 /// assert!(b >= a);
118 /// ```
119 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120 Some(self.cmp(other))
121 }
122}
123
124impl Ord for Modulus {
125 //! Enables the usage of `max`, `min`, and `clamp`.
126 //!
127 //! # Examples
128 //! ```
129 //! use qfall_math::integer_mod_q::Modulus;
130 //! use std::cmp::{max, min};
131 //!
132 //! let a: Modulus = Modulus::from(10);
133 //! let b: Modulus = Modulus::from(42);
134 //!
135 //! assert_eq!(b, max(a.clone(), b.clone()));
136 //! assert_eq!(a, min(a.clone(), b.clone()));
137 //! assert_eq!(a, Modulus::from(2).clamp(a.clone(), b.clone()));
138 //! ```
139
140 /// Compares two [`Modulus`] values. Used by the `<`, `<=`, `>`, and `>=` operators.
141 ///
142 /// Parameters:
143 /// - `other`: the other value that is used to compare the elements
144 ///
145 /// Returns the [`Ordering`] of the elements.
146 ///
147 /// # Examples
148 /// ```
149 /// use qfall_math::integer_mod_q::Modulus;
150 ///
151 /// let a: Modulus = Modulus::from(10);
152 /// let b: Modulus = Modulus::from(42);
153 ///
154 /// assert!(a < b);
155 /// assert!(a <= b);
156 /// assert!(b > a);
157 /// assert!(b >= a);
158 /// ```
159 fn cmp(&self, other: &Self) -> Ordering {
160 let z_1: Z = self.into();
161 let z_2: Z = other.into();
162 z_1.cmp(&z_2)
163 }
164}
165
166impl PartialOrd<Z> for Modulus {
167 /// Compares a [`Z`] value with a [`Modulus`]. Used by the `<`, `<=`, `>`, and `>=` operators.
168 /// [`PartialOrd`] is also implemented for [`Z`] using [`Modulus`].
169 ///
170 /// Parameters:
171 /// - `other`: the other value that is used to compare the elements
172 ///
173 /// Returns the [`Ordering`] of the elements.
174 ///
175 /// # Examples
176 /// ```
177 /// use qfall_math::integer::Z;
178 /// use qfall_math::integer_mod_q::Modulus;
179 ///
180 /// let a: Modulus = Modulus::from(10);
181 /// let b: Z = Z::from(42);
182 ///
183 /// assert!(a < b);
184 /// assert!(a <= b);
185 /// assert!(b > a);
186 /// assert!(b >= a);
187 /// ```
188 fn partial_cmp(&self, other: &Z) -> Option<Ordering> {
189 Some(unsafe { fmpz_cmp(&self.modulus.n[0], &other.value).cmp(&0) })
190 }
191}
192
193implement_for_others!(Z, Modulus, PartialOrd for fmpz i8 i16 i32 i64 u8 u16 u32 u64);
194
195#[cfg(test)]
196mod test_eq {
197 use super::Modulus;
198 use crate::integer::Z;
199 use std::str::FromStr;
200
201 /// Checks whether two equal, large Moduli created with different constructors are equal
202 #[test]
203 fn equal_large() {
204 let a = Modulus::from_str(&"1".repeat(65)).unwrap();
205 let b = Modulus::from(&Z::from_str(&"1".repeat(65)).unwrap());
206 let a_clone = a.clone();
207
208 assert_eq!(a, b);
209 assert_eq!(a, a_clone);
210 assert_eq!(b, a_clone);
211 }
212
213 /// Checks whether two equal, small Moduli created with different constructors are equal
214 #[test]
215 fn equal_small() {
216 let a = Modulus::from(2);
217 let b = Modulus::from(&Z::from(2));
218 let b_clone = b.clone();
219
220 assert_eq!(a, b);
221 assert_eq!(b, b_clone);
222 assert_eq!(a, b_clone);
223 }
224
225 /// Checks whether unequal Moduli are unequal
226 #[test]
227 fn unequal() {
228 let one = Modulus::from(3);
229 let two = Modulus::from(2);
230 let large = Modulus::from_str(&"1".repeat(65)).unwrap();
231
232 assert_ne!(one, two);
233 assert_ne!(one, large);
234 assert_ne!(two, large);
235 }
236}
237
238/// Test that the [`PartialEq`] trait is correctly implemented.
239#[cfg(test)]
240mod test_partial_eq_modulus_other {
241 use super::Z;
242 use crate::integer_mod_q::Modulus;
243
244 /// Ensure that the function can be called with several types
245 #[test]
246 #[allow(clippy::op_ref)]
247 fn availability() {
248 let modulus = Modulus::from(2);
249 let z = Z::from(2);
250
251 assert!(modulus == z);
252 assert!(modulus == z.value);
253 assert!(modulus == 2i8);
254 assert!(modulus == 2u8);
255 assert!(modulus == 2i16);
256 assert!(modulus == 2u16);
257 assert!(modulus == 2i32);
258 assert!(modulus == 2u32);
259 assert!(modulus == 2i64);
260 assert!(modulus == 2u64);
261
262 assert!(z == modulus);
263 assert!(z.value == modulus);
264 assert!(2i8 == modulus);
265 assert!(2u8 == modulus);
266 assert!(2i16 == modulus);
267 assert!(2u16 == modulus);
268 assert!(2i32 == modulus);
269 assert!(2u32 == modulus);
270 assert!(2i64 == modulus);
271 assert!(2u64 == modulus);
272
273 assert!(&modulus == &z);
274 assert!(&z == &modulus);
275 assert!(&modulus == &2i8);
276 assert!(&2i8 == &modulus);
277 }
278
279 /// Ensure that large values are compared correctly
280 #[test]
281 fn equal_large() {
282 let modulus = Modulus::from(u64::MAX);
283 let z = Z::from(u64::MAX);
284
285 assert!(modulus == z);
286 assert!(modulus != z + 1);
287 }
288}
289
290/// Test the [`PartialOrd`] trait implementation for [`Modulus`]. Only basic tests are
291/// performed, since the function is the same as for [`Z`](crate::integer::Z).
292#[cfg(test)]
293mod test_partial_ord {
294 use crate::integer_mod_q::Modulus;
295
296 /// Tests comparisons between [`Modulus`] values.
297 #[test]
298 fn order_correct() {
299 let a = Modulus::from(2);
300 let b = Modulus::from(3);
301
302 assert!(a < b);
303 assert!(a <= b);
304 assert!(a <= a);
305 assert!(b > a);
306 assert!(b >= a);
307 assert!(a >= a);
308 }
309
310 /// Tests comparisons between large [`Modulus`] values.
311 #[test]
312 fn order_large() {
313 let a = Modulus::from(i64::MAX);
314 let b = Modulus::from(u64::MAX);
315
316 assert!(a < b);
317 assert!(a <= b);
318 assert!(a <= a);
319 assert!(b <= b);
320 assert!(b > a);
321 assert!(b >= a);
322 assert!(a >= a);
323 assert!(b >= b);
324 }
325}
326
327/// Test that the [`PartialOrd`] trait is correctly implemented.
328#[cfg(test)]
329mod test_partial_ord_modulus_other {
330 use super::Modulus;
331 use crate::integer::Z;
332
333 /// Ensure that the function can be called with several types
334 #[test]
335 #[allow(clippy::op_ref)]
336 fn availability() {
337 let modulus = Modulus::from(2);
338 let z = Z::from(2);
339
340 assert!(modulus <= z);
341 assert!(modulus <= z.value);
342 assert!(modulus <= 2i8);
343 assert!(modulus <= 2u8);
344 assert!(modulus <= 2i16);
345 assert!(modulus <= 2u16);
346 assert!(modulus <= 2i32);
347 assert!(modulus <= 2u32);
348 assert!(modulus <= 2i64);
349 assert!(modulus <= 2u64);
350
351 assert!(z.value >= modulus);
352 assert!(2i8 >= modulus);
353 assert!(2u8 >= modulus);
354 assert!(2i16 >= modulus);
355 assert!(2u16 >= modulus);
356 assert!(2i32 >= modulus);
357 assert!(2u32 >= modulus);
358 assert!(2i64 >= modulus);
359 assert!(2u64 >= modulus);
360
361 assert!(&modulus <= &z);
362 assert!(&modulus <= &2i8);
363 assert!(&2i8 >= &modulus);
364 }
365}
366
367#[cfg(test)]
368mod test_ord {
369 use crate::integer_mod_q::Modulus;
370 use std::cmp::{max, min};
371
372 // Tests that are already performed in the [`PartialOrd`] tests and the
373 // implementation of [`Ord`] for [`Z`](crate::integer::Z) are omitted.
374
375 /// Checks whether default implementations `max`, `min`, `clamp` work properly.
376 #[test]
377 fn default_implementations() {
378 let a: Modulus = Modulus::from(10);
379 let b: Modulus = Modulus::from(42);
380
381 assert_eq!(b, max(a.clone(), b.clone()));
382 assert_eq!(a, min(a.clone(), b.clone()));
383
384 assert_eq!(a, Modulus::from(2).clamp(a.clone(), b.clone()));
385 assert_eq!(a, a.clone().clamp(Modulus::from(2), b.clone()));
386 assert_eq!(a, b.clamp(Modulus::from(2), a.clone()));
387 }
388}