Skip to main content

malachite_base/unsigned_vector/arithmetic/
mod_sub.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, ModSub, ModSubAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13// Subtracts each element of `ys` from the element of `xs` at the same index, modulo `m`.
14pub(crate) fn mod_sub_assign_slice<T: PrimitiveUnsigned>(xs: &mut [T], ys: &[T], m: T) {
15    for (x, &y) in xs.iter_mut().zip(ys) {
16        *x = x.mod_sub(y, m);
17    }
18}
19
20fn assert_reduced<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, w: &UnsignedVector<T>, m: T) {
21    assert_eq!(
22        v.elements.len(),
23        w.elements.len(),
24        "cannot subtract vectors of different dimensions"
25    );
26    assert!(
27        v.mod_is_reduced(&m),
28        "self must be reduced mod m, but {v} has an element >= {m}"
29    );
30    assert!(
31        w.mod_is_reduced(&m),
32        "other must be reduced mod m, but {w} has an element >= {m}"
33    );
34}
35
36fn mod_sub_assign<T: PrimitiveUnsigned>(v: &mut UnsignedVector<T>, w: &UnsignedVector<T>, m: T) {
37    assert_reduced(v, w, m);
38    mod_sub_assign_slice(&mut v.elements, &w.elements, m);
39}
40
41fn mod_sub_ref_val<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, w: &mut UnsignedVector<T>, m: T) {
42    assert_reduced(v, w, m);
43    for (x, &y) in w.elements.iter_mut().zip(&v.elements) {
44        *x = y.mod_sub(*x, m);
45    }
46}
47
48impl<T: PrimitiveUnsigned> ModSub<Self, T> for UnsignedVector<T> {
49    type Output = Self;
50
51    /// Subtracts two [`UnsignedVector`]s modulo $m$, taking the first by value and the second by
52    /// value. The elements of both must already be reduced modulo $m$.
53    ///
54    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
55    /// same dimension as the operands.
56    ///
57    /// $$
58    /// f(v, w, m) = v - w \bmod m.
59    /// $$
60    ///
61    /// # Worst-case complexity
62    /// $T(n) = O(n)$
63    ///
64    /// $M(n) = O(1)$
65    ///
66    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
67    ///
68    /// # Panics
69    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
70    /// either is greater than or equal to `m`.
71    ///
72    /// # Examples
73    /// ```
74    /// use core::str::FromStr;
75    /// use malachite_base::num::arithmetic::traits::ModSub;
76    /// use malachite_base::unsigned_vector::UnsignedVector;
77    ///
78    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
79    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
80    /// assert_eq!(v.mod_sub(w, 8).to_string(), "(1, 2, 3)");
81    /// ```
82    ///
83    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
84    #[inline]
85    fn mod_sub(mut self, other: Self, m: T) -> Self {
86        mod_sub_assign(&mut self, &other, m);
87        self
88    }
89}
90
91impl<T: PrimitiveUnsigned> ModSub<&Self, T> for UnsignedVector<T> {
92    type Output = Self;
93
94    /// Subtracts two [`UnsignedVector`]s modulo $m$, taking the first by value and the second by
95    /// reference. The elements of both must already be reduced modulo $m$.
96    ///
97    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
98    /// same dimension as the operands.
99    ///
100    /// $$
101    /// f(v, w, m) = v - w \bmod m.
102    /// $$
103    ///
104    /// # Worst-case complexity
105    /// $T(n) = O(n)$
106    ///
107    /// $M(n) = O(1)$
108    ///
109    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
110    ///
111    /// # Panics
112    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
113    /// either is greater than or equal to `m`.
114    ///
115    /// # Examples
116    /// ```
117    /// use core::str::FromStr;
118    /// use malachite_base::num::arithmetic::traits::ModSub;
119    /// use malachite_base::unsigned_vector::UnsignedVector;
120    ///
121    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
122    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
123    /// assert_eq!(v.mod_sub(&w, 8).to_string(), "(1, 2, 3)");
124    /// ```
125    ///
126    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
127    #[inline]
128    fn mod_sub(mut self, other: &Self, m: T) -> Self {
129        mod_sub_assign(&mut self, other, m);
130        self
131    }
132}
133
134impl<T: PrimitiveUnsigned> ModSub<UnsignedVector<T>, T> for &UnsignedVector<T> {
135    type Output = UnsignedVector<T>;
136
137    /// Subtracts two [`UnsignedVector`]s modulo $m$, taking the first by reference and the second
138    /// by value. The elements of both must already be reduced modulo $m$.
139    ///
140    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
141    /// same dimension as the operands.
142    ///
143    /// $$
144    /// f(v, w, m) = v - w \bmod m.
145    /// $$
146    ///
147    /// # Worst-case complexity
148    /// $T(n) = O(n)$
149    ///
150    /// $M(n) = O(1)$
151    ///
152    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
153    ///
154    /// # Panics
155    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
156    /// either is greater than or equal to `m`.
157    ///
158    /// # Examples
159    /// ```
160    /// use core::str::FromStr;
161    /// use malachite_base::num::arithmetic::traits::ModSub;
162    /// use malachite_base::unsigned_vector::UnsignedVector;
163    ///
164    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
165    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
166    /// assert_eq!((&v).mod_sub(w, 8).to_string(), "(1, 2, 3)");
167    /// ```
168    ///
169    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
170    #[inline]
171    fn mod_sub(self, mut other: UnsignedVector<T>, m: T) -> UnsignedVector<T> {
172        mod_sub_ref_val(self, &mut other, m);
173        other
174    }
175}
176
177impl<T: PrimitiveUnsigned> ModSub<&UnsignedVector<T>, T> for &UnsignedVector<T> {
178    type Output = UnsignedVector<T>;
179
180    /// Subtracts two [`UnsignedVector`]s modulo $m$, taking the first by reference and the second
181    /// by reference. The elements of both must already be reduced modulo $m$.
182    ///
183    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
184    /// same dimension as the operands.
185    ///
186    /// $$
187    /// f(v, w, m) = v - w \bmod m.
188    /// $$
189    ///
190    /// # Worst-case complexity
191    /// $T(n) = O(n)$
192    ///
193    /// $M(n) = O(n)$
194    ///
195    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
196    ///
197    /// # Panics
198    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
199    /// either is greater than or equal to `m`.
200    ///
201    /// # Examples
202    /// ```
203    /// use core::str::FromStr;
204    /// use malachite_base::num::arithmetic::traits::ModSub;
205    /// use malachite_base::unsigned_vector::UnsignedVector;
206    ///
207    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
208    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
209    /// assert_eq!((&v).mod_sub(&w, 8).to_string(), "(1, 2, 3)");
210    /// ```
211    ///
212    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
213    #[inline]
214    fn mod_sub(self, other: &UnsignedVector<T>, m: T) -> UnsignedVector<T> {
215        let mut v = self.clone();
216        mod_sub_assign(&mut v, other, m);
217        v
218    }
219}
220
221impl<T: PrimitiveUnsigned> ModSubAssign<Self, T> for UnsignedVector<T> {
222    /// Subtracts an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$, in place, taking the
223    /// [`UnsignedVector`] on the right-hand side by value. The elements of both must already be
224    /// reduced modulo $m$.
225    ///
226    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
227    /// same dimension as the operands.
228    ///
229    /// $$
230    /// f(v, w, m) = v - w \bmod m.
231    /// $$
232    ///
233    /// # Worst-case complexity
234    /// $T(n) = O(n)$
235    ///
236    /// $M(n) = O(1)$
237    ///
238    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
239    ///
240    /// # Panics
241    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
242    /// either is greater than or equal to `m`.
243    ///
244    /// # Examples
245    /// ```
246    /// use core::str::FromStr;
247    /// use malachite_base::num::arithmetic::traits::ModSubAssign;
248    /// use malachite_base::unsigned_vector::UnsignedVector;
249    ///
250    /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
251    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
252    /// v.mod_sub_assign(w, 8);
253    /// assert_eq!(v.to_string(), "(1, 2, 3)");
254    /// ```
255    ///
256    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
257    #[inline]
258    fn mod_sub_assign(&mut self, other: Self, m: T) {
259        mod_sub_assign(self, &other, m);
260    }
261}
262
263impl<T: PrimitiveUnsigned> ModSubAssign<&Self, T> for UnsignedVector<T> {
264    /// Subtracts an [`UnsignedVector`] from an [`UnsignedVector`] modulo $m$, in place, taking the
265    /// [`UnsignedVector`] on the right-hand side by reference. The elements of both must already be
266    /// reduced modulo $m$.
267    ///
268    /// The difference is taken element by element, each reduced modulo $m$, so the result has the
269    /// same dimension as the operands.
270    ///
271    /// $$
272    /// f(v, w, m) = v - w \bmod m.
273    /// $$
274    ///
275    /// # Worst-case complexity
276    /// $T(n) = O(n)$
277    ///
278    /// $M(n) = O(1)$
279    ///
280    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
281    ///
282    /// # Panics
283    /// Panics if `m` is zero, if `self` and `other` have different dimensions, or if any element of
284    /// either is greater than or equal to `m`.
285    ///
286    /// # Examples
287    /// ```
288    /// use core::str::FromStr;
289    /// use malachite_base::num::arithmetic::traits::ModSubAssign;
290    /// use malachite_base::unsigned_vector::UnsignedVector;
291    ///
292    /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
293    /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
294    /// v.mod_sub_assign(&w, 8);
295    /// assert_eq!(v.to_string(), "(1, 2, 3)");
296    /// ```
297    ///
298    /// This is equivalent to `_nmod_vec_sub` from `nmod_vec/sub.c`, FLINT 3.6.0.
299    #[inline]
300    fn mod_sub_assign(&mut self, other: &Self, m: T) {
301        mod_sub_assign(self, other, m);
302    }
303}