Skip to content

Sparse FBA (MIP)

The sparse FBA problem consists of finding the optimal flux value for a reaction minimizing the number of reactions with non-zero flux (l0-norm sparsity). Note that minimizing the l0-norm is a NP-hard problem, and so obtaing an optimal solution is not possible in many cases. The COBRA Toolbox includes different LP heuristics to minimize different approximations of the l0-norm. However, using a MIO formulation, it's is possible to obtain a solution which is close to optimal, with a lower number of reactions than the LP approximations, and very quickly.

Here is the implementation of sparse-FBA with MIOM:

import miom

# Load a genome-scale metabolic network. You can load SMBL or Matlab metabolic networks
# as well using the same method, but it requires to have the cobratoolbox python library
# installed.
network = miom.load_gem("@iMM1865")

# Create the sparse FBA problem to get a solution that maximizes
# the optimal flux through the BIOMASS_reaction minimizing the
# number of active reactions. The solution should be not more than
# 5% of the optimal solution (opt_tol = 0.05).
V, X = (miom
        .load(network, solver=miom.Solvers.GUROBI_PYMIP)
        # Set-up the solver options
        .setup(int_tol=1e-8, opt_tol=0.05, verbosity=1)
        # Add the steady-state constraints (S*V = 0)
        .steady_state()
        # Set the reaction to optimize using FBA
        .set_rxn_objective('BIOMASS_reaction')
        # Solve the FBA (LP) problem (optimal flux)
        .solve()
        # Add a constraint to force a flux through
        # the reaction equal to the optimal flux
        .set_fluxes_for('BIOMASS_reaction')
        # Convert to a MIO problem (best subset selection)
        # Each reaction in the network is associated
        # with a negative weight of -1. The optimization
        # problem now tries to minimize the selection of
        # reactions with negative weights (respecting
        # the previous constraints). Since each reaction 
        # has a weight of -1, all reactions are equally 
        # important in the optimization problem.
        # This is exactly the optimal sparse-FBA problem
        # with l0-norm: minimize the number of reactions
        # but mantaining the optimal FBA flux possible.
        .subset_selection(-1)
        # Solve the MIO problem (note that it's NP-Hard)
        # You can control the optimality by changing the
        # opt_tol in the .setup() method.
        .solve()
        # Return the flux values (V) and the binary 
        # indicator values (X)
        .get_values())

# Show reactions with a flux > 1e-8
print("Number of reactions with flux above +/- 1e-8:", sum(abs(V) > 1e-8))

# Count reactions with an indicator value of 0 (active). Note that since
# the weights of the reactions are negative (for all rxns), an indicator
# value of 1 corresponds to a succesful removed reaction not included in
# the solution, and a value of 0 to a reaction that could not be removed.
print("Indicator variables with a value of 1 (selected rxns):", sum(X < 0.5))

# Show the flux value of the biomass reaction
print("Optimal biomass flux:", V[m.get_reaction_id("BIOMASS_reaction")], "mmol/(h·gDW)")