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}