qfall_math/integer_mod_q/mat_polynomial_ring_zq/
norm.rs

1// Copyright © 2025 Niklas Siemer
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 matrices.
11
12use super::MatPolynomialRingZq;
13use crate::{
14    integer::Z,
15    rational::Q,
16    traits::{MatrixDimensions, MatrixGetSubmatrix},
17};
18
19impl MatPolynomialRingZq {
20    /// Outputs the squared l_{2, ∞}-norm, i.e. it computes the squared Euclidean
21    /// norm of each column of the matrix and returns the largest one.
22    ///
23    /// # Examples
24    /// ```
25    /// use qfall_math::{integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}, integer::{Z, MatPolyOverZ}};
26    /// use std::str::FromStr;
27    ///
28    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 7").unwrap();
29    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  3],[1  2, 0]]").unwrap();
30    /// let mat = MatPolynomialRingZq::from((&mat, &modulus));
31    ///
32    /// let eucl_norm = mat.norm_l_2_infty_sqrd();
33    ///
34    /// // 3^2 + 0^2 = 9
35    /// assert_eq!(Z::from(9), eucl_norm);
36    /// ```
37    pub fn norm_l_2_infty_sqrd(&self) -> Z {
38        let mut max_sqrd_norm = Z::ZERO;
39        for i in 0..self.get_num_columns() {
40            let column = unsafe { self.get_column_unchecked(i) };
41            let sqrd_norm = column.norm_eucl_sqrd().unwrap();
42            if sqrd_norm > max_sqrd_norm {
43                max_sqrd_norm = sqrd_norm;
44            }
45        }
46        max_sqrd_norm
47    }
48
49    /// Outputs the l_{2, ∞}-norm, i.e. it computes the Euclidean
50    /// norm of each column of the matrix and returns the largest one.
51    ///
52    /// # Examples
53    /// ```
54    /// use qfall_math::{integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}, integer::{Z, MatPolyOverZ}};
55    /// use std::str::FromStr;
56    /// # use qfall_math::rational::Q;
57    ///
58    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 5").unwrap();
59    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  3],[1  2, 1  0],[1  3, 1  4],[1  3, 1  4]]").unwrap();
60    /// let mat = MatPolynomialRingZq::from((&mat, &modulus));
61    ///
62    /// let eucl_norm = mat.norm_l_2_infty();
63    ///
64    /// // sqrt(4 * 2^2) = 4
65    /// assert_eq!(Q::from(4), eucl_norm);
66    /// ```
67    pub fn norm_l_2_infty(&self) -> Q {
68        self.norm_l_2_infty_sqrd().sqrt()
69    }
70
71    /// Outputs the l_{∞, ∞}-norm, i.e. it computes the ∞-norm
72    /// of each column of the matrix and returns the largest one.
73    ///
74    /// # Examples
75    /// ```
76    /// use qfall_math::{integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}, integer::{Z, MatPolyOverZ}};
77    /// use std::str::FromStr;
78    ///
79    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 7").unwrap();
80    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  4],[1  2, 0]]").unwrap();
81    /// let mat = MatPolynomialRingZq::from((&mat, &modulus));
82    ///
83    /// let eucl_norm = mat.norm_l_infty_infty();
84    ///
85    /// // max{2, 3} = 3
86    /// assert_eq!(Z::from(3), eucl_norm);
87    /// ```
88    pub fn norm_l_infty_infty(&self) -> Z {
89        let mut max_norm = Z::ZERO;
90        for i in 0..self.get_num_columns() {
91            let column = unsafe { self.get_column_unchecked(i) };
92            let norm = column.norm_infty().unwrap();
93            if norm > max_norm {
94                max_norm = norm;
95            }
96        }
97        max_norm
98    }
99}
100
101#[cfg(test)]
102mod test_matrix_norms {
103    use super::{MatPolynomialRingZq, Q, Z};
104    use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
105    use std::str::FromStr;
106
107    /// Ensures that the squared l_{2, ∞}-norm is correctly computed.
108    #[test]
109    fn norm_sqrd_l_2_infty() {
110        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 9").unwrap();
111        let mat = MatPolyOverZ::from_str(
112            "[[1  3, 1  -2, 1  5],[1  -5, 1  -6, 2  1 1],[1  -4, 0, 0],[1  2, 0, 3  1 1 1]]",
113        )
114        .unwrap();
115        let mat = MatPolynomialRingZq::from((&mat, &modulus));
116
117        let sqrd_norm = mat.norm_l_2_infty_sqrd();
118
119        assert_eq!(Z::from(45), sqrd_norm);
120    }
121
122    /// Ensures that the l_{2, ∞}-norm is correctly computed.
123    #[test]
124    fn norm_l_2_infty() {
125        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 5").unwrap();
126        let mat =
127            MatPolyOverZ::from_str("[[1  -2, 4  -2 0 0 1],[1  -2, 1  -3],[1  -2, 0],[1  2, 0]]")
128                .unwrap();
129        let mat = MatPolynomialRingZq::from((&mat, &modulus));
130
131        let norm = mat.norm_l_2_infty();
132
133        assert_eq!(Q::from(4), norm);
134    }
135
136    /// Ensures that the l_{∞, ∞}-norm is correctly computed.
137    #[test]
138    fn norm_l_infty_infty() {
139        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 8").unwrap();
140        let mat = MatPolyOverZ::from_str("[[2  -2 1, 1  3],[1  2, 1  -5],[1  -2, 0]]").unwrap();
141        let mat = MatPolynomialRingZq::from((&mat, &modulus));
142
143        let infty_norm = mat.norm_l_infty_infty();
144
145        assert_eq!(Z::from(3), infty_norm);
146    }
147}