#![deny(rustdoc::broken_intra_doc_links)]

//! # Numerical Kernels and Validated Types
//!
//! This module is the core of the numerical backend for the [`num-valid`](crate) crate.
//! It defines the fundamental traits, types, and operations for floating-point arithmetic.
//!
//! ## Core Architecture
//!
//! The architecture is built on three key concepts:
//!
//! 1.  **Raw Traits ([`RawScalarTrait`], [`RawRealTrait`], [`RawComplexTrait`]):**
//!     These traits define the baseline contract for a "raw" number type (like [`f64`] or
//!     [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html)).
//!     They provide a comprehensive set of `unchecked_*` methods for arithmetic and mathematical
//!     functions. The "unchecked" prefix signifies that these methods do **not** perform
//!     any validation (e.g., for domain, finiteness, or division by zero) and are intended
//!     for internal use where validity has already been confirmed.
//!
//! 2.  **Validated Structs ([`RealValidated`], [`ComplexValidated`]):**
//!     These are wrapper types (newtypes) that enforce correctness. An instance of `RealValidated<P>`
//!     is guaranteed to hold a raw value that has been successfully validated against the policy `P`.
//!     All operations on these types (addition, `sqrt`, etc.) are designed to preserve this validity,
//!     either by returning a `Result` or by panicking on failure in debug builds.
//!
//! 3.  **Validation Policies ([`NumKernel`]):**
//!     This trait allows the validation strategy to be generic. A kernel can be configured with
//!     different policies, such as [`NumKernelStrictFinite`], which ensures all numbers are
//!     finite (not NaN or Infinity).
//!
//! ## Available Kernels
//!
//! The library provides concrete kernels that bundle these concepts:
//!
//! - **`native64`:** Uses Rust's standard [`f64`] and `num::Complex<f64>` as the raw types.
//!   This is the default, high-performance kernel.
//!
//! - **`rug` (feature-gated):** Uses arbitrary-precision types from the [`rug`](https://crates.io/crates/rug) crate,
//!   ideal for high-precision scientific computing.

pub mod native64;
pub mod native64_validated;
mod validated;

#[cfg(feature = "rug")]
pub mod rug;

pub use validated::{ComplexValidated, RealValidated};

use crate::{
    ComplexScalar, Conjugate, FpChecks, NegAssign, NeumaierAddable, RealScalar,
    functions::{Rounding, Sign},
    validation::{
        DebugValidationPolicy, ErrorsRawRealToInteger, ErrorsTryFromf64,
        ErrorsValidationRawComplex, ErrorsValidationRawReal, StrictFinitePolicy,
        ValidationPolicyComplex, ValidationPolicyReal, capture_backtrace,
    },
};
use az::CheckedAs;
use duplicate::duplicate_item;
use num::{Complex, Zero};
use num_traits::{MulAdd, MulAddAssign};
use serde::{Deserialize, Serialize};
use std::{
    cmp::Ordering,
    fmt::{Debug, Display},
    hash::{Hash, Hasher},
    marker::PhantomData,
    num::FpCategory,
    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};

/// A baseline trait for raw scalar types, defining core operations and properties.
///
/// This trait must be implemented by the underlying number types used in a kernel,
/// such as like [`f64`] or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
/// It provides a standard interface for arithmetic
/// and a suite of `unchecked_*` methods for mathematical functions.
///
/// ## Hashing Support
///
/// All raw scalar types (both real and complex) must implement [`compute_hash()`](Self::compute_hash),
/// which provides a consistent hashing mechanism. The hash implementation must ensure:
///
/// - **Mathematical Equality**: Values that are mathematically equal produce identical hashes
/// - **Signed Zero Handling**: Both `+0.0` and `-0.0` hash to the same value
/// - **Finite Values Only**: The hash is only well-defined for finite values (not NaN or infinity)
/// - **Consistency**: The same value always produces the same hash across multiple calls
///
/// For complex numbers, the hash is computed by sequentially hashing the real and imaginary
/// parts, ensuring that different complex numbers produce different hashes while maintaining
/// the equality invariant.
///
/// This enables validated wrapper types to implement [`Hash`] when their validation
/// policies guarantee finite values (via [`crate::validation::GuaranteesFiniteValues`]),
/// allowing them to be used as keys in [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
///
/// # Safety and Contracts
///
/// The `unchecked_*` methods are designed for performance and assume that the caller
/// has already validated the inputs. Calling them with invalid data (e.g., `unchecked_sqrt`
/// on a negative real number) may lead to panics, incorrect results, or undefined behavior,
/// depending on the underlying type's implementation.
pub trait RawScalarTrait:
    Serialize + for<'a> Deserialize<'a>
    + Debug
    + Display
    + Clone
    + Sync
    + Send
    + Add<Output = Self>
    + Sub<Output = Self>
    + Mul<Output = Self>
    + Div<Output = Self>
    + for<'a> Add<&'a Self, Output = Self>
    + for<'a> Sub<&'a Self, Output = Self>
    + for<'a> Mul<&'a Self, Output = Self>
    + for<'a> Div<&'a Self, Output = Self>
    + AddAssign
    + SubAssign
    + MulAssign
    + DivAssign
    + for<'a> AddAssign<&'a Self>
    + for<'a> SubAssign<&'a Self>
    + for<'a> MulAssign<&'a Self>
    + for<'a> DivAssign<&'a Self>
    + Neg<Output = Self>
    + NegAssign
    + NeumaierAddable
    + PartialEq
