qfall_math/integer/mat_poly_over_z/
evaluate.rs

1//! Implementations to evaluate a [`MatPolyOverZ`].
2//! For each reasonable type, an implementation
3//! of the [`Evaluate`] trait should be implemented.
4
5use super::MatPolyOverZ;
6use crate::{
7    integer::{MatZ, Z},
8    traits::{Evaluate, MatrixDimensions},
9};
10use flint_sys::fmpz_poly_mat::fmpz_poly_mat_evaluate_fmpz;
11
12impl<Integer: Into<Z>> Evaluate<Integer, MatZ> for MatPolyOverZ {
13    /// Evaluates a [`MatPolyOverZ`] on a given input entrywise.
14    ///
15    /// Parameters:
16    /// - `value`: the value with which to evaluate the matrix of polynomials.
17    ///
18    /// Returns the evaluation of the polynomial as a [`MatZ`].
19    ///
20    /// # Examples
21    /// ```rust
22    /// use qfall_math::traits::*;
23    /// use qfall_math::integer::Z;
24    /// use qfall_math::integer::MatPolyOverZ;
25    /// use std::str::FromStr;
26    ///
27    /// let poly = MatPolyOverZ::from_str("[[0, 1  17, 2  24 42],[2  24 42, 2  24 42, 2  24 42]]").unwrap();
28    /// let res = poly.evaluate(3);
29    /// ```
30    fn evaluate(&self, value: Integer) -> MatZ {
31        let value = value.into();
32        // we can unwrap since we know, that the dimensions of our current matrix are positive
33        let mut res = MatZ::new(self.get_num_rows(), self.get_num_columns());
34
35        unsafe { fmpz_poly_mat_evaluate_fmpz(&mut res.matrix, &self.matrix, &value.value) };
36
37        res
38    }
39}
40
41#[cfg(test)]
42mod test_evaluate {
43    use crate::integer::{MatPolyOverZ, MatZ, Z};
44    use crate::traits::Evaluate;
45    use std::str::FromStr;
46
47    /// Tests if evaluate works for [`Z`] as input
48    #[test]
49    fn eval_z() {
50        let poly_str = "[[1  17],[2  24 42]]";
51        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
52
53        let res = poly.evaluate(Z::from(3));
54
55        assert_eq!(MatZ::from_str("[[17],[150]]").unwrap(), res);
56    }
57
58    /// Tests if evaluate_z_ref with a reference works
59    #[test]
60    fn eval_z_ref() {
61        let poly_str = "[[1  17],[2  24 42]]";
62        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
63
64        let res = poly.evaluate(&Z::from(3));
65
66        assert_eq!(MatZ::from_str("[[17],[150]]").unwrap(), res);
67    }
68
69    /// Tests if evaluate works with negative values
70    #[test]
71    fn eval_z_negative() {
72        let poly_str = "[[1  17],[2  24 42]]";
73        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
74
75        let res = poly.evaluate(&Z::from(-5));
76
77        assert_eq!(MatZ::from_str("[[17],[-186]]").unwrap(), res);
78    }
79
80    /// Tests if evaluate works with large integers
81    #[test]
82    fn eval_z_large() {
83        let poly_str = "[[1  17],[2  6 2]]";
84        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
85
86        let res = poly.evaluate(&Z::from_str(&"1".repeat(65)).unwrap());
87
88        let res_cmp_str = format!("[[17],[{}8]]", "2".repeat(64));
89        assert_eq!(MatZ::from_str(&res_cmp_str).unwrap(), res);
90    }
91
92    /// Tests whether evaluation of a large entry in the matrix with a large value works
93    #[test]
94    fn eval_large_with_large() {
95        let poly_str = format!("[[2  {} -1, 1  1],[1  {}, 2  0 1]]", u64::MAX, u64::MAX);
96        let poly = MatPolyOverZ::from_str(&poly_str).unwrap();
97        let res = poly.evaluate(Z::from(u64::MAX));
98
99        let res_cmp_str = format!("[[0, 1],[{}, {}]]", u64::MAX, u64::MAX);
100        assert_eq!(MatZ::from_str(&res_cmp_str).unwrap(), res);
101    }
102
103    /// Test if evaluate works with max of i64, i32, ...
104    #[test]
105    fn eval_max() {
106        let poly_str = "[[1  17],[2  24 42]]";
107        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
108
109        // signed
110        let _ = poly.evaluate(i64::MAX);
111        let _ = poly.evaluate(i32::MAX);
112        let _ = poly.evaluate(i16::MAX);
113        let _ = poly.evaluate(i8::MAX);
114
115        //unsigned
116        let _ = poly.evaluate(u64::MAX);
117        let _ = poly.evaluate(u32::MAX);
118        let _ = poly.evaluate(u16::MAX);
119        let _ = poly.evaluate(u8::MAX);
120    }
121
122    /// Test if evaluate works with min of i64, i32, ...
123    #[test]
124    fn eval_min() {
125        let poly_str = "[[1  17],[2  24 42]]";
126        let poly = MatPolyOverZ::from_str(poly_str).unwrap();
127
128        // signed
129        let _ = poly.evaluate(i64::MIN);
130        let _ = poly.evaluate(i32::MIN);
131        let _ = poly.evaluate(i16::MIN);
132        let _ = poly.evaluate(i8::MIN);
133
134        // unsigned
135        let _ = poly.evaluate(u64::MIN);
136        let _ = poly.evaluate(u32::MIN);
137        let _ = poly.evaluate(u16::MIN);
138        let _ = poly.evaluate(u8::MIN);
139    }
140}