use super::super::MatQ;
use crate::{error::MathError, rational::Q, traits::MatrixDimensions};
use flint_sys::fmpq::{fmpq_abs, fmpq_addmul, fmpq_cmp};
impl MatQ {
pub fn norm_eucl_sqrd(&self) -> Result<Q, MathError> {
if !self.is_vector() {
return Err(MathError::VectorFunctionCalledOnNonVector(
String::from("norm_eucl_sqrd"),
self.get_num_rows(),
self.get_num_columns(),
));
}
let entries = self.collect_entries();
let mut result = Q::default();
for entry in entries {
unsafe { fmpq_addmul(&mut result.value, &entry, &entry) }
}
Ok(result)
}
pub fn norm_eucl(&self) -> Result<Q, MathError> {
Ok(self.norm_eucl_sqrd()?.sqrt())
}
pub fn norm_infty(&self) -> Result<Q, MathError> {
if !self.is_vector() {
return Err(MathError::VectorFunctionCalledOnNonVector(
String::from("norm_infty"),
self.get_num_rows(),
self.get_num_columns(),
));
}
let entries = self.collect_entries();
let mut max = Q::ZERO;
for entry in entries {
let mut abs_entry = Q::default();
unsafe { fmpq_abs(&mut abs_entry.value, &entry) };
if unsafe { fmpq_cmp(&max.value, &abs_entry.value) } < 0 {
max = abs_entry;
}
}
Ok(max)
}
}
#[cfg(test)]
mod test_norm_eucl_sqrd {
use super::{MatQ, Q};
use std::str::FromStr;
#[test]
fn row_vector_small_entries() {
let vec_1 = MatQ::from_str("[[1]]").unwrap();
let vec_2 = MatQ::from_str("[[1, 10/1, -1000/10]]").unwrap();
let vec_3 = MatQ::from_str("[[1, 10, 100, 1000]]").unwrap();
assert_eq!(vec_1.norm_eucl_sqrd().unwrap(), Q::ONE);
assert_eq!(vec_2.norm_eucl_sqrd().unwrap(), Q::from(10101));
assert_eq!(vec_3.norm_eucl_sqrd().unwrap(), Q::from(1010101));
}
#[test]
fn row_vector_large_entries() {
let vec = MatQ::from_str(&format!("[[{}/1, {}/-1, 2/1]]", i64::MAX, i64::MIN)).unwrap();
let max = Q::from(i64::MAX);
let min = Q::from(i64::MIN);
let cmp = &min * &min + &max * &max + Q::from(4);
assert_eq!(vec.norm_eucl_sqrd().unwrap(), cmp);
}
#[test]
fn column_vector_small_entries() {
let vec_1 = MatQ::from_str("[[1],[-100/10],[100]]").unwrap();
let vec_2 = MatQ::from_str("[[1],[-10/-1],[100],[1000]]").unwrap();
assert_eq!(vec_1.norm_eucl_sqrd().unwrap(), Q::from(10101));
assert_eq!(vec_2.norm_eucl_sqrd().unwrap(), Q::from(1010101));
}
#[test]
fn column_vector_large_entries() {
let vec = MatQ::from_str(&format!("[[{}/-1],[-1/{}],[2]]", i64::MAX, i64::MIN)).unwrap();
let max = Q::from(i64::MAX);
let min = Q::from((1, i64::MIN));
let cmp = &min * &min + &max * &max + Q::from(4);
assert_eq!(vec.norm_eucl_sqrd().unwrap(), cmp);
}
#[test]
fn non_vector_yield_error() {
let mat = MatQ::from_str("[[1, 1/1],[10/-1, 2]]").unwrap();
assert!(mat.norm_eucl_sqrd().is_err());
}
}
#[cfg(test)]
mod test_norm_infty {
use super::{MatQ, Q};
use std::str::FromStr;
#[test]
fn row_vector_small_entries() {
let vec_1 = MatQ::from_str("[[1]]").unwrap();
let vec_2 = MatQ::from_str("[[1, 100/10, 1000/-10]]").unwrap();
let vec_3 = MatQ::from_str("[[1, -10/-1, -100/1, 1000]]").unwrap();
assert_eq!(vec_1.norm_infty().unwrap(), Q::ONE);
assert_eq!(vec_2.norm_infty().unwrap(), Q::from(100));
assert_eq!(vec_3.norm_infty().unwrap(), Q::from(1000));
}
#[test]
fn row_vector_large_entries() {
let vec = MatQ::from_str(&format!("[[{}/-1, {}/1, 2]]", i64::MAX, i64::MIN)).unwrap();
let cmp = -1 * Q::from(i64::MIN);
assert_eq!(vec.norm_infty().unwrap(), cmp);
}
#[test]
fn column_vector_small_entries() {
let vec_1 = MatQ::from_str("[[1],[100/10],[100]]").unwrap();
let vec_2 = MatQ::from_str("[[-1/1],[10/-1],[-100/-1],[1000]]").unwrap();
assert_eq!(vec_1.norm_infty().unwrap(), Q::from(100));
assert_eq!(vec_2.norm_infty().unwrap(), Q::from(1000));
}
#[test]
fn column_vector_large_entries() {
let vec = MatQ::from_str(&format!("[[{}/1],[{}],[2]]", i64::MAX, i64::MIN)).unwrap();
let cmp = Q::from(-1) * Q::from(i64::MIN);
assert_eq!(vec.norm_infty().unwrap(), cmp);
}
#[test]
fn non_vector_yield_error() {
let mat = MatQ::from_str("[[1, 1],[10/1, 2]]").unwrap();
assert!(mat.norm_infty().is_err());
}
}