num-valid 0.6.0

A robust numerical library providing validated types for real and complex numbers to prevent common floating-point errors like NaN propagation. Features a generic, layered architecture with support for native f64 and optional arbitrary-precision arithmetic.
Documentation
# Native Validation Matrix

This note summarizes the current validation behavior of the native `f64` and `Complex<f64>` implementations used through `RealScalar` and `ComplexScalar`.

Scope:

- native `f64` paths wired through `RealScalar`
- native `Complex<f64>` paths wired through `ComplexScalar`
- related fallible `Pow` implementations for `f64` and `Complex<f64>`

It does not cover the validated wrapper types (`RealValidated<K>`, `ComplexValidated<K>`), whose behavior is stricter by design.

## Summary

The current native API is not uniform.

- Some entry points always validate in both debug and release.
- Some `try_*` methods now validate only in debug and return direct native results in release.
- Some panicking variants validate in debug but skip structured validation in release.
- Some mutating complex-part methods only use `debug_assert!`, so they validate only in debug builds.
- Many native mathematical delegates do no explicit validation at all and rely on the underlying `f64` or `Complex<f64>` behavior.

## `RealScalar` for `f64`

| Method or group | Impl location | Input validation in debug | Input validation in release | Output validation in debug | Output validation in release | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| `try_from_f64` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L471 | Yes | No | Yes, same validation path | No | In debug it uses `validate_native_scalar()` and rejects NaN/infinities/subnormals; in release it currently returns `Ok(value)` directly. |
| `from_f64` default trait method | [src/lib.rs]../../src/lib.rs#L1305 | Yes | No | Yes | No | Delegates to `try_from_f64(...).expect(...)`; for native `f64`, release behavior follows `try_from_f64` and can therefore accept invalid values. |
| `Abs::try_abs` and `Abs::try_abs_squared` for `f64` | [src/functions/abs.rs]../../src/functions/abs.rs#L200 | Yes | No | Yes | No | In debug they validate input/output via `validate_native_scalar()`; in release they return `Ok(...)` from direct numeric operations. |
| `Exp::try_exp` for `f64` | [src/functions/exponential.rs]../../src/functions/exponential.rs#L145 | Yes | No | Yes | No | In debug it validates input/output via `validate_native_scalar()`; in release it returns `Ok(f64::exp(value))`. |
| `Ln::try_ln`, `Log10::try_log10`, `Log2::try_log2` for `f64` | [src/functions/logarithm.rs]../../src/functions/logarithm.rs#L237 | Yes | No | Yes | No | In debug they validate input/output and enforce domain checks; in release they return direct backend results in `Ok(...)`. |
| Hyperbolic `try_*` for `f64` (`try_sinh`, `try_cosh`, `try_tanh`, `try_asinh`, `try_acosh`, `try_atanh`) | [src/functions/hyperbolic.rs]../../src/functions/hyperbolic.rs#L256 | Yes | No | Yes | No | In debug they validate and enforce domain checks where applicable; in release they return direct backend results in `Ok(...)`. |
| `Pow<&f64>::try_pow` | [src/functions/pow.rs]../../src/functions/pow.rs#L356 | Yes | Yes | Yes | Yes | Validates base and exponent, checks negative base domain, validates output via `validate_native_scalar()`. |
| `Pow<&f64>::pow` | [src/functions/pow.rs]../../src/functions/pow.rs#L394 | Yes | No structured validation | Yes via `try_pow().unwrap()` | No structured validation | In release it calls `powf` directly. |
| `Sign`, `Rounding`, `Clamp`, `Classify`, `ExpM1`, `Hypot`, `Ln1p`, `TotalCmp`, `Constants` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L160 | No explicit validation | No explicit validation | No explicit validation | No explicit validation | Direct delegation to native operations or constants. |
| `kernel_mul_add_mul_mut`, `kernel_mul_sub_mul_mut` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L450 | No explicit validation | No explicit validation | No explicit validation | No explicit validation | Pure arithmetic delegate. |

## `ComplexScalar` for `Complex<f64>`

