diff --git a/tests/correlators_test.py b/tests/correlators_test.py index cd629275..9df114d6 100644 --- a/tests/correlators_test.py +++ b/tests/correlators_test.py @@ -804,3 +804,18 @@ def test_prune_with_Nones(): for t in range(T): assert np.all(pruned_then_padded.content[t] == padded_then_pruned.content[t]) + + +def test_Corr_padding_default_not_shared(): + data = [pe.pseudo_Obs(i + 1, 0.1, "e") for i in range(5)] + c1 = pe.Corr(data) + c2 = pe.Corr(data) + assert c1 is not c2 + assert len(c1.content) == len(c2.content) == 5 + assert all(a[0] == b[0] for a, b in zip(c1.content, c2.content)) + + +def test_Corr_unhashable(): + c = pe.Corr([pe.pseudo_Obs(i + 1, 0.1, "e") for i in range(5)]) + with pytest.raises(TypeError): + hash(c) diff --git a/tests/integrate_test.py b/tests/integrate_test.py index 07a4313b..5bfe1260 100644 --- a/tests/integrate_test.py +++ b/tests/integrate_test.py @@ -49,3 +49,24 @@ def test_integration(): assert r1 == -r2 iamzero, _ = pe.integrate.quad(F, pobs, 1, 1) assert iamzero == 0 + + +def test_integrate_per_parameter_derivatives(): + # \int_0^1 p0*x + p1*x^2 dx = p0/2 + p1/3 + # If the lambda closure in integrate.quad failed to bind `i` per-iteration, + # all per-parameter derivatives would collapse to a single value. + def f(p, x): + return p[0] * x + p[1] * x ** 2 + + p = [pe.cov_Obs(1.0, 0.1 ** 2, "p0"), pe.cov_Obs(2.0, 0.2 ** 2, "p1")] + res, _ = pe.integrate.quad(f, p, 0.0, 1.0) + res.gm() + + ana_val = p[0].value / 2 + p[1].value / 3 + assert np.isclose(res.value, ana_val) + + grad0 = res.covobs["p0"].grad.item() + grad1 = res.covobs["p1"].grad.item() + assert np.isclose(grad0, 0.5) + assert np.isclose(grad1, 1.0 / 3.0) + assert not np.isclose(grad0, grad1) diff --git a/tests/misc_test.py b/tests/misc_test.py index 99bb5056..028ea6da 100644 --- a/tests/misc_test.py +++ b/tests/misc_test.py @@ -22,3 +22,18 @@ def test_obs_errorbar(): def test_print_config(): pe.print_config() + + +def test_pseudo_Obs_seed_independence(): + # pseudo_Obs now uses a module-local np.random.default_rng() generator, + # so np.random.seed() no longer controls its output. The per-sample + # deltas therefore differ between successive calls even with a re-seed, + # though the normalized value / dvalue still match the requested inputs. + np.random.seed(0) + a = pe.pseudo_Obs(1.0, 0.1, "e") + np.random.seed(0) + b = pe.pseudo_Obs(1.0, 0.1, "e") + + assert not np.allclose(a.deltas["e"], b.deltas["e"]) + assert np.isclose(a.value, b.value) + assert np.isclose(a.dvalue, b.dvalue) diff --git a/tests/obs_test.py b/tests/obs_test.py index a6cee885..3a9eb0a8 100644 --- a/tests/obs_test.py +++ b/tests/obs_test.py @@ -1211,6 +1211,33 @@ def test_hash(): assert hash(o1) != hash(o2) +def test_Obs_mismatched_lengths(): + with pytest.raises(ValueError): + pe.Obs([np.random.rand(100), np.random.rand(100)], ["a"]) + with pytest.raises(ValueError): + pe.Obs([np.random.rand(100)], ["a"], idl=[range(100), range(50)]) + with pytest.raises(ValueError): + pe.Obs([np.random.rand(100), np.random.rand(100)], ["a", "b"], + idl=[range(100)]) + + +def test_details_fractional_Nsigma(capsys): + # N_sigma only appears in details() output when tau_exp > 0. + # Verifies the format change from '%1.0i' (integer truncation) to + # f'{:g}' preserves fractional digits. + o = pe.pseudo_Obs(1.0, 0.1, "e") + o.gamma_method(tau_exp=1.5, N_sigma=1.5) + o.details() + out = capsys.readouterr().out + assert "N_\N{GREEK SMALL LETTER SIGMA}=1.5" in out + + +def test_CObs_unhashable(): + c = pe.CObs(pe.pseudo_Obs(1.0, 0.1, "e"), pe.pseudo_Obs(0.0, 0.1, "e")) + with pytest.raises(TypeError): + hash(c) + + def test_gm_alias(): samples = np.random.rand(500)