Skip to main content

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