| Method or group | Impl location | Input validation in debug | Input validation in release | Output validation in debug | Output validation in release | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| `try_new_complex` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L485 | Yes | Yes | Yes | Yes | Uses `validate_complex_from_parts`, therefore validates both parts through the strict-finite native real policy. |
| `Abs::try_abs` and `Abs::try_abs_squared` for `Complex<f64>` | [src/functions/abs.rs]../../src/functions/abs.rs#L320 | Yes | No | Yes | No | In debug they validate complex input and real output; in release they return `Ok(self.norm())` / `Ok(self.norm_sqr())` directly. |
| `Exp::try_exp` for `Complex<f64>` | [src/functions/exponential.rs]../../src/functions/exponential.rs#L242 | Yes | No | Yes | No | In debug it validates input/output via `validate_native_scalar()`; in release it returns `Ok(num::Complex::exp(value))`. |
| `Ln::try_ln`, `Log10::try_log10`, `Log2::try_log2` for `Complex<f64>` | [src/functions/logarithm.rs]../../src/functions/logarithm.rs#L295 | Yes | No | Yes | No | In debug they validate input/output and enforce zero-domain checks; in release they return direct backend results in `Ok(...)`. |
| Hyperbolic `try_*` for `Complex<f64>` (`try_sinh`, `try_cosh`, `try_tanh`, `try_asinh`, `try_acosh`, `try_atanh`) | [src/functions/hyperbolic.rs]../../src/functions/hyperbolic.rs#L256 | Yes | No | Yes | No | In debug they validate and enforce domain checks where applicable; in release they return direct backend results in `Ok(...)`. |
| `new_complex`, `new_pure_real`, `new_pure_imaginary` default trait methods | [src/functions/complex.rs]../../src/functions/complex.rs#L47 | Yes | Yes | Yes | Yes | They delegate to the fallible constructors and unwrap. |
| `set_real_part`, `set_imaginary_part` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L538 | Yes, via `debug_assert!` only | No | Yes, via `debug_assert!` on assigned value only | No | These are debug-only finiteness guards. |
| `add_to_real_part`, `add_to_imaginary_part` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L572 | No explicit input validation; debug-only post-check | No | Yes, via `debug_assert!` on resulting component | No | In release these operations can leave non-finite parts unchecked. |
| `multiply_real_part`, `multiply_imaginary_part` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L602 | No explicit input validation; debug-only post-check | No | Yes, via `debug_assert!` on resulting component | No | Same pattern as additive mutators. |
| `ComplexScalar::into_parts` | [src/backends/native/raw.rs]../../src/backends/native/raw.rs#L631 | No | No | No | No | Pure extraction. |
| `Pow<&f64>::try_pow` for `Complex<f64>` | [src/functions/pow.rs]../../src/functions/pow.rs#L413 | Yes | Yes | Yes | Yes | Validates base and exponent; validates output with `StrictFinitePolicy::<Complex<f64>, 53>::validate(...)`. |

## What The Documentation Says

### Statements that match the implementation

| Doc area | Location | Assessment |
| --- | --- | --- |
| `RealScalar` native backend description | [src/lib.rs]../../src/lib.rs#L1183 | Accurate at high level: it describes the native `f64` backend as direct delegation with maximum performance, which is consistent with many non-fallible native methods not validating explicitly. |
| `Pow` trait documentation | [src/functions/pow.rs]../../src/functions/pow.rs#L330 | Accurate: it explicitly says the panicking variant may validate in debug and may call the underlying power function directly in release. |
| `ComplexScalarConstructors::try_new_complex` docs | [src/functions/complex.rs]../../src/functions/complex.rs#L39 | Accurate: it states that invalid components return an error, which matches the implementation. |

### Statements that are too strong or incomplete

| Doc area | Location | Assessment |
| --- | --- | --- |
| `ComplexScalar` trait overview | [src/lib.rs]../../src/lib.rs#L1425 | Slightly too strong semantically: it describes a type-safe, validated context, but the native `Complex<f64>` mutators do not preserve strict runtime validation in release builds. |
| `ComplexScalarSetParts` docs | [src/functions/complex.rs]../../src/functions/complex.rs#L167 | Incomplete: it explains mutation semantics but does not say the native implementation only checks finiteness with `debug_assert!`. |
| `ComplexScalarMutateParts` docs | [src/functions/complex.rs]../../src/functions/complex.rs#L217 | Incomplete: it presents the operations as safe in-place utilities, but the native implementation performs only debug-only finiteness checks after mutation. |

## Practical Interpretation

Today the codebase effectively exposes two different behavioral classes for native scalars.

1. Validation behavior for native fallible APIs is mixed: `try_from_f64`, `try_abs*`, `try_exp`, logarithm `try_*`, and hyperbolic `try_*` are currently debug-only validated, while `try_pow` still validates in release.
2. Native direct delegates and complex-part mutators are performance-oriented APIs, with some checks downgraded to `debug_assert!`.

So the observed difformity is real, especially for `Complex<f64>` mutators and for the difference between `try_pow` and `pow`.