num_valid/core/traits/
raw.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Raw trait definitions for unchecked scalar operations.
4//!
5//! This module defines the fundamental traits for raw number types (like `f64` or `rug::Float`).
6//! These traits provide `unchecked_*` methods that assume inputs are valid and do not perform
7//! any validation.
8//!
9//! # Trait Hierarchy
10//!
11//! ```text
12//! RawScalarTrigonometric ─┐
13//! RawScalarHyperbolic ────┼──> RawScalarTrait ──> RawRealTrait
14//! RawScalarPow ───────────┘                   └──> RawComplexTrait
15//! ```
16
17use crate::{
18    Arithmetic, Conjugate, NeumaierAddable, ScalarCore,
19    core::{
20        errors::{
21            ErrorsRawRealToInteger, ErrorsTryFromf64, ErrorsValidationRawComplex,
22            ErrorsValidationRawReal,
23        },
24        traits::validation::{FpChecks, ValidationPolicyReal},
25    },
26    functions::{Rounding, Sign},
27};
28use std::{
29    cmp::Ordering,
30    hash::Hasher,
31    num::FpCategory,
32    ops::{Mul, MulAssign},
33};
34
35// =============================================================================
36// Trigonometric Operations
37// =============================================================================
38
39/// Trait for unchecked trigonometric operations.
40///
41/// Provides sine, cosine, tangent and their inverse functions without validation.
42pub trait RawScalarTrigonometric {
43    /// Computes the sine without validation.
44    fn unchecked_sin(self) -> Self;
45
46    /// Computes the arcsine without validation.
47    fn unchecked_asin(self) -> Self;
48
49    /// Computes the cosine without validation.
50    fn unchecked_cos(self) -> Self;
51
52    /// Computes the arccosine without validation.
53    fn unchecked_acos(self) -> Self;
54
55    /// Computes the tangent without validation.
56    fn unchecked_tan(self) -> Self;
57
58    /// Computes the arctangent without validation.
59    fn unchecked_atan(self) -> Self;
60}
61
62// =============================================================================
63// Hyperbolic Operations
64// =============================================================================
65
66/// Trait for unchecked hyperbolic operations.
67///
68/// Provides hyperbolic sine, cosine, tangent and their inverse functions without validation.
69pub trait RawScalarHyperbolic {
70    /// Computes the hyperbolic sine without validation.
71    fn unchecked_sinh(self) -> Self;
72
73    /// Computes the inverse hyperbolic sine without validation.
74    fn unchecked_asinh(self) -> Self;
75
76    /// Computes the hyperbolic cosine without validation.
77    fn unchecked_cosh(self) -> Self;
78
79    /// Computes the inverse hyperbolic cosine without validation.
80    fn unchecked_acosh(self) -> Self;
81
82    /// Computes the hyperbolic tangent without validation.
83    fn unchecked_tanh(self) -> Self;
84
85    /// Computes the inverse hyperbolic tangent without validation.
86    fn unchecked_atanh(self) -> Self;
87}
88
89// =============================================================================
90// Power Operations
91// =============================================================================
92
93/// Trait for unchecked power operations with integer exponents.
94///
95/// Provides power functions for all standard integer types without validation.
96pub trait RawScalarPow {
97    /// Raises `self` to the power of an `i8` exponent without validation.
98    ///
99    /// **Contract:** The caller must ensure the inputs are valid.
100    fn unchecked_pow_exponent_i8(self, exponent: &i8) -> Self;
101
102    /// Raises `self` to the power of an `i16` exponent without validation.
103    ///
104    /// **Contract:** The caller must ensure the inputs are valid.
105    fn unchecked_pow_exponent_i16(self, exponent: &i16) -> Self;
106
107    /// Raises `self` to the power of an `i32` exponent without validation.
108    ///
109    /// **Contract:** The caller must ensure the inputs are valid.
110    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self;
111
112    /// Raises `self` to the power of an `i64` exponent without validation.
113    ///
114    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
115    /// includes ensuring the `exponent` is within the representable range of the underlying
116    /// power function (e.g., `i32` for `f64::powi`).
117    fn unchecked_pow_exponent_i64(self, exponent: &i64) -> Self;
118
119    /// Raises `self` to the power of an `i128` exponent without validation.
120    ///
121    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
122    /// includes ensuring the `exponent` is within the representable range of the underlying
123    /// power function (e.g., `i32` for `f64::powi`).
124    fn unchecked_pow_exponent_i128(self, exponent: &i128) -> Self;
125
126    /// Raises `self` to the power of an `isize` exponent without validation.
127    ///
128    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
129    /// includes ensuring the `exponent` is within the representable range of the underlying
130    /// power function (e.g., `i32` for `f64::powi`).
131    fn unchecked_pow_exponent_isize(self, exponent: &isize) -> Self;
132
133    /// Raises `self` to the power of a `u8` exponent without validation.
134    ///
135    /// **Contract:** The caller must ensure the inputs are valid.
136    fn unchecked_pow_exponent_u8(self, exponent: &u8) -> Self;
137
138    /// Raises `self` to the power of a `u16` exponent without validation.
139    ///
140    /// **Contract:** The caller must ensure the inputs are valid.
141    fn unchecked_pow_exponent_u16(self, exponent: &u16) -> Self;
142
143    /// Raises `self` to the power of a `u32` exponent without validation.
144    ///
145    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
146    /// includes ensuring the `exponent` is within the representable range of the underlying
147    /// power function (e.g., `i32` for `f64::powi`).
148    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self;
149
150    /// Raises `self` to the power of a `u64` exponent without validation.
151    ///
152    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
153    /// includes ensuring the `exponent` is within the representable range of the underlying
154    /// power function (e.g., `i32` for `f64::powi`).
155    fn unchecked_pow_exponent_u64(self, exponent: &u64) -> Self;
156
157    /// Raises `self` to the power of a `u128` exponent without validation.
158    ///
159    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
160    /// includes ensuring the `exponent` is within the representable range of the underlying
161    /// power function (e.g., `i32` for `f64::powi`).
162    fn unchecked_pow_exponent_u128(self, exponent: &u128) -> Self;
163
164    /// Raises `self` to the power of a `usize` exponent without validation.
165    ///
166    /// **Contract:** The caller must ensure the inputs are valid. For integer powers, this
167    /// includes ensuring the `exponent` is within the representable range of the underlying
168    /// power function (e.g., `i32` for `f64::powi`).
169    fn unchecked_pow_exponent_usize(self, exponent: &usize) -> Self;
170}
171
172// =============================================================================
173// Core Scalar Trait
174// =============================================================================
175
176/// A baseline trait for raw scalar types, defining core operations and properties.
177///
178/// This trait must be implemented by the underlying number types used in a kernel,
179/// such as like [`f64`] or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
180/// It provides a standard interface for arithmetic
181/// and a suite of `unchecked_*` methods for mathematical functions.
182///
183/// ## Hashing Support
184///
185/// All raw scalar types (both real and complex) must implement [`compute_hash()`](Self::compute_hash),
186/// which provides a consistent hashing mechanism. The hash implementation must ensure:
187///
188/// - **Mathematical Equality**: Values that are mathematically equal produce identical hashes
189/// - **Signed Zero Handling**: Both `+0.0` and `-0.0` hash to the same value
190/// - **Finite Values Only**: The hash is only well-defined for finite values (not NaN or infinity)
191/// - **Consistency**: The same value always produces the same hash across multiple calls
192///
193/// For complex numbers, the hash is computed by sequentially hashing the real and imaginary
194/// parts, ensuring that different complex numbers produce different hashes while maintaining
195/// the equality invariant.
196///
197/// This enables validated wrapper types to implement [`Hash`](std::hash::Hash) when their validation
198/// policies guarantee finite values (via [`crate::core::traits::validation::GuaranteesFiniteRealValues`]),
199/// allowing them to be used as keys in [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
200///
201/// # Safety and Contracts
202///
203/// The `unchecked_*` methods are designed for performance and assume that the caller
204/// has already validated the inputs. Calling them with invalid data (e.g., `unchecked_sqrt`
205/// on a negative real number) may lead to panics, incorrect results, or undefined behavior,
206/// depending on the underlying type's implementation.
207pub trait RawScalarTrait:
208    ScalarCore
209    + Arithmetic
210    + NeumaierAddable
211    + FpChecks
212    + RawScalarTrigonometric
213    + RawScalarHyperbolic
214    + RawScalarPow
215{
216    /// The associated error type for validation failures of this raw type.
217    type ValidationErrors: std::error::Error;
218
219    /// Returns `true` if `self` is zero.
220    fn is_zero(&self) -> bool;
221
222    /// Returns zero with the given precision.
223    fn raw_zero(precision: u32) -> Self;
224
225    /// Returns one with the given precision.
226    fn raw_one(precision: u32) -> Self;
227
228    /// Returns negative one with the given precision.
229    #[inline(always)]
230    fn raw_negative_one(precision: u32) -> Self {
231        Self::raw_one(precision).neg()
232    }
233
234    /// Computes the reciprocal (1/x) without validation.
235    ///
236    /// **Contract:** The caller must ensure `self` is not zero.
237    fn unchecked_reciprocal(self) -> Self;
238
239    /// Computes the exponential (e^x) without validation.
240    ///
241    /// **Contract:** The caller must ensure the input is valid.
242    fn unchecked_exp(self) -> Self;
243
244    /// Computes the square root without validation.
245    ///
246    /// **Contract:** For real numbers, the caller must ensure `self >= 0`.
247    fn unchecked_sqrt(self) -> Self;
248
249    /// Computes the natural logarithm without validation.
250    fn unchecked_ln(self) -> Self;
251
252    /// Computes the base-2 logarithm without validation.
253    fn unchecked_log2(self) -> Self;
254
255    /// Computes the base-10 logarithm without validation.
256    fn unchecked_log10(self) -> Self;
257
258    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
259    ///
260    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
261    ///
262    /// **Contract:** The caller must ensure all inputs are valid.
263    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self;
264
265    /// Computes a hash value for this scalar (real or complex).
266    ///
267    /// This method must ensure that mathematically equal values produce
268    /// the same hash, even across different representations (e.g., +0.0 and -0.0).
269    ///
270    /// For complex numbers, implementations should hash the real and imaginary
271    /// parts sequentially to ensure distinct complex numbers have different hashes.
272    ///
273    /// # Implementation Notes
274    ///
275    /// - For real numbers: Hash the value directly, normalizing signed zeros
276    /// - For complex numbers: Call `compute_hash()` on real part, then imaginary part
277    ///
278    /// # Debug Assertions
279    ///
280    /// Implementations should include a debug assertion that the value is finite,
281    /// as hashing non-finite values may lead to inconsistent results.
282    fn compute_hash<H: Hasher>(&self, state: &mut H);
283}
284
285// =============================================================================
286// Real Trait
287// =============================================================================
288
289/// A trait for raw real scalar types, extending [`RawScalarTrait`] with real-specific operations.
290///
291/// This trait defines the fundamental operations for real number types without
292/// validation or safety checks. Implementations should assume inputs are valid
293/// and focus on computational efficiency.
294///
295/// This trait is implemented by the underlying real number types within a kernel, such as [`f64`]
296/// or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
297/// It builds upon [`RawScalarTrait`] by adding operations that are unique
298/// to real numbers, like `atan2`, and by enforcing an ordering relationship.
299///
300/// ## Hashing Support
301///
302/// Types implementing this trait must provide a `compute_hash` method that:
303/// - Produces consistent hash values for mathematically equal numbers
304/// - Handles floating-point edge cases (like signed zeros) correctly  
305/// - Maintains the contract that `a == b` implies `hash(a) == hash(b)`
306///
307/// This enables validated wrapper types to implement [`Hash`](std::hash::Hash) when appropriate
308/// validation policies guarantee finite values.
309///
310/// # Trait Bounds
311///
312/// - `RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>`: Ensures that the type
313///   is a raw scalar and that its validation error type is the standard one for real numbers.
314/// - [`PartialOrd`]: Requires that the type can be partially ordered, which is fundamental for
315///   real numbers.
316/// - [`PartialOrd<f64>`]: These crucial bounds allow instances of the raw
317///   real type to be directly compared with `f64` constants. This is essential for implementing
318///   domain checks (e.g., `value < 0.0` or `value >= 0.0`) that work across
319///   both [`f64`] and [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html) without extra conversions.
320///
321/// # Associated Types
322///
323/// - `type RawComplex: RawComplexTrait<RawReal = Self>`: This links the raw real type to its
324///   corresponding complex number representation. For example, for [`f64`], this would be
325///   [`num::Complex<f64>`]. This association is vital for operations that can transition
326///   from the real to the complex domain.
327pub trait RawRealTrait:
328    RawScalarTrait<ValidationErrors = ErrorsValidationRawReal<Self>>
329    + PartialOrd
330    + PartialOrd<f64>
331    + Sign
332    + Rounding
333{
334    /// The associated complex type that uses this type as its real part.
335    type RawComplex: RawComplexTrait<RawReal = Self>;
336
337    /// Computes the absolute value of `self` without validation.
338    ///
339    /// **Contract:** The caller must ensure that the input value has already been validated
340    /// and is suitable for the operation.
341    fn unchecked_abs(self) -> Self;
342
343    /// Computes the four-quadrant arctangent of `self` (`y`) and `denominator` (`x`) without validation.
344    ///
345    /// **Contract:** The caller must ensure that `self` and `denominator` are not both zero.
346    fn unchecked_atan2(self, denominator: &Self) -> Self;
347
348    /// Raises `self` to the power of a real `exponent` without validation.
349    ///
350    /// **Contract:** The caller must ensure the inputs are valid for the power function. For
351    /// example, if `self` is negative, the `exponent` should be an integer, but this function
352    /// does not enforce this.
353    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self;
354
355    /// Computes the Euclidean distance `sqrt(self² + other²)` without validation.
356    fn unchecked_hypot(self, other: &Self) -> Self;
357
358    /// Computes `ln(1 + self)` accurately for small values without validation.
359    fn unchecked_ln_1p(self) -> Self;
360
361    /// Computes `exp(self) - 1` accurately for small values without validation.
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    /// Performs a total ordering comparison.
377    fn raw_total_cmp(&self, other: &Self) -> Ordering;
378
379    /// Clamps the value within the specified bounds.
380    fn raw_clamp(self, min: &Self, max: &Self) -> Self;
381
382    /// Classifies the floating-point value.
383    fn raw_classify(&self) -> FpCategory;
384
385    /// Returns two with the given precision.
386    fn raw_two(precision: u32) -> Self;
387
388    /// Returns 0.5 with the given precision.
389    fn raw_one_div_2(precision: u32) -> Self;
390
391    /// Returns π with the given precision.
392    fn raw_pi(precision: u32) -> Self;
393
394    /// Returns 2π with the given precision.
395    fn raw_two_pi(precision: u32) -> Self;
396
397    /// Returns π/2 with the given precision.
398    fn raw_pi_div_2(precision: u32) -> Self;
399
400    /// Returns the maximum finite value with the given precision.
401    fn raw_max_finite(precision: u32) -> Self;
402
403    /// Returns the minimum finite value with the given precision.
404    fn raw_min_finite(precision: u32) -> Self;
405
406    /// Returns the machine epsilon with the given precision.
407    fn raw_epsilon(precision: u32) -> Self;
408
409    /// Returns ln(2) with the given precision.
410    fn raw_ln_2(precision: u32) -> Self;
411
412    /// Returns ln(10) with the given precision.
413    fn raw_ln_10(precision: u32) -> Self;
414
415    /// Returns log₁₀(2) with the given precision.
416    fn raw_log10_2(precision: u32) -> Self;
417
418    /// Returns log₂(10) with the given precision.
419    fn raw_log2_10(precision: u32) -> Self;
420
421    /// Returns log₂(e) with the given precision.
422    fn raw_log2_e(precision: u32) -> Self;
423
424    /// Returns log₁₀(e) with the given precision.
425    fn raw_log10_e(precision: u32) -> Self;
426
427    /// Returns e (Euler's number) with the given precision.
428    fn raw_e(precision: u32) -> Self;
429
430    /// Tries to create a new raw real value from an `f64`.
431    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
432        value: f64,
433    ) -> Result<Self, ErrorsTryFromf64<Self>>;
434
435    /// Returns the precision (in bits) of the raw real type.
436    fn precision(&self) -> u32;
437
438    /// Safely converts the truncated value to `usize`.
439    ///
440    /// Truncates toward zero and validates the result is a valid `usize`.
441    ///
442    /// # Returns
443    ///
444    /// - `Ok(usize)`: If truncated value is in `0..=usize::MAX`
445    /// - `Err(ErrorsRawRealToInteger)`: If value is not finite or out of range
446    ///   - `NotFinite`: Value is `NaN` or `±∞`
447    ///   - `OutOfRange`: Value is negative or > `usize::MAX`
448    ///
449    /// # Note
450    ///
451    /// The `NotAnInteger` error variant is not returned because truncation
452    /// explicitly handles the fractional part.
453    ///
454    /// # Examples
455    ///
456    /// ```
457    /// # use num_valid::core::traits::raw::RawRealTrait;
458    /// let value = 42.9_f64;
459    /// assert_eq!(value.truncate_to_usize().unwrap(), 42);
460    ///
461    /// let zero = 0.0_f64;
462    /// assert_eq!(zero.truncate_to_usize().unwrap(), 0);
463    /// ```
464    ///
465    /// ## Error cases
466    ///
467    /// ```
468    /// # use num_valid::core::traits::raw::RawRealTrait;
469    /// # use num_valid::core::errors::ErrorsRawRealToInteger;
470    /// // Negative value
471    /// let neg = -10.5_f64;
472    /// assert!(matches!(neg.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
473    ///
474    /// // Too large for usize
475    /// let large = (usize::MAX as f64) + 100.0;
476    /// assert!(matches!(large.truncate_to_usize(), Err(ErrorsRawRealToInteger::OutOfRange { .. })));
477    ///
478    /// // Not finite
479    /// let nan = f64::NAN;
480    /// assert!(matches!(nan.truncate_to_usize(), Err(ErrorsRawRealToInteger::NotFinite { .. })));
481    /// ```
482    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<Self, usize>>;
483}
484
485// =============================================================================
486// Complex Trait
487// =============================================================================
488
489/// A trait for raw complex scalar types, extending [`RawScalarTrait`].
490///
491/// This trait is implemented by the underlying complex number types within a kernel,
492/// such as [`num::Complex<f64>`]. It builds upon [`RawScalarTrait`] by adding operations
493/// that are unique to complex numbers.
494///
495/// # Trait Bounds
496///
497/// - `RawScalarTrait<...>`: Ensures the type is a raw scalar and fixes its validation
498///   error type to [`ErrorsValidationRawComplex`], which in turn wraps the validation
499///   error of the associated real type. This establishes a consistent error structure.
500/// - [`Conjugate`]: Requires that the complex number can be conjugated.
501///
502/// # Associated Types
503///
504/// - `type RawReal: RawRealTrait<RawComplex = Self>`: This is a critical part of the
505///   design. It links the complex type to its underlying real component type (e.g., [`f64`]
506///   for [`num::Complex<f64>`]). This associated real type must itself implement [`RawRealTrait`],
507///   creating a two-way link between the real and complex raw types.
508///
509/// # Methods
510///
511/// This trait provides methods for accessing components and performing complex-specific
512/// mathematical operations without validation checks.
513pub trait RawComplexTrait:
514    RawScalarTrait<
515        ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<Self::RawReal>>,
516    > + Conjugate
517    + for<'a> Mul<&'a Self::RawReal, Output = Self>
518    + for<'a> MulAssign<&'a Self::RawReal>
519{
520    /// The associated real type that makes up the components of this complex type.
521    type RawReal: RawRealTrait<RawComplex = Self>;
522
523    /// Creates a new complex number from real and imaginary parts without validation.
524    fn new_unchecked_raw_complex(real: Self::RawReal, imag: Self::RawReal) -> Self;
525
526    /// Computes the absolute value (modulus or norm) of `self` without validation.
527    ///
528    /// **Contract:** The caller must ensure the input is valid for this operation.
529    fn unchecked_abs(self) -> Self::RawReal;
530
531    /// Returns a reference to the real part of the complex number.
532    fn raw_real_part(&self) -> &Self::RawReal;
533
534    /// Returns a reference to the imaginary part of the complex number.
535    fn raw_imag_part(&self) -> &Self::RawReal;
536
537    /// Returns a mutable reference to the real part of the complex number.
538    fn mut_raw_real_part(&mut self) -> &mut Self::RawReal;
539
540    /// Returns a mutable reference to the imaginary part of the complex number.
541    fn mut_raw_imag_part(&mut self) -> &mut Self::RawReal;
542
543    /// Computes the argument (or phase) of `self` in radians, without validation.
544    ///
545    /// **Contract:** The caller must ensure that `self` is not zero.
546    fn unchecked_arg(self) -> Self::RawReal;
547
548    /// Raises `self` to the power of a real `exponent` without validation.
549    ///
550    /// **Contract:** The caller must ensure the inputs are valid for the power function.
551    fn unchecked_pow_exponent_real(self, exponent: &Self::RawReal) -> Self;
552}