Skip to content

Commit 32ca057

Browse files
author
peng.li24
committed
Add [float64]/[float32] tags to all ULP report labels
Each test label now includes dtype suffix for full transparency: ✓ pdf batch=100 [float64]: 29/100 differ, max=2 ULP (tol=3) ✓ pdf batch=100 [float32]: 31/100 differ, max=2 ULP (tol=3) All 189 tests pass, 0 failures.
1 parent d16682d commit 32ca057

1 file changed

Lines changed: 40 additions & 36 deletions

File tree

tests/test_all.py

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313

1414
BATCH = 100
1515

16+
def _s(label, dtype=None):
17+
"""Append [f64] or [f32] to label for ULP report clarity."""
18+
return label if dtype is None else f"{label} [{np.dtype(dtype).name}]"
19+
1620
# ============================================================================
1721
# ULP computation & reporting
1822
# ============================================================================
@@ -149,16 +153,16 @@ def dtype(self, request): return request.param
149153

150154
def test_batch_default(self, cpp, dtype):
151155
a = random_batch((BATCH,), dtype=dtype, seed=1001)
152-
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), f"pdf batch={BATCH}")
156+
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), _s(f"pdf batch={BATCH}", dtype))
153157

154158
@pytest.mark.parametrize("v", [0.0, 1.0, -1.0, 2.0, -2.0, 3.0, -3.0, 5.0, -5.0])
155159
def test_canonical(self, cpp, dtype, v):
156160
a = np.array([v], dtype=dtype)
157-
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), f"pdf({v})")
161+
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), _s(f"pdf({v})", dtype))
158162

159163
def test_extreme(self, cpp, dtype):
160164
a = np.array([6.0, 8.0, 10.0, -6.0, -8.0, -10.0, 20.0, -20.0], dtype=dtype)
161-
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), "pdf extreme")
165+
assert_ulp_close(cpp.stats.norm.pdf(a), sp_norm.pdf(a), _s("pdf extreme", dtype))
162166

163167
@pytest.mark.parametrize("loc,scale", [
164168
(0.0,1.0),(1.0,1.0),(-2.0,1.0),(0.0,2.0),(0.0,0.5),(3.0,4.0),
@@ -168,14 +172,14 @@ def test_loc_scale(self, cpp, dtype, loc, scale):
168172
a = random_batch((BATCH,), dtype=dtype, seed=1002)
169173
assert_ulp_close(cpp.stats.norm.pdf(a, dtype(loc), dtype(scale)),
170174
sp_norm.pdf(a, loc=dtype(loc), scale=dtype(scale)),
171-
f"pdf(loc={loc},scale={scale})")
175+
_s(f"pdf(loc={loc},scale={scale})", dtype))
172176

173177
@pytest.mark.parametrize("loc,scale", [(-10.0,0.01), (10.0,0.01)])
174178
def test_tiny_scale(self, cpp, dtype, loc, scale):
175179
a = random_batch((BATCH,), dtype=dtype, seed=1003)
176180
assert_ulp_close(cpp.stats.norm.pdf(a, dtype(loc), dtype(scale)),
177181
sp_norm.pdf(a, loc=dtype(loc), scale=dtype(scale)),
178-
f"pdf(loc={loc},scale={scale})")
182+
_s(f"pdf(loc={loc},scale={scale})", dtype))
179183

180184

181185
class TestNormCdf:
@@ -184,12 +188,12 @@ def dtype(self, request): return request.param
184188

185189
def test_batch_default(self, cpp, dtype):
186190
a = random_batch((BATCH,), dtype=dtype, seed=1004)
187-
assert_bit_aligned(cpp.stats.norm.cdf(a), sp_norm.cdf(a), f"cdf batch={BATCH}")
191+
assert_bit_aligned(cpp.stats.norm.cdf(a), sp_norm.cdf(a), _s(f"cdf batch={BATCH}", dtype))
188192

