From 0f028fe64050aa464399ecce86ab675eece88dd2 Mon Sep 17 00:00:00 2001 From: axelvonkamp Date: Wed, 3 Jul 2024 15:37:43 +0200 Subject: [PATCH] bump version --- conda-recipe/meta.yaml | 8 +- examples/ECC2comp.ipynb | 1170 +++++++++++++------------ optlang_enumerator/cMCS_enumerator.py | 212 +++-- optlang_enumerator/mcs_computation.py | 193 +++- setup.py | 4 +- 5 files changed, 890 insertions(+), 697 deletions(-) diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 80b65d1..a37637a 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,4 +1,4 @@ -{% set version = '0.0.9' %} +{% set version = '0.0.10' %} package: name: optlang_enumerator @@ -14,11 +14,11 @@ requirements: - python run: - python - - numpy<1.24 + - numpy=1.23 - scipy - optlang - - cobra - - efmtool_link + - cobra>=0.26.3 + - efmtool_link>=0.0.5 - sympy>=1.12 diff --git a/examples/ECC2comp.ipynb b/examples/ECC2comp.ipynb index 86c376e..bf7d3a3 100644 --- a/examples/ECC2comp.ipynb +++ b/examples/ECC2comp.ipynb @@ -1,1004 +1,988 @@ { - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.10" - }, - "orig_nbformat": 2, - "kernelspec": { - "name": "python3", - "display_name": "Python 3.7.10 64-bit ('cnapy3': conda)" - }, - "interpreter": { - "hash": "934ac3fdf6172ea19fa36e418c62d8759e237019ba7d63c030562927bd521148" - } - }, - "nbformat": 4, - "nbformat_minor": 2, "cells": [ { "cell_type": "code", "execution_count": 1, + "metadata": {}, + "outputs": [], "source": [ - "import cobra\r\n", - "import optlang\r\n", - "import optlang_enumerator.cobra_cnapy\r\n", - "import optlang_enumerator.mcs_computation as mcs_computation\r\n", - "import numpy\r\n", - "from pathlib import Path\r\n", - "# results_cache_dir = None # do not cache preprocessing results\r\n", + "import optlang\n", + "import optlang_enumerator.cobra_cnapy\n", + "import optlang_enumerator.mcs_computation as mcs_computation\n", + "import numpy\n", + "from pathlib import Path\n", + "# results_cache_dir = None # do not cache preprocessing results\n", "results_cache_dir = Path(\".\") # cache preprocessing results (in the current directory)" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 2, - "source": [ - "ecc2 = optlang_enumerator.cobra_cnapy.CNApyModel.read_sbml_model(\"ECC2comp.sbml\")\r\n", - "# allow all reactions that are not boundary reactions as cuts (same as exclude_boundary_reactions_as_cuts option of compute_mcs)\r\n", - "cuts = numpy.array([not r.boundary for r in ecc2.reactions])\r\n", - "reac_id = ecc2.reactions.list_attr('id') # list of reaction IDs in the model\r\n", - "# define target (multiple targets are possible; each target can have multiple linear inequality constraints)\r\n", - "ecc2_mue_target = [[(\"Growth\", \">=\", 0.01)]] # one target with one constraint, a.k.a. syntehtic lethals\r\n", - "# this constraint alone would not be sufficient, but there are uptake limits defined in the reaction bounds\r\n", - "# of the model that are integerated below, first, however, parse the constraint(s) and convert to matrix format\r\n", - "ecc2_mue_target = [mcs_computation.relations2leq_matrix(\r\n", - " mcs_computation.parse_relations(t, reac_id_symbols=mcs_computation.get_reac_id_symbols(reac_id)), reac_id)\r\n", - " for t in ecc2_mue_target]\r\n", - "# now integrate the non-default reaction bounds from the network\r\n", - "mcs_computation.integrate_model_bounds(ecc2, ecc2_mue_target)\r\n", - "# this is just to show what the first (and only) target now looks like:\r\n", - "for c in mcs_computation.get_leq_constraints(ecc2, ecc2_mue_target)[0]:\r\n", - " print(c)" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "Restricted license - for non-production use only - expires 2022-01-13\n", - "20f50bdc-5e83-11ec-913a-7824af3cf13a: -1.0*Growth + 1.0*Growth_reverse_699ae <= -0.01\n", - "20f50bdd-5e83-11ec-b138-7824af3cf13a: 1.0*AcUp - 1.0*AcUp_reverse_36302 <= 10.0\n", - "20f50bde-5e83-11ec-8aa0-7824af3cf13a: 1.0*CO2Up - 1.0*CO2Up_reverse_9ac6c <= 10.0\n", - "20f50bdf-5e83-11ec-85b1-7824af3cf13a: 1.0*GlcUp - 1.0*GlcUp_reverse_f2a50 <= 10.0\n", - "20f50be0-5e83-11ec-a36a-7824af3cf13a: 1.0*GlycUp - 1.0*GlycUp_reverse_d1488 <= 10.0\n", - "20f50be1-5e83-11ec-a3f4-7824af3cf13a: 1.0*SuccUp - 1.0*SuccUp_reverse_79869 <= 10.0\n" + "Restricted license - for non-production use only - expires 2025-11-24\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_0: -1.0*Growth + 1.0*Growth_reverse_699ae <= -0.01 None\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_1: 1.0*AcUp - 1.0*AcUp_reverse_36302 <= 10.0 None\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_2: 1.0*CO2Up - 1.0*CO2Up_reverse_9ac6c <= 10.0 None\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_3: 1.0*GlcUp - 1.0*GlcUp_reverse_f2a50 <= 10.0 None\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_4: 1.0*GlycUp - 1.0*GlycUp_reverse_d1488 <= 10.0 None\n", + "eed2d55c-354f-11ef-8715-004e01c408d4_0_5: 1.0*SuccUp - 1.0*SuccUp_reverse_79869 <= 10.0 None\n" ] } ], - "metadata": {} + "source": [ + "ecc2 = optlang_enumerator.cobra_cnapy.CNApyModel.read_sbml_model(\"ECC2comp.sbml\")\n", + "# allow all reactions that are not boundary reactions as cuts (same as exclude_boundary_reactions_as_cuts option of compute_mcs)\n", + "cuts = numpy.array([not r.boundary for r in ecc2.reactions])\n", + "reac_id = ecc2.reactions.list_attr('id') # list of reaction IDs in the model\n", + "# define target (multiple targets are possible; each target can have multiple linear inequality constraints)\n", + "ecc2_mue_target = [[(\"Growth\", \">=\", 0.01)]] # one target with one constraint, a.k.a. syntehtic lethals\n", + "# this constraint alone would not be sufficient, but there are uptake limits defined in the reaction bounds\n", + "# of the model that are integerated below, first, however, parse the constraint(s) and convert to matrix format\n", + "ecc2_mue_target = [mcs_computation.relations2leq_matrix(\n", + " mcs_computation.parse_relations(t, reac_id_symbols=mcs_computation.get_reac_id_symbols(reac_id)), reac_id)\n", + " for t in ecc2_mue_target]\n", + "# now integrate the non-default reaction bounds from the network\n", + "mcs_computation.integrate_model_bounds(ecc2, ecc2_mue_target)\n", + "# this is just to show what the first (and only) target now looks like:\n", + "for c in mcs_computation.get_leq_constraints(ecc2, ecc2_mue_target)[0]:\n", + " print(c, c.problem)" + ] }, { "cell_type": "code", "execution_count": 3, - "source": [ - "# calculate MCS up to size 3 with \"any MCS\" enumeration method\r\n", - "ecc2_mcs,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=True,\r\n", - " include_model_bounds=False, results_cache_dir=results_cache_dir)\r\n", - "print(len(ecc2_mcs), \"MCS found.\")\r\n", - "# show MCS as n-tuples of reaction IDs\r\n", - "ecc2_mcs_rxns= [tuple(reac_id[r] for r in mcs) for mcs in ecc2_mcs]\r\n", - "print(ecc2_mcs_rxns)\r\n", - "# check that all MCS disable the first (and only) target\r\n", - "print(all(mcs_computation.check_mcs(ecc2, ecc2_mue_target[0], ecc2_mcs, optlang.interface.INFEASIBLE)))" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "FVA to find blocked reactions...\n", - "No cached result available, running FVA...\n", - "Saved FVA result to CNA_ECC2comp_FVA_ce7a56f83eb0160025980498b314e26a\n", - "Read LP format model from file C:\\Users\\axel_2\\AppData\\Local\\Temp\\tmpftw53_q6.lp\n", - "Reading time = 0.01 seconds\n", - ": 94 rows, 244 columns, 834 nonzeros\n", - "Flipped EX_ca2_ex\n", - "Flipped EX_cl_ex\n", - "Flipped EX_cobalt2_ex\n", - "Flipped EX_cu2_ex\n", - "Flipped EX_fe2_ex\n", - "Flipped EX_fe3_ex\n", - "Flipped EX_glc_DASH_D_ex\n", - "Flipped EX_glyc_ex\n", - "Flipped EX_k_ex\n", - "Flipped EX_mg2_ex\n", - "Flipped EX_mn2_ex\n", - "Flipped EX_mobd_ex\n", - "Flipped EX_nh4_ex\n", - "Flipped EX_ni2_ex\n", - "Flipped EX_o2_ex\n", - "Flipped EX_pi_ex\n", - "Flipped EX_so4_ex\n", - "Flipped EX_zn2_ex\n", - "Flipped RPI\n", - "Removing 5 reactions:\n", - "[EX_q8_c, EX_adp_c, EX_nad_c, EX_mqn8_c, EX_nadp_c]\n", - "Saved compressed model to CNA_ECC2comp_subsets_compressed_59040b07c3bb98f20f85160d37565f50\n", + "Loaded compressed model from CNA_ECC2comp_subsets_compressed_75890a457ad63e16157884b633ad1014\n", "Using big M.\n", + "knock_in_idx []\n", "Objective function is empty; set objective to self.minimize_sum_over_z\n", "Found solution with objective value 2.0\n", - "CS (24, 33) -> MCS (24, 33)\n", - "Found solution with objective value 1.0\n", - "Found solution with objective value 3.0\n", - "CS (3, 9, 30) -> MCS (3, 9)\n", - "Found solution with objective value 2.0\n", - "CS (17, 29) -> MCS (17,)\n", - "Found solution with objective value 2.0\n", - "CS (7, 21) -> MCS (7, 21)\n", + "CS ['{TALA|TKT1}' 'TKT2'] -> MCS ['{TALA|TKT1}' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (33, 53, 54) -> MCS (33, 53, 54)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{EX_h_ex|h_pEx}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{EX_h_ex|h_pEx}']\n", "Found solution with objective value 3.0\n", - "CS (29, 48, 52) -> MCS (29, 52)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'ATPS4rpp' '{GAPD|PGK}'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' '{GAPD|PGK}']\n", "Found solution with objective value 1.0\n", + "MCS ['ICDHyr']\n", "Found solution with objective value 2.0\n", - "CS (32, 64) -> MCS (32, 64)\n", + "CS ['AcEx' '{ACKr|PTAr}'] -> MCS ['AcEx' '{ACKr|PTAr}']\n", + "Found solution with objective value 1.0\n", + "MCS ['ADK1']\n", + "Found solution with objective value 1.0\n", + "MCS ['{ACONTa|ACONTb|CS}']\n", "Found solution with objective value 3.0\n", - "CS (60, 62, 63) -> MCS (60, 62)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'RPI' '{TALA|TKT1}'] -> MCS ['RPI']\n", + "Found solution with objective value 1.0\n", + "MCS ['{EX_Biomass|EX_4CRSOL_ex|EX_5DRIB_ex|EX_AMOB_ex|EX_ca2_ex|EX_cl_ex|EX_coa_c|EX_cobalt2_ex|EX_cu2_ex|EX_fe2_ex|EX_fe3_ex|EX_k_ex|EX_meoh_ex|EX_mg2_ex|EX_mn2_ex|EX_mobd_ex|EX_MTHTHF_ex|EX_nh4_ex|EX_ni2_ex|EX_pi_c|EX_pi_ex|EX_so4_ex|EX_zn2_ex|Growth}']\n", "Found solution with objective value 2.0\n", - "CS (42, 52) -> MCS (42, 52)\n", + "CS ['{EX_h_ex|h_pEx}' 'CO2Ex'] -> MCS ['{EX_h_ex|h_pEx}' 'CO2Ex']\n", "Found solution with objective value 2.0\n", - "CS (38, 66) -> MCS (38, 66)\n", - "Found solution with objective value 3.0\n", - "CS (58, 62, 63) -> MCS (58, 62)\n", - "Found solution with objective value 3.0\n", - "CS (11, 21, 24) -> MCS (11, 24)\n", + "CS ['GND' 'RPE'] -> MCS ['GND' 'RPE']\n", "Found solution with objective value 2.0\n", - "CS (18, 63) -> MCS (18, 63)\n", - "Found solution with objective value 3.0\n", - "CS (29, 60, 63) -> MCS (29, 60)\n", - "Found solution with objective value 3.0\n", - "CS (24, 53, 54) -> MCS (24, 53, 54)\n", + "CS ['FUM' 'SuccEx'] -> MCS ['FUM' 'SuccEx']\n", "Found solution with objective value 2.0\n", - "CS (30, 36) -> MCS (30, 36)\n", + "CS ['G3PD2' 'GLYK'] -> MCS ['G3PD2' 'GLYK']\n", "Found solution with objective value 2.0\n", - "CS (38, 56) -> MCS (38, 56)\n", - "Found solution with objective value 3.0\n", - "CS (11, 33, 59) -> MCS (11, 33)\n", + "CS ['RPE' 'TKT2'] -> MCS ['RPE' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (56, 64) -> MCS (56, 64)\n", - "Found solution with objective value 2.0\n", - "CS (64, 66) -> MCS (64, 66)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ENO|PGM}'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ENO|PGM}']\n", "Found solution with objective value 3.0\n", - "CS (40, 52, 59) -> MCS (40, 52, 59)\n", + "CS ['{EX_h_ex|h_pEx}' 'RPE' '{TALA|TKT1}'] -> MCS ['RPE' '{TALA|TKT1}']\n", + "Found solution with objective value 2.0\n", + "CS ['AKGDH' 'SUCOAS'] -> MCS ['AKGDH' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (21, 52, 63) -> MCS (21, 52)\n", + "CS ['FBA' 'GLYK' 'TPI'] -> MCS ['FBA' 'GLYK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (5, 9, 21) -> MCS (5, 9, 21)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBA'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBA']\n", "Found solution with objective value 2.0\n", - "CS (6, 30) -> MCS (6, 30)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'G3PD2'] -> MCS ['{EX_glyc_ex|GlycUp}' 'G3PD2']\n", "Found solution with objective value 3.0\n", - "CS (33, 42, 54) -> MCS (33, 42, 54)\n", - "Found solution with objective value 2.0\n", - "CS (52, 62) -> MCS (52, 62)\n", + "CS ['{EX_h_ex|h_pEx}' '{ENO|PGM}' '{GAPD|PGK}'] -> MCS ['{ENO|PGM}' '{GAPD|PGK}']\n", "Found solution with objective value 3.0\n", - "CS (5, 33, 67) -> MCS (5, 33, 67)\n", - "Found solution with objective value 2.0\n", - "CS (13, 14) -> MCS (13, 14)\n", - "Found solution with objective value 2.0\n", - "CS (0, 42) -> MCS (0,)\n", - "Found solution with objective value 2.0\n", - "CS (56, 66) -> MCS (56, 66)\n", + "CS ['CO2Ex' 'PPC' 'SUCOAS'] -> MCS ['CO2Ex' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (24, 42, 54) -> MCS (24, 42, 54)\n", - "Found solution with objective value 2.0\n", - "CS (20, 39) -> MCS (39,)\n", + "CS ['PFK' 'PGI' 'TKT2'] -> MCS ['PFK' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (26, 50, 66) -> MCS (26, 50, 66)\n", - "Found solution with objective value 2.0\n", - "CS (28, 29) -> MCS (28, 29)\n", + "CS ['SUCCt3pp' 'SUCDi' 'SUCOAS'] -> MCS ['SUCCt3pp' 'SUCDi']\n", + "Found solution with objective value 3.0\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'FUM'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 63) -> MCS (21, 60, 63)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'CO2Ex' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'CO2Ex' 'PFL']\n", "Found solution with objective value 2.0\n", - "CS (38, 64) -> MCS (38, 64)\n", + "CS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h2o_ex|h2oEx}'] -> MCS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h2o_ex|h2oEx}']\n", "Found solution with objective value 3.0\n", - "CS (21, 29, 66) -> MCS (21, 29, 66)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (4, 9, 21) -> MCS (4, 9, 21)\n", + "CS ['CO2Ex' 'RPE' 'SuccEx'] -> MCS ['CO2Ex' 'RPE' 'SuccEx']\n", + "Found solution with objective value 3.0\n", + "CS ['{GAPD|PGK}' 'PPCK' 'PPS'] -> MCS ['{GAPD|PGK}' 'PPCK' 'PPS']\n", + "Found solution with objective value 2.0\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'ATPS4rpp'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'ATPS4rpp']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 66) -> MCS (5, 50, 66)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' '{TALA|TKT1}'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (5, 24, 67) -> MCS (5, 24, 67)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{GAPD|PGK}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{GAPD|PGK}' 'TPI']\n", + "Found solution with objective value 2.0\n", + "CS ['MDH' 'PPC'] -> MCS ['MDH' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 56) -> MCS (5, 50, 56)\n", + "CS ['{ICL|MALS}' 'PPC' 'SUCCt2_2pp'] -> MCS ['{ICL|MALS}' 'PPC' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 64) -> MCS (5, 50, 64)\n", + "CS ['CO2Ex' '{ENO|PGM}' 'PPS'] -> MCS ['CO2Ex' '{ENO|PGM}' 'PPS']\n", + "Found solution with objective value 2.0\n", + "CS ['FUM' 'PPC'] -> MCS ['FUM' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (48, 50, 66) -> MCS (48, 50, 66)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBP'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBP']\n", "Found solution with objective value 2.0\n", - "CS (29, 58) -> MCS (29, 58)\n", + "CS ['{FRD2|NADH17pp}' 'FUM'] -> MCS ['{FRD2|NADH17pp}' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (5, 25, 27) -> MCS (5, 25, 27)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'FUM'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (11, 20, 26) -> MCS (11, 20)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCCt2_2pp'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (11, 32, 66) -> MCS (32, 66)\n", + "CS ['SuccEx' 'SUCDi' 'SUCOAS'] -> MCS ['SuccEx' 'SUCDi']\n", + "Found solution with objective value 2.0\n", + "CS ['FUM' 'SUCCt3pp'] -> MCS ['FUM' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (11, 32, 56) -> MCS (32, 56)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SuccUp'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SuccUp']\n", + "Found solution with objective value 2.0\n", + "CS ['GND' '{TALA|TKT1}'] -> MCS ['GND' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (6, 48, 67) -> MCS (6, 48, 67)\n", + "CS ['{ENO|PGM}' 'PPS' 'SUCDi'] -> MCS ['{ENO|PGM}' 'PPS' 'SUCDi']\n", + "Found solution with objective value 2.0\n", + "CS ['{G6PDH2r|PGL}' '{TALA|TKT1}'] -> MCS ['{G6PDH2r|PGL}' '{TALA|TKT1}']\n", + "Found solution with objective value 2.0\n", + "CS ['GND' 'TKT2'] -> MCS ['GND' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 64) -> MCS (21, 60, 64)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBA'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBA']\n", + "Found solution with objective value 2.0\n", + "CS ['{G6PDH2r|PGL}' 'RPE'] -> MCS ['{G6PDH2r|PGL}' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (21, 24, 54) -> MCS (21, 24, 54)\n", + "CS ['{ENO|PGM}' 'PPCK' 'PPS'] -> MCS ['{ENO|PGM}' 'PPCK' 'PPS']\n", + "Found solution with objective value 2.0\n", + "CS ['{G6PDH2r|PGL}' 'TKT2'] -> MCS ['{G6PDH2r|PGL}' 'TKT2']\n", + "Found solution with objective value 2.0\n", + "CS ['PPC' 'SUCDi'] -> MCS ['PPC' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 63) -> MCS (21, 58, 63)\n", + "CS ['{ICL|MALS}' 'PPC' 'SuccUp'] -> MCS ['{ICL|MALS}' 'PPC' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (5, 9, 62) -> MCS (5, 9, 62)\n", + "CS ['CO2Ex' '{GAPD|PGK}' 'PPS'] -> MCS ['CO2Ex' '{GAPD|PGK}' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 21) -> MCS (5, 6, 21)\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCCt2_2pp'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 64) -> MCS (21, 58, 64)\n", + "CS ['CO2Ex' 'FUM' 'TKT2'] -> MCS ['CO2Ex' 'FUM' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (9, 21, 49) -> MCS (9, 21, 49)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'CO2Ex'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'CO2Ex']\n", "Found solution with objective value 3.0\n", - "CS (21, 33, 54) -> MCS (21, 33, 54)\n", + "CS ['GLYK' 'PFK' 'TPI'] -> MCS ['GLYK' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 63) -> MCS (21, 28, 63)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{ENO|PGM}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{ENO|PGM}' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 64) -> MCS (21, 28, 64)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'RPE'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 59) -> MCS (7, 14, 59)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCDi'] -> MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 61) -> MCS (7, 14, 61)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'TKT2'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (5, 25, 26) -> MCS (5, 25, 26)\n", + "CS ['FBA' 'PGI' 'TKT2'] -> MCS ['FBA' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (36, 48, 67) -> MCS (36, 48, 67)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}']\n", "Found solution with objective value 3.0\n", - "CS (26, 36, 67) -> MCS (26, 36, 67)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'AcUp' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'AcUp' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (7, 16, 59) -> MCS (7, 16, 59)\n", + "CS ['{ENO|PGM}' 'FUM' 'PPS'] -> MCS ['{ENO|PGM}' 'FUM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (6, 26, 67) -> MCS (6, 26, 67)\n", + "CS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_glc_DASH_D_ex|GlcUp}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}'] -> MCS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_glc_DASH_D_ex|GlcUp}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}']\n", "Found solution with objective value 3.0\n", - "CS (7, 16, 61) -> MCS (7, 16, 61)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' '{TALA|TKT1}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 11) -> MCS (5, 6, 11)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'PYK'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'PYK']\n", "Found solution with objective value 3.0\n", - "CS (40, 52, 61) -> MCS (40, 52, 61)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'FUM'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (11, 45, 60) -> MCS (11, 45, 60)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'PFK' 'TPI'] -> MCS ['{EX_glyc_ex|GlycUp}' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (3, 5, 11) -> MCS (3, 5, 11)\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SuccUp'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (5, 11, 55) -> MCS (5, 11, 55)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'FBA' 'TPI'] -> MCS ['{EX_glyc_ex|GlycUp}' 'FBA' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (11, 45, 58) -> MCS (11, 45, 58)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{ENO|PGM}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{ENO|PGM}']\n", "Found solution with objective value 3.0\n", - "CS (14, 47, 49) -> MCS (14, 47, 49)\n", + "CS ['{ACKr|PTAr}' 'PDH' 'PFL'] -> MCS ['{ACKr|PTAr}' 'PDH' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (11, 45, 52) -> MCS (11, 45, 52)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (24, 29, 54) -> MCS (24, 29, 54)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBP'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBP']\n", "Found solution with objective value 3.0\n", - "CS (21, 29, 56) -> MCS (21, 29, 56)\n", + "CS ['CO2Ex' 'SuccEx' 'SUCOAS'] -> MCS ['CO2Ex' 'SuccEx' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (29, 33, 54) -> MCS (29, 33, 54)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'RPE'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 62) -> MCS (7, 14, 62)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'TKT2'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (7, 16, 62) -> MCS (7, 16, 62)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'SUCOAS'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 66) -> MCS (21, 60, 66)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'NADH16pp' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'NADH16pp' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 66) -> MCS (21, 58, 66)\n", + "CS ['CO2Ex' 'FUM' 'RPE'] -> MCS ['CO2Ex' 'FUM' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 27) -> MCS (5, 6, 27)\n", + "CS ['CO2Ex' 'RPE' 'SUCCt3pp'] -> MCS ['CO2Ex' 'RPE' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 29) -> MCS (7, 14, 29)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'TKT2'] -> MCS ['CO2Ex' 'SUCCt3pp' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 26) -> MCS (5, 6, 26)\n", + "CS ['FUM' '{GAPD|PGK}' 'PPS'] -> MCS ['FUM' '{GAPD|PGK}' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (7, 16, 29) -> MCS (7, 16, 29)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'FUM' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'FUM' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 56) -> MCS (21, 28, 56)\n", + "CS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}' 'FUM'] -> MCS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (5, 11, 14) -> MCS (5, 11, 14)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCDi'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 66) -> MCS (21, 28, 66)\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCDi'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (9, 29, 49) -> MCS (9, 29, 49)\n", + "CS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}' 'SUCDi'] -> MCS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (33, 54, 62) -> MCS (33, 54, 62)\n", + "CS ['CO2Ex' 'SuccEx' 'TKT2'] -> MCS ['CO2Ex' 'SuccEx' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (5, 9, 29) -> MCS (5, 9, 29)\n", + "CS ['CO2Ex' 'SuccEx' '{TALA|TKT1}'] -> MCS ['CO2Ex' 'SuccEx' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 29) -> MCS (5, 6, 29)\n", + "CS ['{ENO|PGM}' 'MDH' 'PPS'] -> MCS ['{ENO|PGM}' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 67) -> MCS (5, 6, 67)\n", + "CS ['{GAPD|PGK}' 'PPS' 'SUCDi'] -> MCS ['{GAPD|PGK}' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 62) -> MCS (5, 6, 62)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'SUCOAS'] -> MCS ['CO2Ex' 'SUCCt3pp' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (3, 7, 11) -> MCS (3, 7, 11)\n", + "CS ['CO2Ex' 'SUCCt3pp' '{TALA|TKT1}'] -> MCS ['CO2Ex' 'SUCCt3pp' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (9, 49, 59) -> MCS (9, 49, 59)\n", + "CS ['{EX_for_ex|FormEx}' '{EX_h2o_ex|h2oEx}' 'CO2Ex'] -> MCS ['{EX_for_ex|FormEx}' '{EX_h2o_ex|h2oEx}' 'CO2Ex']\n", "Found solution with objective value 3.0\n", - "CS (9, 49, 62) -> MCS (9, 49, 62)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ACKr|PTAr}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ACKr|PTAr}']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 24) -> MCS (5, 6, 24)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SUCCt3pp'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (24, 54, 62) -> MCS (24, 54, 62)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SuccEx'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (9, 45, 49) -> MCS (9, 45, 49)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'PPC'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (21, 56, 60) -> MCS (21, 56, 60)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FUM'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FUM']\n", "Found solution with objective value 3.0\n", - "CS (21, 56, 58) -> MCS (21, 56, 58)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCCt2_2pp'] -> MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (9, 49, 61) -> MCS (9, 49, 61)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SuccUp'] -> MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (9, 14, 49) -> MCS (9, 14, 49)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'CO2Ex'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'CO2Ex']\n", "Found solution with objective value 3.0\n", - "CS (9, 16, 49) -> MCS (9, 16, 49)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'SUCDi'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (3, 7, 62) -> MCS (3, 7, 62)\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 33) -> MCS (5, 6, 33)\n", + "CS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}'] -> MCS ['{EX_etoh_ex|ACALD|ALCD2x|EthEx}' '{EX_h_ex|h_pEx}'\n", + " '{EX_o2_ex|CYTBO3_4pp|O2Up}']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h2o_ex|h2oEx}' '{ACKr|PTAr}' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' '{ACKr|PTAr}' 'PFL']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'AcUp']\n", "Found solution with objective value 3.0\n", + "MCS ['{GAPD|PGK}' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{GAPD|PGK}']\n", "Stopping enumeration with status infeasible\n", "195 MCS found.\n", - "[('ENO', 'GAPD'), ('GAPD', 'PGM'), ('ENO', 'PGK'), ('PGK', 'PGM'), ('ACONTa',), ('ACONTb',), ('CS',), ('ACALD', 'h2oEx'), ('ALCD2x', 'h2oEx'), ('EthEx', 'h2oEx'), ('ADK1',), ('CO2Ex', 'h_pEx'), ('GAPD', 'PPCK', 'PPS'), ('PGK', 'PPCK', 'PPS'), ('FUM', 'PPC'), ('RPI',), ('G6PDH2r', 'TALA'), ('PGL', 'TALA'), ('G6PDH2r', 'TKT1'), ('PGL', 'TKT1'), ('SUCCt3pp', 'SUCDi'), ('MDH', 'PPC'), ('GND', 'TKT2'), ('SuccEx', 'SUCDi'), ('CYTBO3_4pp', 'ENO'), ('ENO', 'O2Up'), ('CYTBO3_4pp', 'PGM'), ('O2Up', 'PGM'), ('AKGDH', 'SUCOAS'), ('FUM', 'SUCCt3pp'), ('ENO', 'PPCK', 'PPS'), ('PGM', 'PPCK', 'PPS'), ('G3PD2', 'GLYK'), ('GND', 'RPE'), ('CYTBO3_4pp', 'GAPD'), ('GAPD', 'O2Up'), ('CYTBO3_4pp', 'PGK'), ('O2Up', 'PGK'), ('RPE', 'TALA'), ('RPE', 'TKT1'), ('TALA', 'TKT2'), ('TKT1', 'TKT2'), ('ICL', 'PPC', 'SUCCt2_2pp'), ('MALS', 'PPC', 'SUCCt2_2pp'), ('CO2Ex', 'PPC'), ('CO2Ex', 'GlcUp', 'h2oEx'), ('G3PD2', 'GlycUp'), ('GAPD', 'MDH', 'PPS'), ('MDH', 'PGK', 'PPS'), ('PPC', 'SUCDi'), ('GAPD', 'GlcUp', 'TPI'), ('GlcUp', 'PGK', 'TPI'), ('AcEx', 'ACKr'), ('AcEx', 'PTAr'), ('Growth',), ('RPE', 'TKT2'), ('ENO', 'MDH', 'PPS'), ('MDH', 'PGM', 'PPS'), ('ICDHyr',), ('FBA', 'PGI', 'TKT2'), ('FRD2', 'FUM'), ('FUM', 'NADH17pp'), ('CO2Ex', 'SUCCt3pp', 'SUCOAS'), ('GND', 'TALA'), ('GND', 'TKT1'), ('CO2Ex', 'FUM', 'TKT2'), ('CO2Ex', 'FormEx', 'h2oEx'), ('GlcUp', 'PGI', 'TKT2'), ('ENO', 'GlcUp', 'TPI'), ('GlcUp', 'PGM', 'TPI'), ('GlcUp', 'PGI', 'RPE'), ('GlcUp', 'PGI', 'TALA'), ('GlcUp', 'PGI', 'TKT1'), ('PFK', 'PGI', 'TKT2'), ('FUM', 'SuccEx'), ('F6PA', 'FBP', 'GlcUp'), ('FBP', 'GlcUp', 'GLYCDx'), ('ATPS4rpp', 'CYTBO3_4pp'), ('ATPS4rpp', 'O2Up'), ('G6PDH2r', 'TKT2'), ('PGL', 'TKT2'), ('G6PDH2r', 'RPE'), ('PGL', 'RPE'), ('GlycUp', 'PFK', 'TPI'), ('CO2Ex', 'SUCCt3pp', 'TALA'), ('CO2Ex', 'SUCCt3pp', 'TKT1'), ('CO2Ex', 'ENO', 'PPS'), ('CO2Ex', 'PGM', 'PPS'), ('CO2Ex', 'SuccEx', 'SUCOAS'), ('GlcUp', 'h2oEx', 'SUCDi'), ('CO2Ex', 'GlcUp', 'GlycUp'), ('CO2Ex', 'SuccEx', 'TALA'), ('CO2Ex', 'SuccEx', 'TKT1'), ('CO2Ex', 'h2oEx', 'PFL'), ('CO2Ex', 'GAPD', 'PPS'), ('CO2Ex', 'PGK', 'PPS'), ('CO2Ex', 'FRD2', 'SUCOAS'), ('CO2Ex', 'NADH17pp', 'SUCOAS'), ('CO2Ex', 'FRD2', 'TALA'), ('CO2Ex', 'NADH17pp', 'TALA'), ('CO2Ex', 'FRD2', 'TKT1'), ('CO2Ex', 'NADH17pp', 'TKT1'), ('ACKr', 'h_pEx', 'SUCCt2_2pp'), ('h_pEx', 'PTAr', 'SUCCt2_2pp'), ('ACKr', 'h_pEx', 'SuccUp'), ('h_pEx', 'PTAr', 'SuccUp'), ('F6PA', 'FBA', 'GlcUp'), ('FBA', 'GlcUp', 'GLYCDx'), ('GLYK', 'PFK', 'TPI'), ('FBA', 'GLYK', 'TPI'), ('AcUp', 'h_pEx', 'SUCCt2_2pp'), ('FBA', 'GlycUp', 'TPI'), ('AcUp', 'h_pEx', 'SuccUp'), ('CYTBO3_4pp', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'O2Up'), ('ICL', 'PPC', 'SuccUp'), ('MALS', 'PPC', 'SuccUp'), ('CYTBO3_4pp', 'NADH16pp', 'SUCCt3pp'), ('NADH16pp', 'O2Up', 'SUCCt3pp'), ('ACALD', 'CYTBO3_4pp', 'GlcUp'), ('ALCD2x', 'CYTBO3_4pp', 'GlcUp'), ('CYTBO3_4pp', 'EthEx', 'GlcUp'), ('ACALD', 'GlcUp', 'O2Up'), ('ALCD2x', 'GlcUp', 'O2Up'), ('EthEx', 'GlcUp', 'O2Up'), ('CYTBO3_4pp', 'GlcUp', 'PYK'), ('GlcUp', 'O2Up', 'PYK'), ('CYTBO3_4pp', 'NADH16pp', 'SuccEx'), ('NADH16pp', 'O2Up', 'SuccEx'), ('ACKr', 'PDH', 'PFL'), ('PDH', 'PFL', 'PTAr'), ('CYTBO3_4pp', 'NADH16pp', 'PPC'), ('NADH16pp', 'O2Up', 'PPC'), ('ENO', 'FUM', 'PPS'), ('FUM', 'PGM', 'PPS'), ('CO2Ex', 'FUM', 'RPE'), ('FUM', 'GAPD', 'PPS'), ('FUM', 'PGK', 'PPS'), ('ACKr', 'h_pEx', 'SUCDi'), ('h_pEx', 'PTAr', 'SUCDi'), ('AcUp', 'h_pEx', 'SUCDi'), ('CO2Ex', 'SUCCt3pp', 'TKT2'), ('CO2Ex', 'SuccEx', 'TKT2'), ('FBP', 'GlcUp', 'GlycUp'), ('ACKr', 'FUM', 'h_pEx'), ('FUM', 'h_pEx', 'PTAr'), ('FBA', 'GlcUp', 'GlycUp'), ('AcUp', 'FUM', 'h_pEx'), ('CO2Ex', 'FRD2', 'RPE'), ('CO2Ex', 'NADH17pp', 'RPE'), ('ACKr', 'CYTBO3_4pp', 'GlcUp'), ('ACKr', 'GlcUp', 'O2Up'), ('CYTBO3_4pp', 'GlcUp', 'PTAr'), ('GlcUp', 'O2Up', 'PTAr'), ('CO2Ex', 'FRD2', 'TKT2'), ('CO2Ex', 'NADH17pp', 'TKT2'), ('FUM', 'h2oEx', 'PFL'), ('GAPD', 'PPS', 'SUCDi'), ('PGK', 'PPS', 'SUCDi'), ('FUM', 'GlcUp', 'h2oEx'), ('FUM', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'TPI'), ('GlcUp', 'GlycUp', 'SUCDi'), ('ACALD', 'CYTBO3_4pp', 'h_pEx'), ('ALCD2x', 'CYTBO3_4pp', 'h_pEx'), ('CYTBO3_4pp', 'EthEx', 'h_pEx'), ('ACALD', 'h_pEx', 'O2Up'), ('ALCD2x', 'h_pEx', 'O2Up'), ('EthEx', 'h_pEx', 'O2Up'), ('h2oEx', 'PFL', 'SUCCt2_2pp'), ('h2oEx', 'PFL', 'SUCDi'), ('ENO', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'PGM'), ('ENO', 'PPS', 'SUCDi'), ('PGM', 'PPS', 'SUCDi'), ('h2oEx', 'NADH16pp', 'PFL'), ('CO2Ex', 'RPE', 'SUCCt3pp'), ('CO2Ex', 'RPE', 'SuccEx'), ('h2oEx', 'PFL', 'SuccUp'), ('ACKr', 'h2oEx', 'PFL'), ('h2oEx', 'PFL', 'PTAr'), ('AcUp', 'h2oEx', 'PFL'), ('ACALD', 'h_pEx', 'SUCDi'), ('ALCD2x', 'h_pEx', 'SUCDi'), ('EthEx', 'h_pEx', 'SUCDi'), ('GAPD', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'PGK'), ('AcUp', 'CYTBO3_4pp', 'GlcUp'), ('AcUp', 'GlcUp', 'O2Up'), ('GlcUp', 'GlycUp', 'h_pEx'), ('CYTBO3_4pp', 'GlcUp', 'TPI'), ('GlcUp', 'O2Up', 'TPI'), ('ACALD', 'FUM', 'h_pEx'), ('ALCD2x', 'FUM', 'h_pEx'), ('EthEx', 'FUM', 'h_pEx')]\n", + "[('ICDHyr',), ('ADK1',), ('ACONTa',), ('ACONTb',), ('CS',), ('RPI',), ('Growth',), ('TALA', 'TKT2'), ('TKT1', 'TKT2'), ('CYTBO3_4pp', 'GAPD'), ('GAPD', 'O2Up'), ('CYTBO3_4pp', 'PGK'), ('O2Up', 'PGK'), ('AcEx', 'ACKr'), ('AcEx', 'PTAr'), ('CO2Ex', 'h_pEx'), ('GND', 'RPE'), ('FUM', 'SuccEx'), ('G3PD2', 'GLYK'), ('RPE', 'TKT2'), ('CYTBO3_4pp', 'ENO'), ('ENO', 'O2Up'), ('CYTBO3_4pp', 'PGM'), ('O2Up', 'PGM'), ('RPE', 'TALA'), ('RPE', 'TKT1'), ('AKGDH', 'SUCOAS'), ('G3PD2', 'GlycUp'), ('ENO', 'GAPD'), ('GAPD', 'PGM'), ('ENO', 'PGK'), ('PGK', 'PGM'), ('CO2Ex', 'PPC'), ('SUCCt3pp', 'SUCDi'), ('ACALD', 'h2oEx'), ('ALCD2x', 'h2oEx'), ('EthEx', 'h2oEx'), ('ATPS4rpp', 'CYTBO3_4pp'), ('ATPS4rpp', 'O2Up'), ('MDH', 'PPC'), ('FUM', 'PPC'), ('FRD2', 'FUM'), ('FUM', 'NADH17pp'), ('SuccEx', 'SUCDi'), ('FUM', 'SUCCt3pp'), ('GND', 'TALA'), ('GND', 'TKT1'), ('G6PDH2r', 'TALA'), ('PGL', 'TALA'), ('G6PDH2r', 'TKT1'), ('PGL', 'TKT1'), ('GND', 'TKT2'), ('G6PDH2r', 'RPE'), ('PGL', 'RPE'), ('G6PDH2r', 'TKT2'), ('PGL', 'TKT2'), ('PPC', 'SUCDi'), ('GlcUp', 'GlycUp', 'h_pEx'), ('FBA', 'GLYK', 'TPI'), ('FBA', 'GlcUp', 'GlycUp'), ('PFK', 'PGI', 'TKT2'), ('AcUp', 'FUM', 'h_pEx'), ('CO2Ex', 'h2oEx', 'PFL'), ('CYTBO3_4pp', 'GlcUp', 'TPI'), ('GlcUp', 'O2Up', 'TPI'), ('CO2Ex', 'RPE', 'SuccEx'), ('GAPD', 'PPCK', 'PPS'), ('PGK', 'PPCK', 'PPS'), ('CO2Ex', 'FRD2', 'TALA'), ('CO2Ex', 'NADH17pp', 'TALA'), ('CO2Ex', 'FRD2', 'TKT1'), ('CO2Ex', 'NADH17pp', 'TKT1'), ('GAPD', 'GlcUp', 'TPI'), ('GlcUp', 'PGK', 'TPI'), ('ICL', 'PPC', 'SUCCt2_2pp'), ('MALS', 'PPC', 'SUCCt2_2pp'), ('CO2Ex', 'ENO', 'PPS'), ('CO2Ex', 'PGM', 'PPS'), ('F6PA', 'FBP', 'GlcUp'), ('FBP', 'GlcUp', 'GLYCDx'), ('FUM', 'GlcUp', 'h2oEx'), ('ACKr', 'h_pEx', 'SUCCt2_2pp'), ('h_pEx', 'PTAr', 'SUCCt2_2pp'), ('ACKr', 'h_pEx', 'SuccUp'), ('h_pEx', 'PTAr', 'SuccUp'), ('ENO', 'PPS', 'SUCDi'), ('PGM', 'PPS', 'SUCDi'), ('F6PA', 'FBA', 'GlcUp'), ('FBA', 'GlcUp', 'GLYCDx'), ('ENO', 'PPCK', 'PPS'), ('PGM', 'PPCK', 'PPS'), ('ICL', 'PPC', 'SuccUp'), ('MALS', 'PPC', 'SuccUp'), ('CO2Ex', 'GAPD', 'PPS'), ('CO2Ex', 'PGK', 'PPS'), ('AcUp', 'h_pEx', 'SUCCt2_2pp'), ('CO2Ex', 'FUM', 'TKT2'), ('CO2Ex', 'GlcUp', 'h2oEx'), ('GLYK', 'PFK', 'TPI'), ('ENO', 'GlcUp', 'TPI'), ('GlcUp', 'PGM', 'TPI'), ('GlcUp', 'PGI', 'RPE'), ('h2oEx', 'PFL', 'SUCDi'), ('GlcUp', 'PGI', 'TKT2'), ('FBA', 'PGI', 'TKT2'), ('CYTBO3_4pp', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'O2Up'), ('AcUp', 'h2oEx', 'PFL'), ('ENO', 'FUM', 'PPS'), ('FUM', 'PGM', 'PPS'), ('ACALD', 'CYTBO3_4pp', 'GlcUp'), ('ALCD2x', 'CYTBO3_4pp', 'GlcUp'), ('CYTBO3_4pp', 'EthEx', 'GlcUp'), ('ACALD', 'GlcUp', 'O2Up'), ('ALCD2x', 'GlcUp', 'O2Up'), ('EthEx', 'GlcUp', 'O2Up'), ('GlcUp', 'PGI', 'TALA'), ('GlcUp', 'PGI', 'TKT1'), ('CYTBO3_4pp', 'GlcUp', 'PYK'), ('GlcUp', 'O2Up', 'PYK'), ('ACKr', 'FUM', 'h_pEx'), ('FUM', 'h_pEx', 'PTAr'), ('GlycUp', 'PFK', 'TPI'), ('AcUp', 'h_pEx', 'SuccUp'), ('FBA', 'GlycUp', 'TPI'), ('ENO', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'PGM'), ('ACKr', 'PDH', 'PFL'), ('PDH', 'PFL', 'PTAr'), ('GlcUp', 'GlycUp', 'TPI'), ('FBP', 'GlcUp', 'GlycUp'), ('CO2Ex', 'SuccEx', 'SUCOAS'), ('CO2Ex', 'FRD2', 'RPE'), ('CO2Ex', 'NADH17pp', 'RPE'), ('CO2Ex', 'FRD2', 'TKT2'), ('CO2Ex', 'NADH17pp', 'TKT2'), ('CO2Ex', 'FRD2', 'SUCOAS'), ('CO2Ex', 'NADH17pp', 'SUCOAS'), ('h2oEx', 'NADH16pp', 'PFL'), ('CO2Ex', 'FUM', 'RPE'), ('CO2Ex', 'RPE', 'SUCCt3pp'), ('CO2Ex', 'SUCCt3pp', 'TKT2'), ('FUM', 'GAPD', 'PPS'), ('FUM', 'PGK', 'PPS'), ('FUM', 'h2oEx', 'PFL'), ('ACALD', 'FUM', 'h_pEx'), ('ALCD2x', 'FUM', 'h_pEx'), ('EthEx', 'FUM', 'h_pEx'), ('ACKr', 'h_pEx', 'SUCDi'), ('h_pEx', 'PTAr', 'SUCDi'), ('AcUp', 'h_pEx', 'SUCDi'), ('ACALD', 'h_pEx', 'SUCDi'), ('ALCD2x', 'h_pEx', 'SUCDi'), ('EthEx', 'h_pEx', 'SUCDi'), ('CO2Ex', 'SuccEx', 'TKT2'), ('CO2Ex', 'SuccEx', 'TALA'), ('CO2Ex', 'SuccEx', 'TKT1'), ('ENO', 'MDH', 'PPS'), ('MDH', 'PGM', 'PPS'), ('GAPD', 'PPS', 'SUCDi'), ('PGK', 'PPS', 'SUCDi'), ('CO2Ex', 'SUCCt3pp', 'SUCOAS'), ('CO2Ex', 'SUCCt3pp', 'TALA'), ('CO2Ex', 'SUCCt3pp', 'TKT1'), ('CO2Ex', 'FormEx', 'h2oEx'), ('ACKr', 'CYTBO3_4pp', 'GlcUp'), ('ACKr', 'GlcUp', 'O2Up'), ('CYTBO3_4pp', 'GlcUp', 'PTAr'), ('GlcUp', 'O2Up', 'PTAr'), ('CYTBO3_4pp', 'NADH16pp', 'SUCCt3pp'), ('NADH16pp', 'O2Up', 'SUCCt3pp'), ('CYTBO3_4pp', 'NADH16pp', 'SuccEx'), ('NADH16pp', 'O2Up', 'SuccEx'), ('CYTBO3_4pp', 'NADH16pp', 'PPC'), ('NADH16pp', 'O2Up', 'PPC'), ('FUM', 'GlcUp', 'GlycUp'), ('h2oEx', 'PFL', 'SUCCt2_2pp'), ('h2oEx', 'PFL', 'SuccUp'), ('CO2Ex', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'SUCDi'), ('GlcUp', 'h2oEx', 'SUCDi'), ('ACALD', 'CYTBO3_4pp', 'h_pEx'), ('ALCD2x', 'CYTBO3_4pp', 'h_pEx'), ('CYTBO3_4pp', 'EthEx', 'h_pEx'), ('ACALD', 'h_pEx', 'O2Up'), ('ALCD2x', 'h_pEx', 'O2Up'), ('EthEx', 'h_pEx', 'O2Up'), ('ACKr', 'h2oEx', 'PFL'), ('h2oEx', 'PFL', 'PTAr'), ('AcUp', 'CYTBO3_4pp', 'GlcUp'), ('AcUp', 'GlcUp', 'O2Up'), ('GAPD', 'MDH', 'PPS'), ('MDH', 'PGK', 'PPS'), ('GAPD', 'GlcUp', 'GlycUp'), ('GlcUp', 'GlycUp', 'PGK')]\n", "True\n" ] } ], - "metadata": {} + "source": [ + "# calculate MCS up to size 3 with \"any MCS\" enumeration method\n", + "ecc2_mcs,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=True,\n", + " include_model_bounds=False, results_cache_dir=results_cache_dir)\n", + "print(len(ecc2_mcs), \"MCS found.\")\n", + "# show MCS as n-tuples of reaction IDs\n", + "ecc2_mcs_rxns= [tuple(reac_id[r] for r in mcs) for mcs in ecc2_mcs]\n", + "print(ecc2_mcs_rxns)\n", + "# check that all MCS disable the first (and only) target\n", + "print(all(mcs_computation.check_mcs(ecc2, ecc2_mue_target[0], ecc2_mcs, optlang.interface.INFEASIBLE)))" + ] }, { "cell_type": "code", "execution_count": 4, - "source": [ - "# %% same calculation without network compression\r\n", - "ecc2_mcsF,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=False,\r\n", - " include_model_bounds=False, results_cache_dir=results_cache_dir)\r\n", - "print(set(ecc2_mcs) == set(ecc2_mcsF)) # check that results agree" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "FVA to find blocked reactions...\n", - "Loaded FVA result from CNA_ECC2comp_FVA_ce7a56f83eb0160025980498b314e26a\n", + "Loaded FVA result from CNA_ECC2comp_FVA_d799bfc002fe911c23c1aed3a650a37b\n", "Found 5 blocked reactions:\n", " ['EX_adp_c', 'EX_mqn8_c', 'EX_nad_c', 'EX_nadp_c', 'EX_q8_c']\n", "Using big M.\n", + "knock_in_idx []\n", "Objective function is empty; set objective to self.minimize_sum_over_z\n", + "Found solution with objective value 3.0\n", + "CS ['TKT1' 'TKT2' 'TPI'] -> MCS ['TKT1' 'TKT2']\n", "Found solution with objective value 1.0\n", + "MCS ['ICDHyr']\n", + "Found solution with objective value 1.0\n", + "MCS ['CS']\n", "Found solution with objective value 3.0\n", - "CS (73, 102, 121) -> MCS (73, 102, 121)\n", - "Found solution with objective value 2.0\n", - "CS (48, 116) -> MCS (48, 116)\n", - "Found solution with objective value 2.0\n", - "CS (66, 104) -> MCS (66, 104)\n", + "CS ['CYTBO3_4pp' 'FBA' 'PGM'] -> MCS ['CYTBO3_4pp' 'PGM']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 104) -> MCS (52, 104)\n", + "CS ['FBA' 'GAPD' 'PGM'] -> MCS ['GAPD' 'PGM']\n", "Found solution with objective value 3.0\n", - "CS (43, 96, 98) -> MCS (43, 96, 98)\n", + "CS ['ATPS4rpp' 'CO2Ex' 'h_pEx'] -> MCS ['CO2Ex' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (113, 115, 116) -> MCS (113, 115)\n", - "Found solution with objective value 2.0\n", - "CS (100, 102) -> MCS (100, 102)\n", + "CS ['CYTBO3_4pp' 'FBA' 'GAPD'] -> MCS ['CYTBO3_4pp' 'GAPD']\n", + "Found solution with objective value 3.0\n", + "CS ['GlcUp' 'PGM' 'TPI'] -> MCS ['GlcUp' 'PGM' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (96, 98, 107) -> MCS (96, 98, 107)\n", + "CS ['ENO' 'O2Up' 'PPCK'] -> MCS ['ENO' 'O2Up']\n", "Found solution with objective value 2.0\n", - "CS (42, 43) -> MCS (42, 43)\n", - "Found solution with objective value 1.0\n", + "CS ['CO2Ex' 'PPC'] -> MCS ['CO2Ex' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (73, 100, 121) -> MCS (73, 100, 121)\n", - "Found solution with objective value 1.0\n", - "Found solution with objective value 1.0\n", + "CS ['ADK1' 'FBA' 'GAPD'] -> MCS ['ADK1']\n", "Found solution with objective value 1.0\n", - "Found solution with objective value 1.0\n", - "Found solution with objective value 1.0\n", - "Found solution with objective value 2.0\n", - "CS (69, 119) -> MCS (69, 119)\n", - "Found solution with objective value 2.0\n", - "CS (119, 120) -> MCS (119, 120)\n", - "Found solution with objective value 2.0\n", - "CS (78, 120) -> MCS (78, 120)\n", - "Found solution with objective value 2.0\n", - "CS (101, 117) -> MCS (101, 117)\n", - "Found solution with objective value 2.0\n", - "CS (111, 115) -> MCS (111, 115)\n", - "Found solution with objective value 2.0\n", - "CS (69, 109) -> MCS (69, 109)\n", + "MCS ['RPI']\n", "Found solution with objective value 3.0\n", - "CS (70, 95, 98) -> MCS (70, 95)\n", - "Found solution with objective value 2.0\n", - "CS (104, 115) -> MCS (104, 115)\n", - "Found solution with objective value 2.0\n", - "CS (51, 55) -> MCS (51, 55)\n", + "CS ['G3PD2' 'PGK' 'PGM'] -> MCS ['PGK' 'PGM']\n", + "Found solution with objective value 3.0\n", + "CS ['CYTBO3_4pp' 'FBA' 'PGK'] -> MCS ['CYTBO3_4pp' 'PGK']\n", + "Found solution with objective value 3.0\n", + "CS ['FBA' 'PGL' 'RPE'] -> MCS ['PGL' 'RPE']\n", + "Found solution with objective value 3.0\n", + "CS ['FBA' 'GND' 'RPE'] -> MCS ['GND' 'RPE']\n", + "Found solution with objective value 3.0\n", + "CS ['GAPD' 'O2Up' 'RPE'] -> MCS ['GAPD' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (55, 73, 75) -> MCS (55, 73, 75)\n", + "CS ['ATPS4rpp' 'CYTBO3_4pp' 'ENO'] -> MCS ['CYTBO3_4pp' 'ENO']\n", + "Found solution with objective value 3.0\n", + "CS ['ENO' 'GAPD' 'LDH_D'] -> MCS ['ENO' 'GAPD']\n", + "Found solution with objective value 3.0\n", + "CS ['GlcUp' 'PGK' 'TPI'] -> MCS ['GlcUp' 'PGK' 'TPI']\n", "Found solution with objective value 2.0\n", - "CS (109, 117) -> MCS (109, 117)\n", + "CS ['AcEx' 'PTAr'] -> MCS ['AcEx' 'PTAr']\n", "Found solution with objective value 2.0\n", - "CS (117, 120) -> MCS (117, 120)\n", + "CS ['FUM' 'NADH17pp'] -> MCS ['FUM' 'NADH17pp']\n", "Found solution with objective value 3.0\n", - "CS (70, 102, 121) -> MCS (70, 102)\n", + "CS ['GAPD' 'PPCK' 'PPS'] -> MCS ['GAPD' 'PPCK' 'PPS']\n", "Found solution with objective value 2.0\n", - "CS (109, 120) -> MCS (109, 120)\n", + "CS ['FRD2' 'FUM'] -> MCS ['FRD2' 'FUM']\n", "Found solution with objective value 2.0\n", - "CS (65, 66) -> MCS (65, 66)\n", + "CS ['ENO' 'PGK'] -> MCS ['ENO' 'PGK']\n", "Found solution with objective value 3.0\n", - "CS (97, 99, 120) -> MCS (97, 99, 120)\n", - "Found solution with objective value 2.0\n", - "CS (67, 76) -> MCS (67, 76)\n", + "CS ['Growth' 'FBA' 'TPI'] -> MCS ['Growth']\n", "Found solution with objective value 3.0\n", - "CS (81, 88, 104) -> MCS (88, 104)\n", + "CS ['ATPS4rpp' 'CYTBO3_4pp' 'FBA'] -> MCS ['ATPS4rpp' 'CYTBO3_4pp']\n", "Found solution with objective value 2.0\n", - "CS (52, 79) -> MCS (52, 79)\n", + "CS ['TALA' 'TKT2'] -> MCS ['TALA' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (58, 95) -> MCS (58, 95)\n", + "CS ['AKGDH' 'SUCOAS'] -> MCS ['AKGDH' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (88, 102, 106) -> MCS (88, 102, 106)\n", + "CS ['PGK' 'PPCK' 'PPS'] -> MCS ['PGK' 'PPCK' 'PPS']\n", + "Found solution with objective value 3.0\n", + "CS ['ATPS4rpp' 'O2Up' 'PGK'] -> MCS ['O2Up' 'PGK']\n", "Found solution with objective value 2.0\n", - "CS (66, 93) -> MCS (66, 93)\n", + "CS ['G6PDH2r' 'TALA'] -> MCS ['G6PDH2r' 'TALA']\n", "Found solution with objective value 2.0\n", - "CS (95, 102) -> MCS (95, 102)\n", + "CS ['RPE' 'TKT2'] -> MCS ['RPE' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (61, 76, 121) -> MCS (61, 76, 121)\n", + "CS ['FBA' 'PGI' 'TKT2'] -> MCS ['FBA' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (55, 58, 99) -> MCS (55, 58)\n", - "Found solution with objective value 2.0\n", - "CS (49, 81) -> MCS (49, 81)\n", + "CS ['ACKr' 'G3PD2' 'GlycUp'] -> MCS ['G3PD2' 'GlycUp']\n", + "Found solution with objective value 1.0\n", + "MCS ['ACONTa']\n", + "Found solution with objective value 3.0\n", + "CS ['GND' 'MDH' 'TALA'] -> MCS ['GND' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (43, 79, 114) -> MCS (43, 79, 114)\n", + "CS ['ACKr' 'ATPS4rpp' 'O2Up'] -> MCS ['ATPS4rpp' 'O2Up']\n", + "Found solution with objective value 2.0\n", + "CS ['MDH' 'PPC'] -> MCS ['MDH' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (52, 58, 106) -> MCS (52, 58, 106)\n", + "CS ['FUM' 'PGK' 'PPS'] -> MCS ['FUM' 'PGK' 'PPS']\n", + "Found solution with objective value 2.0\n", + "CS ['ACONTb' 'TALA'] -> MCS ['ACONTb']\n", "Found solution with objective value 3.0\n", - "CS (55, 81, 100) -> MCS (55, 100)\n", + "CS ['CO2Ex' 'FRD2' 'RPE'] -> MCS ['CO2Ex' 'FRD2' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (52, 81, 98) -> MCS (52, 81, 98)\n", + "CS ['ACKr' 'PDH' 'PFL'] -> MCS ['ACKr' 'PDH' 'PFL']\n", "Found solution with objective value 2.0\n", - "CS (58, 100) -> MCS (58, 100)\n", + "CS ['O2Up' 'PGM'] -> MCS ['O2Up' 'PGM']\n", + "Found solution with objective value 3.0\n", + "CS ['MALS' 'PPC' 'SuccUp'] -> MCS ['MALS' 'PPC' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (58, 70, 99) -> MCS (58, 70)\n", + "CS ['ENO' 'GlcUp' 'TPI'] -> MCS ['ENO' 'GlcUp' 'TPI']\n", "Found solution with objective value 2.0\n", - "CS (42, 107) -> MCS (42, 107)\n", + "CS ['AcEx' 'ACKr'] -> MCS ['AcEx' 'ACKr']\n", "Found solution with objective value 3.0\n", - "CS (100, 105, 106) -> MCS (100, 105, 106)\n", + "CS ['ENO' 'PPCK' 'PPS'] -> MCS ['ENO' 'PPCK' 'PPS']\n", "Found solution with objective value 2.0\n", - "CS (78, 109) -> MCS (78, 109)\n", + "CS ['GND' 'TKT2'] -> MCS ['GND' 'TKT2']\n", + "Found solution with objective value 3.0\n", + "CS ['GAPD' 'GlcUp' 'TPI'] -> MCS ['GAPD' 'GlcUp' 'TPI']\n", "Found solution with objective value 2.0\n", - "CS (109, 119) -> MCS (109, 119)\n", + "CS ['FUM' 'PPC'] -> MCS ['FUM' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (52, 64, 81) -> MCS (52, 64, 81)\n", + "CS ['PGM' 'PPCK' 'PPS'] -> MCS ['PGM' 'PPCK' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (51, 67, 75) -> MCS (67, 75)\n", + "CS ['ICL' 'PPC' 'SUCCt2_2pp'] -> MCS ['ICL' 'PPC' 'SUCCt2_2pp']\n", "Found solution with objective value 2.0\n", - "CS (95, 100) -> MCS (95, 100)\n", - "Found solution with objective value 3.0\n", - "CS (73, 75, 79) -> MCS (73, 75, 79)\n", + "CS ['FUM' 'SUCCt3pp'] -> MCS ['FUM' 'SUCCt3pp']\n", "Found solution with objective value 2.0\n", - "CS (51, 95) -> MCS (51, 95)\n", + "CS ['FUM' 'SuccEx'] -> MCS ['FUM' 'SuccEx']\n", "Found solution with objective value 2.0\n", - "CS (78, 117) -> MCS (78, 117)\n", + "CS ['RPE' 'TKT1'] -> MCS ['RPE' 'TKT1']\n", "Found solution with objective value 2.0\n", - "CS (69, 117) -> MCS (69, 117)\n", + "CS ['PGL' 'TALA'] -> MCS ['PGL' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (69, 116, 120) -> MCS (69, 120)\n", - "Found solution with objective value 2.0\n", - "CS (59, 81) -> MCS (59, 81)\n", + "CS ['GlcUp' 'RPE' 'TALA'] -> MCS ['RPE' 'TALA']\n", + "Found solution with objective value 3.0\n", + "CS ['GlcUp' 'h2oEx' 'SUCDi'] -> MCS ['GlcUp' 'h2oEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (43, 79, 112) -> MCS (43, 79, 112)\n", + "CS ['SUCCt3pp' 'SUCDi' 'SUCOAS'] -> MCS ['SUCCt3pp' 'SUCDi']\n", "Found solution with objective value 2.0\n", - "CS (78, 119) -> MCS (78, 119)\n", + "CS ['G3PD2' 'GLYK'] -> MCS ['G3PD2' 'GLYK']\n", "Found solution with objective value 3.0\n", - "CS (76, 97, 121) -> MCS (76, 97, 121)\n", + "CS ['SuccEx' 'SUCDi' 'SUCOAS'] -> MCS ['SuccEx' 'SUCDi']\n", + "Found solution with objective value 2.0\n", + "CS ['PPC' 'SUCDi'] -> MCS ['PPC' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (79, 107, 112) -> MCS (79, 107, 112)\n", + "CS ['PDH' 'PFL' 'PTAr'] -> MCS ['PDH' 'PFL' 'PTAr']\n", + "Found solution with objective value 2.0\n", + "CS ['GND' 'TKT1'] -> MCS ['GND' 'TKT1']\n", + "Found solution with objective value 2.0\n", + "CS ['PGL' 'TKT1'] -> MCS ['PGL' 'TKT1']\n", + "Found solution with objective value 2.0\n", + "CS ['G6PDH2r' 'RPE'] -> MCS ['G6PDH2r' 'RPE']\n", + "Found solution with objective value 2.0\n", + "CS ['G6PDH2r' 'TKT2'] -> MCS ['G6PDH2r' 'TKT2']\n", + "Found solution with objective value 2.0\n", + "CS ['G6PDH2r' 'TKT1'] -> MCS ['G6PDH2r' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (102, 105, 106) -> MCS (102, 105, 106)\n", + "CS ['GlcUp' 'PGI' 'RPE'] -> MCS ['GlcUp' 'PGI' 'RPE']\n", + "Found solution with objective value 2.0\n", + "CS ['PGL' 'TKT2'] -> MCS ['PGL' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (55, 70, 81) -> MCS (55, 70)\n", + "CS ['ACKr' 'h_pEx' 'SUCCt2_2pp'] -> MCS ['ACKr' 'h_pEx' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (70, 105, 106) -> MCS (70, 105, 106)\n", + "CS ['FUM' 'GAPD' 'PPS'] -> MCS ['FUM' 'GAPD' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (70, 73, 121) -> MCS (70, 73, 121)\n", - "Found solution with objective value 2.0\n", - "CS (66, 111) -> MCS (66, 111)\n", - "Found solution with objective value 2.0\n", - "CS (101, 119) -> MCS (101, 119)\n", + "CS ['h_pEx' 'PTAr' 'SuccUp'] -> MCS ['h_pEx' 'PTAr' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (73, 99, 120) -> MCS (73, 99, 120)\n", + "CS ['PFK' 'PGI' 'TKT2'] -> MCS ['PFK' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (66, 81, 98) -> MCS (66, 81, 98)\n", + "CS ['FBA' 'GLYK' 'TPI'] -> MCS ['FBA' 'GLYK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (58, 88, 106) -> MCS (58, 88, 106)\n", + "CS ['FBA' 'GlycUp' 'TPI'] -> MCS ['FBA' 'GlycUp' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (52, 102, 106) -> MCS (52, 102, 106)\n", + "CS ['h_pEx' 'PTAr' 'SUCCt2_2pp'] -> MCS ['h_pEx' 'PTAr' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (79, 107, 114) -> MCS (79, 107, 114)\n", + "CS ['ACKr' 'h_pEx' 'SuccUp'] -> MCS ['ACKr' 'h_pEx' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (58, 105, 106) -> MCS (58, 105, 106)\n", + "CS ['AcUp' 'h_pEx' 'SUCCt2_2pp'] -> MCS ['AcUp' 'h_pEx' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (81, 98, 115) -> MCS (81, 98, 115)\n", + "CS ['AcUp' 'h_pEx' 'SuccUp'] -> MCS ['AcUp' 'h_pEx' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (46, 79, 112) -> MCS (46, 79, 112)\n", + "CS ['GlcUp' 'PGI' 'TKT2'] -> MCS ['GlcUp' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (60, 62, 73) -> MCS (60, 62, 73)\n", + "CS ['ICL' 'PPC' 'SuccUp'] -> MCS ['ICL' 'PPC' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (62, 73, 74) -> MCS (62, 73, 74)\n", + "CS ['h2oEx' 'NADH16pp' 'PFL'] -> MCS ['h2oEx' 'NADH16pp' 'PFL']\n", + "Found solution with objective value 2.0\n", + "MCS ['EthEx' 'h2oEx']\n", + "Found solution with objective value 2.0\n", + "CS ['ALCD2x' 'h2oEx'] -> MCS ['ALCD2x' 'h2oEx']\n", + "Found solution with objective value 2.0\n", + "CS ['ACALD' 'h2oEx'] -> MCS ['ACALD' 'h2oEx']\n", "Found solution with objective value 3.0\n", - "CS (73, 99, 117) -> MCS (73, 99, 117)\n", + "CS ['FUM' 'h2oEx' 'PFL'] -> MCS ['FUM' 'h2oEx' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (46, 79, 114) -> MCS (46, 79, 114)\n", + "CS ['h2oEx' 'PFL' 'SUCDi'] -> MCS ['h2oEx' 'PFL' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (60, 61, 73) -> MCS (60, 61, 73)\n", - "Found solution with objective value 2.0\n", - "CS (66, 113) -> MCS (66, 113)\n", + "CS ['FUM' 'GlcUp' 'h2oEx'] -> MCS ['FUM' 'GlcUp' 'h2oEx']\n", "Found solution with objective value 3.0\n", - "CS (73, 99, 119) -> MCS (73, 99, 119)\n", + "CS ['GlcUp' 'PGI' 'TALA'] -> MCS ['GlcUp' 'PGI' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (41, 66, 79) -> MCS (41, 66, 79)\n", - "Found solution with objective value 2.0\n", - "CS (101, 120) -> MCS (101, 120)\n", + "CS ['GLYK' 'PFK' 'TPI'] -> MCS ['GLYK' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (75, 97, 121) -> MCS (75, 97, 121)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'SUCOAS'] -> MCS ['CO2Ex' 'SUCCt3pp' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (61, 75, 121) -> MCS (61, 75, 121)\n", + "CS ['MALS' 'PPC' 'SUCCt2_2pp'] -> MCS ['MALS' 'PPC' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (61, 99, 120) -> MCS (61, 99, 120)\n", - "Found solution with objective value 2.0\n", - "CS (101, 109) -> MCS (101, 109)\n", - "Found solution with objective value 2.0\n", + "CS ['ACKr' 'FUM' 'h_pEx'] -> MCS ['ACKr' 'FUM' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (43, 81, 98) -> MCS (43, 81, 98)\n", + "CS ['GlcUp' 'PGI' 'TKT1'] -> MCS ['GlcUp' 'PGI' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (61, 73, 74) -> MCS (61, 73, 74)\n", + "CS ['NADH16pp' 'O2Up' 'SuccEx'] -> MCS ['NADH16pp' 'O2Up' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (102, 106, 115) -> MCS (102, 106, 115)\n", + "CS ['CYTBO3_4pp' 'NADH16pp' 'SUCCt3pp'] -> MCS ['CYTBO3_4pp' 'NADH16pp' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (73, 99, 109) -> MCS (73, 99, 109)\n", - "Found solution with objective value 2.0\n", + "CS ['CYTBO3_4pp' 'NADH16pp' 'SuccEx'] -> MCS ['CYTBO3_4pp' 'NADH16pp' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (58, 73, 121) -> MCS (58, 73, 121)\n", + "CS ['GlcUp' 'GlycUp' 'O2Up'] -> MCS ['GlcUp' 'GlycUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (84, 104, 112) -> MCS (84, 104, 112)\n", + "CS ['ACALD' 'GlcUp' 'O2Up'] -> MCS ['ACALD' 'GlcUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (49, 79, 95) -> MCS (49, 79, 95)\n", + "CS ['CO2Ex' 'h2oEx' 'PFL'] -> MCS ['CO2Ex' 'h2oEx' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (58, 66, 106) -> MCS (58, 66, 106)\n", + "CS ['ALCD2x' 'GlcUp' 'O2Up'] -> MCS ['ALCD2x' 'GlcUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (59, 79, 95) -> MCS (59, 79, 95)\n", + "CS ['EthEx' 'GlcUp' 'O2Up'] -> MCS ['EthEx' 'GlcUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (81, 92, 98) -> MCS (81, 92, 98)\n", + "CS ['GlcUp' 'O2Up' 'PYK'] -> MCS ['GlcUp' 'O2Up' 'PYK']\n", "Found solution with objective value 3.0\n", - "CS (41, 55, 79) -> MCS (41, 55, 79)\n", + "CS ['GAPD' 'GlcUp' 'GlycUp'] -> MCS ['GAPD' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (41, 79, 95) -> MCS (41, 79, 95)\n", + "CS ['FUM' 'PGM' 'PPS'] -> MCS ['FUM' 'PGM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (73, 81, 115) -> MCS (73, 81, 115)\n", + "CS ['ENO' 'FUM' 'PPS'] -> MCS ['ENO' 'FUM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (87, 104, 112) -> MCS (87, 104, 112)\n", + "CS ['CO2Ex' 'GAPD' 'PPS'] -> MCS ['CO2Ex' 'GAPD' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (92, 95, 113) -> MCS (92, 95, 113)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'TKT1'] -> MCS ['CO2Ex' 'SUCCt3pp' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (87, 104, 114) -> MCS (87, 104, 114)\n", + "CS ['ENO' 'GlcUp' 'GlycUp'] -> MCS ['ENO' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (84, 104, 114) -> MCS (84, 104, 114)\n", + "CS ['GlycUp' 'PFK' 'TPI'] -> MCS ['GlycUp' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (49, 55, 73) -> MCS (49, 55, 73)\n", + "CS ['NADH16pp' 'O2Up' 'SUCCt3pp'] -> MCS ['NADH16pp' 'O2Up' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (55, 59, 73) -> MCS (55, 59, 73)\n", + "CS ['CO2Ex' 'PGK' 'PPS'] -> MCS ['CO2Ex' 'PGK' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (41, 55, 73) -> MCS (41, 55, 73)\n", + "CS ['ACKr' 'GlcUp' 'O2Up'] -> MCS ['ACKr' 'GlcUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (55, 73, 108) -> MCS (55, 73, 108)\n", + "CS ['GlcUp' 'O2Up' 'PTAr'] -> MCS ['GlcUp' 'O2Up' 'PTAr']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 119) -> MCS (52, 93, 119)\n", + "CS ['AcUp' 'GlcUp' 'O2Up'] -> MCS ['AcUp' 'GlcUp' 'O2Up']\n", "Found solution with objective value 3.0\n", - "CS (70, 106, 115) -> MCS (70, 106, 115)\n", + "CS ['CO2Ex' 'FormEx' 'h2oEx'] -> MCS ['CO2Ex' 'FormEx' 'h2oEx']\n", "Found solution with objective value 3.0\n", - "CS (55, 92, 113) -> MCS (55, 92, 113)\n", + "CS ['FBP' 'GlcUp' 'GLYCDx'] -> MCS ['FBP' 'GlcUp' 'GLYCDx']\n", "Found solution with objective value 3.0\n", - "CS (55, 92, 111) -> MCS (55, 92, 111)\n", + "CS ['CYTBO3_4pp' 'GlcUp' 'GlycUp'] -> MCS ['CYTBO3_4pp' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (81, 98, 114) -> MCS (81, 98, 114)\n", + "CS ['GlcUp' 'GlycUp' 'PGM'] -> MCS ['GlcUp' 'GlycUp' 'PGM']\n", "Found solution with objective value 3.0\n", - "CS (52, 65, 117) -> MCS (52, 65, 117)\n", + "CS ['F6PA' 'FBP' 'GlcUp'] -> MCS ['F6PA' 'FBP' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (58, 73, 75) -> MCS (58, 73, 75)\n", + "CS ['FBA' 'GlcUp' 'GLYCDx'] -> MCS ['FBA' 'GlcUp' 'GLYCDx']\n", "Found solution with objective value 3.0\n", - "CS (92, 95, 111) -> MCS (92, 95, 111)\n", + "CS ['F6PA' 'FBA' 'GlcUp'] -> MCS ['F6PA' 'FBA' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (66, 70, 106) -> MCS (66, 70, 106)\n", + "CS ['CO2Ex' 'NADH17pp' 'RPE'] -> MCS ['CO2Ex' 'NADH17pp' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (52, 66, 120) -> MCS (52, 66, 120)\n", + "CS ['FBP' 'GlcUp' 'GlycUp'] -> MCS ['FBP' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (66, 102, 106) -> MCS (66, 102, 106)\n", + "CS ['FBA' 'GlcUp' 'GlycUp'] -> MCS ['FBA' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (55, 73, 107) -> MCS (55, 73, 107)\n", + "CS ['CO2Ex' 'GlcUp' 'GlycUp'] -> MCS ['CO2Ex' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (58, 106, 115) -> MCS (58, 106, 115)\n", + "CS ['CYTBO3_4pp' 'GlcUp' 'PYK'] -> MCS ['CYTBO3_4pp' 'GlcUp' 'PYK']\n", "Found solution with objective value 3.0\n", - "CS (66, 100, 106) -> MCS (66, 100, 106)\n", + "CS ['CO2Ex' 'FRD2' 'TKT1'] -> MCS ['CO2Ex' 'FRD2' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (73, 75, 102) -> MCS (73, 75, 102)\n", + "CS ['ACALD' 'CYTBO3_4pp' 'GlcUp'] -> MCS ['ACALD' 'CYTBO3_4pp' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (81, 98, 107) -> MCS (81, 98, 107)\n", + "CS ['h_pEx' 'PTAr' 'SUCDi'] -> MCS ['h_pEx' 'PTAr' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (62, 73, 75) -> MCS (62, 73, 75)\n", + "CS ['ALCD2x' 'CYTBO3_4pp' 'GlcUp'] -> MCS ['ALCD2x' 'CYTBO3_4pp' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (81, 98, 112) -> MCS (81, 98, 112)\n", + "CS ['CYTBO3_4pp' 'EthEx' 'GlcUp'] -> MCS ['CYTBO3_4pp' 'EthEx' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (73, 75, 100) -> MCS (73, 75, 100)\n", + "CS ['h2oEx' 'PFL' 'SUCCt2_2pp'] -> MCS ['h2oEx' 'PFL' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (61, 73, 75) -> MCS (61, 73, 75)\n", + "CS ['CO2Ex' 'PGM' 'PPS'] -> MCS ['CO2Ex' 'PGM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (52, 65, 116) -> MCS (52, 65, 116)\n", + "CS ['h2oEx' 'PFL' 'SuccUp'] -> MCS ['h2oEx' 'PFL' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (49, 73, 95) -> MCS (49, 73, 95)\n", + "CS ['ACKr' 'h2oEx' 'PFL'] -> MCS ['ACKr' 'h2oEx' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (59, 73, 95) -> MCS (59, 73, 95)\n", + "CS ['CO2Ex' 'RPE' 'SuccEx'] -> MCS ['CO2Ex' 'RPE' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (41, 73, 95) -> MCS (41, 73, 95)\n", + "CS ['CO2Ex' 'NADH17pp' 'SUCOAS'] -> MCS ['CO2Ex' 'NADH17pp' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (73, 95, 108) -> MCS (73, 95, 108)\n", + "CS ['CO2Ex' 'FRD2' 'TALA'] -> MCS ['CO2Ex' 'FRD2' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (49, 55, 79) -> MCS (49, 55, 79)\n", + "CS ['CO2Ex' 'NADH17pp' 'TALA'] -> MCS ['CO2Ex' 'NADH17pp' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (55, 92, 104) -> MCS (55, 92, 104)\n", + "CS ['ACALD' 'CYTBO3_4pp' 'h_pEx'] -> MCS ['ACALD' 'CYTBO3_4pp' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (52, 65, 109) -> MCS (52, 65, 109)\n", + "CS ['CO2Ex' 'FRD2' 'SUCOAS'] -> MCS ['CO2Ex' 'FRD2' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (52, 109, 111) -> MCS (52, 109, 111)\n", + "CS ['CO2Ex' 'SuccEx' 'TALA'] -> MCS ['CO2Ex' 'SuccEx' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (79, 107, 115) -> MCS (79, 107, 115)\n", + "CS ['FUM' 'h_pEx' 'PTAr'] -> MCS ['FUM' 'h_pEx' 'PTAr']\n", "Found solution with objective value 3.0\n", - "CS (52, 65, 120) -> MCS (52, 65, 120)\n", + "CS ['NADH16pp' 'O2Up' 'PPC'] -> MCS ['NADH16pp' 'O2Up' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (55, 59, 79) -> MCS (55, 59, 79)\n", + "CS ['CO2Ex' 'NADH17pp' 'TKT1'] -> MCS ['CO2Ex' 'NADH17pp' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (52, 109, 113) -> MCS (52, 109, 113)\n", + "CS ['AcUp' 'FUM' 'h_pEx'] -> MCS ['AcUp' 'FUM' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (43, 79, 115) -> MCS (43, 79, 115)\n", + "CS ['ACALD' 'FUM' 'h_pEx'] -> MCS ['ACALD' 'FUM' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (52, 65, 119) -> MCS (52, 65, 119)\n", + "CS ['EthEx' 'FUM' 'h_pEx'] -> MCS ['EthEx' 'FUM' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 109) -> MCS (52, 93, 109)\n", + "CS ['CO2Ex' 'ENO' 'PPS'] -> MCS ['CO2Ex' 'ENO' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 117) -> MCS (52, 93, 117)\n", + "CS ['CO2Ex' 'RPE' 'SUCCt3pp'] -> MCS ['CO2Ex' 'RPE' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (46, 79, 115) -> MCS (46, 79, 115)\n", + "CS ['CO2Ex' 'SuccEx' 'TKT2'] -> MCS ['CO2Ex' 'SuccEx' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (59, 79, 115) -> MCS (59, 79, 115)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'TKT2'] -> MCS ['CO2Ex' 'SUCCt3pp' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (43, 66, 79) -> MCS (43, 66, 79)\n", + "CS ['CO2Ex' 'SuccEx' 'SUCOAS'] -> MCS ['CO2Ex' 'SuccEx' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 116) -> MCS (52, 93, 116)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'TALA'] -> MCS ['CO2Ex' 'SUCCt3pp' 'TALA']\n", "Found solution with objective value 3.0\n", - "CS (52, 93, 120) -> MCS (52, 93, 120)\n", + "CS ['CO2Ex' 'SuccEx' 'TKT1'] -> MCS ['CO2Ex' 'SuccEx' 'TKT1']\n", "Found solution with objective value 3.0\n", - "CS (46, 66, 79) -> MCS (46, 66, 79)\n", + "CS ['ACKr' 'h_pEx' 'SUCDi'] -> MCS ['ACKr' 'h_pEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (49, 79, 115) -> MCS (49, 79, 115)\n", + "CS ['CO2Ex' 'FRD2' 'TKT2'] -> MCS ['CO2Ex' 'FRD2' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (66, 79, 107) -> MCS (66, 79, 107)\n", + "CS ['ALCD2x' 'CYTBO3_4pp' 'h_pEx'] -> MCS ['ALCD2x' 'CYTBO3_4pp' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (43, 55, 73) -> MCS (43, 55, 73)\n", + "CS ['AcUp' 'h_pEx' 'SUCDi'] -> MCS ['AcUp' 'h_pEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (49, 66, 79) -> MCS (49, 66, 79)\n", + "CS ['GAPD' 'MDH' 'PPS'] -> MCS ['GAPD' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (55, 73, 121) -> MCS (55, 73, 121)\n", + "CS ['GlcUp' 'GlycUp' 'SUCDi'] -> MCS ['GlcUp' 'GlycUp' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (52, 111, 120) -> MCS (52, 111, 120)\n", + "CS ['MDH' 'PGM' 'PPS'] -> MCS ['MDH' 'PGM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (46, 81, 98) -> MCS (46, 81, 98)\n", + "CS ['ALCD2x' 'FUM' 'h_pEx'] -> MCS ['ALCD2x' 'FUM' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (70, 73, 75) -> MCS (70, 73, 75)\n", + "CS ['ALCD2x' 'h_pEx' 'SUCDi'] -> MCS ['ALCD2x' 'h_pEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (73, 75, 95) -> MCS (73, 75, 95)\n", + "CS ['ENO' 'PPS' 'SUCDi'] -> MCS ['ENO' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (92, 95, 104) -> MCS (92, 95, 104)\n", + "CS ['EthEx' 'h_pEx' 'SUCDi'] -> MCS ['EthEx' 'h_pEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (52, 73, 75) -> MCS (52, 73, 75)\n", + "CS ['CO2Ex' 'NADH17pp' 'TKT2'] -> MCS ['CO2Ex' 'NADH17pp' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (52, 111, 117) -> MCS (52, 111, 117)\n", + "CS ['CO2Ex' 'FUM' 'TKT2'] -> MCS ['CO2Ex' 'FUM' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (52, 111, 119) -> MCS (52, 111, 119)\n", + "CS ['PGM' 'PPS' 'SUCDi'] -> MCS ['PGM' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (66, 73, 75) -> MCS (66, 73, 75)\n", + "CS ['CYTBO3_4pp' 'GlcUp' 'PTAr'] -> MCS ['CYTBO3_4pp' 'GlcUp' 'PTAr']\n", "Found solution with objective value 3.0\n", - "CS (66, 73, 81) -> MCS (66, 73, 81)\n", + "CS ['CO2Ex' 'GlcUp' 'h2oEx'] -> MCS ['CO2Ex' 'GlcUp' 'h2oEx']\n", "Found solution with objective value 3.0\n", - "CS (73, 75, 115) -> MCS (73, 75, 115)\n", + "CS ['ACALD' 'h_pEx' 'SUCDi'] -> MCS ['ACALD' 'h_pEx' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (59, 66, 79) -> MCS (59, 66, 79)\n", + "CS ['CYTBO3_4pp' 'NADH16pp' 'PPC'] -> MCS ['CYTBO3_4pp' 'NADH16pp' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (73, 75, 121) -> MCS (73, 75, 121)\n", + "CS ['CO2Ex' 'FUM' 'RPE'] -> MCS ['CO2Ex' 'FUM' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (52, 111, 116) -> MCS (52, 111, 116)\n", + "MCS ['h2oEx' 'PFL' 'PTAr']\n", "Found solution with objective value 3.0\n", - "CS (52, 113, 120) -> MCS (52, 113, 120)\n", + "CS ['AcUp' 'h2oEx' 'PFL'] -> MCS ['AcUp' 'h2oEx' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (52, 113, 116) -> MCS (52, 113, 116)\n", + "MCS ['GAPD' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (52, 113, 117) -> MCS (52, 113, 117)\n", + "CS ['PGK' 'PPS' 'SUCDi'] -> MCS ['PGK' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (52, 70, 106) -> MCS (52, 70, 106)\n", + "MCS ['FUM' 'GlcUp' 'GlycUp']\n", "Found solution with objective value 3.0\n", - "CS (52, 113, 119) -> MCS (52, 113, 119)\n", + "MCS ['GlcUp' 'GlycUp' 'PGK']\n", "Found solution with objective value 3.0\n", - "CS (52, 66, 109) -> MCS (52, 66, 109)\n", + "MCS ['MDH' 'PGK' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (43, 73, 95) -> MCS (43, 73, 95)\n", + "CS ['AcUp' 'CYTBO3_4pp' 'GlcUp'] -> MCS ['AcUp' 'CYTBO3_4pp' 'GlcUp']\n", "Found solution with objective value 3.0\n", - "CS (73, 95, 121) -> MCS (73, 95, 121)\n", + "CS ['GlcUp' 'GlycUp' 'TPI'] -> MCS ['GlcUp' 'GlycUp' 'TPI']\n", "Found solution with objective value 3.0\n", + "CS ['ENO' 'MDH' 'PPS'] -> MCS ['ENO' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (70, 88, 106) -> MCS (70, 88, 106)\n", + "CS ['CYTBO3_4pp' 'GlcUp' 'TPI'] -> MCS ['CYTBO3_4pp' 'GlcUp' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (41, 79, 115) -> MCS (41, 79, 115)\n", + "CS ['GlcUp' 'O2Up' 'TPI'] -> MCS ['GlcUp' 'O2Up' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (46, 73, 95) -> MCS (46, 73, 95)\n", + "MCS ['GlcUp' 'GlycUp' 'h_pEx']\n", "Found solution with objective value 3.0\n", - "CS (46, 55, 73) -> MCS (46, 55, 73)\n", + "MCS ['ACKr' 'CYTBO3_4pp' 'GlcUp']\n", "Found solution with objective value 3.0\n", + "CS ['CYTBO3_4pp' 'EthEx' 'h_pEx'] -> MCS ['CYTBO3_4pp' 'EthEx' 'h_pEx']\n", "Found solution with objective value 3.0\n", + "CS ['ALCD2x' 'h_pEx' 'O2Up'] -> MCS ['ALCD2x' 'h_pEx' 'O2Up']\n", "Found solution with objective value 3.0\n", + "MCS ['EthEx' 'h_pEx' 'O2Up']\n", "Found solution with objective value 3.0\n", + "MCS ['ACALD' 'h_pEx' 'O2Up']\n", "Stopping enumeration with status infeasible\n", "True\n" ] } ], - "metadata": {} + "source": [ + "# %% same calculation without network compression\n", + "ecc2_mcsF,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=False,\n", + " include_model_bounds=False, results_cache_dir=results_cache_dir)\n", + "print(set(ecc2_mcs) == set(ecc2_mcsF)) # check that results agree" + ] }, { "cell_type": "code", "execution_count": 5, - "source": [ - "# %% define a desired behaviour for cMCS calculation\r\n", - "ecc2_ethanol_desired = [[(\"EthEx\", \">=\", 1)]]\r\n", - "ecc2_ethanol_desired = [mcs_computation.relations2leq_matrix(\r\n", - " mcs_computation.parse_relations(t, reac_id_symbols=mcs_computation.get_reac_id_symbols(reac_id)), reac_id)\r\n", - " for t in ecc2_ethanol_desired]\r\n", - "mcs_computation.integrate_model_bounds(ecc2, ecc2_ethanol_desired)\r\n", - "ecc2_ethanol_desired_constraints= mcs_computation.get_leq_constraints(ecc2, ecc2_ethanol_desired)\r\n", - "for c in ecc2_ethanol_desired_constraints[0]: # print constraints that make up the desired region\r\n", - " print(c)\r\n" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "957b37f0-5e83-11ec-b3d6-7824af3cf13a: -1.0*EthEx + 1.0*EthEx_reverse_aaa12 <= -1.0\n", - "957b37f1-5e83-11ec-b42e-7824af3cf13a: 1.0*AcUp - 1.0*AcUp_reverse_36302 <= 10.0\n", - "957b5f08-5e83-11ec-bd1e-7824af3cf13a: 1.0*CO2Up - 1.0*CO2Up_reverse_9ac6c <= 10.0\n", - "957b5f09-5e83-11ec-9a59-7824af3cf13a: 1.0*GlcUp - 1.0*GlcUp_reverse_f2a50 <= 10.0\n", - "957b5f0a-5e83-11ec-8a64-7824af3cf13a: 1.0*GlycUp - 1.0*GlycUp_reverse_d1488 <= 10.0\n", - "957b5f0b-5e83-11ec-abdc-7824af3cf13a: 1.0*SuccUp - 1.0*SuccUp_reverse_79869 <= 10.0\n" + "0b06a99c-3550-11ef-8715-004e01c408d4_0_0: -1.0*EthEx + 1.0*EthEx_reverse_aaa12 <= -1.0\n", + "0b06a99c-3550-11ef-8715-004e01c408d4_0_1: 1.0*AcUp - 1.0*AcUp_reverse_36302 <= 10.0\n", + "0b06a99c-3550-11ef-8715-004e01c408d4_0_2: 1.0*CO2Up - 1.0*CO2Up_reverse_9ac6c <= 10.0\n", + "0b06a99c-3550-11ef-8715-004e01c408d4_0_3: 1.0*GlcUp - 1.0*GlcUp_reverse_f2a50 <= 10.0\n", + "0b06a99c-3550-11ef-8715-004e01c408d4_0_4: 1.0*GlycUp - 1.0*GlycUp_reverse_d1488 <= 10.0\n", + "0b06a99c-3550-11ef-8715-004e01c408d4_0_5: 1.0*SuccUp - 1.0*SuccUp_reverse_79869 <= 10.0\n" ] } ], - "metadata": {} + "source": [ + "# %% define a desired behaviour for cMCS calculation\n", + "ecc2_ethanol_desired = [[(\"EthEx\", \">=\", 1)]]\n", + "ecc2_ethanol_desired = [mcs_computation.relations2leq_matrix(\n", + " mcs_computation.parse_relations(t, reac_id_symbols=mcs_computation.get_reac_id_symbols(reac_id)), reac_id)\n", + " for t in ecc2_ethanol_desired]\n", + "mcs_computation.integrate_model_bounds(ecc2, ecc2_ethanol_desired)\n", + "ecc2_ethanol_desired_constraints= mcs_computation.get_leq_constraints(ecc2, ecc2_ethanol_desired)\n", + "for c in ecc2_ethanol_desired_constraints[0]: # print constraints that make up the desired region\n", + " print(c)\n" + ] }, { "cell_type": "code", "execution_count": 6, - "source": [ - "# %% calculate cMCS\r\n", - "ecc2_cmcs,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, desired=ecc2_ethanol_desired, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=True,\r\n", - " include_model_bounds=False, results_cache_dir=results_cache_dir)\r\n", - "\r\n", - "# %% check cMCS\r\n", - "print(len(ecc2_cmcs))\r\n", - "# all cMCS disable the target\r\n", - "print(all(mcs_computation.check_mcs(ecc2, ecc2_mue_target[0], ecc2_cmcs, optlang.interface.INFEASIBLE)))\r\n", - "# all cMCS allow the desired behaviour\r\n", - "print(all(mcs_computation.check_mcs(ecc2, ecc2_ethanol_desired[0], ecc2_cmcs, optlang.interface.OPTIMAL)))\r\n", - "# cMCS are a subset of the MCS \r\n", - "print(set(ecc2_cmcs).issubset(ecc2_mcs))\r\n", - "# cMCS are those MCS that preserve the desired behaviour\r\n", - "print(set(ecc2_cmcs) ==\r\n", - " set(m for m,c in zip(ecc2_mcs, mcs_computation.check_mcs(ecc2, ecc2_ethanol_desired[0], ecc2_mcs, optlang.interface.OPTIMAL)) if c))\r\n" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "Loaded compressed model from CNA_ECC2comp_subsets_compressed_59040b07c3bb98f20f85160d37565f50\n", + "Loaded compressed model from CNA_ECC2comp_subsets_compressed_75890a457ad63e16157884b633ad1014\n", "Running FVA for desired regions...\n", - "No cached result available, running FVA...\n", - "Saved FVA result to CNA_ECC2comp_FVA_d53b4ef084928152f972967773e9e6e5\n", + "Loaded FVA result from CNA_ECC2comp_FVA_8cc4436bd2392239946de888ef2c5b95\n", "1 essential reactions in desired region 0\n", "Using big M.\n", + "knock_in_idx []\n", "Objective function is empty; set objective to self.minimize_sum_over_z\n", + "Found solution with objective value 1.0\n", + "MCS ['{EX_Biomass|EX_4CRSOL_ex|EX_5DRIB_ex|EX_AMOB_ex|EX_ca2_ex|EX_cl_ex|EX_coa_c|EX_cobalt2_ex|EX_cu2_ex|EX_fe2_ex|EX_fe3_ex|EX_k_ex|EX_meoh_ex|EX_mg2_ex|EX_mn2_ex|EX_mobd_ex|EX_MTHTHF_ex|EX_nh4_ex|EX_ni2_ex|EX_pi_c|EX_pi_ex|EX_so4_ex|EX_zn2_ex|Growth}']\n", "Found solution with objective value 2.0\n", - "CS (13, 14) -> MCS (13, 14)\n", + "CS ['{ACONTa|ACONTb|CS}' 'SUCOAS'] -> MCS ['{ACONTa|ACONTb|CS}']\n", "Found solution with objective value 2.0\n", - "CS (11, 15) -> MCS (15,)\n", + "CS ['{ENO|PGM}' '{GAPD|PGK}'] -> MCS ['{ENO|PGM}' '{GAPD|PGK}']\n", "Found solution with objective value 3.0\n", - "CS (33, 39, 66) -> MCS (39,)\n", + "CS ['MDH' 'PPC' 'SUCOAS'] -> MCS ['MDH' 'PPC']\n", "Found solution with objective value 2.0\n", - "CS (29, 60) -> MCS (29, 60)\n", - "Found solution with objective value 3.0\n", - "CS (60, 62, 63) -> MCS (60, 62)\n", - "Found solution with objective value 3.0\n", - "CS (58, 62, 63) -> MCS (58, 62)\n", + "CS ['RPE' 'RPI'] -> MCS ['RPI']\n", "Found solution with objective value 2.0\n", - "CS (24, 33) -> MCS (24, 33)\n", + "CS ['{TALA|TKT1}' 'TKT2'] -> MCS ['{TALA|TKT1}' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (29, 52) -> MCS (29, 52)\n", + "CS ['GND' 'RPE'] -> MCS ['GND' 'RPE']\n", + "Found solution with objective value 3.0\n", + "CS ['{GAPD|PGK}' 'PPCK' 'PPS'] -> MCS ['{GAPD|PGK}' 'PPCK' 'PPS']\n", + "Found solution with objective value 1.0\n", + "MCS ['ICDHyr']\n", "Found solution with objective value 2.0\n", - "CS (56, 66) -> MCS (56, 66)\n", + "CS ['{FRD2|NADH17pp}' 'FUM'] -> MCS ['{FRD2|NADH17pp}' 'FUM']\n", "Found solution with objective value 2.0\n", - "CS (17, 67) -> MCS (17,)\n", - "Found solution with objective value 1.0\n", + "CS ['CO2Ex' 'PPC'] -> MCS ['CO2Ex' 'PPC']\n", + "Found solution with objective value 2.0\n", + "CS ['AcEx' '{ACKr|PTAr}'] -> MCS ['AcEx' '{ACKr|PTAr}']\n", "Found solution with objective value 3.0\n", - "CS (24, 53, 54) -> MCS (24, 53, 54)\n", + "CS ['SUCCt3pp' 'SUCDi' 'SUCOAS'] -> MCS ['SUCCt3pp' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (28, 29, 45) -> MCS (28, 29)\n", + "CS ['SuccEx' 'SUCDi' 'SUCOAS'] -> MCS ['SuccEx' 'SUCDi']\n", "Found solution with objective value 2.0\n", - "CS (0, 42) -> MCS (0,)\n", + "CS ['AKGDH' 'SUCOAS'] -> MCS ['AKGDH' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (21, 52, 63) -> MCS (21, 52)\n", - "Found solution with objective value 2.0\n", - "CS (38, 64) -> MCS (38, 64)\n", - "Found solution with objective value 2.0\n", - "CS (30, 36) -> MCS (30, 36)\n", + "CS ['{ENO|PGM}' 'PPCK' 'PPS'] -> MCS ['{ENO|PGM}' 'PPCK' 'PPS']\n", + "Found solution with objective value 3.0\n", + "CS ['{EX_h_ex|h_pEx}' 'ADK1' 'PYK'] -> MCS ['ADK1']\n", "Found solution with objective value 3.0\n", - "CS (5, 33, 67) -> MCS (5, 33, 67)\n", + "CS ['GND' 'TKT2' 'TPI'] -> MCS ['GND' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (6, 30) -> MCS (6, 30)\n", + "CS ['RPE' 'TKT2'] -> MCS ['RPE' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (18, 63) -> MCS (18, 63)\n", + "CS ['GND' '{TALA|TKT1}'] -> MCS ['GND' '{TALA|TKT1}']\n", "Found solution with objective value 2.0\n", - "CS (38, 66) -> MCS (38, 66)\n", + "CS ['RPE' '{TALA|TKT1}'] -> MCS ['RPE' '{TALA|TKT1}']\n", + "Found solution with objective value 3.0\n", + "CS ['PFK' 'PGI' 'TKT2'] -> MCS ['PFK' 'PGI' 'TKT2']\n", + "Found solution with objective value 3.0\n", + "CS ['FBA' 'PGI' 'TKT2'] -> MCS ['FBA' 'PGI' 'TKT2']\n", "Found solution with objective value 2.0\n", - "CS (64, 66) -> MCS (64, 66)\n", + "CS ['G3PD2' 'GLYK'] -> MCS ['G3PD2' 'GLYK']\n", "Found solution with objective value 3.0\n", - "CS (24, 29, 54) -> MCS (24, 29, 54)\n", + "CS ['{ICL|MALS}' 'PPC' 'SUCCt2_2pp'] -> MCS ['{ICL|MALS}' 'PPC' 'SUCCt2_2pp']\n", "Found solution with objective value 2.0\n", - "CS (38, 56) -> MCS (38, 56)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'G3PD2'] -> MCS ['{EX_glyc_ex|GlycUp}' 'G3PD2']\n", "Found solution with objective value 2.0\n", - "CS (56, 64) -> MCS (56, 64)\n", + "CS ['{G6PDH2r|PGL}' 'RPE'] -> MCS ['{G6PDH2r|PGL}' 'RPE']\n", + "Found solution with objective value 3.0\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{ENO|PGM}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{ENO|PGM}' 'TPI']\n", "Found solution with objective value 2.0\n", - "CS (32, 64) -> MCS (32, 64)\n", + "CS ['{G6PDH2r|PGL}' 'TKT2'] -> MCS ['{G6PDH2r|PGL}' 'TKT2']\n", + "Found solution with objective value 3.0\n", + "CS ['{ACKr|PTAr}' 'FUM' 'SUCCt3pp'] -> MCS ['FUM' 'SUCCt3pp']\n", "Found solution with objective value 2.0\n", - "CS (32, 56) -> MCS (32, 56)\n", + "CS ['{G6PDH2r|PGL}' '{TALA|TKT1}'] -> MCS ['{G6PDH2r|PGL}' '{TALA|TKT1}']\n", "Found solution with objective value 2.0\n", - "CS (32, 66) -> MCS (32, 66)\n", + "MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' '{GAPD|PGK}']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 64) -> MCS (5, 50, 64)\n", - "Found solution with objective value 2.0\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBP'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBP']\n", "Found solution with objective value 3.0\n", - "CS (5, 25, 27) -> MCS (5, 25, 27)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBA'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{F6PA|GLYCDx}' 'FBA']\n", "Found solution with objective value 2.0\n", - "CS (42, 52) -> MCS (42, 52)\n", + "MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'ATPS4rpp']\n", "Found solution with objective value 2.0\n", + "MCS ['PPC' 'SUCDi']\n", "Found solution with objective value 2.0\n", + "MCS ['FUM' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (40, 52, 61) -> MCS (40, 52, 61)\n", - "Found solution with objective value 3.0\n", - "CS (36, 48, 67) -> MCS (36, 48, 67)\n", - "Found solution with objective value 3.0\n", - "CS (7, 16, 59) -> MCS (7, 16, 59)\n", - "Found solution with objective value 3.0\n", - "CS (33, 53, 54) -> MCS (33, 53, 54)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SuccEx'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SuccEx']\n", + "Found solution with objective value 2.0\n", + "MCS ['FUM' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (6, 48, 67) -> MCS (6, 48, 67)\n", + "CS ['CO2Ex' '{GAPD|PGK}' 'PPS'] -> MCS ['CO2Ex' '{GAPD|PGK}' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 56) -> MCS (5, 50, 56)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBP'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBP']\n", "Found solution with objective value 3.0\n", - "CS (5, 50, 66) -> MCS (5, 50, 66)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBA'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'FBA']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 64) -> MCS (21, 60, 64)\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SuccUp'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (21, 56, 60) -> MCS (21, 56, 60)\n", + "CS ['{ICL|MALS}' 'PPC' 'SuccUp'] -> MCS ['{ICL|MALS}' 'PPC' 'SuccUp']\n", "Found solution with objective value 3.0\n", - "CS (5, 11, 14) -> MCS (5, 11, 14)\n", + "CS ['CO2Ex' 'RPE' 'SuccEx'] -> MCS ['CO2Ex' 'RPE' 'SuccEx']\n", "Found solution with objective value 3.0\n", - "CS (11, 45, 60) -> MCS (11, 45, 60)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' '{TALA|TKT1}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (6, 26, 67) -> MCS (6, 26, 67)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'TKT2'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (11, 45, 58) -> MCS (11, 45, 58)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'RPE'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' 'PGI' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (26, 36, 67) -> MCS (26, 36, 67)\n", + "CS ['CO2Ex' 'SuccEx' 'TKT2'] -> MCS ['CO2Ex' 'SuccEx' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (21, 29, 66) -> MCS (21, 29, 66)\n", + "CS ['{ENO|PGM}' 'FUM' 'PPS'] -> MCS ['{ENO|PGM}' 'FUM' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (21, 29, 56) -> MCS (21, 29, 56)\n", - "Found solution with objective value 2.0\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ACKr|PTAr}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ACKr|PTAr}']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 63) -> MCS (21, 28, 63)\n", + "CS ['CO2Ex' 'SuccEx' 'SUCOAS'] -> MCS ['CO2Ex' 'SuccEx' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (48, 50, 66) -> MCS (48, 50, 66)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{ENO|PGM}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{ENO|PGM}']\n", "Found solution with objective value 3.0\n", - "CS (26, 50, 66) -> MCS (26, 50, 66)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 56) -> MCS (21, 28, 56)\n", + "CS ['CO2Ex' 'SuccEx' '{TALA|TKT1}'] -> MCS ['CO2Ex' 'SuccEx' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 66) -> MCS (21, 28, 66)\n", + "CS ['CO2Ex' 'RPE' 'SUCCt3pp'] -> MCS ['CO2Ex' 'RPE' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", - "CS (5, 25, 26) -> MCS (5, 25, 26)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'TKT2'] -> MCS ['CO2Ex' 'SUCCt3pp' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (21, 28, 64) -> MCS (21, 28, 64)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'PFK' 'TPI'] -> MCS ['{EX_glyc_ex|GlycUp}' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 61) -> MCS (7, 14, 61)\n", + "CS ['{EX_glyc_ex|GlycUp}' 'FBA' 'TPI'] -> MCS ['{EX_glyc_ex|GlycUp}' 'FBA' 'TPI']\n", "Found solution with objective value 2.0\n", + "MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' '{ENO|PGM}']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 64) -> MCS (21, 58, 64)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'SUCOAS'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (21, 56, 58) -> MCS (21, 56, 58)\n", + "CS ['FUM' '{GAPD|PGK}' 'PPS'] -> MCS ['FUM' '{GAPD|PGK}' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (21, 33, 54) -> MCS (21, 33, 54)\n", + "CS ['{ENO|PGM}' 'MDH' 'PPS'] -> MCS ['{ENO|PGM}' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 27) -> MCS (5, 6, 27)\n", + "CS ['{GAPD|PGK}' 'MDH' 'PPS'] -> MCS ['{GAPD|PGK}' 'MDH' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 63) -> MCS (21, 60, 63)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCCt2_2pp'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 67) -> MCS (5, 6, 67)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{GAPD|PGK}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{GAPD|PGK}' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 26) -> MCS (5, 6, 26)\n", + "CS ['CO2Ex' 'SUCCt3pp' '{TALA|TKT1}'] -> MCS ['CO2Ex' 'SUCCt3pp' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (21, 60, 66) -> MCS (21, 60, 66)\n", + "CS ['CO2Ex' '{ENO|PGM}' 'PPS'] -> MCS ['CO2Ex' '{ENO|PGM}' 'PPS']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 66) -> MCS (21, 58, 66)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'AcUp' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'AcUp' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (29, 33, 54) -> MCS (29, 33, 54)\n", + "CS ['GLYK' 'PFK' 'TPI'] -> MCS ['GLYK' 'PFK' 'TPI']\n", "Found solution with objective value 3.0\n", + "CS ['FBA' 'GLYK' 'TPI'] -> MCS ['FBA' 'GLYK' 'TPI']\n", "Found solution with objective value 3.0\n", - "CS (21, 58, 63) -> MCS (21, 58, 63)\n", + "CS ['CO2Ex' 'SUCCt3pp' 'SUCOAS'] -> MCS ['CO2Ex' 'SUCCt3pp' 'SUCOAS']\n", "Found solution with objective value 3.0\n", - "CS (5, 24, 67) -> MCS (5, 24, 67)\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCCt2_2pp'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCCt2_2pp']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 29) -> MCS (7, 14, 29)\n", + "CS ['CO2Ex' 'FUM' 'TKT2'] -> MCS ['CO2Ex' 'FUM' 'TKT2']\n", "Found solution with objective value 3.0\n", - "CS (40, 52, 59) -> MCS (40, 52, 59)\n", + "CS ['{EX_h2o_ex|h2oEx}' 'NADH16pp' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'NADH16pp' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (7, 14, 62) -> MCS (7, 14, 62)\n", + "CS ['CO2Ex' 'FUM' 'RPE'] -> MCS ['CO2Ex' 'FUM' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (24, 54, 62) -> MCS (24, 54, 62)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' '{TALA|TKT1}'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' '{TALA|TKT1}']\n", "Found solution with objective value 3.0\n", - "CS (24, 42, 54) -> MCS (24, 42, 54)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'RPE'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'RPE']\n", "Found solution with objective value 3.0\n", - "CS (21, 24, 54) -> MCS (21, 24, 54)\n", + "CS ['CO2Ex' '{FRD2|NADH17pp}' 'TKT2'] -> MCS ['CO2Ex' '{FRD2|NADH17pp}' 'TKT2']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h2o_ex|h2oEx}' '{ACKr|PTAr}' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' '{ACKr|PTAr}' 'PFL']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'PPC'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'PPC']\n", "Found solution with objective value 3.0\n", - "CS (7, 16, 62) -> MCS (7, 16, 62)\n", + "CS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SUCCt3pp'] -> MCS ['{EX_o2_ex|CYTBO3_4pp|O2Up}' 'NADH16pp' 'SUCCt3pp']\n", "Found solution with objective value 3.0\n", + "CS ['{ENO|PGM}' 'PPS' 'SUCDi'] -> MCS ['{ENO|PGM}' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'FUM']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'TPI'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'TPI']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCDi'] -> MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCDi']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h2o_ex|h2oEx}' 'FUM' 'PFL'] -> MCS ['{EX_h2o_ex|h2oEx}' 'FUM' 'PFL']\n", "Found solution with objective value 3.0\n", - "CS (9, 49, 59) -> MCS (9, 49, 59)\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'AcUp'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'AcUp']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SuccUp'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SuccUp']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCDi'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (5, 6, 24) -> MCS (5, 6, 24)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCDi'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'SUCDi']\n", "Found solution with objective value 3.0\n", - "CS (5, 11, 55) -> MCS (5, 11, 55)\n", + "CS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'FUM'] -> MCS ['{EX_h_ex|h_pEx}' '{ACKr|PTAr}' 'FUM']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{GAPD|PGK}'] -> MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_glyc_ex|GlycUp}' '{GAPD|PGK}']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h_ex|h_pEx}' 'AcUp' 'FUM'] -> MCS ['{EX_h_ex|h_pEx}' 'AcUp' 'FUM']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'CO2Ex']\n", "Found solution with objective value 3.0\n", + "CS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SuccUp'] -> MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SuccUp']\n", "Found solution with objective value 3.0\n", + "CS ['{GAPD|PGK}' 'PPS' 'SUCDi'] -> MCS ['{GAPD|PGK}' 'PPS' 'SUCDi']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_o2_ex|CYTBO3_4pp|O2Up}' 'PYK']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_glc_DASH_D_ex|GlcUp}' '{EX_h2o_ex|h2oEx}' 'SUCDi']\n", "Found solution with objective value 3.0\n", + "MCS ['{EX_h2o_ex|h2oEx}' 'PFL' 'SUCCt2_2pp']\n", "Stopping enumeration with status infeasible\n", "163\n", "True\n", @@ -1008,7 +992,47 @@ ] } ], - "metadata": {} + "source": [ + "# %% calculate cMCS\n", + "ecc2_cmcs,_ = mcs_computation.compute_mcs(ecc2, ecc2_mue_target, desired=ecc2_ethanol_desired, cuts=cuts, enum_method=3, max_mcs_size=3, network_compression=True,\n", + " include_model_bounds=False, results_cache_dir=results_cache_dir)\n", + "\n", + "# %% check cMCS\n", + "print(len(ecc2_cmcs))\n", + "# all cMCS disable the target\n", + "print(all(mcs_computation.check_mcs(ecc2, ecc2_mue_target[0], ecc2_cmcs, optlang.interface.INFEASIBLE)))\n", + "# all cMCS allow the desired behaviour\n", + "print(all(mcs_computation.check_mcs(ecc2, ecc2_ethanol_desired[0], ecc2_cmcs, optlang.interface.OPTIMAL)))\n", + "# cMCS are a subset of the MCS \n", + "print(set(ecc2_cmcs).issubset(ecc2_mcs))\n", + "# cMCS are those MCS that preserve the desired behaviour\n", + "print(set(ecc2_cmcs) ==\n", + " set(m for m,c in zip(ecc2_mcs, mcs_computation.check_mcs(ecc2, ecc2_ethanol_desired[0], ecc2_mcs, optlang.interface.OPTIMAL)) if c))\n" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "interpreter": { + "hash": "934ac3fdf6172ea19fa36e418c62d8759e237019ba7d63c030562927bd521148" + }, + "kernelspec": { + "display_name": "Python 3.7.10 64-bit ('cnapy3': conda)", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + }, + "orig_nbformat": 2 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/optlang_enumerator/cMCS_enumerator.py b/optlang_enumerator/cMCS_enumerator.py index 131a55a..a718fc7 100644 --- a/optlang_enumerator/cMCS_enumerator.py +++ b/optlang_enumerator/cMCS_enumerator.py @@ -2,7 +2,7 @@ import scipy import cobra import optlang.glpk_interface -from optlang.symbolics import add, Zero +from optlang.symbolics import add, mul, Zero, Real from optlang.exceptions import IndicatorConstraintsNotSupported from swiglpk import glp_write_lp try: @@ -27,12 +27,11 @@ class ConstrainedMinimalCutSetsEnumerator: def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=None, - desired=None, knock_in=None, bigM=0, threshold=1, split_reversible_v=True, - irrev_geq=False, ref_set= None): # reduce_constraints=True, combined_z=True + desired=None, knock_in_idx=frozenset(), bigM: float=0, threshold=1, split_reversible_v=True, + irrev_geq=False, intervention_costs = None, ref_set= None): # the matrices in st, targets and desired should be numpy.array or scipy.sparse (csr, csc, lil) format - # targets is a list of (T,t) pairs that represent T <= t + # targets is a list of (T, t) pairs that represent T <= t # implements only combined_z which implies reduce_constraints=True - # knock_in not yet implemented self.ref_set = ref_set # optional set of reference MCS for debugging if not isinstance(st, scipy.sparse.lil_matrix): st = scipy.sparse.lil_matrix(st) @@ -45,15 +44,23 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non if bigM <= 0 and self.Constraint._INDICATOR_CONSTRAINT_SUPPORT is False: raise IndicatorConstraintsNotSupported("This solver does not support indicators. Please choose a different solver or use a big M formulation.") self.Variable = optlang_interface.Variable - irr = [not r for r in reversible] + reversible = numpy.asarray(reversible) + irr = numpy.logical_not(reversible) self.num_reac = len(reversible) if cuts is None: cuts = numpy.full(self.num_reac, True, dtype=bool) irrepressible = [] else: irrepressible = numpy.where(cuts == False)[0] - #iv_cost(irrepressible)= 0; + self.knock_in_idx = frozenset(knock_in_idx) # in case it was passed as list + knock_in_idx = list(knock_in_idx) # for numpy indexing + cuts[knock_in_idx] = False + irrepressible = set(irrepressible) + irrepressible.difference_update(self.knock_in_idx) cuts_idx = numpy.where(cuts)[0] + if any(reversible[knock_in_idx]): + raise ValueError("split_reversible_v cannot be used with reversible knock-in reactions") + # TODO: rectify this if desired is None: desired = [] num_targets = len(targets) @@ -65,7 +72,10 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non kn = scipy.sparse.csc_matrix(kn) # otherwise stacking for dual does not work if split_reversible_v: - split_v_idx = [i for i, x in enumerate(reversible) if x] + split_v_idx = numpy.where(reversible)[0] + # split_v_idx = reversible.copy() + # split_v_idx[knock_in_idx] = False # do not split if reaction is a knock-in + # split_v_idx = numpy.where(split_v_idx)[0] dual_rev_neg_idx = [i for i in range(self.num_reac, self.num_reac + len(split_v_idx))] dual_rev_neg_idx_map = [None] * self.num_reac for i in range(len(split_v_idx)): @@ -79,9 +89,21 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non self.model.add(self.z_vars) self.model.update() # cannot change bound below without this for i in irrepressible: - self.z_vars[i].ub = 0 # only if it is not a knock-in (not yet supported) - # minimize_sum_over_z needs to use an abstract expression because this objective is not automatically associated with a model - self.minimize_sum_over_z = optlang_interface.Objective(add(self.z_vars), direction='min', name='minimize_sum_over_z') + self.z_vars[i].ub = 0 + + # minimize_sum_over_z needs to use an abstract expression because this + # objective is not automatically associated with a model + if isinstance(intervention_costs, numpy.ndarray): + self.all_intervention_costs_integer = numpy.issubdtype(intervention_costs.dtype, numpy.integer) or \ + all(map(float.is_integer, intervention_costs)) + self.minimize_sum_over_z = optlang_interface.Objective( + add([mul(Real(cost), zvar) for cost,zvar in zip(intervention_costs, self.z_vars)]), + direction='min', name='minimize_sum_over_z') + else: + self.all_intervention_costs_integer = True + self.minimize_sum_over_z = optlang_interface.Objective( + add(self.z_vars), direction='min', name='minimize_sum_over_z') + z_local = [None] * num_targets if num_targets == 1: z_local[0] = self.z_vars # global and local Z are the same if there is only one target @@ -93,7 +115,7 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non # z_local[k] = [self.Variable("Z"+str(k)+"_"+str(i), type="binary", problem=self.model.problem) for i in range(self.num_reac)] # self.model.add(z_local[k]) # for i in range(self.num_reac): - # if cuts[i]: # && ~knock_in(i) % knock-ins only use global Z, do not need local ones + # if cuts[i] and i not in self.knock_in_idx: # knock-ins only use global Z, do not need local ones # self.model.add(self.Constraint( # (1/num_targets - 1e-9)*add([z_local[k][i] for k in range(num_targets)]) - self.z_vars[i], ub=0, # name= "ZL"+str(i))) @@ -102,7 +124,6 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non for k in range(num_targets): # !! unboundedness is only properly represented by None with optlang; using inifinity may cause trouble !! dual_lb = [None] * self.num_reac # optlang interprets None as Inf - #dual_lb = numpy.full(self.num_reac, numpy.NINF) dual_ub = [None] * self.num_reac #dual_ub = numpy.full(self.num_reac, numpy.inf) # can lead to GLPK crash when trying to otimize an infeasible MILP # GLPK treats infinity different than declaring unboundedness explicitly by glp_set_col_bnds ?!? @@ -153,7 +174,10 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non constr = self.Constraint(Zero, ub=-threshold, name="DW"+str(k), sloppy=True) self.model.add(constr) self.model.update() - constr.set_linear_coefficients({var: cf for cf, var in zip(targets[k][1], dual_vars[k][first_w:]) if cf != 0}) + w_coeff = {var: cf for cf, var in zip(targets[k][1], dual_vars[k][first_w:]) if cf != 0} + if len(w_coeff) == 0: + raise ValueError(f"Target {k} contains the zero vector and therefore cannot be suppressed.\nCheck the target fromulation.") + constr.set_linear_coefficients(w_coeff) # constraints for the target(s) (cuts and knock-ins) if bigM > 0: @@ -172,21 +196,24 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non dn = dual_vars[k][i] c.name = z_local[k][i].name+dn.name+"r" c.set_linear_coefficients({dn: 1.0, z_local[k][i]: bigM}) - # if knock_in(i) - # lpfw.write_z_flux_link(obj.z_var_names{i}, dual_var_names{k}{i}, bigM, '<='); - # if ~irr(i) - # switch split_level - # case 1 - # dn= dual_var_names{k}{dual_rev_neg_idx_map(i)}; - # case 2 - # dn= dual_var_names{k}{obj.num_reac+i}; - # otherwise - # dn= dual_var_names{k}{i}; - # end - # lpfw.write_z_flux_link(obj.z_var_names{i}, dn, -bigM, '>='); - # end - # end - # end + + # dn <= (1-z)*bigM <=> dn <= bigM - z*bigM <=> dn + z*bigM <= bigM + constr = [(self.Constraint(Zero, ub=bigM, name="KI_"+z_local[k][i].name+dual_vars[k][i].name), i) for i in knock_in_idx] + self.model.add([c for c,_ in constr]) + self.model.update() + for c, i in constr: + c.set_linear_coefficients({dual_vars[k][i]: 1.0, z_local[k][i]: bigM}) + # dn >= (z-1)*bigM <=> dn >= -bigM + z*bigM <=> dn - z*bigM >= -bigM + constr = [(self.Constraint(Zero, lb=-bigM), i) for i in knock_in_idx if reversible[i]] + self.model.add([c for c,_ in constr]) + self.model.update() + for c, i in constr: + if split_reversible_v: + dn = dual_vars[k][dual_rev_neg_idx_map[i]] + else: + dn = dual_vars[k][i] + c.name = "KI_"+z_local[k][i].name+dn.name+"r" + c.set_linear_coefficients({dn: 1.0, z_local[k][i]: -bigM}) else: # indicators for i in range(self.num_reac): if cuts[i]: @@ -207,21 +234,18 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non self.model.add(self.Constraint(dual_vars[k][i], lb=lb, ub=0, indicator_variable=z_local[k][i], active_when=0, name=z_local[k][i].name+dual_vars[k][i].name)) - # if knock_in(i) - # fprintf(lpfw_fid, '%s = 1 -> %s <= 0\n', obj.z_var_names{i}, dual_var_names{k}{i}); - # if ~irr(i) - # switch split_level - # case 1 - # dn= dual_var_names{k}{dual_rev_neg_idx_map(i)}; - # case 2 - # dn= dual_var_names{k}{obj.num_reac+i}; - # otherwise - # dn= dual_var_names{k}{i}; - # end - # fprintf(lpfw_fid, '%s = 1 -> %s >= 0\n', obj.z_var_names{i}, dn); - # end - # end - # end + elif i in knock_in_idx: + self.model.add(self.Constraint(dual_vars[k][i], ub=0, + indicator_variable=z_local[k][i], active_when=1, + name="KI_"+z_local[k][i].name+dual_vars[k][i].name)) + if reversible[i]: + if split_reversible_v: + dn = dual_vars[k][dual_rev_neg_idx_map[i]] + else: + dn = dual_vars[k][i] + self.model.add(self.Constraint(dual_vars[k][i], lb=0, + indicator_variable=z_local[k][i], active_when=1, + name="KI_"+z_local[k][i].name+dual_vars[k][i].name+"r")) self.flux_vars= [None]*len(desired) for l in range(len(desired)): @@ -261,20 +285,29 @@ def __init__(self, optlang_interface, st, reversible, targets, kn=None, cuts=Non self.model.update() for c, i in constr: c.set_linear_coefficients({self.flux_vars[l][i]: 1, self.z_vars[i]: flux_lb[i]}) - # for i= knock_in_idx - # if flux_ub{l}(i) ~= 0 - # lpfw.write_direct_z_flux_link(obj.z_var_names{i}, obj.flux_var_names{i, l}, flux_ub{l}(i), '<='); - # end - # if flux_lb{l}(i) ~= 0 - # lpfw.write_direct_z_flux_link(obj.z_var_names{i}, obj.flux_var_names{i, l}, flux_lb{l}(i), '>='); - # end - # end + # fv <= ub*z <=> fv - ub*z <= 0 + constr = [(self.Constraint(Zero, ub=0, name="KI_"+self.flux_vars[l][i].name+self.z_vars[i].name+"UB"), i) + for i in knock_in_idx if flux_ub[i] != 0] + self.model.add([c for c,_ in constr]) + self.model.update() + for c, i in constr: + c.set_linear_coefficients({self.flux_vars[l][i]: 1, self.z_vars[i]: -flux_ub[i]}) + # fv >= lb*z <=> fv - lb*z >= 0 + constr = [(self.Constraint(Zero, lb=0, name="KI_"+self.flux_vars[l][i].name+self.z_vars[i].name+"LB"), i) + for i in knock_in_idx if flux_lb[i] != 0] + self.model.add([c for c,_ in constr]) + self.model.update() + for c, i in constr: + c.set_linear_coefficients({self.flux_vars[l][i]: 1, self.z_vars[i]: -flux_lb[i]}) self.evs_sz_lb = 0 self.evs_sz = self.Constraint(Zero, lb=self.evs_sz_lb, name='evs_sz') self.model.add(self.evs_sz) self.model.update() - self.evs_sz.set_linear_coefficients({z: 1.0 for z in self.z_vars}) + if isinstance(intervention_costs, numpy.ndarray): + self.evs_sz.set_linear_coefficients({z: c for z,c in zip(self.z_vars, intervention_costs)}) + else: + self.evs_sz.set_linear_coefficients({z: 1 for z in self.z_vars}) def single_solve(self): status = self.model._optimize() # raw solve without any retries @@ -298,12 +331,18 @@ def add_exclusion_constraint(self, mcs): constr.set_linear_coefficients({self.z_vars[i]: 1.0 for i in mcs}) def enumerate_mcs(self, max_mcs_size: int=None, max_mcs_num=float('inf'), enum_method: int=1, timeout=None, - model: cobra.Model=None, targets=None, desired=None, info=None) -> Tuple[List[Union[Tuple[int], FrozenSet[int]]], int]: + model: cobra.Model=None, targets=None, desired=None, info=None, + reaction_display_attr="id") -> Tuple[List[Union[Tuple[int], FrozenSet[int]]], int]: # model is the metabolic network, not the MILP - # returns a list of sorted tuples (enum_method 1-3) or a list of frozensets (enum_method 4) + # returns a list of tuples (enum_method 1-3) or a list of frozensets (enum_method 4) # if a dictionary is passed as info some status/runtime information is stored in there all_mcs = [] err_val = 0 + if enum_method != 2: + if model is None: + reaction_names = numpy.array([str(i) for i in range(self.num_reac)]) + else: + reaction_names = numpy.array(model.reactions.list_attr(reaction_display_attr)) if enum_method == 2 or enum_method == 4: if self._optlang_interface is not optlang.cplex_interface \ and self._optlang_interface is not optlang.gurobi_interface: @@ -322,6 +361,8 @@ def enumerate_mcs(self, max_mcs_size: int=None, max_mcs_num=float('inf'), enum_m self.model.problem.Params.PoolSolutions = 2000000000 # maximum value according to documentation z_vars = [self.model.problem.getVarByName(z.name) for z in self.z_vars] if enum_method == 2: + if not self.all_intervention_costs_integer: + raise ValueError("Enum_method 2 (populate) can only be used if all interventions costs are integer.\n") print("Populate by cardinality up tp MCS size ", max_mcs_size) if self._optlang_interface is optlang.cplex_interface: self.model.problem.parameters.emphasis.mip.set(1) # integer feasibility @@ -336,11 +377,13 @@ def enumerate_mcs(self, max_mcs_size: int=None, max_mcs_num=float('inf'), enum_m self.model.objective = self.minimize_sum_over_z print('Objective function is empty; set objective to self.minimize_sum_over_z') if self._optlang_interface is optlang.cplex_interface: - cut_set_cb = CPLEXmakeMCSCallback(z_idx, model, targets, desired=desired, max_mcs_num=max_mcs_num) + cut_set_cb = CPLEXmakeMCSCallback(z_idx, model, targets, reaction_names, desired=desired, max_mcs_num=max_mcs_num, + knock_in_idx=self.knock_in_idx) self.model.problem.set_callback(cut_set_cb, cplex.callbacks.Context.id.candidate) else: # Gurobi self.model.problem.Params.LazyConstraints = 1 # must be activated explicitly - cut_set_cb = GUROBImakeMCSCallback(z_vars, model, targets, desired=desired, max_mcs_num=max_mcs_num) + cut_set_cb = GUROBImakeMCSCallback(z_vars, model, targets, reaction_names, desired=desired, max_mcs_num=max_mcs_num, + knock_in_idx=self.knock_in_idx) def call_back_func(model, where): # encapsulating with functools.partial not accepted by Gurobi cut_set_cb.invoke(model, where) # passing this directly to optimize not accepted by Gurobi elif enum_method == 1 or enum_method == 3: @@ -349,6 +392,10 @@ def call_back_func(model, where): # encapsulating with functools.partial not acc print('Objective function is empty; set objective to self.minimize_sum_over_z') if enum_method == 3: target_constraints= mcs_computation.get_leq_constraints(model, targets) + if len(self.knock_in_idx) > 0 and desired is not None: + desired_constraints = mcs_computation.get_leq_constraints(model, desired) + else: + desired_constraints = None if max_mcs_size is not None: self.evs_sz.ub = max_mcs_size else: @@ -383,9 +430,10 @@ def call_back_func(model, where): # encapsulating with functools.partial not acc # print(ov) else: # enum_method == 3: # and self.model.status == 'feasible': # query best bound and use it to update self.evs_sz_lb - print("CS", mcs, end="") - mcs = mcs_computation.make_minimal_cut_set(model, mcs, target_constraints) - print(" -> MCS", mcs) + print("CS", reaction_names[list(mcs)], end=" -> ") + mcs = mcs_computation.make_minimal_intervention_set(model, mcs, target_constraints, + desired_constraints=desired_constraints, knock_in_idx=self.knock_in_idx) + print("MCS", reaction_names[list(mcs)]) self.add_exclusion_constraint(mcs) self.model.update() # needs to be done explicitly when using _optimize all_mcs.append(mcs) @@ -416,7 +464,7 @@ def call_back_func(model, where): # encapsulating with functools.partial not acc info['cplex_status'] = cplex_status info['cplex_status_string'] = self.model.problem.solution.get_status_string() if cplex_status is SolutionStatus.MIP_optimal or cplex_status is SolutionStatus.MIP_time_limit_feasible \ - or cplex_status is SolutionStatus.optimal_populated_tolerance: # may occur when a non-zero onjective function is set + or cplex_status is SolutionStatus.optimal_populated_tolerance: # may occur when a non-zero objective function is set if cplex_status is SolutionStatus.MIP_optimal or cplex_status is SolutionStatus.optimal_populated_tolerance: self.evs_sz_lb += 1 print("Increased MCS size to:", self.evs_sz_lb) @@ -553,17 +601,19 @@ def write_lp_file(self, fname): raise NotImplementedError("Writing LP files not yet implemented for this solver.") class CPLEXmakeMCSCallback(): - def __init__(self, z_vars_idx, model, targets, desired=None, max_mcs_num=float('inf'), redundant_constraints=True): - # needs max_mcs_num parameter + def __init__(self, z_vars_idx, model, targets, reaction_names, desired=None, knock_in_idx=frozenset(), + max_mcs_num=float('inf'), redundant_constraints=True): self.z_vars_idx = z_vars_idx self.candidate_count = 0 self.minimal_cut_sets = [] self.model = model self.target_constraints= mcs_computation.get_leq_constraints(model, targets) + self.reaction_names = reaction_names if desired is None: self.desired_constraints = None else: self.desired_constraints = mcs_computation.get_leq_constraints(model, desired) + self.knock_in_idx = knock_in_idx self.redundant_constraints = redundant_constraints self.non_cut_set_candidates = 0 self.abort_status = 0 # 1: stop because max_mcs_num is reached; -1: aborted due to excessive generation of candidates that are not cut sets @@ -573,16 +623,18 @@ def invoke(self, context): if context.in_candidate() and context.is_candidate_point(): # there are also candidate rays but these should not occur here self.candidate_count += 1 cut_set = numpy.nonzero(numpy.round(context.get_candidate_point(self.z_vars_idx)))[0] - print("CS", cut_set, end="") + print("CS", self.reaction_names[cut_set], end="") if self.desired_constraints is not None: for des in self.desired_constraints: - if not mcs_computation.check_mcs(self.model, des, [cut_set], optlang.interface.OPTIMAL)[0]: + if not mcs_computation.check_mcs(self.model, des, [cut_set], optlang.interface.OPTIMAL, + knock_in_idx=self.knock_in_idx)[0]: print(": Rejecting candidate that does not fulfill a desired behaviour.") context.reject_candidate(constraints=[cplex.SparsePair([self.z_vars_idx[c] for c in cut_set], [1.0]*len(cut_set))], senses="L", rhs=[len(cut_set)-1.0]) return for targ in self.target_constraints: - if not mcs_computation.check_mcs(self.model, targ, [cut_set], optlang.interface.INFEASIBLE)[0]: + if not mcs_computation.check_mcs(self.model, targ, [cut_set], optlang.interface.INFEASIBLE, + knock_in_idx=self.knock_in_idx)[0]: # cut_set cannot be a superset of an already identified MCS here print(": Rejecting candidate that does not inhibit a target.") self.non_cut_set_candidates += 1 @@ -599,15 +651,16 @@ def invoke(self, context): cut_set_s = set(cut_set) # cut_set is an array, need set for >= comparison for mcs in self.minimal_cut_sets: if cut_set_s >= mcs: - print(" already contained as", mcs) + print(" already contained as", self.reaction_names[list(mcs)]) not_superset = False cut_set = mcs # for the lazy constraint break if not_superset: if len(cut_set) > context.get_double_info(cplex.callbacks.Context.info.best_bound): # could use ceiling of best bound unless there are non-integer intervention costs - cut_set = mcs_computation.make_minimal_cut_set(self.model, cut_set, self.target_constraints) - print(" -> MCS", cut_set, end="") + cut_set = mcs_computation.make_minimal_intervention_set(self.model, cut_set, self.target_constraints, + desired_constraints=self.desired_constraints, knock_in_idx=self.knock_in_idx) + print(" -> MCS", self.reaction_names[list(cut_set)], end="") else: print(" is MCS", end="") self.minimal_cut_sets.append(frozenset(cut_set)) @@ -625,17 +678,19 @@ def invoke(self, context): context.reject_candidate() class GUROBImakeMCSCallback(): - def __init__(self, z_vars, model, targets, desired=None, max_mcs_num=float('inf'), redundant_constraints=True): - # needs max_mcs_num parameter + def __init__(self, z_vars, model, targets, reaction_names, desired=None, knock_in_idx=frozenset(), + max_mcs_num=float('inf'), redundant_constraints=True): self.z_vars = z_vars # Gurobi variables self.candidate_count = 0 self.minimal_cut_sets = [] self.model = model self.target_constraints= mcs_computation.get_leq_constraints(model, targets) + self.reaction_names = reaction_names if desired is None: self.desired_constraints = None else: self.desired_constraints = mcs_computation.get_leq_constraints(model, desired) + self.knock_in_idx = knock_in_idx self.redundant_constraints = redundant_constraints self.non_cut_set_candidates = 0 self.abort_status = 0 # 1: stop because max_mcs_num is reached; -1: aborted due to excessive generation of candidates that are not cut sets @@ -645,16 +700,18 @@ def invoke(self, grb_model, where): if where == GRB.Callback.MIPSOL: self.candidate_count += 1 cut_set = numpy.nonzero(numpy.round(grb_model.cbGetSolution(self.z_vars)))[0] - print("CS", cut_set, end="") + print("CS", self.reaction_names[cut_set], end="") if self.desired_constraints is not None: for des in self.desired_constraints: - if not mcs_computation.check_mcs(self.model, des, [cut_set], optlang.interface.OPTIMAL)[0]: + if not mcs_computation.check_mcs(self.model, des, [cut_set], optlang.interface.OPTIMAL, + knock_in_idx=self.knock_in_idx)[0]: print(": Rejecting candidate that does not fulfill a desired behaviour.") grb_model.cbLazy(LinExpr([1.0]*len(cut_set), [self.z_vars[c] for c in cut_set]), GRB.LESS_EQUAL, len(cut_set)-1.0) return for targ in self.target_constraints: - if not mcs_computation.check_mcs(self.model, targ, [cut_set], optlang.interface.INFEASIBLE)[0]: + if not mcs_computation.check_mcs(self.model, targ, [cut_set], optlang.interface.INFEASIBLE, + knock_in_idx=self.knock_in_idx)[0]: # cut_set cannot be a superset of an already identified MCS here print(": Rejecting candidate that does not inhibit a target.") self.non_cut_set_candidates += 1 @@ -668,15 +725,16 @@ def invoke(self, grb_model, where): cut_set_s = set(cut_set) # cut_set is an array, need set for >= comparison for mcs in self.minimal_cut_sets: # is this necessary with Gurobi? if cut_set_s >= mcs: - print(" already contained as", mcs) + print(" already contained as", self.reaction_names[list(mcs)]) not_superset = False cut_set = mcs # for the lazy constraint break if not_superset: if len(cut_set) > grb_model.cbGet(GRB.Callback.MIPSOL_OBJBND): # could use ceiling of best bound unless there are non-integer intervention costs - cut_set = mcs_computation.make_minimal_cut_set(self.model, cut_set, self.target_constraints) - print(" -> MCS", cut_set, end="") + cut_set = mcs_computation.make_minimal_intervention_set(self.model, cut_set, self.target_constraints, + desired_constraints=self.desired_constraints, knock_in_idx=self.knock_in_idx) + print(" -> MCS", self.reaction_names[list(cut_set)], end="") else: print(" is MCS", end="") self.minimal_cut_sets.append(frozenset(cut_set)) diff --git a/optlang_enumerator/mcs_computation.py b/optlang_enumerator/mcs_computation.py index c8ebb46..ddd90cb 100644 --- a/optlang_enumerator/mcs_computation.py +++ b/optlang_enumerator/mcs_computation.py @@ -23,7 +23,6 @@ optlang.coinor_cbc_interface = None # make sure this symbol is defined for type() comparisons import itertools from typing import List, Tuple, Union, Set, FrozenSet -import time import sympy from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application from cobra.core.configuration import Configuration @@ -74,9 +73,8 @@ def matrix_row_expressions(mat, vars): def leq_constraints(optlang_constraint_class, row_expressions, rhs): return [optlang_constraint_class(expr, ub=ub) for expr, ub in zip(row_expressions, rhs)] -def check_mcs(model, constr, mcs, expected_status, flux_expr=None): - # if flux_expr is None: - # flux_expr = [r.flux_expression for r in model.reactions] +def check_mcs(model, constr, mcs, expected_status, knock_in_idx=frozenset(), flux_expr=None): + # mcs: list of tuples/sets check_ok= numpy.zeros(len(mcs), dtype=bool) with model as constr_model: constr_model.problem.Objective(0) @@ -89,13 +87,15 @@ def check_mcs(model, constr, mcs, expected_status, flux_expr=None): constr_model.add_cons_vars(leq_constraints(constr_model.problem.Constraint, rexpr, constr[1])) for m in range(len(mcs)): with constr_model as KO_model: - for r in mcs[m]: - if type(r) is str: + cuts = mcs[m] + if len(knock_in_idx): # assumes that cuts is a tuple of indices + cuts = set(cuts) + cuts.symmetric_difference_update(knock_in_idx) # knock out all unused knock-ins but keep the used ones + for r in cuts: + if isinstance(r, str): KO_model.reactions.get_by_id(r).knock_out() else: # assume r is an index if it is not a string KO_model.reactions[r].knock_out() - # for r in KO_model.reactions.get_by_any(mcs[m]): # get_by_any() does not accept tuple - # r.knock_out() KO_model.slim_optimize() check_ok[m] = KO_model.solver.status == expected_status return check_ok @@ -104,9 +104,6 @@ def check_mcs(model, constr, mcs, expected_status, flux_expr=None): def make_minimal_cut_set(model, cut_set, target_constraints): original_bounds = [model.reactions[r].bounds for r in cut_set] keep_ko = [True] * len(cut_set) - # with model as KO_model: - # for r in cut_set: - # KO_model.reactions[r].knock_out() try: for r in cut_set: model.reactions[r].knock_out() @@ -148,6 +145,65 @@ def make_minimal_cut_set(model, cut_set, target_constraints): model.solver.update() # just in case... return mcs +def make_minimal_intervention_set(model, interventions: list, target_constraints, + desired_constraints=None, knock_in_idx=frozenset()): + intervention_set = set(interventions) + original_bounds = [model.reactions[r].bounds for r in interventions] + with model as KO_model: + for r in knock_in_idx - intervention_set: # knock-ins that are not active in this intervention set + # print("deactivate", r) + KO_model.reactions[r].knock_out() + keep_intervention = [True] * len(interventions) + try: + for r in intervention_set - knock_in_idx: # leave active knock-ins operational + if r not in knock_in_idx: + # print("knock out", r) + KO_model.reactions[r].knock_out() + for i in range(len(interventions)): + r = interventions[i] + if r in knock_in_idx: + # print("Checking KI", r) + is_knock_in = True + KO_model.reactions[r].knock_out() + else: + # print("Checking KO", r) + is_knock_in = False + KO_model.reactions[r].bounds = original_bounds[i] + targets_still_infeasible = True + for target in target_constraints: + with KO_model as target_model: + target_model.problem.Objective(0) + target_model.add_cons_vars(target) + target_model.slim_optimize() + targets_still_infeasible = target_model.solver.status == optlang.interface.INFEASIBLE + if not targets_still_infeasible: + break + desired_still_feasible = True + if is_knock_in and desired_constraints is not None: + for desired in desired_constraints: + with KO_model as desired_model: + desired_model.problem.Objective(0) + desired_model.add_cons_vars(desired) + desired_model.slim_optimize() + desired_still_feasible = desired_model.solver.status == optlang.interface.OPTIMAL + if not desired_still_feasible: + break + if targets_still_infeasible and desired_still_feasible: # this intervention is redundant + keep_intervention[i] = False + else: # this intervention is necessary + if is_knock_in: # reactivate + KO_model.reactions[r].bounds = original_bounds[i] + else: + KO_model.reactions[r].knock_out() + mcs = tuple(ko for(ko, keep) in zip(interventions, keep_intervention) if keep) + # don't handle the exception, just make sure KO_model is restored + finally: + for i in range(len(interventions)): + r = interventions[i] + KO_model.reactions[r].bounds = original_bounds[i] + KO_model.solver.update() # just in case... + return mcs + def parse_relation(lhs : str, rhs : float, reac_id_symbols=None): transformations = (standard_transformations + (implicit_multiplication_application,)) slash = lhs.find('/') @@ -166,32 +222,44 @@ def parse_relation(lhs : str, rhs : float, reac_id_symbols=None): return lhs, rhs -def parse_relations(relations : List, reac_id_symbols=None): +def parse_relations(relations: list, reac_id_symbols=None): for r in range(len(relations)): lhs, rhs = parse_relation(relations[r][0], relations[r][2], reac_id_symbols=reac_id_symbols) relations[r] = (lhs, relations[r][1], rhs) return relations -# def get_reac_id_symbols(model) -> dict: -# return {id: sympy.symbols(id) for id in model.reactions.list_attr("id")} - def get_reac_id_symbols(reac_id) -> dict: return {rxn: sympy.symbols(rxn) for rxn in reac_id} +def get_reaction_id_symbols(reactions: cobra.DictList) -> dict: + return {rxn: sympy.symbols(rxn.id) for rxn in reactions} + def relations2leq_matrix(relations : List, variables): - matrix = numpy.zeros((len(relations), len(variables))) - rhs = numpy.zeros(len(relations)) - for i in range(len(relations)): - if relations[i][1] == ">=": + num_inequalities = len(relations) + for rel in relations: + if rel[1] == "=": + num_inequalities += 1 + matrix = numpy.zeros((num_inequalities, len(variables))) + rhs = numpy.zeros(num_inequalities) + i = 0 + for rel in relations: + if rel[1] == ">=": f = -1.0 - else: + elif rel[1] == "<=" or rel[1] == "=": f = 1.0 - for r in relations[i][0].keys(): # the keys are symbols - matrix[i][variables.index(str(r))] = f*relations[i][0][r] - rhs[i] = f*relations[i][2] + else: + raise ValueError('Only "<=", ">=" and "=" relations are supported.') + for r,c in rel[0].items(): # the keys are symbols + matrix[i][variables.index(str(r))] = f*c + rhs[i] = f*rel[2] + i += 1 + if rel[1] == "=": + matrix[i, :] = -matrix[i-1, :] + rhs[i] = -rhs[i-1] + i += 1 return matrix, rhs # matrix <= rhs -def get_leq_constraints(model, leq_mat : List[Tuple], flux_expr=None): +def get_leq_constraints(model: cobra.Model, leq_mat : List[Tuple], flux_expr=None): # leq_mat can be either targets or desired (as matrices) # returns contstraints that can be added to model if flux_expr is None: @@ -250,6 +318,8 @@ def compressed_model_to_dict(model): def flux_variability_analysis(model: optlang_enumerator.cobra_cnapy.cobra.Model, loopless=False, fraction_of_optimum=0.0, processes=None, results_cache_dir: Path=None, fva_hash=None, print_func=print): # all bounds in the model must be finite because the COBRApy FVA treats unbounded results as errors + model_stoichiometry_hash_object = model.stoichiometry_hash_object + model._stoichiometry_hash_object = None # in case model needs to be pickled if results_cache_dir is not None: fva_hash.update(pickle.dumps((loopless, fraction_of_optimum, model.tolerance))) # integrate solver tolerances? fva_hash.update(pickle.dumps(model.reactions.list_attr("objective_coefficient"))) @@ -273,30 +343,34 @@ def flux_variability_analysis(model: optlang_enumerator.cobra_cnapy.cobra.Model, print_func("Saved FVA result to ", str(file_path)) except: print_func("Failed to write FVA result to ", str(file_path)) - return fva_result else: - return cobra.flux_analysis.flux_variability_analysis(model, reaction_list=None, loopless=loopless, + fva_result = cobra.flux_analysis.flux_variability_analysis(model, reaction_list=None, loopless=loopless, fraction_of_optimum=fraction_of_optimum, pfba_factor=None, processes=processes) + model.restore_stoichiometry_hash_object(model_stoichiometry_hash_object) + return fva_result class InfeasibleRegion(Exception): pass # convenience function def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desired=None, - cuts=None, enum_method=1, max_mcs_size=2, max_mcs_num=1000, timeout=600, - exclude_boundary_reactions_as_cuts=False, network_compression=True, fva_tolerance=1e-9, + cuts=None, knock_in_idx=None, intervention_costs=None, + enum_method=1, max_mcs_size=2, max_mcs_num=1000, timeout=600, + exclude_boundary_reactions_as_cuts=False, network_compression:bool=True, fva_tolerance=1e-9, include_model_bounds=True, bigM=0, mip_opt_tol=1e-6, mip_feas_tol=1e-6, mip_int_tol=1e-6, set_mip_parameters_callback=None, results_cache_dir: Path=None) -> List[Tuple[int]]: # if include_model_bounds=True this function integrates non-default reaction bounds of the model into the # target and desired regions and directly modifies(!) these parameters - - # make fva_res and compressed model optional parameters if desired is None: desired = [] + if knock_in_idx is None: + knock_in_idx = [] - target_constraints= get_leq_constraints(model, targets) - desired_constraints= get_leq_constraints(model, desired) + flux_expr = [r.flux_expression for r in model.reactions] + target_constraints = get_leq_constraints(model, targets, flux_expr=flux_expr) + desired_constraints = get_leq_constraints(model, desired, flux_expr=flux_expr) + del flux_expr # check whether all target/desired regions are feasible for i in range(len(targets)): @@ -318,11 +392,18 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi integrate_model_bounds(model, targets, desired) if cuts is None: - cuts= numpy.full(len(model.reactions), True, dtype=bool) + cuts = numpy.full(len(model.reactions), True, dtype=bool) + else: + cuts = numpy.asarray(cuts) # in case it was passed as list if exclude_boundary_reactions_as_cuts: for r in range(len(model.reactions)): if model.reactions[r].boundary: cuts[r] = False + cuts[knock_in_idx] = False # knock-ins supersede cuts + intervenable = cuts.copy() # needed for MCS expansion and sorting according to cost + intervenable[knock_in_idx] = True + if intervention_costs is not None: + intervention_costs = numpy.asarray(intervention_costs) # in case it was passed as list compressed_model = None if results_cache_dir is None: @@ -375,7 +456,9 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi compressed_model.reactions[i].upper_bound = fva_res.values[i, 1] else: compressed_model.reactions[i].upper_bound = 0 - subT = efmtool4cobra.compress_model_sympy(compressed_model) + # rows of subT are the reactions, columns the subsets + print("Network compression...") + subT = efmtool4cobra.compress_model_sympy(compressed_model, protected_reactions=knock_in_idx) if results_cache_dir is not None: try: with open(compressed_model_file, "wb") as file: @@ -383,7 +466,14 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi print("Saved compressed model to", str(compressed_model_file)) except: print("Failed to save compressed model to", str(compressed_model_file)) + model_reactions = model.reactions.list_attr("id") model = compressed_model + for r in model.reactions: + if len(r.subset_rxns) > 1: + r.subset_id = "{"+"|".join(model_reactions[i] for i in r.subset_rxns)+"}" + else: + r.subset_id = r.id + del model_reactions if results_cache_dir is not None: model.set_reaction_hashes() model.set_stoichiometry_hash_object() @@ -404,13 +494,19 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi if results_cache_dir is not None: # not optimal as it integrates the matrix type into the hash value desired_hash_value[i] = hashlib.md5(pickle.dumps(desired[i])).digest() - full_cuts = cuts # needed for MCS expansion cuts = numpy.any(subT[cuts, :], axis=0) + knock_in_idx = [numpy.where(subT[i, :])[0][0] for i in knock_in_idx] + if intervention_costs is not None: + iv_cost_uncompressed = intervention_costs + intervention_costs = numpy.zeros(subT.shape[1]) + for i in range(subT.shape[1]): + idx = numpy.where(subT[:, i])[0] + if len(idx > 0): + intervention_costs[i] = min(iv_cost_uncompressed[idx]) else: stoich_mat = cobra.util.array.create_stoichiometric_matrix(model, array_type='lil') blocked_rxns = [] for i in range(fva_res.values.shape[0]): - # if res.values[i, 0] == 0 and res.values[i, 1] == 0: if fva_res.values[i, 0] >= -fva_tolerance and fva_res.values[i, 1] <= fva_tolerance: blocked_rxns.append(fva_res.index[i]) cuts[i] = False @@ -455,7 +551,8 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi print("Using big M.") e = cMCS_enumerator.ConstrainedMinimalCutSetsEnumerator(optlang_interface, stoich_mat, rev, targets, desired=desired, - bigM=bigM, threshold=0.1, cuts=cuts, split_reversible_v=True, irrev_geq=True) + bigM=bigM, threshold=0.1, cuts=cuts, intervention_costs=intervention_costs, + knock_in_idx=knock_in_idx, split_reversible_v=not network_compression, irrev_geq=True) if enum_method == 3: if optlang_interface.__name__ == 'optlang.cplex_interface': e.model.problem.parameters.mip.tolerances.mipgap.set(0.98) @@ -479,16 +576,31 @@ def compute_mcs(model: optlang_enumerator.cobra_cnapy.cobra.Model, targets, desi e.model.configuration.tolerances.optimality = mip_opt_tol e.model.configuration.tolerances.feasibility = mip_feas_tol e.model.configuration.tolerances.integrality = mip_int_tol - if set_mip_parameters_callback != None: + if set_mip_parameters_callback is not None: set_mip_parameters_callback(e.model) mcs, err_val = e.enumerate_mcs(max_mcs_size=max_mcs_size, max_mcs_num=max_mcs_num, enum_method=enum_method, - model=model, targets=targets, desired=desired, timeout=timeout) + model=model, targets=targets, desired=desired, timeout=timeout, + reaction_display_attr='subset_id' if network_compression else 'id') if network_compression: xsubT= subT.copy() - xsubT[numpy.logical_not(full_cuts), :] = 0 # only expand to reactions that are repressible within a given subset + xsubT[numpy.logical_not(intervenable), :] = 0 # only expand to reactions that are intervenable within a given subset mcs = expand_mcs(mcs, xsubT) + if intervention_costs is not None: + intervention_costs = iv_cost_uncompressed elif enum_method == 4: mcs = [tuple(sorted(m)) for m in mcs] + + if intervention_costs is not None and numpy.any(intervention_costs[intervenable] != 1): + print("Sorting and filtering interventions according to their cost") + mcs = [(m, sum(intervention_costs[list(m)])) for m in mcs] + mcs = [(m, c) for m,c in mcs if c <= max_mcs_size] + mcs = sorted(mcs, key=lambda x: x[1]) + mcs = [m for m,_ in mcs] + elif enum_method == 3 or enum_method == 4: # sort according to intervention size + mcs = sorted(mcs, key=len) + # if some intervention costs are 0 supersets with these interventions may or may + # not be present depending on the enumeration scheme + return mcs, err_val def stoich_mat2cobra(stoich_mat, irrev_reac): @@ -517,4 +629,3 @@ def equations_to_matrix(model, equations): return dual.values.transpose() else: raise RuntimeError("Index order was not preserved.") - diff --git a/setup.py b/setup.py index b7dcd52..fffd26a 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,12 @@ from setuptools import setup setup(name='optlang_enumerator', - version='0.0.9', + version='0.0.10', description='Enumeration of multiple solutions to a MILP with optlang.', url='https://github.com/cnapy-org/optlang_enumerator.git', author='Axel von Kamp', author_email='axelk1@gmx.de', license='Apache License 2.0', packages=['optlang_enumerator'], - install_requires=['numpy<1.24', 'scipy', 'cobra', 'optlang', 'efmtool_link', 'sympy>=1.12', 'swiglpk'], + install_requires=['numpy==1.23', 'scipy', 'cobra>=0.26.3', 'optlang', 'efmtool_link', 'sympy>=1.12', 'swiglpk'], zip_safe=False)