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