qfall_math/integer/mat_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::MatZ;
13use crate::{
14 integer::Z,
15 rational::Q,
16 traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
17};
18
19impl MatZ {
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::{MatZ, Z};
26 /// use std::str::FromStr;
27 ///
28 /// let mat = MatZ::from_str("[[2, 3],[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::MatZ, rational::Q};
53 /// use std::str::FromStr;
54 ///
55 /// let mat = MatZ::from_str("[[2, 3],[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::{MatZ, Z};
72 /// use std::str::FromStr;
73 ///
74 /// let mat = MatZ::from_str("[[2, 3],[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 returns the number of
94 /// non-zero entries in the matrix.
95 ///
96 /// # Examples
97 /// ```
98 /// use qfall_math::integer::MatZ;
99 /// use std::str::FromStr;
100 ///
101 /// let mat = MatZ::from_str("[[2, 3],[2, 0]]").unwrap();
102 ///
103 /// let hamming_weight = mat.hamming_weight();
104 ///
105 /// assert_eq!(3, 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 if !entry.is_zero() {
113 hamming_weight += 1;
114 }
115 }
116 }
117 hamming_weight
118 }
119}
120
121#[cfg(test)]
122mod test_matrix_norms {
123 use super::{MatZ, Q, Z};
124 use std::str::FromStr;
125
126 /// Ensures that the squared l_{2, ∞}-norm is correctly computed.
127 #[test]
128 fn norm_sqrd_l_2_infty() {
129 let mat = MatZ::from_str("[[3, -2, 5],[-5, -6, 2],[-4, 0, 0],[2, 0, 1]]").unwrap();
130
131 let sqrd_norm = mat.norm_l_2_infty_sqrd();
132
133 assert_eq!(Z::from(54), sqrd_norm);
134 }
135
136 /// Ensures that the l_{2, ∞}-norm is correctly computed.
137 #[test]
138 fn norm_l_2_infty() {
139 let mat = MatZ::from_str("[[-2, -2],[-2, -3],[-2, 0],[2, 0]]").unwrap();
140
141 let norm = mat.norm_l_2_infty();
142
143 assert_eq!(Q::from(4), norm);
144 }
145
146 /// Ensures that the l_{∞, ∞}-norm is correctly computed.
147 #[test]
148 fn norm_l_infty_infty() {
149 let mat = MatZ::from_str("[[-2, 3],[2, -5],[-2, 0]]").unwrap();
150
151 let infty_norm = mat.norm_l_infty_infty();
152
153 assert_eq!(Z::from(5), infty_norm);
154 }
155}
156
157#[cfg(test)]
158mod test_hamming_weight {
159 use super::MatZ;
160 use std::str::FromStr;
161
162 /// Ensures that the hamming weight is computed correctly.
163 #[test]
164 fn hamming_weight() {
165 let mat0 = MatZ::new(10, 8);
166 let mat1 = MatZ::from_str("[[-2, 3],[2, -5],[-2, 0]]").unwrap();
167
168 let hw0 = mat0.hamming_weight();
169 let hw1 = mat1.hamming_weight();
170
171 assert_eq!(0, hw0);
172 assert_eq!(5, hw1);
173 }
174}