Skip to main content

qfall_math/integer/poly_over_z/
norm.rs

1// Copyright 2023 Phil Milewski
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 several norms
10//! defined on polynomials.
11
12use crate::{
13    integer::{PolyOverZ, Z},
14    rational::Q,
15    traits::{GetCoefficient, Pow},
16};
17use std::cmp::max;
18
19impl PolyOverZ {
20    /// Returns the squared Euclidean norm or squared 2-norm of the given polynomial.
21    /// The squared Euclidean norm for a polynomial is obtained by treating the coefficients
22    /// of the polynomial as a vector and then applying the standard squared Euclidean norm.
23    ///
24    /// # Examples
25    /// ```
26    /// use qfall_math::integer::{PolyOverZ, Z};
27    /// use std::str::FromStr;
28    ///
29    /// let poly = PolyOverZ::from_str("3  1 2 3").unwrap();
30    ///
31    /// let sqrd_2_norm = poly.norm_eucl_sqrd();
32    ///
33    /// // 1*1 + 2*2 + 3*3 = 14
34    /// assert_eq!(Z::from(14), sqrd_2_norm);
35    /// ```
36    pub fn norm_eucl_sqrd(&self) -> Z {
37        let mut res = Z::ZERO;
38
39        for i in 0..=self.get_degree() {
40            let coeff = unsafe { self.get_coeff_unchecked(i) };
41            res += coeff.pow(2).unwrap();
42        }
43        res
44    }
45
46    /// Returns the Euclidean norm or 2-norm of the given polynomial.
47    /// The Euclidean norm for a polynomial is obtained by treating the coefficients
48    /// of the polynomial as a vector and then applying the standard Euclidean norm.
49    ///
50    /// # Examples
51    /// ```
52    /// use qfall_math::{integer::PolyOverZ, rational::Q};
53    /// use std::str::FromStr;
54    ///
55    /// let poly = PolyOverZ::from_str("1  3").unwrap();
56    ///
57    /// let norm = poly.norm_eucl();
58    ///
59    /// // sqrt(3^2) = 3
60    /// assert_eq!(Q::from(3), norm);
61    /// ```
62    pub fn norm_eucl(&self) -> Q {
63        self.norm_eucl_sqrd().sqrt()
64    }
65
66    /// Returns the infinity norm or the maximal absolute value of a
67    /// coefficient of the given polynomial.
68    /// The infinity norm for a polynomial is obtained by treating the coefficients
69    /// of the polynomial as a vector and then applying the standard infinity norm.
70    ///
71    /// # Examples
72    /// ```
73    /// use qfall_math::integer::{PolyOverZ, Z};
74    /// use std::str::FromStr;
75    ///
76    /// let poly = PolyOverZ::from_str("3  1 2 3").unwrap();
77    ///
78    /// let infty_norm = poly.norm_infty();
79    ///
80    /// // max coefficient is 3
81    /// assert_eq!(Z::from(3), infty_norm);
82    /// ```
83    pub fn norm_infty(&self) -> Z {
84        let mut res = Z::ZERO;
85        for i in 0..=self.get_degree() {
86            if res < unsafe { self.get_coeff_unchecked(i).abs() } {
87                res = max(res, unsafe { self.get_coeff_unchecked(i).abs() });
88            }
89        }
90        res
91    }
92
93    /// Outputs the hamming weight of `self`, i.e. it returns the number of
94    /// non-zero coefficients in the polynomial.
95    ///
96    /// # Examples
97    /// ```
98    /// use qfall_math::integer::PolyOverZ;
99    /// use std::str::FromStr;
100    ///
101    /// let poly = PolyOverZ::from_str("5  1 2 3 0 4").unwrap();
102    ///
103    /// let hamming_weight = poly.hamming_weight();
104    ///
105    /// assert_eq!(4, hamming_weight);
106    /// ```
107    pub fn hamming_weight(&self) -> i64 {
108        let mut hamming_weight = 0;
109        for i in 0..=self.get_degree() {
110            let coeff = unsafe { self.get_coeff_unchecked(i) };
111            if !coeff.is_zero() {
112                hamming_weight += 1;
113            }
114        }
115        hamming_weight
116    }
117}
118
119#[cfg(test)]
120mod test_norm_eucl_sqrd {
121    use super::{PolyOverZ, Z};
122    use std::str::FromStr;
123
124    /// Check whether the squared euclidean norm for polynomials
125    /// with small coefficients is calculated correctly
126    #[test]
127    fn poly_small_coefficient() {
128        let poly_1 = PolyOverZ::default();
129        let poly_2 = PolyOverZ::from_str("3  1 2 3").unwrap();
130        let poly_3 = PolyOverZ::from_str("3  1 20 90").unwrap();
131
132        assert_eq!(poly_1.norm_eucl_sqrd(), Z::ZERO);
133        assert_eq!(poly_2.norm_eucl_sqrd(), Z::from(14));
134        assert_eq!(poly_3.norm_eucl_sqrd(), Z::from(8501));
135    }
136
137    /// Check whether the squared euclidean norm for polynomials
138    /// with small coefficients is calculated correctly
139    #[test]
140    fn poly_large_coefficient() {
141        let poly_1 = PolyOverZ::from(u64::MAX);
142        let poly_2 =
143            PolyOverZ::from_str(&format!("3  {} {} {}", u64::MAX, i64::MIN, i64::MAX)).unwrap();
144
145        assert_eq!(
146            poly_1.norm_eucl_sqrd(),
147            Z::from(u64::MAX) * Z::from(u64::MAX)
148        );
149        assert_eq!(
150            poly_2.norm_eucl_sqrd(),
151            Z::from(u64::MAX) * Z::from(u64::MAX)
152                + Z::from(i64::MAX) * Z::from(i64::MAX)
153                + Z::from(i64::MIN) * Z::from(i64::MIN)
154        );
155    }
156}
157
158#[cfg(test)]
159mod test_norm_infty {
160    use super::{PolyOverZ, Z};
161    use std::str::FromStr;
162
163    /// Check whether the infinity norm for polynomials
164    /// with small coefficients is calculated correctly
165    #[test]
166    fn poly_small_coefficient() {
167        let poly_1 = PolyOverZ::default();
168        let poly_2 = PolyOverZ::from_str("3  1 2 3").unwrap();
169        let poly_3 = PolyOverZ::from_str("3  1 2010 90").unwrap();
170
171        assert_eq!(poly_1.norm_infty(), Z::ZERO);
172        assert_eq!(poly_2.norm_infty(), Z::from(3));
173        assert_eq!(poly_3.norm_infty(), Z::from(2010));
174    }
175
176    /// Check whether the infinity norm for polynomials
177    /// with small coefficients is calculated correctly
178    #[test]
179    fn poly_large_coefficient() {
180        let poly_1 = PolyOverZ::from(u64::MAX);
181        let poly_2 =
182            PolyOverZ::from_str(&format!("3  {} {} {}", u64::MAX, i64::MIN, i64::MAX)).unwrap();
183
184        assert_eq!(poly_1.norm_infty(), Z::from(u64::MAX));
185        assert_eq!(poly_2.norm_infty(), Z::from(u64::MAX));
186    }
187}
188
189#[cfg(test)]
190mod test_hamming_weight {
191    use super::PolyOverZ;
192    use std::str::FromStr;
193
194    /// Ensures that the hamming weight is computed correctly.
195    #[test]
196    fn hamming_weight() {
197        let poly0 = PolyOverZ::default();
198        let poly1 = PolyOverZ::from_str("6  0 0 2 3 4 5").unwrap();
199
200        let hw0 = poly0.hamming_weight();
201        let hw1 = poly1.hamming_weight();
202
203        assert_eq!(0, hw0);
204        assert_eq!(4, hw1);
205    }
206}