norman 0.0.4

Implementations of different norms for elements of vector spaces
Documentation
/******************************************************************************
 * Copyright 2019 Manuel Simon
 * This file is part of the norman library.
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 *****************************************************************************/

//! Implementations of norms for primitive types.

use crate::desc::Abs;

use crate::{Norm, Distance};

/// Generically implements `Norm<Abs>` for the unsigned integer types
/// by simply returning the original value.
macro_rules! norm_impl_self {
    ($($t:ty)*) => ($(
        impl Norm<Abs> for $t {
            type Output = Self;
            fn norm(&self, _desc: Abs) -> <Self as Norm<Abs>>::Output {
                *self
            }
        }
        impl Distance<Abs> for $t {
            type Output = Self;
            fn distance(&self, other: &Self, _desc: Abs) -> <Self as Distance<Abs>>::Output {
                if self > other {
                    self - other
                } else {
                    other - self
                }
            }
        }
    )*)
}

/// Generically implements `Norm<Abs>` for types with an `abs` function
/// by returning the result of this function.
macro_rules! norm_impl_abs {
    ($($t:ty)*) => ($(
        impl Norm<Abs> for $t {
            type Output = Self;
            fn norm(&self, _desc: Abs) -> <Self as Norm<Abs>>::Output {
                self.abs()
            }
        }
        impl Distance<Abs> for $t {
            type Output = Self;
            fn distance(&self, other: &Self, _desc: Abs) -> <Self as Distance<Abs>>::Output {
                (self - other).abs()
            }
        }
    )*)
}

/// Generically implements `Norm<Abs>` for the signed integer types
/// by calling their `abs` function and casting to the corresponding unsinged
/// integer type.
macro_rules! norm_impl_unsigned_output {
    ($($t:ty, $out:ty);*) => ($(
        impl Norm<Abs> for $t {
            type Output = $out;
            fn norm(&self, _desc: Abs) -> <Self as Norm<Abs>>::Output {
                self.abs() as $out
            }
        }
        impl Distance<Abs> for $t {
            type Output = $out;
            fn distance(&self, other: &Self, _desc: Abs) -> <Self as Distance<Abs>>::Output {
                (self - other).abs() as $out
            }
        }
    )*)
}

norm_impl_abs!(f32 f64);
norm_impl_unsigned_output!(i8, u8; i16, u16; i32, u32; i64, u64; isize, usize);
norm_impl_self!(u8 u16 u32 u64 usize);

norm_impl_unsigned_output!(i128, u128);

norm_impl_self!(u128);


#[cfg(test)]
mod tests {
    use crate::desc::Abs;
    use crate::{Distance, Norm};
    #[test]
    fn norm_floating_point() {
        assert_eq!((-2.0f32).norm(Abs::new()), 2.0);
        assert_eq!((-3.0f64).norm(Abs::new()), 3.0);
    }

    #[test]
    fn distance_floating_point() {
        assert_eq!((5.0f32).distance(&3.0, Abs::new()), 2.0);
        assert_eq!((2.0f32).distance(&-3.0, Abs::new()), 5.0);
        assert_eq!((1.0f64).distance(&4.0, Abs::new()), 3.0);
    }

    #[test]
    fn norm_unsigned_integer() {
        assert_eq!(2u8.norm(Abs::new()), 2);
        assert_eq!(3u16.norm(Abs::new()), 3);
        assert_eq!(4u32.norm(Abs::new()), 4);
        assert_eq!(5u64.norm(Abs::new()), 5);
        assert_eq!(6u128.norm(Abs::new()), 6);
        assert_eq!(7usize.norm(Abs::new()), 7);
    }

    #[test]
    fn distance_unsigned_integer() {
        assert_eq!(2u8.distance(&4, Abs::new()), 2);
        assert_eq!(3u16.distance(&4, Abs::new()), 1);
        assert_eq!(4u32.distance(&4, Abs::new()), 0);
        assert_eq!(5u64.distance(&4, Abs::new()), 1);
        assert_eq!(6u128.distance(&4, Abs::new()), 2);
        assert_eq!(7usize.distance(&4, Abs::new()), 3);
    }

    #[test]
    fn norm_signed_integer() {
        assert_eq!((-2i8).norm(Abs::new()), 2);
        assert_eq!((3i16).norm(Abs::new()), 3);
        assert_eq!((-4i32).norm(Abs::new()), 4);
        assert_eq!((5i64).norm(Abs::new()), 5);
        assert_eq!((-5i128).norm(Abs::new()), 5);
        assert_eq!((6isize).norm(Abs::new()), 6);
    }

    #[test]
    fn distance_signed_integer() {
        assert_eq!(2i8.distance(&4, Abs::new()), 2);
        assert_eq!(3i16.distance(&-4, Abs::new()), 7);
        assert_eq!((-4i32).distance(&4, Abs::new()), 8);
        assert_eq!((-5i64).distance(&-4, Abs::new()), 1);
        assert_eq!(6i128.distance(&4, Abs::new()), 2);
        assert_eq!(7isize.distance(&4, Abs::new()), 3);
    }
}