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