File size: 2,822 Bytes
4c4d79d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | """Numerical tests for the TRACE method-specific components (no training data needed)."""
import sys
import unittest
from pathlib import Path
import numpy as np
from scipy.interpolate import PchipInterpolator
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from biochime_regulon_core import ( # noqa: E402
pchip_slopes, hermite_eval, project_shape_safe_slopes,
_match_bio_vector_norm, fit_ridge_map, permute_tf_channels,
)
class TestTRACECore(unittest.TestCase):
def test_pchip_matches_scipy(self):
rng = np.random.default_rng(17)
for k in (2, 3, 4):
x = np.cumsum(np.r_[0.0, rng.uniform(0.1, 0.7, k-1)])
y = rng.normal(size=(k, 15, 6))
m = pchip_slopes(x, y)
ref = PchipInterpolator(x, y, axis=0)
np.testing.assert_allclose(m, ref.derivative()(x), atol=1e-10)
t = rng.uniform(x[0], x[-1], len(y[0]))
pos, vel = hermite_eval(x, y, m, t)
np.testing.assert_allclose(pos, np.stack([ref(tt)[i] for i, tt in enumerate(t)]), atol=1e-10)
np.testing.assert_allclose(vel, np.stack([ref.derivative()(tt)[i] for i, tt in enumerate(t)]), atol=1e-10)
def test_projected_slope_preserves_monotone_intervals(self):
x = np.array([0.0, 0.4, 1.0])
z = np.array([[[0., 0.]], [[1., 2.]], [[2., 3.]]])
raw = np.array([[[20., 20.]], [[-50., 10.]], [[20., -15.]]])
m = project_shape_safe_slopes(x, z, raw)
for lo, hi in [(0., 0.4), (0.4, 1.0)]:
t = np.linspace(lo, hi, 29)
# evaluate one query time for one trajectory at a time
for tt in t:
pos, _ = hermite_eval(x, z, m, np.array([tt]))
self.assertTrue(np.all(pos[0] >= z[0, 0] - 1e-9))
self.assertTrue(np.all(pos[0] <= z[-1, 0] + 1e-9))
def test_ridge_activity_to_state_direction(self):
rng = np.random.default_rng(23)
a = rng.normal(size=(200, 7))
w = rng.normal(size=(7, 4))
b = rng.normal(size=4)
z = a @ w + b
fitted, intercept = fit_ridge_map(a, z, lam=0.0)
np.testing.assert_allclose(fitted, w, atol=1e-5)
np.testing.assert_allclose(intercept, b, atol=1e-5)
def test_norm_clipping_and_permutation(self):
m_geom = np.ones((3, 12, 5), dtype=float)
m_bio = np.ones_like(m_geom) * 100.0
matched = _match_bio_vector_norm(m_geom, m_bio)
np.testing.assert_allclose(matched, m_bio * 0.25)
a = {0.0: np.arange(18).reshape(6, 3), 1.0: np.arange(18).reshape(6, 3) + 1}
perm = permute_tf_channels(a, seed=4)
self.assertEqual(perm[0.0].shape, a[0.0].shape)
self.assertEqual(sorted(perm[0.0].T.tolist()), sorted(a[0.0].T.tolist()))
if __name__ == '__main__':
unittest.main()
|