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}