### Formal definition of loop-law constraints

In loopless-COBRA, the constraints added to the linear problem are:

\begin{array}{l}\phantom{\rule{1em}{0ex}}\phantom{\rule{2.77695pt}{0ex}}\phantom{\rule{0.3em}{0ex}}{G}_{i}<0\phantom{\rule{1em}{0ex}}\text{for all}\phantom{\rule{1em}{0ex}}{v}_{i}>0\phantom{\rule{2em}{0ex}}\\ \phantom{\rule{1em}{0ex}}\phantom{\rule{2.77695pt}{0ex}}\phantom{\rule{0.3em}{0ex}}{G}_{i}>0\phantom{\rule{1em}{0ex}}\text{for all}\phantom{\rule{1em}{0ex}}{v}_{i}<0\phantom{\rule{2em}{0ex}}\\ \phantom{\rule{1em}{0ex}}\phantom{\rule{2.77695pt}{0ex}}\phantom{\rule{0.3em}{0ex}}{G}_{i}\in \mathbb{R}\phantom{\rule{1em}{0ex}}\text{for all}\phantom{\rule{1em}{0ex}}{v}_{i}=0\phantom{\rule{2em}{0ex}}\\ {N}_{\mathrm{int}}G=0\phantom{\rule{2em}{0ex}}\end{array}

where *v*_{
i
} are the flux variables and *N*_{
int
} is the null-space matrix of *S*_{
int
}(the stoichiometric matrix of internal reactions). The third constraint ({G}_{i}\in \mathbb{R}) is not actually a constraint, but a way to say that *G*_{
i
} can have any value if *v*_{
i
} = 0. We can rewrite all these constraints succinctly as:

\exists G\in {\mathbb{R}}^{n}\phantom{\rule{2.77695pt}{0ex}}\text{s.t.}\phantom{\rule{2.77695pt}{0ex}}\text{null}\left({S}_{\mathrm{int}}\right)\xb7G\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}0\wedge \left(\forall i\phantom{\rule{2.77695pt}{0ex}}\text{sign}\left({G}_{i}\right)\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}-\text{sign}\left({v}_{i}\right)\vee {v}_{i}\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}0\right)

(1)

### Formal definition of loops

In order to prove that this constraint eliminates loops (and only loops), we must first find a mathematical formulation for a loop, using the same notation as above. We thus define a loop as a nonzero vectorx\in {\mathbb{R}}^{n} which satisfies the mass-balance equation for the internal reactions, i.e. *S*_{
int
} · *x* = 0. This means that although there is a nonzero net flux in some of the reactions, overall, the internal network is at steady-state (an obvious violation of the second law of thermodynamics). It is important to point out, that this equation for defining loops must not be confused with the steady-state assumption commonly used in flux balance analysis models, namely *S*·*v* = 0, where the *full* stoichiometric matrix (*S*) is used.

According to this definition, a flux distribution (v\in {\mathbb{R}}^{n}) will contain a loop if and only if there exists a vectorx\in {\mathbb{R}}^{n}\setminus \left\{0\right\} which is consistent with the flux directions in *v* (i.e. *x*_{
i
} is either zero or has the same sign as *v*_{
i
}) and is itself a loop (i.e. *S*_{
int
} · *x* = 0). Formally, *v* has a loop if and only if:

\exists x\in {\mathbb{R}}^{n}\setminus \left\{0\right\}\phantom{\rule{2.77695pt}{0ex}}\text{s.t.}\left(\forall i\phantom{\rule{2.77695pt}{0ex}}\text{sign}\left({x}_{i}\right)\in \left\{\text{sign}\right({v}_{i}),0\}\right)\wedge {S}_{\mathrm{int}}\xb7x=0

(2)

We have now finished laying the groundwork for our mathematical proof that loopless-COBRA is sound and complete. In order to do that, we are left only to show that Equation 1 is satisfiable if and only if Equation 2 is unsatisfiable (in other words, there are no loops).

### Gordan’s theorem

We start our proof by quoting Gordan’s theorem: For allA\in {\mathbb{R}}^{m\times n} exactly one of the following two statements is true:

