torchcell.metabolism.constraints.independent_balance_rows

independent_balance_rows(s: Tensor, tol: float = 1e-09) → tuple[Tensor, int][source]

Pick a maximal set of linearly independent rows of S.

Rank-revealing QR with column pivoting on \(S^\top\): the pivot order returned by scipy.linalg.qr(..., pivoting=True) lists columns of \(S^\top\) – i.e. rows of \(S\) – in decreasing order of independence, and the first rank of them are a basis for the row space.

Why bother: the mass-balance penalty runs over rows of S, and the dependent rows (conserved moieties, dead-end metabolites) carry residuals that are exact linear combinations of the independent ones. Penalizing all 2,806 rows therefore weights some directions of the residual several times over, which is a silent, structured mis-weighting of the physics term rather than a harmless redundancy. On yeast-GEM 9.0.2 the rank is 2,593, so 213 rows are redundant.

Parameters:
  • s – [m, r] stoichiometric matrix, sparse or dense.

  • tol – Relative tolerance on the R diagonal for the numerical rank.

Returns:

(rows, rank) – a sorted long tensor of row indices, and the numerical rank.