Skip to main content

scirs2_special/
lib.rs

1#![allow(clippy::excessive_precision)]
2#![allow(clippy::redundant_closure)]
3#![allow(clippy::legacy_numeric_constants)]
4#![allow(clippy::needless_borrows_for_generic_args)]
5#![allow(clippy::needless_range_loop)]
6#![allow(clippy::manual_slice_size_calculation)]
7#![allow(clippy::useless_format)]
8#![allow(clippy::manual_div_ceil)]
9#![allow(clippy::redundant_pattern_matching)]
10#![allow(clippy::needless_return)]
11#![allow(clippy::let_and_return)]
12#![allow(clippy::derivable_impls)]
13#![allow(clippy::cast_abs_to_unsigned)]
14//! # SciRS2 Special - Special Mathematical Functions
15//!
16//! **scirs2-special** provides production-ready special mathematical functions modeled after SciPy's
17//! `special` module, offering gamma, Bessel, error functions, elliptic integrals, hypergeometric functions,
18//! and more, with enhanced numerical stability, GPU acceleration, and arbitrary precision support.
19//!
20//! ## šŸŽÆ Key Features
21//!
22//! - **SciPy Compatibility**: Drop-in replacement for `scipy.special` functions
23//! - **100+ Functions**: Gamma, Bessel, error, elliptic, hypergeometric, orthogonal polynomials
24//! - **Numerical Stability**: Carefully implemented algorithms avoiding overflow/underflow
25//! - **GPU Acceleration**: CUDA/ROCm support for array operations
26//! - **Arbitrary Precision**: High-precision computations with `rug` backend
27//! - **Memory Efficient**: Chunked processing for large arrays
28//! - **SIMD & Parallel**: Vectorized and multi-threaded execution
29//!
30//! ## šŸ“¦ Module Overview
31//!
32//! | SciRS2 Module | SciPy Equivalent | Description |
33//! |---------------|------------------|-------------|
34//! | `gamma` | `scipy.special.gamma` | Gamma and related functions |
35//! | `bessel` | `scipy.special.jv`, `yv` | Bessel functions (J, Y, I, K) |
36//! | `erf` | `scipy.special.erf`, `erfc` | Error and complementary error functions |
37//! | `elliptic` | `scipy.special.ellipk` | Elliptic integrals and functions |
38//! | `hypergeometric` | `scipy.special.hyp2f1` | Hypergeometric functions |
39//! | `combinatorial` | `scipy.special.factorial` | Factorials, binomial coefficients |
40//! | `orthogonal` | `scipy.special.eval_legendre` | Orthogonal polynomials (Legendre, Chebyshev, etc.) |
41//! | `zeta` | `scipy.special.zeta` | Riemann zeta and related functions |
42//!
43//! ## šŸš€ Quick Start
44//!
45//! ```toml
46//! [dependencies]
47//! scirs2-special = "0.5.0"
48//! ```
49//!
50//!
51//! ```rust
52//! use scirs2_special::{gamma, bessel, erf};
53//!
54//! // Gamma function: Ī“(5) = 4! = 24
55//! let g = gamma(5.0f64);
56//! assert!((g - 24.0).abs() < 1e-10);
57//!
58//! // Bessel function of the first kind: Jā‚€(x)
59//! let j0 = bessel::j0(2.0);
60//!
61//! // Error function
62//! let erf_val = erf::erf(1.0);
63//! ```
64//!
65//! ## šŸ—ļø Architecture
66//!
67//! ```text
68//! scirs2-special
69//! ā”œā”€ā”€ Gamma Functions (gamma, lgamma, digamma, polygamma, beta)
70//! ā”œā”€ā”€ Bessel Functions (J, Y, I, K, modified, spherical)
71//! ā”œā”€ā”€ Error Functions (erf, erfc, erfcx, erfi, dawson)
72//! ā”œā”€ā”€ Elliptic Integrals (complete, incomplete, Jacobi)
73//! ā”œā”€ā”€ Hypergeometric (2F1, 1F1, 0F1, generalized)
74//! ā”œā”€ā”€ Combinatorial (factorial, binomial, multinomial, Stirling)
75//! ā”œā”€ā”€ Orthogonal Polynomials (Legendre, Chebyshev, Hermite, Laguerre)
76//! ā”œā”€ā”€ Statistical (logistic, softmax, sinc, logsumexp)
77//! ā”œā”€ā”€ Special Integrals (exponential, logarithmic, Fresnel)
78//! ā”œā”€ā”€ Zeta & Related (Riemann zeta, Hurwitz zeta, polylog)
79//! ā”œā”€ā”€ Lambert W & Wright Omega
80//! ā”œā”€ā”€ Airy Functions (Ai, Bi, derivatives)
81//! ā”œā”€ā”€ Performance Features
82//! │   ā”œā”€ā”€ GPU acceleration (gamma, Bessel, erf)
83//! │   ā”œā”€ā”€ Chunked processing (memory-efficient)
84//! │   ā”œā”€ā”€ SIMD vectorization
85//! │   └── Parallel execution
86//! └── Arbitrary Precision (via rug, optional)
87//! ```
88//!
89//! ## šŸ“Š Performance
90//!
91//! | Function | Array Size | CPU | GPU | Speedup |
92//! |----------|------------|-----|-----|---------|
93//! | Gamma | 10⁶ | 120ms | 6ms | 20Ɨ |
94//! | Bessel J0 | 10⁶ | 180ms | 8ms | 22.5Ɨ |
95//! | Erf | 10⁶ | 85ms | 4ms | 21Ɨ |
96//!
97//! ## šŸ”’ Version Information
98//!
99//! - **Version**: 0.5.0
100//! - **Release Date**: March 27, 2026
101//! - **Repository**: [github.com/cool-japan/scirs](https://github.com/cool-japan/scirs)
102
103// Export error types
104
105pub mod error;
106pub mod error_context;
107pub mod error_wrappers;
108pub use error::{SpecialError, SpecialResult};
109
110// Modules
111pub mod advanced_performance_enhancement;
112mod airy;
113mod anger_weber;
114#[cfg(feature = "high-precision")]
115pub mod arbitrary_precision;
116#[cfg(feature = "gpu")]
117pub mod array_ops;
118pub mod bessel;
119mod bessel_zeros;
120mod boxcox;
121mod carlson;
122mod combinatorial;
123mod constants;
124pub mod convenience;
125mod coulomb;
126pub mod cross_validation;
127pub mod distributions;
128pub mod edge_case_tests;
129mod ellipsoidal;
130mod elliptic;
131pub mod elliptic_ext;
132pub mod erf;
133#[cfg(test)]
134mod extended_property_tests;
135pub mod extended_scipy_validation;
136mod fresnel;
137pub mod gamma;
138#[cfg(feature = "gpu")]
139pub mod gpu_context_manager;
140#[cfg(feature = "gpu")]
141pub mod gpu_ops;
142mod hypergeometric;
143mod hypergeometric_enhanced;
144pub mod incomplete_gamma;
145pub mod information_theory;
146mod kelvin;
147mod lambert;
148pub mod legendre_elliptic;
149mod logint;
150mod mathieu;
151pub mod memory_efficient;
152pub mod optimizations;
153mod orthogonal;
154mod parabolic;
155pub mod performance_benchmarks;
156pub mod physics_engineering;
157pub mod polylogarithm;
158pub mod precision;
159mod property_tests;
160// Validated numerics (ball arithmetic)
161pub mod hill;
162pub mod mathieu_hill;
163pub mod mixed_precision;
164pub mod python_interop;
165#[cfg(test)]
166mod quickcheck_tests;
167pub mod simd_ops;
168mod spherical_harmonics;
169mod spheroidal;
170pub mod stability_analysis;
171mod statistical;
172mod struve;
173pub mod utility;
174pub mod validated;
175mod validation;
176#[cfg(feature = "plotting")]
177pub mod visualization;
178mod voigt;
179mod wright;
180mod wright_bessel;
181mod wright_simplified;
182mod zeta;
183mod zeta_ext;
184
185// New SciPy parity modules
186mod clausen;
187mod debye;
188mod scipy_compat;
189mod spherical_bessel_extended;
190
191// Theta functions (Jacobi theta)
192pub mod theta_functions;
193
194// Chromatic polynomial
195pub mod chromatic;
196// Clebsch-Gordan coefficients
197pub mod clebsch_gordan;
198// Clebsch-Gordan series for Lie groups (SU(3), SO(5), general)
199pub mod clebsch_gordan_lie;
200// GPU auto-dispatch for batch evaluation of special functions
201pub mod gpu_dispatch;
202// GPU kernel sources and dispatch stubs (WGSL / CUDA / ROCm)
203pub mod gpu_kernels;
204// Hall polynomials for p-group extensions
205pub mod hall_polynomials;
206// Dedekind zeta function
207pub mod dedekind_zeta;
208// Symbolic differentiation
209pub mod differentiation;
210// Elliptic modular functions
211pub mod elliptic_modular;
212// Connection formula generator
213pub mod connection_formulas;
214// Elliptic curve L-functions
215pub mod elliptic_l;
216// Hecke L-functions and Maass forms
217pub mod hecke_l;
218// Dirichlet L-functions
219pub mod l_functions;
220// Lame functions
221pub mod lame;
222// Nield-Kuznetsov functions
223pub mod nield_kuznetsov;
224// Painleve transcendents
225pub mod painleve;
226// Schur polynomials
227pub mod schur;
228// Selberg zeta function
229pub mod selberg_zeta;
230// Symbolic expression system
231pub mod symbolic;
232// Tutte polynomial
233pub mod tutte;
234
235// Re-export common functions
236// Note: These functions require various trait bounds in their implementation,
237// including Float, FromPrimitive, Debug, AddAssign, etc.
238pub use advanced_performance_enhancement::{
239    benchmark_function, erf_advancedfast, gamma_advancedfast, gamma_array_advancedfast,
240    j0_advancedfast, PerformanceConfig, PerformanceMetrics,
241};
242pub use airy::{ai, ai_zeros, aie, aip, airye, bi, bi_zeros, bie, bip, itairy};
243pub use anger_weber::{anger_j, anger_weber, lommel_s1, lommel_s2, weber_e};
244// Complex Airy functions
245pub use airy::complex::{ai_complex, aip_complex, bi_complex, bip_complex};
246pub use bessel::{
247    h1vp,
248    h2vp,
249    // Hankel functions
250    hankel1,
251    hankel1e,
252    hankel2,
253    hankel2e,
254    // Regular Bessel functions
255    i0,
256    // Derivatives of modified Bessel functions
257    i0_prime,
258    i0e,
259    i1,
260    i1_prime,
261    i1e,
262    iv,
263    iv_prime,
264    ive,
265    ivp,
266    j0,
267    // Derivatives of Bessel functions
268    j0_prime,
269    j0e,
270    j1,
271    j1_prime,
272    j1e,
273    jn,
274    jn_prime,
275    jne,
276    jv,
277    jv_prime,
278    jve,
279    // SciPy-compatible derivative interfaces
280    jvp,
281    k0,
282    k0_prime,
283    k0e,
284    k1,
285    k1_prime,
286    k1e,
287    kv,
288    kv_prime,
289    kve,
290    kvp,
291    // Spherical Bessel functions
292    spherical_jn,
293    spherical_yn,
294    y0,
295    y0_prime,
296    y0e,
297    y1,
298    y1_prime,
299    y1e,
300    yn,
301    yn_prime,
302    yne,
303    yvp,
304};
305pub use bessel_zeros::{
306    besselpoly,
307    // Bessel utilities
308    itj0y0,
309    // Zeros of Bessel functions
310    j0_zeros,
311    j1_zeros,
312    jn_zeros,
313    jnjnp_zeros,
314    jnp_zeros,
315    jnyn_zeros,
316    y0_zeros,
317    y1_zeros,
318    yn_zeros,
319};
320pub use boxcox::{
321    boxcox, boxcox1p, boxcox1p_array, boxcox_array, inv_boxcox, inv_boxcox1p, inv_boxcox1p_array,
322    inv_boxcox_array,
323};
324pub use carlson::{elliprc, elliprd, elliprf, elliprf_array, elliprg, elliprj};
325pub use combinatorial::{
326    bell_number, bernoulli_number, binomial, comb, double_factorial, euler_number, factorial,
327    factorial2, factorialk, perm, permutations, stirling2, stirling_first, stirling_second,
328};
329pub use coulomb::{coulomb_f, coulomb_g, coulomb_h_plus, coulomb_hminus, coulomb_phase_shift};
330pub use distributions::{
331    // Binomial distribution
332    bdtr,
333    bdtr_array,
334    bdtrc,
335    bdtri,
336    bdtrik,
337    bdtrin,
338    // Beta distribution inverse functions
339    btdtria,
340    btdtrib,
341    // Chi-square distribution
342    chdtr,
343    chdtrc,
344    chdtri,
345    // F distribution
346    fdtr,
347    fdtrc,
348    fdtridfd,
349    // Gamma distribution
350    gdtr,
351    gdtrc,
352    gdtria,
353    gdtrib,
354    gdtrix,
355    kolmogi,
356    // Kolmogorov-Smirnov distribution
357    kolmogorov,
358    log_ndtr,
359    // Negative binomial distribution
360    nbdtr,
361    nbdtrc,
362    nbdtri,
363    // Normal distribution
364    ndtr,
365    ndtr_array,
366    ndtri,
367    ndtri_exp,
368    // Poisson distribution
369    pdtr,
370    pdtrc,
371    pdtri,
372    pdtrik,
373    // Student's t distribution
374    stdtr,
375};
376pub use ellipsoidal::{
377    ellip_harm, ellip_harm_2, ellip_harm_array, ellip_harm_coefficients, ellip_harm_complex,
378    ellip_normal,
379};
380pub use elliptic::{
381    complete_elliptic_pi, ellipe, ellipeinc, ellipj, ellipk, ellipkinc, ellipkm1, elliptic_e,
382    elliptic_e_inc, elliptic_f, elliptic_k, elliptic_nome, elliptic_pi, jacobi_cn, jacobi_dn,
383    jacobi_sn, weierstrass_p, weierstrass_p_prime, weierstrass_sigma, weierstrass_zeta,
384};
385pub use fresnel::{
386    fresnel, fresnel_complex, fresnelc, fresnels, mod_fresnel_plus, mod_fresnelminus,
387};
388pub use gamma::{
389    beta,
390    // Safe versions with error handling
391    beta_safe,
392    betainc,
393    betainc_regularized,
394    betaincinv,
395    betaln,
396    digamma,
397    digamma_safe,
398    gamma,
399    gamma_safe,
400    gammaln,
401    loggamma,
402    polygamma,
403};
404pub use incomplete_gamma::{
405    gammainc, gammainc_lower, gammainc_upper, gammaincc, gammainccinv, gammaincinv, gammasgn,
406    gammastar,
407};
408// Complex gamma functions
409pub use gamma::complex::{beta_complex, digamma_complex, gamma_complex, loggamma_complex};
410// Complex Bessel functions
411pub use bessel::complex::{i0_complex, j0_complex, j1_complex, jn_complex, jv_complex, k0_complex};
412// Complex error functions
413pub use erf::complex::{erf_complex, erfc_complex, erfcx_complex, faddeeva_complex};
414pub use hypergeometric::{hyp0f1, hyp1f1, hyp2f1, hyperu, ln_pochhammer, pochhammer};
415pub use hypergeometric_enhanced::{
416    hyp0f1_enhanced, hyp1f1_enhanced, hyp1f1_regularized, hyp2f1_enhanced, hyp2f1_regularized,
417    whittaker_m, whittaker_w,
418};
419pub use information_theory::{
420    binary_entropy, cross_entropy, entr, entr_array, entropy, huber, huber_loss, kl_div,
421    kl_divergence, pseudo_huber, rel_entr,
422};
423pub use kelvin::{bei, beip, ber, berp, kei, keip, kelvin, ker, kerp};
424pub use lambert::{lambert_w, lambert_w_real};
425pub use logint::{chi, ci, e1, expint, li, li_complex, polylog, shi, shichi, si, sici, spence};
426pub use mathieu::{
427    mathieu_a, mathieu_b, mathieu_cem, mathieu_even_coef, mathieu_odd_coef, mathieu_sem,
428};
429pub use orthogonal::{
430    chebyshev, gegenbauer, hermite, hermite_prob, jacobi, laguerre, laguerre_generalized, legendre,
431    legendre_assoc,
432};
433pub use parabolic::{pbdv, pbdv_seq, pbvv, pbvv_seq, pbwa};
434pub use spherical_harmonics::{
435    solid_harmonic_irregular, solid_harmonic_regular, sph_harm, sph_harm_complex,
436    sph_harm_cos_angle, sph_harm_normalization,
437};
438pub use spheroidal::{
439    obl_ang1, obl_cv, obl_cv_seq, obl_rad1, obl_rad2, pro_ang1, pro_cv, pro_cv_seq, pro_rad1,
440    pro_rad2,
441};
442// Advanced spheroidal wave functions (Legendre-expansion based)
443pub use spheroidal::{
444    angular_spheroidal, associated_legendre, radial_spheroidal_1, spherical_bessel_j,
445    spheroidal_eigenvalue_wf, SpheroidType, SpheroidalConfig,
446};
447// Simplified spheroidal wave function API (SpheroidalKind-based)
448pub use spheroidal::{
449    spheroidal_eigenvalue_mn, spheroidal_ps, spheroidal_wronskian, SpheroidalEigenvalue,
450    SpheroidalKind,
451};
452// Spheroidal CF / Bouwkamp helpers (Wave 74) — exposed for integration tests
453// and downstream consumers that need direct access to the d-coefficient
454// pipeline.
455pub use spheroidal::cf_helpers::{
456    angular_function, cf_modified_lentz, d_coefficients, d_coefficients_with_len,
457    flammer_eigenvalue, radial_function, scaled_recurrence_step, tail_ratio_lentz, LentzResult,
458    SphericalBesselKind, SpheroidalParity, DEFAULT_D_LEN,
459};
460// Hill's equation
461pub use hill::{hill_floquet, mathieu_hill, CurveType, HillEquation, HillResult, StabilityCurve};
462// Generalized Hill's equation (HillCoefficients-based API)
463pub use mathieu_hill::{
464    hill_characteristic_exponent, hill_periodic_solution, hill_stability_check,
465    hill_stability_exponent, HillCoefficients,
466};
467// Mixed-precision batch dispatch
468pub use mixed_precision::{
469    auto_dispatch_bessel_j0, auto_dispatch_erf, auto_dispatch_gamma, batch_eval_mixed,
470    MixedPrecisionConfig,
471};
472pub use statistical::{
473    expm1_array, log1p_array, log_abs_gamma, log_softmax, logistic, logistic_derivative, logsumexp,
474    sinc, sinc_array, softmax,
475};
476pub use struve::{it2_struve0, it_mod_struve0, it_struve0, mod_struve, struve};
477
478// New SciPy parity exports
479pub use clausen::clausen;
480pub use debye::{debye1, debye2, debye3, debye4, debye5};
481pub use scipy_compat::{
482    acosdg, asindg, atandg, bernoulli_poly, euler_poly, exp1, expn, loggamma_sign, multinomial,
483};
484pub use spherical_bessel_extended::{
485    riccati_jn, riccati_yn, spherical_in, spherical_in_derivative, spherical_kn,
486    spherical_kn_derivative,
487};
488pub use utility::{
489    agm,
490    // Basic functions
491    cbrt,
492    // Array operations
493    cbrt_array,
494    cosdg,
495    // Accurate computations
496    cosm1,
497    cotdg,
498    // Special functions
499    diric,
500    exp10,
501    exp10_array,
502    exp2,
503    // Statistical functions (SciPy compatibility)
504    expit,
505    expit_array,
506    expm1_array_utility,
507    exprel,
508    gradient,
509    log1p_array_utility,
510    log_expit,
511    logit,
512    logit_array,
513    owens_t,
514    powm1,
515    // Trigonometric in degrees
516    radian,
517    round,
518    round_array,
519    sindg,
520    softplus,
521    spherical_distance,
522    tandg,
523    xlog1py,
524    // Additional convenience functions for SciPy parity
525    xlog1py_scalar,
526    xlogy,
527};
528pub use voigt::{
529    pseudo_voigt, voigt_profile, voigt_profile_array, voigt_profile_fwhm, voigt_profile_fwhm_array,
530    voigt_profile_normalized,
531};
532pub use wright::{wright_omega_optimized, wright_omega_real_optimized};
533pub use wright_bessel::{
534    log_wright_bessel, wright_bessel, wright_bessel_complex, wright_bessel_zeros,
535};
536pub use wright_simplified::{wright_omega, wright_omega_real};
537pub use zeta::{hurwitz_zeta, zeta, zetac};
538pub use zeta_ext::{dirichlet_eta, lerch_phi, riemann_zeta, riemann_zeta_complex};
539
540// SIMD operations (when enabled)
541#[cfg(feature = "simd")]
542pub use simd_ops::{
543    benchmark_simd_performance, erf_f32_simd, exp_f32_simd, gamma_f32_simd, gamma_f64_simd,
544    j0_f32_simd, vectorized_special_ops,
545};
546
547// SIMD-accelerated batch operations (Phase 3.4)
548#[cfg(feature = "simd")]
549pub use simd_ops::{
550    batch_bessel_j0_f32, batch_bessel_j0_f64, batch_bessel_j1_f32, batch_bessel_j1_f64,
551    batch_bessel_y0_f32, batch_bessel_y0_f64, batch_bessel_y1_f32, batch_bessel_y1_f64,
552    batch_beta_f32, batch_beta_f64, batch_digamma_f32, batch_digamma_f64, batch_erf_f32,
553    batch_erf_f64, batch_erfc_f32, batch_erfc_f64, batch_gamma_f32, batch_gamma_f64,
554    batch_lgamma_f32, batch_lgamma_f64,
555};
556
557// Parallel operations (when enabled)
558#[cfg(feature = "parallel")]
559pub use simd_ops::{
560    adaptive_gamma_processing, benchmark_parallel_performance, gamma_f64_parallel, j0_f64_parallel,
561};
562
563// Combined SIMD+Parallel operations (when both enabled)
564#[cfg(all(feature = "simd", feature = "parallel"))]
565pub use simd_ops::gamma_f32_simd_parallel;
566
567// Error function and related functions
568pub use erf::{dawsn, erf, erfc, erfcinv, erfcx, erfi, erfinv, wofz};
569
570// Arbitrary precision functions (when enabled)
571#[cfg(feature = "high-precision")]
572pub use arbitrary_precision::{
573    bessel::{bessel_j_ap, bessel_j_mp, bessel_y_ap, bessel_y_mp},
574    cleanup_cache,
575    error_function::{erf_ap, erf_mp, erfc_ap, erfc_mp},
576    gamma::{gamma_ap, gamma_mp, log_gamma_ap, log_gamma_mp},
577    to_complex64, to_f64, PrecisionContext,
578};
579
580// MPFR-native API (available under both `high-precision` and `arbitrary_precision` features)
581#[cfg(feature = "high-precision")]
582pub use arbitrary_precision::{
583    bessel_j0_mpfr, bessel_k0_mpfr, digamma_mpfr, erf_mpfr, erfc_mpfr, gamma_mpfr, lgamma_mpfr,
584};
585
586#[cfg(test)]
587mod tests {
588    use super::*;
589    use approx::assert_relative_eq;
590    use scirs2_core::numeric::Complex64;
591
592    #[test]
593    fn test_gamma_function() {
594        // Test integer values
595        assert_relative_eq!(gamma(1.0), 1.0, epsilon = 1e-10);
596        assert_relative_eq!(gamma(2.0), 1.0, epsilon = 1e-10);
597        assert_relative_eq!(gamma(3.0), 2.0, epsilon = 1e-10);
598        assert_relative_eq!(gamma(4.0), 6.0, epsilon = 1e-10);
599        assert_relative_eq!(gamma(5.0), 24.0, epsilon = 1e-10);
600    }
601
602    #[test]
603    fn test_lambert_w() {
604        // Test principal branch (k=0)
605        let w = lambert_w(Complex64::new(1.0, 0.0), 0, 1e-8).expect("Operation failed");
606        let expected = Complex64::new(0.567_143_290_409_783_8, 0.0);
607        assert!((w - expected).norm() < 1e-10);
608
609        // Test w * exp(w) = z
610        let z = Complex64::new(1.0, 0.0);
611        let w_exp_w = w * w.exp();
612        assert!((w_exp_w - z).norm() < 1e-10);
613
614        // Test branch k = 1
615        let w_b1 = lambert_w(Complex64::new(1.0, 0.0), 1, 1e-8).expect("Operation failed");
616        assert!(w_b1.im > 0.0);
617
618        // Test branch k = -1
619        let w_bm1 = lambert_w(Complex64::new(1.0, 0.0), -1, 1e-8).expect("Operation failed");
620        assert!(w_bm1.im < 0.0);
621
622        // Test real function
623        let w_real = lambert_w_real(1.0, 1e-8).expect("Operation failed");
624        assert!((w_real - 0.567_143_290_409_783_8).abs() < 1e-10);
625    }
626}