qfall_math/integer/poly_over_z/
evaluate.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//! Implementations to evaluate a [`PolyOverZ`].
10//! For each reasonable type, an implementation
11//! of the [`Evaluate`] trait should be implemented.
12
13use super::PolyOverZ;
14use crate::{integer::Z, rational::Q, traits::Evaluate};
15use flint_sys::fmpz_poly::{fmpz_poly_evaluate_fmpq, fmpz_poly_evaluate_fmpz};
16
17impl<Integer: Into<Z>> Evaluate<Integer, Z> for PolyOverZ {
18    /// Evaluates a [`PolyOverZ`] on a given input.
19    ///
20    /// Parameters:
21    /// - `value`: the value with which to evaluate the polynomial.
22    ///
23    /// Returns the evaluation of the polynomial as a [`Z`].
24    ///
25    /// # Examples
26    /// ```
27    /// use qfall_math::traits::*;
28    /// use qfall_math::integer::Z;
29    /// use qfall_math::integer::PolyOverZ;
30    /// use std::str::FromStr;
31    ///
32    /// let poly = PolyOverZ::from_str("5  0 1 2 -3 1").unwrap();
33    /// let res: Z = poly.evaluate(3);
34    /// ```
35    fn evaluate(&self, value: Integer) -> Z {
36        let value = value.into();
37        let mut res = Z::default();
38
39        unsafe { fmpz_poly_evaluate_fmpz(&mut res.value, &self.poly, &value.value) };
40
41        res
42    }
43}
44
45impl<Rational: Into<Q>> Evaluate<Rational, Q> for PolyOverZ {
46    /// Evaluates a [`PolyOverZ`] on a given input.
47    ///
48    /// Parameters:
49    /// - `value`: the value with which to evaluate the polynomial.
50    ///
51    /// Returns the evaluation of the polynomial as a [`Q`].
52    ///
53    /// # Examples
54    /// ```
55    /// use qfall_math::traits::*;
56    /// use qfall_math::rational::Q;
57    /// use qfall_math::integer::PolyOverZ;
58    /// use std::str::FromStr;
59    ///
60    /// let poly = PolyOverZ::from_str("5  0 1 2 -3 1").unwrap();
61    /// let value = Q::from((3, 2));
62    /// let res: Q = poly.evaluate(&value);
63    /// ```
64    fn evaluate(&self, value: Rational) -> Q {
65        let value = value.into();
66        let mut res = Q::default();
67
68        unsafe { fmpz_poly_evaluate_fmpq(&mut res.value, &self.poly, &value.value) };
69
70        res
71    }
72}
73
74#[cfg(test)]
75mod test_evaluate_z {
76    use crate::integer::{PolyOverZ, Z};
77    use crate::traits::Evaluate;
78    use std::str::FromStr;
79
80    /// Tests if evaluate works for [`Z`] as input
81    #[test]
82    fn eval_z() {
83        let poly = PolyOverZ::from_str("2  1 2").unwrap();
84
85        let res: Z = poly.evaluate(Z::from(3));
86
87        assert_eq!(7, res);
88    }
89
90    /// Tests if evaluate with a reference works
91    #[test]
92    fn eval_z_ref() {
93        let poly = PolyOverZ::from_str("2  1 2").unwrap();
94
95        let res: Z = poly.evaluate(&Z::from(3));
96
97        assert_eq!(7, res);
98    }
99
100    /// Tests if evaluate works with negative values
101    #[test]
102    fn eval_z_negative() {
103        let poly = PolyOverZ::from_str("2  1 2").unwrap();
104
105        let res: Z = poly.evaluate(-5);
106
107        assert_eq!(-9, res);
108    }
109
110    /// Tests if evaluate works with large integers
111    #[test]
112    fn eval_z_large() {
113        let poly = PolyOverZ::from_str("2  1 2").unwrap();
114
115        let res: Z = poly.evaluate(&Z::from_str(&"1".repeat(65)).unwrap());
116
117        let mut res_cmp_str = "2".repeat(64);
118        res_cmp_str.push('3');
119        assert_eq!(Z::from_str(&res_cmp_str).unwrap(), res);
120    }
121
122    /// Test if evaluate works with max of [`i64`],[`i32`], ...
123    #[test]
124    fn eval_max() {
125        let poly = PolyOverZ::from_str("2  1 2").unwrap();
126
127        // signed
128        let _: Z = poly.evaluate(i64::MAX);
129        let _: Z = poly.evaluate(i32::MAX);
130        let _: Z = poly.evaluate(i16::MAX);
131        let _: Z = poly.evaluate(i8::MAX);
132
133        //unsigned
134        let _: Z = poly.evaluate(u64::MAX);
135        let _: Z = poly.evaluate(u32::MAX);
136        let _: Z = poly.evaluate(u16::MAX);
137        let _: Z = poly.evaluate(u8::MAX);
138    }
139
140    /// Test if evaluate works with min of [`i64`],[`i32`], ...
141    #[test]
142    fn eval_min() {
143        let poly = PolyOverZ::from_str("2  1 2").unwrap();
144
145        // signed
146        let _: Z = poly.evaluate(i64::MIN);
147        let _: Z = poly.evaluate(i32::MIN);
148        let _: Z = poly.evaluate(i16::MIN);
149        let _: Z = poly.evaluate(i8::MIN);
150
151        // unsigned
152        let _: Z = poly.evaluate(u64::MIN);
153        let _: Z = poly.evaluate(u32::MIN);
154        let _: Z = poly.evaluate(u16::MIN);
155        let _: Z = poly.evaluate(u8::MIN);
156    }
157}
158
159#[cfg(test)]
160mod test_evaluate_q {
161    use crate::{integer::PolyOverZ, rational::Q, traits::Evaluate};
162    use std::str::FromStr;
163
164    /// Ensures that positive values return expected evaluation
165    #[test]
166    fn evaluate_positive() {
167        let poly = PolyOverZ::from_str("2  1 3").unwrap();
168        let value = Q::from((3, 2));
169
170        let res_ref = poly.evaluate(&value);
171        let res = poly.evaluate(value);
172
173        assert_eq!(Q::from((11, 2)), res);
174        assert_eq!(res_ref, res);
175    }
176
177    /// Ensures that negative values return expected evaluation
178    #[test]
179    fn evaluate_negative() {
180        let poly = PolyOverZ::from_str("2  1 3").unwrap();
181        let value = Q::from((-3, 2));
182
183        let res_ref = poly.evaluate(&value);
184        let res = poly.evaluate(value);
185
186        assert_eq!(Q::from((-7, 2)), res);
187        assert_eq!(res_ref, res);
188    }
189
190    /// Ensures that positive large values return expected evaluation
191    #[test]
192    fn evaluate_large_positive() {
193        let poly = PolyOverZ::from_str(&format!("2  {} 1", (u64::MAX - 1) / 2)).unwrap();
194        let value = Q::from((u64::MAX - 1) / 2);
195
196        let res_ref = poly.evaluate(&value);
197        let res = poly.evaluate(value);
198
199        assert_eq!(Q::from(u64::MAX - 1), res);
200        assert_eq!(res_ref, res);
201    }
202
203    /// Ensures that negative large values return expected evaluation
204    #[test]
205    fn evaluate_large_negative() {
206        let poly = PolyOverZ::from_str(&format!("2  {} 2", u64::MAX)).unwrap();
207        let value = Q::from_str(&format!("-{}", (u64::MAX - 1) / 2)).unwrap();
208
209        let res_ref = poly.evaluate(&value);
210        let res = poly.evaluate(value);
211
212        assert_eq!(Q::ONE, res);
213        assert_eq!(res_ref, res);
214    }
215}