qfall_math/rational/poly_over_q/
set.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 manipulate a [`PolyOverQ`] polynomial.
10
11use super::PolyOverQ;
12use crate::{rational::Q, traits::SetCoefficient};
13use flint_sys::fmpq_poly::fmpq_poly_set_coeff_fmpq;
14
15impl<Rational: Into<Q>> SetCoefficient<Rational> for PolyOverQ {
16    /// Sets the coefficient of a polynomial [`PolyOverQ`].
17    /// We advise to use small coefficients, since already 2^32 coefficients take space
18    /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
19    /// the index is very high.
20    ///
21    /// Parameters:
22    /// - `index`: the index of the coefficient to set (has to be positive)
23    /// - `value`: the new value the index should have
24    ///
25    /// Returns an empty `Ok` if the action could be performed successfully.
26    /// Otherwise, a [`MathError`](crate::error::MathError) is returned if either the index is negative
27    /// or it does not fit into an [`i64`].
28    ///
29    /// # Examples
30    /// ```
31    /// use qfall_math::rational::PolyOverQ;
32    /// use qfall_math::rational::Q;
33    /// use qfall_math::traits::*;
34    /// use std::str::FromStr;
35    ///
36    /// let mut poly = PolyOverQ::from_str("4  0 1 2/3 3/17").unwrap();
37    /// let value = Q::from((3, 17));
38    ///
39    /// assert!(poly.set_coeff(4, &value).is_ok());
40    /// unsafe{ poly.set_coeff_unchecked(5, 3.5_f64) };
41    /// ```
42    ///
43    /// # Safety
44    /// To use this function safely, make sure that the selected index
45    /// is greater or equal than `0` and that the provided value has
46    /// the same base so that they have a matching base.
47    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: Rational) {
48        let value = value.into();
49
50        unsafe {
51            fmpq_poly_set_coeff_fmpq(&mut self.poly, index, &value.value);
52        }
53    }
54}
55
56#[cfg(test)]
57mod test_set_coeff_z {
58    use crate::{integer::Z, rational::PolyOverQ, traits::SetCoefficient};
59    use std::str::FromStr;
60
61    /// Ensure that the negative indices return an error.
62    #[test]
63    fn set_min_negative_coeff() {
64        let mut poly = PolyOverQ::from_str("2  -1 3/17").unwrap();
65
66        assert!(poly.set_coeff(i64::MIN, 2).is_err());
67        assert!(poly.set_coeff(i32::MIN, 2).is_err());
68        assert!(poly.set_coeff(i16::MIN, 2).is_err());
69        assert!(poly.set_coeff(i8::MIN, 2).is_err());
70    }
71
72    /// Ensure that large coefficients work.
73    #[test]
74    fn set_coeff_large() {
75        let mut poly = PolyOverQ::from_str("2  -1 3/17").unwrap();
76
77        assert!(poly.set_coeff(2, i32::MAX).is_ok());
78        assert!(poly.set_coeff(2, i64::MAX).is_ok());
79    }
80
81    /// Ensure that the max of [`u8`] and [`u16`] works as an index.
82    #[test]
83    fn set_index_large() {
84        let mut poly = PolyOverQ::from_str("2  -1 3/17").unwrap();
85
86        assert!(poly.set_coeff(u8::MAX, 2).is_ok());
87        assert!(poly.set_coeff(u16::MAX, 2).is_ok());
88    }
89
90    /// Ensure that a general case is working.
91    #[test]
92    fn set_coeff_working() {
93        let mut poly = PolyOverQ::from_str("4  0 -1 2 3/17").unwrap();
94        let value = 10000;
95
96        poly.set_coeff(0, value).unwrap();
97        poly.set_coeff(5, value).unwrap();
98        assert_eq!(
99            PolyOverQ::from_str("6  10000 -1 2 3/17 0 10000").unwrap(),
100            poly
101        );
102    }
103
104    /// Ensure that the correct coefficient is set and all others are set to `0`.
105    #[test]
106    fn set_coeff_rest_zero() {
107        let mut poly = PolyOverQ::default();
108
109        poly.set_coeff(4, -10).unwrap();
110        assert_eq!(PolyOverQ::from_str("5  0 0 0 0 -10").unwrap(), poly);
111    }
112
113    /// Ensure that setting with a [`Z`] works.
114    #[test]
115    fn set_coeff_z() {
116        let mut poly = PolyOverQ::default();
117
118        poly.set_coeff(4, Z::from(123)).unwrap();
119        poly.set_coeff(5, &Z::from(321)).unwrap();
120        assert_eq!(PolyOverQ::from_str("6  0 0 0 0 123 321").unwrap(), poly);
121    }
122
123    /// Ensure that setting large coefficients works.
124    #[test]
125    fn large_coeff_z() {
126        let mut poly = PolyOverQ::default();
127
128        poly.set_coeff(4, u64::MAX).unwrap();
129        assert_eq!(
130            PolyOverQ::from_str(&format!("5  0 0 0 0 {}", u64::MAX)).unwrap(),
131            poly
132        );
133    }
134}
135
136#[cfg(test)]
137mod test_set_coeff_q {
138    use crate::{
139        rational::{PolyOverQ, Q},
140        traits::{GetCoefficient, SetCoefficient},
141    };
142    use std::str::FromStr;
143
144    /// Ensure that setting with a large [`Q`] works
145    #[test]
146    fn large_coeff() {
147        let mut poly = PolyOverQ::from_str("1  1").unwrap();
148        let q = Q::from((u64::MAX - 1, u64::MAX));
149
150        poly.set_coeff(2, &q).unwrap();
151
152        assert_eq!(q, poly.get_coeff(2).unwrap());
153        assert_eq!(
154            PolyOverQ::from_str(&format!("3  1 0 {}/{}", u64::MAX - 1, u64::MAX)).unwrap(),
155            poly
156        )
157    }
158}