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