1use crate::algebra::blas::{dot_conj, nrm2};
4use crate::algebra::prelude::*;
5
6pub const ATOL: R = 1e-12;
8pub const RTOL: R = 1e-10;
9
10#[inline]
12pub fn s(x: f64) -> S {
13 S::from_real(x)
14}
15
16#[inline]
18pub fn is_zero(z: S, eps: R) -> bool {
19 z.abs() < eps
20}
21
22#[inline]
24pub fn approx_s(a: S, b: S, atol: R, rtol: R) -> bool {
25 let diff = (a - b).abs();
26 let scale = a.abs().max(b.abs());
27 diff <= atol + rtol * scale
28}
29
30#[track_caller]
32pub fn assert_s_close(label: &str, a: S, b: S, atol: R, rtol: R) {
33 if !approx_s(a, b, atol, rtol) {
34 panic!(
35 "{label}: |a-b|={} (a={:?}, b={:?}) > atol+rtol*scale (atol={:.3e}, rtol={:.3e})",
36 (a - b).abs(),
37 a,
38 b,
39 atol,
40 rtol
41 );
42 }
43}
44
45#[inline]
47pub fn vec_err(a: &[S], b: &[S]) -> R {
48 let mut tmp = Vec::<S>::with_capacity(a.len());
49 unsafe {
50 tmp.set_len(a.len());
51 }
52 for i in 0..a.len() {
53 tmp[i] = a[i] - b[i];
54 }
55 nrm2(&tmp)
56}
57
58#[inline]
60pub fn vec_dot(a: &[S], b: &[S]) -> S {
61 dot_conj(a, b)
62}
63
64#[track_caller]
66pub fn assert_vec_close(label: &str, a: &[S], b: &[S], atol: R, rtol: R) {
67 assert_eq!(
68 a.len(),
69 b.len(),
70 "{label}: length mismatch {} != {}",
71 a.len(),
72 b.len()
73 );
74 let err = vec_err(a, b);
75 let na = nrm2(a);
76 let nb = nrm2(b);
77 let scale = na.max(nb);
78 if err > atol + rtol * scale {
79 panic!(
80 "{label}: ||a-b||2={:.3e} > {:.3e} (atol+rtol*max(||a||,||b||))",
81 err,
82 atol + rtol * scale
83 );
84 }
85}
86
87#[macro_export]
89macro_rules! assert_s_close {
90 ($label:expr, $a:expr, $b:expr) => {{
91 $crate::testkit::assert_s_close(
92 $label,
93 $a,
94 $b,
95 $crate::testkit::ATOL,
96 $crate::testkit::RTOL,
97 )
98 }};
99}
100
101#[macro_export]
103macro_rules! assert_vec_close {
104 ($label:expr, $a:expr, $b:expr) => {{
105 $crate::testkit::assert_vec_close(
106 $label,
107 $a,
108 $b,
109 $crate::testkit::ATOL,
110 $crate::testkit::RTOL,
111 )
112 }};
113}