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//-----------------------------------------------------------------------------------------------