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}