qfall_math/integer_mod_q/mat_polynomial_ring_zq/
default.rs

1// Copyright © 2023 Marcel Luca Schmidt
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//! Initialize a [`MatPolynomialRingZq`] with common defaults, e.g., zero and identity.
10
11use super::MatPolynomialRingZq;
12use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
13use std::fmt::Display;
14
15impl MatPolynomialRingZq {
16    /// Creates a new matrix with `num_rows` rows, `num_cols` columns,
17    /// zeros as entries and `modulus` as the modulus.
18    ///
19    /// Parameters:
20    /// - `num_rows`: number of rows the new matrix should have
21    /// - `num_cols`: number of columns the new matrix should have
22    /// - `modulus`: the common modulus of the matrix entries
23    ///
24    /// Returns a new [`MatPolynomialRingZq`] instance of the provided dimensions.
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::integer_mod_q::PolyOverZq;
29    /// use qfall_math::integer_mod_q::MatPolynomialRingZq;
30    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
31    /// use std::str::FromStr;
32    ///
33    /// let poly_mod = PolyOverZq::from_str("3  1 0 1 mod 17").unwrap();
34    /// let modulus = ModulusPolynomialRingZq::try_from(&poly_mod).unwrap();
35    ///
36    /// let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
37    /// ```
38    ///
39    /// # Panics ...
40    /// - if the number of rows or columns is negative, `0`, or does not fit into an [`i64`].
41    pub fn new(
42        num_rows: impl TryInto<i64> + Display,
43        num_cols: impl TryInto<i64> + Display,
44        modulus: impl Into<ModulusPolynomialRingZq>,
45    ) -> Self {
46        let matrix = MatPolyOverZ::new(num_rows, num_cols);
47
48        // Here we do not use the efficient from trait with ownership, as there are no
49        // values that need to be reduced.
50        MatPolynomialRingZq {
51            matrix,
52            modulus: modulus.into(),
53        }
54    }
55
56    /// Generate a `num_rows` times `num_columns` matrix with `1` on the
57    /// diagonal and `0` anywhere else with a given modulus.
58    ///
59    /// Parameters:
60    /// - `rum_rows`: the number of rows of the identity matrix
61    /// - `num_columns`: the number of columns of the identity matrix
62    /// - `modulus`: the polynomial mod q which serves as the modulus of the matrix
63    ///
64    /// Returns a matrix with `1` across the diagonal and `0` anywhere else.
65    ///
66    /// # Examples
67    /// ```
68    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
69    /// use std::str::FromStr;
70    ///
71    /// let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
72    /// let matrix = MatPolynomialRingZq::identity(2, 3, &modulus);
73    ///
74    /// let identity = MatPolynomialRingZq::identity(10, 10, &modulus);
75    /// ```
76    ///
77    /// # Panics ...
78    /// - if the provided number of rows and columns are not suited to create a matrix.
79    ///   For further information see [`MatPolyOverZ::new`].
80    pub fn identity(
81        num_rows: impl TryInto<i64> + Display,
82        num_cols: impl TryInto<i64> + Display,
83        modulus: impl Into<ModulusPolynomialRingZq>,
84    ) -> Self {
85        let matrix = MatPolyOverZ::identity(num_rows, num_cols);
86        MatPolynomialRingZq::from((matrix, modulus))
87    }
88}
89
90#[cfg(test)]
91mod test_new {
92    use crate::{
93        integer::PolyOverZ,
94        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq, PolyOverZq},
95        traits::MatrixGetEntry,
96    };
97    use std::str::FromStr;
98
99    const LARGE_PRIME: u64 = u64::MAX - 58;
100
101    /// Ensure that initialization works.
102    #[test]
103    fn initialization() {
104        let poly_mod = PolyOverZq::from_str("3  1 0 1 mod 17").unwrap();
105        let modulus = ModulusPolynomialRingZq::from(&poly_mod);
106
107        let _ = MatPolynomialRingZq::new(2, 2, &modulus);
108    }
109
110    /// Ensure that entries of a new matrix are `0`.
111    #[test]
112    fn entry_zero() {
113        let poly_mod = PolyOverZq::from_str("3  1 0 1 mod 17").unwrap();
114        let modulus = ModulusPolynomialRingZq::from(&poly_mod);
115
116        let matrix = MatPolynomialRingZq::new(2, 2, &modulus);
117
118        let entry_1: PolyOverZ = matrix.get_entry(0, 0).unwrap();
119        let entry_2: PolyOverZ = matrix.get_entry(0, 1).unwrap();
120        let entry_3: PolyOverZ = matrix.get_entry(1, 0).unwrap();
121        let entry_4: PolyOverZ = matrix.get_entry(1, 1).unwrap();
122
123        assert_eq!(PolyOverZ::default(), entry_1);
124        assert_eq!(PolyOverZ::default(), entry_2);
125        assert_eq!(PolyOverZ::default(), entry_3);
126        assert_eq!(PolyOverZ::default(), entry_4);
127    }
128
129    /// Ensure that a new zero matrix fails with `0` as `num_cols`.
130    #[should_panic]
131    #[test]
132    fn error_zero_num_cols() {
133        let poly_mod = PolyOverZq::from_str("3  1 0 1 mod 17").unwrap();
134        let modulus = ModulusPolynomialRingZq::from(&poly_mod);
135
136        let _ = MatPolynomialRingZq::new(1, 0, &modulus);
137    }
138
139    /// Ensure that a new zero matrix fails with `0` as `num_rows`.
140    #[should_panic]
141    #[test]
142    fn error_zero_num_rows() {
143        let poly_mod = PolyOverZq::from_str("3  1 0 1 mod 17").unwrap();
144        let modulus = ModulusPolynomialRingZq::from(&poly_mod);
145
146        let _ = MatPolynomialRingZq::new(0, 1, &modulus);
147    }
148
149    /// Ensure that the modulus can be large.
150    #[test]
151    fn large_modulus() {
152        let poly_mod =
153            PolyOverZq::from_str(&format!("3  1 {} 1 mod {LARGE_PRIME}", i64::MAX)).unwrap();
154        let modulus = ModulusPolynomialRingZq::from(&poly_mod);
155
156        let _ = MatPolynomialRingZq::new(2, 2, &modulus);
157    }
158}
159
160#[cfg(test)]
161mod test_identity {
162    use crate::{
163        integer::PolyOverZ,
164        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
165        traits::{MatrixDimensions, MatrixGetEntry},
166    };
167    use std::str::FromStr;
168
169    /// Tests if an identity matrix is set from a zero matrix.
170    #[test]
171    fn identity() {
172        let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
173        let matrix = MatPolynomialRingZq::identity(10, 10, &modulus);
174
175        for i in 0..matrix.get_num_rows() {
176            for j in 0..matrix.get_num_columns() {
177                let entry: PolyOverZ = matrix.get_entry(i, j).unwrap();
178                if i != j {
179                    assert!(entry.is_zero());
180                } else {
181                    assert!(entry.is_one());
182                }
183            }
184        }
185    }
186
187    /// Tests if function works for a non-square matrix.
188    #[test]
189    fn non_square_works() {
190        let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
191        let matrix = MatPolynomialRingZq::identity(10, 7, &modulus);
192
193        for i in 0..10 {
194            for j in 0..7 {
195                let entry: PolyOverZ = matrix.get_entry(i, j).unwrap();
196                if i != j {
197                    assert!(entry.is_zero());
198                } else {
199                    assert!(entry.is_one());
200                }
201            }
202        }
203
204        let matrix = MatPolynomialRingZq::identity(7, 10, &modulus);
205
206        for i in 0..7 {
207            for j in 0..10 {
208                let entry: PolyOverZ = matrix.get_entry(i, j).unwrap();
209                if i != j {
210                    assert!(entry.is_zero());
211                } else {
212                    assert!(entry.is_one());
213                }
214            }
215        }
216    }
217
218    /// Tests if an identity matrix can be created using a large modulus.
219    #[test]
220    fn modulus_large() {
221        let modulus =
222            ModulusPolynomialRingZq::from_str(&format!("4  1 0 {} 1 mod {}", i64::MAX, u64::MAX))
223                .unwrap();
224        let matrix = MatPolynomialRingZq::identity(10, 10, &modulus);
225
226        for i in 0..10 {
227            for j in 0..10 {
228                let entry: PolyOverZ = matrix.get_entry(i, j).unwrap();
229                if i != j {
230                    assert!(entry.is_zero());
231                } else {
232                    assert!(entry.is_one());
233                }
234            }
235        }
236    }
237
238    /// Assert that a number of rows that is not suited to create a matrix is not allowed.
239    #[should_panic]
240    #[test]
241    fn no_rows() {
242        let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
243        let _ = MatPolynomialRingZq::identity(0, 7, &modulus);
244    }
245
246    /// Assert that a number of columns that is not suited to create a matrix is not allowed.
247    #[should_panic]
248    #[test]
249    fn no_columns() {
250        let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
251        let _ = MatPolynomialRingZq::identity(7, 0, &modulus);
252    }
253}