ftl_numkernel/
functions.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
4    errors::{ComplexValueErrors, ComplexValueValidator, RealValueErrors, RealValueValidator},
5    Native64, NumKernel, TryNew, Zero,
6};
7use num::Complex;
8use std::{backtrace::Backtrace, fmt};
9use thiserror::Error;
10
11#[cfg(feature = "rug")]
12use crate::{ComplexRug, RealRug, Rug};
13
14//------------------------------------------------------------------------------------------------
15/// Errors that can occur during the computation of the square root of a real number,
16/// before the computation of the square root.
17#[derive(Debug, Error)]
18pub enum SqrtRealInputErrors<T: NumKernel + 'static> {
19    /// The input value is negative.
20    ///
21    /// This error occurs when the input value for the square root computation is negative.
22    #[error("the input value ({value:?}) is negative!")]
23    NegativeValue {
24        /// The negative input value.
25        value: T::RawRealType,
26
27        /// The backtrace of the error.
28        backtrace: Backtrace,
29    },
30
31    /// The input value (i.e. the value before the computation of the square root) is invalid.
32    ///
33    /// This error occurs when the input value for the square root computation is invalid
34    /// (i.e. NaN, infinite or sub-normal).
35    #[error("the input value is invalid!")]
36    ValidationError {
37        #[from]
38        source: RealValueErrors<T::RawRealType>,
39    },
40}
41
42/// Errors that can occur during the computation of the square root of a complex number,
43/// before the computation of the square root.
44#[derive(Debug, Error)]
45pub enum SqrtComplexInputErrors<T: NumKernel + 'static> {
46    /// The input value (i.e. the value before the computation of the square root) is invalid.
47    ///
48    /// This error occurs when the input value for the square root computation is invalid
49    /// (i.e. the real or imaginary part of the complex number is NaN, infinite or sub-normal).
50    #[error("the input value is invalid!")]
51    ValidationError {
52        /// The source error that occurred during validation.
53        #[from]
54        source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
55    },
56}
57
58/// Errors that can occur during the computation of the square root of a real number.
59#[derive(Debug, Error)]
60pub enum SqrtRealErrors<T: NumKernel + 'static> {
61    /// The input value (i.e. the value before the computation of the square root) is invalid.
62    ///
63    /// This error occurs when the input value for the square root computation is invalid.
64    #[error("the input value is invalid!")]
65    Input {
66        /// The source error that occurred during validation.
67        #[from]
68        source: SqrtRealInputErrors<T>,
69    },
70
71    /// The output value (i.e. the value after the computation of the square root) is invalid.
72    ///
73    /// This error occurs when the output value of the square root computation is invalid.
74    #[error("the output value is invalid!")]
75    Output {
76        /// The source error that occurred during validation.
77        #[from]
78        source: RealValueErrors<T::RawRealType>,
79    },
80}
81
82/// Errors that can occur during the computation of the square root of a complex number.
83#[derive(Debug, Error)]
84pub enum SqrtComplexErrors<T: NumKernel + 'static> {
85    /// The input value (i.e. the value before the computation of the square root) is invalid.
86    ///
87    /// This error occurs when the input value for the square root computation is invalid.
88    #[error("the input value is invalid!")]
89    Input {
90        /// The source error that occurred during validation.
91        #[from]
92        source: SqrtComplexInputErrors<T>,
93    },
94
95    /// The output value (i.e. the value after the computation of the square root) is invalid.
96    ///
97    /// This error occurs when the output value of the square root computation is invalid.
98    #[error("the output value is invalid!")]
99    Output {
100        /// The source error that occurred during validation.
101        #[from]
102        source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
103    },
104}
105
106/// Validation of the input real value for the square root function.
107///
108/// The input value is valid if is *finite*, *positive* and *normal*;
109fn sqrt_real_validate_input<T: NumKernel>(
110    value: T::RawRealType,
111) -> Result<T::RawRealType, SqrtRealInputErrors<T>> {
112    let v = value.validate();
113    match v {
114        Ok(value) => {
115            if value < 0. {
116                Err(SqrtRealInputErrors::NegativeValue {
117                    value,
118                    backtrace: Backtrace::force_capture(),
119                })
120            } else {
121                Ok(value)
122            }
123        }
124        Err(e) => Err(SqrtRealInputErrors::ValidationError { source: e }),
125    }
126}
127
128/// Validation of the input complex value for the square root function.
129///
130/// The input value is valid if is *finite* and *normal*;
131fn sqrt_complex_validate_input<T: NumKernel>(
132    value: T::RawComplexType,
133) -> Result<T::RawComplexType, SqrtComplexInputErrors<T>> {
134    Ok(value.validate()?)
135}
136//--------------------------------------------------------------------------------------------
137
138//--------------------------------------------------------------------------------------------
139/// This trait provides the interface for the function used to compute the square root of a number.
140pub trait Sqrt: TryNew {
141    /// The error type that can be returned by the `try_sqrt` method.
142    type Error: fmt::Debug;
143
144    /// Computes the square root of `self`, checking the input and output values for validity.
145    ///
146    /// # Validity
147    ///
148    /// - For the square root of a real number:
149    ///   - the input value is valid if is *finite*, *positive* and *normal*;
150    ///   - the output value is valid if is *finite* and *normal*.
151    /// - For the square root of a complex number:
152    ///   - The input and output values are valid if they are *finite* and *normal*.
153    ///
154    /// # Returns
155    ///
156    /// - `Ok(self)` if the square root computation is successful and the input and output values are valid.
157    /// - `Err(Self::Error)` if the input or output values are invalid.
158    fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error>;
159
160    /// Computes the square root of `self`, with no checks (in Release mode) on the validity of the input and output values.
161    ///
162    /// In Debug mode, this function internally calls the function [`Sqrt::try_sqrt()`] and a `panic!` is raised if the function returns an error.
163    ///
164    /// # Panics
165    ///
166    /// This function will panic in Debug mode if the input or output values are invalid.
167    fn sqrt(self) -> Self;
168}
169
170#[duplicate::duplicate_item(
171    T E input_validation trait_comment;
172    [f64] [SqrtRealErrors::<Native64>] [sqrt_real_validate_input] ["Implementation of the [`Sqrt`] trait for [`f64`]."];
173    [Complex::<f64>] [SqrtComplexErrors::<Native64>] [sqrt_complex_validate_input] ["Implementation of the [`Sqrt`] trait for [`Complex`]."];
174)]
175#[doc = trait_comment]
176impl Sqrt for T {
177    type Error = E;
178
179    #[inline(always)]
180    fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error> {
181        let value = input_validation(self)?;
182
183        match T::try_new(value.sqrt()) {
184            Ok(sqrt) => Ok(sqrt),
185            Err(e) => Err(E::Output { source: e }),
186        }
187    }
188
189    #[inline(always)]
190    fn sqrt(self) -> Self {
191        if cfg!(debug_assertions) {
192            self.try_sqrt().unwrap()
193        } else {
194            self.sqrt()
195        }
196    }
197}
198
199#[cfg(feature = "rug")]
200#[duplicate::duplicate_item(
201    T E input_validation trait_comment;
202    [RealRug::<PRECISION>] [SqrtRealErrors::<Rug<PRECISION>>] [sqrt_real_validate_input] ["Implementation of the [`Sqrt`] trait for [`RealRug`]."];
203    [ComplexRug::<PRECISION>] [SqrtComplexErrors::<Rug<PRECISION>>] [sqrt_complex_validate_input] ["Implementation of the [`Sqrt`] trait for [`ComplexRug`]."];
204)]
205#[doc = trait_comment]
206impl<const PRECISION: u32> Sqrt for T {
207    type Error = E;
208
209    #[inline(always)]
210    fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error> {
211        let value = input_validation(self.0)?;
212
213        match T::try_new(value.sqrt()) {
214            Ok(sqrt) => Ok(sqrt),
215            Err(e) => Err(E::Output { source: e }),
216        }
217    }
218
219    #[inline(always)]
220    fn sqrt(self) -> Self {
221        if cfg!(debug_assertions) {
222            self.try_sqrt().unwrap()
223        } else {
224            Self(self.0.sqrt())
225        }
226    }
227}
228
229//------------------------------------------------------------------------------------------------
230
231//------------------------------------------------------------------------------------------------
232/// Errors that can occur during the computation of the reciprocal of a real number.
233#[derive(Debug, Error)]
234pub enum RecipRealInputErrors<T: NumKernel + 'static> {
235    /// The input value is zero.
236    ///
237    /// This error occurs when the input value for the reciprocal computation is zero.
238    #[error("division by zero!")]
239    DivisionByZero {
240        /// The backtrace of the error.
241        backtrace: Backtrace,
242    },
243
244    /// The input value is invalid.
245    ///
246    /// This error occurs when the input value for the reciprocal computation is invalid.
247    #[error("the input value is invalid!")]
248    ValidationError {
249        /// The source error that occurred during validation.
250        #[from]
251        source: RealValueErrors<T::RawRealType>,
252    },
253}
254
255/// Errors that can occur during the computation of the reciprocal of a complex number.
256#[derive(Debug, Error)]
257pub enum RecipComplexInputErrors<T: NumKernel + 'static> {
258    /// The input value is zero.
259    ///
260    /// This error occurs when the input value for the reciprocal computation is zero.
261    #[error("division by zero!")]
262    DivisionByZero {
263        /// The backtrace of the error.
264        backtrace: Backtrace,
265    },
266
267    /// The input value is invalid.
268    ///
269    /// This error occurs when the input value for the reciprocal computation is invalid.
270    #[error("the input value is invalid!")]
271    ValidationError {
272        /// The source error that occurred during validation.
273        #[from]
274        source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
275    },
276}
277
278/// Errors that can occur during the computation of the reciprocal of a real number.
279#[derive(Debug, Error)]
280pub enum RecipRealErrors<T: NumKernel + 'static> {
281    /// The input value is invalid.
282    ///
283    /// This error occurs when the input value for the reciprocal computation is invalid.
284    #[error("the input value is invalid!")]
285    Input {
286        /// The source error that occurred during validation.
287        #[from]
288        source: RecipRealInputErrors<T>,
289    },
290
291    /// The output value is invalid.
292    ///
293    /// This error occurs when the output value of the reciprocal computation is invalid.
294    #[error("the output value is invalid!")]
295    Output {
296        /// The source error that occurred during validation.
297        #[from]
298        source: RealValueErrors<T::RawRealType>,
299    },
300}
301
302/// Errors that can occur during the computation of the reciprocal of a complex number.
303#[derive(Debug, Error)]
304pub enum RecipComplexErrors<T: NumKernel + 'static> {
305    /// The input value is invalid.
306    ///
307    /// This error occurs when the input value for the reciprocal computation is invalid.
308    #[error("the input value is invalid!")]
309    Input {
310        /// The source error that occurred during validation.
311        #[from]
312        source: RecipComplexInputErrors<T>,
313    },
314
315    /// The output value is invalid.
316    ///
317    /// This error occurs when the output value of the reciprocal computation is invalid.
318    #[error("the output value is invalid!")]
319    Output {
320        /// The source error that occurred during validation.
321        #[from]
322        source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
323    },
324}
325
326/// A trait for computing the reciprocal of a number.
327pub trait Reciprocal: TryNew {
328    /// The error type that can be returned by the `try_recip` method.
329    type Error: fmt::Debug;
330
331    /// Computes the reciprocal of `self`, checking the input and output values for validity.
332    ///
333    /// # Validity
334    ///
335    /// - The input value is valid if it is *finite*, *non-zero*, and *normal*.
336    ///
337    /// # Returns
338    ///
339    /// - `Ok(self)` if the reciprocal computation is successful and the input and output values are valid.
340    /// - `Err(Self::Error)` if the input or output values are invalid.
341    fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error>;
342
343    /// Computes the reciprocal of `self`, with no checks (in Release mode) on the validity of the input and output values.
344    ///
345    /// In Debug mode, this function internally calls the function [`Reciprocal::try_reciprocal()`] and a `panic!` is raised if the function returns an error.
346    ///
347    /// # Panics
348    ///
349    /// This function will panic in Debug mode if the input or output values are invalid.
350    fn reciprocal(self) -> Self;
351}
352
353#[duplicate::duplicate_item(
354    T implementation E  InputError trait_comment;
355    [f64] [recip()] [RecipRealErrors::<Native64>] [RecipRealInputErrors] ["Implementation of the [`Reciprocal`] trait for [`f64`]."];
356    [Complex::<f64>] [inv()]  [RecipComplexErrors::<Native64>] [RecipComplexInputErrors] ["Implementation of the [`Reciprocal`] trait for [`Complex`]."];
357)]
358impl Reciprocal for T {
359    type Error = E;
360
361    #[inline(always)]
362    fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error> {
363        match self.validate() {
364            Ok(value) => {
365                if value.is_zero() {
366                    Err(E::Input {
367                        source: InputError::DivisionByZero {
368                            backtrace: Backtrace::force_capture(),
369                        },
370                    })
371                } else {
372                    // value is different from zero, so we can "safely" compute the reciprocal
373                    match Self::try_new(value.implementation) {
374                        Ok(recip) => Ok(recip),
375                        Err(e) => Err(E::Output { source: e }),
376                    }
377                }
378            }
379            Err(e) => Err(E::Input {
380                source: InputError::ValidationError { source: e },
381            }),
382        }
383    }
384
385    #[inline(always)]
386    fn reciprocal(self) -> Self {
387        if cfg!(debug_assertions) {
388            self.try_reciprocal().unwrap()
389        } else {
390            self.implementation
391        }
392    }
393}
394
395#[cfg(feature = "rug")]
396#[duplicate::duplicate_item(
397    T E InputError trait_comment;
398    [RealRug::<PRECISION>] [RecipRealErrors::<Rug<PRECISION>>] [RecipRealInputErrors] ["Implementation of the [`Reciprocal`] trait for [`f64`]."];
399    [ComplexRug::<PRECISION>] [RecipComplexErrors::<Rug<PRECISION>>] [RecipComplexInputErrors] ["Implementation of the [`Reciprocal`] trait for [`Complex`]."];
400)]
401impl<const PRECISION: u32> Reciprocal for T {
402    type Error = E;
403
404    #[inline(always)]
405    fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error> {
406        match self.0.validate() {
407            Ok(value) => {
408                if value.is_zero() {
409                    Err(E::Input {
410                        source: InputError::DivisionByZero {
411                            backtrace: Backtrace::force_capture(),
412                        },
413                    })
414                } else {
415                    // value is different from zero, so we can "safely" compute the reciprocal
416                    match Self::try_new(value.recip()) {
417                        Ok(recip) => Ok(recip),
418                        Err(e) => Err(E::Output { source: e }),
419                    }
420                }
421            }
422            Err(e) => Err(E::Input {
423                source: InputError::ValidationError { source: e },
424            }),
425        }
426    }
427
428    #[inline(always)]
429    fn reciprocal(self) -> Self {
430        if cfg!(debug_assertions) {
431            self.try_reciprocal().unwrap()
432        } else {
433            Self(self.0.recip())
434        }
435    }
436}
437//--------------------------------------------------------------------------------------------
438
439//------------------------------------------------------------------------------------------------
440/// This trait provides the interface for the function used to compute the *absolute value* of a number.
441pub trait Abs {
442    /// The return type of the *absolute value* function. It is always a real number (also when the input is a complex number).
443    type Output;
444
445    /// Returns the *absolute value* of `self`. The return type is always a real number (also when `self` is a complex number)
446    fn abs(self) -> Self::Output;
447}
448
449#[duplicate::duplicate_item(
450    T implementation trait_comment;
451    [f64] [self.abs()] ["Implementation of the [`Abs`] trait for `f64`."];
452    [Complex<f64>] [self.norm()] ["Implementation of the [`Abs`] trait for `Complex<f64>`."];
453)]
454#[doc = trait_comment]
455impl Abs for T {
456    /// The return type of the *absolute value* function.
457    type Output = f64;
458
459    /// Returns the *absolute value* of `self`.
460    #[inline(always)]
461    fn abs(self) -> Self::Output {
462        implementation
463    }
464}
465
466#[cfg(feature = "rug")]
467#[duplicate::duplicate_item(
468    T implementation trait_comment;
469    [RealRug<PRECISION>] [RealRug(self.0.abs())] ["Implementation of the [`Abs`] trait for [`RealRug`]."];
470    [ComplexRug<PRECISION>] [RealRug(self.0.abs().real().clone())] ["Implementation of the [`Abs`] trait for [`ComplexRug`]."];
471)]
472#[doc = trait_comment]
473impl<const PRECISION: u32> Abs for T {
474    /// The return type of the *absolute value* function.
475    type Output = RealRug<PRECISION>;
476
477    /// Returns the *absolute value* of `self`.
478    #[inline(always)]
479    fn abs(self) -> Self::Output {
480        implementation
481    }
482}
483//------------------------------------------------------------------------------------------------