qfall_math/rational/poly_over_q/arithmetic/
sub.rs

1// Copyright © 2023 Phil Milewski, Marcel Luca Schmidt
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//! Implementation of the [`Sub`] trait for [`PolyOverQ`] values.
10
11use super::super::PolyOverQ;
12use crate::{
13    integer::PolyOverZ,
14    macros::arithmetics::{
15        arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
16        arithmetic_trait_mixed_borrowed_owned,
17    },
18};
19use flint_sys::fmpq_poly::fmpq_poly_sub;
20use std::ops::{Sub, SubAssign};
21
22impl SubAssign<&PolyOverQ> for PolyOverQ {
23    /// Computes the subtraction of `self` and `other` reusing
24    /// the memory of `self`.
25    /// [`SubAssign`] can be used on [`PolyOverQ`] in combination with
26    /// [`PolyOverQ`] and [`PolyOverZ`].
27    ///
28    /// Parameters:
29    /// - `other`: specifies the polynomial to subtract to `self`
30    ///
31    /// Returns the difference of both polynomials as a [`PolyOverQ`].
32    ///
33    /// # Examples
34    /// ```
35    /// use qfall_math::{rational::PolyOverQ, integer::PolyOverZ};
36    /// use std::str::FromStr;
37    ///
38    /// let mut a = PolyOverQ::from_str("3  1 2/3 -3/4").unwrap();
39    /// let b = PolyOverQ::from_str("5  1 2 -3 0 8/9").unwrap();
40    /// let c = PolyOverZ::from_str("2  -1 2").unwrap();
41    ///
42    /// a -= &b;
43    /// a -= b;
44    /// a -= &c;
45    /// a -= c;
46    /// ```
47    fn sub_assign(&mut self, other: &Self) {
48        unsafe { fmpq_poly_sub(&mut self.poly, &self.poly, &other.poly) };
49    }
50}
51impl SubAssign<&PolyOverZ> for PolyOverQ {
52    /// Documentation at [`PolyOverQ::sub_assign`].
53    fn sub_assign(&mut self, other: &PolyOverZ) {
54        let other = PolyOverQ::from(other);
55
56        self.sub_assign(other);
57    }
58}
59
60arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverQ, PolyOverQ);
61arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverQ, PolyOverZ);
62
63impl Sub for &PolyOverQ {
64    type Output = PolyOverQ;
65    /// Implements the [`Sub`] trait for two [`PolyOverQ`] values.
66    /// [`Sub`] is implemented for any combination of [`PolyOverQ`] and borrowed [`PolyOverQ`].
67    ///
68    /// Parameters:
69    /// - `other`: specifies the value to subtract from `self`
70    ///
71    /// Returns the result of the subtraction of both polynomials as a [`PolyOverQ`].
72    ///
73    /// # Examples
74    /// ```
75    /// use qfall_math::rational::PolyOverQ;
76    /// use std::str::FromStr;
77    ///
78    /// let a: PolyOverQ = PolyOverQ::from_str("3  1/8 2/5 -3").unwrap();
79    /// let b: PolyOverQ = PolyOverQ::from_str("5  1/9 2/7 -3/17 0 8/9").unwrap();
80    ///
81    /// let c: PolyOverQ = &a - &b;
82    /// let d: PolyOverQ = a - b;
83    /// let e: PolyOverQ = &c - d;
84    /// let f: PolyOverQ = c - &e;
85    /// ```
86    fn sub(self, other: Self) -> Self::Output {
87        let mut out = PolyOverQ::default();
88        unsafe {
89            fmpq_poly_sub(&mut out.poly, &self.poly, &other.poly);
90        }
91        out
92    }
93}
94
95arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverQ, PolyOverQ, PolyOverQ);
96arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverQ, PolyOverQ, PolyOverQ);
97
98impl Sub<&PolyOverZ> for &PolyOverQ {
99    type Output = PolyOverQ;
100    /// Implements the [`Sub`] trait for [`PolyOverQ`] and [`PolyOverZ`].
101    /// [`Sub`] is implemented for any combination of owned and borrowed values.
102    ///
103    /// Parameters:
104    /// - `other`: specifies the polynomial to subtract from `self`
105    ///
106    /// Returns the subtraction of both polynomials as a [`PolyOverQ`].
107    ///
108    /// # Examples
109    /// ```
110    /// use qfall_math::rational::PolyOverQ;
111    /// use qfall_math::integer::PolyOverZ;
112    /// use std::str::FromStr;
113    ///
114    /// let a = PolyOverQ::from_str("4  1/2 0 3/7 1").unwrap();
115    /// let b = PolyOverZ::from_str("4  2 0 3 1").unwrap();
116    ///
117    /// let c: PolyOverQ = &a - &b;
118    /// ```
119    fn sub(self, other: &PolyOverZ) -> Self::Output {
120        let mut out = PolyOverQ::default();
121        unsafe {
122            fmpq_poly_sub(&mut out.poly, &self.poly, &PolyOverQ::from(other).poly);
123        }
124        out
125    }
126}
127
128arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverQ, PolyOverZ, PolyOverQ);
129arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverQ, PolyOverZ, PolyOverQ);
130
131#[cfg(test)]
132mod test_sub_assign {
133    use super::PolyOverQ;
134    use crate::{integer::PolyOverZ, rational::Q};
135    use std::str::FromStr;
136
137    /// Ensure that `sub_assign` works for small numbers.
138    #[test]
139    fn correct_small() {
140        let mut a = PolyOverQ::from_str("3  1/7 2/7 -3").unwrap();
141        let b = PolyOverQ::from_str("3  -1 2/7 -3").unwrap();
142        let cmp = PolyOverQ::from_str("1  8/7").unwrap();
143
144        a -= &b;
145
146        assert_eq!(cmp, a);
147    }
148
149    /// Ensure that `sub_assign` works for large numbers.
150    #[test]
151    fn correct_large() {
152        let mut a: PolyOverQ = PolyOverQ::from_str(&format!(
153            "3  {} {}/{} {}",
154            u64::MAX,
155            i64::MIN,
156            u128::MAX,
157            i64::MAX
158        ))
159        .unwrap();
160        let b = PolyOverQ::from_str(&format!("2  -{} -{}", u64::MAX, i64::MAX)).unwrap();
161        let cmp = PolyOverQ::from_str(&format!(
162            "3  {} {} {}",
163            u128::from(u64::MAX) * 2,
164            (Q::from_str(&format!("{}/{}", i64::MIN, u128::MAX)).unwrap() + Q::from(i64::MAX)),
165            i64::MAX
166        ))
167        .unwrap();
168
169        a -= b;
170
171        assert_eq!(cmp, a);
172    }
173
174    /// Ensure that `sub_assign` is available for all types.
175    #[test]
176    fn availability() {
177        let mut a = PolyOverQ::from_str("3  1 2 -3").unwrap();
178        let b = PolyOverQ::from_str("3  -1 -2 3").unwrap();
179        let c = PolyOverZ::from_str("4  2 -1 2 3").unwrap();
180
181        a -= &b;
182        a -= b;
183        a -= &c;
184        a -= c;
185    }
186}
187
188#[cfg(test)]
189mod test_sub {
190    use super::PolyOverQ;
191    use crate::rational::Q;
192    use std::str::FromStr;
193
194    /// Testing subtraction for two [`PolyOverQ`]
195    #[test]
196    fn sub() {
197        let a: PolyOverQ = PolyOverQ::from_str("3  1/9 2 -3/7").unwrap();
198        let b: PolyOverQ = PolyOverQ::from_str("5  1/8 -2/9 5/7 1 2/9").unwrap();
199        let c: PolyOverQ = a - b;
200        assert_eq!(
201            c,
202            PolyOverQ::from_str("5  -1/72 20/9 -8/7 -1 -2/9").unwrap()
203        );
204    }
205
206    /// Testing subtraction for two borrowed [`PolyOverQ`]
207    #[test]
208    fn sub_borrow() {
209        let a: PolyOverQ = PolyOverQ::from_str("3  1/9 2 -3/7").unwrap();
210        let b: PolyOverQ = PolyOverQ::from_str("5  1/8 -2/9 5/7 1 2/9").unwrap();
211        let c: PolyOverQ = &a - &b;
212        assert_eq!(
213            c,
214            PolyOverQ::from_str("5  -1/72 20/9 -8/7 -1 -2/9").unwrap()
215        );
216    }
217
218    /// Testing subtraction for borrowed [`PolyOverQ`] and [`PolyOverQ`]
219    #[test]
220    fn sub_first_borrowed() {
221        let a: PolyOverQ = PolyOverQ::from_str("3  1/9 2 -3/7").unwrap();
222        let b: PolyOverQ = PolyOverQ::from_str("5  1/8 -2/9 5/7 1 2/9").unwrap();
223        let c: PolyOverQ = &a - b;
224        assert_eq!(
225            c,
226            PolyOverQ::from_str("5  -1/72 20/9 -8/7 -1 -2/9").unwrap()
227        );
228    }
229
230    /// Testing subtraction for [`PolyOverQ`] and borrowed [`PolyOverQ`]
231    #[test]
232    fn sub_second_borrowed() {
233        let a: PolyOverQ = PolyOverQ::from_str("3  1/9 2 -3/7").unwrap();
234        let b: PolyOverQ = PolyOverQ::from_str("5  1/8 -2/9 5/7 1 2/9").unwrap();
235        let c: PolyOverQ = a - &b;
236        assert_eq!(
237            c,
238            PolyOverQ::from_str("5  -1/72 20/9 -8/7 -1 -2/9").unwrap()
239        );
240    }
241
242    /// Testing subtraction with eliminating coefficients
243    #[test]
244    fn sub_eliminating_coefficients() {
245        let a: PolyOverQ = PolyOverQ::from_str("3  1/8 2/7 -3").unwrap();
246        let b: PolyOverQ = PolyOverQ::from_str("3  1/8 2/7 -3").unwrap();
247        let c: PolyOverQ = a - b;
248        assert_eq!(c, PolyOverQ::default());
249    }
250
251    /// Testing subtraction for large [`PolyOverQ`]
252    #[test]
253    fn sub_large_numbers() {
254        let a: PolyOverQ = PolyOverQ::from_str(&format!(
255            "3  {} {}/{} {}",
256            u64::MAX,
257            i64::MIN,
258            u128::MAX - 126,
259            i64::MAX
260        ))
261        .unwrap();
262        let b: PolyOverQ = PolyOverQ::from_str(&format!("2  {} {}", u64::MAX, i64::MAX)).unwrap();
263        let c: PolyOverQ = a - b;
264
265        assert!(
266            c == PolyOverQ::from_str(&format!(
267                "3  0 {} {}",
268                (Q::from_str(&format!("{}/{}", i64::MIN, u128::MAX - 126)).unwrap()
269                    - Q::from(i64::MAX)),
270                i64::MAX
271            ))
272            .unwrap()
273        );
274    }
275}
276
277#[cfg(test)]
278mod test_mul_poly_over_z {
279    use super::PolyOverQ;
280    use crate::integer::PolyOverZ;
281    use std::str::FromStr;
282
283    /// Checks if polynomial subtraction works fine for both borrowed
284    #[test]
285    fn borrowed_correctness() {
286        let poly_1 = PolyOverQ::from_str(&format!("1  1/{}", i64::MAX)).unwrap();
287        let poly_2 = PolyOverZ::from_str("2  1 2").unwrap();
288        let poly_cmp =
289            PolyOverQ::from_str(&format!("2  {}/{} -2", -i64::MAX as i128 + 1, i64::MAX)).unwrap();
290
291        let poly_1 = &poly_1 - &poly_2;
292
293        assert_eq!(poly_cmp, poly_1);
294    }
295
296    /// Checks if subtraction works fine for different types
297    #[test]
298    fn availability() {
299        let poly = PolyOverQ::from_str("3  1/2 2 3/7").unwrap();
300        let z = PolyOverZ::from(2);
301
302        _ = poly.clone() - z.clone();
303        _ = &poly - &z;
304        _ = &poly - z.clone();
305        _ = poly.clone() - &z;
306    }
307}