//    + MulAddRef
    + FpChecks
    + 'static
{
    /// The associated error type for validation failures of this raw type.
    type ValidationErrors: std::error::Error;

    fn is_zero(&self) -> bool;

    fn raw_zero(precision: u32) -> Self;

    fn raw_one(precision: u32) -> Self;

    fn raw_negative_one(precision: u32) -> Self {
        Self::raw_one(precision).neg()
    }

    /// Computes the reciprocal (1/x) without validation.
    /// 
    /// **Contract:** The caller must ensure `self` is not zero.
    fn unchecked_reciprocal(self) -> Self;

    /// Computes the exponential (e^x) without validation.
    /// 
    /// **Contract:** The caller must ensure the input is valid.
    fn unchecked_exp(self) -> Self;

    /// Computes the square root without validation.
    /// 
    /// **Contract:** For real numbers, the caller must ensure `self >= 0`.
    fn unchecked_sqrt(self) -> Self;

    fn unchecked_sin(self) -> Self;

    fn unchecked_asin(self) -> Self;

    fn unchecked_cos(self) -> Self;

    fn unchecked_acos(self) -> Self;

    fn unchecked_tan(self) -> Self;

    fn unchecked_atan(self) -> Self;

    fn unchecked_sinh(self) -> Self;

    fn unchecked_asinh(self) -> Self;

    fn unchecked_cosh(self) -> Self;

    fn unchecked_acosh(self) -> Self;

    fn unchecked_tanh(self) -> Self;

    fn unchecked_atanh(self) -> Self;

    fn unchecked_ln(self) -> Self;
    fn unchecked_log2(self) -> Self;
    fn unchecked_log10(self) -> Self;

    /// Raises `self` to the power of an `i8` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid.
    fn unchecked_pow_exponent_i8(self, exponent: &i8) -> Self;

    /// Raises `self` to the power of an `i16` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid.
    fn unchecked_pow_exponent_i16(self, exponent: &i16) -> Self;

    /// Raises `self` to the power of an `i32` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid.
    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self;

    /// Raises `self` to the power of an `i64` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_i64(self, exponent: &i64) -> Self;

    /// Raises `self` to the power of an `i128` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_i128(self, exponent: &i128) -> Self;

    /// Raises `self` to the power of an `isize` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_isize(self, exponent: &isize) -> Self;

    /// Raises `self` to the power of an `u8` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid.
    fn unchecked_pow_exponent_u8(self, exponent: &u8) -> Self;

    /// Raises `self` to the power of an `u16` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid.
    fn unchecked_pow_exponent_u16(self, exponent: &u16) -> Self;

    /// Raises `self` to the power of an `u32` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self;

    /// Raises `self` to the power of an `u64` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_u64(self, exponent: &u64) -> Self;

    /// Raises `self` to the power of an `u128` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_u128(self, exponent: &u128) -> Self;

    /// Raises `self` to the power of an `usize` exponent without validation.
    /// 
    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
    /// includes ensuring the `exponent` is within the representable range of the underlying
    /// power function (e.g., `i32` for `f64::powi`).
    fn unchecked_pow_exponent_usize(self, exponent: &usize) -> Self;

    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
    ///
    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
    ///
    /// **Contract:** The caller must ensure all inputs are valid.
    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self;

    /// Computes a hash value for this scalar (real or complex).
    ///
    /// This method must ensure that mathematically equal values produce
    /// the same hash, even across different representations (e.g., +0.0 and -0.0).
    ///
    /// For complex numbers, implementations should hash the real and imaginary
    /// parts sequentially to ensure distinct complex numbers have different hashes.
    ///
    /// # Implementation Notes
    ///
    /// - For real numbers: Hash the value directly, normalizing signed zeros
    /// - For complex numbers: Call `compute_hash()` on real part, then imaginary part
    ///
    /// # Debug Assertions
    ///
    /// Implementations should include a debug assertion that the value is finite,
    /// as hashing non-finite values may lead to inconsistent results.
    fn compute_hash<H: Hasher>(&self, state: &mut H);
}

