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}