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}