\begin{array}{l}\left(a\right)\phantom{\rule{1em}{0ex}}\exists x\in {\mathbb{R}}_{+}^{n}\setminus \left\{0\right\}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{1em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\text{Ax}=0\phantom{\rule{2em}{0ex}}\\ \left(b\right)\phantom{\rule{2em}{0ex}}\exists y\in {\mathbb{R}}^{m}\phantom{\rule{2em}{0ex}}\phantom{\rule{1.3em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}{A}^{\top}y>0\phantom{\rule{2em}{0ex}}\end{array}

We will show that statement (*a*) in Gordan’s theorem is equivalent to having a loop (Equation 2) and statement (*b*) is equivalent to the MILP constraints used by loopless-COBRA (Equation 1). After doing so, we would easily reach the conclusion of the proof.

As a guidance for the following sections, one can see that statement (*a*) already resembles Equation 2 if we define *A* = *S*_{
int
}. The only difference is that *x* is constrained to have only non-negative values (note the ‘+’ in{\mathbb{R}}_{+}^{n}), instead of being consistent with the sign of *v*. Corollaries 1 and 2 will show how we can overcome this discrepancy by defining *A* in a slightly different way.

At first glance, statement (*b*) might look unrelated to Equation 1. However, in the last part of our proof, we show that choosingG\phantom{\rule{0.3em}{0ex}}\in \phantom{\rule{0.3em}{0ex}}{\mathbb{R}}^{n}, which satisfies null(*S*_{
int
})*G* = 0, is the same as choosingy\phantom{\rule{0.3em}{0ex}}\in \phantom{\rule{0.3em}{0ex}}{\mathbb{R}}^{m} and then takingG={S}_{\mathrm{int}}^{\top}\xb7y. Only for sake of understanding the algebra, one can think of *y* as the vector of formation Gibbs energies, and of *G* as the vector of reaction Gibbs energies. The rest of the proof, like for statement (*a*), deals with adjusting *A* to fit with the non-positive values in *v*. The toy example in Figure2 shows how Gordan’s theorem corresponds to having or not having a loop, for a network with 3 compounds and 3 internal reactions.

### Corollary 1

For allA\in {\mathbb{R}}^{m\times n} and *d* ∈ {−1,0,1}^{n} exactly one of the following two statements is true:

\begin{array}{c}\left(1a\right)\phantom{\rule{1em}{0ex}}\exists x\in {\mathbb{R}}^{n}\setminus \left\{0\right\}\phantom{\rule{1em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{2.77695pt}{0ex}}\text{sign}\left({x}_{i}\right)\in \{{d}_{i},0\}\right)\wedge \text{Ax}=0\\ \left(1b\right)\phantom{\rule{2em}{0ex}}\exists y\in {\mathbb{R}}^{m}\phantom{\rule{2em}{0ex}}\phantom{\rule{.5em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}{\left({A}^{\top}y\right)}_{i}={d}_{i}\vee {d}_{i}=0\right)\end{array}

#### Proof

First, define a new matrix\xc2 that is the same as *A*, without the columns corresponding to *d*_{
i
} = 0 and where columns corresponding to *d*_{
i
} = −1 are multiplied by −1. Statement (1*a*) is true for *A* if and only if (*a*) is true for\xc2. The forward direction is easily shown by removing the zeros from *x*, where *d*_{
i
} = 0, and negating values corresponding to *d*_{
i
} = −1 (as previously done for *A*). Reversing this process (i.e. taking a positive solution for\xc2\widehat{x}=0, adding back the zeros and negating the same values) shows the other direction is true as well.

Likewise, statement (1*b*) for *A* is true if and only if (*b*) is true for\xc2, since columns with *d*_{
i
} = −1 are negated in\xc2 and thus sign{\left({\xc2}^{\top}y\right)}_{i}=1. Columns with *d*_{
i
} = 0 have no other constraints in (1*b*) and the same goes for (*b*) since they are removed from\xc2.

Therefore, Corollary 1 is directly derived from Gordan’s theorem. □

Since constraint-based models usually use a vector of real values (v\in {\mathbb{R}}^{n}) to represent the flux distribution, we subsequently change the formulation of the Corollary slightly to match.

### Corollary 2

For allA\in {\mathbb{R}}^{m\times n} andv\in {\mathbb{R}}^{n}, exactly one of the following two statements is true:

\begin{array}{c}\left(2a\right)\phantom{\rule{1em}{0ex}}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\exists x\in {\mathbb{R}}^{n}\setminus \left\{0\right\}\phantom{\rule{1em}{0ex}}\phantom{\rule{0.3em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}\left({x}_{i}\right)\in \left\{\text{sign}\right({v}_{i}),0\}\right)\wedge \mathrm{Ax}=0\\ \left(2b\right)\phantom{\rule{2em}{0ex}}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\exists y\in {\mathbb{R}}^{m}\phantom{\rule{2em}{0ex}}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{0.3em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}{\left({A}^{\top}y\right)}_{i}=-\text{sign}\left({v}_{i}\right)\vee {v}_{i}=0\right)\end{array}

#### Proof

Defining *d*_{
i
} ≡ sign(*v*_{
i
}), we get this directly from Corollary 1. Note that −sign(*v*_{
i
}) can be used in (2b), since the existence of *y* is equivalent to the existence of −*y*. □

This adjustment now allows us to apply Corollary 2 to constraint-based problems and show that it eliminates loops (see example in Figure2). In order to avoid any confusion, we point out that a solution for *Ax* = 0 is considered a loop only if *A* is the stoichiometric matrix of *internal* reactions. This should not be mistaken as the steady-state mass-balance equation which looks exactly the same, except that *A* contains both internal and external reactions.

### Corollary 3

Adding the following constraint:

\exists y\in {\mathbb{R}}^{m}\phantom{\rule{2.77695pt}{0ex}}\text{s.t.}\phantom{\rule{2.77695pt}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}{\left({A}^{\top}y\right)}_{i}=-\text{sign}\left({v}_{i}\right)\phantom{\rule{0.3em}{0ex}}\vee \phantom{\rule{0.3em}{0ex}}{v}_{i}=0\right)

