Skip to main content

malachite_base/unsigned_vector/arithmetic/
mod_sub_mul.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{ModIsReduced, ModSubMul, ModSubMulAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13fn assert_reduced<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, w: &UnsignedVector<T>, c: T, m: T) {
14    assert_eq!(
15        v.elements.len(),
16        w.elements.len(),
17        "cannot sub-multiply vectors of different dimensions"
18    );
19    assert!(
20        v.mod_is_reduced(&m),
21        "self must be reduced mod m, but {v} has an element >= {m}"
22    );
23    assert!(
24        w.mod_is_reduced(&m),
25        "w must be reduced mod m, but {w} has an element >= {m}"
26    );
27    assert!(
28        c.mod_is_reduced(&m),
29        "c must be reduced mod m, but {c} >= {m}"
30    );
31}
32
33// Subtracts `ys` times `c` from `xs` modulo `m`, in place, for inputs already known to be reduced.
34// Like FLINT, this handles `c` equal to 0, 1, and `m - 1` directly, and otherwise computes the data
35// for multiplying modulo `m` once and reuses it for every element.
36fn mod_sub_mul_assign_unchecked<T: PrimitiveUnsigned>(xs: &mut [T], ys: &[T], c: T, m: T) {
37    if c == T::ZERO {
38        return;
39    }
40    if c == T::ONE {
41        for (x, &y) in xs.iter_mut().zip(ys) {
42            x.mod_sub_assign(y, m);
43        }
44    } else if c == m - T::ONE {
45        for (x, &y) in xs.iter_mut().zip(ys) {
46            x.mod_add_assign(y, m);
47        }
48    } else {
49        let data = T::precompute_mod_mul_data(&m);
50        for (x, &y) in xs.iter_mut().zip(ys) {
51            x.mod_sub_assign(y.mod_mul_precomputed(c, m, &data), m);
52        }
53    }
54}
55
56impl<T: PrimitiveUnsigned> ModSubMul<Self, T, T> for UnsignedVector<T> {
57    type Output = Self;
58
59    /// Subtracts a scalar multiple of an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$,
60    /// taking both vectors by value. The elements and the scalar must already be reduced modulo
61    /// $m$.
62    ///
63    /// The operation is taken element by element, so the result has the same dimension as the
64    /// vectors.
65    ///
66    /// $$
67    /// f(v, w, c, m) = (v - cw) \bmod m.
68    /// $$
69    ///
70    /// # Worst-case complexity
71    /// $T(n) = O(n)$
72    ///
73    /// $M(n) = O(1)$
74    ///
75    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
76    ///
77    /// # Panics
78    /// Panics if `self` and `w` have different dimensions, or if any element of `self` or `w`, or
79    /// `c`, is greater than or equal to `m`.
80    ///
81    /// # Examples
82    /// ```
83    /// use core::str::FromStr;
84    /// use malachite_base::num::arithmetic::traits::ModSubMul;
85    /// use malachite_base::unsigned_vector::UnsignedVector;
86    ///
87    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
88    /// let w = UnsignedVector::<u8>::from_str("(2, 6, 4)").unwrap();
89    /// assert_eq!(v.mod_sub_mul(w, 3, 7).to_string(), "(6, 4, 5)");
90    /// ```
91    #[inline]
92    fn mod_sub_mul(mut self, w: Self, c: T, m: T) -> Self {
93        self.mod_sub_mul_assign(&w, c, m);
94        self
95    }
96}
97
98impl<T: PrimitiveUnsigned> ModSubMul<&Self, T, T> for UnsignedVector<T> {
99    type Output = Self;
100
101    /// Subtracts a scalar multiple of an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$,
102    /// taking the first vector by value and the second by reference. The elements and the scalar
103    /// must already be reduced modulo $m$.
104    ///
105    /// See the documentation for the [`ModSubMul`] implementation that takes both vectors by value
106    /// for details.
107    ///
108    /// # Worst-case complexity
109    /// $T(n) = O(n)$
110    ///
111    /// $M(n) = O(1)$
112    ///
113    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
114    ///
115    /// # Panics
116    /// Panics if `self` and `w` have different dimensions, or if any element of `self` or `w`, or
117    /// `c`, is greater than or equal to `m`.
118    ///
119    /// # Examples
120    /// ```
121    /// use core::str::FromStr;
122    /// use malachite_base::num::arithmetic::traits::ModSubMul;
123    /// use malachite_base::unsigned_vector::UnsignedVector;
124    ///
125    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
126    /// let w = UnsignedVector::<u8>::from_str("(2, 6, 4)").unwrap();
127    /// assert_eq!(v.mod_sub_mul(&w, 3, 7).to_string(), "(6, 4, 5)");
128    /// ```
129    #[inline]
130    fn mod_sub_mul(mut self, w: &Self, c: T, m: T) -> Self {
131        self.mod_sub_mul_assign(w, c, m);
132        self
133    }
134}
135
136impl<T: PrimitiveUnsigned> ModSubMul<&UnsignedVector<T>, T, T> for &UnsignedVector<T> {
137    type Output = UnsignedVector<T>;
138
139    /// Subtracts a scalar multiple of an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$,
140    /// taking both vectors by reference. The elements and the scalar must already be reduced modulo
141    /// $m$.
142    ///
143    /// See the documentation for the [`ModSubMul`] implementation that takes both vectors by value
144    /// for details.
145    ///
146    /// # Worst-case complexity
147    /// $T(n) = O(n)$
148    ///
149    /// $M(n) = O(n)$
150    ///
151    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
152    ///
153    /// # Panics
154    /// Panics if `self` and `w` have different dimensions, or if any element of `self` or `w`, or
155    /// `c`, is greater than or equal to `m`.
156    ///
157    /// # Examples
158    /// ```
159    /// use core::str::FromStr;
160    /// use malachite_base::num::arithmetic::traits::ModSubMul;
161    /// use malachite_base::unsigned_vector::UnsignedVector;
162    ///
163    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
164    /// let w = UnsignedVector::<u8>::from_str("(2, 6, 4)").unwrap();
165    /// assert_eq!((&v).mod_sub_mul(&w, 3, 7).to_string(), "(6, 4, 5)");
166    /// ```
167    fn mod_sub_mul(self, w: &UnsignedVector<T>, c: T, m: T) -> UnsignedVector<T> {
168        assert_reduced(self, w, c, m);
169        let mut elements = self.elements.clone();
170        mod_sub_mul_assign_unchecked(&mut elements, &w.elements, c, m);
171        UnsignedVector { elements }
172    }
173}
174
175impl<T: PrimitiveUnsigned> ModSubMulAssign<Self, T, T> for UnsignedVector<T> {
176    /// Subtracts a scalar multiple of an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$,
177    /// in place, taking the vector on the right-hand side by value. The elements and the scalar
178    /// must already be reduced modulo $m$.
179    ///
180    /// See the documentation for the [`ModSubMul`] implementation that takes both vectors by value
181    /// for details.
182    ///
183    /// # Worst-case complexity
184    /// $T(n) = O(n)$
185    ///
186    /// $M(n) = O(1)$
187    ///
188    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
189    ///
190    /// # Panics
191    /// Panics if `self` and `w` have different dimensions, or if any element of `self` or `w`, or
192    /// `c`, is greater than or equal to `m`.
193    ///
194    /// # Examples
195    /// ```
196    /// use core::str::FromStr;
197    /// use malachite_base::num::arithmetic::traits::ModSubMulAssign;
198    /// use malachite_base::unsigned_vector::UnsignedVector;
199    ///
200    /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
201    /// let w = UnsignedVector::<u8>::from_str("(2, 6, 4)").unwrap();
202    /// v.mod_sub_mul_assign(w, 3, 7);
203    /// assert_eq!(v.to_string(), "(6, 4, 5)");
204    /// ```
205    #[inline]
206    fn mod_sub_mul_assign(&mut self, w: Self, c: T, m: T) {
207        self.mod_sub_mul_assign(&w, c, m);
208    }
209}
210
211impl<T: PrimitiveUnsigned> ModSubMulAssign<&Self, T, T> for UnsignedVector<T> {
212    /// Subtracts a scalar multiple of an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$,
213    /// in place, taking the vector on the right-hand side by reference. The elements and the scalar
214    /// must already be reduced modulo $m$.
215    ///
216    /// See the documentation for the [`ModSubMul`] implementation that takes both vectors by value
217    /// for details.
218    ///
219    /// # Worst-case complexity
220    /// $T(n) = O(n)$
221    ///
222    /// $M(n) = O(1)$
223    ///
224    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
225    ///
226    /// # Panics
227    /// Panics if `self` and `w` have different dimensions, or if any element of `self` or `w`, or
228    /// `c`, is greater than or equal to `m`.
229    ///
230    /// # Examples
231    /// ```
232    /// use core::str::FromStr;
233    /// use malachite_base::num::arithmetic::traits::ModSubMulAssign;
234    /// use malachite_base::unsigned_vector::UnsignedVector;
235    ///
236    /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
237    /// let w = UnsignedVector::<u8>::from_str("(2, 6, 4)").unwrap();
238    /// v.mod_sub_mul_assign(&w, 3, 7);
239    /// assert_eq!(v.to_string(), "(6, 4, 5)");
240    /// ```
241    fn mod_sub_mul_assign(&mut self, w: &Self, c: T, m: T) {
242        assert_reduced(self, w, c, m);
243        mod_sub_mul_assign_unchecked(&mut self.elements, &w.elements, c, m);
244    }
245}