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}