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