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}