qfall_math/integer_mod_q/mat_zq/
set.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//! Implementation to manipulate a [`MatZq`] matrix.
10
11use crate::{
12    error::MathError,
13    integer::Z,
14    integer_mod_q::{MatZq, Modulus, Zq},
15    macros::for_others::implement_for_owned,
16    traits::{AsInteger, MatrixDimensions, MatrixSetEntry, MatrixSetSubmatrix, MatrixSwaps},
17    utils::index::{evaluate_index_for_vector, evaluate_indices_for_matrix},
18};
19use flint_sys::{
20    fmpz::fmpz_swap,
21    fmpz_mat::{
22        fmpz_mat_entry, fmpz_mat_invert_cols, fmpz_mat_invert_rows, fmpz_mat_swap_cols,
23        fmpz_mat_swap_rows,
24    },
25    fmpz_mod_mat::{
26        _fmpz_mod_mat_reduce, _fmpz_mod_mat_set_mod, fmpz_mod_mat_set, fmpz_mod_mat_set_entry,
27        fmpz_mod_mat_window_clear, fmpz_mod_mat_window_init,
28    },
29};
30use std::{
31    fmt::Display,
32    mem::MaybeUninit,
33    ptr::{null, null_mut},
34};
35
36impl<Integer: Into<Z>> MatrixSetEntry<Integer> for MatZq {
37    /// Sets the value of a specific matrix entry according to a given `value`
38    /// that implements [`Into<Z>`].
39    ///
40    /// Parameters:
41    /// - `row`: specifies the row in which the entry is located
42    /// - `column`: specifies the column in which the entry is located
43    /// - `value`: specifies the value to which the entry is set
44    ///
45    /// Negative indices can be used to index from the back, e.g., `-1` for
46    /// the last element.
47    ///
48    /// Returns an empty `Ok` if the action could be performed successfully.
49    /// Otherwise, a [`MathError`] is returned if the specified entry is not part of the matrix.
50    ///
51    /// # Examples
52    /// ```
53    /// use qfall_math::integer_mod_q::MatZq;
54    /// use qfall_math::traits::*;
55    ///
56    /// let mut matrix = MatZq::new(3, 3, 10);
57    ///
58    /// matrix.set_entry(0, 1, 5).unwrap();
59    /// matrix.set_entry(-1, 2, 19).unwrap();
60    ///
61    /// assert_eq!("[[0, 5, 0],[0, 0, 0],[0, 0, 9]] mod 10", matrix.to_string());
62    /// ```
63    ///
64    /// # Errors and Failures
65    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
66    ///   if `row` or `column` are greater than the matrix size.
67    fn set_entry(
68        &mut self,
69        row: impl TryInto<i64> + Display,
70        column: impl TryInto<i64> + Display,
71        value: Integer,
72    ) -> Result<(), MathError> {
73        // Calculate mod q before adding the entry to the matrix.
74        let value: Zq = Zq::from((value, &self.modulus));
75
76        self.set_entry(row, column, value)
77    }
78
79    /// Sets the value of a specific matrix entry according to a given `value`
80    /// that implements [`Into<Z>`] without checking whether the coordinate is part of the matrix,
81    /// if the moduli match or the entry is reduced.
82    ///
83    /// Parameters:
84    /// - `row`: specifies the row in which the entry is located
85    /// - `column`: specifies the column in which the entry is located
86    /// - `value`: specifies the value to which the entry is set
87    ///
88    /// # Safety
89    /// To use this function safely, make sure that the selected entry is part
90    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
91    /// occur.
92    ///
93    /// # Examples
94    /// ```
95    /// use qfall_math::integer_mod_q::MatZq;
96    /// use qfall_math::traits::*;
97    ///
98    /// let mut matrix = MatZq::new(3, 3, 10);
99    ///
100    /// unsafe {
101    ///     matrix.set_entry_unchecked(0, 1, 5);
102    ///     matrix.set_entry_unchecked(2, 2, 19);
103    /// }
104    ///
105    /// assert_eq!("[[0, 5, 0],[0, 0, 0],[0, 0, 19]] mod 10", matrix.to_string());
106    /// ```
107    unsafe fn set_entry_unchecked(&mut self, row: i64, column: i64, value: Integer) {
108        let value: Z = value.into();
109
110        unsafe {
111            // get entry and replace the pointed at value with the specified value
112            fmpz_mod_mat_set_entry(&mut self.matrix, row, column, &value.value)
113        };
114    }
115}
116
117impl MatrixSetEntry<&Zq> for MatZq {
118    /// Sets the value of a specific matrix entry according to a given `value` of type [`Zq`]
119    /// without checking whether the coordinate is part of the matrix,
120    /// if the moduli match or the entry is reduced.
121    ///
122    /// Parameters:
123    /// - `row`: specifies the row in which the entry is located
124    /// - `column`: specifies the column in which the entry is located
125    /// - `value`: specifies the value to which the entry is set
126    ///
127    /// # Safety
128    /// To use this function safely, make sure that the selected entry is part
129    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
130    /// occur.
131    ///
132    /// # Examples
133    /// ```
134    /// use qfall_math::integer_mod_q::{MatZq, Zq};
135    /// use qfall_math::traits::*;
136    ///
137    /// let mut matrix = MatZq::new(3, 3, 10);
138    /// let value = Zq::from((5, 10));
139    ///
140    /// unsafe {
141    ///     matrix.set_entry_unchecked(0, 1, &value);
142    ///     matrix.set_entry_unchecked(2, 2, Zq::from((19, 10)));
143    /// }
144    ///
145    /// assert_eq!("[[0, 5, 0],[0, 0, 0],[0, 0, 9]] mod 10", matrix.to_string());
146    /// ```
147    unsafe fn set_entry_unchecked(&mut self, row: i64, column: i64, value: &Zq) {
148        unsafe {
149            // get entry and replace the pointed at value with the specified value
150            fmpz_mod_mat_set_entry(&mut self.matrix, row, column, &value.value.value)
151        };
152    }
153}
154
155implement_for_owned!(Zq, MatZq, MatrixSetEntry);
156
157impl MatrixSetSubmatrix for MatZq {
158    /// Sets the matrix entries in `self` to entries defined in `other`.
159    /// The entries in `self` starting from `(row_self_start, col_self_start)` up to
160    /// `(row_self_end, col_self_end)`are set to be
161    /// the entries from the submatrix from `other` defined by `(row_other_start, col_other_start)`
162    /// to `(row_other_end, col_other_end)` (exclusively).
163    ///
164    /// Parameters:
165    /// `row_self_start`: the starting row of the matrix in which to set a submatrix
166    /// `col_self_start`: the starting column of the matrix in which to set a submatrix
167    /// `other`: the matrix from where to take the submatrix to set
168    /// `row_other_start`: the starting row of the specified submatrix
169    /// `col_other_start`: the starting column of the specified submatrix
170    /// `row_other_end`: the ending row of the specified submatrix
171    /// `col_other_end`:the ending column of the specified submatrix
172    ///
173    /// # Examples
174    /// ```
175    /// use qfall_math::integer_mod_q::{MatZq, Modulus};
176    /// use qfall_math::integer::MatZ;
177    /// use qfall_math::traits::MatrixSetSubmatrix;
178    /// use std::str::FromStr;
179    ///
180    /// let mat = MatZ::identity(3, 3);
181    /// let modulus = Modulus::from(17);
182    /// let mut mat = MatZq::from((&mat, &modulus));
183    ///
184    /// mat.set_submatrix(0, 1, &mat.clone(), 0, 0, 1, 1).unwrap();
185    /// // [[1,1,0],[0,0,1],[0,0,1]]
186    /// let mat_cmp = MatZ::from_str("[[1, 1, 0],[0, 0, 1],[0, 0, 1]]").unwrap();
187    /// assert_eq!(mat, MatZq::from((&mat_cmp, &modulus)));
188    ///
189    /// unsafe{ mat.set_submatrix_unchecked(2, 0, 3, 2, &mat.clone(), 0, 0, 1, 2) };
190    /// let mat_cmp = MatZ::from_str("[[1, 1, 0],[0, 0, 1],[1, 1, 1]]").unwrap();
191    /// assert_eq!(mat, MatZq::from((&mat_cmp, &modulus)));
192    /// ```
193    ///
194    /// # Safety
195    /// To use this function safely, make sure that the selected submatrices are part
196    /// of the matrices, the submatrices are of the same dimensions and the base types are the same.
197    /// If not, memory leaks, unexpected panics, etc. might occur.
198    unsafe fn set_submatrix_unchecked(
199        &mut self,
200        row_self_start: i64,
201        col_self_start: i64,
202        row_self_end: i64,
203        col_self_end: i64,
204        other: &Self,
205        row_other_start: i64,
206        col_other_start: i64,
207        row_other_end: i64,
208        col_other_end: i64,
209    ) {
210        {
211            let mut window_self = MaybeUninit::uninit();
212            // The memory for the elements of window is shared with self.
213            unsafe {
214                fmpz_mod_mat_window_init(
215                    window_self.as_mut_ptr(),
216                    &self.matrix,
217                    row_self_start,
218                    col_self_start,
219                    row_self_end,
220                    col_self_end,
221                )
222            };
223            let mut window_other = MaybeUninit::uninit();
224            // The memory for the elements of window is shared with other.
225            unsafe {
226                fmpz_mod_mat_window_init(
227                    window_other.as_mut_ptr(),
228                    &other.matrix,
229                    row_other_start,
230                    col_other_start,
231                    row_other_end,
232                    col_other_end,
233                )
234            };
235            unsafe {
236                fmpz_mod_mat_set(window_self.as_mut_ptr(), window_other.as_ptr());
237
238                // Clears the matrix window and releases any memory that it uses. Note that
239                // the memory to the underlying matrix that window points to is not freed
240                fmpz_mod_mat_window_clear(window_self.as_mut_ptr());
241                fmpz_mod_mat_window_clear(window_other.as_mut_ptr());
242            }
243        }
244    }
245}
246
247impl MatrixSwaps for MatZq {
248    /// Swaps two entries of the specified matrix.
249    ///
250    /// Parameters:
251    /// - `row_0`: specifies the row, in which the first entry is located
252    /// - `col_0`: specifies the column, in which the first entry is located
253    /// - `row_1`: specifies the row, in which the second entry is located
254    /// - `col_1`: specifies the column, in which the second entry is located
255    ///
256    /// Negative indices can be used to index from the back, e.g., `-1` for
257    /// the last element.
258    ///
259    /// Returns an empty `Ok` if the action could be performed successfully.
260    /// Otherwise, a [`MathError`] is returned if one of the specified entries is not part of the matrix.
261    ///
262    /// # Examples
263    /// ```
264    /// use qfall_math::{integer_mod_q::MatZq, traits::MatrixSwaps};
265    ///
266    /// let mut matrix = MatZq::new(4, 3, 5);
267    /// matrix.swap_entries(0, 0, 2, 1);
268    /// ```
269    ///
270    /// # Errors and Failures
271    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
272    ///   if row or column are greater than the matrix size.
273    fn swap_entries(
274        &mut self,
275        row_0: impl TryInto<i64> + Display,
276        col_0: impl TryInto<i64> + Display,
277        row_1: impl TryInto<i64> + Display,
278        col_1: impl TryInto<i64> + Display,
279    ) -> Result<(), MathError> {
280        let (row_0, col_0) = evaluate_indices_for_matrix(self, row_0, col_0)?;
281        let (row_1, col_1) = evaluate_indices_for_matrix(self, row_1, col_1)?;
282
283        unsafe {
284            fmpz_swap(
285                fmpz_mat_entry(&self.matrix.mat[0], row_0, col_0),
286                fmpz_mat_entry(&self.matrix.mat[0], row_1, col_1),
287            )
288        };
289        Ok(())
290    }
291
292    /// Swaps two columns of the specified matrix.
293    ///
294    /// Parameters:
295    /// - `col_0`: specifies the first column which is swapped with the second one
296    /// - `col_1`: specifies the second column which is swapped with the first one
297    ///
298    /// Negative indices can be used to index from the back, e.g., `-1` for
299    /// the last element.
300    ///
301    /// Returns an empty `Ok` if the action could be performed successfully.
302    /// Otherwise, a [`MathError`] is returned if one of the specified columns is not part of the matrix.
303    ///
304    /// # Examples
305    /// ```
306    /// use qfall_math::{integer_mod_q::MatZq, traits::MatrixSwaps};
307    ///
308    /// let mut matrix = MatZq::new(4, 3, 5);
309    /// matrix.swap_columns(0, 2);
310    /// ```
311    ///
312    /// # Errors and Failures
313    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
314    ///   if one of the given columns is greater than the matrix.
315    fn swap_columns(
316        &mut self,
317        col_0: impl TryInto<i64> + Display,
318        col_1: impl TryInto<i64> + Display,
319    ) -> Result<(), MathError> {
320        let num_cols = self.get_num_columns();
321        let col_0 = evaluate_index_for_vector(col_0, num_cols)?;
322        let col_1 = evaluate_index_for_vector(col_1, num_cols)?;
323
324        if col_0 >= num_cols || col_1 >= num_cols {
325            return Err(MathError::OutOfBounds(
326                format!("smaller than {num_cols}"),
327                if col_0 > col_1 {
328                    col_0.to_string()
329                } else {
330                    col_1.to_string()
331                },
332            ));
333        }
334        unsafe { fmpz_mat_swap_cols(&mut self.matrix.mat[0], null(), col_0, col_1) }
335        Ok(())
336    }
337
338    /// Swaps two rows of the specified matrix.
339    ///
340    /// Parameters:
341    /// - `row_0`: specifies the first row which is swapped with the second one
342    /// - `row_1`: specifies the second row which is swapped with the first one
343    ///
344    /// Negative indices can be used to index from the back, e.g., `-1` for
345    /// the last element.
346    ///
347    /// Returns an empty `Ok` if the action could be performed successfully.
348    /// Otherwise, a [`MathError`] is returned if one of the specified rows is not part of the matrix.
349    ///
350    /// # Examples
351    /// ```
352    /// use qfall_math::{integer_mod_q::MatZq, traits::MatrixSwaps};
353    ///
354    /// let mut matrix = MatZq::new(4, 3, 5);
355    /// matrix.swap_rows(0, 2);
356    /// ```
357    ///
358    /// # Errors and Failures
359    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
360    ///   if one of the given rows is greater than the matrix.
361    fn swap_rows(
362        &mut self,
363        row_0: impl TryInto<i64> + Display,
364        row_1: impl TryInto<i64> + Display,
365    ) -> Result<(), MathError> {
366        let num_rows = self.get_num_rows();
367        let row_0 = evaluate_index_for_vector(row_0, num_rows)?;
368        let row_1 = evaluate_index_for_vector(row_1, num_rows)?;
369
370        if row_0 >= num_rows || row_1 >= num_rows {
371            return Err(MathError::OutOfBounds(
372                format!("smaller than {num_rows}"),
373                if row_0 > row_1 {
374                    row_0.to_string()
375                } else {
376                    row_1.to_string()
377                },
378            ));
379        }
380        unsafe { fmpz_mat_swap_rows(&mut self.matrix.mat[0], null(), row_0, row_1) }
381        Ok(())
382    }
383}
384
385impl MatZq {
386    /// Swaps the `i`-th column with the `n-i`-th column for all `i <= n/2`
387    /// of the specified matrix with `n` columns.
388    ///
389    /// # Examples
390    /// ```
391    /// use qfall_math::integer_mod_q::MatZq;
392    ///
393    /// let mut matrix = MatZq::new(4, 3, 5);
394    /// matrix.reverse_columns();
395    /// ```
396    pub fn reverse_columns(&mut self) {
397        // If the second argument to this function is not null, the permutation
398        // of the columns is also applied to this argument.
399        // Hence, passing in null is justified here.
400        unsafe { fmpz_mat_invert_cols(&mut self.matrix.mat[0], null_mut()) }
401    }
402
403    /// Swaps the `i`-th row with the `n-i`-th row for all `i <= n/2`
404    /// of the specified matrix with `n` rows.
405    ///
406    /// # Examples
407    /// ```
408    /// use qfall_math::integer_mod_q::MatZq;
409    ///
410    /// let mut matrix = MatZq::new(4, 3, 5);
411    /// matrix.reverse_rows();
412    /// ```
413    pub fn reverse_rows(&mut self) {
414        // If the second argument to this function is not null, the permutation
415        // of the rows is also applied to this argument.
416        // Hence, passing in null is justified here.
417        unsafe { fmpz_mat_invert_rows(&mut self.matrix.mat[0], null_mut()) }
418    }
419
420    /// Changes the modulus of the given matrix to the new modulus.
421    /// It takes the representation of each coefficient in [0, q) as the new
422    /// matrix entries and reduces them by the new modulus automatically.
423    ///
424    /// Parameters:
425    /// - `modulus`: the new modulus of the matrix
426    ///
427    /// # Examples
428    /// ```
429    /// use qfall_math::integer_mod_q::{MatZq, Modulus};
430    /// use std::str::FromStr;
431    ///
432    /// let mut mat = MatZq::from_str("[[1, 2]] mod 3").unwrap();
433    /// mat.change_modulus(2);
434    /// ```
435    ///
436    /// # Panics ...
437    /// - if `modulus` is smaller than `2`.
438    pub fn change_modulus(&mut self, modulus: impl Into<Modulus>) {
439        self.modulus = modulus.into();
440        unsafe {
441            _fmpz_mod_mat_set_mod(&mut self.matrix, self.modulus.get_fmpz_ref().unwrap());
442            _fmpz_mod_mat_reduce(&mut self.matrix)
443        }
444    }
445}
446
447#[cfg(test)]
448mod test_setter {
449    use crate::{
450        integer::Z,
451        integer_mod_q::{MatZq, Zq},
452        traits::{MatrixGetEntry, MatrixSetEntry, MatrixSetSubmatrix},
453    };
454    use std::str::FromStr;
455
456    /// Ensure that setting entries works with large numbers.
457    #[test]
458    fn max_int_positive() {
459        let mut matrix = MatZq::new(5, 10, u64::MAX);
460        let value = Z::from(i64::MAX);
461        matrix.set_entry(0, 0, value).unwrap();
462
463        let entry: Z = matrix.get_entry(0, 0).unwrap();
464
465        assert_eq!(Z::from(i64::MAX), entry);
466    }
467
468    /// Ensure that setting entries works with large numbers (larger than [`i64`]).
469    #[test]
470    fn large_positive() {
471        let mut matrix = MatZq::new(5, 10, u64::MAX);
472        let value = Z::from(u64::MAX - 1);
473        matrix.set_entry(0, 0, value).unwrap();
474
475        let entry: Z = matrix.get_entry(0, 0).unwrap();
476
477        assert_eq!(u64::MAX - 1, entry);
478    }
479
480    /// Ensure that setting entries works with large numbers.
481    #[test]
482    fn max_int_negative() {
483        let mut matrix = MatZq::new(5, 10, u64::MAX);
484        let value = Z::from(-i64::MAX);
485        matrix.set_entry(0, 0, value).unwrap();
486
487        let entry: Z = matrix.get_entry(0, 0).unwrap();
488
489        assert_eq!((u64::MAX as i128 - i64::MAX as i128) as u64, entry);
490    }
491
492    /// Ensure that setting entries works with large numbers (larger than [`i64`]).
493    #[test]
494    fn large_negative() {
495        let mut matrix = MatZq::new(5, 10, u64::MAX);
496        let value = Z::from(-i64::MAX - 1);
497        matrix.set_entry(0, 0, value).unwrap();
498
499        let entry: Z = matrix.get_entry(0, 0).unwrap();
500
501        assert_eq!((u64::MAX as i128 - i64::MAX as i128) as u64 - 1, entry);
502    }
503
504    /// Ensure that a wrong number of rows yields an Error.
505    #[test]
506    fn error_wrong_row() {
507        let mut matrix = MatZq::new(5, 10, 7);
508
509        assert!(matrix.set_entry(5, 1, 3).is_err());
510        assert!(matrix.set_entry(-6, 1, 1).is_err());
511    }
512
513    /// Ensure that a wrong number of columns yields an Error.
514    #[test]
515    fn error_wrong_column() {
516        let mut matrix = MatZq::new(5, 10, 7);
517
518        assert!(matrix.set_entry(1, 100, 3).is_err());
519        assert!(matrix.set_entry(1, -11, 1).is_err());
520    }
521
522    /// Ensure that setting entries works with different types.
523    #[test]
524    fn diff_types() {
525        let mut matrix = MatZq::new(5, 10, 56);
526
527        matrix.set_entry(0, 0, Z::default()).unwrap();
528        matrix.set_entry(0, 0, Zq::from((12, 56))).unwrap();
529        matrix.set_entry(0, 0, 3).unwrap();
530        matrix.set_entry(0, 0, &Z::default()).unwrap();
531        matrix.set_entry(0, 0, &Zq::from((12, 56))).unwrap();
532    }
533
534    /// Ensure that negative indices return address the correct entires.
535    #[test]
536    fn negative_indexing() {
537        let mut matrix = MatZq::new(3, 3, 10);
538
539        matrix.set_entry(-1, -1, 9).unwrap();
540        matrix.set_entry(-1, -2, 8).unwrap();
541        matrix.set_entry(-3, -3, Zq::from((1, 10))).unwrap();
542
543        let matrix_cmp = MatZq::from_str("[[1, 0, 0],[0, 0, 0],[0, 8, 9]] mod 10").unwrap();
544        assert_eq!(matrix_cmp, matrix);
545    }
546
547    /// Ensure that value is correctly reduced.
548    #[test]
549    fn set_entry_reduce() {
550        let mut matrix = MatZq::new(5, 10, 3);
551        matrix.set_entry(1, 1, Z::from(u64::MAX)).unwrap();
552
553        let entry: Z = matrix.get_entry(1, 1).unwrap();
554
555        assert_eq!(entry, Z::from(0));
556    }
557
558    /// Ensure that differing moduli result in an error.
559    #[test]
560    fn modulus_error() {
561        let mut matrix = MatZq::new(5, 10, 3);
562        assert!(matrix.set_entry(1, 1, Zq::from((2, 5))).is_err());
563    }
564
565    /// Ensures that setting columns works fine for small entries
566    #[test]
567    fn column_small_entries() {
568        let mut mat_1 = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 11").unwrap();
569        let mat_2 = MatZq::from_str("[[0],[-1]] mod 11").unwrap();
570
571        let cmp = MatZq::from_str("[[1, 0, 3],[4, -1, 6]] mod 11").unwrap();
572
573        mat_1.set_column(1, &mat_2, 0).unwrap();
574
575        assert_eq!(cmp, mat_1);
576    }
577
578    /// Ensures that setting columns works fine for large entries
579    #[test]
580    fn column_large_entries() {
581        let mut mat_1 = MatZq::from_str(&format!(
582            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
583            i64::MIN,
584            i64::MAX,
585            i64::MAX,
586            u64::MAX
587        ))
588        .unwrap();
589        let mat_2 = MatZq::from_str(&format!(
590            "[[1, {}],[{}, 0],[7, -1]] mod {}",
591            i64::MIN,
592            i64::MAX,
593            u64::MAX
594        ))
595        .unwrap();
596        let cmp = MatZq::from_str(&format!(
597            "[[{}, 1, 3, 4],[0, 4, {}, 5],[-1, 6, 8, 9]] mod {}",
598            i64::MIN,
599            i64::MAX,
600            u64::MAX
601        ))
602        .unwrap();
603
604        mat_1.set_column(0, &mat_2, 1).unwrap();
605
606        assert_eq!(cmp, mat_1);
607    }
608
609    /// Ensures that setting the column to itself does not change anything
610    #[test]
611    fn column_swap_same_entry() {
612        let mut mat_1 = MatZq::from_str(&format!(
613            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
614            i64::MIN,
615            i64::MAX,
616            i64::MAX,
617            u64::MAX
618        ))
619        .unwrap();
620        let cmp = mat_1.clone();
621
622        mat_1.set_column(0, &cmp, 0).unwrap();
623        mat_1.set_column(1, &cmp, 1).unwrap();
624
625        assert_eq!(cmp, mat_1);
626    }
627
628    /// Ensures that `set_column` returns an error if one of the specified columns is out of bounds
629    #[test]
630    fn column_out_of_bounds() {
631        let mut mat_1 = MatZq::new(5, 2, 17);
632        let mat_2 = mat_1.clone();
633
634        assert!(mat_1.set_column(-3, &mat_2, 0).is_err());
635        assert!(mat_1.set_column(2, &mat_2, 0).is_err());
636        assert!(mat_1.set_column(1, &mat_2, -3).is_err());
637        assert!(mat_1.set_column(1, &mat_2, 2).is_err());
638    }
639
640    /// Ensures that mismatching row dimensions result in an error
641    #[test]
642    fn column_mismatching_columns() {
643        let mut mat_1 = MatZq::new(5, 2, 17);
644        let mat_2 = MatZq::new(2, 2, 17);
645
646        assert!(mat_1.set_column(0, &mat_2, 0).is_err());
647        assert!(mat_1.set_column(1, &mat_2, 1).is_err());
648    }
649
650    /// Ensures that mismatching moduli result in an error
651    #[test]
652    fn column_mismatching_moduli() {
653        let mut mat_1 = MatZq::new(3, 3, 19);
654        let mat_2 = MatZq::new(3, 3, 17);
655
656        assert!(mat_1.set_column(0, &mat_2, 0).is_err());
657    }
658
659    /// Ensures that setting rows works fine for small entries
660    #[test]
661    fn row_small_entries() {
662        let mut mat_1 = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 11").unwrap();
663        let mat_2 = MatZq::from_str("[[0, -1, 2]] mod 11").unwrap();
664        let cmp = MatZq::from_str("[[1, 2, 3],[0, -1, 2]] mod 11").unwrap();
665
666        let _ = mat_1.set_row(1, &mat_2, 0);
667
668        assert_eq!(cmp, mat_1);
669    }
670
671    /// Ensures that setting rows works fine for large entries
672    #[test]
673    fn row_large_entries() {
674        let mut mat_1 = MatZq::from_str(&format!(
675            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
676            i64::MIN,
677            i64::MAX,
678            i64::MAX,
679            u64::MAX
680        ))
681        .unwrap();
682        let mat_2 = MatZq::from_str(&format!(
683            "[[0, 0, 0, 0],[{}, 0, {}, 0]] mod {}",
684            i64::MIN,
685            i64::MAX,
686            u64::MAX
687        ))
688        .unwrap();
689        let cmp = MatZq::from_str(&format!(
690            "[[{}, 0, {}, 0],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
691            i64::MIN,
692            i64::MAX,
693            i64::MAX,
694            i64::MAX,
695            u64::MAX
696        ))
697        .unwrap();
698
699        let _ = mat_1.set_row(0, &mat_2, 1);
700
701        assert_eq!(cmp, mat_1);
702    }
703
704    /// Ensures that setting the rows to itself does not change anything
705    #[test]
706    fn row_swap_same_entry() {
707        let mut mat_1 = MatZq::from_str(&format!(
708            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
709            i64::MIN,
710            i64::MAX,
711            i64::MAX,
712            u64::MAX
713        ))
714        .unwrap();
715        let cmp = mat_1.clone();
716
717        let _ = mat_1.set_row(0, &cmp, 0);
718        let _ = mat_1.set_row(1, &cmp, 1);
719
720        assert_eq!(cmp, mat_1);
721    }
722
723    /// Ensures that `set_row` returns an error if one of the specified rows is out of bounds
724    #[test]
725    fn row_out_of_bounds() {
726        let mut mat_1 = MatZq::new(5, 2, 17);
727        let mat_2 = mat_1.clone();
728
729        assert!(mat_1.set_row(-6, &mat_2, 0).is_err());
730        assert!(mat_1.set_row(5, &mat_2, 0).is_err());
731        assert!(mat_1.set_row(2, &mat_2, -6).is_err());
732        assert!(mat_1.set_row(2, &mat_2, 5).is_err());
733    }
734
735    /// Ensures that mismatching column dimensions result in an error
736    #[test]
737    fn row_mismatching_columns() {
738        let mut mat_1 = MatZq::new(3, 2, 17);
739        let mat_2 = MatZq::new(3, 3, 17);
740
741        assert!(mat_1.set_row(0, &mat_2, 0).is_err());
742        assert!(mat_1.set_row(1, &mat_2, 1).is_err());
743    }
744
745    /// Ensures that mismatching moduli result in an error
746    #[test]
747    fn row_mismatching_moduli() {
748        let mut mat_1 = MatZq::new(3, 3, 19);
749        let mat_2 = MatZq::new(3, 3, 17);
750
751        assert!(mat_1.set_row(0, &mat_2, 0).is_err());
752    }
753
754    /// Ensure that negative indices work for set_column/row.
755    #[test]
756    fn negative_indexing_row_column() {
757        let mut matrix = MatZq::identity(3, 3, 17);
758        let matrix2 = MatZq::identity(3, 3, 17);
759
760        matrix.set_column(-1, &matrix2, -2).unwrap();
761        matrix.set_row(-1, &matrix2, -2).unwrap();
762
763        let matrix_cmp = MatZq::from_str("[[1, 0, 0],[0, 1, 1],[0, 1, 0]] mod 17").unwrap();
764        assert_eq!(matrix_cmp, matrix);
765    }
766}
767
768#[cfg(test)]
769mod test_swaps {
770    use super::MatZq;
771    use crate::traits::{MatrixGetSubmatrix, MatrixSwaps};
772    use std::str::FromStr;
773
774    /// Ensures that swapping entries works fine for small entries
775    #[test]
776    fn entries_small_entries() {
777        let mut matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 7").unwrap();
778        let cmp = MatZq::from_str("[[1, 5, 3],[4, 2, 6]] mod 7").unwrap();
779
780        let _ = matrix.swap_entries(1, 1, 0, 1);
781
782        assert_eq!(cmp, matrix);
783    }
784
785    /// Ensures that swapping entries works fine for large entries
786    #[test]
787    fn entries_large_entries() {
788        let mut matrix = MatZq::from_str(&format!(
789            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
790            i64::MIN,
791            i64::MAX,
792            i64::MAX,
793            u64::MAX
794        ))
795        .unwrap();
796        let cmp = MatZq::from_str(&format!(
797            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
798            i64::MAX,
799            i64::MAX,
800            i64::MIN,
801            u64::MAX
802        ))
803        .unwrap();
804
805        let _ = matrix.swap_entries(0, 0, 1, 2);
806
807        assert_eq!(cmp, matrix);
808    }
809
810    /// Ensures that swapping the same entry does not change anything
811    #[test]
812    fn entries_swap_same_entry() {
813        let mut matrix = MatZq::from_str(&format!(
814            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
815            i64::MIN,
816            i64::MAX,
817            i64::MAX,
818            u64::MAX
819        ))
820        .unwrap();
821        let cmp = matrix.clone();
822
823        let _ = matrix.swap_entries(0, 0, 0, 0);
824        let _ = matrix.swap_entries(1, 1, 1, 1);
825
826        assert_eq!(cmp, matrix);
827    }
828
829    /// Ensures that `swap_entries` returns an error if one of the specified entries is out of bounds
830    #[test]
831    fn entries_out_of_bounds() {
832        let mut matrix = MatZq::new(5, 2, 5);
833
834        assert!(matrix.swap_entries(-6, 0, 0, 0).is_err());
835        assert!(matrix.swap_entries(0, -3, 0, 0).is_err());
836        assert!(matrix.swap_entries(0, 0, 5, 0).is_err());
837        assert!(matrix.swap_entries(0, 5, 0, 0).is_err());
838    }
839
840    /// Ensure that `swap_entries` can properly handle negative indexing.
841    #[test]
842    fn entries_negative_indexing() {
843        let mut matrix = MatZq::identity(2, 2, 2);
844
845        matrix.swap_entries(-2, -2, -2, -1).unwrap();
846        assert_eq!("[[0, 1],[0, 1]] mod 2", matrix.to_string());
847    }
848
849    /// Ensures that swapping columns works fine for small entries
850    #[test]
851    fn columns_small_entries() {
852        let mut matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 17").unwrap();
853        let cmp_vec_0 = MatZq::from_str("[[1],[4]] mod 17").unwrap();
854        let cmp_vec_1 = MatZq::from_str("[[3],[6]] mod 17").unwrap();
855        let cmp_vec_2 = MatZq::from_str("[[2],[5]] mod 17").unwrap();
856
857        let _ = matrix.swap_columns(1, 2);
858
859        assert_eq!(cmp_vec_0, matrix.get_column(0).unwrap());
860        assert_eq!(cmp_vec_1, matrix.get_column(1).unwrap());
861        assert_eq!(cmp_vec_2, matrix.get_column(2).unwrap());
862    }
863
864    /// Ensures that swapping columns works fine for large entries
865    #[test]
866    fn columns_large_entries() {
867        let mut matrix = MatZq::from_str(&format!(
868            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
869            i64::MIN,
870            i64::MAX,
871            i64::MAX,
872            u64::MAX
873        ))
874        .unwrap();
875        let cmp_vec_0 =
876            MatZq::from_str(&format!("[[3],[{}],[8]] mod {}", i64::MAX, u64::MAX)).unwrap();
877        let cmp_vec_1 = MatZq::from_str(&format!("[[1],[4],[6]] mod {}", u64::MAX)).unwrap();
878        let cmp_vec_2 = MatZq::from_str(&format!(
879            "[[{}],[{}],[7]] mod {}",
880            i64::MIN,
881            i64::MAX,
882            u64::MAX
883        ))
884        .unwrap();
885        let cmp_vec_3 = MatZq::from_str(&format!("[[4],[5],[9]] mod {}", u64::MAX)).unwrap();
886
887        let _ = matrix.swap_columns(0, 2);
888
889        assert_eq!(cmp_vec_0, matrix.get_column(0).unwrap());
890        assert_eq!(cmp_vec_1, matrix.get_column(1).unwrap());
891        assert_eq!(cmp_vec_2, matrix.get_column(2).unwrap());
892        assert_eq!(cmp_vec_3, matrix.get_column(3).unwrap());
893    }
894
895    /// Ensures that swapping the same column does not change anything
896    #[test]
897    fn columns_swap_same_col() {
898        let mut matrix = MatZq::from_str(&format!(
899            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
900            i64::MIN,
901            i64::MAX,
902            i64::MAX,
903            u64::MAX
904        ))
905        .unwrap();
906        let cmp = matrix.clone();
907
908        let _ = matrix.swap_columns(0, 0);
909
910        assert_eq!(cmp, matrix);
911    }
912
913    /// Ensures that `swap_columns` returns an error if one of the specified columns is out of bounds
914    #[test]
915    fn column_out_of_bounds() {
916        let mut matrix = MatZq::new(5, 2, 5);
917
918        assert!(matrix.swap_columns(-6, 0).is_err());
919        assert!(matrix.swap_columns(0, -6).is_err());
920        assert!(matrix.swap_columns(5, 0).is_err());
921        assert!(matrix.swap_columns(0, 5).is_err());
922    }
923
924    /// Ensures that swapping rows works fine for small entries
925    #[test]
926    fn rows_small_entries() {
927        let mut matrix = MatZq::from_str("[[1, 2],[3, 4]] mod 12").unwrap();
928        let cmp_vec_0 = MatZq::from_str("[[3, 4]] mod 12").unwrap();
929        let cmp_vec_1 = MatZq::from_str("[[1, 2]] mod 12").unwrap();
930
931        let _ = matrix.swap_rows(1, 0);
932
933        assert_eq!(cmp_vec_0, matrix.get_row(0).unwrap());
934        assert_eq!(cmp_vec_1, matrix.get_row(1).unwrap());
935    }
936
937    /// Ensures that swapping rows works fine for large entries
938    #[test]
939    fn rows_large_entries() {
940        let mut matrix = MatZq::from_str(&format!(
941            "[[{}, 1, 3, 4],[7, 6, 8, 9],[{}, 4, {}, 5]] mod {}",
942            i64::MIN,
943            i64::MAX,
944            i64::MAX,
945            u64::MAX
946        ))
947        .unwrap();
948        let cmp_vec_0 = MatZq::from_str(&format!(
949            "[[{}, 4, {}, 5]] mod {}",
950            i64::MAX,
951            i64::MAX,
952            u64::MAX
953        ))
954        .unwrap();
955        let cmp_vec_1 = MatZq::from_str(&format!("[[7, 6, 8, 9]] mod {}", u64::MAX)).unwrap();
956        let cmp_vec_2 =
957            MatZq::from_str(&format!("[[{}, 1, 3, 4]] mod {}", i64::MIN, u64::MAX)).unwrap();
958
959        let _ = matrix.swap_rows(0, 2);
960
961        assert_eq!(cmp_vec_0, matrix.get_row(0).unwrap());
962        assert_eq!(cmp_vec_1, matrix.get_row(1).unwrap());
963        assert_eq!(cmp_vec_2, matrix.get_row(2).unwrap());
964    }
965
966    /// Ensures that swapping the same row does not change anything
967    #[test]
968    fn rows_swap_same_row() {
969        let mut matrix = MatZq::from_str(&format!(
970            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
971            i64::MIN,
972            i64::MAX,
973            i64::MAX,
974            u64::MAX
975        ))
976        .unwrap();
977        let cmp = matrix.clone();
978
979        let _ = matrix.swap_rows(1, 1);
980
981        assert_eq!(cmp, matrix);
982    }
983
984    /// Ensures that `swap_rows` returns an error if one of the specified rows is out of bounds
985    #[test]
986    fn row_out_of_bounds() {
987        let mut matrix = MatZq::new(2, 4, 5);
988
989        assert!(matrix.swap_rows(-3, 0).is_err());
990        assert!(matrix.swap_rows(0, -3).is_err());
991        assert!(matrix.swap_rows(4, 0).is_err());
992        assert!(matrix.swap_rows(0, 4).is_err());
993    }
994
995    /// Ensure that negative indices work for swap_column/row.
996    #[test]
997    fn negative_indexing_row_column() {
998        let mut matrix = MatZq::identity(3, 3, 17);
999        let mut matrix2 = MatZq::identity(3, 3, 17);
1000
1001        matrix.swap_columns(-1, -2).unwrap();
1002        matrix2.swap_rows(-1, -2).unwrap();
1003
1004        let matrix_cmp = MatZq::from_str("[[1, 0, 0],[0, 0, 1],[0, 1, 0]] mod 17").unwrap();
1005        assert_eq!(matrix_cmp, matrix);
1006        assert_eq!(matrix_cmp, matrix2);
1007    }
1008}
1009
1010#[cfg(test)]
1011mod test_reverses {
1012    use super::MatZq;
1013    use crate::traits::MatrixGetSubmatrix;
1014    use std::str::FromStr;
1015
1016    /// Ensures that reversing columns works fine for small entries
1017    #[test]
1018    fn columns_small_entries() {
1019        let mut matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 7").unwrap();
1020        let cmp_vec_0 = MatZq::from_str("[[1],[4]] mod 7").unwrap();
1021        let cmp_vec_1 = MatZq::from_str("[[2],[5]] mod 7").unwrap();
1022        let cmp_vec_2 = MatZq::from_str("[[3],[6]] mod 7").unwrap();
1023
1024        matrix.reverse_columns();
1025
1026        assert_eq!(cmp_vec_2, matrix.get_column(0).unwrap());
1027        assert_eq!(cmp_vec_1, matrix.get_column(1).unwrap());
1028        assert_eq!(cmp_vec_0, matrix.get_column(2).unwrap());
1029    }
1030
1031    /// Ensures that reversing columns works fine for large entries
1032    #[test]
1033    fn columns_large_entries() {
1034        let mut matrix = MatZq::from_str(&format!(
1035            "[[{}, 1, 3, 4],[{}, 4, {}, 5],[7, 6, 8, 9]] mod {}",
1036            i64::MIN,
1037            i64::MAX,
1038            i64::MAX,
1039            u64::MAX
1040        ))
1041        .unwrap();
1042        let cmp_vec_0 = MatZq::from_str(&format!(
1043            "[[{}],[{}],[7]] mod {}",
1044            i64::MIN,
1045            i64::MAX,
1046            u64::MAX
1047        ))
1048        .unwrap();
1049        let cmp_vec_1 = MatZq::from_str(&format!("[[1],[4],[6]] mod {}", u64::MAX)).unwrap();
1050        let cmp_vec_2 =
1051            MatZq::from_str(&format!("[[3],[{}],[8]] mod {}", i64::MAX, u64::MAX)).unwrap();
1052        let cmp_vec_3 = MatZq::from_str(&format!("[[4],[5],[9]] mod {}", u64::MAX)).unwrap();
1053
1054        matrix.reverse_columns();
1055
1056        assert_eq!(cmp_vec_3, matrix.get_column(0).unwrap());
1057        assert_eq!(cmp_vec_2, matrix.get_column(1).unwrap());
1058        assert_eq!(cmp_vec_1, matrix.get_column(2).unwrap());
1059        assert_eq!(cmp_vec_0, matrix.get_column(3).unwrap());
1060    }
1061
1062    /// Ensures that reversing rows works fine for small entries
1063    #[test]
1064    fn rows_small_entries() {
1065        let mut matrix = MatZq::from_str("[[1, 2],[3, 4]] mod 6").unwrap();
1066        let cmp_vec_0 = MatZq::from_str("[[1, 2]] mod 6").unwrap();
1067        let cmp_vec_1 = MatZq::from_str("[[3, 4]] mod 6").unwrap();
1068
1069        matrix.reverse_rows();
1070
1071        assert_eq!(cmp_vec_1, matrix.get_row(0).unwrap());
1072        assert_eq!(cmp_vec_0, matrix.get_row(1).unwrap());
1073    }
1074
1075    /// Ensures that reversing rows works fine for large entries
1076    #[test]
1077    fn rows_large_entries() {
1078        let mut matrix = MatZq::from_str(&format!(
1079            "[[{}, 1, 3, 4],[7, 6, 8, 9],[{}, 4, {}, 5]] mod {}",
1080            i64::MIN,
1081            i64::MAX,
1082            i64::MAX,
1083            u64::MAX
1084        ))
1085        .unwrap();
1086        let cmp_vec_0 =
1087            MatZq::from_str(&format!("[[{}, 1, 3, 4]] mod {}", i64::MIN, u64::MAX)).unwrap();
1088        let cmp_vec_1 = MatZq::from_str(&format!("[[7, 6, 8, 9]] mod {}", u64::MAX)).unwrap();
1089        let cmp_vec_2 = MatZq::from_str(&format!(
1090            "[[{}, 4, {}, 5]] mod {}",
1091            i64::MAX,
1092            i64::MAX,
1093            u64::MAX
1094        ))
1095        .unwrap();
1096
1097        matrix.reverse_rows();
1098
1099        assert_eq!(cmp_vec_2, matrix.get_row(0).unwrap());
1100        assert_eq!(cmp_vec_1, matrix.get_row(1).unwrap());
1101        assert_eq!(cmp_vec_0, matrix.get_row(2).unwrap());
1102    }
1103}
1104
1105#[cfg(test)]
1106mod test_change_modulus {
1107    use super::MatZq;
1108    use crate::integer_mod_q::Modulus;
1109    use std::str::FromStr;
1110
1111    /// Ensures that the modulus is changed correctly.
1112    #[test]
1113    fn modulus_correct() {
1114        let mut matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 7").unwrap();
1115        let modulus = Modulus::from(8);
1116
1117        matrix.change_modulus(&modulus);
1118
1119        assert_eq!("[[1, 2, 3],[4, 5, 6]] mod 8", matrix.to_string());
1120    }
1121
1122    /// Ensures that the modulus is changed correctly, if the modulus is big.
1123    #[test]
1124    fn big_modulus_correct() {
1125        let mut matrix =
1126            MatZq::from_str(&format!("[[1, 2, 3],[4, 5, 6]] mod {}", i64::MAX)).unwrap();
1127        let modulus = Modulus::from(u64::MAX);
1128
1129        matrix.change_modulus(&modulus);
1130
1131        assert_eq!(
1132            format!("[[1, 2, 3],[4, 5, 6]] mod {}", u64::MAX),
1133            matrix.to_string()
1134        );
1135    }
1136
1137    /// Ensures that the matrix is reduced correctly.
1138    #[test]
1139    fn reduced_correct() {
1140        let mut matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6]] mod 7").unwrap();
1141        let modulus = Modulus::from(2);
1142
1143        matrix.change_modulus(&modulus);
1144
1145        assert_eq!("[[1, 0, 1],[0, 1, 0]] mod 2", matrix.to_string());
1146    }
1147}
1148
1149#[cfg(test)]
1150mod test_set_submatrix {
1151    use crate::{
1152        integer::MatZ,
1153        integer_mod_q::{MatZq, Modulus},
1154        traits::MatrixSetSubmatrix,
1155    };
1156    use std::str::FromStr;
1157
1158    /// Ensure that the entire matrix can be set.
1159    #[test]
1160    fn entire_matrix() {
1161        let modulus = Modulus::from(u64::MAX);
1162        let mut mat = MatZq::from((&MatZ::sample_uniform(10, 10, -100, 100).unwrap(), &modulus));
1163        let identity = MatZq::identity(10, 10, &modulus);
1164
1165        mat.set_submatrix(0, 0, &identity, 0, 0, 9, 9).unwrap();
1166
1167        assert_eq!(identity, mat);
1168    }
1169
1170    /// Ensure that matrix access out of bounds leads to an error.
1171    #[test]
1172    fn out_of_bounds() {
1173        let modulus = Modulus::from(u64::MAX);
1174        let mut mat = MatZq::identity(10, 10, &modulus);
1175
1176        assert!(mat.set_submatrix(10, 0, &mat.clone(), 0, 0, 9, 9).is_err());
1177        assert!(mat.set_submatrix(0, 10, &mat.clone(), 0, 0, 9, 9).is_err());
1178        assert!(mat.set_submatrix(0, 0, &mat.clone(), 10, 0, 9, 9).is_err());
1179        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 10, 9, 9).is_err());
1180        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 10, 9).is_err());
1181        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 9, 10).is_err());
1182        assert!(mat.set_submatrix(-11, 0, &mat.clone(), 0, 0, 9, 9).is_err());
1183        assert!(mat.set_submatrix(0, -11, &mat.clone(), 0, 0, 9, 9).is_err());
1184        assert!(mat.set_submatrix(0, 0, &mat.clone(), -11, 0, 9, 9).is_err());
1185        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, -11, 9, 9).is_err());
1186        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, -11, 9).is_err());
1187        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 9, -11).is_err());
1188    }
1189
1190    /// Ensure that the function returns an error if the defined submatrix is too large
1191    /// and there is not enough space in the original matrix.
1192    #[test]
1193    fn submatrix_too_large() {
1194        let modulus = Modulus::from(u64::MAX);
1195        let mut mat = MatZq::identity(10, 10, &modulus);
1196
1197        assert!(
1198            mat.set_submatrix(0, 0, &MatZq::identity(11, 11, &modulus), 0, 0, 10, 10)
1199                .is_err()
1200        );
1201        assert!(mat.set_submatrix(1, 2, &mat.clone(), 0, 0, 9, 9).is_err());
1202    }
1203
1204    /// Ensure that setting submatrices with large values works.
1205    #[test]
1206    fn large_values() {
1207        let modulus = Modulus::from(u64::MAX);
1208        let mut mat = MatZq::from((
1209            &MatZ::from_str(&format!("[[1, {}],[-{}, 0]]", u64::MAX, u64::MAX)).unwrap(),
1210            &modulus,
1211        ));
1212        let cmp_mat = MatZq::from((
1213            &MatZ::from_str(&format!("[[-{}, 0],[-{}, 0]]", u64::MAX, u64::MAX)).unwrap(),
1214            &modulus,
1215        ));
1216
1217        mat.set_submatrix(0, 0, &mat.clone(), 1, 0, 1, 1).unwrap();
1218        assert_eq!(cmp_mat, mat);
1219    }
1220
1221    /// Ensure that setting with an undefined submatrix.
1222    #[test]
1223    #[should_panic]
1224    fn submatrix_negative() {
1225        let modulus = Modulus::from(u64::MAX);
1226        let mut mat = MatZq::identity(10, 10, &modulus);
1227
1228        let _ = mat.set_submatrix(0, 0, &mat.clone(), 0, 9, 9, 5);
1229    }
1230
1231    /// Ensure that different moduli cause the set_submatrix to fail.
1232    #[test]
1233    fn different_moduli() {
1234        let modulus1 = Modulus::from(u64::MAX);
1235        let mut mat1 = MatZq::identity(10, 10, &modulus1);
1236
1237        let modulus2 = Modulus::from(u64::MAX - 1);
1238        let mat2 = MatZq::identity(10, 10, &modulus2);
1239
1240        assert!(mat1.set_submatrix(0, 0, &mat2.clone(), 0, 9, 0, 9).is_err());
1241    }
1242}