qfall_math/integer/mat_poly_over_z/vector/
norm.rs

1// Copyright © 2024 Marcel Luca Schmidt
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 vectors.
11
12use super::super::MatPolyOverZ;
13use crate::{
14    error::MathError,
15    integer::Z,
16    rational::Q,
17    traits::{MatrixDimensions, MatrixGetEntry},
18};
19
20impl MatPolyOverZ {
21    /// Returns the squared Euclidean norm or 2-norm of the given (row or column) vector
22    /// or an error if the given [`MatPolyOverZ`] instance is not a (row or column) vector.
23    /// The squared Euclidean norm for a polynomial vector is obtained by
24    /// computing the sum of the squared Euclidean norms of the individual polynomials.
25    /// The squared Euclidean norm for a polynomial is obtained by treating the coefficients
26    /// of the polynomial as a vector and then applying the standard squared Euclidean norm.
27    ///
28    /// # Examples
29    /// ```
30    /// use qfall_math::integer::{MatPolyOverZ, Z};
31    /// use std::str::FromStr;
32    ///
33    /// let vec = MatPolyOverZ::from_str("[[1  1],[2  2 2],[1  3]]").unwrap();
34    ///
35    /// let sqrd_2_norm = vec.norm_eucl_sqrd().unwrap();
36    ///
37    /// assert_eq!(Z::from(18), sqrd_2_norm);
38    /// ```
39    ///
40    /// # Errors and Failures
41    /// - Returns a [`MathError`] of type [`MathError::VectorFunctionCalledOnNonVector`] if
42    ///   the given [`MatPolyOverZ`] instance is not a (row or column) vector.
43    pub fn norm_eucl_sqrd(&self) -> Result<Z, MathError> {
44        if !self.is_vector() {
45            return Err(MathError::VectorFunctionCalledOnNonVector(
46                String::from("norm_eucl_sqrd"),
47                self.get_num_rows(),
48                self.get_num_columns(),
49            ));
50        }
51
52        let mut result = Z::ZERO;
53
54        for row in 0..self.get_num_rows() {
55            for column in 0..self.get_num_columns() {
56                result += unsafe { self.get_entry_unchecked(row, column) }.norm_eucl_sqrd();
57            }
58        }
59
60        Ok(result)
61    }
62
63    /// Returns the Euclidean norm or 2-norm of the given (row or column) vector
64    /// or an error if the given [`MatPolyOverZ`] instance is not a (row or column) vector.
65    ///
66    /// # Examples
67    /// ```
68    /// use qfall_math::integer::MatPolyOverZ;
69    /// use std::str::FromStr;
70    ///
71    /// let vec = MatPolyOverZ::from_str("[[1  2],[2  2 2],[1  2]]").unwrap();
72    ///
73    /// let eucl_norm = vec.norm_eucl().unwrap();
74    ///
75    /// assert_eq!(4, eucl_norm);
76    /// ```
77    ///
78    /// # Errors and Failures
79    /// - Returns a [`MathError`] of type [`MathError::VectorFunctionCalledOnNonVector`] if
80    ///   the given [`MatPolyOverZ`] instance is not a (row or column) vector.
81    pub fn norm_eucl(&self) -> Result<Q, MathError> {
82        Ok(self.norm_eucl_sqrd()?.sqrt())
83    }
84
85    /// Returns the infinity norm or ∞-norm of the given (row or column) vector
86    /// or an error if the given [`MatPolyOverZ`] instance is not a (row or column) vector.
87    /// The infinity norm for a polynomial vector is obtained by computing the
88    /// infinity norm on the vector consisting of the infinity norms of the individual polynomials.
89    /// The infinity norm for a polynomial is obtained by treating the coefficients
90    /// of the polynomial as a vector and then applying the standard infinity norm.
91    ///
92    /// # Examples
93    /// ```
94    /// use qfall_math::integer::{MatPolyOverZ, Z};
95    /// use std::str::FromStr;
96    ///
97    /// let vec = MatPolyOverZ::from_str("[[1  1],[2  2 4],[1  3]]").unwrap();
98    ///
99    /// let infty_norm = vec.norm_infty().unwrap();
100    ///
101    /// assert_eq!(Z::from(4), infty_norm);
102    /// ```
103    ///
104    /// # Errors and Failures
105    /// - Returns a [`MathError`] of type [`MathError::VectorFunctionCalledOnNonVector`] if
106    ///   the given [`MatPolyOverZ`] instance is not a (row or column) vector.
107    pub fn norm_infty(&self) -> Result<Z, MathError> {
108        if !self.is_vector() {
109            return Err(MathError::VectorFunctionCalledOnNonVector(
110                String::from("norm_infty"),
111                self.get_num_rows(),
112                self.get_num_columns(),
113            ));
114        }
115
116        let mut result = Z::ZERO;
117
118        for row in 0..self.get_num_rows() {
119            for column in 0..self.get_num_columns() {
120                let entry_norm = unsafe { self.get_entry_unchecked(row, column) }
121                    .norm_infty()
122                    .abs();
123                if result < entry_norm {
124                    result = entry_norm;
125                }
126            }
127        }
128
129        Ok(result)
130    }
131}
132
133#[cfg(test)]
134mod test_norm_eucl_sqrd {
135    use crate::integer::{MatPolyOverZ, Z};
136    use std::str::FromStr;
137
138    /// Check whether the squared euclidean norm for row vectors
139    /// with small entries is calculated correctly
140    #[test]
141    fn row_vector_small_entries() {
142        let vec_1 = MatPolyOverZ::from_str("[[1  1]]").unwrap();
143        let vec_2 = MatPolyOverZ::from_str("[[1  1, 2  10 3, 3  1 2 100]]").unwrap();
144        let vec_3 = MatPolyOverZ::from_str("[[2  1 3, 1  10, 3  1 2 100, 1  1000]]").unwrap();
145
146        assert_eq!(vec_1.norm_eucl_sqrd().unwrap(), Z::ONE);
147        assert_eq!(vec_2.norm_eucl_sqrd().unwrap(), Z::from(10115));
148        assert_eq!(vec_3.norm_eucl_sqrd().unwrap(), Z::from(1010115));
149    }
150
151    /// Check whether the squared euclidean norm for row vectors
152    /// with large entries is calculated correctly
153    #[test]
154    fn row_vector_large_entries() {
155        let vec =
156            MatPolyOverZ::from_str(&format!("[[1  {}, 2  {} 2, 2  2 1]]", i64::MAX, i64::MIN))
157                .unwrap();
158        let max = Z::from(i64::MAX);
159        let min = Z::from(i64::MIN);
160        let cmp = &min * &min + &max * &max + Z::from(9);
161
162        assert_eq!(vec.norm_eucl_sqrd().unwrap(), cmp);
163    }
164
165    /// Check whether the squared euclidean norm for column vectors
166    /// with small entries is calculated correctly
167    #[test]
168    fn column_vector_small_entries() {
169        let vec_1 = MatPolyOverZ::from_str("[[1  1],[2  10 3],[3  1 2 100]]").unwrap();
170        let vec_2 = MatPolyOverZ::from_str("[[2  1 3],[1  10],[3  1 2 100],[1  1000]]").unwrap();
171
172        assert_eq!(vec_1.norm_eucl_sqrd().unwrap(), Z::from(10115));
173        assert_eq!(vec_2.norm_eucl_sqrd().unwrap(), Z::from(1010115));
174    }
175
176    /// Check whether the squared euclidean norm for column vectors
177    /// with large entries is calculated correctly
178    #[test]
179    fn column_vector_large_entries() {
180        let vec =
181            MatPolyOverZ::from_str(&format!("[[2  2 {}],[1  {}],[1  2]]", i64::MAX, i64::MIN))
182                .unwrap();
183        let max = Z::from(i64::MAX);
184        let min = Z::from(i64::MIN);
185        let cmp = &min * &min + &max * &max + Z::from(8);
186
187        assert_eq!(vec.norm_eucl_sqrd().unwrap(), cmp);
188    }
189
190    /// Check whether euclidean norm calculations of non vectors yield an error
191    #[test]
192    fn non_vector_yield_error() {
193        let mat = MatPolyOverZ::from_str("[[2  1 20, 1  1],[1  10, 2  1 2]]").unwrap();
194
195        assert!(mat.norm_eucl_sqrd().is_err());
196    }
197}
198
199#[cfg(test)]
200mod test_norm_infty {
201    use crate::integer::{MatPolyOverZ, Z};
202    use std::str::FromStr;
203
204    /// Check whether the infinity norm for row vectors
205    /// with small entries is calculated correctly
206    #[test]
207    fn row_vector_small_entries() {
208        let vec_1 = MatPolyOverZ::from_str("[[1  1]]").unwrap();
209        let vec_2 = MatPolyOverZ::from_str("[[1  1, 2  10 3, 3  1 2 100]]").unwrap();
210        let vec_3 = MatPolyOverZ::from_str("[[2  1 3, 1  10, 3  1 2 100, 1  1000]]").unwrap();
211
212        assert_eq!(vec_1.norm_infty().unwrap(), Z::ONE);
213        assert_eq!(vec_2.norm_infty().unwrap(), Z::from(100));
214        assert_eq!(vec_3.norm_infty().unwrap(), Z::from(1000));
215    }
216
217    /// Check whether the infinity norm for row vectors
218    /// with large entries is calculated correctly
219    #[test]
220    fn row_vector_large_entries() {
221        let vec =
222            MatPolyOverZ::from_str(&format!("[[1  {}, 2  {} 2, 2  2 1]]", i64::MAX, i64::MIN))
223                .unwrap();
224
225        assert_eq!(vec.norm_infty().unwrap(), Z::from(i64::MIN).abs());
226    }
227
228    /// Check whether the infinity norm for column vectors
229    /// with small entries is calculated correctly
230    #[test]
231    fn column_vector_small_entries() {
232        let vec_1 = MatPolyOverZ::from_str("[[1  1],[2  10 3],[3  1 2 100]]").unwrap();
233        let vec_2 = MatPolyOverZ::from_str("[[2  1 3],[1  10],[3  1 2 100],[1  1000]]").unwrap();
234
235        assert_eq!(vec_1.norm_infty().unwrap(), Z::from(100));
236        assert_eq!(vec_2.norm_infty().unwrap(), Z::from(1000));
237    }
238
239    /// Check whether the infinity norm for column vectors
240    /// with large entries is calculated correctly
241    #[test]
242    fn column_vector_large_entries() {
243        let vec =
244            MatPolyOverZ::from_str(&format!("[[2  2 {}],[1  {}],[1  2]]", i64::MAX, i64::MIN))
245                .unwrap();
246
247        assert_eq!(vec.norm_infty().unwrap(), Z::from(i64::MIN).abs());
248    }
249
250    /// Check whether infinity norm calculations of non vectors yield an error
251    #[test]
252    fn non_vector_yield_error() {
253        let mat = MatPolyOverZ::from_str("[[2  1 20, 1  1],[1  10, 2  1 2]]").unwrap();
254
255        assert!(mat.norm_infty().is_err());
256    }
257}