Skip to main content

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}