Skip to main content

qfall_math/integer/mat_poly_over_z/
norm.rs

1// Copyright 2025 Jan 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::MatPolyOverZ;
13use crate::{
14    integer::Z,
15    rational::Q,
16    traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
17};
18
19impl MatPolyOverZ {
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::{MatPolyOverZ, Z};
26    /// use std::str::FromStr;
27    ///
28    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  3],[1  2, 0]]").unwrap();
29    ///
30    /// let eucl_norm = mat.norm_l_2_infty_sqrd();
31    ///
32    /// // 3^2 + 0^2 = 9
33    /// assert_eq!(Z::from(9), eucl_norm);
34    /// ```
35    pub fn norm_l_2_infty_sqrd(&self) -> Z {
36        let mut max_sqrd_norm = Z::ZERO;
37        for i in 0..self.get_num_columns() {
38            let column = unsafe { self.get_column_unchecked(i) };
39            let sqrd_norm = column.norm_eucl_sqrd().unwrap();
40            if sqrd_norm > max_sqrd_norm {
41                max_sqrd_norm = sqrd_norm;
42            }
43        }
44        max_sqrd_norm
45    }
46
47    /// Outputs the l_{2, ∞}-norm, i.e. it computes the Euclidean
48    /// norm of each column of the matrix and returns the largest one.
49    ///
50    /// # Examples
51    /// ```
52    /// use qfall_math::{integer::MatPolyOverZ, rational::Q};
53    /// use std::str::FromStr;
54    ///
55    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  3],[1  2, 0]]").unwrap();
56    ///
57    /// let eucl_norm = mat.norm_l_2_infty();
58    ///
59    /// // sqrt(3^2 + 0^2) = 3
60    /// assert_eq!(Q::from(3), eucl_norm);
61    /// ```
62    pub fn norm_l_2_infty(&self) -> Q {
63        self.norm_l_2_infty_sqrd().sqrt()
64    }
65
66    /// Outputs the l_{∞, ∞}-norm, i.e. it computes the ∞-norm
67    /// of each column of the matrix and returns the largest one.
68    ///
69    /// # Examples
70    /// ```
71    /// use qfall_math::integer::{MatPolyOverZ, Z};
72    /// use std::str::FromStr;
73    ///
74    /// let mat = MatPolyOverZ::from_str("[[1  2, 1  3],[1  2, 0]]").unwrap();
75    ///
76    /// let eucl_norm = mat.norm_l_infty_infty();
77    ///
78    /// // max{2, 3} = 3
79    /// assert_eq!(Z::from(3), eucl_norm);
80    /// ```
81    pub fn norm_l_infty_infty(&self) -> Z {
82        let mut max_norm = Z::ZERO;
83        for i in 0..self.get_num_columns() {
84            let column = unsafe { self.get_column_unchecked(i) };
85            let norm = column.norm_infty().unwrap();
86            if norm > max_norm {
87                max_norm = norm;
88            }
89        }
90        max_norm
91    }
92
93    /// Outputs the hamming weight of `self`, i.e. it computes the number of non-zero
94    /// coefficients across all polynomials in the matrix.
95    ///
96    /// # Examples
97    /// ```
98    /// use qfall_math::integer::MatPolyOverZ;
99    /// use std::str::FromStr;
100    ///
101    /// let mat = MatPolyOverZ::from_str("[[2  2 1, 2  3 0],[1  2, 0]]").unwrap();
102    ///
103    /// let hamming_weight = mat.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 row in 0..self.get_num_rows() {
110            for col in 0..self.get_num_columns() {
111                let entry = unsafe { self.get_entry_unchecked(row, col) };
112                hamming_weight += entry.hamming_weight();
113            }
114        }
115        hamming_weight
116    }
117}
118
119#[cfg(test)]
120mod test_matrix_norms {
121    use super::{MatPolyOverZ, Q, Z};
122    use std::str::FromStr;
123
124    /// Ensures that the squared l_{2, ∞}-norm is correctly computed.
125    #[test]
126    fn norm_sqrd_l_2_infty() {
127        let mat = MatPolyOverZ::from_str(
128            "[[1  3, 1  -2, 1  5],[1  -5, 1  -6, 2  2 1],[1  -4, 0, 0],[1  2, 0, 1  1]]",
129        )
130        .unwrap();
131
132        let sqrd_norm = mat.norm_l_2_infty_sqrd();
133
134        assert_eq!(Z::from(54), sqrd_norm);
135    }
136
137    /// Ensures that the l_{2, ∞}-norm is correctly computed.
138    #[test]
139    fn norm_l_2_infty() {
140        let mat =
141            MatPolyOverZ::from_str("[[1  -2, 3  -2 1 1],[1  -2, 1  -3],[1  -2, 0],[1  2, 0]]")
142                .unwrap();
143
144        let norm = mat.norm_l_2_infty();
145
146        assert_eq!(Q::from(4), norm);
147    }
148
149    /// Ensures that the l_{∞, ∞}-norm is correctly computed.
150    #[test]
151    fn norm_l_infty_infty() {
152        let mat = MatPolyOverZ::from_str("[[2  -2 1, 1  3],[1  2, 1  -5],[1  -2, 0]]").unwrap();
153
154        let infty_norm = mat.norm_l_infty_infty();
155
156        assert_eq!(Z::from(5), infty_norm);
157    }
158}
159
160#[cfg(test)]
161mod test_hamming_weight {
162    use super::MatPolyOverZ;
163    use std::str::FromStr;
164
165    /// Ensures that the hamming weight is computed correctly.
166    #[test]
167    fn hamming_weight() {
168        let mat0 = MatPolyOverZ::new(3, 4);
169        let mat1 = MatPolyOverZ::from_str("[[1  -2, 2  3 2],[2  2 0, 1  -5],[1  -2, 0]]").unwrap();
170
171        let hw0 = mat0.hamming_weight();
172        let hw1 = mat1.hamming_weight();
173
174        assert_eq!(0, hw0);
175        assert_eq!(6, hw1);
176    }
177}