Skip to main content

malachite_base/unsigned_vector/arithmetic/
mod_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, ModMul, ModMulAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12use alloc::vec::Vec;
13
14fn assert_reduced<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, c: T, m: T) {
15    assert!(
16        v.mod_is_reduced(&m),
17        "self must be reduced mod m, but {v} has an element >= {m}"
18    );
19    assert!(
20        c.mod_is_reduced(&m),
21        "c must be reduced mod m, but {c} >= {m}"
22    );
23}
24
25// Multiplies every element by `c` modulo `m`, which the elements and `c` are already reduced
26// modulo. The data for multiplying modulo `m` is computed once and shared by all the elements.
27pub(crate) fn mod_mul_assign_unchecked<T: PrimitiveUnsigned>(xs: &mut [T], c: T, m: T) {
28    let data = T::precompute_mod_mul_data(&m);
29    for x in xs {
30        x.mod_mul_precomputed_assign(c, m, &data);
31    }
32}
33
34// The elements multiplied by `c` modulo `m`, as `mod_mul_assign_unchecked` computes them.
35pub(crate) fn mod_mul_unchecked<T: PrimitiveUnsigned>(xs: &[T], c: T, m: T) -> Vec<T> {
36    let data = T::precompute_mod_mul_data(&m);
37    xs.iter()
38        .map(|&x| x.mod_mul_precomputed(c, m, &data))
39        .collect()
40}
41
42impl<T: PrimitiveUnsigned> ModMul<T, T> for UnsignedVector<T> {
43    type Output = Self;
44
45    /// Multiplies every element of an [`UnsignedVector`] by a scalar modulo $m$, taking the vector
46    /// by value. The elements and the scalar must already be reduced modulo $m$.
47    ///
48    /// Each product is reduced modulo $m$, and the result has the same dimension as the vector. The
49    /// data for multiplying modulo $m$ is precomputed once and shared by all the elements.
50    ///
51    /// $$
52    /// f(v, c, m) = cv \bmod m.
53    /// $$
54    ///
55    /// # Worst-case complexity
56    /// $T(n) = O(n)$
57    ///
58    /// $M(n) = O(1)$
59    ///
60    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
61    ///
62    /// # Panics
63    /// Panics if `m` is zero, or if any element of `self`, or `c`, is greater than or equal to `m`.
64    ///
65    /// # Examples
66    /// ```
67    /// use core::str::FromStr;
68    /// use malachite_base::num::arithmetic::traits::ModMul;
69    /// use malachite_base::unsigned_vector::UnsignedVector;
70    ///
71    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
72    /// assert_eq!(v.mod_mul(3, 7).to_string(), "(1, 3, 2)");
73    /// ```
74    #[inline]
75    fn mod_mul(mut self, c: T, m: T) -> Self {
76        self.mod_mul_assign(c, m);
77        self
78    }
79}
80
81impl<T: PrimitiveUnsigned> ModMul<T, T> for &UnsignedVector<T> {
82    type Output = UnsignedVector<T>;
83
84    /// Multiplies every element of an [`UnsignedVector`] by a scalar modulo $m$, taking the vector
85    /// by reference. The elements and the scalar must already be reduced modulo $m$.
86    ///
87    /// See the documentation for the [`ModMul`] implementation that takes the vector by value for
88    /// details.
89    ///
90    /// # Worst-case complexity
91    /// $T(n) = O(n)$
92    ///
93    /// $M(n) = O(n)$
94    ///
95    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
96    ///
97    /// # Panics
98    /// Panics if `m` is zero, or if any element of `self`, or `c`, is greater than or equal to `m`.
99    ///
100    /// # Examples
101    /// ```
102    /// use core::str::FromStr;
103    /// use malachite_base::num::arithmetic::traits::ModMul;
104    /// use malachite_base::unsigned_vector::UnsignedVector;
105    ///
106    /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
107    /// assert_eq!((&v).mod_mul(3, 7).to_string(), "(1, 3, 2)");
108    /// ```
109    fn mod_mul(self, c: T, m: T) -> UnsignedVector<T> {
110        assert_reduced(self, c, m);
111        UnsignedVector {
112            elements: mod_mul_unchecked(&self.elements, c, m),
113        }
114    }
115}
116
117impl<T: PrimitiveUnsigned> ModMulAssign<T, T> for UnsignedVector<T> {
118    /// Multiplies every element of an [`UnsignedVector`] by a scalar modulo $m$, in place. The
119    /// elements and the scalar must already be reduced modulo $m$.
120    ///
121    /// See the documentation for the [`ModMul`] implementation that takes the vector by value for
122    /// details.
123    ///
124    /// # Worst-case complexity
125    /// $T(n) = O(n)$
126    ///
127    /// $M(n) = O(1)$
128    ///
129    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
130    ///
131    /// # Panics
132    /// Panics if `m` is zero, or if any element of `self`, or `c`, is greater than or equal to `m`.
133    ///
134    /// # Examples
135    /// ```
136    /// use core::str::FromStr;
137    /// use malachite_base::num::arithmetic::traits::ModMulAssign;
138    /// use malachite_base::unsigned_vector::UnsignedVector;
139    ///
140    /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
141    /// v.mod_mul_assign(3, 7);
142    /// assert_eq!(v.to_string(), "(1, 3, 2)");
143    /// ```
144    fn mod_mul_assign(&mut self, c: T, m: T) {
145        assert_reduced(self, c, m);
146        mod_mul_assign_unchecked(&mut self.elements, c, m);
147    }
148}