Skip to main content

num_valid/
scalars.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Type-safe scalar wrappers for numerical tolerances and constrained real values.
4//!
5//! This module provides strongly-typed wrappers around primitive scalar types to prevent
6//! value confusion and enforce mathematical constraints at compile time. These types are
7//! fundamental building blocks for numerical computations that require validated tolerances
8//! and constrained real number values.
9//!
10//! # Overview
11//!
12//! The module provides four primary types:
13//!
14//! | Type | Constraint | Zero Valid? | Use Cases |
15//! |------|------------|-------------|-----------|
16//! | [`AbsoluteTolerance<T>`] | `≥ 0` | ✅ Yes | Fixed error bounds for comparisons |
17//! | [`RelativeTolerance<T>`] | `≥ 0` | ✅ Yes | Proportional error bounds |
18//! | [`PositiveRealScalar<T>`] | `> 0` | ❌ No | Lengths, positive quantities |
19//! | [`NonNegativeRealScalar<T>`] | `≥ 0` | ✅ Yes | Distances, magnitudes, absolute values |
20//!
21//! All types are generic over [`RealScalar`], enabling consistent validation across
22//! different numerical backends (native `f64`, arbitrary-precision `rug`, etc.).
23//!
24//! ## Architectural Design
25//!
26//! - **Tolerance Types** ([`AbsoluteTolerance<T>`], [`RelativeTolerance<T>`]): Semantically specialized
27//!   wrappers built on top of [`NonNegativeRealScalar<T>`]. They inherit all validation and provide
28//!   tolerance-specific methods like [`RelativeTolerance::absolute_tolerance()`].
29//! - **Constrained Scalar Types** ([`PositiveRealScalar<T>`], [`NonNegativeRealScalar<T>`]): Full-featured
30//!   types with algebraic operations (addition, multiplication, powers), comparison traits, and immutable
31//!   access patterns. They form the foundation for general mathematical computations.
32//! - **Comparative Utilities**: The [`approximately_equal()`] function provides precise, tolerance-aware
33//!   value comparisons across all scalar types.
34//!
35//! # Design Philosophy
36//!
37//! ## Type Safety Through Distinct Types
38//!
39//! Rather than using raw primitives like `f64` directly, this module provides
40//! semantically meaningful types that encode mathematical constraints:
41//!
42//! ```rust
43//! use num_valid::{
44//!     backends::native::validated::RealNative64StrictFinite, RealScalar,
45//!     scalars::{AbsoluteTolerance, RelativeTolerance, PositiveRealScalar},
46//! };
47//! use try_create::TryNew;
48//!
49//! // These are different types that cannot be confused:
50//! let abs_tol = AbsoluteTolerance::try_new(
51//!     RealNative64StrictFinite::try_new(1e-10_f64).unwrap()
52//! ).unwrap();   // For absolute comparisons
53//! let rel_tol = RelativeTolerance::try_new(1e-6_f64).unwrap();    // For relative comparisons
54//! let length = PositiveRealScalar::try_new(5.0_f64).unwrap();     // Must be > 0
55//!
56//! // Type system prevents mixing them up:
57//! // let wrong: AbsoluteTolerance<f64> = rel_tol;  // ← Compilation error!
58//! ```
59//!
60//! ## Validation at Construction Time
61//!
62//! All types validate their input at construction time, failing fast on invalid values:
63//!
64//! ```rust
65//! use num_valid::{*, scalars::*};
66//! use try_create::TryNew;
67//! use std::assert_matches;
68//!
69//! // Negative tolerances are rejected
70//! let invalid_tol = AbsoluteTolerance::try_new(
71//!     RealNative64StrictFinite::try_new(-1e-6_f64).unwrap()
72//! ).unwrap_err();
73//! assert_matches!(invalid_tol, ErrorsNonNegativeRealScalar::NegativeValue { .. });
74//!
75//! // Zero is not positive
76//! let invalid_pos = PositiveRealScalar::try_new(0.0_f64).unwrap_err();
77//! assert_matches!(invalid_pos, ErrorsPositiveRealScalar::ZeroValue { .. });
78//! ```
79//!
80//! # Error Handling
81//!
82//! Both [`AbsoluteTolerance<T>`] and [`RelativeTolerance<T>`] use [`ErrorsNonNegativeRealScalar`]
83//! for error reporting, since they are wrappers around [`NonNegativeRealScalar<T>`]. This provides
84//! consistent error semantics:
85//!
86//! - **No negative values:** Both types reject negative inputs
87//! - **Debug validation:** NaN and infinity are panicked on in debug builds
88//! - **Backtrace support:** When the `backtrace` feature is enabled
89//!
90//! # Tolerance Types
91//!
92//! ## [`AbsoluteTolerance<T>`]
93//!
94//! Represents an absolute error bound for numerical comparisons. The tolerance value
95//! must be non-negative (≥ 0).
96//!
97//! ```rust
98//! use num_valid::{*, scalars::*};
99//! use try_create::TryNew;
100//!
101//! // Create tolerances
102//! let tight = AbsoluteTolerance::try_new(1e-12_f64).unwrap();
103//! let loose = AbsoluteTolerance::try_new(1e-6_f64).unwrap();
104//! let zero = AbsoluteTolerance::<f64>::zero();       // Exact comparison
105//! let epsilon = AbsoluteTolerance::<f64>::epsilon(); // Machine epsilon
106//!
107//! // Use in approximate comparison
108//! assert!(approximately_equal(1.0, 1.0 + 1e-13, &tight));
109//! assert!(!approximately_equal(1.0, 1.0 + 1e-11, &tight));
110//! ```
111//!
112//! ## [`RelativeTolerance<T>`]
113//!
114//! Represents a relative (proportional) error bound. Can be converted to an absolute
115//! tolerance based on a reference value.
116//!
117//! ```rust
118//! use num_valid::scalars::RelativeTolerance;
119//! use try_create::TryNew;
120//!
121//! let rel_tol = RelativeTolerance::try_new(0.01_f64).unwrap(); // 1% tolerance
122//!
123//! // Convert to absolute tolerance based on reference value
124//! let reference = 1000.0_f64;
125//! let abs_tol = rel_tol.absolute_tolerance(reference);
126//! assert_eq!(*abs_tol.as_ref().as_ref(), 10.0); // 1% of 1000 = 10
127//! ```
128//!
129//! # Constrained Real Number Types
130//!
131//! ## [`PositiveRealScalar<T>`]
132//!
133//! Wraps a real scalar that must be strictly positive (> 0). Zero is **not** valid.
134//!
135//! ```rust
136//! use num_valid::scalars::{PositiveRealScalar, ErrorsPositiveRealScalar};
137//! use try_create::TryNew;
138//!
139//! // Valid positive values
140//! let length = PositiveRealScalar::try_new(2.5_f64).unwrap();
141//! let tiny = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
142//!
143//! // Zero is NOT positive (x > 0 required)
144//! let zero_result = PositiveRealScalar::try_new(0.0_f64);
145//! assert!(matches!(zero_result, Err(ErrorsPositiveRealScalar::ZeroValue { .. })));
146//!
147//! // Negative values rejected
148//! let neg_result = PositiveRealScalar::try_new(-1.0_f64);
149//! assert!(matches!(neg_result, Err(ErrorsPositiveRealScalar::NegativeValue { .. })));
150//! ```
151//!
152//! ## [`NonNegativeRealScalar<T>`]
153//!
154//! Wraps a real scalar that must be non-negative (≥ 0). Zero **is** valid.
155//!
156//! ```rust
157//! use num_valid::scalars::{NonNegativeRealScalar, PositiveRealScalar};
158//! use try_create::TryNew;
159//!
160//! // Zero is valid for NonNegativeRealScalar
161//! let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
162//! assert_eq!(*zero.as_ref(), 0.0);
163//!
164//! // But NOT for PositiveRealScalar
165//! assert!(PositiveRealScalar::try_new(0.0_f64).is_err());
166//!
167//! // Use case: computing distances (can be zero)
168//! fn distance(a: f64, b: f64) -> NonNegativeRealScalar<f64> {
169//!     NonNegativeRealScalar::try_new((a - b).abs()).unwrap()
170//! }
171//!
172//! let d = distance(5.0, 5.0); // Zero distance is valid
173//! assert_eq!(*d.as_ref(), 0.0);
174//! ```
175//!
176//! # Generic Programming with [`RealScalar`]
177//!
178//! All types work seamlessly with any scalar type implementing [`RealScalar`]:
179//!
180//! ```rust
181//! use num_valid::{
182//!     backends::native::validated::{RealNative64StrictFinite, RealNative64StrictFiniteInDebug},
183//!     RealScalar,
184//!     scalars::AbsoluteTolerance
185//! };
186//! use try_create::TryNew;
187//!
188//! // Same tolerance type works with different backends
189//! type FastTol = AbsoluteTolerance<f64>;
190//! type SafeTol = AbsoluteTolerance<RealNative64StrictFinite>;
191//! type DebugTol = AbsoluteTolerance<RealNative64StrictFiniteInDebug>;
192//!
193//! let fast = FastTol::try_new(1e-10).unwrap();
194//! let safe = SafeTol::try_new(RealNative64StrictFinite::try_from_f64(1e-10).unwrap()).unwrap();
195//! ```
196//!
197//! # Performance Characteristics
198//!
199//! All wrapper types are designed as zero-cost abstractions:
200//!
201//! | Type | Memory Layout | Runtime Overhead |
202//! |------|---------------|------------------|
203//! | [`AbsoluteTolerance<T>`] | Same as `T` | Zero (validation at construction only) |
204//! | [`RelativeTolerance<T>`] | Same as `T` | Zero (validation at construction only) |
205//! | [`PositiveRealScalar<T>`] | Same as `T` | Zero (validation at construction only) |
206//! | [`NonNegativeRealScalar<T>`] | Same as `T` | Zero (validation at construction only) |
207//!
208//! The `#[repr(transparent)]` attribute ensures that each wrapper has the exact same
209//! memory layout as its underlying type.
210//!
211//! # Relationship to `approx` Crate
212//!
213//! These tolerance types complement the [`approx`] crate's comparison traits. While `approx`
214//! uses raw `f64` for epsilon values (which can be negative, causing silent failures),
215//! these wrappers guarantee non-negativity at construction time:
216//!
217//! ```rust
218//! use num_valid::scalars::AbsoluteTolerance;
219//! use num_valid::approx::assert_abs_diff_eq;
220//!
221//! // Create a validated tolerance
222//! let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
223//!
224//! // Use with approx (extract the inner value)
225//! let a = 1.0_f64;
226//! let b = 1.0 + 1e-11;
227//! assert_abs_diff_eq!(a, b, epsilon = *tol.as_ref().as_ref());
228//! ```
229
230use crate::{
231    Pow, RealScalar,
232    algorithms::accumulators::{NeumaierAddable, neumaier_sum_and_compensation_real},
233    core::errors::capture_backtrace,
234    functions::{Max, Min, PowIntExponentErrors},
235};
236use derive_more::{AsRef, Display, LowerExp};
237use duplicate::duplicate_item;
238use into_inner::IntoInner;
239use num::{One, Zero};
240use serde::{Deserialize, Serialize};
241use std::{
242    backtrace::Backtrace,
243    ops::{Add, AddAssign, Mul, MulAssign},
244};
245use thiserror::Error;
246use try_create::TryNew;
247
248//------------------------------------------------------------------------------------------------------------
249// Error Types
250//------------------------------------------------------------------------------------------------------------
251
252/// Error type for [`PositiveRealScalar<T>`] validation failures.
253///
254/// This enum provides detailed error information when attempting to construct
255/// a [`PositiveRealScalar<T>`] with invalid input values.
256///
257/// # Error Variants
258///
259/// - [`ErrorsPositiveRealScalar::NegativeValue`]: The input was negative (< 0).
260/// - [`ErrorsPositiveRealScalar::ZeroValue`]: The input was zero (not strictly positive).
261///
262/// # Mathematical Distinction
263///
264/// Positive real numbers are defined as `ℝ⁺ = {x ∈ ℝ : x > 0}`, which **excludes** zero.
265/// This is distinct from non-negative reals `ℝ₀⁺ = {x ∈ ℝ : x ≥ 0}`.
266///
267/// # Examples
268///
269/// ```rust
270/// use num_valid::scalars::{PositiveRealScalar, ErrorsPositiveRealScalar};
271/// use try_create::TryNew;
272///
273/// // Zero is NOT positive
274/// match PositiveRealScalar::try_new(0.0_f64) {
275///     Err(ErrorsPositiveRealScalar::ZeroValue { .. }) => {
276///         println!("Zero is not strictly positive (x > 0 required)");
277///     }
278///     _ => unreachable!(),
279/// }
280///
281/// // Negative values rejected with the value included in the error
282/// match PositiveRealScalar::try_new(-2.5_f64) {
283///     Err(ErrorsPositiveRealScalar::NegativeValue { value, .. }) => {
284///         assert_eq!(value, -2.5);
285///     }
286///     _ => unreachable!(),
287/// }
288/// ```
289#[derive(Debug, Error)]
290pub enum ErrorsPositiveRealScalar<RealType: RealScalar> {
291    /// The input value was negative (< 0).
292    #[error("Negative value detected: {value} (valid value must be strictly positive, i.e., > 0)")]
293    NegativeValue {
294        /// The specific negative value that was rejected.
295        value: RealType,
296        /// Stack trace for debugging.
297        backtrace: Backtrace,
298    },
299
300    /// The input value was exactly zero (not strictly positive).
301    ///
302    /// Zero is NOT positive in mathematical terms. The positive real numbers
303    /// are defined as `ℝ⁺ = {x ∈ ℝ : x > 0}`, which excludes zero.
304    #[error("Zero value detected (valid value must be strictly positive, i.e., > 0)")]
305    ZeroValue {
306        /// Stack trace for debugging.
307        backtrace: Backtrace,
308    },
309}
310
311/// Error type for [`NonNegativeRealScalar<T>`] validation failures.
312///
313/// This enum provides error information when attempting to construct a
314/// [`NonNegativeRealScalar<T>`] with a negative value.
315///
316/// # Error Variants
317///
318/// - [`ErrorsNonNegativeRealScalar::NegativeValue`]: The input was negative (< 0).
319///
320/// Note that zero is **valid** for [`NonNegativeRealScalar`], unlike [`PositiveRealScalar`].
321///
322/// # Examples
323///
324/// ```rust
325/// use num_valid::scalars::{NonNegativeRealScalar, ErrorsNonNegativeRealScalar};
326/// use try_create::TryNew;
327///
328/// // Zero is valid for NonNegativeRealScalar
329/// let zero = NonNegativeRealScalar::try_new(0.0_f64);
330/// assert!(zero.is_ok());
331///
332/// // Negative values are rejected
333/// match NonNegativeRealScalar::try_new(-1.0_f64) {
334///     Err(ErrorsNonNegativeRealScalar::NegativeValue { value, .. }) => {
335///         assert_eq!(value, -1.0);
336///     }
337///     _ => unreachable!(),
338/// }
339/// ```
340#[derive(Debug, Error)]
341pub enum ErrorsNonNegativeRealScalar<RealType: RealScalar> {
342    /// The input value was negative (must be ≥ 0).
343    #[error("Negative value detected: {value} (valid value must be non-negative, i.e., ≥ 0)")]
344    NegativeValue {
345        /// The negative value that was rejected.
346        value: RealType,
347        /// Stack trace for debugging.
348        backtrace: Backtrace,
349    },
350}
351
352//------------------------------------------------------------------------------------------------------------
353// AbsoluteTolerance
354//------------------------------------------------------------------------------------------------------------
355
356/// Type-safe wrapper for absolute tolerance values.
357///
358/// [`AbsoluteTolerance<T>`] represents a non-negative (≥ 0) tolerance value used for
359/// absolute error comparisons. It ensures that the tolerance is always valid by
360/// rejecting negative values at construction time.
361///
362/// # Implementation
363///
364/// This type is a `#[repr(transparent)]` wrapper around [`NonNegativeRealScalar<T>`].
365/// All validation is performed by the underlying `NonNegativeRealScalar`, and errors
366/// are reported as [`ErrorsNonNegativeRealScalar`].
367///
368/// # Mathematical Definition
369///
370/// An absolute tolerance `ε` is used in comparisons like:
371/// ```text
372/// |a - b| ≤ ε
373/// ```
374///
375/// Since `ε` represents a distance or error bound, it must be non-negative.
376///
377/// # Type Parameters
378///
379/// - `RealType`: The underlying real scalar type (e.g., `f64`, [`RealNative64StrictFinite`](crate::RealNative64StrictFinite))
380///
381/// # Examples
382///
383/// ## Basic Usage
384///
385/// ```rust
386/// use num_valid::scalars::AbsoluteTolerance;
387///
388/// // Create from f64
389/// let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
390/// assert_eq!(*tol.as_ref().as_ref(), 1e-10);
391///
392/// // Use convenience constructors
393/// let zero = AbsoluteTolerance::<f64>::zero();
394/// let eps = AbsoluteTolerance::<f64>::epsilon();
395/// ```
396///
397/// ## In Numerical Comparisons
398///
399/// ```rust
400/// use num_valid::{*, scalars::*};
401/// use try_create::{IntoInner, TryNew};
402///
403/// let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
404/// assert!(approximately_equal(1.0, 1.0 + 1e-11, &tol));
405/// assert!(!approximately_equal(1.0, 1.0 + 1e-9, &tol));
406/// ```
407///
408/// # Zero-Cost Abstraction
409///
410/// This type uses `#[repr(transparent)]` and has zero runtime overhead beyond
411/// the initial validation at construction time.
412#[derive(
413    Debug, Clone, PartialEq, PartialOrd, AsRef, IntoInner, Display, LowerExp, Serialize, Deserialize,
414)]
415#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
416#[repr(transparent)]
417pub struct AbsoluteTolerance<RealType: RealScalar>(NonNegativeRealScalar<RealType>);
418
419impl<RealType: RealScalar> AbsoluteTolerance<RealType> {
420    /// Creates an absolute tolerance of zero.
421    ///
422    /// A zero tolerance represents an exact comparison (no error allowed).
423    ///
424    /// # Examples
425    ///
426    /// ```rust
427    /// use num_valid::scalars::AbsoluteTolerance;
428    ///
429    /// let zero_tol = AbsoluteTolerance::<f64>::zero();
430    /// assert_eq!(*zero_tol.as_ref().as_ref(), 0.0);
431    /// ```
432    #[inline(always)]
433    pub fn zero() -> Self {
434        AbsoluteTolerance(NonNegativeRealScalar::zero())
435    }
436
437    /// Creates an absolute tolerance equal to machine epsilon.
438    ///
439    /// Machine epsilon is the smallest value such that `1.0 + epsilon != 1.0`.
440    /// This is often a good default tolerance for floating-point comparisons.
441    ///
442    /// # Examples
443    ///
444    /// ```rust
445    /// use num_valid::scalars::AbsoluteTolerance;
446    ///
447    /// let eps_tol = AbsoluteTolerance::<f64>::epsilon();
448    /// assert_eq!(*eps_tol.as_ref().as_ref(), f64::EPSILON);
449    /// ```
450    #[inline(always)]
451    pub fn epsilon() -> Self {
452        AbsoluteTolerance(NonNegativeRealScalar(RealType::epsilon()))
453    }
454
455    /// Wraps a [`NonNegativeRealScalar<T>`] as an [`AbsoluteTolerance<T>`].
456    ///
457    /// This constructor allows explicit conversion from a validated non-negative scalar
458    /// to a tolerance type, providing semantic clarity.
459    ///
460    /// # Examples
461    ///
462    /// ```rust
463    /// use num_valid::scalars::{AbsoluteTolerance, NonNegativeRealScalar};
464    /// use try_create::TryNew;
465    ///
466    /// let non_neg = NonNegativeRealScalar::try_new(1e-10_f64).unwrap();
467    /// let tol = AbsoluteTolerance::new(non_neg);
468    /// assert_eq!(*tol.as_ref().as_ref(), 1e-10);
469    /// ```
470    pub fn new(value: NonNegativeRealScalar<RealType>) -> Self {
471        AbsoluteTolerance(value)
472    }
473
474    /// Attempts to create a [`AbsoluteTolerance`] from a value.
475    ///
476    /// # Errors
477    ///
478    /// Returns [`ErrorsNonNegativeRealScalar::NegativeValue`] if the input is negative.
479    ///
480    /// # Panics (Debug Mode Only)
481    ///
482    /// In debug builds, panics if the input is not finite (NaN or infinity).
483    pub fn try_new(value: RealType) -> Result<Self, ErrorsNonNegativeRealScalar<RealType>> {
484        NonNegativeRealScalar::try_new(value).map(AbsoluteTolerance)
485    }
486}
487
488/// Compares two scalar values within an absolute tolerance.
489///
490/// Tests whether the absolute difference between two values is less than or equal to
491/// a specified tolerance. This is the standard approach for approximate floating-point
492/// comparisons when the expected magnitude of values is known.
493///
494/// # Mathematical Definition
495///
496/// Returns `true` if and only if:
497/// ```text
498/// |a - b| ≤ tolerance
499/// ```
500///
501/// # Symmetry
502///
503/// The comparison is symmetric: `approximately_equal(a, b, tol) == approximately_equal(b, a, tol)`
504///
505/// # Type Parameters
506///
507/// - `T`: Any scalar type implementing [`RealScalar`]
508///
509/// # Arguments
510///
511/// - `a`: First value
512/// - `b`: Second value to compare with
513/// - `tolerance`: The maximum allowed absolute difference (must be non-negative)
514///
515/// # Examples
516///
517/// ## Basic Floating-Point Comparison
518///
519/// ```rust
520/// use num_valid::scalars::{AbsoluteTolerance, approximately_equal};
521/// use try_create::TryNew;
522///
523/// let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
524///
525/// // Values within tolerance
526/// assert!(approximately_equal(1.0, 1.0 + 1e-11, &tol));
527///
528/// // Values outside tolerance
529/// assert!(!approximately_equal(1.0, 1.0 + 1e-9, &tol));
530///
531/// // Exact match
532/// assert!(approximately_equal(1.0, 1.0, &tol));
533/// ```
534///
535/// ## Zero Tolerance (Exact Comparison)
536///
537/// ```rust
538/// use num_valid::scalars::{AbsoluteTolerance, approximately_equal};
539///
540/// let exact_tol = AbsoluteTolerance::<f64>::zero();
541///
542/// // Only exact matches pass
543/// assert!(approximately_equal(1.0, 1.0, &exact_tol));
544/// assert!(!approximately_equal(1.0, 1.0 + 1e-15, &exact_tol));
545/// ```
546///
547/// ## Negative Values
548///
549/// ```rust
550/// use num_valid::scalars::{AbsoluteTolerance, approximately_equal};
551/// use try_create::TryNew;
552///
553/// let tol = AbsoluteTolerance::try_new(0.1_f64).unwrap();
554///
555/// // Works with negative values
556/// assert!(approximately_equal(-5.0, -5.05, &tol));
557/// assert!(!approximately_equal(-5.0, -5.2, &tol));
558/// ```
559///
560/// # When to Use
561///
562/// - **Use `approximately_equal()`** when you have a fixed maximum allowable error (absolute tolerance)
563/// - **Use [`RelativeTolerance::absolute_tolerance()`]** when the tolerance is proportional to values
564///
565/// # See Also
566///
567/// - [`AbsoluteTolerance`] for creating and managing absolute tolerances
568/// - [`RelativeTolerance`] for proportional error bounds
569pub fn approximately_equal<T: RealScalar>(a: T, b: T, tolerance: &AbsoluteTolerance<T>) -> bool {
570    let diff = (a - b).abs();
571    &diff <= tolerance.as_ref()
572}
573
574//------------------------------------------------------------------------------------------------------------
575// RelativeTolerance
576//------------------------------------------------------------------------------------------------------------
577
578/// Type-safe wrapper for relative tolerance values.
579///
580/// [`RelativeTolerance<T>`] represents a non-negative (≥ 0) tolerance value used for
581/// relative (proportional) error comparisons. It can be converted to an absolute
582/// tolerance based on a reference value.
583///
584/// # Implementation
585///
586/// This type is a `#[repr(transparent)]` wrapper around [`NonNegativeRealScalar<T>`].
587/// All validation is performed by the underlying `NonNegativeRealScalar`, and errors
588/// are reported as [`ErrorsNonNegativeRealScalar`].
589///
590/// # Mathematical Definition
591///
592/// A relative tolerance `ε_rel` is used in comparisons like:
593/// ```text
594/// |a - b| ≤ ε_rel × |reference|
595/// ```
596///
597/// Common relative tolerances:
598/// - `0.01` = 1% tolerance
599/// - `0.001` = 0.1% tolerance
600/// - `1e-6` = one part per million
601///
602/// # Examples
603///
604/// ## Basic Usage
605///
606/// ```rust
607/// use num_valid::scalars::RelativeTolerance;
608/// use try_create::TryNew;
609///
610/// let one_percent = RelativeTolerance::try_new(0.01_f64).unwrap();
611/// assert_eq!(*one_percent.as_ref().as_ref(), 0.01);
612/// ```
613///
614/// ## Converting to Absolute Tolerance
615///
616/// ```rust
617/// use num_valid::scalars::RelativeTolerance;
618/// use try_create::TryNew;
619///
620/// let rel_tol = RelativeTolerance::try_new(0.01_f64).unwrap(); // 1%
621///
622/// // Convert based on reference value
623/// let abs_tol = rel_tol.absolute_tolerance(1000.0);
624/// assert_eq!(*abs_tol.as_ref().as_ref(), 10.0); // 1% of 1000 = 10
625///
626/// // Works with negative references (uses absolute value)
627/// let abs_tol_neg = rel_tol.absolute_tolerance(-500.0);
628/// assert_eq!(*abs_tol_neg.as_ref().as_ref(), 5.0); // 1% of |-500| = 5
629/// ```
630#[derive(
631    Debug, Clone, PartialEq, PartialOrd, AsRef, IntoInner, Display, LowerExp, Serialize, Deserialize,
632)]
633#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
634#[repr(transparent)]
635pub struct RelativeTolerance<RealType: RealScalar>(NonNegativeRealScalar<RealType>);
636
637impl<RealType: RealScalar> RelativeTolerance<RealType> {
638    /// Creates a relative tolerance of zero.
639    ///
640    /// A zero relative tolerance represents an exact comparison.
641    ///
642    /// # Examples
643    ///
644    /// ```rust
645    /// use num_valid::scalars::RelativeTolerance;
646    ///
647    /// let zero_tol = RelativeTolerance::<f64>::zero();
648    /// assert_eq!(*zero_tol.as_ref().as_ref(), 0.0);
649    /// ```
650    #[inline(always)]
651    pub fn zero() -> Self {
652        RelativeTolerance(NonNegativeRealScalar::zero())
653    }
654
655    /// Creates a relative tolerance equal to machine epsilon.
656    ///
657    /// # Examples
658    ///
659    /// ```rust
660    /// use num_valid::scalars::RelativeTolerance;
661    ///
662    /// let eps_tol = RelativeTolerance::<f64>::epsilon();
663    /// assert_eq!(*eps_tol.as_ref().as_ref(), f64::EPSILON);
664    /// ```
665    #[inline(always)]
666    pub fn epsilon() -> Self {
667        RelativeTolerance(NonNegativeRealScalar(RealType::epsilon()))
668    }
669
670    /// Converts this relative tolerance to an absolute tolerance based on a reference value.
671    ///
672    /// The absolute tolerance is computed as:
673    /// ```text
674    /// absolute_tolerance = relative_tolerance × |reference|
675    /// ```
676    ///
677    /// # Parameters
678    ///
679    /// - `reference`: The reference value to scale by. The absolute value is used.
680    ///
681    /// # Examples
682    ///
683    /// ```rust
684    /// use num_valid::scalars::RelativeTolerance;
685    /// use try_create::TryNew;
686    ///
687    /// let rel_tol = RelativeTolerance::try_new(0.1_f64).unwrap(); // 10%
688    ///
689    /// // 10% of 100 = 10
690    /// let abs_tol = rel_tol.absolute_tolerance(100.0);
691    /// assert_eq!(*abs_tol.as_ref().as_ref(), 10.0);
692    ///
693    /// // 10% of |-50| = 5
694    /// let abs_tol_neg = rel_tol.absolute_tolerance(-50.0);
695    /// assert_eq!(*abs_tol_neg.as_ref().as_ref(), 5.0);
696    ///
697    /// // 10% of 0 = 0
698    /// let abs_tol_zero = rel_tol.absolute_tolerance(0.0);
699    /// assert_eq!(*abs_tol_zero.as_ref().as_ref(), 0.0);
700    /// ```
701    #[inline(always)]
702    pub fn absolute_tolerance(&self, reference: RealType) -> AbsoluteTolerance<RealType> {
703        let abs_tol = reference.abs() * &self.0;
704        AbsoluteTolerance(abs_tol)
705    }
706
707    /// Wraps a [`NonNegativeRealScalar<T>`] as a [`RelativeTolerance<T>`].
708    ///
709    /// This constructor allows explicit conversion from a validated non-negative scalar
710    /// to a tolerance type, providing semantic clarity.
711    ///
712    /// # Examples
713    ///
714    /// ```rust
715    /// use num_valid::scalars::{RelativeTolerance, NonNegativeRealScalar};
716    /// use try_create::TryNew;
717    ///
718    /// let non_neg = NonNegativeRealScalar::try_new(0.01_f64).unwrap(); // 1%
719    /// let tol = RelativeTolerance::new(non_neg);
720    /// assert_eq!(*tol.as_ref().as_ref(), 0.01);
721    /// ```
722    pub fn new(value: NonNegativeRealScalar<RealType>) -> Self {
723        RelativeTolerance(value)
724    }
725
726    /// Attempts to create a [`RelativeTolerance`] from a value.
727    ///
728    /// # Errors
729    ///
730    /// Returns [`ErrorsNonNegativeRealScalar::NegativeValue`] if the input is negative.
731    ///
732    /// # Panics (Debug Mode Only)
733    ///
734    /// In debug builds, panics if the input is not finite (NaN or infinity).
735    pub fn try_new(value: RealType) -> Result<Self, ErrorsNonNegativeRealScalar<RealType>> {
736        NonNegativeRealScalar::try_new(value).map(RelativeTolerance)
737    }
738}
739
740//------------------------------------------------------------------------------------------------------------
741// PositiveRealScalar
742//------------------------------------------------------------------------------------------------------------
743
744/// Type-safe wrapper for strictly positive real scalar values.
745///
746/// [`PositiveRealScalar<T>`] guarantees that wrapped values are strictly greater than zero.
747/// Zero is **not** valid for this type. For values that can be zero, use [`NonNegativeRealScalar`].
748///
749/// # Mathematical Definition
750///
751/// ```text
752/// PositiveRealScalar<T> = { x ∈ T : x > 0 }
753/// ```
754///
755/// This is the set of positive real numbers `ℝ⁺`, which **excludes** zero.
756///
757/// # Use Cases
758///
759/// - Lengths and distances that cannot be zero
760/// - Positive tolerances
761/// - Scaling factors that must be positive
762/// - Any quantity that is mathematically required to be > 0
763///
764/// # Examples
765///
766/// ## Basic Usage
767///
768/// ```rust
769/// use num_valid::scalars::{PositiveRealScalar, ErrorsPositiveRealScalar};
770/// use try_create::TryNew;
771///
772/// // Valid positive values
773/// let length = PositiveRealScalar::try_new(2.5_f64).unwrap();
774/// let tiny = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
775///
776/// // Zero is NOT positive
777/// assert!(matches!(
778///     PositiveRealScalar::try_new(0.0_f64),
779///     Err(ErrorsPositiveRealScalar::ZeroValue { .. })
780/// ));
781///
782/// // Negative values rejected
783/// assert!(matches!(
784///     PositiveRealScalar::try_new(-1.0_f64),
785///     Err(ErrorsPositiveRealScalar::NegativeValue { .. })
786/// ));
787/// ```
788///
789/// ## Difference from [`NonNegativeRealScalar`]
790///
791/// ```rust
792/// use num_valid::scalars::{PositiveRealScalar, NonNegativeRealScalar};
793/// use try_create::TryNew;
794///
795/// // Zero is INVALID for PositiveRealScalar (x > 0)
796/// assert!(PositiveRealScalar::try_new(0.0_f64).is_err());
797///
798/// // Zero is VALID for NonNegativeRealScalar (x ≥ 0)
799/// assert!(NonNegativeRealScalar::try_new(0.0_f64).is_ok());
800/// ```
801///
802/// ## Algebraic and Ordering Operations
803///
804/// [`PositiveRealScalar`] supports:
805/// - **Addition**: Sum of positive values is positive
806/// - **Multiplication**: Product of positive values is positive  
807/// - **Integer powers**: Raising positive to any integer exponent yields positive
808/// - **Square root**: Preserves positivity (√x > 0 if x > 0)
809/// - **Multiplicative identity** ([`One`]): For neutral multiplication operations
810/// - **Comparison** ([`Max`], [`Min`]): Ordering and selection helpers
811///
812/// ```rust
813/// use num::One;
814/// use num_valid::{
815///     functions::{Max, Min, Pow},
816///     scalars::PositiveRealScalar,
817/// };
818/// use try_create::{IntoInner, TryNew};
819///
820/// let a = PositiveRealScalar::try_new(2.0_f64).unwrap();
821/// let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
822///
823/// // Add preserves positivity for valid operands.
824/// let sum = a.clone() + b.clone();
825/// assert_eq!(*sum.as_ref(), 5.0);
826///
827/// // Multiply preserves positivity
828/// let product = a.clone() * b.clone();
829/// assert_eq!(*product.as_ref(), 6.0);
830///
831/// // Integer powers preserve positivity
832/// let squared = a.clone().pow(2u32);
833/// assert_eq!(*squared.as_ref(), 4.0);
834///
835/// // Square root preserves positivity
836/// let sqrt = PositiveRealScalar::try_new(4.0_f64).unwrap().sqrt();
837/// assert_eq!(*sqrt.as_ref(), 2.0);
838///
839/// // One is the multiplicative identity.
840/// let one = PositiveRealScalar::<f64>::one();
841/// let result = a.clone() * one;
842/// assert_eq!(*result.as_ref(), 2.0);
843///
844/// let x = PositiveRealScalar::try_new(1.0_f64).unwrap();
845/// let y = PositiveRealScalar::try_new(3.0_f64).unwrap();
846/// assert_eq!(*Max::max_by_ref(&x, &y).as_ref(), 3.0);
847/// assert_eq!(*Min::min_by_value(x, y).as_ref(), 1.0);
848/// ```
849#[derive(
850    Debug, Clone, PartialEq, PartialOrd, AsRef, IntoInner, Display, Serialize, Deserialize,
851)]
852#[repr(transparent)]
853#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
854pub struct PositiveRealScalar<RealType: RealScalar>(RealType);
855
856impl<RealType: RealScalar> PositiveRealScalar<RealType> {
857    /// Computes the square root of this positive scalar.
858    ///
859    /// Since the input is guaranteed to be positive, the result is always defined
860    /// and remains positive.
861    ///
862    /// # Examples
863    ///
864    /// ```rust
865    /// use num_valid::scalars::PositiveRealScalar;
866    /// use try_create::TryNew;
867    ///
868    /// let value = PositiveRealScalar::try_new(4.0_f64).unwrap();
869    /// let sqrt = value.sqrt();
870    /// assert_eq!(*sqrt.as_ref(), 2.0);
871    /// ```
872    pub fn sqrt(self) -> Self {
873        PositiveRealScalar(self.0.sqrt())
874    }
875
876    #[inline(always)]
877    pub fn new(value: RealType) -> Self {
878        #[cfg(debug_assertions)]
879        {
880            Self::try_new(value)
881                .expect("Error in the creation of the positive real scalar in debug mode")
882        }
883        #[cfg(not(debug_assertions))]
884        {
885            Self(value)
886        }
887    }
888}
889
890impl<RealType: RealScalar> TryNew for PositiveRealScalar<RealType> {
891    type Error = ErrorsPositiveRealScalar<RealType>;
892
893    /// Attempts to create a [`PositiveRealScalar`] from a value.
894    ///
895    /// # Errors
896    ///
897    /// - [`ErrorsPositiveRealScalar::NegativeValue`]: If the input is negative (< 0).
898    /// - [`ErrorsPositiveRealScalar::ZeroValue`]: If the input is zero.
899    ///
900    /// # Panics (Debug Mode Only)
901    ///
902    /// In debug builds, panics if the input is not finite (NaN or infinity).
903    ///
904    /// # Examples
905    ///
906    /// ```rust
907    /// use num_valid::scalars::{PositiveRealScalar, ErrorsPositiveRealScalar};
908    /// use try_create::TryNew;
909    ///
910    /// // Positive value succeeds
911    /// assert!(PositiveRealScalar::try_new(1.0_f64).is_ok());
912    ///
913    /// // Zero fails
914    /// assert!(matches!(
915    ///     PositiveRealScalar::try_new(0.0_f64),
916    ///     Err(ErrorsPositiveRealScalar::ZeroValue { .. })
917    /// ));
918    ///
919    /// // Negative fails
920    /// assert!(matches!(
921    ///     PositiveRealScalar::try_new(-1.0_f64),
922    ///     Err(ErrorsPositiveRealScalar::NegativeValue { value: v, .. }) if v == -1.0
923    /// ));
924    /// ```
925    fn try_new(value: RealType) -> Result<Self, Self::Error> {
926        debug_assert!(value.is_finite(), "The input value {value} is not finite!");
927        if value.kernel_is_sign_negative() {
928            Err(ErrorsPositiveRealScalar::NegativeValue {
929                value,
930                backtrace: capture_backtrace(),
931            })
932        } else if value.is_zero() {
933            Err(ErrorsPositiveRealScalar::ZeroValue {
934                backtrace: capture_backtrace(),
935            })
936        } else {
937            Ok(Self(value))
938        }
939    }
940}
941
942/// Implements additive composition for [`PositiveRealScalar`].
943///
944/// Since both operands are guaranteed to be positive, their sum is also positive.
945impl<RealType: RealScalar> Add for PositiveRealScalar<RealType> {
946    type Output = Self;
947
948    fn add(self, other: Self) -> Self {
949        PositiveRealScalar(self.0 + other.0)
950    }
951}
952
953/// Implements multiplicative composition for [`PositiveRealScalar`].
954///
955/// Since both operands are guaranteed to be positive, their product is also positive.
956impl<RealType: RealScalar> Mul for PositiveRealScalar<RealType> {
957    type Output = Self;
958
959    fn mul(self, other: Self) -> Self {
960        PositiveRealScalar(self.0 * other.0)
961    }
962}
963
964/// Implements reference-based addition for [`PositiveRealScalar`].
965///
966/// This allows adding a reference to a positive scalar without consuming it.
967/// Since both operands are guaranteed to be positive, their sum is also positive.
968impl<'a, RealType: RealScalar> Add<&'a PositiveRealScalar<RealType>>
969    for PositiveRealScalar<RealType>
970{
971    type Output = PositiveRealScalar<RealType>;
972
973    fn add(self, other: &'a PositiveRealScalar<RealType>) -> PositiveRealScalar<RealType> {
974        PositiveRealScalar(self.0 + other.0.clone())
975    }
976}
977
978/// Implements reference-based multiplication for [`PositiveRealScalar`].
979///
980/// This allows multiplying a positive scalar by a reference to another positive scalar
981/// without consuming it. Since both operands are guaranteed to be positive, their product is also positive.
982impl<'a, RealType: RealScalar> Mul<&'a PositiveRealScalar<RealType>>
983    for PositiveRealScalar<RealType>
984{
985    type Output = PositiveRealScalar<RealType>;
986
987    fn mul(self, other: &'a PositiveRealScalar<RealType>) -> PositiveRealScalar<RealType> {
988        PositiveRealScalar(self.0 * other.0.clone())
989    }
990}
991
992/// Implements in-place reference-based addition for [`PositiveRealScalar`].
993///
994/// This allows adding a reference to a positive scalar to `self` without consuming `self`.
995impl<'a, RealType: RealScalar> AddAssign<&'a PositiveRealScalar<RealType>>
996    for PositiveRealScalar<RealType>
997{
998    fn add_assign(&mut self, other: &'a PositiveRealScalar<RealType>) {
999        self.0 += &other.0;
1000    }
1001}
1002
1003/// Implements in-place addition for [`PositiveRealScalar`] by value.
1004///
1005/// This allows adding a positive scalar value to `self`.
1006impl<RealType: RealScalar> AddAssign<PositiveRealScalar<RealType>>
1007    for PositiveRealScalar<RealType>
1008{
1009    fn add_assign(&mut self, other: PositiveRealScalar<RealType>) {
1010        self.0 += other.0;
1011    }
1012}
1013
1014/// Implements in-place reference-based multiplication for [`PositiveRealScalar`].
1015///
1016/// This allows multiplying `self` by a reference to another positive scalar without consuming `self`.
1017impl<'a, RealType: RealScalar> MulAssign<&'a PositiveRealScalar<RealType>>
1018    for PositiveRealScalar<RealType>
1019{
1020    fn mul_assign(&mut self, other: &'a PositiveRealScalar<RealType>) {
1021        self.0 *= &other.0;
1022    }
1023}
1024
1025/// Implements in-place multiplication for [`PositiveRealScalar`] by value.
1026///
1027/// This allows multiplying `self` by a positive scalar value.
1028impl<RealType: RealScalar> MulAssign<PositiveRealScalar<RealType>>
1029    for PositiveRealScalar<RealType>
1030{
1031    fn mul_assign(&mut self, other: PositiveRealScalar<RealType>) {
1032        self.0 *= other.0;
1033    }
1034}
1035
1036impl<RealType: RealScalar> One for PositiveRealScalar<RealType> {
1037    fn one() -> Self {
1038        PositiveRealScalar(RealType::one())
1039    }
1040}
1041
1042#[duplicate_item(
1043    exponent_type;
1044    [u8];
1045    [i8];
1046    [u16];
1047    [i16];
1048    [u32];
1049    [i32];
1050    [u64];
1051    [i64];
1052    [u128];
1053    [i128];
1054    [usize];
1055    [isize];
1056)]
1057impl<RealType: RealScalar> Pow<exponent_type> for PositiveRealScalar<RealType> {
1058    type Error = PowIntExponentErrors<<RealType as IntoInner>::InnerType, exponent_type>;
1059
1060    fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
1061        self.0.try_pow(exponent).map(PositiveRealScalar)
1062    }
1063
1064    #[inline(always)]
1065    /// Raises the number `self` to the power `exponent`.
1066    fn pow(self, exponent: exponent_type) -> Self {
1067        #[cfg(debug_assertions)]
1068        {
1069            self.try_pow(exponent).unwrap()
1070        }
1071        #[cfg(not(debug_assertions))]
1072        {
1073            PositiveRealScalar(self.0.pow(exponent))
1074        }
1075    }
1076}
1077
1078/// Implements [`Max`] for [`PositiveRealScalar`].
1079///
1080/// Maximum selection is delegated to the default trait behavior based on [`PartialOrd`].
1081impl<RealType: RealScalar> Max for PositiveRealScalar<RealType> {}
1082/// Implements [`Min`] for [`PositiveRealScalar`].
1083///
1084/// Minimum selection is delegated to the default trait behavior based on [`PartialOrd`].
1085impl<RealType: RealScalar> Min for PositiveRealScalar<RealType> {}
1086
1087/// Implements Neumaier compensated summation for [`PositiveRealScalar`].
1088///
1089/// This implementation delegates to the underlying real scalar type's Neumaier
1090/// compensated sum operation, preserving numerical stability for sums of positive values.
1091impl<RealType: RealScalar> NeumaierAddable for PositiveRealScalar<RealType> {
1092    #[inline(always)]
1093    fn neumaier_compensated_sum(value: Self, sum: &mut Self, compensation: &mut Self) {
1094        neumaier_sum_and_compensation_real(value.into_inner(), &mut sum.0, &mut compensation.0)
1095    }
1096}
1097
1098//------------------------------------------------------------------------------------------------------------
1099// NonNegativeRealScalar
1100//------------------------------------------------------------------------------------------------------------
1101
1102/// Type-safe wrapper for non-negative real scalar values.
1103///
1104/// [`NonNegativeRealScalar<T>`] guarantees that wrapped values are greater than or equal to zero.
1105/// Zero **is** valid for this type. For values that must be strictly positive, use [`PositiveRealScalar`].
1106///
1107/// # Mathematical Definition
1108///
1109/// ```text
1110/// NonNegativeRealScalar<T> = { x ∈ T : x ≥ 0 }
1111/// ```
1112///
1113/// This is the set of non-negative real numbers `ℝ₀⁺`, which **includes** zero.
1114///
1115/// # Use Cases
1116///
1117/// - Distances (can be zero when comparing a value to itself)
1118/// - Absolute values
1119/// - Magnitudes
1120/// - Any quantity that is mathematically required to be ≥ 0
1121///
1122/// # Examples
1123///
1124/// ## Basic Usage
1125///
1126/// ```rust
1127/// use num_valid::scalars::{NonNegativeRealScalar, ErrorsNonNegativeRealScalar};
1128/// use try_create::TryNew;
1129///
1130/// // Zero is valid
1131/// let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
1132/// assert_eq!(*zero.as_ref(), 0.0);
1133///
1134/// // Positive values are valid
1135/// let positive = NonNegativeRealScalar::try_new(5.0_f64).unwrap();
1136///
1137/// // Negative values are rejected
1138/// assert!(matches!(
1139///     NonNegativeRealScalar::try_new(-1.0_f64),
1140///     Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
1141/// ));
1142/// ```
1143///
1144/// ## Use Case: Computing Distances
1145///
1146/// ```rust
1147/// use num_valid::scalars::NonNegativeRealScalar;
1148/// use try_create::TryNew;
1149///
1150/// fn distance(a: f64, b: f64) -> NonNegativeRealScalar<f64> {
1151///     NonNegativeRealScalar::try_new((a - b).abs()).unwrap()
1152/// }
1153///
1154/// // Different points
1155/// let d1 = distance(0.0, 5.0);
1156/// assert_eq!(*d1.as_ref(), 5.0);
1157///
1158/// // Same point (zero distance is valid!)
1159/// let d2 = distance(3.0, 3.0);
1160/// assert_eq!(*d2.as_ref(), 0.0);
1161/// ```
1162///
1163/// ## Algebraic and Ordering Operations
1164///
1165/// [`NonNegativeRealScalar`] supports:
1166/// - **Addition**: Sum of non-negative values is non-negative
1167/// - **Multiplication**: Product of non-negative values is non-negative  
1168/// - **Integer powers**: Raising non-negative to any integer exponent yields non-negative
1169/// - **Additive identity** ([`Zero`]): For neutral addition operations
1170/// - **Multiplicative identity** ([`One`]): For neutral multiplication operations
1171/// - **Comparison** ([`Max`], [`Min`]): Ordering and selection helpers
1172///
1173/// ```rust
1174/// use num::{One, Zero};
1175/// use num_valid::{
1176///     functions::{Max, Min, Pow},
1177///     scalars::NonNegativeRealScalar,
1178/// };
1179/// use try_create::TryNew;
1180///
1181/// let a = NonNegativeRealScalar::try_new(1.25_f64).unwrap();
1182/// let b = NonNegativeRealScalar::try_new(2.75_f64).unwrap();
1183///
1184/// // Add preserves non-negativity for valid operands.
1185/// let sum = a.clone() + &b;
1186/// assert_eq!(*sum.as_ref(), 4.0);
1187///
1188/// // Multiply preserves non-negativity
1189/// let product = a * b;
1190/// assert!(*product.as_ref() > 0.0);
1191///
1192/// // Integer powers preserve non-negativity
1193/// let base = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
1194/// let squared = base.clone().pow(2u32);
1195/// assert_eq!(*squared.as_ref(), 4.0);
1196///
1197/// // Zero is the additive identity.
1198/// let z = NonNegativeRealScalar::<f64>::zero();
1199/// assert!(z.is_zero());
1200/// assert_eq!(*(sum + z).as_ref(), 4.0);
1201///
1202/// // One is the multiplicative identity.
1203/// let one = NonNegativeRealScalar::<f64>::one();
1204/// let result = base.clone() * one;
1205/// assert_eq!(*result.as_ref(), 2.0);
1206///
1207/// let x = NonNegativeRealScalar::try_new(1.0_f64).unwrap();
1208/// let y = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
1209/// assert_eq!(*Max::max_by_ref(&x, &y).as_ref(), 3.0);
1210/// assert_eq!(*Min::min_by_value(x, y).as_ref(), 1.0);
1211/// ```
1212#[derive(
1213    Debug, Clone, PartialEq, PartialOrd, AsRef, IntoInner, Display, Serialize, Deserialize,
1214)]
1215#[repr(transparent)]
1216#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
1217pub struct NonNegativeRealScalar<RealType: RealScalar>(RealType);
1218
1219impl<RealType: RealScalar> NonNegativeRealScalar<RealType> {
1220    /// Computes the square root of this non-negative scalar.
1221    ///
1222    /// Since the input is guaranteed to be non-negative, the result is always defined
1223    /// and remains non-negative.
1224    ///
1225    /// # Examples
1226    ///
1227    /// ```rust
1228    /// use num_valid::scalars::NonNegativeRealScalar;
1229    /// use try_create::TryNew;
1230    ///
1231    /// let value = NonNegativeRealScalar::try_new(4.0_f64).unwrap();
1232    /// let sqrt = value.sqrt();
1233    /// assert_eq!(*sqrt.as_ref(), 2.0);
1234    /// ```
1235    pub fn sqrt(self) -> Self {
1236        NonNegativeRealScalar(self.0.sqrt())
1237    }
1238
1239    #[inline(always)]
1240    pub fn new(value: RealType) -> Self {
1241        #[cfg(debug_assertions)]
1242        {
1243            Self::try_new(value)
1244                .expect("Error in the creation of the non-negative real scalar in debug mode")
1245        }
1246        #[cfg(not(debug_assertions))]
1247        {
1248            Self(value)
1249        }
1250    }
1251}
1252
1253impl<RealType: RealScalar> TryNew for NonNegativeRealScalar<RealType> {
1254    type Error = ErrorsNonNegativeRealScalar<RealType>;
1255
1256    /// Attempts to create a [`NonNegativeRealScalar`] from a value.
1257    ///
1258    /// # Errors
1259    ///
1260    /// Returns [`ErrorsNonNegativeRealScalar::NegativeValue`] if the input is negative.
1261    ///
1262    /// # Panics (Debug Mode Only)
1263    ///
1264    /// In debug builds, panics if the input is not finite (NaN or infinity).
1265    ///
1266    /// # Examples
1267    ///
1268    /// ```rust
1269    /// use num_valid::scalars::{NonNegativeRealScalar, ErrorsNonNegativeRealScalar};
1270    /// use try_create::TryNew;
1271    ///
1272    /// // Zero is valid
1273    /// assert!(NonNegativeRealScalar::try_new(0.0_f64).is_ok());
1274    ///
1275    /// // Positive is valid
1276    /// assert!(NonNegativeRealScalar::try_new(1.0_f64).is_ok());
1277    ///
1278    /// // Negative is rejected
1279    /// assert!(matches!(
1280    ///     NonNegativeRealScalar::try_new(-1.0_f64),
1281    ///     Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
1282    /// ));
1283    /// ```
1284    fn try_new(value: RealType) -> Result<Self, Self::Error> {
1285        debug_assert!(value.is_finite(), "The input value {value} is not finite!");
1286        if value.kernel_is_sign_negative() {
1287            Err(ErrorsNonNegativeRealScalar::NegativeValue {
1288                value,
1289                backtrace: capture_backtrace(),
1290            })
1291        } else {
1292            Ok(Self(value))
1293        }
1294    }
1295}
1296
1297/// Implements additive composition for [`NonNegativeRealScalar`].
1298///
1299/// Since both operands are guaranteed to be non-negative, their sum is also non-negative.
1300impl<RealType: RealScalar> Add for NonNegativeRealScalar<RealType> {
1301    type Output = Self;
1302
1303    fn add(self, other: Self) -> Self {
1304        NonNegativeRealScalar(self.0 + other.0)
1305    }
1306}
1307
1308/// Implements multiplicative composition for [`NonNegativeRealScalar`].
1309///
1310/// Since both operands are guaranteed to be non-negative, their product is also non-negative.
1311impl<RealType: RealScalar> Mul for NonNegativeRealScalar<RealType> {
1312    type Output = Self;
1313
1314    fn mul(self, other: Self) -> Self {
1315        NonNegativeRealScalar(self.0 * other.0)
1316    }
1317}
1318
1319/// Implements reference-based addition for [`NonNegativeRealScalar`].
1320///
1321/// This allows adding a reference to a non-negative scalar without consuming it.
1322/// Since both operands are guaranteed to be non-negative, their sum is also non-negative.
1323impl<'a, RealType: RealScalar> Add<&'a NonNegativeRealScalar<RealType>>
1324    for NonNegativeRealScalar<RealType>
1325{
1326    type Output = NonNegativeRealScalar<RealType>;
1327
1328    fn add(self, other: &'a NonNegativeRealScalar<RealType>) -> NonNegativeRealScalar<RealType> {
1329        NonNegativeRealScalar(self.0 + other.0.clone())
1330    }
1331}
1332
1333/// Implements reference-based multiplication for [`NonNegativeRealScalar`].
1334///
1335/// This allows multiplying a non-negative scalar by a reference to another non-negative scalar
1336/// without consuming it. Since both operands are guaranteed to be non-negative, their product is also non-negative.
1337impl<'a, RealType: RealScalar> Mul<&'a NonNegativeRealScalar<RealType>>
1338    for NonNegativeRealScalar<RealType>
1339{
1340    type Output = NonNegativeRealScalar<RealType>;
1341
1342    fn mul(self, other: &'a NonNegativeRealScalar<RealType>) -> NonNegativeRealScalar<RealType> {
1343        NonNegativeRealScalar(self.0 * other.0.clone())
1344    }
1345}
1346
1347/// Implements in-place reference-based addition for [`NonNegativeRealScalar`].
1348///
1349/// This allows adding a reference to a non-negative scalar to `self` without consuming `self`.
1350impl<'a, RealType: RealScalar> AddAssign<&'a NonNegativeRealScalar<RealType>>
1351    for NonNegativeRealScalar<RealType>
1352{
1353    fn add_assign(&mut self, other: &'a NonNegativeRealScalar<RealType>) {
1354        self.0 += &other.0;
1355    }
1356}
1357
1358/// Implements in-place addition for [`NonNegativeRealScalar`] by value.
1359///
1360/// This allows adding a non-negative scalar value to `self`.
1361impl<RealType: RealScalar> AddAssign<NonNegativeRealScalar<RealType>>
1362    for NonNegativeRealScalar<RealType>
1363{
1364    fn add_assign(&mut self, other: NonNegativeRealScalar<RealType>) {
1365        self.0 += other.0;
1366    }
1367}
1368
1369/// Implements in-place reference-based multiplication for [`NonNegativeRealScalar`].
1370///
1371/// This allows multiplying `self` by a reference to another non-negative scalar without consuming `self`.
1372impl<'a, RealType: RealScalar> MulAssign<&'a NonNegativeRealScalar<RealType>>
1373    for NonNegativeRealScalar<RealType>
1374{
1375    fn mul_assign(&mut self, other: &'a NonNegativeRealScalar<RealType>) {
1376        self.0 *= &other.0;
1377    }
1378}
1379
1380/// Implements in-place multiplication for [`NonNegativeRealScalar`] by value.
1381///
1382/// This allows multiplying `self` by a non-negative scalar value.
1383impl<RealType: RealScalar> MulAssign<NonNegativeRealScalar<RealType>>
1384    for NonNegativeRealScalar<RealType>
1385{
1386    fn mul_assign(&mut self, other: NonNegativeRealScalar<RealType>) {
1387        self.0 *= other.0;
1388    }
1389}
1390
1391/// Implements [`Zero`] for [`NonNegativeRealScalar`].
1392///
1393/// The zero value is always valid, and acts as the additive identity.
1394impl<RealType: RealScalar> Zero for NonNegativeRealScalar<RealType> {
1395    fn is_zero(&self) -> bool {
1396        self.0.is_zero()
1397    }
1398
1399    fn zero() -> Self {
1400        NonNegativeRealScalar(RealType::zero())
1401    }
1402}
1403
1404impl<RealType: RealScalar> One for NonNegativeRealScalar<RealType> {
1405    fn one() -> Self {
1406        NonNegativeRealScalar(RealType::one())
1407    }
1408}
1409
1410#[duplicate_item(
1411    exponent_type;
1412    [u8];
1413    [i8];
1414    [u16];
1415    [i16];
1416    [u32];
1417    [i32];
1418    [u64];
1419    [i64];
1420    [u128];
1421    [i128];
1422    [usize];
1423    [isize];
1424)]
1425impl<RealType: RealScalar> Pow<exponent_type> for NonNegativeRealScalar<RealType> {
1426    type Error = PowIntExponentErrors<<RealType as IntoInner>::InnerType, exponent_type>;
1427
1428    fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
1429        self.0.try_pow(exponent).map(NonNegativeRealScalar)
1430    }
1431
1432    #[inline(always)]
1433    /// Raises the number `self` to the power `exponent`.
1434    fn pow(self, exponent: exponent_type) -> Self {
1435        #[cfg(debug_assertions)]
1436        {
1437            self.try_pow(exponent).unwrap()
1438        }
1439        #[cfg(not(debug_assertions))]
1440        {
1441            NonNegativeRealScalar(self.0.pow(exponent))
1442        }
1443    }
1444}
1445
1446/// Implements [`Max`] for [`NonNegativeRealScalar`].
1447///
1448/// Maximum selection is delegated to the default trait behavior based on [`PartialOrd`].
1449impl<RealType: RealScalar> Max for NonNegativeRealScalar<RealType> {}
1450/// Implements [`Min`] for [`NonNegativeRealScalar`].
1451///
1452/// Minimum selection is delegated to the default trait behavior based on [`PartialOrd`].
1453impl<RealType: RealScalar> Min for NonNegativeRealScalar<RealType> {}
1454
1455/// Implements Neumaier compensated summation for [`NonNegativeRealScalar`].
1456///
1457/// This implementation delegates to the underlying real scalar type's Neumaier
1458/// compensated sum operation, preserving numerical stability for sums of non-negative values.
1459impl<RealType: RealScalar> NeumaierAddable for NonNegativeRealScalar<RealType> {
1460    #[inline(always)]
1461    fn neumaier_compensated_sum(value: Self, sum: &mut Self, compensation: &mut Self) {
1462        neumaier_sum_and_compensation_real(value.into_inner(), &mut sum.0, &mut compensation.0)
1463    }
1464}
1465
1466//------------------------------------------------------------------------------------------------------------
1467// Conversions
1468//------------------------------------------------------------------------------------------------------------
1469
1470/// Converts a [`PositiveRealScalar<T>`] to a [`NonNegativeRealScalar<T>`].
1471///
1472/// This conversion is mathematically valid because every positive number (x > 0) is
1473/// also non-negative (x ≥ 0). The conversion is infallible and zero-cost.
1474///
1475/// # Examples
1476///
1477/// ```rust
1478/// use num_valid::scalars::{PositiveRealScalar, NonNegativeRealScalar};
1479/// use try_create::TryNew;
1480///
1481/// let positive = PositiveRealScalar::try_new(5.0_f64).unwrap();
1482/// let non_negative: NonNegativeRealScalar<f64> = positive.into();
1483///
1484/// assert_eq!(*non_negative.as_ref(), 5.0);
1485/// ```
1486impl<RealType: RealScalar> From<PositiveRealScalar<RealType>> for NonNegativeRealScalar<RealType> {
1487    fn from(positive: PositiveRealScalar<RealType>) -> Self {
1488        NonNegativeRealScalar(positive.into_inner())
1489    }
1490}
1491
1492//------------------------------------------------------------------------------------------------------------
1493// Cross-type arithmetic operations
1494//------------------------------------------------------------------------------------------------------------
1495
1496/// Adds a [`NonNegativeRealScalar`] to a [`PositiveRealScalar`], yielding a [`PositiveRealScalar`].
1497///
1498/// Since `self` is strictly positive (x > 0) and `other` is non-negative (y ≥ 0),
1499/// their sum is strictly positive: x + y > 0.
1500///
1501/// # Examples
1502///
1503/// ```rust
1504/// use num_valid::scalars::{PositiveRealScalar, NonNegativeRealScalar};
1505/// use try_create::TryNew;
1506///
1507/// let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
1508/// let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
1509///
1510/// let result: PositiveRealScalar<f64> = pos + non_neg;
1511/// assert_eq!(*result.as_ref(), 5.0);
1512/// ```
1513impl<RealType: RealScalar> Add<NonNegativeRealScalar<RealType>> for PositiveRealScalar<RealType> {
1514    type Output = PositiveRealScalar<RealType>;
1515
1516    fn add(self, other: NonNegativeRealScalar<RealType>) -> PositiveRealScalar<RealType> {
1517        PositiveRealScalar(self.0 + other.0)
1518    }
1519}
1520
1521/// Adds a [`NonNegativeRealScalar`] by reference to a [`PositiveRealScalar`], yielding a [`PositiveRealScalar`].
1522///
1523/// Since `self` is strictly positive (x > 0) and `other` is non-negative (y ≥ 0),
1524/// their sum is strictly positive: x + y > 0.
1525impl<'a, RealType: RealScalar> Add<&'a NonNegativeRealScalar<RealType>>
1526    for PositiveRealScalar<RealType>
1527{
1528    type Output = PositiveRealScalar<RealType>;
1529
1530    fn add(self, other: &'a NonNegativeRealScalar<RealType>) -> PositiveRealScalar<RealType> {
1531        PositiveRealScalar(self.0 + &other.0)
1532    }
1533}
1534
1535/// Adds a [`PositiveRealScalar`] to a [`NonNegativeRealScalar`], yielding a [`PositiveRealScalar`].
1536///
1537/// Since `other` is strictly positive (x > 0) and `self` is non-negative (y ≥ 0),
1538/// their sum is strictly positive: x + y > 0.
1539///
1540/// # Examples
1541///
1542/// ```rust
1543/// use num_valid::scalars::{PositiveRealScalar, NonNegativeRealScalar};
1544/// use try_create::TryNew;
1545///
1546/// let non_neg = NonNegativeRealScalar::try_new(0.0_f64).unwrap(); // zero!
1547/// let pos = PositiveRealScalar::try_new(5.0_f64).unwrap();
1548///
1549/// let result: PositiveRealScalar<f64> = non_neg + pos;
1550/// assert_eq!(*result.as_ref(), 5.0);
1551/// ```
1552impl<RealType: RealScalar> Add<PositiveRealScalar<RealType>> for NonNegativeRealScalar<RealType> {
1553    type Output = PositiveRealScalar<RealType>;
1554
1555    fn add(self, other: PositiveRealScalar<RealType>) -> PositiveRealScalar<RealType> {
1556        PositiveRealScalar(self.0 + other.0)
1557    }
1558}
1559
1560/// Adds a [`PositiveRealScalar`] by reference to a [`NonNegativeRealScalar`], yielding a [`PositiveRealScalar`].
1561///
1562/// Since `other` is strictly positive (x > 0) and `self` is non-negative (y ≥ 0),
1563/// their sum is strictly positive: x + y > 0.
1564impl<'a, RealType: RealScalar> Add<&'a PositiveRealScalar<RealType>>
1565    for NonNegativeRealScalar<RealType>
1566{
1567    type Output = PositiveRealScalar<RealType>;
1568
1569    fn add(self, other: &'a PositiveRealScalar<RealType>) -> PositiveRealScalar<RealType> {
1570        PositiveRealScalar(self.0 + &other.0)
1571    }
1572}
1573
1574//------------------------------------------------------------------------------------------------------------
1575// Tests
1576//------------------------------------------------------------------------------------------------------------
1577
1578#[cfg(test)]
1579mod tests {
1580    use super::*;
1581    use crate::backends::native::validated::RealNative64StrictFinite;
1582
1583    mod absolute_tolerance {
1584        use super::*;
1585
1586        #[test]
1587        fn try_new_valid() {
1588            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1e-10_f64).unwrap());
1589            assert_eq!(*tol.as_ref().as_ref(), 1e-10);
1590        }
1591
1592        #[test]
1593        fn try_new_zero() {
1594            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.0_f64).unwrap());
1595            assert_eq!(*tol.as_ref().as_ref(), 0.0);
1596        }
1597
1598        #[test]
1599        fn zero_constructor() {
1600            let tol = AbsoluteTolerance::<f64>::zero();
1601            assert_eq!(*tol.as_ref().as_ref(), 0.0);
1602        }
1603
1604        #[test]
1605        fn epsilon_constructor() {
1606            let tol = AbsoluteTolerance::<f64>::epsilon();
1607            assert_eq!(*tol.as_ref().as_ref(), f64::EPSILON);
1608        }
1609
1610        #[test]
1611        fn display_trait() {
1612            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5_f64).unwrap());
1613            assert_eq!(format!("{}", tol), "0.5");
1614        }
1615
1616        #[test]
1617        fn lower_exp_trait() {
1618            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.00001_f64).unwrap());
1619            assert_eq!(format!("{:e}", tol.into_inner().into_inner()), "1e-5");
1620        }
1621
1622        #[test]
1623        fn into_inner() {
1624            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5_f64).unwrap());
1625            let inner = tol.into_inner().into_inner();
1626            assert_eq!(inner, 0.5);
1627        }
1628
1629        #[test]
1630        fn clone_and_partial_eq() {
1631            let tol1 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1e-10_f64).unwrap());
1632            let tol2 = tol1.clone();
1633            assert_eq!(tol1, tol2);
1634        }
1635
1636        #[test]
1637        fn partial_ord() {
1638            let tol1 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1e-10_f64).unwrap());
1639            let tol2 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1e-9_f64).unwrap());
1640            assert!(tol1 < tol2);
1641        }
1642
1643        #[test]
1644        fn serialize_deserialize() {
1645            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5_f64).unwrap());
1646            let serialized = serde_json::to_string(&tol).unwrap();
1647            let deserialized: AbsoluteTolerance<f64> = serde_json::from_str(&serialized).unwrap();
1648            assert_eq!(tol, deserialized);
1649        }
1650
1651        #[test]
1652        fn with_validated_type() {
1653            let val = RealNative64StrictFinite::try_from_f64(1e-10).unwrap();
1654            let tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(val).unwrap());
1655            assert_eq!(tol.as_ref().as_ref().as_ref(), &1e-10);
1656        }
1657
1658        #[test]
1659        #[cfg(debug_assertions)]
1660        #[should_panic(expected = "is not finite")]
1661        fn debug_panics_on_nan() {
1662            let _ = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(f64::NAN).unwrap());
1663        }
1664
1665        #[test]
1666        #[cfg(debug_assertions)]
1667        #[should_panic(expected = "is not finite")]
1668        fn debug_panics_on_infinity() {
1669            let _ = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(f64::INFINITY).unwrap());
1670        }
1671
1672        #[test]
1673        fn try_new() {
1674            // Test creating an AbsoluteTolerance instance with a value of 0.0
1675            let v = AbsoluteTolerance::<f64>::zero();
1676            assert_eq!(*v.as_ref().as_ref(), 0.0);
1677
1678            // Test creating an AbsoluteTolerance instance with a positive value
1679            let v = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(2.0).unwrap());
1680            assert_eq!(*v.as_ref().as_ref(), 2.0);
1681        }
1682
1683        #[test]
1684        #[cfg(debug_assertions)]
1685        #[should_panic = "The input value inf is not finite!"]
1686        fn try_new_invalid_infinite() {
1687            // Test creating an invalid AbsoluteTolerance instance with an infinite value
1688            let _tol =
1689                AbsoluteTolerance::new(NonNegativeRealScalar::try_new(f64::INFINITY).unwrap());
1690        }
1691
1692        #[test]
1693        #[cfg(debug_assertions)]
1694        #[should_panic = "The input value NaN is not finite!"]
1695        fn try_new_invalid_nan() {
1696            // Test creating an invalid AbsoluteTolerance instance with a NaN value
1697            let _tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(f64::NAN).unwrap());
1698        }
1699
1700        #[test]
1701        fn epsilon() {
1702            // Test creating an AbsoluteTolerance instance with epsilon value
1703            let epsilon_tol = AbsoluteTolerance::<f64>::epsilon();
1704            assert_eq!(*epsilon_tol.as_ref().as_ref(), f64::EPSILON);
1705        }
1706
1707        #[test]
1708        fn equality_operator() {
1709            // Test equality operator for AbsoluteTolerance instances
1710            let a = AbsoluteTolerance::<f64>::zero();
1711            let b = AbsoluteTolerance::<f64>::zero();
1712            assert!(a == b);
1713
1714            let c = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1.0).unwrap());
1715            let d = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1.0).unwrap());
1716            assert!(c == d);
1717        }
1718
1719        #[test]
1720        fn inequality_operator() {
1721            // Test inequality operator for AbsoluteTolerance instances
1722            let a = AbsoluteTolerance::<f64>::zero();
1723            let b = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1.0).unwrap());
1724            assert!(a != b);
1725
1726            let c = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1.0).unwrap());
1727            let d = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(2.0).unwrap());
1728            assert!(c != d);
1729        }
1730
1731        #[test]
1732        fn debug_trait() {
1733            // Test the Debug trait
1734            let tolerance = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1735            assert_eq!(
1736                format!("{:?}", tolerance),
1737                "AbsoluteTolerance(NonNegativeRealScalar(0.5))"
1738            );
1739        }
1740
1741        #[test]
1742        fn clone_trait() {
1743            // Test the Clone trait
1744            let tolerance = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1745            let cloned_tolerance = tolerance.clone();
1746            assert_eq!(tolerance, cloned_tolerance);
1747        }
1748
1749        #[test]
1750        fn partial_eq_trait() {
1751            // Test the PartialEq trait
1752            let tolerance1 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1753            let tolerance2 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1754            assert_eq!(tolerance1, tolerance2);
1755        }
1756
1757        #[test]
1758        fn partial_ord_trait() {
1759            // Test the PartialOrd trait
1760            let tolerance1 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1761            let tolerance2 = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1.0).unwrap());
1762            assert!(tolerance1 < tolerance2);
1763        }
1764
1765        #[test]
1766        fn as_ref_trait() {
1767            // Test the AsRef trait
1768            let tolerance = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(0.5).unwrap());
1769            let inner: &f64 = tolerance.as_ref().as_ref();
1770            assert_eq!(*inner, 0.5);
1771        }
1772
1773        #[test]
1774        fn zero() {
1775            // Test the zero constructor
1776            let zero_tol = AbsoluteTolerance::<f64>::zero();
1777            assert_eq!(*zero_tol.as_ref().as_ref(), 0.0);
1778        }
1779
1780        #[test]
1781        fn edge_cases() {
1782            // Test with very small positive values
1783            let tiny_tol =
1784                AbsoluteTolerance::new(NonNegativeRealScalar::try_new(f64::MIN_POSITIVE).unwrap());
1785            assert_eq!(*tiny_tol.as_ref().as_ref(), f64::MIN_POSITIVE);
1786
1787            // Test with large positive values
1788            let large_tol = AbsoluteTolerance::new(NonNegativeRealScalar::try_new(1e100).unwrap());
1789            assert_eq!(*large_tol.as_ref().as_ref(), 1e100);
1790        }
1791
1792        #[test]
1793        fn approximately_equal_exact_match() {
1794            let a = 1.0_f64;
1795            let b = 1.0_f64;
1796            let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
1797            assert!(approximately_equal(a, b, &tol));
1798        }
1799
1800        #[test]
1801        fn approximately_equal_within_tolerance() {
1802            let a = 1.0_f64;
1803            let b = 1.0 + 1e-11_f64;
1804            let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
1805            assert!(approximately_equal(a, b, &tol));
1806        }
1807
1808        #[test]
1809        fn approximately_equal_outside_tolerance() {
1810            let a = 1.0_f64;
1811            let b = 1.0 + 1e-9_f64;
1812            let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
1813            assert!(!approximately_equal(a, b, &tol));
1814        }
1815
1816        #[test]
1817        fn approximately_equal_negative_values() {
1818            let a = -5.0_f64;
1819            let b = -5.0 + 1e-12_f64;
1820            let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
1821            assert!(approximately_equal(a, b, &tol));
1822        }
1823
1824        #[test]
1825        fn approximately_equal_zero_tolerance() {
1826            let a = 1.0_f64;
1827            let b = 1.0_f64;
1828            let tol = AbsoluteTolerance::<f64>::zero();
1829            assert!(approximately_equal(a, b, &tol));
1830
1831            let c = 1.0_f64 + 1e-15;
1832            assert!(!approximately_equal(a, c, &tol)); // Even tiny difference fails with zero tolerance
1833        }
1834
1835        #[test]
1836        fn approximately_equal_large_difference_outside_tolerance() {
1837            let a = 1.0_f64;
1838            let b = 2.0_f64;
1839            let tol = AbsoluteTolerance::try_new(0.1_f64).unwrap();
1840            assert!(!approximately_equal(a, b, &tol));
1841        }
1842
1843        #[test]
1844        fn approximately_equal_symmetric() {
1845            let a = 1.0_f64;
1846            let b = 1.0 + 1e-12_f64;
1847            let tol = AbsoluteTolerance::try_new(1e-10_f64).unwrap();
1848            assert_eq!(
1849                approximately_equal(a, b, &tol),
1850                approximately_equal(b, a, &tol)
1851            );
1852        }
1853
1854        #[test]
1855        fn approximately_equal_with_validated_type() {
1856            let a = RealNative64StrictFinite::try_from_f64(1.0).unwrap();
1857            let b = RealNative64StrictFinite::try_from_f64(1.0 + 1e-11).unwrap();
1858            let tol = AbsoluteTolerance::new(
1859                NonNegativeRealScalar::try_new(
1860                    RealNative64StrictFinite::try_from_f64(1e-10).unwrap(),
1861                )
1862                .unwrap(),
1863            );
1864            assert!(approximately_equal(a, b, &tol));
1865        }
1866    }
1867
1868    mod relative_tolerance {
1869        use super::*;
1870
1871        #[test]
1872        fn try_new_valid() {
1873            let tol = RelativeTolerance::try_new(0.01_f64).unwrap();
1874            assert_eq!(*tol.as_ref().as_ref(), 0.01);
1875        }
1876
1877        #[test]
1878        fn try_new_zero() {
1879            let tol = RelativeTolerance::try_new(0.0_f64).unwrap();
1880            assert_eq!(*tol.as_ref().as_ref(), 0.0);
1881        }
1882
1883        #[test]
1884        fn try_new_negative() {
1885            let result = RelativeTolerance::try_new(-0.01_f64);
1886            assert!(matches!(
1887                result,
1888                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
1889            ));
1890        }
1891
1892        #[test]
1893        fn zero_constructor() {
1894            let tol = RelativeTolerance::<f64>::zero();
1895            assert_eq!(*tol.as_ref().as_ref(), 0.0);
1896        }
1897
1898        #[test]
1899        fn epsilon_constructor() {
1900            let tol = RelativeTolerance::<f64>::epsilon();
1901            assert_eq!(*tol.as_ref().as_ref(), f64::EPSILON);
1902        }
1903
1904        #[test]
1905        fn absolute_tolerance_positive_reference() {
1906            let rel_tol = RelativeTolerance::try_new(0.1_f64).unwrap();
1907            let abs_tol = rel_tol.absolute_tolerance(100.0);
1908            assert_eq!(*abs_tol.as_ref().as_ref(), 10.0);
1909        }
1910
1911        #[test]
1912        fn absolute_tolerance_negative_reference() {
1913            let rel_tol = RelativeTolerance::try_new(0.1_f64).unwrap();
1914            let abs_tol = rel_tol.absolute_tolerance(-50.0);
1915            assert_eq!(*abs_tol.as_ref().as_ref(), 5.0);
1916        }
1917
1918        #[test]
1919        fn absolute_tolerance_zero_reference() {
1920            let rel_tol = RelativeTolerance::try_new(0.1_f64).unwrap();
1921            let abs_tol = rel_tol.absolute_tolerance(0.0);
1922            assert_eq!(*abs_tol.as_ref().as_ref(), 0.0);
1923        }
1924
1925        #[test]
1926        fn display_trait() {
1927            let tol = RelativeTolerance::try_new(0.5_f64).unwrap();
1928            assert_eq!(format!("{}", tol), "0.5");
1929        }
1930
1931        #[test]
1932        fn into_inner() {
1933            let tol = RelativeTolerance::try_new(0.01_f64).unwrap();
1934            let inner = tol.into_inner();
1935            assert_eq!(inner.as_ref(), &0.01);
1936        }
1937
1938        #[test]
1939        fn serialize_deserialize() {
1940            let tol = RelativeTolerance::try_new(0.01_f64).unwrap();
1941            let serialized = serde_json::to_string(&tol).unwrap();
1942            let deserialized: RelativeTolerance<f64> = serde_json::from_str(&serialized).unwrap();
1943            assert_eq!(tol, deserialized);
1944        }
1945
1946        #[test]
1947        fn try_new() {
1948            // Test creating a RelativeTolerance instance with a value of 0.0
1949            let v = RelativeTolerance::<f64>::zero();
1950            assert_eq!(*v.as_ref().as_ref(), 0.0);
1951
1952            // Test creating a RelativeTolerance instance with a positive value
1953            let v = RelativeTolerance::try_new(2.0).unwrap();
1954            assert_eq!(*v.as_ref().as_ref(), 2.0);
1955        }
1956
1957        #[test]
1958        fn try_new_invalid_negative() {
1959            // Test creating an invalid RelativeTolerance instance with a negative value
1960            let tol = RelativeTolerance::try_new(-0.1);
1961            assert!(matches!(
1962                tol,
1963                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
1964            ));
1965        }
1966
1967        #[test]
1968        #[cfg(debug_assertions)]
1969        #[should_panic = "The input value inf is not finite!"]
1970        fn try_new_invalid_infinite() {
1971            // Test creating an invalid RelativeTolerance instance with an infinite value
1972            let _tol = RelativeTolerance::try_new(f64::INFINITY);
1973        }
1974
1975        #[test]
1976        #[cfg(debug_assertions)]
1977        #[should_panic = "The input value NaN is not finite!"]
1978        fn try_new_invalid_nan() {
1979            // Test creating an invalid RelativeTolerance instance with a NaN value
1980            let _tol = RelativeTolerance::try_new(f64::NAN);
1981        }
1982
1983        #[test]
1984        fn epsilon() {
1985            // Test creating a RelativeTolerance instance with epsilon value
1986            let epsilon_tol = RelativeTolerance::<f64>::epsilon();
1987            assert_eq!(*epsilon_tol.as_ref().as_ref(), f64::EPSILON);
1988        }
1989
1990        #[test]
1991        fn absolute_tolerance() {
1992            // Test converting relative tolerance to absolute tolerance
1993            let rel_tol = RelativeTolerance::try_new(0.1).unwrap();
1994            let reference = 10.0;
1995            let abs_tol = rel_tol.absolute_tolerance(reference);
1996            assert_eq!(*abs_tol.as_ref().as_ref(), 1.0); // 0.1 * |10.0| = 1.0
1997
1998            // Test with negative reference value
1999            let reference = -5.0;
2000            let abs_tol = rel_tol.absolute_tolerance(reference);
2001            assert_eq!(*abs_tol.as_ref().as_ref(), 0.5); // 0.1 * |-5.0| = 0.5
2002
2003            // Test with zero reference value
2004            let reference = 0.0;
2005            let abs_tol = rel_tol.absolute_tolerance(reference);
2006            assert_eq!(*abs_tol.as_ref().as_ref(), 0.0); // 0.1 * |0.0| = 0.0
2007        }
2008
2009        #[test]
2010        fn equality_operator() {
2011            // Test equality operator for RelativeTolerance instances
2012            let a = RelativeTolerance::<f64>::zero();
2013            let b = RelativeTolerance::<f64>::zero();
2014            assert!(a == b);
2015
2016            let c = RelativeTolerance::try_new(1.0).unwrap();
2017            let d = RelativeTolerance::try_new(1.0).unwrap();
2018            assert!(c == d);
2019        }
2020
2021        #[test]
2022        fn inequality_operator() {
2023            // Test inequality operator for RelativeTolerance instances
2024            let a = RelativeTolerance::<f64>::zero();
2025            let b = RelativeTolerance::try_new(1.0).unwrap();
2026            assert!(a != b);
2027
2028            let c = RelativeTolerance::try_new(1.0).unwrap();
2029            let d = RelativeTolerance::try_new(2.0).unwrap();
2030            assert!(c != d);
2031        }
2032
2033        #[test]
2034        fn debug_trait() {
2035            // Test the Debug trait
2036            let tolerance = RelativeTolerance::try_new(0.5).unwrap();
2037            assert_eq!(
2038                format!("{:?}", tolerance),
2039                "RelativeTolerance(NonNegativeRealScalar(0.5))"
2040            );
2041        }
2042
2043        #[test]
2044        fn clone_trait() {
2045            // Test the Clone trait
2046            let tolerance = RelativeTolerance::try_new(0.5).unwrap();
2047            let cloned_tolerance = tolerance.clone();
2048            assert_eq!(tolerance, cloned_tolerance);
2049        }
2050
2051        #[test]
2052        fn partial_eq_trait() {
2053            // Test the PartialEq trait
2054            let tolerance1 = RelativeTolerance::try_new(0.5).unwrap();
2055            let tolerance2 = RelativeTolerance::try_new(0.5).unwrap();
2056            assert_eq!(tolerance1, tolerance2);
2057        }
2058
2059        #[test]
2060        fn partial_ord_trait() {
2061            // Test the PartialOrd trait
2062            let tolerance1 = RelativeTolerance::try_new(0.5).unwrap();
2063            let tolerance2 = RelativeTolerance::try_new(1.0).unwrap();
2064            assert!(tolerance1 < tolerance2);
2065        }
2066
2067        #[test]
2068        fn as_ref_trait() {
2069            // Test the AsRef trait
2070            let tolerance = RelativeTolerance::try_new(0.5).unwrap();
2071            let inner: &f64 = tolerance.as_ref().as_ref();
2072            assert_eq!(*inner, 0.5);
2073        }
2074
2075        #[test]
2076        fn lower_exp_trait() {
2077            // Test the LowerExp trait (scientific notation formatting)
2078            let tolerance = RelativeTolerance::try_new(0.00001).unwrap();
2079            assert_eq!(format!("{:e}", tolerance.as_ref().as_ref()), "1e-5");
2080        }
2081    }
2082
2083    mod positive_real_scalar {
2084        use super::*;
2085        use crate::backends::native::validated::RealNative64StrictFiniteInDebug;
2086
2087        #[test]
2088        fn try_new_positive() {
2089            let val = PositiveRealScalar::try_new(2.5_f64).unwrap();
2090            assert_eq!(*val.as_ref(), 2.5);
2091        }
2092
2093        #[test]
2094        fn try_new_min_positive() {
2095            let val = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2096            assert_eq!(*val.as_ref(), f64::MIN_POSITIVE);
2097        }
2098
2099        #[test]
2100        fn try_new_zero_fails() {
2101            let result = PositiveRealScalar::try_new(0.0_f64);
2102            assert!(matches!(
2103                result,
2104                Err(ErrorsPositiveRealScalar::ZeroValue { .. })
2105            ));
2106        }
2107
2108        #[test]
2109        fn try_new_negative_fails() {
2110            let result = PositiveRealScalar::try_new(-1.0_f64);
2111            assert!(
2112                matches!(result, Err(ErrorsPositiveRealScalar::NegativeValue { value, .. }) if value == -1.0)
2113            );
2114        }
2115
2116        #[test]
2117        fn display_trait() {
2118            let val = PositiveRealScalar::try_new(1.618_f64).unwrap();
2119            assert_eq!(format!("{}", val), "1.618");
2120        }
2121
2122        #[test]
2123        fn into_inner() {
2124            let val = PositiveRealScalar::try_new(42.0_f64).unwrap();
2125            let inner = val.into_inner();
2126            assert_eq!(inner, 42.0);
2127        }
2128
2129        #[test]
2130        fn partial_ord() {
2131            let a = PositiveRealScalar::try_new(1.0_f64).unwrap();
2132            let b = PositiveRealScalar::try_new(2.0_f64).unwrap();
2133            assert!(a < b);
2134        }
2135
2136        #[test]
2137        fn serialize_deserialize() {
2138            let val = PositiveRealScalar::try_new(3.0_f64).unwrap();
2139            let serialized = serde_json::to_string(&val).unwrap();
2140            let deserialized: PositiveRealScalar<f64> = serde_json::from_str(&serialized).unwrap();
2141            assert_eq!(val, deserialized);
2142        }
2143
2144        #[test]
2145        fn with_validated_type() {
2146            let inner = RealNative64StrictFinite::try_from_f64(5.0).unwrap();
2147            let val = PositiveRealScalar::try_new(inner).unwrap();
2148            assert_eq!(*val.as_ref().as_ref(), 5.0);
2149        }
2150
2151        #[test]
2152        #[cfg(debug_assertions)]
2153        #[should_panic(expected = "is not finite")]
2154        fn debug_panics_on_nan() {
2155            let _ = PositiveRealScalar::try_new(f64::NAN);
2156        }
2157
2158        #[test]
2159        fn try_new() {
2160            // Test creating a PositiveRealScalar instance with a positive value
2161            let v = PositiveRealScalar::try_new(2.5).unwrap();
2162            assert_eq!(*v.as_ref(), 2.5);
2163
2164            // Test creating a PositiveRealScalar instance with a very small positive value
2165            let v = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2166            assert_eq!(*v.as_ref(), f64::MIN_POSITIVE);
2167
2168            // Test creating a PositiveRealScalar instance with a large positive value
2169            let v = PositiveRealScalar::try_new(1e100).unwrap();
2170            assert_eq!(*v.as_ref(), 1e100);
2171        }
2172
2173        #[test]
2174        fn try_new_invalid_negative() {
2175            // Test creating an invalid PositiveRealScalar instance with a negative value
2176            let scalar = PositiveRealScalar::try_new(-0.1);
2177            assert!(matches!(
2178                scalar,
2179                Err(ErrorsPositiveRealScalar::NegativeValue { .. })
2180            ));
2181
2182            // Test with a negative value close to zero
2183            let scalar = PositiveRealScalar::try_new(-f64::EPSILON);
2184            assert!(matches!(
2185                scalar,
2186                Err(ErrorsPositiveRealScalar::NegativeValue { .. })
2187            ));
2188        }
2189
2190        #[test]
2191        fn try_new_invalid_zero() {
2192            // Test creating an invalid PositiveRealScalar instance with zero
2193            let scalar = PositiveRealScalar::try_new(0.0);
2194            assert!(matches!(
2195                scalar,
2196                Err(ErrorsPositiveRealScalar::ZeroValue { .. })
2197            ));
2198        }
2199
2200        #[test]
2201        #[cfg(debug_assertions)]
2202        #[should_panic = "The input value inf is not finite!"]
2203        fn try_new_invalid_infinite() {
2204            // Test creating an invalid PositiveRealScalar instance with an infinite value
2205            let _scalar = PositiveRealScalar::try_new(f64::INFINITY);
2206        }
2207
2208        #[test]
2209        #[cfg(debug_assertions)]
2210        #[should_panic = "The input value -inf is not finite!"]
2211        fn try_new_invalid_negative_infinite() {
2212            // Test creating an invalid PositiveRealScalar instance with negative infinity
2213            let _scalar = PositiveRealScalar::try_new(f64::NEG_INFINITY);
2214        }
2215
2216        #[test]
2217        #[cfg(debug_assertions)]
2218        #[should_panic = "The input value NaN is not finite!"]
2219        fn try_new_invalid_nan() {
2220            // Test creating an invalid PositiveRealScalar instance with a NaN value
2221            let _scalar = PositiveRealScalar::try_new(f64::NAN);
2222        }
2223
2224        #[test]
2225        fn equality_operator() {
2226            // Test equality operator for PositiveRealScalar instances
2227            let a = PositiveRealScalar::try_new(1.5).unwrap();
2228            let b = PositiveRealScalar::try_new(1.5).unwrap();
2229            assert!(a == b);
2230
2231            let c = PositiveRealScalar::try_new(3.1).unwrap();
2232            let d = PositiveRealScalar::try_new(3.1).unwrap();
2233            assert!(c == d);
2234        }
2235
2236        #[test]
2237        fn inequality_operator() {
2238            // Test inequality operator for PositiveRealScalar instances
2239            let a = PositiveRealScalar::try_new(1.0).unwrap();
2240            let b = PositiveRealScalar::try_new(2.0).unwrap();
2241            assert!(a != b);
2242
2243            let c = PositiveRealScalar::try_new(0.5).unwrap();
2244            let d = PositiveRealScalar::try_new(1.5).unwrap();
2245            assert!(c != d);
2246        }
2247
2248        #[test]
2249        fn debug_trait() {
2250            // Test the Debug trait
2251            let scalar = PositiveRealScalar::try_new(2.7).unwrap();
2252            assert_eq!(format!("{:?}", scalar), "PositiveRealScalar(2.7)");
2253        }
2254
2255        #[test]
2256        fn clone_trait() {
2257            // Test the Clone trait
2258            let scalar = PositiveRealScalar::try_new(1.414).unwrap();
2259            let cloned_scalar = scalar.clone();
2260            assert_eq!(scalar, cloned_scalar);
2261        }
2262
2263        #[test]
2264        fn partial_eq_trait() {
2265            // Test the PartialEq trait
2266            let scalar1 = PositiveRealScalar::try_new(0.577).unwrap();
2267            let scalar2 = PositiveRealScalar::try_new(0.577).unwrap();
2268            assert_eq!(scalar1, scalar2);
2269        }
2270
2271        #[test]
2272        fn partial_ord_trait() {
2273            // Test the PartialOrd trait
2274            let scalar1 = PositiveRealScalar::try_new(1.0).unwrap();
2275            let scalar2 = PositiveRealScalar::try_new(2.0).unwrap();
2276            assert!(scalar1 < scalar2);
2277
2278            let scalar3 = PositiveRealScalar::try_new(3.0).unwrap();
2279            let scalar4 = PositiveRealScalar::try_new(3.0).unwrap();
2280            assert!(scalar3 <= scalar4);
2281            assert!(scalar4 >= scalar3);
2282        }
2283
2284        #[test]
2285        fn as_ref_trait() {
2286            // Test the AsRef trait
2287            let scalar = PositiveRealScalar::try_new(2.0).unwrap();
2288            let inner: &f64 = scalar.as_ref();
2289            assert_eq!(*inner, 2.0);
2290        }
2291
2292        #[test]
2293        fn edge_cases() {
2294            // Test with very small positive values
2295            let tiny_scalar = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2296            assert_eq!(*tiny_scalar.as_ref(), f64::MIN_POSITIVE);
2297
2298            // Test with large positive values
2299            let large_scalar = PositiveRealScalar::try_new(f64::MAX).unwrap();
2300            assert_eq!(*large_scalar.as_ref(), f64::MAX);
2301
2302            // Test with epsilon
2303            let epsilon_scalar = PositiveRealScalar::try_new(f64::EPSILON).unwrap();
2304            assert_eq!(*epsilon_scalar.as_ref(), f64::EPSILON);
2305        }
2306
2307        #[test]
2308        fn generic_scalar_types() {
2309            // Test with RealNative64StrictFiniteInDebug type
2310            let scalar =
2311                PositiveRealScalar::try_new(RealNative64StrictFiniteInDebug::try_new(5.0).unwrap())
2312                    .unwrap();
2313            assert_eq!(
2314                *scalar.as_ref(),
2315                RealNative64StrictFiniteInDebug::try_new(5.0).unwrap()
2316            );
2317
2318            // Test error case with generic type
2319            let zero_value = RealNative64StrictFiniteInDebug::try_new(0.0).unwrap();
2320            let scalar_result = PositiveRealScalar::try_new(zero_value);
2321            assert!(matches!(
2322                scalar_result,
2323                Err(ErrorsPositiveRealScalar::ZeroValue { .. })
2324            ));
2325        }
2326
2327        #[test]
2328        fn mathematical_operations() {
2329            // Test that the wrapped values behave correctly in mathematical contexts
2330            let scalar1 = PositiveRealScalar::try_new(2.0).unwrap();
2331            let scalar2 = PositiveRealScalar::try_new(3.0).unwrap();
2332
2333            // Test comparison operations
2334            assert!(scalar1 < scalar2);
2335            assert!(scalar2 > scalar1);
2336            assert_eq!(
2337                scalar1.partial_cmp(&scalar2),
2338                Some(std::cmp::Ordering::Less)
2339            );
2340        }
2341
2342        #[test]
2343        fn error_messages() {
2344            // Test that error messages are descriptive
2345            let negative_result = PositiveRealScalar::try_new(-1.0);
2346            match negative_result {
2347                Err(ErrorsPositiveRealScalar::NegativeValue { value, .. }) => {
2348                    assert_eq!(value, -1.0);
2349                }
2350                _ => panic!("Expected NegativeValue error"),
2351            }
2352
2353            let zero_result = PositiveRealScalar::try_new(0.0);
2354            match zero_result {
2355                Err(ErrorsPositiveRealScalar::ZeroValue { .. }) => {
2356                    // Expected
2357                }
2358                _ => panic!("Expected ZeroValue error"),
2359            }
2360        }
2361
2362        #[test]
2363        fn sqrt_preserves_positivity() {
2364            // Test that sqrt of a positive value is also positive
2365            let base = PositiveRealScalar::try_new(4.0_f64).unwrap();
2366            let result = base.sqrt();
2367            assert_eq!(*result.as_ref(), 2.0);
2368
2369            // Test with other values
2370            let base = PositiveRealScalar::try_new(9.0_f64).unwrap();
2371            let result = base.sqrt();
2372            assert_eq!(*result.as_ref(), 3.0);
2373        }
2374
2375        #[test]
2376        fn sqrt_with_small_base() {
2377            // Test sqrt with very small positive value
2378            let base = PositiveRealScalar::try_new(0.01_f64).unwrap();
2379            let result = base.sqrt();
2380            assert_eq!(*result.as_ref(), 0.1);
2381        }
2382
2383        #[test]
2384        fn sqrt_with_generic_types() {
2385            // Test sqrt with validated types
2386            let base_val = RealNative64StrictFiniteInDebug::try_new(4.0).unwrap();
2387            let base = PositiveRealScalar::try_new(base_val).unwrap();
2388
2389            let result = base.sqrt();
2390            assert_eq!(*result.as_ref().as_ref(), 2.0);
2391        }
2392
2393        #[test]
2394        fn new_constructor_debug_validates() {
2395            // Test the new() constructor (validates in debug, skips in release)
2396            // In debug mode, new() should behave like try_new().unwrap()
2397            #[cfg(debug_assertions)]
2398            {
2399                let val = PositiveRealScalar::new(2.5_f64);
2400                assert_eq!(*val.as_ref(), 2.5);
2401            }
2402
2403            #[cfg(not(debug_assertions))]
2404            {
2405                // In release mode, new() trusts the input
2406                let val = PositiveRealScalar::new(2.5_f64);
2407                assert_eq!(*val.as_ref(), 2.5);
2408            }
2409        }
2410
2411        #[test]
2412        #[cfg(debug_assertions)]
2413        #[should_panic(expected = "Error in the creation")]
2414        fn new_constructor_panics_on_zero_debug() {
2415            // In debug mode, new() should panic on zero
2416            let _ = PositiveRealScalar::new(0.0_f64);
2417        }
2418
2419        #[test]
2420        #[cfg(debug_assertions)]
2421        #[should_panic(expected = "Error in the creation")]
2422        fn new_constructor_panics_on_negative_debug() {
2423            // In debug mode, new() should panic on negative
2424            let _ = PositiveRealScalar::new(-1.0_f64);
2425        }
2426
2427        #[test]
2428        fn one_trait_identity() {
2429            // Test the One trait: one() should return PositiveRealScalar(1.0)
2430            let one = PositiveRealScalar::<f64>::one();
2431            assert_eq!(*one.as_ref(), 1.0);
2432        }
2433
2434        #[test]
2435        fn one_trait_multiplicative_identity() {
2436            // Test that one acts as multiplicative identity
2437            let value = PositiveRealScalar::try_new(5.5_f64).unwrap();
2438            let one = PositiveRealScalar::<f64>::one();
2439
2440            let result = value.clone() * one.clone();
2441            assert_eq!(*result.as_ref(), 5.5);
2442
2443            let result = one * value;
2444            assert_eq!(*result.as_ref(), 5.5);
2445        }
2446
2447        #[test]
2448        fn one_trait_with_generic_types() {
2449            // Test One trait with validated types
2450            let one = PositiveRealScalar::<RealNative64StrictFiniteInDebug>::one();
2451            assert_eq!(*one.as_ref().as_ref(), 1.0);
2452        }
2453
2454        #[test]
2455        fn pow_integer_exponents() {
2456            // Test Pow trait with different integer exponent types
2457            let base = PositiveRealScalar::try_new(2.0_f64).unwrap();
2458
2459            // Test with u32
2460            let result = base.clone().pow(3u32);
2461            assert_eq!(*result.as_ref(), 8.0);
2462
2463            // Test with u8
2464            let result = base.clone().pow(2u8);
2465            assert_eq!(*result.as_ref(), 4.0);
2466
2467            // Test with i32 (positive)
2468            let result = base.clone().pow(2i32);
2469            assert_eq!(*result.as_ref(), 4.0);
2470        }
2471
2472        #[test]
2473        fn pow_zero_exponent() {
2474            // Test that any number raised to power 0 equals 1
2475            let base = PositiveRealScalar::try_new(5.5_f64).unwrap();
2476
2477            let result = base.pow(0u32);
2478            assert_eq!(*result.as_ref(), 1.0);
2479        }
2480
2481        #[test]
2482        fn pow_one_exponent() {
2483            // Test that any number raised to power 1 equals itself
2484            let base = PositiveRealScalar::try_new(3.7_f64).unwrap();
2485
2486            let result = base.clone().pow(1u32);
2487            assert_eq!(*result.as_ref(), 3.7);
2488        }
2489
2490        #[test]
2491        fn pow_preserves_positivity() {
2492            // Test that raising positive to any integer power preserves positivity
2493            let base = PositiveRealScalar::try_new(2.5_f64).unwrap();
2494
2495            let result = base.clone().pow(5u32);
2496            assert!(*result.as_ref() > 0.0);
2497            assert_eq!(*result.as_ref(), 2.5_f64.powi(5));
2498        }
2499
2500        #[test]
2501        fn pow_with_try_pow() {
2502            // Test the try_pow method
2503            let base = PositiveRealScalar::try_new(3.0_f64).unwrap();
2504
2505            let result = base.clone().try_pow(2u32);
2506            assert!(result.is_ok());
2507            assert_eq!(*result.unwrap().as_ref(), 9.0);
2508
2509            // Test with different exponent types
2510            let result = base.try_pow(3i32);
2511            assert!(result.is_ok());
2512            assert_eq!(*result.unwrap().as_ref(), 27.0);
2513        }
2514
2515        #[test]
2516        fn pow_large_exponents() {
2517            // Test with large exponents
2518            let base = PositiveRealScalar::try_new(1.1_f64).unwrap();
2519            let result = base.pow(10u32);
2520            let expected = 1.1_f64.powi(10);
2521            assert!((result.as_ref() - expected).abs() < 1e-10);
2522        }
2523
2524        #[test]
2525        fn pow_small_base() {
2526            // Test with small base values
2527            let base = PositiveRealScalar::try_new(0.5_f64).unwrap();
2528
2529            let result = base.clone().pow(2u32);
2530            assert_eq!(*result.as_ref(), 0.25);
2531
2532            let result = base.pow(3u32);
2533            assert_eq!(*result.as_ref(), 0.125);
2534        }
2535
2536        #[test]
2537        fn pow_with_generic_types() {
2538            // Test Pow with validated types
2539            let base_val = RealNative64StrictFiniteInDebug::try_new(2.0).unwrap();
2540            let base = PositiveRealScalar::try_new(base_val).unwrap();
2541
2542            let result = base.pow(3u32);
2543            assert_eq!(*result.as_ref().as_ref(), 8.0);
2544        }
2545
2546        #[test]
2547        fn pow_chain_operations() {
2548            // Test chaining pow operations
2549            let base = PositiveRealScalar::try_new(2.0_f64).unwrap();
2550
2551            // (2^3)^2 = 2^6 = 64
2552            let result = base.pow(3u32).pow(2u32);
2553            assert_eq!(*result.as_ref(), 64.0);
2554        }
2555
2556        #[test]
2557        fn add_trait_value_semantics() {
2558            // Test Add trait for by-value operands
2559            let a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2560            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2561
2562            let sum = a + b;
2563            assert_eq!(*sum.as_ref(), 5.0);
2564            assert!(*sum.as_ref() > 0.0);
2565        }
2566
2567        #[test]
2568        fn add_trait_reference_semantics() {
2569            // Test Add trait with reference operand
2570            let a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2571            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2572
2573            let sum = a + &b;
2574            assert_eq!(*sum.as_ref(), 5.0);
2575        }
2576
2577        #[test]
2578        fn mul_trait_value_semantics() {
2579            // Test Mul trait for by-value operands
2580            let a = PositiveRealScalar::try_new(2.5_f64).unwrap();
2581            let b = PositiveRealScalar::try_new(4.0_f64).unwrap();
2582
2583            let product = a * b;
2584            assert_eq!(*product.as_ref(), 10.0);
2585            assert!(*product.as_ref() > 0.0);
2586        }
2587
2588        #[test]
2589        fn mul_trait_reference_semantics() {
2590            // Test Mul trait with reference operand
2591            let a = PositiveRealScalar::try_new(2.5_f64).unwrap();
2592            let b = PositiveRealScalar::try_new(4.0_f64).unwrap();
2593
2594            let product = a * &b;
2595            assert_eq!(*product.as_ref(), 10.0);
2596        }
2597
2598        #[test]
2599        fn add_assign_value_semantics() {
2600            // Test AddAssign trait for by-value operand
2601            let mut a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2602            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2603
2604            a += b;
2605            assert_eq!(*a.as_ref(), 5.0);
2606        }
2607
2608        #[test]
2609        fn add_assign_reference_semantics() {
2610            // Test AddAssign trait with reference operand
2611            let mut a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2612            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2613
2614            a += &b;
2615            assert_eq!(*a.as_ref(), 5.0);
2616        }
2617
2618        #[test]
2619        fn mul_assign_value_semantics() {
2620            // Test MulAssign trait for by-value operand
2621            let mut a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2622            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2623
2624            a *= b;
2625            assert_eq!(*a.as_ref(), 6.0);
2626        }
2627
2628        #[test]
2629        fn mul_assign_reference_semantics() {
2630            // Test MulAssign trait with reference operand
2631            let mut a = PositiveRealScalar::try_new(2.0_f64).unwrap();
2632            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2633
2634            a *= &b;
2635            assert_eq!(*a.as_ref(), 6.0);
2636        }
2637
2638        #[test]
2639        fn max_min_traits() {
2640            // Test Max/Min traits (delegated to default behavior)
2641            let a = PositiveRealScalar::try_new(1.0_f64).unwrap();
2642            let b = PositiveRealScalar::try_new(3.0_f64).unwrap();
2643
2644            let max_val = Max::max_by_ref(&a, &b);
2645            assert_eq!(*max_val.as_ref(), 3.0);
2646
2647            let min_val = Min::min_by_ref(&a, &b);
2648            assert_eq!(*min_val.as_ref(), 1.0);
2649        }
2650    }
2651
2652    mod non_negative_real_scalar {
2653        use super::*;
2654        use crate::backends::native::validated::RealNative64StrictFiniteInDebug;
2655        use crate::functions::{Max, Min};
2656        use num::Zero;
2657
2658        #[test]
2659        fn add_trait_preserves_non_negativity() {
2660            let a = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
2661            let b = NonNegativeRealScalar::try_new(3.5_f64).unwrap();
2662
2663            let sum = a + b;
2664            assert_eq!(*sum.as_ref(), 5.5);
2665            assert!(*sum.as_ref() >= 0.0);
2666        }
2667
2668        #[test]
2669        fn add_trait_zero_is_identity() {
2670            let value = NonNegativeRealScalar::try_new(4.25_f64).unwrap();
2671            let zero = NonNegativeRealScalar::<f64>::zero();
2672
2673            assert_eq!(*(value.clone() + zero.clone()).as_ref(), 4.25);
2674            assert_eq!(*(zero + value).as_ref(), 4.25);
2675        }
2676
2677        #[test]
2678        fn zero_trait_methods() {
2679            let zero = NonNegativeRealScalar::<f64>::zero();
2680            let non_zero = NonNegativeRealScalar::try_new(0.5_f64).unwrap();
2681
2682            assert!(zero.is_zero());
2683            assert!(!non_zero.is_zero());
2684            assert_eq!(*zero.as_ref(), 0.0);
2685        }
2686
2687        #[test]
2688        fn max_trait_by_ref_and_by_value() {
2689            let small = NonNegativeRealScalar::try_new(1.0_f64).unwrap();
2690            let large = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
2691
2692            let by_ref = Max::max_by_ref(&small, &large);
2693            assert_eq!(*by_ref.as_ref(), 3.0);
2694
2695            let by_value = Max::max_by_value(small, large);
2696            assert_eq!(*by_value.as_ref(), 3.0);
2697        }
2698
2699        #[test]
2700        fn min_trait_by_ref_and_by_value() {
2701            let small = NonNegativeRealScalar::try_new(1.0_f64).unwrap();
2702            let large = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
2703
2704            let by_ref = Min::min_by_ref(&small, &large);
2705            assert_eq!(*by_ref.as_ref(), 1.0);
2706
2707            let by_value = Min::min_by_value(small, large);
2708            assert_eq!(*by_value.as_ref(), 1.0);
2709        }
2710
2711        #[test]
2712        fn max_min_by_ref_equal_values_returns_left_operand() {
2713            let left_max = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
2714            let right_max = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
2715            let selected_max = Max::max_by_ref(&left_max, &right_max);
2716            assert!(std::ptr::eq(selected_max, &left_max));
2717
2718            let left_min = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
2719            let right_min = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
2720            let selected_min = Min::min_by_ref(&left_min, &right_min);
2721            assert!(std::ptr::eq(selected_min, &left_min));
2722        }
2723
2724        #[test]
2725        fn try_new_negative_fails() {
2726            let result = NonNegativeRealScalar::try_new(-1.0_f64);
2727            assert!(
2728                matches!(result, Err(ErrorsNonNegativeRealScalar::NegativeValue { value, .. }) if value == -1.0)
2729            );
2730        }
2731
2732        #[test]
2733        fn display_trait() {
2734            let val = NonNegativeRealScalar::try_new(2.7_f64).unwrap();
2735            assert_eq!(format!("{}", val), "2.7");
2736
2737            let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
2738            assert_eq!(format!("{}", zero), "0");
2739        }
2740
2741        #[test]
2742        fn partial_ord() {
2743            let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
2744            let positive = NonNegativeRealScalar::try_new(1.0_f64).unwrap();
2745            assert!(zero < positive);
2746        }
2747
2748        #[test]
2749        fn serialize_deserialize() {
2750            let val = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
2751            let serialized = serde_json::to_string(&val).unwrap();
2752            let deserialized: NonNegativeRealScalar<f64> =
2753                serde_json::from_str(&serialized).unwrap();
2754            assert_eq!(val, deserialized);
2755        }
2756
2757        #[test]
2758        fn with_validated_type() {
2759            let inner = RealNative64StrictFinite::try_from_f64(0.0).unwrap();
2760            let val = NonNegativeRealScalar::try_new(inner).unwrap();
2761            assert_eq!(*val.as_ref().as_ref(), 0.0);
2762        }
2763
2764        #[test]
2765        #[cfg(debug_assertions)]
2766        #[should_panic(expected = "is not finite")]
2767        fn debug_panics_on_nan() {
2768            let _ = NonNegativeRealScalar::try_new(f64::NAN);
2769        }
2770
2771        #[test]
2772        fn try_new_positive() {
2773            // Test creating a NonNegativeRealScalar instance with positive values
2774            let v = NonNegativeRealScalar::try_new(2.5).unwrap();
2775            assert_eq!(*v.as_ref(), 2.5);
2776
2777            // Test with very small positive value
2778            let v = NonNegativeRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2779            assert_eq!(*v.as_ref(), f64::MIN_POSITIVE);
2780
2781            // Test with large positive value
2782            let v = NonNegativeRealScalar::try_new(1e100).unwrap();
2783            assert_eq!(*v.as_ref(), 1e100);
2784        }
2785
2786        #[test]
2787        fn try_new_zero() {
2788            // Test creating a NonNegativeRealScalar instance with zero (VALID case)
2789            let v = NonNegativeRealScalar::try_new(0.0).unwrap();
2790            assert_eq!(*v.as_ref(), 0.0);
2791
2792            // This is the key difference from PositiveRealScalar:
2793            // Zero is VALID for NonNegativeRealScalar (x ≥ 0)
2794            // but INVALID for PositiveRealScalar (x > 0)
2795        }
2796
2797        #[test]
2798        fn try_new_invalid_negative() {
2799            // Test creating an invalid NonNegativeRealScalar instance with negative values
2800            let scalar = NonNegativeRealScalar::try_new(-0.1);
2801            assert!(matches!(
2802                scalar,
2803                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
2804            ));
2805
2806            // Test with negative value close to zero
2807            let scalar = NonNegativeRealScalar::try_new(-f64::EPSILON);
2808            assert!(matches!(
2809                scalar,
2810                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
2811            ));
2812
2813            // Test with large negative value
2814            let scalar = NonNegativeRealScalar::try_new(-100.0);
2815            assert!(matches!(
2816                scalar,
2817                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
2818            ));
2819        }
2820
2821        #[test]
2822        #[cfg(debug_assertions)]
2823        #[should_panic = "The input value inf is not finite!"]
2824        fn try_new_invalid_infinite() {
2825            // Test creating an invalid NonNegativeRealScalar instance with infinity
2826            let _scalar = NonNegativeRealScalar::try_new(f64::INFINITY);
2827        }
2828
2829        #[test]
2830        #[cfg(debug_assertions)]
2831        #[should_panic = "The input value -inf is not finite!"]
2832        fn try_new_invalid_negative_infinite() {
2833            // Test creating an invalid NonNegativeRealScalar instance with negative infinity
2834            let _scalar = NonNegativeRealScalar::try_new(f64::NEG_INFINITY);
2835        }
2836
2837        #[test]
2838        #[cfg(debug_assertions)]
2839        #[should_panic = "The input value NaN is not finite!"]
2840        fn try_new_invalid_nan() {
2841            // Test creating an invalid NonNegativeRealScalar instance with NaN
2842            let _scalar = NonNegativeRealScalar::try_new(f64::NAN);
2843        }
2844
2845        #[test]
2846        fn equality_operator() {
2847            // Test equality operator for NonNegativeRealScalar instances
2848            let a = NonNegativeRealScalar::try_new(1.5).unwrap();
2849            let b = NonNegativeRealScalar::try_new(1.5).unwrap();
2850            assert!(a == b);
2851
2852            let c = NonNegativeRealScalar::try_new(0.0).unwrap();
2853            let d = NonNegativeRealScalar::try_new(0.0).unwrap();
2854            assert!(c == d);
2855        }
2856
2857        #[test]
2858        fn inequality_operator() {
2859            // Test inequality operator for NonNegativeRealScalar instances
2860            let a = NonNegativeRealScalar::try_new(0.0).unwrap();
2861            let b = NonNegativeRealScalar::try_new(1.0).unwrap();
2862            assert!(a != b);
2863
2864            let c = NonNegativeRealScalar::try_new(0.5).unwrap();
2865            let d = NonNegativeRealScalar::try_new(1.5).unwrap();
2866            assert!(c != d);
2867        }
2868
2869        #[test]
2870        fn debug_trait() {
2871            // Test the Debug trait
2872            let scalar = NonNegativeRealScalar::try_new(2.7).unwrap();
2873            assert_eq!(format!("{:?}", scalar), "NonNegativeRealScalar(2.7)");
2874
2875            let zero = NonNegativeRealScalar::try_new(0.0).unwrap();
2876            assert_eq!(format!("{:?}", zero), "NonNegativeRealScalar(0.0)");
2877        }
2878
2879        #[test]
2880        fn clone_trait() {
2881            // Test the Clone trait
2882            let scalar = NonNegativeRealScalar::try_new(1.414).unwrap();
2883            let cloned_scalar = scalar.clone();
2884            assert_eq!(scalar, cloned_scalar);
2885        }
2886
2887        #[test]
2888        fn partial_eq_trait() {
2889            // Test the PartialEq trait
2890            let scalar1 = NonNegativeRealScalar::try_new(0.577).unwrap();
2891            let scalar2 = NonNegativeRealScalar::try_new(0.577).unwrap();
2892            assert_eq!(scalar1, scalar2);
2893
2894            // Test with zero
2895            let zero1 = NonNegativeRealScalar::try_new(0.0).unwrap();
2896            let zero2 = NonNegativeRealScalar::try_new(0.0).unwrap();
2897            assert_eq!(zero1, zero2);
2898        }
2899
2900        #[test]
2901        fn partial_ord_trait() {
2902            // Test the PartialOrd trait
2903            let scalar1 = NonNegativeRealScalar::try_new(0.0).unwrap();
2904            let scalar2 = NonNegativeRealScalar::try_new(1.0).unwrap();
2905            assert!(scalar1 < scalar2);
2906
2907            let scalar3 = NonNegativeRealScalar::try_new(3.0).unwrap();
2908            let scalar4 = NonNegativeRealScalar::try_new(3.0).unwrap();
2909            assert!(scalar3 <= scalar4);
2910            assert!(scalar4 >= scalar3);
2911
2912            // Test that zero is less than positive values
2913            let zero = NonNegativeRealScalar::try_new(0.0).unwrap();
2914            let positive = NonNegativeRealScalar::try_new(0.001).unwrap();
2915            assert!(zero < positive);
2916        }
2917
2918        #[test]
2919        fn as_ref_trait() {
2920            // Test the AsRef trait
2921            let scalar = NonNegativeRealScalar::try_new(2.0).unwrap();
2922            let inner: &f64 = scalar.as_ref();
2923            assert_eq!(*inner, 2.0);
2924
2925            let zero = NonNegativeRealScalar::try_new(0.0).unwrap();
2926            let inner: &f64 = zero.as_ref();
2927            assert_eq!(*inner, 0.0);
2928        }
2929
2930        #[test]
2931        fn into_inner() {
2932            // Test converting a NonNegativeRealScalar instance into its inner value
2933            let scalar = NonNegativeRealScalar::try_new(42.0).unwrap();
2934            let inner = scalar.into_inner();
2935            assert_eq!(inner, 42.0);
2936
2937            // Test with zero
2938            let zero = NonNegativeRealScalar::try_new(0.0).unwrap();
2939            let inner = zero.into_inner();
2940            assert_eq!(inner, 0.0);
2941
2942            // Test with very small positive value
2943            let scalar = NonNegativeRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2944            let inner = scalar.into_inner();
2945            assert_eq!(inner, f64::MIN_POSITIVE);
2946        }
2947
2948        #[test]
2949        fn edge_cases() {
2950            // Test with zero (key edge case)
2951            let zero_scalar = NonNegativeRealScalar::try_new(0.0).unwrap();
2952            assert_eq!(*zero_scalar.as_ref(), 0.0);
2953
2954            // Test with very small positive values
2955            let tiny_scalar = NonNegativeRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
2956            assert_eq!(*tiny_scalar.as_ref(), f64::MIN_POSITIVE);
2957
2958            // Test with large positive values
2959            let large_scalar = NonNegativeRealScalar::try_new(f64::MAX).unwrap();
2960            assert_eq!(*large_scalar.as_ref(), f64::MAX);
2961
2962            // Test with epsilon
2963            let epsilon_scalar = NonNegativeRealScalar::try_new(f64::EPSILON).unwrap();
2964            assert_eq!(*epsilon_scalar.as_ref(), f64::EPSILON);
2965        }
2966
2967        #[test]
2968        fn generic_scalar_types() {
2969            // Test with RealNative64StrictFiniteInDebug type
2970            let scalar = NonNegativeRealScalar::try_new(
2971                RealNative64StrictFiniteInDebug::try_new(5.0).unwrap(),
2972            )
2973            .unwrap();
2974            assert_eq!(
2975                *scalar.as_ref(),
2976                RealNative64StrictFiniteInDebug::try_new(5.0).unwrap()
2977            );
2978
2979            // Test with zero (valid for NonNegativeRealScalar)
2980            let zero_value = RealNative64StrictFiniteInDebug::try_new(0.0).unwrap();
2981            let scalar_result = NonNegativeRealScalar::try_new(zero_value);
2982            assert!(scalar_result.is_ok()); // Should succeed!
2983
2984            // Test error case with generic type
2985            let negative_value = RealNative64StrictFiniteInDebug::try_new(-1.0).unwrap();
2986            let scalar_result = NonNegativeRealScalar::try_new(negative_value);
2987            assert!(matches!(
2988                scalar_result,
2989                Err(ErrorsNonNegativeRealScalar::NegativeValue { .. })
2990            ));
2991        }
2992
2993        #[test]
2994        fn mathematical_operations() {
2995            // Test that the wrapped values behave correctly in mathematical contexts
2996            let scalar1 = NonNegativeRealScalar::try_new(0.0).unwrap();
2997            let scalar2 = NonNegativeRealScalar::try_new(2.0).unwrap();
2998            let scalar3 = NonNegativeRealScalar::try_new(3.0).unwrap();
2999
3000            // Test comparison operations
3001            assert!(scalar1 < scalar2);
3002            assert!(scalar2 < scalar3);
3003            assert!(scalar3 > scalar1);
3004            assert_eq!(
3005                scalar1.partial_cmp(&scalar2),
3006                Some(std::cmp::Ordering::Less)
3007            );
3008            assert_eq!(
3009                scalar2.partial_cmp(&scalar1),
3010                Some(std::cmp::Ordering::Greater)
3011            );
3012        }
3013
3014        #[test]
3015        fn error_messages() {
3016            // Test that error messages are descriptive
3017            let negative_result = NonNegativeRealScalar::try_new(-1.0);
3018            match negative_result {
3019                Err(ErrorsNonNegativeRealScalar::NegativeValue { value, .. }) => {
3020                    assert_eq!(value, -1.0);
3021                }
3022                _ => panic!("Expected NegativeValue error"),
3023            }
3024
3025            let large_negative_result = NonNegativeRealScalar::try_new(-100.5);
3026            match large_negative_result {
3027                Err(ErrorsNonNegativeRealScalar::NegativeValue { value, .. }) => {
3028                    assert_eq!(value, -100.5);
3029                }
3030                _ => panic!("Expected NegativeValue error"),
3031            }
3032        }
3033
3034        #[test]
3035        fn distinction_from_positive_real_scalar() {
3036            // Critical test: demonstrate the key difference between
3037            // NonNegativeRealScalar (x ≥ 0) and PositiveRealScalar (x > 0)
3038
3039            // Zero is VALID for NonNegativeRealScalar
3040            let non_neg_zero = NonNegativeRealScalar::try_new(0.0);
3041            assert!(
3042                non_neg_zero.is_ok(),
3043                "Zero should be valid for NonNegativeRealScalar (x ≥ 0)"
3044            );
3045
3046            // Zero is INVALID for PositiveRealScalar
3047            let pos_zero = PositiveRealScalar::try_new(0.0);
3048            assert!(
3049                pos_zero.is_err(),
3050                "Zero should be invalid for PositiveRealScalar (x > 0)"
3051            );
3052            assert!(matches!(
3053                pos_zero,
3054                Err(ErrorsPositiveRealScalar::ZeroValue { .. })
3055            ));
3056
3057            // Positive values are valid for both
3058            let non_neg_positive = NonNegativeRealScalar::try_new(1.0);
3059            let pos_positive = PositiveRealScalar::try_new(1.0);
3060            assert!(non_neg_positive.is_ok());
3061            assert!(pos_positive.is_ok());
3062
3063            // Negative values are invalid for both
3064            let non_neg_negative = NonNegativeRealScalar::try_new(-1.0);
3065            let pos_negative = PositiveRealScalar::try_new(-1.0);
3066            assert!(non_neg_negative.is_err());
3067            assert!(pos_negative.is_err());
3068        }
3069
3070        #[test]
3071        fn use_case_distance() {
3072            // Real-world use case: computing distances (which can be zero)
3073            fn compute_distance(x1: f64, x2: f64) -> NonNegativeRealScalar<f64> {
3074                let diff = (x2 - x1).abs();
3075                NonNegativeRealScalar::try_new(diff).unwrap()
3076            }
3077
3078            // Distance between different points
3079            let dist1 = compute_distance(0.0, 5.0);
3080            assert_eq!(*dist1.as_ref(), 5.0);
3081
3082            // Distance from a point to itself (zero distance is valid!)
3083            let dist2 = compute_distance(3.0, 3.0);
3084            assert_eq!(*dist2.as_ref(), 0.0);
3085        }
3086
3087        #[test]
3088        fn use_case_absolute_value() {
3089            // Real-world use case: absolute values (which can be zero)
3090            fn safe_abs(x: f64) -> NonNegativeRealScalar<f64> {
3091                NonNegativeRealScalar::try_new(x.abs()).unwrap()
3092            }
3093
3094            assert_eq!(*safe_abs(-5.0).as_ref(), 5.0);
3095            assert_eq!(*safe_abs(0.0).as_ref(), 0.0); // Zero is valid!
3096            assert_eq!(*safe_abs(3.0).as_ref(), 3.0);
3097        }
3098
3099        #[test]
3100        fn one_trait_identity() {
3101            // Test the One trait: one() should return NonNegativeRealScalar(1.0)
3102            let one = NonNegativeRealScalar::<f64>::one();
3103            assert_eq!(*one.as_ref(), 1.0);
3104        }
3105
3106        #[test]
3107        fn one_trait_multiplicative_identity() {
3108            // Test that one acts as multiplicative identity
3109            let value = NonNegativeRealScalar::try_new(5.5_f64).unwrap();
3110            let one = NonNegativeRealScalar::<f64>::one();
3111
3112            let result = value.clone() * one.clone();
3113            assert_eq!(*result.as_ref(), 5.5);
3114
3115            let result = one * value;
3116            assert_eq!(*result.as_ref(), 5.5);
3117        }
3118
3119        #[test]
3120        fn one_trait_with_generic_types() {
3121            // Test One trait with validated types
3122            let one = NonNegativeRealScalar::<RealNative64StrictFiniteInDebug>::one();
3123            assert_eq!(*one.as_ref().as_ref(), 1.0);
3124        }
3125
3126        #[test]
3127        fn pow_integer_exponents() {
3128            // Test Pow trait with different integer exponent types
3129            let base = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
3130
3131            // Test with u32
3132            let result = base.clone().pow(3u32);
3133            assert_eq!(*result.as_ref(), 8.0);
3134
3135            // Test with u8
3136            let result = base.clone().pow(2u8);
3137            assert_eq!(*result.as_ref(), 4.0);
3138
3139            // Test with i32 (positive)
3140            let result = base.clone().pow(2i32);
3141            assert_eq!(*result.as_ref(), 4.0);
3142        }
3143
3144        #[test]
3145        fn pow_zero_exponent() {
3146            // Test that any number raised to power 0 equals 1
3147            let base = NonNegativeRealScalar::try_new(5.5_f64).unwrap();
3148
3149            let result = base.clone().pow(0u32);
3150            assert_eq!(*result.as_ref(), 1.0);
3151
3152            // Even 0 raised to power 0 should be 1
3153            let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
3154            let result = zero.pow(0u32);
3155            assert_eq!(*result.as_ref(), 1.0);
3156        }
3157
3158        #[test]
3159        fn pow_one_exponent() {
3160            // Test that any number raised to power 1 equals itself
3161            let base = NonNegativeRealScalar::try_new(3.7_f64).unwrap();
3162
3163            let result = base.clone().pow(1u32);
3164            assert_eq!(*result.as_ref(), 3.7);
3165        }
3166
3167        #[test]
3168        fn pow_preserves_non_negativity() {
3169            // Test that raising non-negative to any integer power preserves non-negativity
3170            let base = NonNegativeRealScalar::try_new(2.5_f64).unwrap();
3171
3172            let result = base.clone().pow(5u32);
3173            assert!(*result.as_ref() >= 0.0);
3174            assert_eq!(*result.as_ref(), 2.5_f64.powi(5));
3175
3176            // Even 0 raised to positive power stays non-negative
3177            let zero = NonNegativeRealScalar::try_new(0.0_f64).unwrap();
3178            let result = zero.pow(10u32);
3179            assert_eq!(*result.as_ref(), 0.0);
3180        }
3181
3182        #[test]
3183        fn pow_with_try_pow() {
3184            // Test the try_pow method
3185            let base = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3186
3187            let result = base.clone().try_pow(2u32);
3188            assert!(result.is_ok());
3189            assert_eq!(*result.unwrap().as_ref(), 9.0);
3190
3191            // Test with different exponent types
3192            let result = base.clone().try_pow(3i32);
3193            assert!(result.is_ok());
3194            assert_eq!(*result.unwrap().as_ref(), 27.0);
3195        }
3196
3197        #[test]
3198        fn pow_large_exponents() {
3199            // Test with large exponents
3200            let base = NonNegativeRealScalar::try_new(1.1_f64).unwrap();
3201            let result = base.pow(10u32);
3202            let expected = 1.1_f64.powi(10);
3203            assert!((result.as_ref() - expected).abs() < 1e-10);
3204        }
3205
3206        #[test]
3207        fn pow_small_base() {
3208            // Test with small base values
3209            let base = NonNegativeRealScalar::try_new(0.5_f64).unwrap();
3210
3211            let result = base.clone().pow(2u32);
3212            assert_eq!(*result.as_ref(), 0.25);
3213
3214            let result = base.clone().pow(3u32);
3215            assert_eq!(*result.as_ref(), 0.125);
3216        }
3217
3218        #[test]
3219        fn pow_with_generic_types() {
3220            // Test Pow with validated types
3221            let base_val = RealNative64StrictFiniteInDebug::try_new(2.0).unwrap();
3222            let base = NonNegativeRealScalar::try_new(base_val).unwrap();
3223
3224            let result = base.pow(3u32);
3225            assert_eq!(*result.as_ref().as_ref(), 8.0);
3226        }
3227
3228        #[test]
3229        fn pow_chain_operations() {
3230            // Test chaining pow operations
3231            let base = NonNegativeRealScalar::try_new(2.0_f64).unwrap();
3232
3233            // (2^3)^2 = 2^6 = 64
3234            let result = base.clone().pow(3u32).pow(2u32);
3235            assert_eq!(*result.as_ref(), 64.0);
3236        }
3237    }
3238
3239    mod distinction_tests {
3240        use super::*;
3241
3242        #[test]
3243        fn positive_vs_non_negative_zero() {
3244            // This is the KEY difference between the two types
3245
3246            // Zero is INVALID for PositiveRealScalar (x > 0)
3247            assert!(PositiveRealScalar::try_new(0.0_f64).is_err());
3248
3249            // Zero is VALID for NonNegativeRealScalar (x ≥ 0)
3250            assert!(NonNegativeRealScalar::try_new(0.0_f64).is_ok());
3251        }
3252
3253        #[test]
3254        fn both_accept_positive() {
3255            let positive = 1.0_f64;
3256            assert!(PositiveRealScalar::try_new(positive).is_ok());
3257            assert!(NonNegativeRealScalar::try_new(positive).is_ok());
3258        }
3259
3260        #[test]
3261        fn both_reject_negative() {
3262            let negative = -1.0_f64;
3263            assert!(PositiveRealScalar::try_new(negative).is_err());
3264            assert!(NonNegativeRealScalar::try_new(negative).is_err());
3265        }
3266    }
3267
3268    mod conversion_tests {
3269        use super::*;
3270        use crate::backends::native::validated::RealNative64StrictFiniteInDebug;
3271
3272        #[test]
3273        fn from_positive_to_non_negative() {
3274            // Test basic conversion from PositiveRealScalar to NonNegativeRealScalar
3275            let positive = PositiveRealScalar::try_new(5.0_f64).unwrap();
3276            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3277
3278            assert_eq!(*non_negative.as_ref(), 5.0);
3279        }
3280
3281        #[test]
3282        fn from_positive_to_non_negative_min_positive() {
3283            // Test conversion with f64::MIN_POSITIVE (smallest positive value)
3284            let positive = PositiveRealScalar::try_new(f64::MIN_POSITIVE).unwrap();
3285            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3286
3287            assert_eq!(*non_negative.as_ref(), f64::MIN_POSITIVE);
3288        }
3289
3290        #[test]
3291        fn from_positive_to_non_negative_large_value() {
3292            // Test conversion with large value
3293            let positive = PositiveRealScalar::try_new(f64::MAX).unwrap();
3294            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3295
3296            assert_eq!(*non_negative.as_ref(), f64::MAX);
3297        }
3298
3299        #[test]
3300        fn from_positive_to_non_negative_one() {
3301            // Test conversion with the multiplicative identity
3302            let positive = PositiveRealScalar::try_new(1.0_f64).unwrap();
3303            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3304
3305            assert_eq!(*non_negative.as_ref(), 1.0);
3306        }
3307
3308        #[test]
3309        fn from_positive_to_non_negative_preserves_value() {
3310            // Test that the conversion preserves the exact value
3311            let test_values = vec![0.5, 1.0, 2.5, 10.0, 99.9, 1e10, 1e-10];
3312
3313            for value in test_values {
3314                let positive = PositiveRealScalar::try_new(value).unwrap();
3315                let non_negative: NonNegativeRealScalar<f64> = positive.into();
3316
3317                assert_eq!(*non_negative.as_ref(), value);
3318            }
3319        }
3320
3321        #[test]
3322        fn from_positive_to_non_negative_with_generic_type() {
3323            // Test conversion with validated types
3324            let inner = RealNative64StrictFiniteInDebug::try_new(5.0).unwrap();
3325            let positive = PositiveRealScalar::try_new(inner).unwrap();
3326            let non_negative: NonNegativeRealScalar<RealNative64StrictFiniteInDebug> =
3327                positive.into();
3328
3329            assert_eq!(*non_negative.as_ref().as_ref(), 5.0);
3330        }
3331
3332        #[test]
3333        fn from_positive_consumed_by_conversion() {
3334            // Test that the conversion consumes the PositiveRealScalar
3335            let positive = PositiveRealScalar::try_new(5.0_f64).unwrap();
3336            let _non_negative: NonNegativeRealScalar<f64> = positive.into();
3337
3338            // If we try to use `positive` here, it would be a compile error
3339            // because it was consumed by the conversion.
3340            // This test just documents the behavior.
3341        }
3342
3343        #[test]
3344        fn from_positive_creates_valid_non_negative() {
3345            // Test that the converted value is indeed non-negative
3346            let positive = PositiveRealScalar::try_new(3.5_f64).unwrap();
3347            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3348
3349            // The converted value should pass all non-negative validation
3350            assert!(*non_negative.as_ref() >= 0.0);
3351            assert!(!non_negative.is_zero()); // Since it came from a positive value
3352        }
3353
3354        #[test]
3355        fn from_positive_mathematical_properties() {
3356            // Test that mathematical properties are preserved after conversion
3357            let positive_a = PositiveRealScalar::try_new(2.0_f64).unwrap();
3358            let positive_b = PositiveRealScalar::try_new(3.0_f64).unwrap();
3359
3360            let non_neg_a: NonNegativeRealScalar<f64> = positive_a.into();
3361            let non_neg_b: NonNegativeRealScalar<f64> = positive_b.into();
3362
3363            // Arithmetic should work the same way after conversion
3364            let sum = non_neg_a + non_neg_b;
3365            assert_eq!(*sum.as_ref(), 5.0);
3366        }
3367
3368        #[test]
3369        fn from_positive_with_chained_operations() {
3370            // Test conversion followed by operations
3371            let positive = PositiveRealScalar::try_new(2.0_f64).unwrap();
3372            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3373
3374            // Test that we can use trait methods on the converted value
3375            let one = NonNegativeRealScalar::<f64>::one();
3376            let result = non_negative * one;
3377
3378            assert_eq!(*result.as_ref(), 2.0);
3379        }
3380
3381        #[test]
3382        fn from_positive_comparison_after_conversion() {
3383            // Test comparison operations work correctly after conversion
3384            let positive_small = PositiveRealScalar::try_new(1.0_f64).unwrap();
3385            let positive_large = PositiveRealScalar::try_new(3.0_f64).unwrap();
3386
3387            let non_neg_small: NonNegativeRealScalar<f64> = positive_small.into();
3388            let non_neg_large: NonNegativeRealScalar<f64> = positive_large.into();
3389
3390            assert!(non_neg_small < non_neg_large);
3391            assert!(non_neg_large > non_neg_small);
3392        }
3393
3394        #[test]
3395        fn from_positive_pow_after_conversion() {
3396            // Test that Pow trait works correctly after conversion
3397            let positive = PositiveRealScalar::try_new(2.0_f64).unwrap();
3398            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3399
3400            let squared = non_negative.pow(2u32);
3401            assert_eq!(*squared.as_ref(), 4.0);
3402        }
3403
3404        #[test]
3405        fn from_positive_sqrt_after_conversion() {
3406            // Test that sqrt works correctly after conversion
3407            let positive = PositiveRealScalar::try_new(4.0_f64).unwrap();
3408            let non_negative: NonNegativeRealScalar<f64> = positive.into();
3409
3410            let sqrt = non_negative.sqrt();
3411            assert_eq!(*sqrt.as_ref(), 2.0);
3412        }
3413    }
3414
3415    mod cross_type_arithmetic_tests {
3416        use super::*;
3417        use crate::backends::native::validated::RealNative64StrictFiniteInDebug;
3418
3419        // --- Pos + NonNeg → Pos ---
3420
3421        #[test]
3422        fn pos_add_non_neg_value() {
3423            // PositiveRealScalar + NonNegativeRealScalar (by value) → PositiveRealScalar
3424            let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
3425            let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3426
3427            let result: PositiveRealScalar<f64> = pos + non_neg;
3428            assert_eq!(*result.as_ref(), 5.0);
3429        }
3430
3431        #[test]
3432        fn pos_add_non_neg_ref() {
3433            // PositiveRealScalar + &NonNegativeRealScalar (by reference) → PositiveRealScalar
3434            let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
3435            let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3436
3437            let result: PositiveRealScalar<f64> = pos + &non_neg;
3438            assert_eq!(*result.as_ref(), 5.0);
3439            // non_neg is still usable here (not consumed)
3440            assert_eq!(*non_neg.as_ref(), 3.0);
3441        }
3442
3443        #[test]
3444        fn pos_add_non_neg_zero_preserves_positivity() {
3445            // Adding zero (NonNeg) to a positive value should remain positive
3446            let pos = PositiveRealScalar::try_new(5.0_f64).unwrap();
3447            let zero = NonNegativeRealScalar::<f64>::zero();
3448
3449            let result: PositiveRealScalar<f64> = pos + zero;
3450            assert_eq!(*result.as_ref(), 5.0);
3451            assert!(*result.as_ref() > 0.0);
3452        }
3453
3454        #[test]
3455        fn pos_add_non_neg_zero_ref_preserves_positivity() {
3456            // Adding zero (NonNeg ref) to a positive value should remain positive
3457            let pos = PositiveRealScalar::try_new(5.0_f64).unwrap();
3458            let zero = NonNegativeRealScalar::<f64>::zero();
3459
3460            let result: PositiveRealScalar<f64> = pos + &zero;
3461            assert_eq!(*result.as_ref(), 5.0);
3462        }
3463
3464        // --- NonNeg + Pos → Pos ---
3465
3466        #[test]
3467        fn non_neg_add_pos_value() {
3468            // NonNegativeRealScalar + PositiveRealScalar (by value) → PositiveRealScalar
3469            let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3470            let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
3471
3472            let result: PositiveRealScalar<f64> = non_neg + pos;
3473            assert_eq!(*result.as_ref(), 5.0);
3474        }
3475
3476        #[test]
3477        fn non_neg_add_pos_ref() {
3478            // NonNegativeRealScalar + &PositiveRealScalar (by reference) → PositiveRealScalar
3479            let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3480            let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
3481
3482            let result: PositiveRealScalar<f64> = non_neg + &pos;
3483            assert_eq!(*result.as_ref(), 5.0);
3484            // pos is still usable here (not consumed)
3485            assert_eq!(*pos.as_ref(), 2.0);
3486        }
3487
3488        #[test]
3489        fn zero_add_pos_value() {
3490            // Zero (NonNeg) + PositiveRealScalar → PositiveRealScalar
3491            // Key test: zero + positive should give the positive value
3492            let zero = NonNegativeRealScalar::<f64>::zero();
3493            let pos = PositiveRealScalar::try_new(5.0_f64).unwrap();
3494
3495            let result: PositiveRealScalar<f64> = zero + pos;
3496            assert_eq!(*result.as_ref(), 5.0);
3497            assert!(*result.as_ref() > 0.0);
3498        }
3499
3500        #[test]
3501        fn zero_add_pos_ref() {
3502            // Zero (NonNeg) + &PositiveRealScalar → PositiveRealScalar
3503            let zero = NonNegativeRealScalar::<f64>::zero();
3504            let pos = PositiveRealScalar::try_new(5.0_f64).unwrap();
3505
3506            let result: PositiveRealScalar<f64> = zero + &pos;
3507            assert_eq!(*result.as_ref(), 5.0);
3508        }
3509
3510        // --- Commutativity ---
3511
3512        #[test]
3513        fn commutativity() {
3514            // Pos + NonNeg and NonNeg + Pos should give the same numeric value
3515            let pos = PositiveRealScalar::try_new(2.0_f64).unwrap();
3516            let non_neg = NonNegativeRealScalar::try_new(3.0_f64).unwrap();
3517
3518            let left: PositiveRealScalar<f64> = pos.clone() + non_neg.clone();
3519            let right: PositiveRealScalar<f64> = non_neg + pos;
3520
3521            assert_eq!(*left.as_ref(), *right.as_ref());
3522        }
3523
3524        // --- Generic types ---
3525
3526        #[test]
3527        fn cross_type_add_with_generic_type() {
3528            let pos_inner = RealNative64StrictFiniteInDebug::try_new(2.0).unwrap();
3529            let non_neg_inner = RealNative64StrictFiniteInDebug::try_new(3.0).unwrap();
3530
3531            let pos = PositiveRealScalar::try_new(pos_inner).unwrap();
3532            let non_neg = NonNegativeRealScalar::try_new(non_neg_inner).unwrap();
3533
3534            let result: PositiveRealScalar<RealNative64StrictFiniteInDebug> = pos + non_neg;
3535            assert_eq!(*result.as_ref().as_ref(), 5.0);
3536        }
3537    }
3538}