Skip to content

[BUG] Reaction addition/subtraction is unaware of reaction direction #1433

@oxinabox

Description

@oxinabox

Is there an existing issue for this?

  • I have searched the existing issues

Problem description

I wanted to test if two reactions we the same at least as far as having the same metabolites involved with same ratios (cf #1414 ).
I remembered that + and - were overloaded on Reactions to combine the metabolites.

So I thought if I substracted them I would get an empty set of metabolites,
and thus I could know they were equivalent reactions (at least as far as that was concerned)

I wrote a bunch of test cases before i started and the one where I was comparing two reactions that were expressed in opposite directions failed

Code sample

Code run:

In [1]: import cobra
   ...: 
   ...: def add_reaction_from_string(model: cobra.Model, reaction_str: str):
   ...:     # helper for demo
   ...:     reaction = cobra.Reaction(f"r_{len(model.reactions)}")
   ...:     model.add_reactions([reaction])
   ...:     # awkwardly, you can't build a reaction from a string without *first* attaching it to am model
   ...:     reaction.build_reaction_from_string(reaction_str)
   ...:     return reaction
   ...: 
   ...: 
   ...: 
   ...: model1 = cobra.Model("model1")
   ...: model1.add_metabolites([
   ...:     cobra.Metabolite("m_foo"),
   ...:     cobra.Metabolite("m_bar")
   ...: ])
   ...: 
   ...: r1 = add_reaction_from_string(model1, "m_foo --> m_bar")
   ...: r2 = add_reaction_from_string(model1, "m_bar <-- m_foo")
   ...: r_diff = r1 - r2
   ...: 
   ...: r_diff.metabolites
Out[1]: 
{<Metabolite m_foo at 0x7f6d668c9730>: -2,
 <Metabolite m_bar at 0x7f6d668c9760>: 2}

Rather than being empty the result is as if I had doubled r1

I believe this is because of the bounds:

In [2]: r1.bounds
Out[2]: (0, 1000.0)

In [3]: r2.bounds
Out[3]: (-1000.0, 0)

In [4]: r_diff.bounds
Out[4]: (0, 1000.0)

Then I also checked +

In [5]: r_sum = r1 + r2

In [6]: r_sum.metabolites
Out[6]: {}

In [7]: r_sum.bounds
Out[7]: (0, 1000.0)

which is the result i expected for -

Environment

Package Information

Package Version
cobra 0.29.1

Dependency Information

Package Version
appdirs~ missing
black missing
bumpversion missing
depinfo~ missing
diskcache~ missing
future 1.0.0
httpx~ missing
importlib-resources 6.5.2
isort missing
numpy 2.1.3
optlang~ missing
pandas 2.2.3
pydantic 2.10.6
python-libsbml~ missing
rich 13.9.4
ruamel.yaml~ missing
scipy 1.15.2
swiglpk 5.0.12
tox missing

Build Tools Information

Package Version
pip 24.3.1
setuptools 75.8.2
wheel 0.45.1

Platform Information

Linux 6.8.0-49-generic-x86_64
CPython 3.12.9

Anything else?

Possible resolution options:

remove reaction addition/subtraction

I don't think it is a particularly intuitive feature.
If people want to do this addition let them just do it on the reaction.metabolites themselves and then create a new Reaction object to store the results.
Maybe could define helpers like a subtype of dict that has math defined.
Which would also force them to make decisions about the bounds

Make this an error when bounds do not agree

Can't add things with different bounds implies can't add things with different directions.
Though this doesn't help for reversible reactions.

Canonicalize sides on creation

In the representation of the metabolites + bounds, arrange things such that the same set of metabolite is always on same side.
This does however mean that not all reactants will be negative and not all products positive in the reaction.metabolites dictionary

match direction as an initial step during addition/subtraction

Not sure how this would go for reactions that and reversible though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions