Skip to main content

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 flint3_sys::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            self.get_mod() == other.get_mod() && fmpz_mat_equal(&self.matrix, &other.matrix) != 0
51        }
52    }
53}
54
55compare_base_get_mod!(MatZq for MatZq Zq);
56compare_base_default!(MatZq for MatZ);
57impl<Integer: Into<Z>> CompareBase<Integer> for MatZq {}
58
59// With the [`Eq`] trait, `a == a` is always true.
60// This is not guaranteed by the [`PartialEq`] trait.
61impl Eq for MatZq {}
62
63/// Test that the [`PartialEq`] trait is correctly implemented.
64#[cfg(test)]
65mod test_partial_eq {
66    use super::MatZq;
67    use crate::traits::{AsInteger, MatrixSetEntry};
68    use std::str::FromStr;
69
70    /// Ensures that different instantiations do not break the equality between matrices
71    #[test]
72    fn equality_between_instantiations() {
73        let a = MatZq::from_str("[[0, 1],[0, 0]] mod 4").unwrap();
74        let mut b = MatZq::new(2, 2, 4);
75        b.set_entry(0, 1, 1).unwrap();
76
77        assert_eq!(a, b);
78    }
79
80    /// Checks that large and small entries (and different points in storage) do not break equality
81    #[test]
82    fn equality_for_large_and_small_entries() {
83        let mat_str_1 = format!(
84            "[[{}, {}, 1],[-10, 10, 0],[0, 1, -10]] mod {}",
85            i64::MAX - 1,
86            i64::MAX,
87            u64::MAX
88        );
89        let mat_str_2 = format!(
90            "[[{}, {}, 1],[-10, 10, 0],[{}, 1, -10]] mod {}",
91            i64::MAX - 1,
92            i64::MAX,
93            u64::MAX,
94            u64::MAX
95        );
96        let a = MatZq::from_str(&mat_str_1).unwrap();
97        let b = MatZq::from_str(&mat_str_1).unwrap();
98        let c = MatZq::from_str(&mat_str_2).unwrap();
99
100        assert_eq!(&a, &b);
101        assert_eq!(&a, &c);
102    }
103
104    /// Checks that different unequal matrices with same modulus are unequal
105    #[test]
106    fn not_equal_same_modulus() {
107        let a =
108            MatZq::from_str(&format!("[[{}, {}],[-10, 10]] mod 42", i64::MIN, i64::MAX)).unwrap();
109        let b = MatZq::from_str(&format!("[[0, {}],[-10, 10]] mod 42", i64::MAX)).unwrap();
110        let c = MatZq::from_str(&format!(
111            "[[{}, {}],[-10, 10],[0, 0]] mod 42",
112            i64::MIN,
113            i64::MAX
114        ))
115        .unwrap();
116        let d = MatZq::from_str(&format!("[[{}, {}]] mod 42", i64::MIN, i64::MAX)).unwrap();
117        let e = MatZq::from_str("[[0]] mod 42").unwrap();
118
119        assert_ne!(&a, &b);
120        assert_ne!(&a, &c);
121        assert_ne!(&a, &d);
122        assert_ne!(&a, &e);
123        assert_ne!(&b, &c);
124        assert_ne!(&b, &d);
125        assert_ne!(&b, &e);
126        assert_ne!(&c, &d);
127        assert_ne!(&c, &e);
128        assert_ne!(&d, &e);
129    }
130
131    /// Checks that the same matrix with different modulus are unequal
132    #[test]
133    fn not_equal_different_modulus() {
134        let a = MatZq::from_str("[[0, 1],[0, 0]] mod 4").unwrap();
135        let b = MatZq::from_str("[[0, 1],[0, 0]] mod 8").unwrap();
136
137        let c = MatZq::from_str(&format!("[[0]] mod {}", u64::MAX)).unwrap();
138        let d = MatZq::from_str(&format!("[[0]] mod {}", u64::MAX - 1)).unwrap();
139        let e =
140            MatZq::from_str(&format!("[[0]] mod {}", unsafe { c.get_mod().into_fmpz() } as u64))
141                .unwrap();
142
143        assert_ne!(a, b);
144
145        assert_ne!(c, d);
146        assert_ne!(c, e);
147    }
148}
149
150/// Test that the [`CompareBase`] trait uses an actual implementation.
151#[cfg(test)]
152mod test_compare_base {
153    use crate::{
154        integer::{MatZ, Z},
155        integer_mod_q::{MatZq, Zq},
156        traits::CompareBase,
157    };
158
159    /// Ensures that the [`CompareBase`] is available for all types it would be checked against
160    /// where no comparison is needed
161    #[test]
162    fn availability_without_comparisons() {
163        let one_1 = MatZq::new(3, 4, 17);
164
165        assert!(one_1.compare_base(&MatZ::new(1, 1)));
166        assert!(one_1.compare_base(&Z::ONE));
167        assert!(one_1.compare_base(&0_i8));
168        assert!(one_1.compare_base(&0_i16));
169        assert!(one_1.compare_base(&0_i32));
170        assert!(one_1.compare_base(&0_i64));
171        assert!(one_1.compare_base(&0_u8));
172        assert!(one_1.compare_base(&0_u16));
173        assert!(one_1.compare_base(&0_u32));
174        assert!(one_1.compare_base(&0_u64));
175
176        assert!(one_1.call_compare_base_error(&MatZ::new(1, 1)).is_none());
177        assert!(one_1.call_compare_base_error(&Z::ONE).is_none());
178        assert!(one_1.call_compare_base_error(&0_i8).is_none());
179        assert!(one_1.call_compare_base_error(&0_i16).is_none());
180        assert!(one_1.call_compare_base_error(&0_i32).is_none());
181        assert!(one_1.call_compare_base_error(&0_i64).is_none());
182        assert!(one_1.call_compare_base_error(&0_u8).is_none());
183        assert!(one_1.call_compare_base_error(&0_u16).is_none());
184        assert!(one_1.call_compare_base_error(&0_u32).is_none());
185        assert!(one_1.call_compare_base_error(&0_u64).is_none());
186    }
187
188    /// Ensures that the [`CompareBase`] is available for all types it would be checked against
189    /// where comparison is needed
190    #[test]
191    fn availability_with_comparisons() {
192        let one_1 = MatZq::new(3, 4, 17);
193
194        assert!(one_1.compare_base(&one_1));
195        assert!(one_1.compare_base(&Zq::from((3, 17))));
196        assert!(!one_1.compare_base(&Zq::from((3, 18))));
197        assert!(one_1.compare_base(&MatZq::new(1, 1, 17)));
198        assert!(!one_1.compare_base(&MatZq::new(1, 1, 18)));
199
200        assert!(one_1.call_compare_base_error(&Zq::from((3, 18))).is_some());
201        assert!(
202            one_1
203                .call_compare_base_error(&MatZq::new(1, 1, 18))
204                .is_some()
205        );
206    }
207}