qfall_math/integer/mat_poly_over_z/
reduce.rs

1// Copyright © 2023 Marvin Beckmann
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 allows to simulate functionality of matrices over the polynomial ring
10//! `Z[X]/f(x)` by entrywise reducing a [`MatPolyOverZ`] by a [`PolyOverZ`] that
11//! has a leading coefficient of `1`.
12
13use super::MatPolyOverZ;
14use crate::{
15    integer::{PolyOverZ, poly_over_z::fmpz_poly_helpers::reduce_fmpz_poly_by_poly_over_z},
16    traits::MatrixDimensions,
17};
18use flint_sys::fmpz_poly_mat::fmpz_poly_mat_entry;
19
20impl MatPolyOverZ {
21    /// Entrywise reduces a matrix of polynomials by a polynomial `modulus`.
22    /// The modulus must have a leading coefficient of `1`, else the function will panic.
23    ///
24    /// Parameters:
25    /// - `modulus`: Specifies the polynomial by which `self` is reduced
26    ///
27    /// # Examples
28    /// ```
29    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
30    /// use std::str::FromStr;
31    ///
32    /// let mut a = MatPolyOverZ::from_str("[[4  0 1 2 3, 3  0 1 1]]").unwrap();
33    /// let modulus = PolyOverZ::from_str("3  0 1 1").unwrap();
34    ///
35    /// a.reduce_by_poly(&modulus);
36    ///
37    /// assert_eq!(MatPolyOverZ::from_str("[[2  0 2, 0]]").unwrap(), a);
38    /// ```
39    ///
40    /// # Panics ...
41    /// - if the modulus does not have a leading coefficient of `1`.
42    pub fn reduce_by_poly(&mut self, modulus: &PolyOverZ) {
43        for i in 0..self.get_num_rows() {
44            for j in 0..self.get_num_columns() {
45                unsafe {
46                    let entry = fmpz_poly_mat_entry(&self.matrix, i, j);
47                    reduce_fmpz_poly_by_poly_over_z(entry, modulus);
48                }
49            }
50        }
51    }
52}
53
54#[cfg(test)]
55mod test_reduce_by_poly {
56    use crate::integer::{MatPolyOverZ, PolyOverZ};
57    use std::str::FromStr;
58
59    /// Ensures that the reduction works properly for a fixed polynomial that has to be
60    /// reduce or more than one coefficient.
61    #[test]
62    fn reduce_more_than_once() {
63        let mut a = MatPolyOverZ::from_str("[[4  0 1 2 3, 3  0 1 1]]").unwrap();
64        let modulus = PolyOverZ::from_str("3  0 1 1").unwrap();
65
66        a.reduce_by_poly(&modulus);
67
68        assert_eq!(MatPolyOverZ::from_str("[[2  0 2, 0]]").unwrap(), a);
69    }
70
71    /// Ensures that the function panics, if the leading coefficient is not `1`.
72    #[test]
73    #[should_panic]
74    fn no_leading_zero() {
75        let mut a = MatPolyOverZ::from_str("[[3  1 2 3]]").unwrap();
76        let modulus = PolyOverZ::from_str("2  1 2").unwrap();
77
78        a.reduce_by_poly(&modulus);
79    }
80
81    /// Ensures that large coefficients are reduced properly.
82    #[test]
83    fn large_coefficients() {
84        let mut a = MatPolyOverZ::from_str(&format!(
85            "[[3  1 -{} -1, 1  1],[1  -1, 4  0 0 {} 1]]",
86            u64::MAX,
87            u64::MAX
88        ))
89        .unwrap();
90        let modulus = PolyOverZ::from_str(&format!("2  {} 1", u64::MAX)).unwrap();
91
92        a.reduce_by_poly(&modulus);
93
94        let cmp_mat = MatPolyOverZ::from_str("[[1  1, 1  1],[1  -1, 0]]").unwrap();
95        assert_eq!(cmp_mat, a);
96    }
97}