sign_vector_conditions.uniqueness

Uniqueness of equilibria

We define some matrices:

sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 0]])
sage: Wt
[ 1  0 -1]
[ 0  1  0]

We want to check whether the corresponding chemical reaction network has at most one equilibrium for all rate constants. For this purpose, we compute the corresponding oriented matroids:

sage: from sign_vectors.oriented_matroids import *
sage: cvW = covectors_from_matrix(W, kernel=False, algorithm='fe')
sage: cvW
{(000),
 (+-+),
 (-+0),
 (-+-),
 (0-+),
 (-++),
 (+--),
 (0+-),
 (+-0),
 (+0-),
 (-0+),
 (--+),
 (++-)}
sage: cvWt = covectors_from_matrix(Wt, kernel=True, algorithm='fe')
sage: cvWt
{(000), (+0+), (-0-)}

The intersection of these oriented matroids consists only of the zero sign vector. We can compute the intersection directly by applying the built in method intersection:

sage: set(cvW).intersection(cvWt)
{(000)}

Therefore, there is at most one equilibrium. We can also check this condition in the following way:

sage: from sign_vector_conditions import *
sage: condition_uniqueness_sign_vectors(W, Wt)
True

There is another way to check this condition that involves the computation of maximal minors of the corresponding matrices:

sage: m1 = W.minors(2)
sage: m1
[1, -1, 1]
sage: m2 = Wt.minors(2)
sage: m2
[1, 0, 1]

We multiply those minors component-wise:

sage: [m1[i] * m2[i] for i in range(len(m1))]
[1, 0, 1]

Since all arguments are greater or equal zero, there is at most one equilibrium. We can also check this condition by applying the following function from this package:

sage: condition_uniqueness_minors(W, Wt)
True

Now, we consider another example:

sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 1]])
sage: Wt
[ 1  0 -1]
[ 0  1  1]

Next, we compute the corresponding oriented matroids:

sage: covectors_from_matrix(W, kernel=False, algorithm='fe', separate=True)
[{(000)},
 {(-+0), (0-+), (0+-), (+-0), (+0-), (-0+)},
 {(+-+), (-+-), (--+), (-++), (++-), (+--)}]
sage: covectors_from_matrix(Wt, kernel=True, algorithm='fe', separate=True)
[{(000)}, {(+-+), (-+-)}]

Now, we check the condition from before:

sage: condition_uniqueness_sign_vectors(W, Wt)
False

Therefore, the corresponding exponential map is not injective. Furthermore, we obtain the following minors:

sage: m1 = W.minors(2)
sage: m1
[1, -1, 1]
sage: m2 = Wt.minors(2)
sage: m2
[1, 1, 1]
sage: [m1[i]*m2[i] for i in range(len(m1))]
[1, -1, 1]

There are positive and negative elements in the resulting list. Hence, this condition also states that there is no unique equilibrium:

sage: condition_uniqueness_minors(W, Wt)
False

Finally, we consider an example with variables:

sage: var('a, b')
(a, b)
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, a], [0, 1, b]])
sage: Wt
[1 0 a]
[0 1 b]

The matrix Wt contains variables \(a, b \in \mathbb{R}\). Consequently, we cannot compute the corresponding oriented matroids. On the other hand, we can still compute the minors of W and Wt, that is:

sage: m1 = W.minors(2)
sage: m1
[1, -1, 1]
sage: m2 = Wt.minors(2)
sage: m2
[1, b, -a]
sage: [m1[i] * m2[i] for i in range(len(m1))]
[1, -b, -a]

Therefore, there is at most one equilibrium if and only if \(a, b \leq 0\). The function condition_uniqueness_minors() also works for matrices with symbolic entries. In this case, it returns a system of inequalities:

sage: condition_uniqueness_minors(W, Wt)
[{-a >= 0, -b >= 0}]

Functions

condition_uniqueness_minors(...)

Uniqueness condition for existence of an equilibrium using maximal minors.

condition_uniqueness_sign_vectors(...)

Uniqueness condition for existence of an equilibrium using sign vectors.

sign_vector_conditions.uniqueness.condition_uniqueness_minors(stoichiometric_kernel_matrix, kinetic_order_kernel_matrix)

Uniqueness condition for existence of an equilibrium using maximal minors.

INPUT:

  • stoichiometric_kernel_matrix – a matrix

  • kinetic_order_kernel_matrix – a matrix

OUTPUT: Return whether there exists at most one equilibrium. If the result depends on variables, a list of sets is returned. The condition holds if the inequalities in exactly one of these sets are satisfied.

Note

The matrices need to have the same rank and number of columns. Otherwise, a ValueError is raised.

EXAMPLES:

sage: from sign_vector_conditions import *
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 0]])
sage: Wt
[ 1  0 -1]
[ 0  1  0]
sage: condition_uniqueness_minors(W, Wt)
True
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 1]])
sage: Wt
[ 1  0 -1]
[ 0  1  1]
sage: condition_uniqueness_minors(W, Wt)
False
sage: var('a, b')
(a, b)
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, a], [0, 1, b]])
sage: Wt
[1 0 a]
[0 1 b]
sage: condition_uniqueness_minors(W, Wt)
[{-a >= 0, -b >= 0}]
sage: W = matrix([
....:     [a, 0, 1, 0],
....:     [0, 1, -1, 0],
....:     [0, 0, 0, 1]
....: ])
sage: Wt = matrix([
....:     [1, 0, 0, -1],
....:     [0, b, 1, 1],
....:     [0, 0, a, 1]
....: ])
sage: condition_uniqueness_minors(W, Wt) # random
[{(a - 1)*a >= 0, a*b >= 0}, {(a - 1)*a <= 0, a*b <= 0}]
sage: len(_), len(_[0]) # for testing
(2, 2)

We can also apply the built-in function solve_ineq to the resulting sets of inequalities. For instance, the first set can be equivalently written as:

sage: solve_ineq(list(condition_uniqueness_minors(W, Wt)[0])) # random
[[b == 0, a == 0],
[a == 0],
[b == 0, a == 1],
[a == 1, 0 < b],
[b == 0, 1 < a],
[0 < b, 1 < a],
[b == 0, a < 0],
[b < 0, a < 0]]
sign_vector_conditions.uniqueness.condition_uniqueness_sign_vectors(stoichiometric_kernel_matrix, kinetic_order_kernel_matrix) bool

Uniqueness condition for existence of an equilibrium using sign vectors.

INPUT:

  • stoichiometric_kernel_matrix – a matrix with n columns

  • kinetic_order_kernel_matrix – a matrix with n columns

OUTPUT: Return whether there exists at most one equilibrium.

Note

This implementation is inefficient and should not be used for large examples. Instead, use condition_uniqueness_minors().

EXAMPLES:

sage: from sign_vector_conditions import *
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 0]])
sage: Wt
[ 1  0 -1]
[ 0  1  0]
sage: condition_uniqueness_sign_vectors(W, Wt)
True
sage: W = matrix([[1, 0, -1], [0, 1, -1]])
sage: W
[ 1  0 -1]
[ 0  1 -1]
sage: Wt = matrix([[1, 0, -1], [0, 1, 1]])
sage: Wt
[ 1  0 -1]
[ 0  1  1]
sage: condition_uniqueness_sign_vectors(W, Wt)
False

TESTS:

sage: from sign_vector_conditions.uniqueness import condition_uniqueness_sign_vectors
sage: A = identity_matrix(3)
sage: B = A # kernel of B is empty
sage: condition_uniqueness_sign_vectors(A, B)
True