use std::convert::TryFrom;
use std::cmp::Ordering;
use num_traits::{Num, Float};
use crate::desc::{PNorm, PNormReal};
pub fn supnorm_iterable<I: IntoIterator<Item=R>, R: Num + PartialOrd>(iter: I) -> R {
let mut iter = iter.into_iter();
if let Some(mut sup) = iter.next() {
for it in iter {
match PartialOrd::partial_cmp(&it, &sup) {
Some(Ordering::Greater) => sup = it,
Some(Ordering::Equal) | Some(Ordering::Less) => (),
None => if sup.partial_cmp(&sup).is_none() && it.partial_cmp(&it).is_some() {
sup = it;
},
}
}
sup
} else {
R::zero()
}
}
pub fn pnorm_iterable<I: IntoIterator<Item=R>, R>(iter: I, desc: PNorm) -> R
where
R: Float + From<f32>
{
let pfloat: R = From::from(u32::from(desc.p) as f32);
let pinv = pfloat.recip();
if let Ok(p) = i32::try_from(u32::from(desc.p)) {
let mut res = R::zero();
let mut iter = iter.into_iter();
while let Some(it) = iter.next() {
let it_pow = it.powi(p);
if it_pow.is_finite() {
res = res + it_pow;
} else if it.is_infinite() {
return R::infinity();
} else {
return supnorm_iterable(iter.chain(std::iter::once(it)));
}
}
res.powf(pinv)
} else {
supnorm_iterable(iter)
}
}
pub fn pnorm_real_iterable<I: IntoIterator<Item=R>, R>(iter: I, desc: PNormReal) -> R
where
R: Float + From<f32>
{
let mut res = R::zero();
let mut iter = iter.into_iter();
while let Some(it) = iter.next() {
let it_pow = it.powf(From::from(desc.p.raw()));
if it_pow.is_finite() {
res = res + it_pow;
} else if it.is_infinite() {
return R::infinity();
} else {
return supnorm_iterable(iter.chain(std::iter::once(it)));
}
}
res.powf(From::from(desc.p.raw().recip()))
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use std::f32::{NAN, INFINITY};
use crate::Norm;
use crate::desc::{Abs, PNorm, PNormReal};
use super::{pnorm_iterable, pnorm_real_iterable, supnorm_iterable};
#[test]
fn pnorm_empty_array() {
let a = [3.0f32; 0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(pnorm_iterable(a, PNorm::default()), 0.0);
}
#[test]
fn norm2_iterable_array() {
let a = [3.0f32, 5.0, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(
pnorm_iterable(a, PNorm::eucl()),
(3.0f32*3.0 + 5.0*5.0 + 7.0*7.0).sqrt()
);
}
#[test]
fn norm2_real_iterable_array() {
let a = [3.0f32, 5.0, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(
pnorm_real_iterable(a, PNormReal::eucl()),
(3.0f32*3.0 + 5.0*5.0 + 7.0*7.0).sqrt()
);
}
#[test]
fn pnorm_maxint_iterable_array() {
let a = [3.0f32, 5.0, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(pnorm_iterable(a, PNorm::new(0x80000000)), 7.0);
}
#[test]
fn pnorm_infinity_iterable_array() {
let a = [3.0f32, std::f32::INFINITY, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(pnorm_iterable(a, PNorm::new(3)), std::f32::INFINITY);
}
#[test]
fn pnorm_real_maxint_iterable_array() {
let a = [3.0f32, 5.0, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(pnorm_real_iterable(a, PNormReal::from_f32(10000.0)), 7.0);
}
#[test]
fn pnorm_real_infinity_iterable_array() {
let a = [3.0f32, std::f32::INFINITY, 7.0].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(pnorm_real_iterable(a, PNormReal::from_f32(3.0)), std::f32::INFINITY);
}
#[test]
fn partial_cmp_float() {
assert_eq!(PartialOrd::partial_cmp(&NAN, &1.0), None);
assert_eq!(PartialOrd::partial_cmp(&INFINITY, &1.0), Some(Ordering::Greater));
assert_eq!(PartialOrd::partial_cmp(&NAN, &NAN), None);
assert_eq!(PartialOrd::partial_cmp(&INFINITY, &INFINITY), Some(Ordering::Equal));
assert_eq!(PartialOrd::partial_cmp(&NAN, &INFINITY), None);
}
#[test]
fn supnorm_iterable_array() {
let a = [3.0f32, -5.0f32, 2.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), 5.0);
}
#[test]
fn supnorm_iterable_array_nan() {
let a = [3.0f32, NAN, -2.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), 3.0);
let a = [NAN, 3.0f32, 4.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), 4.0);
let a = [NAN, NAN, 2.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), 2.0);
let a = [NAN, NAN, NAN].into_iter().map(|a| a.norm(Abs::new()));
assert!(supnorm_iterable(a).is_nan());
}
#[test]
fn supnorm_iterable_array_infinity() {
let a = [INFINITY, 1.0f32, 1.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), INFINITY);
let a = [3.0f32, INFINITY, 3.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), INFINITY);
}
#[test]
fn supnorm_iterable_array_infinity_nan() {
let a = [NAN, INFINITY, 2.0f32].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), INFINITY);
let a = [INFINITY, 2.0f32, NAN].into_iter().map(|a| a.norm(Abs::new()));
assert_eq!(supnorm_iterable(a), INFINITY);
}
}