From 16aacdde276e1bc04dedcdab458f8cca8a9c6fd1 Mon Sep 17 00:00:00 2001 From: VonAlphaBisZulu Date: Fri, 19 Jul 2024 18:16:28 +0000 Subject: [PATCH] updated version number --- conda-recipe/meta.yaml | 2 +- docs/source/conf.py | 2 +- setup.py | 10 ++++------ straindesign/compute_strain_designs.py | 4 +--- straindesign/cplex_interface.py | 2 +- straindesign/glpk_interface.py | 2 +- straindesign/gurobi_interface.py | 6 +++--- straindesign/scip_interface.py | 12 ++++++------ straindesign/solver_interface.py | 10 ++++++---- straindesign/strainDesignProblem.py | 15 ++++++++++----- tests/test_03_plots.py | 3 +++ tests/test_04_preprocessing.py | 2 ++ tests/test_05_straindesign.py | 7 +++++++ 13 files changed, 46 insertions(+), 31 deletions(-) diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 04cf854..8bc950a 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,4 +1,4 @@ -{% set version = '1.11' %} +{% set version = '1.12' %} package: name: straindesign diff --git a/docs/source/conf.py b/docs/source/conf.py index 7549942..10d3e6b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,7 +21,7 @@ author = "Philipp Schneider" # The full version, including alpha/beta/rc tags -release = "1.11" +release = "1.12" # -- General configuration --------------------------------------------------- diff --git a/setup.py b/setup.py index 9479b66..b939bf9 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="straindesign", - version="1.11", + version="1.12", url="https://github.com/klamt-lab/straindesign.git", description="Computational strain design package for the COBRApy framework", long_description= @@ -21,11 +21,9 @@ "Documentation": "https://straindesign.readthedocs.io/en/latest/index.html" }, classifiers=[ - "Intended Audience :: Science/Research", "Development Status :: 3 - Alpha", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", - "Natural Language :: English", "Operating System :: OS Independent", - "Topic :: Scientific/Engineering :: Bio-Informatics" + "Intended Audience :: Science/Research", "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Natural Language :: English", "Operating System :: OS Independent", "Topic :: Scientific/Engineering :: Bio-Informatics" ], keywords=["metabolism", "constraint-based", "mixed-integer", "strain design"], zip_safe=False, diff --git a/straindesign/compute_strain_designs.py b/straindesign/compute_strain_designs.py index 4f36ab6..f2641c0 100644 --- a/straindesign/compute_strain_designs.py +++ b/straindesign/compute_strain_designs.py @@ -407,7 +407,7 @@ def compute_strain_designs(model: Model, **kwargs: dict) -> SDSolutions: solution_approach = kwargs.pop(SOLUTION_APPROACH) else: solution_approach = BEST - + # solve MILP if solution_approach == ANY: cmp_sd_solution = sd_milp.compute(**kwargs_computation) @@ -431,8 +431,6 @@ def compute_strain_designs(model: Model, **kwargs: dict) -> SDSolutions: sd_solutions = SDSolutions(orig_model, sd, cmp_sd_solution.status, setup) logging.info(str(len(sd)) + ' solutions found.') - - return sd_solutions diff --git a/straindesign/cplex_interface.py b/straindesign/cplex_interface.py index 0582191..c95e9da 100644 --- a/straindesign/cplex_interface.py +++ b/straindesign/cplex_interface.py @@ -149,7 +149,7 @@ def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=No # yield only optimal solutions in pool if seed is None: # seed = random.randint(0, _const.CPX_BIGINT) - seed = int(random.randint(0, 2**16-1)) + seed = int(random.randint(0, 2**16 - 1)) self.parameters.randomseed.set(seed) self.parameters.mip.pool.absgap.set(0.0) self.parameters.mip.pool.relgap.set(0.0) diff --git a/straindesign/glpk_interface.py b/straindesign/glpk_interface.py index d0ab464..9876705 100644 --- a/straindesign/glpk_interface.py +++ b/straindesign/glpk_interface.py @@ -96,7 +96,7 @@ class GLPK_MILP_LP(): A GLPK MILP/LP interface class. """ - + def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=None, ub=None, vtype=None, indic_constr=None, M=None): self.glpk = glp_create_prob() # Careful with indexing! GLPK indexing starts with 1 and not with 0 diff --git a/straindesign/gurobi_interface.py b/straindesign/gurobi_interface.py index 6be96e4..53c1319 100644 --- a/straindesign/gurobi_interface.py +++ b/straindesign/gurobi_interface.py @@ -119,7 +119,7 @@ def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=No if A_ineq.shape[0]: self.addMConstr(A_ineq, x, grb.LESS_EQUAL, array(b_ineq)) if A_eq.shape[0]: - self.addMConstr(A_eq, x, grb.EQUAL, array(b_eq)) + self.addMConstr(A_eq, x, grb.EQUAL, array(b_eq)) # add indicator constraints if not indic_constr == None: @@ -138,8 +138,8 @@ def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=No if 'B' in vtype or 'I' in vtype: if seed is None: # seed = random(0, grb.MAXINT) - seed = int(random.randint(0, 2**16-1)) - logging.info(' MILP Seed: '+str(seed)) + seed = int(random.randint(0, 2**16 - 1)) + logging.info(' MILP Seed: ' + str(seed)) self.params.Seed = seed self.params.IntFeasTol = 1e-9 # (0 is not allowed by Gurobi) # yield only optimal solutions in pool diff --git a/straindesign/scip_interface.py b/straindesign/scip_interface.py index 3d4b46c..9772201 100644 --- a/straindesign/scip_interface.py +++ b/straindesign/scip_interface.py @@ -94,7 +94,7 @@ class SCIP_MILP(pso.Model): A SCIP MILP interface class. """ - def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=None, ub=None, vtype=None, indic_constr=None, seed = None): + def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=None, ub=None, vtype=None, indic_constr=None, seed=None): super().__init__() # uncomment to forward SCIP output to python terminal # self.redirectOutput() @@ -164,7 +164,7 @@ def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=No if seed is None: # seed = randint(0, 2**31 - 1) seed = int(random.randint(2**16 - 1)) - logging.info(' MILP Seed: '+str(seed)) + logging.info(' MILP Seed: ' + str(seed)) self.setParam('randomization/randomseedshift', seed) self.setEmphasis(0) # self.setParam('constraints/indicator/forcerestart',True) @@ -178,7 +178,7 @@ def __init__(self, c=None, A_ineq=None, b_ineq=None, A_eq=None, b_eq=None, lb=No # self.setParam('display/lpinfo',False) # self.setParam('reoptimization/enable',True) self.setParam('display/verblevel', 0) - + # SCIP_PARAMEMPHASIS_DEFAULT = 0, /**< use default values */ # SCIP_PARAMEMPHASIS_CPSOLVER = 1, /**< get CP like search (e.g. no LP relaxation) */ # SCIP_PARAMEMPHASIS_EASYCIP = 2, /**< solve easy problems fast */ @@ -333,7 +333,7 @@ def set_objective(self, c): self.setParam('display/verblevel', 0) else: self.setEmphasis(1) - + def set_objective_idx(self, C): """Set the objective function with index-value pairs @@ -349,7 +349,7 @@ def set_objective_idx(self, C): self.setParam('display/verblevel', 0) else: self.setEmphasis(1) - + def set_ub(self, ub): """Set the upper bounds to a given vector""" self.freeTransform() @@ -403,7 +403,7 @@ def add_eq_constraints(self, A_eq, b_eq): The right hand side vector """ self.freeTransform() - eqs = [self.addCons(pso.Expr() == b_i,modifiable=True) for b_i in b_eq] + eqs = [self.addCons(pso.Expr() == b_i, modifiable=True) for b_i in b_eq] for row, a_eq in zip(eqs, A_eq): X = [self.vars[i] for i in a_eq.indices] for col, coeff in zip(X, a_eq.data): diff --git a/straindesign/solver_interface.py b/straindesign/solver_interface.py index d987048..9dbdd82 100644 --- a/straindesign/solver_interface.py +++ b/straindesign/solver_interface.py @@ -101,7 +101,9 @@ class MILP_LP(object): """ def __init__(self, **kwargs): - allowed_keys = {'c', 'A_ineq', 'b_ineq', 'A_eq', 'b_eq', 'lb', 'ub', 'vtype', 'indic_constr', 'M', 'solver', 'skip_checks', 'tlim', SEED} + allowed_keys = { + 'c', 'A_ineq', 'b_ineq', 'A_eq', 'b_eq', 'lb', 'ub', 'vtype', 'indic_constr', 'M', 'solver', 'skip_checks', 'tlim', SEED + } # set all keys passed in kwargs for key, value in kwargs.items(): if key in allowed_keys: @@ -181,11 +183,11 @@ def __init__(self, **kwargs): if self.solver == CPLEX: from straindesign.cplex_interface import Cplex_MILP_LP self.backend = Cplex_MILP_LP(self.c, self.A_ineq, self.b_ineq, self.A_eq, self.b_eq, self.lb, self.ub, self.vtype, - self.indic_constr,self.seed) + self.indic_constr, self.seed) elif self.solver == GUROBI: from straindesign.gurobi_interface import Gurobi_MILP_LP self.backend = Gurobi_MILP_LP(self.c, self.A_ineq, self.b_ineq, self.A_eq, self.b_eq, self.lb, self.ub, self.vtype, - self.indic_constr,self.seed) + self.indic_constr, self.seed) elif self.solver == SCIP: from straindesign.scip_interface import SCIP_MILP, SCIP_LP self.isLP = all(v == 'C' for v in self.vtype) @@ -194,7 +196,7 @@ def __init__(self, **kwargs): return else: self.backend = SCIP_MILP(self.c, self.A_ineq, self.b_ineq, self.A_eq, self.b_eq, self.lb, self.ub, self.vtype, - self.indic_constr,self.seed) + self.indic_constr, self.seed) elif self.solver == GLPK: from straindesign.glpk_interface import GLPK_MILP_LP self.backend = GLPK_MILP_LP(self.c, self.A_ineq, self.b_ineq, self.A_eq, self.b_eq, self.lb, self.ub, self.vtype, diff --git a/straindesign/strainDesignProblem.py b/straindesign/strainDesignProblem.py index 66ebcd0..5e5bd53 100644 --- a/straindesign/strainDesignProblem.py +++ b/straindesign/strainDesignProblem.py @@ -263,7 +263,8 @@ def addModule(self, sd_module): # 4. connect primal w/ undesired region and dual w/o undesired region (i.e. biomass) via c = c_inner. A_ineq_p = sparse.block_diag((A_ineq_v, A_ineq_dual)).tocsr() b_ineq_p = b_ineq_v + b_ineq_dual - A_eq_p = sparse.vstack((sparse.block_diag((A_eq_v, A_eq_dual)), sparse.hstack((sparse.csr_matrix(c_v), sparse.csr_matrix(c_inner_dual))))).tocsr() + A_eq_p = sparse.vstack((sparse.block_diag( + (A_eq_v, A_eq_dual)), sparse.hstack((sparse.csr_matrix(c_v), sparse.csr_matrix(c_inner_dual))))).tocsr() b_eq_p = b_eq_v + b_eq_dual + [0.0] lb_p = lb_v + lb_dual ub_p = ub_v + ub_dual @@ -299,7 +300,8 @@ def addModule(self, sd_module): # 5. connect primal w/ undesired region and dual w/o undesired region (i.e. biomass) via c = c_inner. A_ineq_p = sparse.block_diag((A_ineq_v, A_ineq_dual)).tocsr() b_ineq_p = b_ineq_v + b_ineq_dual - A_eq_p = sparse.vstack((sparse.block_diag((A_eq_v, A_eq_dual)), sparse.hstack((sparse.csr_matrix(c_v), sparse.csr_matrix(c_inner_dual))))).tocsr() + A_eq_p = sparse.vstack((sparse.block_diag( + (A_eq_v, A_eq_dual)), sparse.hstack((sparse.csr_matrix(c_v), sparse.csr_matrix(c_inner_dual))))).tocsr() b_eq_p = b_eq_v + b_eq_dual + [0.0] lb_p = lb_v + lb_dual ub_p = ub_v + ub_dual @@ -316,7 +318,8 @@ def addModule(self, sd_module): # 8. Connect outer problem to the dualized combined inner problem to construct min-max problem. A_ineq_q = sparse.block_diag((A_ineq_r, A_ineq_dl_mmx)).tocsr() b_ineq_q = b_ineq_r + b_ineq_dl_mmx - A_eq_q = sparse.vstack((sparse.block_diag((A_eq_r, A_eq_dl_mmx)), sparse.hstack((sparse.csr_matrix(c_r), sparse.csr_matrix(c_dl_mmx))))).tocsr() + A_eq_q = sparse.vstack((sparse.block_diag( + (A_eq_r, A_eq_dl_mmx)), sparse.hstack((sparse.csr_matrix(c_r), sparse.csr_matrix(c_dl_mmx))))).tocsr() b_eq_q = b_eq_r + b_eq_dl_mmx + [0.0] lb_q = lb_r + lb_dl_mmx ub_q = ub_r + ub_dl_mmx @@ -344,7 +347,9 @@ def addModule(self, sd_module): # 8. Create no-production bi-level system. A_ineq_b = sparse.block_diag((A_ineq_r, A_ineq_r_dl), format='csr') b_ineq_b = b_ineq_r + b_ineq_dl_r_dl - A_eq_b = sparse.vstack((sparse.block_diag((A_eq_r, A_eq_dl_r_dl)), sparse.hstack((sparse.csr_matrix(c_r), sparse.csr_matrix(c_r_dl)))), format='csr') + A_eq_b = sparse.vstack((sparse.block_diag( + (A_eq_r, A_eq_dl_r_dl)), sparse.hstack((sparse.csr_matrix(c_r), sparse.csr_matrix(c_r_dl)))), + format='csr') b_eq_b = b_eq_r + b_eq_r_dl + [0.0] lb_b = lb_r + lb_r_dl ub_b = ub_r + ub_r_dl @@ -847,7 +852,7 @@ def farkas_dualize(A_ineq_p, b_ineq_p, A_eq_p, b_eq_p, lb_p, ub_p, else: A_ineq_d, b_ineq_d, A_eq_d, b_eq_d, lb_f, ub_f, c_d = LP_dualize(A_ineq_p, b_ineq_p, A_eq_p, b_eq_p, lb_p, ub_p, c_p) # add constraint b_prim'y or (c_dual'*y) <= -1; - A_ineq_f = sparse.vstack((A_ineq_d,sparse.csr_matrix(c_d))).tocsr() + A_ineq_f = sparse.vstack((A_ineq_d, sparse.csr_matrix(c_d))).tocsr() b_ineq_f = b_ineq_d + [-1] A_eq_f = A_eq_d b_eq_f = b_eq_d diff --git a/tests/test_03_plots.py b/tests/test_03_plots.py index a090bda..f30b976 100644 --- a/tests/test_03_plots.py +++ b/tests/test_03_plots.py @@ -2,18 +2,21 @@ from .test_01_load_models_and_solvers import * import straindesign as sd + @pytest.mark.timeout(15) def test_plot_2d_flux_space(curr_solver, model_weak_coupling): """Test plot with constraints.""" constr = ['r4 = 0', 'r7 = 0', 'r9 = 0', 'r_BM >= 4'] sd.plot_flux_space(model_weak_coupling, ('r_P', 'r_S'), constraints=constr, plt_backend='template') + @pytest.mark.timeout(15) def test_plot_2d_yield_space(curr_solver, model_weak_coupling): """Test plot with constraints.""" constr = ['r4 = 0', 'r7 = 0', 'r9 = 0', 'r_BM >= 4'] sd.plot_flux_space(model_weak_coupling, (('r_P', 'r_S'), ('r_BM', 'r_S')), constraints=constr, plt_backend='template') + @pytest.mark.timeout(15) def test_plot_3d_space(curr_solver, model_weak_coupling): """Test plot with constraints.""" diff --git a/tests/test_04_preprocessing.py b/tests/test_04_preprocessing.py index d8c3c07..8a99d86 100644 --- a/tests/test_04_preprocessing.py +++ b/tests/test_04_preprocessing.py @@ -3,6 +3,7 @@ import straindesign as sd from numpy import inf + @pytest.mark.timeout(15) def test_gpr_extension_compression1(model_gpr): gkocost = { @@ -21,6 +22,7 @@ def test_gpr_extension_compression1(model_gpr): assert (len(gkocost) == 4) assert (len(gkicost) == 3) + @pytest.mark.timeout(15) def test_gpr_extension_compression2(model_gpr): gkocost = { diff --git a/tests/test_05_straindesign.py b/tests/test_05_straindesign.py index 34bc936..b03e4ad 100644 --- a/tests/test_05_straindesign.py +++ b/tests/test_05_straindesign.py @@ -3,6 +3,7 @@ import straindesign as sd from numpy import inf + @pytest.mark.timeout(15) def test_mcs(curr_solver, model_small_example, comp_approach, bigM, compression): modules = [sd.SDModule(model_small_example, SUPPRESS, constraints=["R3 - 0.5 R1 <= 0.0", "R2 <= 0", "R1 >= 0.1"])] @@ -31,6 +32,7 @@ def test_mcs(curr_solver, model_small_example, comp_approach, bigM, compression) assert ({'R7': -1.0} in sols) assert ({'R10': -1.0} in sols) + @pytest.mark.timeout(15) def test_mcs_opt(curr_solver, model_weak_coupling, comp_approach, bigM, compression): """Test MCS computation with nested optimization constraints.""" @@ -57,6 +59,7 @@ def test_mcs_opt(curr_solver, model_weak_coupling, comp_approach, bigM, compress solution = sd.compute_strain_designs(model_weak_coupling, sd_setup=sd_setup) assert (len(solution.reaction_sd) == 3) + @pytest.mark.timeout(15) def test_mcs_gpr(model_gpr, comp_approach): """Test MCS computation with gpr rules.""" @@ -91,6 +94,7 @@ def test_mcs_gpr(model_gpr, comp_approach): solution = sd.compute_strain_designs(model_gpr, sd_setup=sd_setup) assert (len(solution.gene_sd) == 4) + @pytest.mark.timeout(15) def test_mcs_gpr2(model_gpr, comp_approach): """Test MCS computation gpr rule (compression).""" @@ -126,6 +130,7 @@ def test_mcs_gpr2(model_gpr, comp_approach): assert (len(solution.gene_sd) == 4) assert (any(['G_g4 <= 0.4' in sol for sol in solution.get_gene_sd()])) + @pytest.mark.timeout(15) def test_optknock(curr_solver, model_weak_coupling, comp_approach_best_populate, bigM, compression): """Test OptKnock computation.""" @@ -152,6 +157,7 @@ def test_optknock(curr_solver, model_weak_coupling, comp_approach_best_populate, solution = sd.compute_strain_designs(model_weak_coupling, sd_setup=sd_setup) assert (len(solution.reaction_sd) == 3) + @pytest.mark.timeout(15) def test_robustknock(curr_solver, model_weak_coupling, comp_approach_best_populate, bigM, compression): """Test RobustKnock computation.""" @@ -192,6 +198,7 @@ def test_robustknock(curr_solver, model_weak_coupling, comp_approach_best_popula sol_min_P = sd.fba(m, obj_sense='minimize', obj='r_P', constraints="r_BM >= " + str(sol_max_BM.objective_value)) assert (sol_min_P.objective_value > 0) + @pytest.mark.timeout(15) def test_optcouple(curr_solver, model_weak_coupling, comp_approach_best_populate, bigM, compression): """Test OptCouple computation."""