qfall_math/rational/poly_over_q/arithmetic/
mul_scalar.rs

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