is equivalent to eliminating all loops in a flux distribution *v*.

#### Proof

Using Corollary 2, all that must be shown is that statement (2a) is equivalent to having a loop. This is apparent since *x* is a vector in the null-space of *A* (i.e., a loop) and is consistent with the flux direction of *v* in each of its nonzero reactions. □

Note that the trivial case *v* = 0 can still be a solution and it should be explicitly avoided if necessary.

### Applying Corollary 3 in loopless-COBRA

The added constraints in loopless-COBRA[17] are slightly different than in Corollary 3, namely:

\begin{array}{l}\exists G\phantom{\rule{0.3em}{0ex}}\in \phantom{\rule{0.3em}{0ex}}{\mathbb{R}}^{n}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{2.77695pt}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\phantom{\rule{2.77695pt}{0ex}}\text{null}\left(A\right)\phantom{\rule{0.3em}{0ex}}\xb7\phantom{\rule{0.3em}{0ex}}G\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}0\phantom{\rule{0.3em}{0ex}}\wedge \phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}\left({G}_{i}\right)\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}-\text{sign}\left({v}_{i}\right)\phantom{\rule{0.3em}{0ex}}\vee \phantom{\rule{0.3em}{0ex}}{v}_{i}\phantom{\rule{0.3em}{0ex}}=\phantom{\rule{0.3em}{0ex}}0\right)\end{array}

We claim here that both formulations are equivalent. The fundamental theorem of linear algebra states that the nullspace, null(*A*), is the orthogonal complement of the row space, image(*A*^{⊤}). Therefore, we can say that null(*A*)·*G* = 0 if and only if *G* ∈ image(*A*^{⊤}), so we can rewrite the constraint above as:

\exists G\in \text{image}\left({A}^{\top}\right)\phantom{\rule{0.3em}{0ex}}\text{s.t.}\phantom{\rule{0.3em}{0ex}}\left(\forall i\phantom{\rule{0.3em}{0ex}}\text{sign}\left({G}_{i}\right)=-\text{sign}\left({v}_{i}\right)\phantom{\rule{0.3em}{0ex}}\vee \phantom{\rule{0.3em}{0ex}}{v}_{i}=0\right)

which is obviously equivalent to the constraint in Corollary 3.