189193
@pytest.mark.parametrize("v", [0.0, 1.0, -1.0, 2.0, -2.0, 3.0, -3.0])
190194
def test_canonical(self, cpp, dtype, v):
191195
a = np.array([v], dtype=dtype)
192-
assert_bit_aligned(cpp.stats.norm.cdf(a), sp_norm.cdf(a), f"cdf({v})")
196+
assert_bit_aligned(cpp.stats.norm.cdf(a), sp_norm.cdf(a), _s(f"cdf({v})", dtype))
193197

194198
@pytest.mark.parametrize("loc,scale", [
195199
(0.0,1.0),(1.0,1.0),(-2.0,1.0),(0.0,2.0),(0.0,0.5),(3.0,4.0),
@@ -198,7 +202,7 @@ def test_loc_scale(self, cpp, dtype, loc, scale):
198202
a = random_batch((BATCH,), dtype=dtype, seed=1005)
199203
assert_bit_aligned(cpp.stats.norm.cdf(a, dtype(loc), dtype(scale)),
200204
sp_norm.cdf(a, loc=dtype(loc), scale=dtype(scale)),
201-
f"cdf(loc={loc},scale={scale})")
205+
_s(f"cdf(loc={loc},scale={scale})", dtype))
202206

203207

204208
class TestNormPpf:
@@ -208,12 +212,12 @@ def dtype(self, request): return request.param
208212

209213
def test_batch_default(self, cpp, dtype):
210214
a = random_uniform((BATCH,), 0.001, 0.999, dtype=dtype, seed=1006)
211-
assert_bit_aligned(cpp.stats.norm.ppf(a), sp_norm.ppf(a), f"ppf batch={BATCH}")
215+
assert_bit_aligned(cpp.stats.norm.ppf(a), sp_norm.ppf(a), _s(f"ppf batch={BATCH}", dtype))
212216

213217
@pytest.mark.parametrize("p", [0.5, 0.025, 0.975, 0.001, 0.999])
214218
def test_canonical(self, cpp, dtype, p):
215219
a = np.array([p], dtype=dtype)
216-
assert_bit_aligned(cpp.stats.norm.ppf(a), sp_norm.ppf(a), f"ppf({p})")
220+
assert_bit_aligned(cpp.stats.norm.ppf(a), sp_norm.ppf(a), _s(f"ppf({p})", dtype))
217221

218222
@pytest.mark.parametrize("loc,scale", [
219223
(0.0,1.0),(1.0,1.0),(-2.0,1.0),(0.0,2.0),(0.0,0.5),
@@ -222,7 +226,7 @@ def test_loc_scale(self, cpp, dtype, loc, scale):
222226
a = random_uniform((BATCH,), 0.001, 0.999, dtype=dtype, seed=1007)
223227
assert_bit_aligned(cpp.stats.norm.ppf(a, dtype(loc), dtype(scale)),
224228
sp_norm.ppf(a, loc=dtype(loc), scale=dtype(scale)),
225-
f"ppf(loc={loc},scale={scale})")
229+
_s(f"ppf(loc={loc},scale={scale})", dtype))
226230

227231

228232
# ============================================================================
@@ -237,19 +241,19 @@ def test_trapezoid_batch(self, cpp, dtype):
237241
y = random_batch((BATCH,), dtype=dtype, seed=1008)
238242
assert_bit_aligned(
239243
np.float64(cpp.trapezoid(y)), np.float64(sp_integrate.trapezoid(y)),
240-
f"trapezoid batch={BATCH}")
244+
_s(f"trapezoid batch={BATCH}", dtype))
241245

242246
def test_simpson_batch(self, cpp, dtype):
243247
y = random_batch((101,), dtype=dtype, seed=1009)
244248
assert_bit_aligned(
245249
np.float64(cpp.simpson(y)), np.float64(sp_integrate.simpson(y)),
246-
f"simpson batch=101")
250+
_s(f"simpson batch=101", dtype))
247251

248252
def test_trapezoid_known(self, cpp, dtype):
249253
y = np.array([0.0, 1.0, 4.0, 9.0, 16.0], dtype=dtype)
250254
assert_bit_aligned(
251255
np.float64(cpp.trapezoid(y)), np.float64(sp_integrate.trapezoid(y)),
252-
"trapezoid known")
256+
_s("trapezoid known", dtype))
253257

