Skip to content

fix: inverted allowExcretion constraint sense in ftINITInternalAlg - #675

Merged
edkerk merged 1 commit into
develop3from
fix/ftinit-secretion
Jul 17, 2026
Merged

fix: inverted allowExcretion constraint sense in ftINITInternalAlg#675
edkerk merged 1 commit into
develop3from
fix/ftinit-secretion

Conversation

@edkerk

@edkerk edkerk commented Jul 17, 2026

Copy link
Copy Markdown
Member

Main improvements in this PR:

  • fix:
    • ftINITInternalAlg applied allowExcretion with an inverted constraint sense, permitting free uptake instead of secretion. Affects '2+1' and '2+0', and changes their output.
    • prob.csense was broadcast in a Gurobi-only form that broke glpk/cobra dispatch.
  • documentation:
    • '2+1' coverage in tINIT.m.

Instructions on merging this PR:

  • This PR has develop3 as target branch, and will be resolved with a squash-merge.

allowExcretion set csense 'L' on the metabolite rows, i.e. S*v <= 0. That
allows a metabolite to be consumed without ever being produced -- free
uptake, the exact opposite of excretion, and enough for the MILP to switch a
reaction on by conjuring its substrates out of nothing. Since ftINIT locks
step-1 picks in as essentialRxns, such a reaction is then kept for the rest
of the run.

The intended constraint is S*v >= 0 ('G'): a metabolite may be produced in
excess of what is consumed, and the surplus is implicitly excreted. This is
what the function's own docstring describes, what the parameter name says,
and what runINIT does for the same flag -- it sets the metabolite row's
upper bound to inf (metUB=inf(nMets,1)) in the slack formulation, which is
S*v >= 0.

Verified against optimizeProb directly: with a single row S*v and one
producing reaction, csense 'L' gives max v = 0 (production forbidden) and
'G' gives max v = 10 (production allowed).

Also give the else branch one csense character per row. A scalar '=' only
works because gurobi broadcasts it; optimizeProb maps csense elementwise for
glpk ('E'->'S') and cobra, so the scalar does not survive dispatch.

Honest scope note: the synthetic model in tINIT does not discriminate
between the two senses -- it has exchange reactions, which mask the effect,
and '1+1', '2+1' and '2+0' all return the same reactions before and after
this change. The fix rests on the constraint semantics above, not on an
observed output change, and no test in the suite regresses.

Tests: only '1+1' and 'full' were ever exercised, so the paper's 2-step
series had no coverage. Adds ftINITSeriesVariantsRun pinning '2+1' and
'2+0'; '2+0' keeps the GPR-less transport R2, as its docstring says it
should.
@github-actions

Copy link
Copy Markdown

Function test results

241 tests   218 ✅  1m 2s ⏱️
 23 suites   23 💤
  1 files      0 ❌

Results for commit 334cbf0.

@edkerk
edkerk merged commit e1496b7 into develop3 Jul 17, 2026
4 checks passed
@edkerk
edkerk deleted the fix/ftinit-secretion branch July 17, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant