torchcell.metabolism.constraints.null_space_basis

null_space_basis(s: Tensor, tol: float = 1e-09, cache_path: str | None = None) → Tensor[source]

An orthonormal basis \(\mathcal{N}\) of \(\ker S\), so \(S\mathcal{N}=0\).

This is the other half of the exactness budget. A flux written as \(v=\mathcal{N}z\) satisfies mass balance identically, to machine precision, for any \(z\) – there is no residual and no loss weight. What it gives up is the box: an orthonormal basis does not preserve \(v^\ell\le v\le v^u\), so bounds and directionality revert to a penalty.

The two parameterizations therefore spend exactness on different constraints, and which is right is an empirical question rather than a matter of taste:

parameterization

\(Sv=0\)

box + directionality

box (sigmoid)

soft, one weight

exact

null space

exact

soft, one weight

On yeast-GEM 9.0.2 the basis is \(4131\times1538\), so the null-space head is 2.7x narrower than the per-reaction head, which is a real secondary benefit.

Computed by SVD rather than by a sparse method: the matrix is 2,806 x 4,131 and dense SVD takes seconds, whereas a sparse null-space routine would need a rank decision anyway. The result is cached because it depends only on S.