/// A trait for raw real scalar types, extending [`RawScalarTrait`] with real-specific operations.
///
/// This trait defines the fundamental operations for real number types without
/// validation or safety checks. Implementations should assume inputs are valid
/// and focus on computational efficiency.
///
/// This trait is implemented by the underlying real number types within a kernel, such as [`f64`]
/// or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
/// It builds upon [`RawScalarTrait`] by adding operations that are unique
/// to real numbers, like `atan2`, and by enforcing an ordering relationship.
///
/// ## Hashing Support
///
/// Types implementing this trait must provide a `compute_hash` method that:
/// - Produces consistent hash values for mathematically equal numbers
/// - Handles floating-point edge cases (like signed zeros) correctly  
/// - Maintains the contract that `a == b` implies `hash(a) == hash(b)`
///
/// This enables validated wrapper types to implement [`Hash`] when appropriate
/// validation policies guarantee finite values.
///
/// # Trait Bounds
///
/// - `RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>`: Ensures that the type
///   is a raw scalar and that its validation error type is the standard one for real numbers.
/// - [`PartialOrd`]: Requires that the type can be partially ordered, which is fundamental for
///   real numbers.
/// - [`PartialOrd<f64>`]: These crucial bounds allow instances of the raw
///   real type to be directly compared with `f64` constants. This is essential for implementing
///   domain checks (e.g., `value < 0.0` or `value >= 0.0`) that work across
///   both [`f64`] and [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html) without extra conversions.
///
/// # Associated Types
///
/// - `type RawComplex: RawComplexTrait<RawReal = Self>`: This links the raw real type to its
///   corresponding complex number representation. For example, for [`f64`], this would be
///   [`num::Complex<f64>`]. This association is vital for operations that can transition
///   from the real to the complex domain.
pub trait RawRealTrait:
    RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>
    + PartialOrd
    + PartialOrd<f64>
    + Sign
    + Rounding
{
    /// The associated complex type that uses this type as its real part.
    type RawComplex: RawComplexTrait<RawReal = Self>;

    /// Computes the absolute value of `self` without validation.
    ///
    /// **Contract:** The caller must ensure that the input value has already been validated
    /// and is suitable for the operation.
    fn unchecked_abs(self) -> Self;

    /// Computes the four-quadrant arctangent of `self` (`y`) and `denominator` (`x`) without validation.
    ///
    /// **Contract:** The caller must ensure that `self` and `denominator` are not both zero.
    fn unchecked_atan2(self, denominator: &Self) -> Self;

    /// Raises `self` to the power of a real `exponent` without validation.
    ///
    /// **Contract:** The caller must ensure the inputs are valid for the power function. For
    /// example, if `self` is negative, the `exponent` should be an integer, but this function
    /// does not enforce this.
    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self;

    fn unchecked_hypot(self, other: &Self) -> Self;

    fn unchecked_ln_1p(self) -> Self;

    fn unchecked_exp_m1(self) -> Self;

    /// Multiplies two pairs and adds them, rounding to the nearest.
    /// `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.
    ///
    /// **Contract:** The caller must ensure all inputs are valid.
    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self);

    /// Multiplies two pairs and subtracts them, rounding to the nearest.
    /// `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.
    ///
    /// **Contract:** The caller must ensure all inputs are valid.
    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self);

    fn raw_total_cmp(&self, other: &Self) -> Ordering;

    /// Clamps the value within the specified bounds.
    fn raw_clamp(self, min: &Self, max: &Self) -> Self;

    fn raw_classify(&self) -> FpCategory;

    fn raw_two(precision: u32) -> Self;

    fn raw_one_div_2(precision: u32) -> Self;

    fn raw_pi(precision: u32) -> Self;

    fn raw_two_pi(precision: u32) -> Self;

    fn raw_pi_div_2(precision: u32) -> Self;

    fn raw_max_finite(precision: u32) -> Self;

    fn raw_min_finite(precision: u32) -> Self;

    fn raw_epsilon(precision: u32) -> Self;

    fn raw_ln_2(_precision: u32) -> Self;

    fn raw_ln_10(_precision: u32) -> Self;

    fn raw_log10_2(_precision: u32) -> Self;

    fn raw_log2_10(_precision: u32) -> Self;

    fn raw_log2_e(_precision: u32) -> Self;

    fn raw_log10_e(_precision: u32) -> Self;

    fn raw_e(_precision: u32) -> Self;

    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
        value: f64,
    ) -> Result<Self, ErrorsTryFromf64<Self>>;

    /// Returns the precision (in bits) of the raw real type.
    fn precision(&self) -> u32;

    /// Safely converts the truncated value to `usize`.
    ///
    /// Truncates toward zero and validates the result is a valid `usize`.
    ///
    /// # Returns
    ///
    /// - `Ok(usize)`: If truncated value is in `0..=usize::MAX`
    /// - `Err(ErrorsRawRealToInteger)`: If value is not finite or out of range
    ///   - `NotFinite`: Value is `NaN` or `±∞`
    ///   - `OutOfRange`: Value is negative or > `usize::MAX`
    ///
    /// # Note
    ///
    /// The `NotAnInteger` error variant is not returned because truncation
    /// explicitly handles the fractional part.
    ///
    /// # Examples
    ///
    /// ```
    /// # use num_valid::kernels::RawRealTrait;
    /// let value = 42.9_f64;
    /// assert_eq!(value.truncate_to_usize().unwrap(), 42);
    ///
    /// let zero = 0.0_f64;
    /// assert_eq!(zero.truncate_to_usize().unwrap(), 0);
    /// ```
    ///
    /// ## Error cases
    ///
    /// ```
    /// # use num_valid::kernels::RawRealTrait;
    /// # use num_valid::validation::ErrorsRawRealToInteger;
    /// // Negative value
    /// let neg = -10.5_f64;
    /// assert!(matches!(neg.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
    ///
    /// // Too large for usize
    /// let large = (usize::MAX as f64) + 100.0;
    /// assert!(matches!(large.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
    ///
    /// // Not finite
    /// let nan = f64::NAN;
    /// assert!(matches!(nan.truncate_to_usize(), Err(ErrorsRawRealToInteger::NotFinite { .. })));
    /// ```
    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<Self, usize>>;
}

