Skip to main content

qfall_math/integer_mod_q/mat_zq/
set.rs

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