254258
def test_simpson_known(self, cpp):
255259
y = np.array([0.0, 1.0, 4.0, 9.0, 16.0], dtype=np.float64)
@@ -302,14 +306,14 @@ def test_solve_2x2(self, cpp, dtype):
302306
b = np.array([5.0, 6.0], dtype=dtype)
303307
assert_bit_aligned(
304308
np.asarray(cpp.linalg.solve(A, b)), self._np_solve(A, b),
305-
"solve 2x2")
309+
_s("solve 2x2", dtype))
306310

307311
def test_solve_identity(self, cpp, dtype):
308312
A = np.eye(3, dtype=dtype)
309313
b = np.array([1.0, 2.0, 3.0], dtype=dtype)
310314
assert_bit_aligned(
311315
np.asarray(cpp.linalg.solve(A, b)), self._np_solve(A, b),
312-
"solve identity")
316+
_s("solve identity", dtype))
313317

314318
def test_solve_batch(self, cpp, dtype):
315319
"""100 random matrices (n=4..8) + random RHS vectors."""
@@ -319,7 +323,7 @@ def test_solve_batch(self, cpp, dtype):
319323
A = (rng.randn(n, n) * 2.0 + 3.0 * np.eye(n)).astype(dtype)
320324
b = rng.randn(n).astype(dtype)
321325
cpp_r = np.asarray(cpp.linalg.solve(A, b), dtype=np.float64)
322-
assert_linalg_close(cpp_r, self._np_solve(A, b), f"solve batch[{i}] n={n}")
326+
assert_linalg_close(cpp_r, self._np_solve(A, b), _s(f"solve batch[{i}] n={n}", dtype))
323327

324328
@pytest.mark.parametrize("n", [10, 20])
325329
def test_solve_large(self, cpp, dtype, n):
@@ -328,7 +332,7 @@ def test_solve_large(self, cpp, dtype, n):
328332
A = (rng.randn(n, n) * 1.5 + 4.0 * np.eye(n)).astype(dtype)
329333
b = rng.randn(n).astype(dtype)
330334
cpp_r = np.asarray(cpp.linalg.solve(A, b), dtype=np.float64)
331-
assert_linalg_close(cpp_r, self._np_solve(A, b), f"solve large n={n}")
335+
assert_linalg_close(cpp_r, self._np_solve(A, b), _s(f"solve large n={n}", dtype))
332336

333337
@pytest.mark.parametrize("seed", [5555, 6666, 7777])
334338
def test_solve_ill_conditioned(self, cpp, dtype, seed):
@@ -342,7 +346,7 @@ def test_solve_ill_conditioned(self, cpp, dtype, seed):
342346
b = rng.randn(n).astype(dtype)
343347
cpp_r = np.asarray(cpp.linalg.solve(A, b), dtype=np.float64)
344348
# For ill-conditioned matrices, relax tolerance (float32 promotion + LU)
345-
assert_linalg_close(cpp_r, self._np_solve(A, b), f"solve ill-cond seed={seed}", atol=1e-10)
349+
assert_linalg_close(cpp_r, self._np_solve(A, b), _s(f"solve ill-cond seed={seed}", dtype), atol=1e-10)
346350

347351

348352
# ============================================================================
@@ -360,15 +364,15 @@ def test_batch(self, cpp, dtype, metric):
360364
assert_bit_aligned(
361365
np.asarray(cpp.spatial.distance.cdist(XA, XB, metric)),
362366
sp_distance.cdist(XA, XB, metric),
363-
f"cdist {metric}")
367+
_s(f"cdist {metric}", dtype))
364368

365369
def test_small(self, cpp, dtype):
366370
XA = np.array([[0., 0.], [1., 1.]], dtype=dtype)
367371
XB = np.array([[0., 1.], [1., 0.], [2., 2.]], dtype=dtype)
368372
assert_bit_aligned(
369373
np.asarray(cpp.spatial.distance.cdist(XA, XB, "euclidean")),
370374
sp_distance.cdist(XA, XB, "euclidean"),
371-
"cdist small")
375+
_s("cdist small", dtype))
372376

373377

