Skip to main content

malachite_base/unsigned_vector/arithmetic/
mod_power_of_2_dot.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::{ModPowerOf2Dot, ModPowerOf2IsReduced};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13// The dot product of two vectors modulo $2^k$, which is the wrapping sum of the wrapping products
14// with all but the lowest $k$ bits cleared, since $2^k$ divides $2^W$.
15fn mod_power_of_2_dot<T: PrimitiveUnsigned>(
16    v: &UnsignedVector<T>,
17    w: &UnsignedVector<T>,
18    pow: u64,
19) -> T {
20    assert!(
21        pow <= T::WIDTH,
22        "pow must be at most {}, but is {pow}",
23        T::WIDTH
24    );
25    assert_eq!(
26        v.elements.len(),
27        w.elements.len(),
28        "the vectors must have the same dimension"
29    );
30    assert!(
31        v.mod_power_of_2_is_reduced(pow),
32        "self must be reduced mod 2^{pow}, but {v} has an element >= 2^{pow}"
33    );
34    assert!(
35        w.mod_power_of_2_is_reduced(pow),
36        "other must be reduced mod 2^{pow}, but {w} has an element >= 2^{pow}"
37    );
38    let mut sum = T::ZERO;
39    for (&x, &y) in v.elements.iter().zip(&w.elements) {
40        sum.wrapping_add_assign(x.wrapping_mul(y));
41    }
42    sum.mod_power_of_2(pow)
43}
44
45impl<T: PrimitiveUnsigned> ModPowerOf2Dot<Self> for UnsignedVector<T> {
46    type Output = T;
47
48    /// Computes the dot product of two [`UnsignedVector`]s modulo $2^k$, taking the first by value
49    /// and the second by value. The elements of both must already be reduced.
50    ///
51    /// The dot product of two 0-dimensional vectors is 0.
52    ///
53    /// $$
54    /// f(v, w, k) = \sum_{i=0}^{n-1} v_iw_i \bmod 2^k,
55    /// $$
56    ///
57    /// where $n$ is the dimension of $v$ and $w$.
58    ///
59    /// # Worst-case complexity
60    /// $T(n) = O(n)$
61    ///
62    /// $M(n) = O(1)$
63    ///
64    /// where $T$ is time, $M$ is additional memory, and $n$ is the dimension of the vectors.
65    ///
66    /// # Panics
67    /// Panics if `pow` is greater than `T::WIDTH`, if the vectors have different dimensions, or if
68    /// any element is greater than or equal to $2^k$.
69    ///
70    /// # Examples
71    /// ```
72    /// use core::str::FromStr;
73    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Dot;
74    /// use malachite_base::unsigned_vector::UnsignedVector;
75    ///
76    /// let v = UnsignedVector::<u8>::from_str("(1, 2, 3)").unwrap();
77    /// let w = UnsignedVector::<u8>::from_str("(4, 5, 7)").unwrap();
78    /// assert_eq!(v.clone().mod_power_of_2_dot(w.clone(), 4), 3);
79    /// ```
80    #[inline]
81    fn mod_power_of_2_dot(self, other: Self, pow: u64) -> T {
82        mod_power_of_2_dot(&self, &other, pow)
83    }
84}
85
86impl<T: PrimitiveUnsigned> ModPowerOf2Dot<&Self> for UnsignedVector<T> {
87    type Output = T;
88
89    /// Computes the dot product of two [`UnsignedVector`]s modulo $2^k$, taking the first by value
90    /// and the second by reference. The elements of both must already be reduced.
91    ///
92    /// The dot product of two 0-dimensional vectors is 0.
93    ///
94    /// $$
95    /// f(v, w, k) = \sum_{i=0}^{n-1} v_iw_i \bmod 2^k,
96    /// $$
97    ///
98    /// where $n$ is the dimension of $v$ and $w$.
99    ///
100    /// # Worst-case complexity
101    /// $T(n) = O(n)$
102    ///
103    /// $M(n) = O(1)$
104    ///
105    /// where $T$ is time, $M$ is additional memory, and $n$ is the dimension of the vectors.
106    ///
107    /// # Panics
108    /// Panics if `pow` is greater than `T::WIDTH`, if the vectors have different dimensions, or if
109    /// any element is greater than or equal to $2^k$.
110    ///
111    /// # Examples
112    /// ```
113    /// use core::str::FromStr;
114    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Dot;
115    /// use malachite_base::unsigned_vector::UnsignedVector;
116    ///
117    /// let v = UnsignedVector::<u8>::from_str("(1, 2, 3)").unwrap();
118    /// let w = UnsignedVector::<u8>::from_str("(4, 5, 7)").unwrap();
119    /// assert_eq!(v.clone().mod_power_of_2_dot(&w, 4), 3);
120    /// ```
121    #[inline]
122    fn mod_power_of_2_dot(self, other: &Self, pow: u64) -> T {
123        mod_power_of_2_dot(&self, other, pow)
124    }
125}
126
127impl<T: PrimitiveUnsigned> ModPowerOf2Dot<UnsignedVector<T>> for &UnsignedVector<T> {
128    type Output = T;
129
130    /// Computes the dot product of two [`UnsignedVector`]s modulo $2^k$, taking the first by
131    /// reference and the second by value. The elements of both must already be reduced.
132    ///
133    /// The dot product of two 0-dimensional vectors is 0.
134    ///
135    /// $$
136    /// f(v, w, k) = \sum_{i=0}^{n-1} v_iw_i \bmod 2^k,
137    /// $$
138    ///
139    /// where $n$ is the dimension of $v$ and $w$.
140    ///
141    /// # Worst-case complexity
142    /// $T(n) = O(n)$
143    ///
144    /// $M(n) = O(1)$
145    ///
146    /// where $T$ is time, $M$ is additional memory, and $n$ is the dimension of the vectors.
147    ///
148    /// # Panics
149    /// Panics if `pow` is greater than `T::WIDTH`, if the vectors have different dimensions, or if
150    /// any element is greater than or equal to $2^k$.
151    ///
152    /// # Examples
153    /// ```
154    /// use core::str::FromStr;
155    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Dot;
156    /// use malachite_base::unsigned_vector::UnsignedVector;
157    ///
158    /// let v = UnsignedVector::<u8>::from_str("(1, 2, 3)").unwrap();
159    /// let w = UnsignedVector::<u8>::from_str("(4, 5, 7)").unwrap();
160    /// assert_eq!((&v).mod_power_of_2_dot(w.clone(), 4), 3);
161    /// ```
162    #[inline]
163    fn mod_power_of_2_dot(self, other: UnsignedVector<T>, pow: u64) -> T {
164        mod_power_of_2_dot(self, &other, pow)
165    }
166}
167
168impl<T: PrimitiveUnsigned> ModPowerOf2Dot<&UnsignedVector<T>> for &UnsignedVector<T> {
169    type Output = T;
170
171    /// Computes the dot product of two [`UnsignedVector`]s modulo $2^k$, taking the first by
172    /// reference and the second by reference. The elements of both must already be reduced.
173    ///
174    /// The dot product of two 0-dimensional vectors is 0.
175    ///
176    /// $$
177    /// f(v, w, k) = \sum_{i=0}^{n-1} v_iw_i \bmod 2^k,
178    /// $$
179    ///
180    /// where $n$ is the dimension of $v$ and $w$.
181    ///
182    /// # Worst-case complexity
183    /// $T(n) = O(n)$
184    ///
185    /// $M(n) = O(1)$
186    ///
187    /// where $T$ is time, $M$ is additional memory, and $n$ is the dimension of the vectors.
188    ///
189    /// # Panics
190    /// Panics if `pow` is greater than `T::WIDTH`, if the vectors have different dimensions, or if
191    /// any element is greater than or equal to $2^k$.
192    ///
193    /// # Examples
194    /// ```
195    /// use core::str::FromStr;
196    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Dot;
197    /// use malachite_base::unsigned_vector::UnsignedVector;
198    ///
199    /// let v = UnsignedVector::<u8>::from_str("(1, 2, 3)").unwrap();
200    /// let w = UnsignedVector::<u8>::from_str("(4, 5, 7)").unwrap();
201    /// assert_eq!((&v).mod_power_of_2_dot(&w, 4), 3);
202    /// ```
203    #[inline]
204    fn mod_power_of_2_dot(self, other: &UnsignedVector<T>, pow: u64) -> T {
205        mod_power_of_2_dot(self, other, pow)
206    }
207}