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