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.