374378
# ============================================================================
@@ -390,15 +394,15 @@ def test_query_batch(self, cpp, dtype):
390394
q = random_batch((3,), dtype=dtype, seed=1016)
391395
d_cpp, i_cpp = self._tk(cpp, dtype)(pts).query(q, k=1)
392396
d_py, i_py = sp_cKDTree(pts).query(q, k=1)
393-
assert_bit_aligned(np.asarray(d_cpp), np.asarray(d_py), "KDTree dist")
397+
assert_bit_aligned(np.asarray(d_cpp), np.asarray(d_py), _s("KDTree dist", dtype))
394398
np.testing.assert_array_equal(np.asarray(i_cpp), np.asarray(i_py))
395399

396400
def test_query_k3_batch(self, cpp, dtype):
397401
pts = random_batch((BATCH, 3), dtype=dtype, seed=1017)
398402
q = random_batch((3,), dtype=dtype, seed=1018)
399403
d_cpp, i_cpp = self._tk(cpp, dtype)(pts).query(q, k=3)
400404
d_py, i_py = sp_cKDTree(pts).query(q, k=3)
401-
assert_bit_aligned(np.asarray(d_cpp), np.asarray(d_py), "KDTree k=3 dist")
405+
assert_bit_aligned(np.asarray(d_cpp), np.asarray(d_py), _s("KDTree k=3 dist", dtype))
402406
np.testing.assert_array_equal(np.asarray(i_cpp), np.asarray(i_py))
403407

404408

@@ -416,15 +420,15 @@ def test_batch(self, cpp, dtype, sigma):
416420
assert_bit_aligned(
417421
np.asarray(cpp.ndimage.gaussian_filter1d(a, sigma=sigma)),
418422
sp_ndimage.gaussian_filter1d(a, sigma=sigma),
419-
f"gaussian_filter1d sigma={sigma}")
423+
_s(f"gaussian_filter1d sigma={sigma}", dtype))
420424

421425
@pytest.mark.parametrize("mode", ["reflect", "constant", "nearest", "mirror", "wrap"])
422426
def test_modes(self, cpp, dtype, mode):
423427
a = random_batch((BATCH,), dtype=dtype, seed=1020)
424428
assert_bit_aligned(
425429
np.asarray(cpp.ndimage.gaussian_filter1d(a, sigma=1.5, mode=mode)),
426430
np.asarray(sp_ndimage.gaussian_filter1d(a, sigma=1.5, mode=mode), dtype=np.float64),
427-
f"gaussian_filter1d mode={mode}")
431+
_s(f"gaussian_filter1d mode={mode}", dtype))
428432

429433

430434
# ============================================================================
@@ -441,7 +445,7 @@ def test_batch(self, cpp, dtype, k):
441445
assert_bit_aligned(
442446
np.asarray(cpp.signal.medfilt(a, kernel_size=k), dtype=np.float64),
443447
np.asarray(sp_signal.medfilt(a, kernel_size=k), dtype=np.float64),
444-
f"medfilt k={k}")
448+
_s(f"medfilt k={k}", dtype))
445449

446450

447451
# ============================================================================
@@ -476,27 +480,27 @@ def _check(self, cpp, dtype, R, seq, label):
476480
# --- identity / canonical angles ---
477481

478482
def test_identity(self, cpp, dtype):
479-
self._check(cpp, dtype, np.eye(3, dtype=dtype), "xyz", "Rotation identity")
483+
self._check(cpp, dtype, np.eye(3, dtype=dtype), "xyz", _s("Rotation identity", dtype))
480484

481485
def test_x_rotation(self, cpp, dtype):
482486
R = sp_Rotation.from_euler("xyz", [np.pi/4, 0, 0]).as_matrix()
483-
self._check(cpp, dtype, R.astype(dtype), "xyz", "Rotation x-45deg")
487+
self._check(cpp, dtype, R.astype(dtype), "xyz", _s("Rotation x-45deg", dtype))
484488

