qfall_math/integer_mod_q/mat_polynomial_ring_zq/
transpose.rs

1// Copyright © 2023 Marcel Luca Schmidt
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module contains the implementation of the `transpose` function.
10
11use super::MatPolynomialRingZq;
12use crate::traits::MatrixDimensions;
13use flint_sys::fmpz_poly_mat::fmpz_poly_mat_transpose;
14
15impl MatPolynomialRingZq {
16    /// Returns the transposed form of the given matrix, i.e. rows get transformed to columns
17    /// and vice versa.
18    ///
19    /// # Examples
20    /// ```
21    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
22    /// use qfall_math::integer::MatPolyOverZ;
23    /// use std::str::FromStr;
24    ///
25    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
26    /// let poly_mat = MatPolyOverZ::from_str("[[1  42],[2  1 2],[1  17]]").unwrap();
27    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
28    ///
29    /// let transpose = poly_ring_mat.transpose();
30    /// ```
31    pub fn transpose(&self) -> Self {
32        let mut out = Self::new(self.get_num_columns(), self.get_num_rows(), &self.modulus);
33        unsafe { fmpz_poly_mat_transpose(&mut out.matrix.matrix, &self.matrix.matrix) };
34        out
35    }
36}
37
38#[cfg(test)]
39mod test_transpose {
40    use crate::{
41        integer::MatPolyOverZ,
42        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
43    };
44    use std::str::FromStr;
45
46    const LARGE_PRIME: u64 = u64::MAX - 58;
47
48    /// Checks if a row is correctly converted to a column
49    #[test]
50    fn row_to_column() {
51        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
52        let poly_mat = MatPolyOverZ::from_str("[[1  42],[2  1 2],[1  17]]").unwrap();
53        let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
54        let cmp = MatPolyOverZ::from_str("[[1  8, 2  1 2, 1  0]]").unwrap();
55
56        assert_eq!(cmp, poly_ring_mat.transpose().matrix);
57    }
58
59    /// Checks if a column is correctly converted to a row
60    #[test]
61    fn column_to_row() {
62        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
63        let poly_mat = MatPolyOverZ::from_str("[[1  42, 2  1 2, 1  17]]").unwrap();
64        let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
65        let cmp = MatPolyOverZ::from_str("[[1  8],[2  1 2],[1  0]]").unwrap();
66
67        assert_eq!(cmp, poly_ring_mat.transpose().matrix);
68    }
69
70    /// Checks if large, negative, and zero values are transposed correctly
71    #[test]
72    fn different_entry_values() {
73        let modulus =
74            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {LARGE_PRIME}")).unwrap();
75        let poly_mat =
76            MatPolyOverZ::from_str(&format!("[[1  {}, 1  -42, 1  0]]", i64::MAX)).unwrap();
77        let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
78        let cmp = MatPolyOverZ::from_str(&format!(
79            "[[1  {}],[1  {}],[1  0]]",
80            i64::MAX,
81            LARGE_PRIME - 42
82        ))
83        .unwrap();
84
85        assert_eq!(cmp, poly_ring_mat.transpose().matrix);
86    }
87}