qfall_math/rational/poly_over_q/
dot_product.rs

1// Copyright © 2023 Marcel Luca Schmidt
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module includes functionality to compute the dot product of two polynomials.
10
11use crate::error::MathError;
12use crate::rational::{PolyOverQ, Q};
13use flint_sys::fmpq::{fmpq_add, fmpq_mul};
14use flint_sys::fmpq_poly::fmpq_poly_get_coeff_fmpq;
15
16impl PolyOverQ {
17    /// Returns the dot product of two polynomials of type [`PolyOverQ`].
18    /// The dot product for polynomials is obtained by treating the coefficients
19    /// of the polynomials as vectors and then applying the standard dot product operation.
20    ///
21    /// Parameters:
22    /// - `other`: specifies the other polynomial the dot product is calculated over
23    ///
24    /// Returns the resulting `dot_product` as a [`PolyOverQ`].
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::rational::PolyOverQ;
29    /// use std::str::FromStr;
30    ///
31    /// let poly_1 = PolyOverQ::from_str("4  -1/2 0 7/8 1").unwrap();
32    /// let poly_2 = PolyOverQ::from_str("1  5/42").unwrap();
33    ///
34    /// let dot_prod = poly_1.dot_product(&poly_2).unwrap();
35    /// ```
36    pub fn dot_product(&self, other: &Self) -> Result<Q, MathError> {
37        let self_degree = self.get_degree();
38        let other_degree = other.get_degree();
39
40        let mut smaller_degree = self_degree;
41        if smaller_degree > other_degree {
42            smaller_degree = other_degree;
43        }
44
45        // calculate dot product of polynomials
46        let mut result = Q::default();
47        let mut temp = Q::default();
48        for i in 0..=smaller_degree {
49            // sets result = result + coefficient_1 * coefficient_2
50            unsafe {
51                let mut coefficient_1 = Q::default();
52                let mut coefficient_2 = Q::default();
53                fmpq_poly_get_coeff_fmpq(&mut coefficient_1.value, &self.poly, i);
54                fmpq_poly_get_coeff_fmpq(&mut coefficient_2.value, &other.poly, i);
55
56                fmpq_mul(&mut temp.value, &coefficient_1.value, &coefficient_2.value);
57
58                fmpq_add(&mut result.value, &result.value, &temp.value)
59            }
60        }
61
62        Ok(result)
63    }
64}
65
66#[cfg(test)]
67mod test_dot_product {
68    use crate::rational::{PolyOverQ, Q};
69    use std::str::FromStr;
70
71    /// Check whether the dot product is calculated correctly
72    #[test]
73    fn dot_product_correct() {
74        let poly_1 = PolyOverQ::from_str("2  1/2 1").unwrap();
75        let poly_2 = PolyOverQ::from_str("2  3 4/2").unwrap();
76
77        let cmp = Q::from((7, 2));
78        let dot_prod = poly_1.dot_product(&poly_2).unwrap();
79
80        assert_eq!(dot_prod, cmp);
81    }
82
83    /// Check whether the dot product is calculated correctly with large numbers.
84    #[test]
85    fn large_numbers() {
86        let poly_1 = PolyOverQ::from_str("3  6 2 2").unwrap();
87        let poly_2 = PolyOverQ::from_str(&format!("3  1 2 {}", i64::MAX / 3)).unwrap();
88
89        let cmp = Q::from(10 + 2 * (i64::MAX / 3));
90        let dot_prod = poly_1.dot_product(&poly_2).unwrap();
91
92        assert_eq!(dot_prod, cmp);
93    }
94
95    /// Check whether the dot product calculation on
96    /// polynomials of different lengths works.
97    #[test]
98    fn different_lengths_work() {
99        let poly_1 = PolyOverQ::from_str("3  1 2 3/7").unwrap();
100        let poly_2 = PolyOverQ::from_str("2  3 4").unwrap();
101
102        let cmp = Q::from(11);
103        let dot_prod = poly_1.dot_product(&poly_2).unwrap();
104
105        assert_eq!(dot_prod, cmp);
106    }
107
108    /// Check whether the dot product calculation on
109    /// polynomials with length 0 works.
110    #[test]
111    fn zero_length_works() {
112        let poly_1 = PolyOverQ::from_str("3  1 2/11 3").unwrap();
113        let poly_2 = PolyOverQ::from_str("0").unwrap();
114
115        let cmp = Q::ZERO;
116        let dot_prod = poly_1.dot_product(&poly_2).unwrap();
117
118        assert_eq!(dot_prod, cmp);
119    }
120}