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