qfall_math/rational/poly_over_q/arithmetic/
div_scalar.rs

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