/// A trait for raw complex scalar types, extending [`RawScalarTrait`].
///
/// This trait is implemented by the underlying complex number types within a kernel,
/// such as [`num::Complex<f64>`]. It builds upon [`RawScalarTrait`] by adding operations
/// that are unique to complex numbers.
///
/// # Trait Bounds
///
/// - `RawScalarTrait<...>`: Ensures the type is a raw scalar and fixes its validation
///   error type to [`ErrorsValidationRawComplex`], which in turn wraps the validation
///   error of the associated real type. This establishes a consistent error structure.
/// - [`Conjugate`]: Requires that the complex number can be conjugated.
///
/// # Associated Types
///
/// - `type RawReal: RawRealTrait<RawComplex = Self>`: This is a critical part of the
///   design. It links the complex type to its underlying real component type (e.g., [`f64`]
///   for [`num::Complex<f64>`]). This associated real type must itself implement [`RawRealTrait`],
///   creating a two-way link between the real and complex raw types.
///
/// # Methods
///
/// This trait provides methods for accessing components and performing complex-specific
/// mathematical operations without validation checks.
pub trait RawComplexTrait:
    RawScalarTrait<
        ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<Self::RawReal>>,
    > + Conjugate
    + for<'a> Mul<&'a Self::RawReal, Output = Self>
    + for<'a> MulAssign<&'a Self::RawReal>
{
    /// The associated real type that makes up the components of this complex type.
    type RawReal: RawRealTrait<RawComplex = Self>;

    fn new_unchecked_raw_complex(real: Self::RawReal, imag: Self::RawReal) -> Self;

    /// Computes the absolute value (modulus or norm) of `self` without validation.
    ///
    /// **Contract:** The caller must ensure the input is valid for this operation.
    fn unchecked_abs(self) -> Self::RawReal;

    /// Returns a reference to the real part of the complex number.
    fn raw_real_part(&self) -> &Self::RawReal;

    /// Returns a reference to the imaginary part of the complex number.
    fn raw_imag_part(&self) -> &Self::RawReal;

    /// Returns a mutable reference to the real part of the complex number.
    fn mut_raw_real_part(&mut self) -> &mut Self::RawReal;

    /// Returns a mutable reference to the imaginary part of the complex number.
    fn mut_raw_imag_part(&mut self) -> &mut Self::RawReal;

    /// Computes the argument (or phase) of `self` in radians, without validation.
    ///
    /// **Contract:** The caller must ensure that `self` is not zero.
    fn unchecked_arg(self) -> Self::RawReal;

    /// Raises `self` to the power of a real `exponent` without validation.
    ///
    /// **Contract:** The caller must ensure the inputs are valid for the power function.
    fn unchecked_pow_exponent_real(self, exponent: &Self::RawReal) -> Self;
}

