qfall_math/rational/poly_over_q/arithmetic/
mul.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 [`Mul`] 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, arithmetic_trait_reverse,
17    },
18};
19use flint_sys::fmpq_poly::fmpq_poly_mul;
20use std::ops::{Mul, MulAssign};
21
22impl MulAssign<&PolyOverQ> for PolyOverQ {
23    /// Computes the multiplication of `self` and `other` reusing
24    /// the memory of `self`.
25    /// [`MulAssign`] can be used on [`PolyOverQ`] in combination with
26    /// [`PolyOverQ`] and [`PolyOverZ`].
27    ///
28    /// Parameters:
29    /// - `other`: specifies the polynomial to multiply to `self`
30    ///
31    /// Returns the product 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 mul_assign(&mut self, other: &Self) {
48        unsafe { fmpq_poly_mul(&mut self.poly, &self.poly, &other.poly) };
49    }
50}
51impl MulAssign<&PolyOverZ> for PolyOverQ {
52    /// Documentation at [`PolyOverQ::mul_assign`].
53    fn mul_assign(&mut self, other: &PolyOverZ) {
54        let other = PolyOverQ::from(other);
55
56        self.mul_assign(other);
57    }
58}
59
60arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverQ, PolyOverQ);
61arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverQ, PolyOverZ);
62
63impl Mul for &PolyOverQ {
64    type Output = PolyOverQ;
65    /// Implements the [`Mul`] trait for two [`PolyOverQ`] values.
66    /// [`Mul`] is implemented for any combination of [`PolyOverQ`] and borrowed [`PolyOverQ`].
67    ///
68    /// Parameters:
69    /// - `other`: specifies the value to multiply with `self`
70    ///
71    /// Returns the product 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/7 2/5 -3").unwrap();
79    /// let b: PolyOverQ = PolyOverQ::from_str("5  1/9 2/5 -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 mul(self, other: Self) -> Self::Output {
87        let mut out = PolyOverQ::default();
88        unsafe {
89            fmpq_poly_mul(&mut out.poly, &self.poly, &other.poly);
90        }
91        out
92    }
93}
94
95arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverQ, PolyOverQ, PolyOverQ);
96arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverQ, PolyOverQ, PolyOverQ);
97
98impl Mul<&PolyOverZ> for &PolyOverQ {
99    type Output = PolyOverQ;
100    /// Implements the [`Mul`] trait for [`PolyOverQ`] and [`PolyOverZ`].
101    /// [`Mul`] is implemented for any combination of owned and borrowed values.
102    ///
103    /// Parameters:
104    /// - `other`: specifies the polynomial to multiply to `self`
105    ///
106    /// Returns the product 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 mul(self, other: &PolyOverZ) -> Self::Output {
120        let mut out = PolyOverQ::default();
121        unsafe {
122            fmpq_poly_mul(&mut out.poly, &self.poly, &PolyOverQ::from(other).poly);
123        }
124        out
125    }
126}
127
128arithmetic_trait_reverse!(Mul, mul, PolyOverZ, PolyOverQ, PolyOverQ);
129
130arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverQ, PolyOverZ, PolyOverQ);
131arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, PolyOverQ, PolyOverQ);
132arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverQ, PolyOverZ, PolyOverQ);
133arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, PolyOverQ, PolyOverQ);
134
135#[cfg(test)]
136mod test_mul_assign {
137    use super::PolyOverQ;
138    use crate::integer::PolyOverZ;
139    use std::str::FromStr;
140
141    /// Ensure that `mul_assign` works for small numbers.
142    #[test]
143    fn correct_small() {
144        let mut a = PolyOverQ::from_str("3  1/7 2/7 -3/7").unwrap();
145        let b = PolyOverQ::from_str("5  1/11 2/11 5/11 1/11 2/11").unwrap();
146
147        a *= b;
148
149        assert_eq!(
150            a,
151            PolyOverQ::from_str("7  1/77 4/77 6/77 5/77 -11/77 1/77 -6/77").unwrap()
152        );
153    }
154
155    /// Ensure that `mul_assign` works for large numbers.
156    #[test]
157    fn correct_large() {
158        let mut a = PolyOverQ::from_str(&format!("2  {} {}", 2, i64::MIN)).unwrap();
159        let b = PolyOverQ::from_str(&format!(
160            "2  {}/{} {}/{}",
161            u32::MAX,
162            u128::MAX,
163            i64::MAX,
164            u128::MAX
165        ))
166        .unwrap();
167
168        a *= b;
169
170        assert_eq!(
171            a,
172            PolyOverQ::from_str(&format!(
173                "3  {}/{} {}/{} {}/{}",
174                2_u128 * u128::from(u32::MAX),
175                u128::MAX,
176                2_i128 * i128::from(i64::MAX) + i128::from(u32::MAX) * i128::from(i64::MIN),
177                u128::MAX,
178                i128::from(i64::MAX) * i128::from(i64::MIN),
179                u128::MAX
180            ))
181            .unwrap()
182        );
183    }
184
185    /// Ensure that `mul_assign` is available for all types.
186    #[test]
187    fn availability() {
188        let mut a = PolyOverQ::from_str("3  1 2 -3").unwrap();
189        let b = PolyOverQ::from_str("3  -1 -2 3").unwrap();
190        let c = PolyOverZ::from_str("4  2 -1 2 3").unwrap();
191
192        a *= &b;
193        a *= b;
194        a *= &c;
195        a *= c;
196    }
197}
198
199#[cfg(test)]
200mod test_mul {
201    use super::PolyOverQ;
202    use std::str::FromStr;
203
204    /// Testing multiplication for two [`PolyOverQ`]
205    #[test]
206    fn mul() {
207        let a: PolyOverQ = PolyOverQ::from_str("3  1/7 2/7 -3/7").unwrap();
208        let b: PolyOverQ = PolyOverQ::from_str("5  1/11 2/11 5/11 1/11 2/11").unwrap();
209        let c: PolyOverQ = a * b;
210        assert_eq!(
211            c,
212            PolyOverQ::from_str("7  1/77 4/77 6/77 5/77 -11/77 1/77 -6/77").unwrap()
213        );
214    }
215
216    /// Testing multiplication for two borrowed [`PolyOverQ`]
217    #[test]
218    fn mul_borrow() {
219        let a: PolyOverQ = PolyOverQ::from_str("3  1/7 2/7 -3/7").unwrap();
220        let b: PolyOverQ = PolyOverQ::from_str("5  1/11 2/11 5/11 1/11 2/11").unwrap();
221        let c: PolyOverQ = &a * &b;
222        assert_eq!(
223            c,
224            PolyOverQ::from_str("7  1/77 4/77 6/77 5/77 -11/77 1/77 -6/77").unwrap()
225        );
226    }
227
228    /// Testing multiplication for borrowed [`PolyOverQ`] and [`PolyOverQ`]
229    #[test]
230    fn mul_first_borrowed() {
231        let a: PolyOverQ = PolyOverQ::from_str("3  1/7 2/7 -3/7").unwrap();
232        let b: PolyOverQ = PolyOverQ::from_str("5  1/11 2/11 5/11 1/11 2/11").unwrap();
233        let c: PolyOverQ = &a * b;
234        assert_eq!(
235            c,
236            PolyOverQ::from_str("7  1/77 4/77 6/77 5/77 -11/77 1/77 -6/77").unwrap()
237        );
238    }
239
240    /// Testing multiplication for [`PolyOverQ`] and borrowed [`PolyOverQ`]
241    #[test]
242    fn mul_second_borrowed() {
243        let a: PolyOverQ = PolyOverQ::from_str("3  1/7 2/7 -3/7").unwrap();
244        let b: PolyOverQ = PolyOverQ::from_str("5  1/11 2/11 5/11 1/11 2/11").unwrap();
245        let c: PolyOverQ = a * &b;
246        assert_eq!(
247            c,
248            PolyOverQ::from_str("7  1/77 4/77 6/77 5/77 -11/77 1/77 -6/77").unwrap()
249        );
250    }
251
252    /// Testing multiplication with a constant [`PolyOverQ`]
253    #[test]
254    fn mul_constant() {
255        let a: PolyOverQ = PolyOverQ::from_str("3  1/11 1/2 -7/3").unwrap();
256        let b: PolyOverQ = PolyOverQ::from_str("1  4/7").unwrap();
257        let c: PolyOverQ = a * b;
258        assert_eq!(c, PolyOverQ::from_str("3  4/77 2/7 -4/3").unwrap());
259    }
260
261    /// Testing multiplication with `0`
262    #[test]
263    fn mul_zero() {
264        let a: PolyOverQ = PolyOverQ::from_str("3  1/18 2/7 -3/10").unwrap();
265        let b: PolyOverQ = PolyOverQ::default();
266        let c: PolyOverQ = a * b;
267        assert_eq!(c, PolyOverQ::default());
268    }
269
270    /// Testing multiplication for large [`PolyOverQ`]
271    #[test]
272    fn mul_large_numbers() {
273        let a: PolyOverQ = PolyOverQ::from_str(&format!("2  {} {}", 2, i64::MIN)).unwrap();
274        let b: PolyOverQ = PolyOverQ::from_str(&format!(
275            "2  {}/{} {}/{}",
276            u32::MAX,
277            u128::MAX,
278            i64::MAX,
279            u128::MAX
280        ))
281        .unwrap();
282        let c: PolyOverQ = a * b;
283
284        assert_eq!(
285            c,
286            PolyOverQ::from_str(&format!(
287                "3  {}/{} {}/{} {}/{}",
288                2_u128 * u128::from(u32::MAX),
289                u128::MAX,
290                2_i128 * i128::from(i64::MAX) + i128::from(u32::MAX) * i128::from(i64::MIN),
291                u128::MAX,
292                i128::from(i64::MAX) * i128::from(i64::MIN),
293                u128::MAX
294            ))
295            .unwrap()
296        );
297    }
298}
299
300#[cfg(test)]
301mod test_mul_poly_over_z {
302    use super::PolyOverQ;
303    use crate::integer::PolyOverZ;
304    use std::str::FromStr;
305
306    /// Checks if polynomial multiplication works fine for both borrowed
307    #[test]
308    fn borrowed_correctness() {
309        let poly_1 = PolyOverQ::from_str(&format!("1  1/{}", i64::MAX)).unwrap();
310        let poly_2 = PolyOverZ::from_str("2  1 2").unwrap();
311        let poly_cmp = PolyOverQ::from_str(&format!("2  1/{} 2/{}", i64::MAX, i64::MAX)).unwrap();
312
313        let poly_1 = &poly_1 * &poly_2;
314
315        assert_eq!(poly_cmp, poly_1);
316    }
317
318    /// Checks if multiplication works fine for different types
319    #[test]
320    fn availability() {
321        let poly = PolyOverQ::from_str("3  1/2 2 3/7").unwrap();
322        let z = PolyOverZ::from(2);
323
324        _ = poly.clone() * z.clone();
325        _ = z.clone() * poly.clone();
326        _ = &poly * &z;
327        _ = &z * &poly;
328        _ = &poly * z.clone();
329        _ = z.clone() * &poly;
330        _ = &z * poly.clone();
331        _ = poly.clone() * &z;
332    }
333}