1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/******************************************************************************
 * 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.
 *****************************************************************************/

//! A collection of norm descriptors.
//!
//! A norm descriptor specifies a norm. The most important ones
//! are the [`Abs`](desc::Abs)-norm for primitive floating point types
//! and complex numbers,
//! [`Sup`](desc::Sup) for the supremum norm,
//! and [`PNorm`](desc::PNorm) which represents a mathematical _p_-norm.

use std::num::NonZeroU32;

use noisy_float::prelude::R32;

/// A norm that is defined by an absolute value function on a field.
///
/// This is used for implementing the norms on types which represent
/// a mathematical field, like the primitive floating point types
/// (representing the field of real numbers) or the [`num_complex::Complex`] types
/// (representing the field of complex numbers).
///
/// It can be seen as the most _primitive_ kind of norm.
///
/// It is the only kind of norm that is used for further generic implementations,
/// i.e. there are impls of the form `impl<T: Norm<Abs>> Norm<SomeNorm> for SomeType<T>`.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Abs {}

impl Abs {
    /// Creates an `Abs` norm.
    pub fn new() -> Self {
        Abs {}
    }
}

/// A norm descriptor that represents the supremum norm.
///
/// As the supremum norm does not need additional specification,
/// there is only one value of this type: [`Sup::new()`](Sup::new).
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Sup {}

impl Sup {
    /// Creates a `Sup`.
    pub fn new() -> Self {
        Sup {}
    }
}

/// A norm descriptor that represents an integral-valued
/// _p_-norm.
///
/// Create one with [`new`](PNorm::new).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PNorm {
    pub(crate) p: NonZeroU32
}

impl Default for PNorm {
    fn default() -> Self {
        PNorm {
            p: NonZeroU32::new(2).unwrap()
        }
    }
}

impl PNorm {
    /// Creates a descriptor of the `p`-norm.
    ///
    /// # Panics
    ///
    /// If `p` is zero.
    pub fn new(p: u32) -> Self {
        PNorm {
            p: NonZeroU32::new(p).unwrap()
        }
    }

    /// Creates a descriptor of the euclidean norm, i.e. the 2-norm.
    pub fn eucl() -> Self {
        PNorm {
            p: NonZeroU32::new(2).unwrap()
        }
    }

    /// Creates a descriptor of the 1-norm.
    pub fn p1() -> Self {
        PNorm {
            p: NonZeroU32::new(1).unwrap()
        }
    }
}

/// A descriptor that represents a real-valued _p_-norm.
///
/// Create one with [`new`](PNormReal::new) or [`from_f32`](PNormReal::from_f32).
///
/// If you only need a real valued _p_, consider using
/// [`PNorm`] instead since it only calculates integral powers.
///
/// Negative values for _p_ are completely allowed and there will be no
/// bad behaviour if one tries to calculate a _p_-norm with a negative _p_,
/// but the result will probably be mathematical nonsense.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PNormReal {
    pub(crate) p: R32
}

impl PNormReal {
    /// Creates a descriptor of the `p`-norm.
    ///
    /// A “NaN-norm” or “Inf-norm” does not make sense,
    /// so p-norms are represented by a [`noisy_float`] which cannot be Nan
    /// or +/- Infinity.
    pub fn new(p: R32) -> Self {
        PNormReal {
            p
        }
    }

    /// Creates a descriptor of the `p`-norm.
    pub fn from_u16(p: u16) -> Self {
        PNormReal {
            p: R32::from_f32(<f32 as From<u16>>::from(p))
        }
    }

    /// Creates a descriptor of the `p`-norm.
    ///
    /// # Panics
    ///
    /// If `p` is NaN or +/- Infinity
    pub fn from_f32(p: f32) -> Self {
        PNormReal {
            p: R32::from_f32(p)
        }
    }

    /// Creates a descriptor of the euclidean norm, i.e. the 2-norm.
    pub fn eucl() -> Self {
        PNormReal {
            p: R32::from_f32(2.0)
        }
    }

    /// Creates a descriptor of the 1-norm.
    pub fn p1() -> Self {
        PNormReal {
            p: R32::from_f32(1.0)
        }
    }
}