impl RawScalarTrait for f64 {
    type ValidationErrors = ErrorsValidationRawReal<f64>;

    #[inline(always)]
    fn raw_zero(_precision: u32) -> f64 {
        0.
    }

    #[inline(always)]
    fn is_zero(&self) -> bool {
        <Self as Zero>::is_zero(self)
    }
    #[inline(always)]
    fn raw_one(_precision: u32) -> f64 {
        1.
    }

    #[duplicate_item(
        unchecked_method       method;
        [unchecked_reciprocal] [recip];
        [unchecked_exp]        [exp];
        [unchecked_sqrt]       [sqrt];
        [unchecked_sin]        [sin];
        [unchecked_asin]       [asin];
        [unchecked_cos]        [cos];
        [unchecked_acos]       [acos];
        [unchecked_tan]        [tan];
        [unchecked_atan]       [atan];
        [unchecked_sinh]       [sinh];
        [unchecked_asinh]      [asinh];
        [unchecked_cosh]       [cosh];
        [unchecked_acosh]      [acosh];
        [unchecked_tanh]       [tanh];
        [unchecked_atanh]      [atanh];
        [unchecked_ln]         [ln];
        [unchecked_log2]       [log2];
        [unchecked_log10]      [log10];
    )]
    #[inline(always)]
    fn unchecked_method(self) -> f64 {
        f64::method(self)
    }

    #[duplicate_item(
        unchecked_method             exponent_type;
        [unchecked_pow_exponent_i8]  [i8];
        [unchecked_pow_exponent_i16] [i16];
        [unchecked_pow_exponent_u8]  [u8];
        [unchecked_pow_exponent_u16] [u16];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> f64 {
        f64::powi(self, (*exponent).into())
    }

    #[inline(always)]
    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
        f64::powi(self, *exponent)
    }

    #[duplicate_item(
        unchecked_method               exponent_type;
        [unchecked_pow_exponent_i64]   [i64];
        [unchecked_pow_exponent_i128]  [i128];
        [unchecked_pow_exponent_isize] [isize];
        [unchecked_pow_exponent_u32]   [u32];
        [unchecked_pow_exponent_u64]   [u64];
        [unchecked_pow_exponent_u128]  [u128];
        [unchecked_pow_exponent_usize] [usize];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> f64 {
        f64::powi(
            self,
            (*exponent)
                .try_into()
                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
        )
    }

    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
    ///
    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
    #[inline(always)]
    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
        f64::mul_add(self, *b, *c)
    }

    #[inline(always)]
    fn compute_hash<H: Hasher>(&self, state: &mut H) {
        debug_assert!(
            self.is_finite(),
            "Hashing a non-finite f64 value (i.e., NaN or Infinity) may lead to inconsistent results."
        );
        if self == &0.0 {
            // Hash all zeros (positive and negative) to the same value
            0.0f64.to_bits().hash(state);
        } else {
            self.to_bits().hash(state);
        }
    }
}

impl RawRealTrait for f64 {
    type RawComplex = Complex<f64>;

    #[inline(always)]
    fn unchecked_abs(self) -> f64 {
        f64::abs(self)
    }

    #[inline(always)]
    fn unchecked_atan2(self, denominator: &Self) -> Self {
        f64::atan2(self, *denominator)
    }

