qfall_math/integer_mod_q/polynomial_ring_zq/norm.rs
1// Copyright © 2025 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 several norms
10//! defined on polynomials.
11
12use super::PolynomialRingZq;
13use crate::{
14 integer::Z,
15 integer_mod_q::fmpz_mod_helpers::length,
16 traits::{GetCoefficient, Pow},
17};
18use std::cmp::max;
19
20impl PolynomialRingZq {
21 /// Returns the squared Euclidean norm or squared 2-norm of the given polynomial.
22 /// The squared Euclidean norm for a polynomial is obtained by treating the coefficients
23 /// of the polynomial as a vector and then applying the standard squared Euclidean norm.
24 ///
25 /// Each length of an entry in this vector is defined as the shortest distance
26 /// to the next zero representative modulo q.
27 ///
28 /// # Examples
29 /// ```
30 /// use qfall_math::{integer::Z, integer_mod_q::PolynomialRingZq};
31 /// use std::str::FromStr;
32 ///
33 /// let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 11").unwrap();
34 ///
35 /// let sqrd_2_norm = poly.norm_eucl_sqrd();
36 ///
37 /// // 1*1 + 2*2 + 3*3 = 14
38 /// assert_eq!(Z::from(14), sqrd_2_norm);
39 /// ```
40 pub fn norm_eucl_sqrd(&self) -> Z {
41 let mut res = Z::ZERO;
42 for i in 0..=self.get_degree() {
43 let coeff: Z = unsafe { self.get_coeff_unchecked(i) };
44 res += length(&coeff.value, &self.modulus.get_fq_ctx().ctxp[0].n[0])
45 .pow(2)
46 .unwrap();
47 }
48 res
49 }
50
51 /// Returns the infinity norm or the maximal absolute value of a
52 /// coefficient of the given polynomial.
53 /// The infinity norm for a polynomial is obtained by treating the coefficients
54 /// of the polynomial as a vector and then applying the standard infinity norm.
55 ///
56 /// Each length of an entry in this vector is defined as the shortest distance
57 /// to the next zero representative modulo q.
58 ///
59 /// # Examples
60 /// ```
61 /// use qfall_math::{integer::Z, integer_mod_q::PolynomialRingZq};
62 /// use std::str::FromStr;
63 ///
64 /// let poly = PolynomialRingZq::from_str("3 1 2 4 / 4 1 2 3 4 mod 7").unwrap();
65 ///
66 /// let infty_norm = poly.norm_infty();
67 ///
68 /// // max coefficient is 4 = -3
69 /// assert_eq!(Z::from(3), infty_norm);
70 /// ```
71 pub fn norm_infty(&self) -> Z {
72 let mut res = Z::ZERO;
73
74 for i in 0..=self.get_degree() {
75 let coeff: Z = unsafe { self.get_coeff_unchecked(i) };
76 let len = length(&coeff.value, &self.modulus.get_fq_ctx().ctxp[0].n[0]);
77 res = max(res, len);
78 }
79 res
80 }
81}
82
83#[cfg(test)]
84mod test_norm_eucl_sqrd {
85 use super::Z;
86 use crate::integer_mod_q::PolynomialRingZq;
87 use std::str::FromStr;
88
89 /// Check whether the squared euclidean norm for polynomials
90 /// with small coefficients is calculated correctly
91 #[test]
92 fn poly_small_coefficient() {
93 let poly_1 = PolynomialRingZq::from_str("0 / 2 1 2 mod 11").unwrap();
94 let poly_2 = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 11").unwrap();
95 let poly_3 = PolynomialRingZq::from_str("3 1 20 194 / 4 1 2 3 4 mod 195").unwrap();
96
97 assert_eq!(poly_1.norm_eucl_sqrd(), Z::ZERO);
98 assert_eq!(poly_2.norm_eucl_sqrd(), Z::from(14));
99 assert_eq!(poly_3.norm_eucl_sqrd(), Z::from(402));
100 }
101
102 /// Check whether the squared euclidean norm for polynomials
103 /// with small coefficients is calculated correctly
104 #[test]
105 fn poly_large_coefficient() {
106 let poly_1 =
107 PolynomialRingZq::from_str(&format!("1 {} / 2 1 2 mod {}", u64::MAX, u128::MAX))
108 .unwrap();
109 let poly_2 = PolynomialRingZq::from_str(&format!(
110 "3 {} {} {} / 4 1 2 3 4 mod {}",
111 u64::MAX,
112 i64::MIN,
113 i64::MAX,
114 u64::MAX - 58
115 ))
116 .unwrap();
117
118 assert_eq!(
119 poly_1.norm_eucl_sqrd(),
120 Z::from(u64::MAX) * Z::from(u64::MAX)
121 );
122 assert_eq!(
123 poly_2.norm_eucl_sqrd(),
124 Z::from(58) * Z::from(58)
125 + Z::from((u64::MAX - 1) / 2 - 57) * Z::from((u64::MAX - 1) / 2 - 57)
126 + Z::from((u64::MAX - 1) / 2 - 58) * Z::from((u64::MAX - 1) / 2 - 58)
127 );
128 }
129}
130
131#[cfg(test)]
132mod test_norm_infty {
133 use super::Z;
134 use crate::integer_mod_q::PolynomialRingZq;
135 use std::str::FromStr;
136
137 /// Check whether the infinity norm for polynomials
138 /// with small coefficients is calculated correctly
139 #[test]
140 fn poly_small_coefficient() {
141 let poly_1 = PolynomialRingZq::from_str("0 / 2 1 2 mod 11").unwrap();
142 let poly_2 = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 5").unwrap();
143 let poly_3 = PolynomialRingZq::from_str("3 1 20 194 / 4 1 2 3 4 mod 195").unwrap();
144
145 assert_eq!(poly_1.norm_infty(), Z::ZERO);
146 assert_eq!(poly_2.norm_infty(), Z::from(2));
147 assert_eq!(poly_3.norm_infty(), Z::from(20));
148 }
149
150 /// Check whether the infinity norm for polynomials
151 /// with small coefficients is calculated correctly
152 #[test]
153 fn poly_large_coefficient() {
154 let poly_1 =
155 PolynomialRingZq::from_str(&format!("1 {} / 2 1 2 mod {}", u64::MAX, u128::MAX))
156 .unwrap();
157 let poly_2 = PolynomialRingZq::from_str(&format!(
158 "3 {} {} {} / 4 1 2 3 4 mod {}",
159 u64::MAX,
160 i64::MIN,
161 i64::MAX,
162 u64::MAX - 58
163 ))
164 .unwrap();
165
166 assert_eq!(poly_1.norm_infty(), Z::from(u64::MAX));
167 assert_eq!(poly_2.norm_infty(), Z::from((u64::MAX - 1) / 2 - 57));
168 }
169}