Skip to main content

num_valid/core/traits/
validation.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Validation traits and marker traits for scalar types.
4//!
5//! This module provides traits for floating-point classification checks and
6//! marker traits that guarantee certain properties of validated types.
7
8use crate::{
9    core::traits::raw::RawScalarValidate,
10    kernels::{RawComplexTrait, RawRealTrait},
11};
12use num::Complex;
13use num_traits::Float;
14use try_create::ValidationPolicy;
15
16pub(crate) mod sealed {
17    use crate::RawRealTrait;
18    use duplicate::duplicate_item;
19    use num_traits::{Float, FloatConst, MulAdd, MulAddAssign};
20    use std::{hash::Hash, ops::RemAssign};
21    //use try_create::IntoInner;
22
23    pub trait NativeReal:
24        RawRealTrait + Float + FloatConst + MulAdd<Output = Self> + MulAddAssign + RemAssign
25    //        + IntoInner<InnerType = Self>
26    {
27        const MANTISSA_DIGITS: u32;
28        type Bits: Hash;
29
30        fn round_ties_even_native_real(&self) -> Self;
31
32        fn to_bits_native_real(&self) -> Self::Bits;
33    }
34
35    #[duplicate_item(
36        T     mantissa_digits bits;
37        [f32] [24]            [u32];
38        [f64] [53]            [u64];
39    )]
40    impl NativeReal for T {
41        const MANTISSA_DIGITS: u32 = mantissa_digits;
42        type Bits = bits;
43
44        #[inline(always)]
45        fn round_ties_even_native_real(&self) -> Self {
46            T::round_ties_even(*self)
47        }
48
49        #[inline(always)]
50        fn to_bits_native_real(&self) -> Self::Bits {
51            T::to_bits(*self)
52        }
53    }
54}
55
56/// Provides a set of fundamental floating-point classification checks.
57///
58/// This trait defines common methods to determine the characteristics of a numerical value,
59/// such as whether it is finite, infinite, NaN (Not a Number), or normal.
60/// It is implemented for standard floating-point types (`f64`), complex numbers
61/// (`num::Complex<f64>`), and their arbitrary-precision counterparts from the `rug`
62/// library (via `RealRugStrictFinite<P>` and `ComplexRugStrictFinite<P>` which internally use [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html)
63/// and [`rug::Complex`](https://docs.rs/rug/latest/rug/struct.Complex.html)) when the "rug" feature is enabled.
64///
65/// `FpChecks` is often used as a supertrait for more general numerical traits like
66/// [`FpScalar`](crate::FpScalar), ensuring that types representing floating-point
67/// scalars can be queried for these basic properties. This is essential for
68/// validation policies and writing robust numerical algorithms.
69///
70/// Note that this trait focuses on these specific classifications. For more detailed
71/// categorization (like distinguishing subnormals or zero explicitly through this trait),
72/// types may provide other methods (e.g., `classify()` for `f64` and [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html),
73/// or `is_zero()` from [`FpScalar`](crate::FpScalar)).
74pub trait FpChecks {
75    /// Returns [`true`] if `self` is finite (i.e., not infinite and not NaN).
76    ///
77    /// For complex numbers, this typically means both the real and imaginary parts are finite.
78    fn is_finite(&self) -> bool;
79
80    /// Returns [`true`] if `self` is positive infinity or negative infinity.
81    ///
82    /// For complex numbers, this typically means at least one part is infinite,
83    /// and no part is NaN.
84    fn is_infinite(&self) -> bool;
85
86    /// Returns [`true`] if `self` is NaN (Not a Number).
87    ///
88    /// For complex numbers, this typically means at least one part is NaN.
89    fn is_nan(&self) -> bool;
90
91    /// Returns [`true`] if `self` is a *normal* number.
92    ///
93    /// A normal number is a finite, non-zero number that is not subnormal.
94    /// For complex numbers, this typically means both real and imaginary parts are normal
95    /// numbers (and thus individually finite, non-zero, and not subnormal).
96    fn is_normal(&self) -> bool;
97}
98
99impl<T: sealed::NativeReal> FpChecks for T {
100    #[inline(always)]
101    fn is_finite(&self) -> bool {
102        <T as Float>::is_finite(*self)
103    }
104
105    #[inline(always)]
106    fn is_infinite(&self) -> bool {
107        <T as Float>::is_infinite(*self)
108    }
109
110    #[inline(always)]
111    fn is_nan(&self) -> bool {
112        <T as Float>::is_nan(*self)
113    }
114
115    #[inline(always)]
116    fn is_normal(&self) -> bool {
117        <T as Float>::is_normal(*self)
118    }
119}
120
121impl<T: sealed::NativeReal> FpChecks for Complex<T> {
122    #[inline(always)]
123    fn is_finite(&self) -> bool {
124        self.re.is_finite() && self.im.is_finite()
125    }
126
127    #[inline(always)]
128    fn is_infinite(&self) -> bool {
129        self.re.is_infinite() || self.im.is_infinite()
130    }
131
132    #[inline(always)]
133    fn is_nan(&self) -> bool {
134        self.re.is_nan() || self.im.is_nan()
135    }
136
137    #[inline(always)]
138    fn is_normal(&self) -> bool {
139        self.re.is_normal() && self.im.is_normal()
140    }
141}
142
143//------------------------------------------------------------------------------------------------
144
145//------------------------------------------------------------------------------------------------
146/// A marker for policies that apply to real types.
147///
148/// This trait refines the generic [`ValidationPolicy`] for types that implement
149/// [`RawRealTrait`]. It adds two key constraints:
150///
151/// 1.  It associates a `const PRECISION` with the policy, essential for backends
152///     like `rug`.
153/// 2.  It enforces that the policy's `Error` type must be the same as the canonical
154///     `ValidationError` type defined on the raw scalar itself. This architectural
155///     choice ensures consistent error handling throughout the library.
156pub trait ValidationPolicyReal:
157    ValidationPolicy<
158        Value: RawRealTrait,
159        Error = <<Self as ValidationPolicy>::Value as RawScalarValidate>::ValidationError,
160    >
161{
162    /// The precision (in bits) of the validated real type.
163    ///
164    /// For IEEE 754 double-precision (`f64`), this is 53 bits.
165    /// For arbitrary-precision types like `rug::Float`, this can be any positive integer.
166    const PRECISION: u32;
167}
168
169/// A marker for policies that apply to complex types.
170///
171/// This trait refines the generic [`ValidationPolicy`] for types that implement
172/// [`RawComplexTrait`]. It adds two key constraints:
173///
174/// 1.  It associates a `const PRECISION` with the policy, essential for backends
175///     like `rug`.
176/// 2.  It enforces that the policy's `Error` type must be the same as the canonical
177///     `ValidationError` type defined on the raw scalar itself. This architectural
178///     choice ensures consistent error handling throughout the library.
179pub trait ValidationPolicyComplex:
180    ValidationPolicy<
181        Value: RawComplexTrait,
182        Error = <<Self as ValidationPolicy>::Value as RawScalarValidate>::ValidationError,
183    >
184{
185    /// The precision (in bits) of the validated complex type's components.
186    ///
187    /// For IEEE 754 double-precision (`Complex<f64>`), this is 53 bits.
188    /// For arbitrary-precision types like `rug::Complex`, this can be any positive integer.
189    const PRECISION: u32;
190}
191
192/// A marker trait for validation policies that guarantee finite real values.
193///
194/// This trait serves as a compile-time marker to identify policies that ensure
195/// all validated real values are always finite (never NaN or infinite). It enables
196/// the implementation of full equality ([`Eq`]) and hashing ([`Hash`]) for
197/// validated types, allowing them to be used as keys in hash-based collections
198/// like [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
199///
200/// ## Enabled Features
201///
202/// When a validation policy implements this trait, the corresponding validated types
203/// (like [`RealValidated<K>`](crate::RealValidated)) automatically gain:
204///
205/// - **Full Equality ([`Eq`])**: Equality becomes reflexive, symmetric, and transitive
206///   since NaN values (which violate these properties) are excluded.
207/// - **Total Ordering ([`Ord`])**: Enables total ordering for validated types, allowing
208///   use in sorted collections like [`BTreeMap`](std::collections::BTreeMap) and [`BTreeSet`](std::collections::BTreeSet),
209///   and enabling standard library sorting operations.
210/// - **Hashing ([`Hash`])**: Combined with [`Eq`], this allows validated types to be
211///   used as keys in hash-based collections like [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
212///
213/// ## Hashing Implementation Details
214///
215/// The [`Hash`] implementation for validated types:
216/// - Delegates to the underlying raw type's [`RawScalarTrait::compute_hash_raw_scalar()`](crate::core::traits::raw::RawScalarTrait::compute_hash_raw_scalar) method
217/// - Handles IEEE 754 floating-point edge cases correctly (e.g., signed zeros)
218/// - Maintains the contract that `a == b` implies `hash(a) == hash(b)`
219/// - Works with both native `f64`/`Complex<f64>` and arbitrary-precision `rug` types
220///
221/// ## Comparison and Ordering
222///
223/// Validated types with finite value guarantees support multiple comparison mechanisms:
224/// 1. **Partial Ordering ([`PartialOrd`])**: Always available, efficient for comparisons
225/// 2. **Total Ordering ([`Ord`])**: Available when this trait is implemented, enables sorted collections
226/// 3. **Reference-based comparison**: The library's [`Max`](crate::functions::Max)/[`Min`](crate::functions::Min)
227///    traits provide `max_by_ref()`/`min_by_ref()` methods that avoid unnecessary cloning
228///
229/// ## Use Cases
230///
231/// This marker trait enables validated numerical types to be used in contexts that
232/// require [`Eq`], [`Hash`], and [`Ord`]:
233///
234/// ```rust
235/// use num_valid::{RealNative64StrictFinite, functions::Max};
236/// use std::collections::{HashMap, HashSet, BTreeMap, BTreeSet};
237/// use try_create::TryNew;
238///
239/// // Use as HashMap keys (requires Eq + Hash)
240/// let mut scores = HashMap::new();
241/// let player1 = RealNative64StrictFinite::try_new(1.5).unwrap();
242/// scores.insert(player1, 100);
243///
244/// // Use in HashSet (requires Eq + Hash)
245/// let mut unique_values = HashSet::new();
246/// unique_values.insert(RealNative64StrictFinite::try_new(3.14).unwrap());
247///
248/// // Use in BTreeMap (requires Ord)
249/// let mut sorted_scores = BTreeMap::new();
250/// sorted_scores.insert(RealNative64StrictFinite::try_new(1.5).unwrap(), 100);
251///
252/// // Comparison works with both PartialOrd and Ord
253/// let a = RealNative64StrictFinite::try_new(1.0).unwrap();
254/// let b = RealNative64StrictFinite::try_new(2.0).unwrap();
255/// assert!(a < b);  // Uses PartialOrd
256/// assert_eq!(a.clone().max(b.clone()), b);  // Uses Ord::max from std (consumes values)
257/// assert_eq!(a.max_by_ref(&b), &b);  // Uses library's Max trait (avoids cloning)
258/// ```
259///
260/// ## Hash Collision Considerations
261///
262/// The hashing implementation ensures:
263/// - Consistent hashes for mathematically equal values
264/// - Proper handling of floating-point edge cases
265/// - Compatibility with both native and arbitrary-precision backends
266/// - No hash collisions due to NaN values (which are excluded by design)
267///
268/// ## Currently Implemented By
269///
270/// - [`StrictFinitePolicy<T, P>`](crate::core::policies::StrictFinitePolicy): The primary policy that
271///   rejects NaN, infinity, and subnormal values.
272/// - [`DebugValidationPolicy<StrictFinitePolicy<T, P>>`](crate::core::policies::DebugValidationPolicy):
273///   A wrapper that applies strict validation only in debug builds.
274///
275/// ## Safety and Correctness
276///
277/// This trait should only be implemented by validation policies that genuinely
278/// guarantee finite values. Incorrect implementation could lead to hash collisions
279/// or violated equality contracts in the methods that rely on this guarantee.
280///
281/// The trait is designed as a marker trait (no methods) to emphasize that it's
282/// purely a compile-time contract rather than runtime functionality.
283pub trait GuaranteesFiniteRealValues: ValidationPolicyReal {}
284
285/// Marker trait indicating that a validation policy guarantees finite complex values.
286///
287/// This trait serves as a compile-time indicator that a validation policy for
288/// complex numbers ensures all validated values have finite real and imaginary components
289/// (i.e., neither component is NaN or infinity). This guarantee enables the
290/// implementation of [`Eq`] and [`Hash`] for [`ComplexValidated`](crate::core::types::ComplexValidated) types, allowing
291/// them to be used as keys in hash-based collections like [`HashMap`](std::collections::HashMap)
292/// and [`HashSet`](std::collections::HashSet).
293///
294/// ## Purpose
295///
296/// Complex numbers can have NaN or infinite components, making equality comparison
297/// problematic (NaN != NaN). By guaranteeing finiteness at the policy level,
298/// this trait allows:
299/// - Full equality ([`Eq`]) implementation for complex validated types
300/// - Consistent hashing ([`Hash`]) for use in hash-based collections
301/// - Compile-time verification of these properties
302///
303/// ## Design Rationale
304///
305/// This trait works in tandem with [`GuaranteesFiniteRealValues`] for real numbers:
306/// - [`GuaranteesFiniteRealValues`]: For real number policies
307/// - [`GuaranteesFiniteComplexValues`]: For complex number policies
308///
309/// This separation allows different validation strategies for real and complex
310/// components while maintaining type safety.
311///
312/// ## Currently Implemented By
313///
314/// - [`StrictFinitePolicy<T, P>`](crate::core::policies::StrictFinitePolicy): Validates both real and imaginary
315///   components for finiteness and non-subnormal values.
316/// - [`DebugValidationPolicy<StrictFinitePolicy<T, P>>`](crate::core::policies::DebugValidationPolicy):
317///   Applies strict validation only in debug builds.
318///
319/// ## Safety and Correctness
320///
321/// This trait should only be implemented by validation policies that genuinely
322/// guarantee finite values in both components. Incorrect implementation could lead
323/// to hash collisions or violated equality contracts.
324pub trait GuaranteesFiniteComplexValues: ValidationPolicyComplex {}