    #[inline(always)]
    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
        f64::powf(self, *exponent)
    }

    #[inline(always)]
    fn unchecked_hypot(self, other: &Self) -> Self {
        f64::hypot(self, *other)
    }

    #[inline(always)]
    fn unchecked_ln_1p(self) -> Self {
        f64::ln_1p(self)
    }

    #[inline(always)]
    fn unchecked_exp_m1(self) -> Self {
        f64::exp_m1(self)
    }

    /// Multiplies two pairs and adds them in one fused operation, rounding to the nearest with only one rounding error.
    /// `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.
    #[inline(always)]
    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
        self.mul_add_assign(*mul, add_mul1 * add_mul2);
    }

    /// Multiplies two pairs and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
    /// `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.
    #[inline(always)]
    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
        self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
    }

    #[inline(always)]
    fn raw_total_cmp(&self, other: &Self) -> Ordering {
        f64::total_cmp(self, other)
    }

    /// Clamps the value within the specified bounds.
    #[inline(always)]
    fn raw_clamp(self, min: &Self, max: &Self) -> Self {
        f64::clamp(self, *min, *max)
    }

    #[inline(always)]
    fn raw_classify(&self) -> FpCategory {
        f64::classify(*self)
    }

    #[inline(always)]
    fn raw_two(_precision: u32) -> Self {
        2.
    }

    #[inline(always)]
    fn raw_one_div_2(_precision: u32) -> Self {
        0.5
    }

    #[inline(always)]
    fn raw_pi(_precision: u32) -> Self {
        std::f64::consts::PI
    }

    #[inline(always)]
    fn raw_two_pi(_precision: u32) -> Self {
        2. * std::f64::consts::PI
    }

    #[inline(always)]
    fn raw_pi_div_2(_precision: u32) -> Self {
        std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn raw_max_finite(_precision: u32) -> Self {
        f64::MAX
    }

    #[inline(always)]
    fn raw_min_finite(_precision: u32) -> Self {
        f64::MIN
    }

    #[inline(always)]
    fn raw_epsilon(_precision: u32) -> Self {
        f64::EPSILON
    }

    #[inline(always)]
    fn raw_ln_2(_precision: u32) -> Self {
        std::f64::consts::LN_2
    }

    #[inline(always)]
    fn raw_ln_10(_precision: u32) -> Self {
        std::f64::consts::LN_10
    }

    #[inline(always)]
    fn raw_log10_2(_precision: u32) -> Self {
        std::f64::consts::LOG10_2
    }

    #[inline(always)]
    fn raw_log2_10(_precision: u32) -> Self {
        std::f64::consts::LOG2_10
    }

    #[inline(always)]
    fn raw_log2_e(_precision: u32) -> Self {
        std::f64::consts::LOG2_E
    }

    #[inline(always)]
    fn raw_log10_e(_precision: u32) -> Self {
        std::f64::consts::LOG10_E
    }

    #[inline(always)]
    fn raw_e(_precision: u32) -> Self {
        std::f64::consts::E
    }

    #[inline(always)]
    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
        value: f64,
    ) -> Result<Self, ErrorsTryFromf64<f64>> {
        RealPolicy::validate(value).map_err(|e| ErrorsTryFromf64::Output { source: e })
    }

    #[inline(always)]
    fn precision(&self) -> u32 {
        53 // f64 has 53 bits of precision
    }

    #[inline(always)]
    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<f64, usize>> {
        if !self.is_finite() {
            return Err(ErrorsRawRealToInteger::NotFinite {
                value: self,
                backtrace: capture_backtrace(),
            });
        }

        match self.checked_as::<usize>() {
            Some(value) => Ok(value),
            None => Err(ErrorsRawRealToInteger::OutOfRange {
                value: self,
                min: usize::MIN,
                max: usize::MAX,
                backtrace: capture_backtrace(),
            }),
        }
    }
}

impl RawScalarTrait for Complex<f64> {
    type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<f64>>;

    #[inline(always)]
    fn raw_zero(_precision: u32) -> Self {
        Complex::new(0., 0.)
    }

    #[inline(always)]
    fn is_zero(&self) -> bool {
        <Self as Zero>::is_zero(self)
    }

    #[inline(always)]
    fn raw_one(_precision: u32) -> Self {
        Complex::new(1., 0.)
    }

