Skip to main content

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}