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}