    #[duplicate_item(
        unchecked_method       method;
        [unchecked_exp]        [exp];
        [unchecked_sqrt]       [sqrt];
        [unchecked_sin]        [sin];
        [unchecked_asin]       [asin];
        [unchecked_cos]        [cos];
        [unchecked_acos]       [acos];
        [unchecked_tan]        [tan];
        [unchecked_atan]       [atan];
        [unchecked_sinh]       [sinh];
        [unchecked_asinh]      [asinh];
        [unchecked_cosh]       [cosh];
        [unchecked_acosh]      [acosh];
        [unchecked_tanh]       [tanh];
        [unchecked_atanh]      [atanh];
        [unchecked_ln]         [ln];
        [unchecked_log10]      [log10];
    )]
    #[inline(always)]
    fn unchecked_method(self) -> Self {
        Complex::<f64>::method(self)
    }

    #[inline(always)]
    fn unchecked_reciprocal(self) -> Self {
        Complex::<f64>::inv(&self)
    }

    #[inline(always)]
    fn unchecked_log2(self) -> Self {
        Complex::<f64>::ln(self) / std::f64::consts::LN_2
    }

    #[duplicate_item(
        unchecked_method             exponent_type;
        [unchecked_pow_exponent_i8]  [i8];
        [unchecked_pow_exponent_i16] [i16];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> Self {
        Complex::<f64>::powi(&self, (*exponent).into())
    }

    #[inline(always)]
    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
        Complex::<f64>::powi(&self, *exponent)
    }

    #[duplicate_item(
        unchecked_method               exponent_type;
        [unchecked_pow_exponent_i64]   [i64];
        [unchecked_pow_exponent_i128]  [i128];
        [unchecked_pow_exponent_isize] [isize];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> Self {
        Complex::<f64>::powi(
            &self,
            (*exponent)
                .try_into()
                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
        )
    }

    #[duplicate_item(
        unchecked_method             exponent_type;
        [unchecked_pow_exponent_u8]  [u8];
        [unchecked_pow_exponent_u16] [u16];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> Self {
        Complex::<f64>::powu(&self, (*exponent).into())
    }

    #[inline(always)]
    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
        Complex::<f64>::powu(&self, *exponent)
    }

    #[duplicate_item(
        unchecked_method               exponent_type;
        [unchecked_pow_exponent_u64]   [u64];
        [unchecked_pow_exponent_u128]  [u128];
        [unchecked_pow_exponent_usize] [usize];
    )]
    #[inline(always)]
    fn unchecked_method(self, exponent: &exponent_type) -> Self {
        Complex::<f64>::powu(
            &self,
            (*exponent)
                .try_into()
                .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
        )
    }

    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
    ///
    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
    #[inline(always)]
    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
        Complex::<f64>::mul_add(self, *b, *c)
    }

    fn compute_hash<H: Hasher>(&self, state: &mut H) {
        self.raw_real_part().compute_hash(state);
        self.raw_imag_part().compute_hash(state);
    }
}

impl RawComplexTrait for Complex<f64> {
    type RawReal = f64;

    fn new_unchecked_raw_complex(real: f64, imag: f64) -> Self {
        Complex::<f64>::new(real, imag)
    }

    /// Returns a mutable reference to the real part of the complex number.
    fn mut_raw_real_part(&mut self) -> &mut f64 {
        &mut self.re
    }

    /// Returns a mutable reference to the imaginary part of the complex number.
    fn mut_raw_imag_part(&mut self) -> &mut f64 {
        &mut self.im
    }

    #[inline(always)]
    fn unchecked_abs(self) -> f64 {
        Complex::<f64>::norm(self)
    }

    #[inline(always)]
    fn raw_real_part(&self) -> &f64 {
        &self.re
    }

    #[inline(always)]
    fn raw_imag_part(&self) -> &f64 {
        &self.im
    }

    #[inline(always)]
    fn unchecked_arg(self) -> f64 {
        Complex::<f64>::arg(self)
    }

    #[inline(always)]
    fn unchecked_pow_exponent_real(self, exponent: &f64) -> Self {
        Complex::<f64>::powf(self, *exponent)
    }
}
//------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------
/// Defines the identity of a raw numerical kernel by associating its fundamental types.
///
/// This trait acts as a low-level building block that groups the core "raw"
/// types of a numerical backend. It specifies which concrete types implement
/// [`RawRealTrait`] and [`RawComplexTrait`] for a given kernel.
///
/// It is primarily used as a supertrait for [`NumKernel`], which extends
/// this type-level association with concrete validation logic and precision information.
pub trait RawKernel: Send + Sync + 'static {
    /// The raw real type associated with this kernel (e.g., [`f64`]).
    type RawReal: RawRealTrait;

    /// The raw complex type associated with this kernel (e.g., [`Complex<f64>`]).
    type RawComplex: RawComplexTrait<RawReal = Self::RawReal>;
}
//------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------
/// Defines a complete numerical kernel, acting as the central configuration point.
///
/// This trait is the primary bound for generic functions that need to operate
/// across different numerical backends. It bundles together:
/// 1.  The raw underlying types (e.g., `f64`) via the [`RawKernel`] supertrait.
/// 2.  The specific validation logic for those types.
/// 3.  The precision of the kernel in bits.
/// 4.  The final, high-level `Real` and `Complex` validated types.
pub trait NumKernel: RawKernel + Sized {
    /// The precision of the kernel in bits (e.g., `53` for `f64`).
    const PRECISION: u32;

