Skip to content

Commit

Permalink
refactor: clean up the get_solution function using new optlang feat…
Browse files Browse the repository at this point in the history
…ures (#481)

* chore: depend on new optlang version

* refactor: use new optlang `is_integer` property

The newly released optlang 1.1.4 has an `interface.Model.is_integer` property
that we can use to declutter the `get_solution` function. Also use this
opportunity to make slight optimizations that avoid multiple loops over
reactions and metabolites.
  • Loading branch information
Midnighter authored and hredestig committed Apr 7, 2017
1 parent b44bdec commit b3fe058
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 21 deletions.
39 changes: 19 additions & 20 deletions cobra/core/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from builtins import object, super
from warnings import warn

from numpy import zeros, asarray, nan
from numpy import empty, nan
from optlang.interface import OPTIMAL
from pandas import Series

Expand Down Expand Up @@ -288,36 +288,35 @@ def get_solution(model, reactions=None, metabolites=None):
if metabolites is None:
metabolites = model.metabolites

rxn_index = [rxn.id for rxn in reactions]
fluxes = zeros(len(reactions))
rxn_index = list()
fluxes = empty(len(reactions))
reduced = empty(len(reactions))
var_primals = model.solver.primal_values
reduced = zeros(len(reactions))
try:
# cplex throws error trying if accessing this attribute and not defined
var_duals = model.solver.reduced_costs
except Exception: # CplexSolverError
var_duals = Series([None] * len(reactions), index=rxn_index)
# reduced costs are not always defined, e.g. for integer problems
if var_duals[rxn_index[0]] is None:
shadow = empty(len(metabolites))
if model.solver.is_integer:
reduced.fill(nan)
shadow.fill(nan)
for (i, rxn) in enumerate(reactions):
rxn_index.append(rxn.id)
fluxes[i] = var_primals[rxn.id] - var_primals[rxn.reverse_id]
met_index = [met.id for met in metabolites]
else:
var_duals = model.solver.reduced_costs
for (i, rxn) in enumerate(reactions):
forward = rxn.id
reverse = rxn.reverse_id
rxn_index.append(forward)
fluxes[i] = var_primals[forward] - var_primals[reverse]
reduced[i] = var_duals[forward] - var_duals[reverse]
met_index = [met.id for met in metabolites]
try:
# cplex throws error trying if accessing this attribute and not defined
met_index = list()
constr_duals = model.solver.shadow_prices
except Exception: # CplexSolverError
constr_duals = Series([None] * len(metabolites), index=met_index)
shadow = asarray([constr_duals[met.id] for met in metabolites])
for (i, met) in enumerate(metabolites):
met_index.append(met.id)
shadow[i] = constr_duals[met.id]
return Solution(model.solver.objective.value, model.solver.status,
reactions,
Series(index=rxn_index, data=fluxes),
Series(index=rxn_index, data=reduced),
Series(index=rxn_index, data=fluxes, name="fluxes"),
Series(index=rxn_index, data=reduced,
name="reduced_costs"),
metabolites,
Series(index=met_index, data=shadow))
Series(index=met_index, data=shadow, name="shadow_prices"))
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def build_extension(self, ext):
version="0.6.0a4",
packages=find_packages(),
setup_requires=setup_requirements,
install_requires=["future", "swiglpk", "optlang",
install_requires=["future", "swiglpk", "optlang>=1.1.4",
"pandas>=0.17.0", "numpy>=1.6", "tabulate"],
tests_require=["jsonschema > 2.5", "pytest", "pytest-benchmark"],
extras_require=extras,
Expand Down

0 comments on commit b3fe058

Please sign in to comment.