Skip to main content

malachite_nz/integer_vector/arithmetic/
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::integer::Integer;
10use crate::integer_vector::IntegerVector;
11use crate::integer_vector::arithmetic::dot_general::vec_dot_general;
12use malachite_base::num::arithmetic::traits::Dot;
13
14impl Dot<Self> for IntegerVector {
15    type Output = Integer;
16
17    /// Computes the dot product of two [`IntegerVector`]s, taking the first by value and the second
18    /// by value.
19    ///
20    /// The dot product is the sum of the products of corresponding elements, and is 0 for two
21    /// 0-dimensional vectors.
22    ///
23    /// $$
24    /// f(v, w) = \sum_{i=0}^{n-1} v_iw_i,
25    /// $$
26    ///
27    /// where $n$ is the dimension of $v$ and $w$.
28    ///
29    /// # Worst-case complexity
30    /// $T(n, m) = O(nm \log m \log\log m)$
31    ///
32    /// $M(m) = O(m \log m)$
33    ///
34    /// where $T$ is time, $M$ is additional memory, $n$ is the dimension of the vectors, and $m$ is
35    /// the largest number of significant bits of any element.
36    ///
37    /// # Panics
38    /// Panics if the vectors have different dimensions.
39    ///
40    /// # Examples
41    /// ```
42    /// use core::str::FromStr;
43    /// use malachite_base::num::arithmetic::traits::Dot;
44    /// use malachite_nz::integer_vector::IntegerVector;
45    ///
46    /// let v = IntegerVector::from_str("(1, -2, 3)").unwrap();
47    /// let w = IntegerVector::from_str("(4, 5, -6)").unwrap();
48    /// assert_eq!(v.clone().dot(w.clone()), -24);
49    /// assert_eq!(
50    ///     IntegerVector::from_str("()")
51    ///         .unwrap()
52    ///         .dot(IntegerVector::from_str("()").unwrap()),
53    ///     0
54    /// );
55    /// ```
56    ///
57    /// This is equivalent to `_fmpz_vec_dot` from `fmpz_vec/dot.c`, FLINT 3.6.0.
58    #[inline]
59    fn dot(mut self, mut other: Self) -> Integer {
60        if self.elements.len() == 1 && other.elements.len() == 1 {
61            // A single product can reuse the allocation of an owned element.
62            self.elements.pop().unwrap() * other.elements.pop().unwrap()
63        } else {
64            (&self).dot(&other)
65        }
66    }
67}
68
69impl Dot<&Self> for IntegerVector {
70    type Output = Integer;
71
72    /// Computes the dot product of two [`IntegerVector`]s, taking the first by value and the second
73    /// by reference.
74    ///
75    /// The dot product is the sum of the products of corresponding elements, and is 0 for two
76    /// 0-dimensional vectors.
77    ///
78    /// $$
79    /// f(v, w) = \sum_{i=0}^{n-1} v_iw_i,
80    /// $$
81    ///
82    /// where $n$ is the dimension of $v$ and $w$.
83    ///
84    /// # Worst-case complexity
85    /// $T(n, m) = O(nm \log m \log\log m)$
86    ///
87    /// $M(m) = O(m \log m)$
88    ///
89    /// where $T$ is time, $M$ is additional memory, $n$ is the dimension of the vectors, and $m$ is
90    /// the largest number of significant bits of any element.
91    ///
92    /// # Panics
93    /// Panics if the vectors have different dimensions.
94    ///
95    /// # Examples
96    /// ```
97    /// use core::str::FromStr;
98    /// use malachite_base::num::arithmetic::traits::Dot;
99    /// use malachite_nz::integer_vector::IntegerVector;
100    ///
101    /// let v = IntegerVector::from_str("(1, -2, 3)").unwrap();
102    /// let w = IntegerVector::from_str("(4, 5, -6)").unwrap();
103    /// assert_eq!(v.clone().dot(&w), -24);
104    /// assert_eq!(
105    ///     IntegerVector::from_str("()")
106    ///         .unwrap()
107    ///         .dot(IntegerVector::from_str("()").unwrap()),
108    ///     0
109    /// );
110    /// ```
111    ///
112    /// This is equivalent to `_fmpz_vec_dot` from `fmpz_vec/dot.c`, FLINT 3.6.0.
113    #[inline]
114    fn dot(mut self, other: &Self) -> Integer {
115        if self.elements.len() == 1 && other.elements.len() == 1 {
116            // A single product can reuse the allocation of an owned element.
117            self.elements.pop().unwrap() * &other.elements[0]
118        } else {
119            (&self).dot(other)
120        }
121    }
122}
123
124impl Dot<IntegerVector> for &IntegerVector {
125    type Output = Integer;
126
127    /// Computes the dot product of two [`IntegerVector`]s, taking the first by reference and the
128    /// second by value.
129    ///
130    /// The dot product is the sum of the products of corresponding elements, and is 0 for two
131    /// 0-dimensional vectors.
132    ///
133    /// $$
134    /// f(v, w) = \sum_{i=0}^{n-1} v_iw_i,
135    /// $$
136    ///
137    /// where $n$ is the dimension of $v$ and $w$.
138    ///
139    /// # Worst-case complexity
140    /// $T(n, m) = O(nm \log m \log\log m)$
141    ///
142    /// $M(m) = O(m \log m)$
143    ///
144    /// where $T$ is time, $M$ is additional memory, $n$ is the dimension of the vectors, and $m$ is
145    /// the largest number of significant bits of any element.
146    ///
147    /// # Panics
148    /// Panics if the vectors have different dimensions.
149    ///
150    /// # Examples
151    /// ```
152    /// use core::str::FromStr;
153    /// use malachite_base::num::arithmetic::traits::Dot;
154    /// use malachite_nz::integer_vector::IntegerVector;
155    ///
156    /// let v = IntegerVector::from_str("(1, -2, 3)").unwrap();
157    /// let w = IntegerVector::from_str("(4, 5, -6)").unwrap();
158    /// assert_eq!((&v).dot(w.clone()), -24);
159    /// assert_eq!(
160    ///     IntegerVector::from_str("()")
161    ///         .unwrap()
162    ///         .dot(IntegerVector::from_str("()").unwrap()),
163    ///     0
164    /// );
165    /// ```
166    ///
167    /// This is equivalent to `_fmpz_vec_dot` from `fmpz_vec/dot.c`, FLINT 3.6.0.
168    #[inline]
169    fn dot(self, mut other: IntegerVector) -> Integer {
170        if self.elements.len() == 1 && other.elements.len() == 1 {
171            // A single product can reuse the allocation of an owned element.
172            &self.elements[0] * other.elements.pop().unwrap()
173        } else {
174            self.dot(&other)
175        }
176    }
177}
178
179impl Dot<&IntegerVector> for &IntegerVector {
180    type Output = Integer;
181
182    /// Computes the dot product of two [`IntegerVector`]s, taking the first by reference and the
183    /// second by reference.
184    ///
185    /// The dot product is the sum of the products of corresponding elements, and is 0 for two
186    /// 0-dimensional vectors.
187    ///
188    /// $$
189    /// f(v, w) = \sum_{i=0}^{n-1} v_iw_i,
190    /// $$
191    ///
192    /// where $n$ is the dimension of $v$ and $w$.
193    ///
194    /// # Worst-case complexity
195    /// $T(n, m) = O(nm \log m \log\log m)$
196    ///
197    /// $M(m) = O(m \log m)$
198    ///
199    /// where $T$ is time, $M$ is additional memory, $n$ is the dimension of the vectors, and $m$ is
200    /// the largest number of significant bits of any element.
201    ///
202    /// # Panics
203    /// Panics if the vectors have different dimensions.
204    ///
205    /// # Examples
206    /// ```
207    /// use core::str::FromStr;
208    /// use malachite_base::num::arithmetic::traits::Dot;
209    /// use malachite_nz::integer_vector::IntegerVector;
210    ///
211    /// let v = IntegerVector::from_str("(1, -2, 3)").unwrap();
212    /// let w = IntegerVector::from_str("(4, 5, -6)").unwrap();
213    /// assert_eq!((&v).dot(&w), -24);
214    /// assert_eq!(
215    ///     IntegerVector::from_str("()")
216    ///         .unwrap()
217    ///         .dot(IntegerVector::from_str("()").unwrap()),
218    ///     0
219    /// );
220    /// ```
221    ///
222    /// This is equivalent to `_fmpz_vec_dot` from `fmpz_vec/dot.c`, FLINT 3.6.0.
223    #[inline]
224    fn dot(self, other: &IntegerVector) -> Integer {
225        assert_eq!(
226            self.elements.len(),
227            other.elements.len(),
228            "the vectors must have the same dimension"
229        );
230        vec_dot_general(None, false, &self.elements, &other.elements, false)
231    }
232}