Skip to main content

qfall_math/integer_mod_q/mat_zq/
get.rs

1// Copyright 2023 Marcel Luca Schmidt, Sven Moog
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to get information about a [`MatZq`] matrix.
10
11use super::MatZq;
12use crate::{
13    integer::{MatZ, Z},
14    integer_mod_q::{Modulus, Zq, fmpz_mod_helpers::length},
15    traits::{AsInteger, MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix, MatrixSetEntry},
16};
17use flint3_sys::{
18    fmpz, fmpz_init_set, fmpz_mat_set, fmpz_mod_mat_entry, fmpz_mod_mat_init_set,
19    fmpz_mod_mat_window_clear, fmpz_mod_mat_window_init,
20};
21use std::mem::MaybeUninit;
22
23impl MatZq {
24    /// Creates a [`MatZ`] where each entry is a representative of the
25    /// equivalence class of each entry from a [`MatZq`].
26    ///
27    /// The values in the output matrix are in the range of `[0, modulus)`.
28    /// Use [`MatZq::get_representative_least_absolute_residue`] if they should be
29    /// in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`.
30    ///
31    /// Returns the matrix as a [`MatZ`].
32    ///
33    /// # Examples
34    /// ```
35    /// use qfall_math::integer::MatZ;
36    /// use qfall_math::integer_mod_q::MatZq;
37    /// use std::str::FromStr;
38    ///
39    /// let mat_zq = MatZq::from_str("[[1, 2],[3, -1]] mod 5").unwrap();
40    ///
41    /// let mat_z = mat_zq.get_representative_least_nonnegative_residue();
42    ///
43    /// assert_eq!(mat_z.to_string(), "[[1, 2],[3, 4]]");
44    /// ```
45    pub fn get_representative_least_nonnegative_residue(&self) -> MatZ {
46        let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
47        unsafe { fmpz_mat_set(&mut out.matrix, &self.matrix) };
48        out
49    }
50
51    /// Creates a [`MatZ`] where each entry is a representative of the
52    /// equivalence class of each entry from a [`MatZq`] with the
53    /// representatives close to `0`.
54    ///
55    /// The values in the output matrix are in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`,
56    /// i.e. `[-(modulus-1)/2, (modulus-1)/2]` for odd moduli and `(-modulus/2, modulus/2]` for even moduli.
57    /// Hence, the positive representative is chosen for the element `modulus/2` of even moduli.
58    /// Use [`MatZq::get_representative_least_nonnegative_residue`] if they should be
59    /// in the range `[0, modulus)`.
60    ///
61    /// Returns an [`MatZ`] representation of the given matrix with
62    /// representatives chosen close to `0`.
63    ///
64    /// # Examples
65    /// ```
66    /// use qfall_math::integer_mod_q::MatZq;
67    /// use std::str::FromStr;
68    ///
69    /// let mat_zq_1 = MatZq::from_str("[[1,2],[3,4]] mod 5").unwrap();
70    /// let mat_zq_2 = MatZq::from_str("[[1,2],[3,4]] mod 4").unwrap();
71    ///
72    /// let mat_z_1 = mat_zq_1.get_representative_least_absolute_residue();
73    /// let mat_z_2 = mat_zq_2.get_representative_least_absolute_residue();
74    ///
75    /// assert_eq!(mat_z_1.to_string(), "[[1, 2],[-2, -1]]");
76    /// assert_eq!(mat_z_2.to_string(), "[[1, 2],[-1, 0]]");
77    /// ```
78    pub fn get_representative_least_absolute_residue(&self) -> MatZ {
79        let modulus: Z = Z::from(&self.modulus);
80        let modulus_half = modulus.div_floor(2);
81
82        let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
83
84        for row in 0..self.get_num_rows() {
85            for column in 0..self.get_num_columns() {
86                let entry: Z = unsafe { self.get_entry_unchecked(row, column) };
87
88                // Not using Zq::distance for performance reasons.
89                if entry > modulus_half {
90                    unsafe { out.set_entry_unchecked(row, column, entry - &modulus) };
91                } else {
92                    unsafe { out.set_entry_unchecked(row, column, entry) };
93                }
94            }
95        }
96
97        out
98    }
99
100    /// Returns the modulus of the matrix as a [`Modulus`].
101    ///
102    /// # Examples
103    /// ```
104    /// use qfall_math::integer_mod_q::MatZq;
105    ///
106    /// let matrix = MatZq::new(5, 10, 7);
107    /// let entry = matrix.get_mod();
108    /// ```
109    pub fn get_mod(&self) -> Modulus {
110        self.modulus.clone()
111    }
112}
113
114impl MatrixGetSubmatrix for MatZq {
115    /// Returns a deep copy of the submatrix defined by the given parameters
116    /// and does not check the provided dimensions.
117    /// There is also a safe version of this function that checks the input.
118    ///
119    /// Parameters:
120    /// `row_1`: the starting row of the submatrix
121    /// `row_2`: the ending row of the submatrix
122    /// `col_1`: the starting column of the submatrix
123    /// `col_2`: the ending column of the submatrix
124    ///
125    /// Returns the submatrix from `(row_1, col_1)` to `(row_2, col_2)`(exclusively).
126    ///
127    /// # Examples
128    /// ```
129    /// use qfall_math::{integer_mod_q::MatZq, traits::MatrixGetSubmatrix};
130    /// use std::str::FromStr;
131    ///
132    /// let mat = MatZq::identity(3, 3, 17);
133    ///
134    /// let sub_mat_1 = mat.get_submatrix(0, 2, 1, 1).unwrap();
135    /// let sub_mat_2 = mat.get_submatrix(0, -1, 1, -2).unwrap();
136    /// let sub_mat_3 = unsafe{mat.get_submatrix_unchecked(0, 3, 1, 2)};
137    ///
138    /// let e_2 = MatZq::from_str("[[0],[1],[0]] mod 17").unwrap();
139    /// assert_eq!(e_2, sub_mat_1);
140    /// assert_eq!(e_2, sub_mat_2);
141    /// assert_eq!(e_2, sub_mat_3);
142    /// ```
143    ///
144    /// # Safety
145    /// To use this function safely, make sure that the selected submatrix is part
146    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
147    /// occur.
148    unsafe fn get_submatrix_unchecked(
149        &self,
150        row_1: i64,
151        row_2: i64,
152        col_1: i64,
153        col_2: i64,
154    ) -> Self {
155        let mut window = MaybeUninit::uninit();
156        // The memory for the elements of window is shared with self.
157        unsafe {
158            fmpz_mod_mat_window_init(
159                window.as_mut_ptr(),
160                &self.matrix,
161                row_1,
162                col_1,
163                row_2,
164                col_2,
165                self.modulus.get_fmpz_mod_ctx_struct(),
166            )
167        };
168        let mut window_copy = MaybeUninit::uninit();
169        unsafe {
170            // Deep clone of the content of the window
171            fmpz_mod_mat_init_set(
172                window_copy.as_mut_ptr(),
173                window.as_ptr(),
174                self.modulus.get_fmpz_mod_ctx_struct(),
175            );
176            // Clears the matrix window and releases any memory that it uses. Note that
177            // the memory to the underlying matrix that window points to is not freed
178            fmpz_mod_mat_window_clear(window.as_mut_ptr(), self.modulus.get_fmpz_mod_ctx_struct());
179        }
180        MatZq {
181            matrix: unsafe { window_copy.assume_init() },
182            modulus: self.get_mod(),
183        }
184    }
185}
186
187impl MatZq {
188    /// Efficiently collects all [`fmpz`]s in a [`MatZq`] without cloning them.
189    ///
190    /// Hence, the values on the returned [`Vec`] are intended for short-term use
191    /// as the access to [`fmpz`] values could lead to memory leaks or modified values
192    /// once the [`MatZq`] instance was modified or dropped.
193    ///
194    /// # Examples
195    /// ```compile_fail
196    /// use qfall_math::integer_mod_q::MatZq;
197    /// use std::str::FromStr;
198    ///
199    /// let mat = MatZq::from_str("[[1, 2],[3, 4],[5, 6]] mod 3").unwrap();
200    ///
201    /// let fmpz_entries = mat.collect_entries();
202    /// ```
203    pub(crate) fn collect_entries(&self) -> Vec<fmpz> {
204        let mut entries: Vec<fmpz> =
205            Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
206
207        for row in 0..self.get_num_rows() {
208            for col in 0..self.get_num_columns() {
209                // efficiently get entry without cloning the entry itself
210                let entry = unsafe { *fmpz_mod_mat_entry(&self.matrix, row, col) };
211                entries.push(entry);
212            }
213        }
214
215        entries
216    }
217
218    /// Computes the lengths of a given vector of [`Z`] values
219    /// considering the [`Modulus`] of `self`.
220    ///
221    /// # Examples
222    /// ```compile_fail
223    /// use qfall_math::integer_mod_q::MatZq;
224    /// use std::str::FromStr;
225    ///
226    /// let mat = MatZq::from_str("[[1, 2],[3, 4]] mod 3").unwrap();
227    ///
228    /// let lengths = mat.collect_lengths();
229    /// ```
230    pub(crate) fn collect_lengths(&self) -> Vec<Z> {
231        let entries_fmpz = self.collect_entries();
232
233        let modulus_fmpz = unsafe { self.get_mod().into_fmpz() };
234        let mut entry_lengths = Vec::with_capacity(entries_fmpz.len());
235        for value in entries_fmpz {
236            entry_lengths.push(length(&value, &modulus_fmpz));
237        }
238
239        entry_lengths
240    }
241}
242
243impl MatrixDimensions for MatZq {
244    /// Returns the number of rows of the matrix as a [`i64`].
245    ///
246    /// # Examples
247    /// ```
248    /// use qfall_math::integer_mod_q::MatZq;
249    /// use qfall_math::traits::*;
250    ///
251    /// let matrix = MatZq::new(5, 6, 7);
252    /// let rows = matrix.get_num_rows();
253    /// ```
254    fn get_num_rows(&self) -> i64 {
255        self.matrix.r
256    }
257
258    /// Returns the number of columns of the matrix as a [`i64`].
259    ///
260    /// # Examples
261    /// ```
262    /// use qfall_math::integer_mod_q::MatZq;
263    /// use qfall_math::traits::*;
264    ///
265    /// let matrix = MatZq::new(5, 6, 7);
266    /// let rows = matrix.get_num_columns();
267    /// ```
268    fn get_num_columns(&self) -> i64 {
269        self.matrix.c
270    }
271}
272
273impl MatrixGetEntry<Z> for MatZq {
274    /// Outputs the [`Z`] value of a specific matrix entry
275    /// without checking whether it's part of the matrix.
276    ///
277    /// Parameters:
278    /// - `row`: specifies the row in which the entry is located
279    /// - `column`: specifies the column in which the entry is located
280    ///
281    /// Returns the [`Z`] value of the matrix at the position of the given
282    /// row and column.
283    ///
284    /// # Safety
285    /// To use this function safely, make sure that the selected entry is part
286    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
287    /// occur.
288    ///
289    /// # Examples
290    /// ```rust
291    /// use qfall_math::integer_mod_q::MatZq;
292    /// use qfall_math::traits::MatrixGetEntry;
293    /// use qfall_math::integer::Z;
294    /// use std::str::FromStr;
295    ///
296    /// let matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6],[7, 8, 9]] mod 10").unwrap();
297    ///
298    /// let entry_1 :Z = unsafe { matrix.get_entry_unchecked(0, 2) };
299    /// let entry_2 :Z = unsafe { matrix.get_entry_unchecked(2, 1) };
300    /// let entry_3 :Z = unsafe { matrix.get_entry_unchecked(2, 1) };
301    ///
302    /// assert_eq!(3, entry_1);
303    /// assert_eq!(8, entry_2);
304    /// assert_eq!(8, entry_3);
305    /// ```
306    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> Z {
307        let mut out = Z::default();
308        let entry = unsafe { fmpz_mod_mat_entry(&self.matrix, row, column) };
309        unsafe { fmpz_init_set(&mut out.value, entry) };
310
311        out
312    }
313}
314
315impl MatrixGetEntry<Zq> for MatZq {
316    /// Outputs the [`Zq`] value of a specific matrix entry
317    /// without checking whether it's part of the matrix.
318    ///
319    /// Parameters:
320    /// - `row`: specifies the row in which the entry is located
321    /// - `column`: specifies the column in which the entry is located
322    ///
323    /// Returns the [`Zq`] value of the matrix at the position of the given
324    /// row and column.
325    ///
326    /// # Safety
327    /// To use this function safely, make sure that the selected entry is part
328    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
329    /// occur.
330    ///
331    /// # Examples
332    /// ```rust
333    /// use qfall_math::integer_mod_q::{MatZq, Zq};
334    /// use qfall_math::traits::MatrixGetEntry;
335    /// use std::str::FromStr;
336    ///
337    /// let matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6],[7, 8, 9]] mod 10").unwrap();
338    ///
339    /// assert_eq!(Zq::from((3, 10)), unsafe { matrix.get_entry_unchecked(0, 2) } );
340    /// assert_eq!(Zq::from((8, 10)), unsafe { matrix.get_entry_unchecked(2, 1) } );
341    /// assert_eq!(Zq::from((8, 10)), unsafe { matrix.get_entry_unchecked(2, 1) } );
342    /// ```
343    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> Zq {
344        let mut out = Zq::from((0, &self.modulus));
345        let entry = unsafe { fmpz_mod_mat_entry(&self.matrix, row, column) };
346        unsafe { fmpz_init_set(&mut out.value.value, entry) };
347
348        out
349    }
350}
351
352#[cfg(test)]
353mod test_get_entry {
354    use super::Zq;
355    use crate::{
356        integer::Z,
357        integer_mod_q::MatZq,
358        traits::{MatrixGetEntry, MatrixSetEntry},
359    };
360    use std::str::FromStr;
361
362    /// Ensure that getting entries works on the edge.
363    #[test]
364    fn get_edges() {
365        let matrix = MatZq::new(5, 10, u64::MAX);
366
367        let entry_1: Z = matrix.get_entry(0, 0).unwrap();
368        let entry_2: Z = matrix.get_entry(4, 9).unwrap();
369
370        assert_eq!(0, entry_1);
371        assert_eq!(0, entry_2);
372    }
373
374    /// Ensure that getting entries works with large numbers.
375    #[test]
376    fn max_int_positive() {
377        let mut matrix = MatZq::new(5, 10, u64::MAX);
378        let value = Z::from(i64::MAX);
379        matrix.set_entry(0, 0, value).unwrap();
380
381        let entry: Z = matrix.get_entry(0, 0).unwrap();
382
383        assert_eq!(i64::MAX, entry);
384    }
385
386    /// Ensure that getting entries works with large numbers (larger than [`i64`]).
387    #[test]
388    fn large_positive() {
389        let mut matrix = MatZq::new(5, 10, u64::MAX);
390        let value = Z::from(u64::MAX - 1);
391        matrix.set_entry(0, 0, value).unwrap();
392
393        let entry: Z = matrix.get_entry(0, 0).unwrap();
394
395        assert_eq!(u64::MAX - 1, entry);
396    }
397
398    /// Ensure that getting entries works with large numbers.
399    #[test]
400    fn max_int_negative() {
401        let mut matrix = MatZq::new(5, 10, u64::MAX);
402        let value = Z::from(-i64::MAX);
403        matrix.set_entry(0, 0, value).unwrap();
404
405        let entry: Z = matrix.get_entry(0, 0).unwrap();
406
407        assert_eq!((u64::MAX as i128 - i64::MAX as i128) as u64, entry);
408    }
409
410    /// Ensure that getting entries works with large numbers (larger than [`i64`]).
411    #[test]
412    fn large_negative() {
413        let mut matrix = MatZq::new(5, 10, u64::MAX);
414        let value = Z::from(-i64::MAX - 1);
415        matrix.set_entry(0, 0, value).unwrap();
416
417        let entry: Z = matrix.get_entry(0, 0).unwrap();
418
419        assert_eq!((u64::MAX as i128 - i64::MAX as i128) as u64 - 1, entry);
420    }
421
422    /// Ensure that a wrong number of rows yields an Error.
423    #[test]
424    fn error_wrong_row() {
425        let matrix: MatZq = MatZq::new(5, 10, 7);
426
427        assert!(MatrixGetEntry::<Z>::get_entry(&matrix, 5, 1).is_err());
428        assert!(MatrixGetEntry::<Z>::get_entry(&matrix, -6, 1).is_err());
429        assert!(MatrixGetEntry::<Zq>::get_entry(&matrix, 5, 1).is_err());
430        assert!(MatrixGetEntry::<Zq>::get_entry(&matrix, -6, 1).is_err());
431    }
432
433    /// Ensure that a wrong number of columns yields an Error.
434    #[test]
435    fn error_wrong_column() {
436        let matrix = MatZq::new(5, 10, 7);
437
438        assert!(MatrixGetEntry::<Z>::get_entry(&matrix, 1, 10).is_err());
439        assert!(MatrixGetEntry::<Z>::get_entry(&matrix, 1, -11).is_err());
440        assert!(MatrixGetEntry::<Zq>::get_entry(&matrix, 1, 10).is_err());
441        assert!(MatrixGetEntry::<Zq>::get_entry(&matrix, 1, -11).is_err());
442    }
443
444    /// Ensure that negative indices return the correct values.
445    #[test]
446    fn negative_indexing() {
447        let matrix = MatZq::from_str("[[1, 2, 3],[4, 5, 6],[7, 8, 9]] mod 10").unwrap();
448
449        let entry_1: Z = matrix.get_entry(-1, -1).unwrap();
450        let entry_2: Z = matrix.get_entry(-1, -2).unwrap();
451        let entry_3: Z = matrix.get_entry(-3, -3).unwrap();
452        let entry_4: Zq = matrix.get_entry(-1, -1).unwrap();
453        let entry_5: Zq = matrix.get_entry(-1, -2).unwrap();
454        let entry_6: Zq = matrix.get_entry(-3, -3).unwrap();
455
456        assert_eq!(9, entry_1);
457        assert_eq!(8, entry_2);
458        assert_eq!(1, entry_3);
459        assert_eq!(Zq::from((9, 10)), entry_4);
460        assert_eq!(Zq::from((8, 10)), entry_5);
461        assert_eq!(Zq::from((1, 10)), entry_6);
462    }
463
464    /// Ensure that the entry is a deep copy and not just a clone of the reference.
465    #[test]
466    fn memory_test() {
467        let mut matrix = MatZq::new(5, 10, u64::MAX);
468        let value = Zq::from((u64::MAX - 1, u64::MAX));
469        matrix.set_entry(1, 1, value).unwrap();
470        let entry: Z = matrix.get_entry(1, 1).unwrap();
471        matrix.set_entry(1, 1, Z::ONE).unwrap();
472
473        assert_eq!(u64::MAX - 1, entry);
474    }
475
476    /// Ensure that no memory leak occurs in get_entry with [`Z`](crate::integer::Z).
477    #[test]
478    fn get_entry_z_memory() {
479        let mut matrix = MatZq::new(5, 10, u64::MAX);
480        matrix.set_entry(1, 1, Z::from(u64::MAX - 3)).unwrap();
481        let _: Z = matrix.get_entry(1, 1).unwrap();
482        matrix.set_entry(2, 2, Z::from(u64::MAX - 10)).unwrap();
483
484        let entry: Z = matrix.get_entry(1, 1).unwrap();
485        let _z = Z::from(u64::MAX);
486
487        assert_eq!(entry, Z::from(u64::MAX - 3));
488    }
489
490    /// Ensure that no memory leak occurs in get_entry with [`Zq`](crate::integer_mod_q::Zq).
491    #[test]
492    fn get_entry_zq_memory() {
493        let mut matrix = MatZq::new(5, 10, u64::MAX);
494        matrix.set_entry(1, 1, Z::from(u64::MAX - 3)).unwrap();
495        let _: Zq = matrix.get_entry(1, 1).unwrap();
496        matrix.set_entry(2, 2, Z::from(u64::MAX - 10)).unwrap();
497
498        let entry: Z = matrix.get_entry(1, 1).unwrap();
499        let _z = Z::from(u64::MAX);
500
501        assert_eq!(entry, Z::from(u64::MAX - 3));
502    }
503
504    /// Ensure that getting entries works with different types.
505    #[test]
506    fn diff_types() {
507        let matrix = MatZq::new(5, 10, u64::MAX);
508
509        let _: Z = matrix.get_entry(0, 0).unwrap();
510        let _: Zq = matrix.get_entry(0, 0).unwrap();
511    }
512}
513
514#[cfg(test)]
515mod test_get_num {
516    use crate::{integer_mod_q::MatZq, traits::MatrixDimensions};
517
518    /// Ensure that the getter for number of rows works correctly.
519    #[test]
520    fn num_rows() {
521        let matrix = MatZq::new(5, 10, 7);
522
523        assert_eq!(matrix.get_num_rows(), 5);
524    }
525
526    /// Ensure that the getter for number of columns works correctly.
527    #[test]
528    fn num_columns() {
529        let matrix = MatZq::new(5, 10, 7);
530
531        assert_eq!(matrix.get_num_columns(), 10);
532    }
533}
534
535#[cfg(test)]
536mod test_get_representative_least_nonnegative_residue {
537    use crate::{
538        integer::Z,
539        integer_mod_q::MatZq,
540        traits::{MatrixDimensions, MatrixGetEntry, MatrixSetEntry},
541    };
542
543    /// Test if the dimensions are taken over correctly
544    #[test]
545    fn dimensions() {
546        let matzq = MatZq::new(15, 17, 13);
547
548        let matz_1 = matzq.get_representative_least_nonnegative_residue();
549
550        assert_eq!(15, matz_1.get_num_rows());
551        assert_eq!(17, matz_1.get_num_columns());
552    }
553
554    /// Test if entries are taken over correctly
555    #[test]
556    fn entries_taken_over_correctly() {
557        let mut matzq = MatZq::new(2, 2, u64::MAX);
558        matzq.set_entry(0, 0, u64::MAX - 58).unwrap();
559        matzq.set_entry(0, 1, -1).unwrap();
560
561        let matz_1 = matzq.get_representative_least_nonnegative_residue();
562
563        assert_eq!(Z::from(u64::MAX - 1), matz_1.get_entry(0, 1).unwrap());
564        assert_eq!(Z::from(u64::MAX - 58), matz_1.get_entry(0, 0).unwrap());
565    }
566}
567
568#[cfg(test)]
569mod test_mod {
570    use crate::integer_mod_q::{MatZq, Modulus};
571
572    /// Ensure that the getter for modulus works correctly.
573    #[test]
574    fn get_mod() {
575        let matrix = MatZq::new(5, 10, 7);
576
577        assert_eq!(matrix.get_mod(), Modulus::from(7));
578    }
579
580    /// Ensure that the getter for modulus works with large numbers.
581    #[test]
582    fn get_mod_large() {
583        let matrix = MatZq::new(5, 10, u64::MAX);
584
585        assert_eq!(matrix.get_mod(), Modulus::from(u64::MAX));
586    }
587
588    /// Ensure that no memory leak occurs in get_mod.
589    #[test]
590    fn get_mod_memory() {
591        let matrix = MatZq::new(5, 10, u64::MAX);
592        let _ = matrix.get_mod();
593        let _ = Modulus::from(u64::MAX - 1);
594
595        let modulus = matrix.get_mod();
596
597        assert_eq!(modulus, Modulus::from(u64::MAX));
598    }
599}
600
601#[cfg(test)]
602mod test_get_vec {
603    use crate::{integer_mod_q::MatZq, traits::MatrixGetSubmatrix};
604    use std::str::FromStr;
605
606    /// Ensure that getting a row works
607    #[test]
608    fn get_row_works() {
609        let matrix = MatZq::from_str(&format!(
610            "[[0, 0, 0],[4, {}, {}]] mod {}",
611            i64::MAX,
612            i64::MIN,
613            u64::MAX
614        ))
615        .unwrap();
616        let row_1 = matrix.get_row(0).unwrap();
617        let row_2 = matrix.get_row(1).unwrap();
618
619        let cmp_1 = MatZq::from_str(&format!("[[0, 0, 0]] mod {}", u64::MAX)).unwrap();
620        let cmp_2 = MatZq::from_str(&format!(
621            "[[4, {}, {}]] mod {}",
622            i64::MAX,
623            i64::MIN,
624            u64::MAX
625        ))
626        .unwrap();
627
628        assert_eq!(cmp_1, row_1);
629        assert_eq!(cmp_2, row_2);
630    }
631
632    /// Ensure that getting a row with a negative index works
633    #[test]
634    fn get_row_negative_indexing_works() {
635        let matrix = MatZq::from_str(&format!(
636            "[[0, 0, 0],[42, {}, {}]] mod {}",
637            i64::MAX,
638            u64::MAX - 1,
639            u64::MAX
640        ))
641        .unwrap();
642        let row_1 = matrix.get_row(-2).unwrap();
643        let row_2 = matrix.get_row(-1).unwrap();
644
645        let cmp_1 = MatZq::from_str(&format!("[[0, 0, 0]] mod {}", u64::MAX)).unwrap();
646        let cmp_2 = MatZq::from_str(&format!(
647            "[[42, {}, {}]] mod {}",
648            i64::MAX,
649            u64::MAX - 1,
650            u64::MAX
651        ))
652        .unwrap();
653
654        assert_eq!(cmp_1, row_1);
655        assert_eq!(cmp_2, row_2);
656    }
657
658    /// Ensure that getting a column works
659    #[test]
660    fn get_column_works() {
661        let matrix = MatZq::from_str(&format!(
662            "[[1, 0, 3],[{}, 0, 5],[{}, 0, 7]] mod {}",
663            i64::MAX,
664            i64::MIN,
665            u64::MAX
666        ))
667        .unwrap();
668        let column_1 = matrix.get_column(0).unwrap();
669        let column_2 = matrix.get_column(1).unwrap();
670        let column_3 = matrix.get_column(2).unwrap();
671
672        let cmp_1 = MatZq::from_str(&format!(
673            "[[1],[{}],[{}]] mod {}",
674            i64::MAX,
675            i64::MIN,
676            u64::MAX
677        ))
678        .unwrap();
679        let cmp_2 = MatZq::from_str(&format!("[[0],[0],[0]] mod {}", u64::MAX)).unwrap();
680        let cmp_3 = MatZq::from_str(&format!("[[3],[5],[7]] mod {}", u64::MAX)).unwrap();
681
682        assert_eq!(cmp_1, column_1);
683        assert_eq!(cmp_2, column_2);
684        assert_eq!(cmp_3, column_3);
685    }
686
687    /// Ensure that getting a column with a negative index works
688    #[test]
689    fn get_column_negative_indexing_works() {
690        let matrix = MatZq::from_str(&format!(
691            "[[42, 0, 42],[{}, 0, 17],[{}, 0, 42]] mod {}",
692            i64::MAX,
693            u64::MAX - 1,
694            u64::MAX
695        ))
696        .unwrap();
697        let column_1 = matrix.get_column(-3).unwrap();
698        let column_2 = matrix.get_column(-2).unwrap();
699        let column_3 = matrix.get_column(-1).unwrap();
700
701        let cmp_1 = MatZq::from_str(&format!(
702            "[[42],[{}],[{}]] mod {}",
703            i64::MAX,
704            u64::MAX - 1,
705            u64::MAX
706        ))
707        .unwrap();
708        let cmp_2 = MatZq::from_str(&format!("[[0],[0],[0]] mod {}", u64::MAX)).unwrap();
709        let cmp_3 = MatZq::from_str(&format!("[[42],[17],[42]] mod {}", u64::MAX)).unwrap();
710
711        assert_eq!(cmp_1, column_1);
712        assert_eq!(cmp_2, column_2);
713        assert_eq!(cmp_3, column_3);
714    }
715
716    /// Ensure that wrong row and column dimensions yields an error
717    #[test]
718    fn wrong_dim_error() {
719        let matrix = MatZq::from_str(&format!(
720            "[[1, 2, 3],[{}, 4, 5],[{}, 6, 7]] mod {}",
721            i64::MAX,
722            i64::MIN,
723            u64::MAX
724        ))
725        .unwrap();
726        let row_1 = matrix.get_row(-4);
727        let row_2 = matrix.get_row(4);
728        let column_1 = matrix.get_column(-4);
729        let column_2 = matrix.get_column(4);
730
731        assert!(row_1.is_err());
732        assert!(row_2.is_err());
733        assert!(column_1.is_err());
734        assert!(column_2.is_err());
735    }
736}
737
738#[cfg(test)]
739mod test_get_submatrix {
740    use crate::{
741        integer::Z,
742        integer_mod_q::MatZq,
743        traits::{MatrixDimensions, MatrixGetSubmatrix},
744    };
745    use std::str::FromStr;
746
747    /// Ensures that getting the entire matrix as a submatrix works.
748    #[test]
749    fn entire_matrix() {
750        let mat = MatZq::identity(5, 5, i64::MAX);
751
752        let sub_mat = mat.get_submatrix(0, 4, 0, 4).unwrap();
753
754        assert_eq!(mat, sub_mat);
755    }
756
757    /// Ensures that a single matrix entry can be retrieved.
758    #[test]
759    fn matrix_single_entry() {
760        let mat = MatZq::identity(5, 5, i64::MAX);
761
762        let sub_mat = mat.get_submatrix(0, 0, 0, 0).unwrap();
763
764        let cmp_mat = MatZq::identity(1, 1, i64::MAX);
765        assert_eq!(cmp_mat, sub_mat);
766    }
767
768    /// Ensures that the dimensions of the submatrix are correct.
769    #[test]
770    fn correct_dimensions() {
771        let mat = MatZq::identity(100, 100, i64::MAX);
772
773        let sub_mat = mat.get_submatrix(1, 37, 0, 29).unwrap();
774
775        assert_eq!(37, sub_mat.get_num_rows());
776        assert_eq!(30, sub_mat.get_num_columns());
777    }
778
779    /// Ensures that a submatrix can be correctly retrieved for a matrix with large
780    /// entries.
781    #[test]
782    fn large_entries() {
783        let mat = MatZq::from_str(&format!(
784            "[[{}, 2, 3],[1, {}, 3]] mod {}",
785            u64::MAX,
786            i64::MIN,
787            u128::MAX
788        ))
789        .unwrap();
790
791        let sub_mat = mat.get_submatrix(0, 1, 0, 1).unwrap();
792
793        let cmp_mat = MatZq::from_str(&format!(
794            "[[{}, 2],[1, {}]] mod {}",
795            u64::MAX,
796            i64::MIN,
797            u128::MAX
798        ))
799        .unwrap();
800        assert_eq!(cmp_mat, sub_mat);
801    }
802
803    /// Ensures that an error is returned if coordinates are addressed that are not
804    /// within the matrix.
805    #[test]
806    fn invalid_coordinates() {
807        let mat = MatZq::identity(10, 10, u64::MAX);
808
809        assert!(mat.get_submatrix(0, 0, 0, 10).is_err());
810        assert!(mat.get_submatrix(0, 10, 0, 0).is_err());
811        assert!(mat.get_submatrix(0, 0, -11, 0).is_err());
812        assert!(mat.get_submatrix(-11, 0, 0, 0).is_err());
813    }
814
815    /// Ensure that negative indices return the correct submatrix.
816    #[test]
817    fn negative_indexing() {
818        let matrix = MatZq::identity(3, 3, u64::MAX);
819
820        assert_eq!(matrix, matrix.get_submatrix(0, -1, 0, -1).unwrap());
821        assert_eq!(matrix, matrix.get_submatrix(-3, -1, -3, -1).unwrap());
822        assert_eq!(
823            matrix.get_row(0).unwrap(),
824            matrix.get_submatrix(0, -3, -3, -1).unwrap()
825        );
826    }
827
828    /// Ensures that the function panics if no columns of the matrix are addressed.
829    #[test]
830    #[should_panic]
831    fn no_columns() {
832        let mat = MatZq::identity(10, 10, u64::MAX);
833
834        let _ = mat.get_submatrix(0, 0, 6, 5);
835    }
836
837    /// Ensures that the function panics if no rows of the matrix are addressed.
838    #[test]
839    #[should_panic]
840    fn no_rows() {
841        let mat = MatZq::identity(10, 10, u64::MAX);
842
843        let _ = mat.get_submatrix(5, 4, 0, 0);
844    }
845
846    /// Ensure that the submatrix function can be called with several types.
847    #[test]
848    fn availability() {
849        let mat = MatZq::identity(10, 10, u64::MAX);
850
851        let _ = mat.get_submatrix(0_i8, 0_i8, 0_i8, 0_i8);
852        let _ = mat.get_submatrix(0_i16, 0_i16, 0_i16, 0_i16);
853        let _ = mat.get_submatrix(0_i32, 0_i32, 0_i32, 0_i32);
854        let _ = mat.get_submatrix(0_i64, 0_i64, 0_i64, 0_i64);
855        let _ = mat.get_submatrix(0_u8, 0_u8, 0_u8, 0_u8);
856        let _ = mat.get_submatrix(0_u16, 0_i16, 0_u16, 0_u16);
857        let _ = mat.get_submatrix(0_u32, 0_i32, 0_u32, 0_u32);
858        let _ = mat.get_submatrix(0_u64, 0_i64, 0_u64, 0_u64);
859        let _ = mat.get_submatrix(&Z::ZERO, &Z::ZERO, &Z::ZERO, &Z::ZERO);
860    }
861}
862
863#[cfg(test)]
864mod test_collect_entries {
865    use super::MatZq;
866    use std::str::FromStr;
867
868    /// Ensures that all entries from the matrices are actually collected in the vector.
869    #[test]
870    fn all_entries_collected() {
871        let mat_1 = MatZq::from_str(&format!(
872            "[[1, 2],[{}, {}],[3, 4]] mod {}",
873            i64::MAX,
874            i64::MIN,
875            u64::MAX
876        ))
877        .unwrap();
878        let mat_2 = MatZq::from_str("[[-1, 2]] mod 2").unwrap();
879
880        let entries_1 = mat_1.collect_entries();
881        let entries_2 = mat_2.collect_entries();
882
883        assert_eq!(entries_1.len(), 6);
884        assert_eq!(entries_1[0], 1);
885        assert_eq!(entries_1[1], 2);
886        assert!(entries_1[2] >= 2_i64.pow(62));
887        assert!(entries_1[3] >= 2_i64.pow(62));
888        assert_eq!(entries_1[4], 3);
889        assert_eq!(entries_1[5], 4);
890
891        assert_eq!(entries_2.len(), 2);
892        assert_eq!(entries_2[0], 1);
893        assert_eq!(entries_2[1], 0);
894    }
895}
896
897#[cfg(test)]
898mod test_collect_lengths {
899    use super::{MatZq, Z};
900    use std::str::FromStr;
901
902    /// Ensures that the lengths of the matrices are collected correctly.
903    #[test]
904    fn lengths_correctly_computed() {
905        let mat_1 = MatZq::from_str(&format!(
906            "[[1, 2],[{}, {}],[3, 4]] mod {}",
907            i64::MAX - 2,
908            i64::MIN,
909            i64::MAX - 1
910        ))
911        .unwrap();
912        let mat_2 = MatZq::from_str("[[-1, 2]] mod 2").unwrap();
913
914        let lengths_1 = mat_1.collect_lengths();
915        let lengths_2 = mat_2.collect_lengths();
916
917        assert_eq!(lengths_1.len(), 6);
918        assert_eq!(lengths_1[0], Z::ONE);
919        assert_eq!(lengths_1[1], Z::from(2));
920        assert_eq!(lengths_1[2], Z::ONE);
921        assert_eq!(lengths_1[3], Z::from(2));
922        assert_eq!(lengths_1[4], Z::from(3));
923        assert_eq!(lengths_1[5], Z::from(4));
924
925        assert_eq!(lengths_2.len(), 2);
926        assert_eq!(lengths_2[0], Z::ONE);
927        assert_eq!(lengths_2[1], Z::ZERO);
928    }
929}
930
931#[cfg(test)]
932mod test_get_representative_least_absolute_residue {
933    use super::*;
934    use std::str::FromStr;
935
936    /// Test with a large modulus.
937    #[test]
938    fn large_modulus() {
939        let mat_zq = MatZq::from_str(&format!("[[1,2],[-1,-2]] mod {}", u64::MAX)).unwrap();
940
941        let mat_z = mat_zq.get_representative_least_absolute_residue();
942
943        let mat_cmp = MatZ::from_str("[[1,2],[-1,-2]]").unwrap();
944        assert_eq!(mat_z.to_string(), mat_cmp.to_string());
945    }
946
947    /// Test with even modulus.
948    #[test]
949    fn even_modulus() {
950        let mat_zq = MatZq::from_str("[[0,1,2,3,4,5,6,7,8,9,10]] mod 10").unwrap();
951
952        let mat_z = mat_zq.get_representative_least_absolute_residue();
953
954        let mat_cmp = MatZ::from_str("[[0,1,2,3,4,5,-4,-3,-2,-1,0]]").unwrap();
955        assert_eq!(mat_z.to_string(), mat_cmp.to_string());
956    }
957
958    /// Test with uneven modulus.
959    #[test]
960    fn uneven_modulus() {
961        let mat_zq = MatZq::from_str("[[0,1,2,3,4,5,6,7,8,9,10,11]] mod 11").unwrap();
962
963        let mat_z = mat_zq.get_representative_least_absolute_residue();
964
965        let mat_cmp = MatZ::from_str("[[0,1,2,3,4,5,-5,-4,-3,-2,-1,0]]").unwrap();
966        assert_eq!(mat_z.to_string(), mat_cmp.to_string());
967    }
968
969    /// Checks whether every entry is mapped to the same representative as by
970    /// [`Zq::get_representative_least_absolute_residue`] for an odd and an even modulus.
971    #[test]
972    fn consistent_with_zq() {
973        for modulus in [256, 257] {
974            let mut mat_zq = MatZq::new(1, modulus, modulus);
975            for value in 0..modulus {
976                mat_zq.set_entry(0, value, value).unwrap();
977            }
978
979            let mat_z = mat_zq.get_representative_least_absolute_residue();
980
981            for value in 0..modulus {
982                let entry: Z = mat_z.get_entry(0, value).unwrap();
983                let cmp = Zq::from((value, modulus)).get_representative_least_absolute_residue();
984                assert_eq!(cmp, entry);
985            }
986        }
987    }
988}