num_valid/
kernels.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Numerical Kernels and Validated Types
4//!
5//! This module is the core of the numerical backend for the [`num-valid`](crate) crate.
6//! It defines the fundamental traits, types, and operations for floating-point arithmetic.
7//!
8//! ## Core Architecture
9//!
10//! The architecture is built on three key concepts:
11//!
12//! 1.  **Raw Traits ([`RawScalarTrait`], [`RawRealTrait`], [`RawComplexTrait`]):**
13//!     These traits define the baseline contract for a "raw" number type (like [`f64`] or
14//!     [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html)).
15//!     They provide a comprehensive set of `unchecked_*` methods for arithmetic and mathematical
16//!     functions. The "unchecked" prefix signifies that these methods do **not** perform
17//!     any validation (e.g., for domain, finiteness, or division by zero) and are intended
18//!     for internal use where validity has already been confirmed.
19//!
20//! 2.  **Validated Structs ([`RealValidated`], [`ComplexValidated`]):**
21//!     These are wrapper types (newtypes) that enforce correctness. An instance of `RealValidated<P>`
22//!     is guaranteed to hold a raw value that has been successfully validated against the policy `P`.
23//!     All operations on these types (addition, `sqrt`, etc.) are designed to preserve this validity,
24//!     either by returning a `Result` or by panicking on failure in debug builds.
25//!
26//! 3.  **Validation Policies ([`NumKernel`]):**
27//!     This trait allows the validation strategy to be generic. A kernel can be configured with
28//!     different policies, such as [`NumKernelStrictFinite`], which ensures all numbers are
29//!     finite (not NaN or Infinity).
30//!
31//! ## Available Kernels
32//!
33//! The library provides concrete kernels that bundle these concepts:
34//!
35//! - **`native64`:** Uses Rust's standard [`f64`] and `num::Complex<f64>` as the raw types.
36//!   This is the default, high-performance kernel.
37//!
38//! - **`rug` (feature-gated):** Uses arbitrary-precision types from the [`rug`](https://crates.io/crates/rug) crate,
39//!   ideal for high-precision scientific computing.
40
41pub mod native64;
42pub mod native64_validated;
43mod validated;
44
45#[cfg(feature = "rug")]
46pub mod rug;
47
48pub use validated::{ComplexValidated, RealValidated};
49
50use crate::{
51    ComplexScalar, Conjugate, FpChecks, NegAssign, NeumaierAddable, RealScalar,
52    functions::{Rounding, Sign},
53    validation::{
54        DebugValidationPolicy, ErrorsRawRealToInteger, ErrorsTryFromf64,
55        ErrorsValidationRawComplex, ErrorsValidationRawReal, StrictFinitePolicy,
56        ValidationPolicyComplex, ValidationPolicyReal, capture_backtrace,
57    },
58};
59use az::CheckedAs;
60use duplicate::duplicate_item;
61use num::{Complex, Zero};
62use num_traits::{MulAdd, MulAddAssign};
63use serde::{Deserialize, Serialize};
64use std::{
65    cmp::Ordering,
66    fmt::{Debug, Display},
67    hash::{Hash, Hasher},
68    marker::PhantomData,
69    num::FpCategory,
70    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
71};
72
73/// A baseline trait for raw scalar types, defining core operations and properties.
74///
75/// This trait must be implemented by the underlying number types used in a kernel,
76/// such as like [`f64`] or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
77/// It provides a standard interface for arithmetic
78/// and a suite of `unchecked_*` methods for mathematical functions.
79///
80/// ## Hashing Support
81///
82/// All raw scalar types (both real and complex) must implement [`compute_hash()`](Self::compute_hash),
83/// which provides a consistent hashing mechanism. The hash implementation must ensure:
84///
85/// - **Mathematical Equality**: Values that are mathematically equal produce identical hashes
86/// - **Signed Zero Handling**: Both `+0.0` and `-0.0` hash to the same value
87/// - **Finite Values Only**: The hash is only well-defined for finite values (not NaN or infinity)
88/// - **Consistency**: The same value always produces the same hash across multiple calls
89///
90/// For complex numbers, the hash is computed by sequentially hashing the real and imaginary
91/// parts, ensuring that different complex numbers produce different hashes while maintaining
92/// the equality invariant.
93///
94/// This enables validated wrapper types to implement [`Hash`] when their validation
95/// policies guarantee finite values (via [`crate::validation::GuaranteesFiniteValues`]),
96/// allowing them to be used as keys in [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
97///
98/// # Safety and Contracts
99///
100/// The `unchecked_*` methods are designed for performance and assume that the caller
101/// has already validated the inputs. Calling them with invalid data (e.g., `unchecked_sqrt`
102/// on a negative real number) may lead to panics, incorrect results, or undefined behavior,
103/// depending on the underlying type's implementation.
104pub trait RawScalarTrait:
105    Serialize + for<'a> Deserialize<'a>
106    + Debug
107    + Display
108    + Clone
109    + Sync
110    + Send
111    + Add<Output = Self>
112    + Sub<Output = Self>
113    + Mul<Output = Self>
114    + Div<Output = Self>
115    + for<'a> Add<&'a Self, Output = Self>
116    + for<'a> Sub<&'a Self, Output = Self>
117    + for<'a> Mul<&'a Self, Output = Self>
118    + for<'a> Div<&'a Self, Output = Self>
119    + AddAssign
120    + SubAssign
121    + MulAssign
122    + DivAssign
123    + for<'a> AddAssign<&'a Self>
124    + for<'a> SubAssign<&'a Self>
125    + for<'a> MulAssign<&'a Self>
126    + for<'a> DivAssign<&'a Self>
127    + Neg<Output = Self>
128    + NegAssign
129    + NeumaierAddable
130    + PartialEq
131//    + MulAddRef
132    + FpChecks
133    + 'static
134{
135    /// The associated error type for validation failures of this raw type.
136    type ValidationErrors: std::error::Error;
137
138    fn is_zero(&self) -> bool;
139
140    fn raw_zero(precision: u32) -> Self;
141
142    fn raw_one(precision: u32) -> Self;
143
144    fn raw_negative_one(precision: u32) -> Self {
145        Self::raw_one(precision).neg()
146    }
147
148    /// Computes the reciprocal (1/x) without validation.
149    /// 
150    /// **Contract:** The caller must ensure `self` is not zero.
151    fn unchecked_reciprocal(self) -> Self;
152
153    /// Computes the exponential (e^x) without validation.
154    /// 
155    /// **Contract:** The caller must ensure the input is valid.
156    fn unchecked_exp(self) -> Self;
157
158    /// Computes the square root without validation.
159    /// 
160    /// **Contract:** For real numbers, the caller must ensure `self >= 0`.
161    fn unchecked_sqrt(self) -> Self;
162
163    fn unchecked_sin(self) -> Self;
164
165    fn unchecked_asin(self) -> Self;
166
167    fn unchecked_cos(self) -> Self;
168
169    fn unchecked_acos(self) -> Self;
170
171    fn unchecked_tan(self) -> Self;
172
173    fn unchecked_atan(self) -> Self;
174
175    fn unchecked_sinh(self) -> Self;
176
177    fn unchecked_asinh(self) -> Self;
178
179    fn unchecked_cosh(self) -> Self;
180
181    fn unchecked_acosh(self) -> Self;
182
183    fn unchecked_tanh(self) -> Self;
184
185    fn unchecked_atanh(self) -> Self;
186
187    fn unchecked_ln(self) -> Self;
188    fn unchecked_log2(self) -> Self;
189    fn unchecked_log10(self) -> Self;
190
191    /// Raises `self` to the power of an `i8` exponent without validation.
192    /// 
193    /// **Contract:** The caller must ensure the inputs are valid.
194    fn unchecked_pow_exponent_i8(self, exponent: &i8) -> Self;
195
196    /// Raises `self` to the power of an `i16` exponent without validation.
197    /// 
198    /// **Contract:** The caller must ensure the inputs are valid.
199    fn unchecked_pow_exponent_i16(self, exponent: &i16) -> Self;
200
201    /// Raises `self` to the power of an `i32` exponent without validation.
202    /// 
203    /// **Contract:** The caller must ensure the inputs are valid.
204    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self;
205
206    /// Raises `self` to the power of an `i64` exponent without validation.
207    /// 
208    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
209    /// includes ensuring the `exponent` is within the representable range of the underlying
210    /// power function (e.g., `i32` for `f64::powi`).
211    fn unchecked_pow_exponent_i64(self, exponent: &i64) -> Self;
212
213    /// Raises `self` to the power of an `i128` exponent without validation.
214    /// 
215    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
216    /// includes ensuring the `exponent` is within the representable range of the underlying
217    /// power function (e.g., `i32` for `f64::powi`).
218    fn unchecked_pow_exponent_i128(self, exponent: &i128) -> Self;
219
220    /// Raises `self` to the power of an `isize` exponent without validation.
221    /// 
222    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
223    /// includes ensuring the `exponent` is within the representable range of the underlying
224    /// power function (e.g., `i32` for `f64::powi`).
225    fn unchecked_pow_exponent_isize(self, exponent: &isize) -> Self;
226
227    /// Raises `self` to the power of an `u8` exponent without validation.
228    /// 
229    /// **Contract:** The caller must ensure the inputs are valid.
230    fn unchecked_pow_exponent_u8(self, exponent: &u8) -> Self;
231
232    /// Raises `self` to the power of an `u16` exponent without validation.
233    /// 
234    /// **Contract:** The caller must ensure the inputs are valid.
235    fn unchecked_pow_exponent_u16(self, exponent: &u16) -> Self;
236
237    /// Raises `self` to the power of an `u32` exponent without validation.
238    /// 
239    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
240    /// includes ensuring the `exponent` is within the representable range of the underlying
241    /// power function (e.g., `i32` for `f64::powi`).
242    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self;
243
244    /// Raises `self` to the power of an `u64` exponent without validation.
245    /// 
246    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
247    /// includes ensuring the `exponent` is within the representable range of the underlying
248    /// power function (e.g., `i32` for `f64::powi`).
249    fn unchecked_pow_exponent_u64(self, exponent: &u64) -> Self;
250
251    /// Raises `self` to the power of an `u128` exponent without validation.
252    /// 
253    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
254    /// includes ensuring the `exponent` is within the representable range of the underlying
255    /// power function (e.g., `i32` for `f64::powi`).
256    fn unchecked_pow_exponent_u128(self, exponent: &u128) -> Self;
257
258    /// Raises `self` to the power of an `usize` exponent without validation.
259    /// 
260    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
261    /// includes ensuring the `exponent` is within the representable range of the underlying
262    /// power function (e.g., `i32` for `f64::powi`).
263    fn unchecked_pow_exponent_usize(self, exponent: &usize) -> Self;
264
265    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
266    ///
267    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
268    ///
269    /// **Contract:** The caller must ensure all inputs are valid.
270    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self;
271
272    /// Computes a hash value for this scalar (real or complex).
273    ///
274    /// This method must ensure that mathematically equal values produce
275    /// the same hash, even across different representations (e.g., +0.0 and -0.0).
276    ///
277    /// For complex numbers, implementations should hash the real and imaginary
278    /// parts sequentially to ensure distinct complex numbers have different hashes.
279    ///
280    /// # Implementation Notes
281    ///
282    /// - For real numbers: Hash the value directly, normalizing signed zeros
283    /// - For complex numbers: Call `compute_hash()` on real part, then imaginary part
284    ///
285    /// # Debug Assertions
286    ///
287    /// Implementations should include a debug assertion that the value is finite,
288    /// as hashing non-finite values may lead to inconsistent results.
289    fn compute_hash<H: Hasher>(&self, state: &mut H);
290}
291
292/// A trait for raw real scalar types, extending [`RawScalarTrait`] with real-specific operations.
293///
294/// This trait defines the fundamental operations for real number types without
295/// validation or safety checks. Implementations should assume inputs are valid
296/// and focus on computational efficiency.
297///
298/// This trait is implemented by the underlying real number types within a kernel, such as [`f64`]
299/// or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
300/// It builds upon [`RawScalarTrait`] by adding operations that are unique
301/// to real numbers, like `atan2`, and by enforcing an ordering relationship.
302///
303/// ## Hashing Support
304///
305/// Types implementing this trait must provide a `compute_hash` method that:
306/// - Produces consistent hash values for mathematically equal numbers
307/// - Handles floating-point edge cases (like signed zeros) correctly  
308/// - Maintains the contract that `a == b` implies `hash(a) == hash(b)`
309///
310/// This enables validated wrapper types to implement [`Hash`] when appropriate
311/// validation policies guarantee finite values.
312///
313/// # Trait Bounds
314///
315/// - `RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>`: Ensures that the type
316///   is a raw scalar and that its validation error type is the standard one for real numbers.
317/// - [`PartialOrd`]: Requires that the type can be partially ordered, which is fundamental for
318///   real numbers.
319/// - [`PartialOrd<f64>`]: These crucial bounds allow instances of the raw
320///   real type to be directly compared with `f64` constants. This is essential for implementing
321///   domain checks (e.g., `value < 0.0` or `value >= 0.0`) that work across
322///   both [`f64`] and [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html) without extra conversions.
323///
324/// # Associated Types
325///
326/// - `type RawComplex: RawComplexTrait<RawReal = Self>`: This links the raw real type to its
327///   corresponding complex number representation. For example, for [`f64`], this would be
328///   [`num::Complex<f64>`]. This association is vital for operations that can transition
329///   from the real to the complex domain.
330pub trait RawRealTrait:
331    RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>
332    + PartialOrd
333    + PartialOrd<f64>
334    + Sign
335    + Rounding
336{
337    /// The associated complex type that uses this type as its real part.
338    type RawComplex: RawComplexTrait<RawReal = Self>;
339
340    /// Computes the absolute value of `self` without validation.
341    ///
342    /// **Contract:** The caller must ensure that the input value has already been validated
343    /// and is suitable for the operation.
344    fn unchecked_abs(self) -> Self;
345
346    /// Computes the four-quadrant arctangent of `self` (`y`) and `denominator` (`x`) without validation.
347    ///
348    /// **Contract:** The caller must ensure that `self` and `denominator` are not both zero.
349    fn unchecked_atan2(self, denominator: &Self) -> Self;
350
351    /// Raises `self` to the power of a real `exponent` without validation.
352    ///
353    /// **Contract:** The caller must ensure the inputs are valid for the power function. For
354    /// example, if `self` is negative, the `exponent` should be an integer, but this function
355    /// does not enforce this.
356    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self;
357
358    fn unchecked_hypot(self, other: &Self) -> Self;
359
360    fn unchecked_ln_1p(self) -> Self;
361
362    fn unchecked_exp_m1(self) -> Self;
363
364    /// Multiplies two pairs and adds them, rounding to the nearest.
365    /// `a.unchecked_mul_add_mul_mut(&b, &c, &d)` produces a result like `&a * &b + &c * &d`, but stores the result in `a` using its precision.
366    ///
367    /// **Contract:** The caller must ensure all inputs are valid.
368    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self);
369
370    /// Multiplies two pairs and subtracts them, rounding to the nearest.
371    /// `a.unchecked_mul_sub_mul_mut(&b, &c, &d)` produces a result like `&a * &b - &c * &d`, but stores the result in `a` using its precision.
372    ///
373    /// **Contract:** The caller must ensure all inputs are valid.
374    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self);
375
376    fn raw_total_cmp(&self, other: &Self) -> Ordering;
377
378    /// Clamps the value within the specified bounds.
379    fn raw_clamp(self, min: &Self, max: &Self) -> Self;
380
381    fn raw_classify(&self) -> FpCategory;
382
383    fn raw_two(precision: u32) -> Self;
384
385    fn raw_one_div_2(precision: u32) -> Self;
386
387    fn raw_pi(precision: u32) -> Self;
388
389    fn raw_two_pi(precision: u32) -> Self;
390
391    fn raw_pi_div_2(precision: u32) -> Self;
392
393    fn raw_max_finite(precision: u32) -> Self;
394
395    fn raw_min_finite(precision: u32) -> Self;
396
397    fn raw_epsilon(precision: u32) -> Self;
398
399    fn raw_ln_2(_precision: u32) -> Self;
400
401    fn raw_ln_10(_precision: u32) -> Self;
402
403    fn raw_log10_2(_precision: u32) -> Self;
404
405    fn raw_log2_10(_precision: u32) -> Self;
406
407    fn raw_log2_e(_precision: u32) -> Self;
408
409    fn raw_log10_e(_precision: u32) -> Self;
410
411    fn raw_e(_precision: u32) -> Self;
412
413    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
414        value: f64,
415    ) -> Result<Self, ErrorsTryFromf64<Self>>;
416
417    /// Returns the precision (in bits) of the raw real type.
418    fn precision(&self) -> u32;
419
420    /// Safely converts the truncated value to `usize`.
421    ///
422    /// Truncates toward zero and validates the result is a valid `usize`.
423    ///
424    /// # Returns
425    ///
426    /// - `Ok(usize)`: If truncated value is in `0..=usize::MAX`
427    /// - `Err(ErrorsRawRealToInteger)`: If value is not finite or out of range
428    ///   - `NotFinite`: Value is `NaN` or `±∞`
429    ///   - `OutOfRange`: Value is negative or > `usize::MAX`
430    ///
431    /// # Note
432    ///
433    /// The `NotAnInteger` error variant is not returned because truncation
434    /// explicitly handles the fractional part.
435    ///
436    /// # Examples
437    ///
438    /// ```
439    /// # use num_valid::kernels::RawRealTrait;
440    /// let value = 42.9_f64;
441    /// assert_eq!(value.truncate_to_usize().unwrap(), 42);
442    ///
443    /// let zero = 0.0_f64;
444    /// assert_eq!(zero.truncate_to_usize().unwrap(), 0);
445    /// ```
446    ///
447    /// ## Error cases
448    ///
449    /// ```
450    /// # use num_valid::kernels::RawRealTrait;
451    /// # use num_valid::validation::ErrorsRawRealToInteger;
452    /// // Negative value
453    /// let neg = -10.5_f64;
454    /// assert!(matches!(neg.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
455    ///
456    /// // Too large for usize
457    /// let large = (usize::MAX as f64) + 100.0;
458    /// assert!(matches!(large.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
459    ///
460    /// // Not finite
461    /// let nan = f64::NAN;
462    /// assert!(matches!(nan.truncate_to_usize(), Err(ErrorsRawRealToInteger::NotFinite { .. })));
463    /// ```
464    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<Self, usize>>;
465}
466
467/// A trait for raw complex scalar types, extending [`RawScalarTrait`].
468///
469/// This trait is implemented by the underlying complex number types within a kernel,
470/// such as [`num::Complex<f64>`]. It builds upon [`RawScalarTrait`] by adding operations
471/// that are unique to complex numbers.
472///
473/// # Trait Bounds
474///
475/// - `RawScalarTrait<...>`: Ensures the type is a raw scalar and fixes its validation
476///   error type to [`ErrorsValidationRawComplex`], which in turn wraps the validation
477///   error of the associated real type. This establishes a consistent error structure.
478/// - [`Conjugate`]: Requires that the complex number can be conjugated.
479///
480/// # Associated Types
481///
482/// - `type RawReal: RawRealTrait<RawComplex = Self>`: This is a critical part of the
483///   design. It links the complex type to its underlying real component type (e.g., [`f64`]
484///   for [`num::Complex<f64>`]). This associated real type must itself implement [`RawRealTrait`],
485///   creating a two-way link between the real and complex raw types.
486///
487/// # Methods
488///
489/// This trait provides methods for accessing components and performing complex-specific
490/// mathematical operations without validation checks.
491pub trait RawComplexTrait:
492    RawScalarTrait<
493        ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<Self::RawReal>>,
494    > + Conjugate
495    + for<'a> Mul<&'a Self::RawReal, Output = Self>
496    + for<'a> MulAssign<&'a Self::RawReal>
497{
498    /// The associated real type that makes up the components of this complex type.
499    type RawReal: RawRealTrait<RawComplex = Self>;
500
501    fn new_unchecked_raw_complex(real: Self::RawReal, imag: Self::RawReal) -> Self;
502
503    /// Computes the absolute value (modulus or norm) of `self` without validation.
504    ///
505    /// **Contract:** The caller must ensure the input is valid for this operation.
506    fn unchecked_abs(self) -> Self::RawReal;
507
508    /// Returns a reference to the real part of the complex number.
509    fn raw_real_part(&self) -> &Self::RawReal;
510
511    /// Returns a reference to the imaginary part of the complex number.
512    fn raw_imag_part(&self) -> &Self::RawReal;
513
514    /// Returns a mutable reference to the real part of the complex number.
515    fn mut_raw_real_part(&mut self) -> &mut Self::RawReal;
516
517    /// Returns a mutable reference to the imaginary part of the complex number.
518    fn mut_raw_imag_part(&mut self) -> &mut Self::RawReal;
519
520    /// Computes the argument (or phase) of `self` in radians, without validation.
521    ///
522    /// **Contract:** The caller must ensure that `self` is not zero.
523    fn unchecked_arg(self) -> Self::RawReal;
524
525    /// Raises `self` to the power of a real `exponent` without validation.
526    ///
527    /// **Contract:** The caller must ensure the inputs are valid for the power function.
528    fn unchecked_pow_exponent_real(self, exponent: &Self::RawReal) -> Self;
529}
530
531impl RawScalarTrait for f64 {
532    type ValidationErrors = ErrorsValidationRawReal<f64>;
533
534    #[inline(always)]
535    fn raw_zero(_precision: u32) -> f64 {
536        0.
537    }
538
539    #[inline(always)]
540    fn is_zero(&self) -> bool {
541        <Self as Zero>::is_zero(self)
542    }
543    #[inline(always)]
544    fn raw_one(_precision: u32) -> f64 {
545        1.
546    }
547
548    #[duplicate_item(
549        unchecked_method       method;
550        [unchecked_reciprocal] [recip];
551        [unchecked_exp]        [exp];
552        [unchecked_sqrt]       [sqrt];
553        [unchecked_sin]        [sin];
554        [unchecked_asin]       [asin];
555        [unchecked_cos]        [cos];
556        [unchecked_acos]       [acos];
557        [unchecked_tan]        [tan];
558        [unchecked_atan]       [atan];
559        [unchecked_sinh]       [sinh];
560        [unchecked_asinh]      [asinh];
561        [unchecked_cosh]       [cosh];
562        [unchecked_acosh]      [acosh];
563        [unchecked_tanh]       [tanh];
564        [unchecked_atanh]      [atanh];
565        [unchecked_ln]         [ln];
566        [unchecked_log2]       [log2];
567        [unchecked_log10]      [log10];
568    )]
569    #[inline(always)]
570    fn unchecked_method(self) -> f64 {
571        f64::method(self)
572    }
573
574    #[duplicate_item(
575        unchecked_method             exponent_type;
576        [unchecked_pow_exponent_i8]  [i8];
577        [unchecked_pow_exponent_i16] [i16];
578        [unchecked_pow_exponent_u8]  [u8];
579        [unchecked_pow_exponent_u16] [u16];
580    )]
581    #[inline(always)]
582    fn unchecked_method(self, exponent: &exponent_type) -> f64 {
583        f64::powi(self, (*exponent).into())
584    }
585
586    #[inline(always)]
587    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
588        f64::powi(self, *exponent)
589    }
590
591    #[duplicate_item(
592        unchecked_method               exponent_type;
593        [unchecked_pow_exponent_i64]   [i64];
594        [unchecked_pow_exponent_i128]  [i128];
595        [unchecked_pow_exponent_isize] [isize];
596        [unchecked_pow_exponent_u32]   [u32];
597        [unchecked_pow_exponent_u64]   [u64];
598        [unchecked_pow_exponent_u128]  [u128];
599        [unchecked_pow_exponent_usize] [usize];
600    )]
601    #[inline(always)]
602    fn unchecked_method(self, exponent: &exponent_type) -> f64 {
603        f64::powi(
604            self,
605            (*exponent)
606                .try_into()
607                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
608        )
609    }
610
611    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
612    ///
613    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
614    #[inline(always)]
615    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
616        f64::mul_add(self, *b, *c)
617    }
618
619    #[inline(always)]
620    fn compute_hash<H: Hasher>(&self, state: &mut H) {
621        debug_assert!(
622            self.is_finite(),
623            "Hashing a non-finite f64 value (i.e., NaN or Infinity) may lead to inconsistent results."
624        );
625        if self == &0.0 {
626            // Hash all zeros (positive and negative) to the same value
627            0.0f64.to_bits().hash(state);
628        } else {
629            self.to_bits().hash(state);
630        }
631    }
632}
633
634impl RawRealTrait for f64 {
635    type RawComplex = Complex<f64>;
636
637    #[inline(always)]
638    fn unchecked_abs(self) -> f64 {
639        f64::abs(self)
640    }
641
642    #[inline(always)]
643    fn unchecked_atan2(self, denominator: &Self) -> Self {
644        f64::atan2(self, *denominator)
645    }
646
647    #[inline(always)]
648    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
649        f64::powf(self, *exponent)
650    }
651
652    #[inline(always)]
653    fn unchecked_hypot(self, other: &Self) -> Self {
654        f64::hypot(self, *other)
655    }
656
657    #[inline(always)]
658    fn unchecked_ln_1p(self) -> Self {
659        f64::ln_1p(self)
660    }
661
662    #[inline(always)]
663    fn unchecked_exp_m1(self) -> Self {
664        f64::exp_m1(self)
665    }
666
667    /// Multiplies two pairs and adds them in one fused operation, rounding to the nearest with only one rounding error.
668    /// `a.unchecked_mul_add_mul_mut(&b, &c, &d)` produces a result like `&a * &b + &c * &d`, but stores the result in `a` using its precision.
669    #[inline(always)]
670    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
671        self.mul_add_assign(*mul, add_mul1 * add_mul2);
672    }
673
674    /// Multiplies two pairs and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
675    /// `a.unchecked_mul_sub_mul_mut(&b, &c, &d)` produces a result like `&a * &b - &c * &d`, but stores the result in `a` using its precision.
676    #[inline(always)]
677    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
678        self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
679    }
680
681    #[inline(always)]
682    fn raw_total_cmp(&self, other: &Self) -> Ordering {
683        f64::total_cmp(self, other)
684    }
685
686    /// Clamps the value within the specified bounds.
687    #[inline(always)]
688    fn raw_clamp(self, min: &Self, max: &Self) -> Self {
689        f64::clamp(self, *min, *max)
690    }
691
692    #[inline(always)]
693    fn raw_classify(&self) -> FpCategory {
694        f64::classify(*self)
695    }
696
697    #[inline(always)]
698    fn raw_two(_precision: u32) -> Self {
699        2.
700    }
701
702    #[inline(always)]
703    fn raw_one_div_2(_precision: u32) -> Self {
704        0.5
705    }
706
707    #[inline(always)]
708    fn raw_pi(_precision: u32) -> Self {
709        std::f64::consts::PI
710    }
711
712    #[inline(always)]
713    fn raw_two_pi(_precision: u32) -> Self {
714        2. * std::f64::consts::PI
715    }
716
717    #[inline(always)]
718    fn raw_pi_div_2(_precision: u32) -> Self {
719        std::f64::consts::FRAC_PI_2
720    }
721
722    #[inline(always)]
723    fn raw_max_finite(_precision: u32) -> Self {
724        f64::MAX
725    }
726
727    #[inline(always)]
728    fn raw_min_finite(_precision: u32) -> Self {
729        f64::MIN
730    }
731
732    #[inline(always)]
733    fn raw_epsilon(_precision: u32) -> Self {
734        f64::EPSILON
735    }
736
737    #[inline(always)]
738    fn raw_ln_2(_precision: u32) -> Self {
739        std::f64::consts::LN_2
740    }
741
742    #[inline(always)]
743    fn raw_ln_10(_precision: u32) -> Self {
744        std::f64::consts::LN_10
745    }
746
747    #[inline(always)]
748    fn raw_log10_2(_precision: u32) -> Self {
749        std::f64::consts::LOG10_2
750    }
751
752    #[inline(always)]
753    fn raw_log2_10(_precision: u32) -> Self {
754        std::f64::consts::LOG2_10
755    }
756
757    #[inline(always)]
758    fn raw_log2_e(_precision: u32) -> Self {
759        std::f64::consts::LOG2_E
760    }
761
762    #[inline(always)]
763    fn raw_log10_e(_precision: u32) -> Self {
764        std::f64::consts::LOG10_E
765    }
766
767    #[inline(always)]
768    fn raw_e(_precision: u32) -> Self {
769        std::f64::consts::E
770    }
771
772    #[inline(always)]
773    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
774        value: f64,
775    ) -> Result<Self, ErrorsTryFromf64<f64>> {
776        RealPolicy::validate(value).map_err(|e| ErrorsTryFromf64::Output { source: e })
777    }
778
779    #[inline(always)]
780    fn precision(&self) -> u32 {
781        53 // f64 has 53 bits of precision
782    }
783
784    #[inline(always)]
785    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<f64, usize>> {
786        if !self.is_finite() {
787            return Err(ErrorsRawRealToInteger::NotFinite {
788                value: self,
789                backtrace: capture_backtrace(),
790            });
791        }
792
793        match self.checked_as::<usize>() {
794            Some(value) => Ok(value),
795            None => Err(ErrorsRawRealToInteger::OutOfRange {
796                value: self,
797                min: usize::MIN,
798                max: usize::MAX,
799                backtrace: capture_backtrace(),
800            }),
801        }
802    }
803}
804
805impl RawScalarTrait for Complex<f64> {
806    type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<f64>>;
807
808    #[inline(always)]
809    fn raw_zero(_precision: u32) -> Self {
810        Complex::new(0., 0.)
811    }
812
813    #[inline(always)]
814    fn is_zero(&self) -> bool {
815        <Self as Zero>::is_zero(self)
816    }
817
818    #[inline(always)]
819    fn raw_one(_precision: u32) -> Self {
820        Complex::new(1., 0.)
821    }
822
823    #[duplicate_item(
824        unchecked_method       method;
825        [unchecked_exp]        [exp];
826        [unchecked_sqrt]       [sqrt];
827        [unchecked_sin]        [sin];
828        [unchecked_asin]       [asin];
829        [unchecked_cos]        [cos];
830        [unchecked_acos]       [acos];
831        [unchecked_tan]        [tan];
832        [unchecked_atan]       [atan];
833        [unchecked_sinh]       [sinh];
834        [unchecked_asinh]      [asinh];
835        [unchecked_cosh]       [cosh];
836        [unchecked_acosh]      [acosh];
837        [unchecked_tanh]       [tanh];
838        [unchecked_atanh]      [atanh];
839        [unchecked_ln]         [ln];
840        [unchecked_log10]      [log10];
841    )]
842    #[inline(always)]
843    fn unchecked_method(self) -> Self {
844        Complex::<f64>::method(self)
845    }
846
847    #[inline(always)]
848    fn unchecked_reciprocal(self) -> Self {
849        Complex::<f64>::inv(&self)
850    }
851
852    #[inline(always)]
853    fn unchecked_log2(self) -> Self {
854        Complex::<f64>::ln(self) / std::f64::consts::LN_2
855    }
856
857    #[duplicate_item(
858        unchecked_method             exponent_type;
859        [unchecked_pow_exponent_i8]  [i8];
860        [unchecked_pow_exponent_i16] [i16];
861    )]
862    #[inline(always)]
863    fn unchecked_method(self, exponent: &exponent_type) -> Self {
864        Complex::<f64>::powi(&self, (*exponent).into())
865    }
866
867    #[inline(always)]
868    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
869        Complex::<f64>::powi(&self, *exponent)
870    }
871
872    #[duplicate_item(
873        unchecked_method               exponent_type;
874        [unchecked_pow_exponent_i64]   [i64];
875        [unchecked_pow_exponent_i128]  [i128];
876        [unchecked_pow_exponent_isize] [isize];
877    )]
878    #[inline(always)]
879    fn unchecked_method(self, exponent: &exponent_type) -> Self {
880        Complex::<f64>::powi(
881            &self,
882            (*exponent)
883                .try_into()
884                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
885        )
886    }
887
888    #[duplicate_item(
889        unchecked_method             exponent_type;
890        [unchecked_pow_exponent_u8]  [u8];
891        [unchecked_pow_exponent_u16] [u16];
892    )]
893    #[inline(always)]
894    fn unchecked_method(self, exponent: &exponent_type) -> Self {
895        Complex::<f64>::powu(&self, (*exponent).into())
896    }
897
898    #[inline(always)]
899    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
900        Complex::<f64>::powu(&self, *exponent)
901    }
902
903    #[duplicate_item(
904        unchecked_method               exponent_type;
905        [unchecked_pow_exponent_u64]   [u64];
906        [unchecked_pow_exponent_u128]  [u128];
907        [unchecked_pow_exponent_usize] [usize];
908    )]
909    #[inline(always)]
910    fn unchecked_method(self, exponent: &exponent_type) -> Self {
911        Complex::<f64>::powu(
912            &self,
913            (*exponent)
914                .try_into()
915                .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
916        )
917    }
918
919    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
920    ///
921    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
922    #[inline(always)]
923    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
924        Complex::<f64>::mul_add(self, *b, *c)
925    }
926
927    fn compute_hash<H: Hasher>(&self, state: &mut H) {
928        self.raw_real_part().compute_hash(state);
929        self.raw_imag_part().compute_hash(state);
930    }
931}
932
933impl RawComplexTrait for Complex<f64> {
934    type RawReal = f64;
935
936    fn new_unchecked_raw_complex(real: f64, imag: f64) -> Self {
937        Complex::<f64>::new(real, imag)
938    }
939
940    /// Returns a mutable reference to the real part of the complex number.
941    fn mut_raw_real_part(&mut self) -> &mut f64 {
942        &mut self.re
943    }
944
945    /// Returns a mutable reference to the imaginary part of the complex number.
946    fn mut_raw_imag_part(&mut self) -> &mut f64 {
947        &mut self.im
948    }
949
950    #[inline(always)]
951    fn unchecked_abs(self) -> f64 {
952        Complex::<f64>::norm(self)
953    }
954
955    #[inline(always)]
956    fn raw_real_part(&self) -> &f64 {
957        &self.re
958    }
959
960    #[inline(always)]
961    fn raw_imag_part(&self) -> &f64 {
962        &self.im
963    }
964
965    #[inline(always)]
966    fn unchecked_arg(self) -> f64 {
967        Complex::<f64>::arg(self)
968    }
969
970    #[inline(always)]
971    fn unchecked_pow_exponent_real(self, exponent: &f64) -> Self {
972        Complex::<f64>::powf(self, *exponent)
973    }
974}
975//------------------------------------------------------------------------------------------------------------
976
977//------------------------------------------------------------------------------------------------------------
978/// Defines the identity of a raw numerical kernel by associating its fundamental types.
979///
980/// This trait acts as a low-level building block that groups the core "raw"
981/// types of a numerical backend. It specifies which concrete types implement
982/// [`RawRealTrait`] and [`RawComplexTrait`] for a given kernel.
983///
984/// It is primarily used as a supertrait for [`NumKernel`], which extends
985/// this type-level association with concrete validation logic and precision information.
986pub trait RawKernel: Send + Sync + 'static {
987    /// The raw real type associated with this kernel (e.g., [`f64`]).
988    type RawReal: RawRealTrait;
989
990    /// The raw complex type associated with this kernel (e.g., [`Complex<f64>`]).
991    type RawComplex: RawComplexTrait<RawReal = Self::RawReal>;
992}
993//------------------------------------------------------------------------------------------------------------
994
995//------------------------------------------------------------------------------------------------------------
996/// Defines a complete numerical kernel, acting as the central configuration point.
997///
998/// This trait is the primary bound for generic functions that need to operate
999/// across different numerical backends. It bundles together:
1000/// 1.  The raw underlying types (e.g., `f64`) via the [`RawKernel`] supertrait.
1001/// 2.  The specific validation logic for those types.
1002/// 3.  The precision of the kernel in bits.
1003/// 4.  The final, high-level `Real` and `Complex` validated types.
1004pub trait NumKernel: RawKernel + Sized {
1005    /// The precision of the kernel in bits (e.g., `53` for `f64`).
1006    const PRECISION: u32;
1007
1008    /// The validation policy for real numbers.
1009    ///
1010    /// # Note
1011    /// The bound on `ValidationPolicyReal::Error` is a critical architectural choice. It enforces that the
1012    /// error type defined by a policy (`RealPolicy::Error`) MUST be the same as the
1013    /// canonical validation error type associated with its value (`RealPolicy::Value::ValidationErrors`).
1014    /// This prevents mismatches and simplifies error handling throughout the library.
1015    type RealPolicy: ValidationPolicyReal<
1016            Value = Self::RawReal,
1017            Error = <Self::RawReal as RawScalarTrait>::ValidationErrors,
1018        >;
1019
1020    /// The validation policy for complex numbers.
1021    ///
1022    /// # Note
1023    /// The bound on `ValidationPolicyComplex::Error` is a critical architectural choice. It enforces that the
1024    /// error type defined by a policy (`ComplexPolicy::Error`) MUST be the same as the
1025    /// canonical validation error type associated with its value (`ComplexPolicy::Value::ValidationErrors`).
1026    /// This prevents mismatches and simplifies error handling throughout the library.
1027    type ComplexPolicy: ValidationPolicyComplex<
1028            Value = Self::RawComplex,
1029            Error = <Self::RawComplex as RawScalarTrait>::ValidationErrors,
1030        >;
1031
1032    /// The final, high-level, validated real scalar type for this kernel.
1033    /// This is typically an alias for `RealValidated<Self>`.
1034    type Real: RealScalar<RawReal = Self::RawReal>;
1035
1036    /// The final, high-level, validated complex scalar type for this kernel.
1037    /// This is typically an alias for `ComplexValidated<Self>`.
1038    /// The `RealType = Self::Real` bound ensures the complex type is composed of the
1039    /// corresponding validated real type from the same kernel.
1040    type Complex: ComplexScalar<RealType = Self::Real>;
1041}
1042//------------------------------------------------------------------------------------------------------------
1043
1044//-----------------------------------------------------------------------------------------------
1045/// A strict finite kernel validation policy for raw real numbers.
1046/// This policy ensures that the real numbers are finite and not NaN.
1047pub struct NumKernelStrictFinite<RawReal: RawRealTrait, const PRECISION: u32> {
1048    _phantom: PhantomData<RawReal>,
1049}
1050
1051impl<RawReal: RawRealTrait, const PRECISION: u32> RawKernel
1052    for NumKernelStrictFinite<RawReal, PRECISION>
1053{
1054    type RawReal = RawReal;
1055    type RawComplex = RawReal::RawComplex;
1056}
1057
1058impl<RawReal: RawRealTrait, const PRECISION: u32> NumKernel
1059    for NumKernelStrictFinite<RawReal, PRECISION>
1060where
1061    StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal<Value = RawReal>,
1062    StrictFinitePolicy<RawReal::RawComplex, PRECISION>:
1063        ValidationPolicyComplex<Value = RawReal::RawComplex>,
1064{
1065    const PRECISION: u32 = PRECISION;
1066
1067    type RealPolicy = StrictFinitePolicy<RawReal, PRECISION>;
1068
1069    type ComplexPolicy = StrictFinitePolicy<RawReal::RawComplex, PRECISION>;
1070
1071    type Real = RealValidated<Self>;
1072    type Complex = ComplexValidated<Self>;
1073}
1074//-----------------------------------------------------------------------------------------------
1075
1076//-----------------------------------------------------------------------------------------------
1077pub struct NumKernelStrictFiniteInDebug<RawReal: RawRealTrait, const PRECISION: u32> {
1078    _phantom: PhantomData<RawReal>,
1079}
1080
1081impl<RawReal: RawRealTrait, const PRECISION: u32> RawKernel
1082    for NumKernelStrictFiniteInDebug<RawReal, PRECISION>
1083{
1084    type RawReal = RawReal;
1085    type RawComplex = RawReal::RawComplex;
1086}
1087
1088impl<RawReal: RawRealTrait, const PRECISION: u32> NumKernel
1089    for NumKernelStrictFiniteInDebug<RawReal, PRECISION>
1090where
1091    StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal<Value = RawReal>,
1092    StrictFinitePolicy<RawReal::RawComplex, PRECISION>:
1093        ValidationPolicyComplex<Value = RawReal::RawComplex>,
1094{
1095    const PRECISION: u32 = PRECISION;
1096
1097    type RealPolicy = DebugValidationPolicy<StrictFinitePolicy<RawReal, PRECISION>>;
1098
1099    type ComplexPolicy = DebugValidationPolicy<StrictFinitePolicy<RawReal::RawComplex, PRECISION>>;
1100
1101    type Real = RealValidated<Self>;
1102    type Complex = ComplexValidated<Self>;
1103}
1104
1105//-----------------------------------------------------------------------------------------------