485489
def test_y_rotation(self, cpp, dtype):
486490
R = sp_Rotation.from_euler("xyz", [0, np.pi/6, 0]).as_matrix()
487-
self._check(cpp, dtype, R.astype(dtype), "xyz", "Rotation y-30deg")
491+
self._check(cpp, dtype, R.astype(dtype), "xyz", _s("Rotation y-30deg", dtype))
488492

489493
def test_z_rotation(self, cpp, dtype):
490494
R = sp_Rotation.from_euler("xyz", [0, 0, np.pi/3]).as_matrix()
491-
self._check(cpp, dtype, R.astype(dtype), "xyz", "Rotation z-60deg")
495+
self._check(cpp, dtype, R.astype(dtype), "xyz", _s("Rotation z-60deg", dtype))
492496

493497
def test_xyz_sequence(self, cpp, dtype):
494498
R = sp_Rotation.from_euler("xyz", np.deg2rad([20., 30., 45.])).as_matrix()
495-
self._check(cpp, dtype, R.astype(dtype), "xyz", "Rotation xyz(20,30,45)")
499+
self._check(cpp, dtype, R.astype(dtype), "xyz", _s("Rotation xyz(20,30,45)", dtype))
496500

497501
def test_zyx_sequence(self, cpp, dtype):
498502
R = sp_Rotation.from_euler("zyx", np.deg2rad([10., -20., 40.])).as_matrix()
499-
self._check(cpp, dtype, R.astype(dtype), "zyx", "Rotation zyx(10,-20,40)")
503+
self._check(cpp, dtype, R.astype(dtype), "zyx", _s("Rotation zyx(10,-20,40)", dtype))
500504

501505
# --- 100 random batches for each Tait-Bryan sequence (§5 requirement) ---
502506

@@ -510,7 +514,7 @@ def test_random_batch(self, cpp, dtype, seq):
510514
for i in range(BATCH):
511515
a = rng.uniform(-np.pi/2 + 0.1, np.pi/2 - 0.1, 3)
512516
R = sp_Rotation.from_euler(seq, a).as_matrix().astype(dtype)
513-
self._check(cpp, dtype, R, seq, f"Rotation {seq} random[{i}]")
517+
self._check(cpp, dtype, R, seq, _s(f"Rotation {seq} random[{i}]", dtype))
514518

515519
# --- gimbal lock boundary tests ---
516520

@@ -524,7 +528,7 @@ def test_gimbal_lock_near(self, cpp, dtype, beta):
524528
alpha = rng.uniform(-np.pi, np.pi)
525529
gamma = rng.uniform(-np.pi, np.pi)
526530
R = sp_Rotation.from_euler("xyz", [alpha, beta, gamma]).as_matrix().astype(dtype)
527-
self._check(cpp, dtype, R, "xyz", f"Rotation gimbal beta={beta:.4f}[{i}]")
531+
self._check(cpp, dtype, R, "xyz", _s(f"Rotation gimbal beta={beta:.4f}[{i}]", dtype))
528532

529533
# --- random rotation matrix test ---
530534

@@ -534,7 +538,7 @@ def test_random_matrices(self, cpp, dtype):
534538
rng = np.random.RandomState(31415)
535539
for i in range(BATCH):
536540
R = sp_Rotation.random(random_state=rng).as_matrix().astype(dtype)
537-
self._check(cpp, dtype, R, "xyz", f"Rotation random_matrix[{i}]")
541+
self._check(cpp, dtype, R, "xyz", _s(f"Rotation random_matrix[{i}]", dtype))
538542

539543
# --- intrinsic 'XYZ' sequence ---
540544

@@ -545,7 +549,7 @@ def test_XYZ_intrinsic(self, cpp, dtype):
545549
for i in range(BATCH):
546550
a = rng.uniform(-np.pi/2 + 0.1, np.pi/2 - 0.1, 3)
547551
R = sp_Rotation.from_euler("XYZ", a).as_matrix().astype(dtype)
548-
self._check(cpp, dtype, R, "XYZ", f"Rotation XYZ intrinsic[{i}]")
552+
self._check(cpp, dtype, R, "XYZ", _s(f"Rotation XYZ intrinsic[{i}]", dtype))
549553

550554

551555
if __name__ == "__main__":

0 commit comments

Comments
 (0)