    /// The validation policy for real numbers.
    ///
    /// # Note
    /// The bound on `ValidationPolicyReal::Error` is a critical architectural choice. It enforces that the
    /// error type defined by a policy (`RealPolicy::Error`) MUST be the same as the
    /// canonical validation error type associated with its value (`RealPolicy::Value::ValidationErrors`).
    /// This prevents mismatches and simplifies error handling throughout the library.
    type RealPolicy: ValidationPolicyReal<
            Value = Self::RawReal,
            Error = <Self::RawReal as RawScalarTrait>::ValidationErrors,
        >;

    /// The validation policy for complex numbers.
    ///
    /// # Note
    /// The bound on `ValidationPolicyComplex::Error` is a critical architectural choice. It enforces that the
    /// error type defined by a policy (`ComplexPolicy::Error`) MUST be the same as the
    /// canonical validation error type associated with its value (`ComplexPolicy::Value::ValidationErrors`).
    /// This prevents mismatches and simplifies error handling throughout the library.
    type ComplexPolicy: ValidationPolicyComplex<
            Value = Self::RawComplex,
            Error = <Self::RawComplex as RawScalarTrait>::ValidationErrors,
        >;

    /// The final, high-level, validated real scalar type for this kernel.
    /// This is typically an alias for `RealValidated<Self>`.
    type Real: RealScalar<RawReal = Self::RawReal>;

    /// The final, high-level, validated complex scalar type for this kernel.
    /// This is typically an alias for `ComplexValidated<Self>`.
    /// The `RealType = Self::Real` bound ensures the complex type is composed of the
    /// corresponding validated real type from the same kernel.
    type Complex: ComplexScalar<RealType = Self::Real>;
}
//------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------
/// A strict finite kernel validation policy for raw real numbers.
/// This policy ensures that the real numbers are finite and not NaN.
pub struct NumKernelStrictFinite<RawReal: RawRealTrait, const PRECISION: u32> {
    _phantom: PhantomData<RawReal>,
}

impl<RawReal: RawRealTrait, const PRECISION: u32> RawKernel
    for NumKernelStrictFinite<RawReal, PRECISION>
{
    type RawReal = RawReal;
    type RawComplex = RawReal::RawComplex;
}

impl<RawReal: RawRealTrait, const PRECISION: u32> NumKernel
    for NumKernelStrictFinite<RawReal, PRECISION>
where
    StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal<Value = RawReal>,
    StrictFinitePolicy<RawReal::RawComplex, PRECISION>:
        ValidationPolicyComplex<Value = RawReal::RawComplex>,
{
    const PRECISION: u32 = PRECISION;

    type RealPolicy = StrictFinitePolicy<RawReal, PRECISION>;

    type ComplexPolicy = StrictFinitePolicy<RawReal::RawComplex, PRECISION>;

    type Real = RealValidated<Self>;
    type Complex = ComplexValidated<Self>;
}
//-----------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------
pub struct NumKernelStrictFiniteInDebug<RawReal: RawRealTrait, const PRECISION: u32> {
    _phantom: PhantomData<RawReal>,
}

impl<RawReal: RawRealTrait, const PRECISION: u32> RawKernel
    for NumKernelStrictFiniteInDebug<RawReal, PRECISION>
{
    type RawReal = RawReal;
    type RawComplex = RawReal::RawComplex;
}

impl<RawReal: RawRealTrait, const PRECISION: u32> NumKernel
    for NumKernelStrictFiniteInDebug<RawReal, PRECISION>
where
    StrictFinitePolicy<RawReal, PRECISION>: ValidationPolicyReal<Value = RawReal>,
    StrictFinitePolicy<RawReal::RawComplex, PRECISION>:
        ValidationPolicyComplex<Value = RawReal::RawComplex>,
{
    const PRECISION: u32 = PRECISION;

    type RealPolicy = DebugValidationPolicy<StrictFinitePolicy<RawReal, PRECISION>>;

    type ComplexPolicy = DebugValidationPolicy<StrictFinitePolicy<RawReal::RawComplex, PRECISION>>;

    type Real = RealValidated<Self>;
    type Complex = ComplexValidated<Self>;
}

//-----------------------------------------------------------------------------------------------
