| import numpy as np |
| import pytest |
|
|
| from pino.genre_benchmark import audit_split, benchmark_split, composition_features, decide |
|
|
|
|
| def row(genre, *components): |
| return {"genre": genre, "formula": [{"cas": cas, "weight_fraction": weight} for cas, weight in components]} |
|
|
|
|
| def test_composition_features_ignore_identity_and_order(): |
| a = row("a", ("64-17-5", .8), ("x", .15), ("y", .05)) |
| b = row("b", ("z", .05), ("q", .15), ("64-17-5", .8)) |
| np.testing.assert_allclose(composition_features([a]), composition_features([b])) |
|
|
|
|
| def test_audit_rejects_shared_active_compounds(): |
| with pytest.raises(ValueError, match="shared compounds"): |
| audit_split([row("a", ("x", 1))], [row("b", ("x", 1))]) |
|
|
|
|
| def test_benchmark_and_negative_decision(): |
| train = [row("a", ("a1", .1)), row("a", ("a2", .12)), row("b", ("b1", .8)), row("b", ("b2", .82))] |
| test = [row("a", ("a3", .11)), row("a", ("a4", .13)), row("b", ("b3", .79)), row("b", ("b4", .81))] |
| learned_train = np.zeros((4, 2)) |
| learned_test = np.zeros((4, 2)) |
| result = benchmark_split(train, test, learned_train, learned_test, bootstrap_samples=200, seed=4) |
| assert result["baseline_accuracy"] == 1.0 |
| assert decide([result], minimum_splits=1)["decision"] == "negative_result" |
|
|
|
|
| def test_decision_requires_every_leakage_free_split_to_clear_ci(): |
| good = {"leakage_audit": {"passed": True}, "paired_advantage": {"ci95_low": .01}} |
| weak = {"leakage_audit": {"passed": True}, "paired_advantage": {"ci95_low": 0.0}} |
| assert decide([good, good, good])["decision"] == "learned_representation_supported" |
| assert decide([good, good, weak])["decision"] == "negative_result" |
|
|