qfall_math/integer_mod_q/mat_zq/
cmp.rs

1// Copyright © 2023 Sven Moog
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 for comparison of [`MatZq`].
10
11use super::MatZq;
12use crate::{
13    error::MathError,
14    integer::{MatZ, Z},
15    integer_mod_q::Zq,
16    macros::compare_base::{compare_base_default, compare_base_get_mod, compare_base_impl},
17    traits::CompareBase,
18};
19use flint_sys::{fmpz::fmpz_equal, fmpz_mat::fmpz_mat_equal};
20
21impl PartialEq for MatZq {
22    /// Checks if two [`MatZq`] instances are equal. Used by the `==` and `!=` operators.
23    /// The values in the matrix as well as the modulus have to be equal.
24    ///
25    /// Parameters:
26    /// - `other`: the other value that is compare against `self`
27    ///
28    /// Returns `true` if the elements are equal, otherwise `false`.
29    ///
30    /// # Examples
31    /// ```
32    /// use qfall_math::integer_mod_q::MatZq;
33    /// use std::str::FromStr;
34    ///
35    /// let a = MatZq::from_str("[[1, 2],[3, 4]] mod 4").unwrap();
36    /// let b = MatZq::from_str("[[1, 2],[2, 4]] mod 4").unwrap();
37    ///
38    /// // These are all equivalent and return false.
39    /// let compared: bool = (a == b);
40    /// # assert!(!compared);
41    /// let compared: bool = (&a == &b);
42    /// # assert!(!compared);
43    /// let compared: bool = (a.eq(&b));
44    /// # assert!(!compared);
45    /// let compared: bool = (MatZq::eq(&a, &b));
46    /// # assert!(!compared);
47    /// ```
48    fn eq(&self, other: &Self) -> bool {
49        unsafe {
50            fmpz_equal(&self.matrix.mod_[0], &other.matrix.mod_[0]) != 0
51                && fmpz_mat_equal(&self.matrix.mat[0], &other.matrix.mat[0]) != 0
52        }
53    }
54}
55
56compare_base_get_mod!(MatZq for MatZq Zq);
57compare_base_default!(MatZq for MatZ);
58impl<Integer: Into<Z>> CompareBase<Integer> for MatZq {}
59
60// With the [`Eq`] trait, `a == a` is always true.
61// This is not guaranteed by the [`PartialEq`] trait.
62impl Eq for MatZq {}
63
64/// Test that the [`PartialEq`] trait is correctly implemented.
65#[cfg(test)]
66mod test_partial_eq {
67    use super::MatZq;
68    use crate::traits::MatrixSetEntry;
69    use std::str::FromStr;
70
71    /// Ensures that different instantiations do not break the equality between matrices
72    #[test]
73    fn equality_between_instantiations() {
74        let a = MatZq::from_str("[[0, 1],[0, 0]] mod 4").unwrap();
75        let mut b = MatZq::new(2, 2, 4);
76        b.set_entry(0, 1, 1).unwrap();
77
78        assert_eq!(a, b);
79    }
80
81    /// Checks that large and small entries (and different points in storage) do not break equality
82    #[test]
83    fn equality_for_large_and_small_entries() {
84        let mat_str_1 = format!(
85            "[[{}, {}, 1],[-10, 10, 0],[0, 1, -10]] mod {}",
86            i64::MAX - 1,
87            i64::MAX,
88            u64::MAX
89        );
90        let mat_str_2 = format!(
91            "[[{}, {}, 1],[-10, 10, 0],[{}, 1, -10]] mod {}",
92            i64::MAX - 1,
93            i64::MAX,
94            u64::MAX,
95            u64::MAX
96        );
97        let a = MatZq::from_str(&mat_str_1).unwrap();
98        let b = MatZq::from_str(&mat_str_1).unwrap();
99        let c = MatZq::from_str(&mat_str_2).unwrap();
100
101        assert_eq!(&a, &b);
102        assert_eq!(&a, &c);
103    }
104
105    /// Checks that different unequal matrices with same modulus are unequal
106    #[test]
107    fn not_equal_same_modulus() {
108        let a =
109            MatZq::from_str(&format!("[[{}, {}],[-10, 10]] mod 42", i64::MIN, i64::MAX)).unwrap();
110        let b = MatZq::from_str(&format!("[[0, {}],[-10, 10]] mod 42", i64::MAX)).unwrap();
111        let c = MatZq::from_str(&format!(
112            "[[{}, {}],[-10, 10],[0, 0]] mod 42",
113            i64::MIN,
114            i64::MAX
115        ))
116        .unwrap();
117        let d = MatZq::from_str(&format!("[[{}, {}]] mod 42", i64::MIN, i64::MAX)).unwrap();
118        let e = MatZq::from_str("[[0]] mod 42").unwrap();
119
120        assert_ne!(&a, &b);
121        assert_ne!(&a, &c);
122        assert_ne!(&a, &d);
123        assert_ne!(&a, &e);
124        assert_ne!(&b, &c);
125        assert_ne!(&b, &d);
126        assert_ne!(&b, &e);
127        assert_ne!(&c, &d);
128        assert_ne!(&c, &e);
129        assert_ne!(&d, &e);
130    }
131
132    /// Checks that the same matrix with different modulus are unequal
133    #[test]
134    fn not_equal_different_modulus() {
135        let a = MatZq::from_str("[[0, 1],[0, 0]] mod 4").unwrap();
136        let b = MatZq::from_str("[[0, 1],[0, 0]] mod 8").unwrap();
137
138        let c = MatZq::from_str(&format!("[[0]] mod {}", u64::MAX)).unwrap();
139        let d = MatZq::from_str(&format!("[[0]] mod {}", u64::MAX - 1)).unwrap();
140        let e = MatZq::from_str(&format!("[[0]] mod {}", c.matrix.mod_[0].0 as u64)).unwrap();
141
142        assert_ne!(a, b);
143
144        assert_ne!(c, d);
145        assert_ne!(c, e);
146    }
147}
148
149/// Test that the [`CompareBase`] trait uses an actual implementation.
150#[cfg(test)]
151mod test_compare_base {
152    use crate::{
153        integer::{MatZ, Z},
154        integer_mod_q::{MatZq, Zq},
155        traits::CompareBase,
156    };
157
158    /// Ensures that the [`CompareBase`] is available for all types it would be checked against
159    /// where no comparison is needed
160    #[test]
161    fn availability_without_comparisons() {
162        let one_1 = MatZq::new(3, 4, 17);
163
164        assert!(one_1.compare_base(&MatZ::new(1, 1)));
165        assert!(one_1.compare_base(&Z::ONE));
166        assert!(one_1.compare_base(&0_i8));
167        assert!(one_1.compare_base(&0_i16));
168        assert!(one_1.compare_base(&0_i32));
169        assert!(one_1.compare_base(&0_i64));
170        assert!(one_1.compare_base(&0_u8));
171        assert!(one_1.compare_base(&0_u16));
172        assert!(one_1.compare_base(&0_u32));
173        assert!(one_1.compare_base(&0_u64));
174
175        assert!(one_1.call_compare_base_error(&MatZ::new(1, 1)).is_none());
176        assert!(one_1.call_compare_base_error(&Z::ONE).is_none());
177        assert!(one_1.call_compare_base_error(&0_i8).is_none());
178        assert!(one_1.call_compare_base_error(&0_i16).is_none());
179        assert!(one_1.call_compare_base_error(&0_i32).is_none());
180        assert!(one_1.call_compare_base_error(&0_i64).is_none());
181        assert!(one_1.call_compare_base_error(&0_u8).is_none());
182        assert!(one_1.call_compare_base_error(&0_u16).is_none());
183        assert!(one_1.call_compare_base_error(&0_u32).is_none());
184        assert!(one_1.call_compare_base_error(&0_u64).is_none());
185    }
186
187    /// Ensures that the [`CompareBase`] is available for all types it would be checked against
188    /// where comparison is needed
189    #[test]
190    fn availability_with_comparisons() {
191        let one_1 = MatZq::new(3, 4, 17);
192
193        assert!(one_1.compare_base(&one_1));
194        assert!(one_1.compare_base(&Zq::from((3, 17))));
195        assert!(!one_1.compare_base(&Zq::from((3, 18))));
196        assert!(one_1.compare_base(&MatZq::new(1, 1, 17)));
197        assert!(!one_1.compare_base(&MatZq::new(1, 1, 18)));
198
199        assert!(one_1.call_compare_base_error(&Zq::from((3, 18))).is_some());
200        assert!(
201            one_1
202                .call_compare_base_error(&MatZq::new(1, 1, 18))
203                .is_some()
204        );
205    }
206}