Skip to main content

qfall_math/integer_mod_q/mat_zq/
properties.rs

1// Copyright 2023 Phil Milewski
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 includes functionality about properties of [`MatZq`] instances.
10
11use super::MatZq;
12use crate::{
13    integer::Z,
14    traits::{MatrixDimensions, MatrixGetEntry},
15};
16use flint3_sys::{
17    fmpz_mat_is_one, {fmpz_mod_mat_is_square, fmpz_mod_mat_is_zero},
18};
19
20impl MatZq {
21    /// Checks if a [`MatZq`] is the identity matrix.
22    ///
23    /// Returns `true` if every diagonal entry of the upper square matrix is `1`
24    /// and all other entries are `0`.
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::integer_mod_q::MatZq;
29    /// use std::str::FromStr;
30    ///
31    /// let value = MatZq::from_str("[[1, 0],[0, 1]] mod 17").unwrap();
32    /// assert!(value.is_identity());
33    /// ```
34    ///
35    /// ```
36    /// use qfall_math::integer_mod_q::MatZq;
37    /// use std::str::FromStr;
38    ///
39    /// let value = MatZq::from_str("[[1, 0],[0, 1],[0, 0]] mod 17").unwrap();
40    /// assert!(value.is_identity());
41    /// ```
42    pub fn is_identity(&self) -> bool {
43        unsafe { 1 == fmpz_mat_is_one(&self.matrix) }
44    }
45
46    /// Checks if a [`MatZq`] is a square matrix.
47    ///
48    /// Returns `true` if the number of rows and columns is identical.
49    ///
50    /// # Examples
51    /// ```
52    /// use qfall_math::integer_mod_q::MatZq;
53    /// use std::str::FromStr;
54    ///
55    /// let value = MatZq::from_str("[[4, 0],[0, 1]] mod 17").unwrap();
56    /// assert!(value.is_square());
57    /// ```
58    pub fn is_square(&self) -> bool {
59        1 == unsafe { fmpz_mod_mat_is_square(&self.matrix, self.modulus.get_fmpz_mod_ctx_struct()) }
60    }
61
62    /// Checks if every entry of a [`MatZq`] is `0`.
63    ///
64    /// Returns `true` if every entry is `0`.
65    ///
66    /// # Examples
67    /// ```
68    /// use qfall_math::integer_mod_q::MatZq;
69    /// use std::str::FromStr;
70    ///
71    /// let value = MatZq::from_str("[[0, 0],[0, 0]] mod 17").unwrap();
72    /// assert!(value.is_zero());
73    /// ```
74    pub fn is_zero(&self) -> bool {
75        1 == unsafe { fmpz_mod_mat_is_zero(&self.matrix, self.modulus.get_fmpz_mod_ctx_struct()) }
76    }
77
78    /// Checks if a [`MatZq`] is symmetric.
79    ///
80    /// Returns `true` if we have `a_ij == a_ji` for all i,j.
81    ///
82    /// # Examples
83    /// ```
84    /// use qfall_math::integer_mod_q::MatZq;
85    ///
86    /// let value = MatZq::identity(2,2,3);
87    /// assert!(value.is_symmetric());
88    /// ```
89    pub fn is_symmetric(&self) -> bool {
90        if !self.is_square() {
91            return false;
92        }
93        for row in 0..self.get_num_rows() {
94            for column in 0..row {
95                if unsafe {
96                    MatrixGetEntry::<Z>::get_entry_unchecked(self, row, column)
97                        != MatrixGetEntry::<Z>::get_entry_unchecked(self, column, row)
98                } {
99                    return false;
100                }
101            }
102        }
103        true
104    }
105}
106
107#[cfg(test)]
108mod test_is_identity {
109    use super::MatZq;
110    use std::str::FromStr;
111
112    /// Ensure that is_identity returns `true` for identity matrices.
113    #[test]
114    fn identity_detection() {
115        let ident_1 = MatZq::from_str("[[1, 0],[0, 1]] mod 7").unwrap();
116        let ident_2 = MatZq::from_str("[[1, 0],[0, 1],[0, 0]] mod 7").unwrap();
117
118        assert!(ident_1.is_identity());
119        assert!(ident_2.is_identity());
120    }
121
122    /// Ensure that is_identity returns `false` for non-identity matrices.
123    #[test]
124    fn identity_rejection() {
125        let small = MatZq::from_str("[[0, 0],[2, 0]] mod 17").unwrap();
126        let large = MatZq::from_str(&format!(
127            "[[1, 0],[0, {}]] mod {}",
128            (u128::MAX - 1) / 2 + 2,
129            u128::MAX
130        ))
131        .unwrap(); // the last 64 bit represent `1`
132
133        assert!(!small.is_identity());
134        assert!(!large.is_identity());
135    }
136}
137
138#[cfg(test)]
139mod test_is_zero {
140    use super::MatZq;
141    use std::str::FromStr;
142
143    /// Ensure that is_zero returns `true` for all zero matrices.
144    #[test]
145    fn zero_detection() {
146        let zero_1 = MatZq::from_str("[[0, 0],[0, 0]] mod 7").unwrap();
147        let zero_2 = MatZq::from_str("[[0, 0],[0, 0],[0, 0],[0, 0]] mod 7").unwrap();
148
149        assert!(zero_1.is_zero());
150        assert!(zero_2.is_zero());
151    }
152
153    /// Ensure that is_zero returns `false` for non-zero matrices.
154    #[test]
155    fn zero_rejection() {
156        let small = MatZq::from_str("[[0, 0],[2, 0]] mod 7").unwrap();
157        let large = MatZq::from_str(&format!(
158            "[[0, 0],[{}, 0]] mod {}",
159            (u128::MAX - 1) / 2 + 1,
160            u128::MAX
161        ))
162        .unwrap();
163
164        assert!(!small.is_zero());
165        assert!(!large.is_zero());
166    }
167}
168
169#[cfg(test)]
170mod test_is_square {
171    use super::MatZq;
172    use std::str::FromStr;
173
174    /// Ensure that is_square returns `true` for square matrices.
175    #[test]
176    fn square_detection() {
177        let square_1 = MatZq::from_str("[[0, 4],[0, 0]] mod 10").unwrap();
178        let square_2 = MatZq::from_str("[[0, 6, 4],[0, 0, 1],[4, 6, 1]] mod 7").unwrap();
179
180        assert!(square_1.is_square());
181        assert!(square_2.is_square());
182    }
183
184    /// Ensure that is_square returns `false` for non-square matrices.
185    #[test]
186    fn sqaure_rejection() {
187        let small = MatZq::from_str("[[0, 0, 4],[2, 0, 1]] mod 7").unwrap();
188        let large = MatZq::from_str(&format!(
189            "[[9, 0],[{}, 0],[1, 4]] mod {}",
190            (u128::MAX - 1) / 2 + 1,
191            u128::MAX
192        ))
193        .unwrap();
194
195        assert!(!small.is_square());
196        assert!(!large.is_square());
197    }
198}
199
200#[cfg(test)]
201mod test_is_symmetric {
202    use super::MatZq;
203    use std::str::FromStr;
204
205    /// Ensure that is_symmetric returns `false` for non-symmetric matrices.
206    #[test]
207    fn symmetric_rejection() {
208        let mat_2x3 = MatZq::from_str("[[0, 5, 4],[2, 0, 1]] mod 17").unwrap();
209        let mat_2x2 = MatZq::from_str("[[9, 0],[127, 0]] mod 17").unwrap();
210
211        assert!(!mat_2x3.is_symmetric());
212        assert!(!mat_2x2.is_symmetric());
213    }
214
215    /// Ensure that is_symmetric returns `true` for symmetric matrices.
216    #[test]
217    fn symmetric_detection() {
218        let mat_2x2 = MatZq::from_str(&format!(
219            "[[2, {}],[{}, {}]] mod {}",
220            i64::MAX,
221            i64::MAX,
222            u64::MIN,
223            u64::MAX
224        ))
225        .unwrap();
226
227        assert!(mat_2x2.is_symmetric());
228    }
229}