qfall_math/rational/poly_over_q/
get.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 get information about a [`PolyOverQ`].
10
11use super::PolyOverQ;
12use crate::{rational::Q, traits::GetCoefficient};
13use flint_sys::fmpq_poly::{fmpq_poly_degree, fmpq_poly_get_coeff_fmpq};
14
15impl GetCoefficient<Q> for PolyOverQ {
16    /// Returns the coefficient of a polynomial [`PolyOverQ`] as a [`Q`].
17    ///
18    /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
19    ///
20    /// Parameters:
21    /// - `index`: the index of the coefficient to get (has to be positive)
22    ///
23    /// Returns the coefficient as a [`Q`], or a [`MathError`](crate::error::MathError) if the provided index
24    /// is negative and therefore invalid, or it does not fit into an [`i64`].
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::rational::{Q, PolyOverQ};
29    /// use std::str::FromStr;
30    /// use qfall_math::traits::*;
31    ///
32    /// let poly = PolyOverQ::from_str("4  0 1 2/3 3/2").unwrap();
33    ///
34    /// let coeff_0 = poly.get_coeff(0).unwrap();
35    /// let coeff_1 = unsafe{ poly.get_coeff_unchecked(1) };
36    /// let coeff_4 = poly.get_coeff(4).unwrap();
37    ///
38    /// assert_eq!(Q::ZERO, coeff_0);
39    /// assert_eq!(Q::ONE, coeff_1);
40    /// assert_eq!(Q::ZERO, coeff_4);
41    /// ```
42    ///
43    /// # Safety
44    /// To use this function safely, make sure that the selected index
45    /// is greater or equal than `0`.
46    unsafe fn get_coeff_unchecked(&self, index: i64) -> Q {
47        let mut out = Q::default();
48        unsafe { fmpq_poly_get_coeff_fmpq(&mut out.value, &self.poly, index) }
49        out
50    }
51}
52
53impl PolyOverQ {
54    /// Returns the degree of a polynomial [`PolyOverQ`] as a [`i64`].
55    /// The zero polynomial has degree `-1`.
56    ///
57    /// # Examples
58    /// ```
59    /// use qfall_math::rational::PolyOverQ;
60    /// use std::str::FromStr;
61    ///
62    /// let poly = PolyOverQ::from_str("4  0 1/9 2 -3/4").unwrap();
63    ///
64    /// let degree = poly.get_degree(); // This would only return 3
65    /// ```
66    pub fn get_degree(&self) -> i64 {
67        unsafe { fmpq_poly_degree(&self.poly) }
68    }
69}
70
71#[cfg(test)]
72mod test_get_coeff {
73    use crate::{
74        rational::{PolyOverQ, Q},
75        traits::GetCoefficient,
76    };
77    use std::str::FromStr;
78
79    /// Ensure that `0` is returned if the provided index is not yet set
80    #[test]
81    fn index_out_of_range() {
82        let poly = PolyOverQ::from_str("4  0 1 2/3 3/2").unwrap();
83
84        let zero_coeff = poly.get_coeff(4).unwrap();
85
86        assert_eq!(Q::ZERO, zero_coeff);
87    }
88
89    /// Test if indices smaller than `0` return an error
90    #[test]
91    fn index_too_small() {
92        let poly = PolyOverQ::default();
93
94        assert!(poly.get_coeff(-1).is_err());
95    }
96
97    /// Tests if negative coefficients are returned correctly
98    #[test]
99    fn negative_coeff() {
100        let poly = PolyOverQ::from_str("4  0 1 2/3 -3/2").unwrap();
101
102        let coeff = poly.get_coeff(3).unwrap();
103
104        assert_eq!(Q::from((-3, 2)), coeff);
105    }
106
107    /// Tests if positive coefficients are returned correctly
108    #[test]
109    fn positive_coeff() {
110        let poly = PolyOverQ::from_str("4  0 1 2/3 -3/2").unwrap();
111
112        let coeff = poly.get_coeff(2).unwrap();
113
114        assert_eq!(Q::from((2, 3)), coeff);
115    }
116
117    /// Tests if large coefficients are returned correctly
118    #[test]
119    fn large_coeff() {
120        let q_str = format!("-{}/{}", u64::MAX, i64::MIN);
121        let large_string = format!("2  {q_str} {}", u64::MAX);
122        let poly = PolyOverQ::from_str(&large_string).unwrap();
123
124        assert_eq!(Q::from_str(&q_str).unwrap(), poly.get_coeff(0).unwrap());
125        assert_eq!(Q::from(u64::MAX), poly.get_coeff(1).unwrap());
126    }
127
128    /// Tests if large negative coefficients are returned correctly
129    #[test]
130    fn large_coeff_neg() {
131        let large_string = format!("2  {}/{} {}", u64::MAX, i64::MIN, u64::MAX);
132        let poly = PolyOverQ::from_str(&large_string).unwrap();
133
134        assert_eq!(Q::from((u64::MAX, i64::MIN)), poly.get_coeff(0).unwrap());
135        assert_eq!(Q::from(u64::MAX), poly.get_coeff(1).unwrap());
136    }
137}
138
139#[cfg(test)]
140mod test_get_degree {
141    use crate::rational::PolyOverQ;
142    use std::str::FromStr;
143
144    /// Ensure that degree is working
145    #[test]
146    fn degree() {
147        let poly = PolyOverQ::from_str("4  -12/7 1 2/9 3/7").unwrap();
148
149        let deg = poly.get_degree();
150
151        assert_eq!(3, deg);
152    }
153
154    /// Ensure that degree is working for constant polynomials
155    #[test]
156    fn degree_constant() {
157        let poly_1 = PolyOverQ::from_str("1  1/8").unwrap();
158        let poly_2 = PolyOverQ::default();
159
160        let deg_1 = poly_1.get_degree();
161        let deg_2 = poly_2.get_degree();
162
163        assert_eq!(0, deg_1);
164        assert_eq!(-1, deg_2);
165    }
166
167    /// Ensure that degree is working for polynomials with leading 0 coefficients
168    #[test]
169    fn degree_leading_zeros() {
170        let poly = PolyOverQ::from_str("4  1/127 0 0 0").unwrap();
171
172        let deg = poly.get_degree();
173
174        assert_eq!(0, deg);
175    }
176}