Example #1
0
def _optimize_gurobi(cobra_model,
                     new_objective=None,
                     objective_sense='maximize',
                     min_norm=0,
                     the_problem=None,
                     tolerance_optimality=1e-6,
                     tolerance_feasibility=1e-6,
                     tolerance_barrier=None,
                     tolerance_integer=1e-9,
                     error_reporting=None,
                     print_solver_time=False,
                     copy_problem=False,
                     lp_method=0,
                     relax_b=None,
                     quad_precision=False,
                     quadratic_component=None,
                     reuse_basis=True,
                     lp_parallel=None,
                     update_problem_reaction_bounds=True):
    """Uses the gurobi (http://gurobi.com) optimizer to perform an optimization on cobra_model
    for the objective_coefficients in cobra_model._objective_coefficients based
    on objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    quad_precision: Boolean.  Whether or not to used quad precision in calculations

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.


    quadratic_component: None or 
          scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions))
         If not None:
          Solves quadratic programming problems for cobra_models of the form:
          minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x
          such that,
            cobra_model._lower_bounds <= x <= cobra_model._upper_bounds
            cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b

            NOTE: When solving quadratic problems it may be necessary to disable quad_precision
            and use lp_method = 0 for gurobi.

    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.

    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX
    
    lp_parallel: Not implemented

    lp.optimize() with Salmonella model:
         cold start: 0.063 seconds
         hot start: 0.057 seconds (Slow due to copying the LP)
         

    """
    if relax_b is not None:
        raise Exception('Need to reimplement constraint relaxation')
    from numpy import array, nan, zeros
    #TODO: speed this up
    if objective_sense == 'maximize':
        objective_sense = -1
    else:
        objective_sense = 1
    from gurobipy import Model, LinExpr, GRB, QuadExpr
    sense_dict = {'E': GRB.EQUAL, 'L': GRB.LESS_EQUAL, 'G': GRB.GREATER_EQUAL}
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict

    variable_kind_dict = eval(variable_kind_dict['gurobi'])
    status_dict = eval(status_dict['gurobi'])

    #Update objectives if they are new.
    if new_objective and new_objective != 'update problem':
        update_objective(cobra_model, new_objective)
    #Create a new problem
    if not the_problem or the_problem in ['return', 'setup'] or \
           not isinstance(the_problem, Model):
        lp = Model("cobra")
        lp.Params.OutputFlag = 0
        lp.Params.LogFile = ''
        # Create variables
        #TODO:  Speed this up
        variable_list = [
            lp.addVar(lb=float(x.lower_bound),
                      ub=float(x.upper_bound),
                      obj=objective_sense * float(x.objective_coefficient),
                      name=x.id,
                      vtype=variable_kind_dict[x.variable_kind])
            for x in cobra_model.reactions
        ]
        reaction_to_variable = dict(zip(cobra_model.reactions, variable_list))
        # Integrate new variables
        lp.update()
        #Set objective to quadratic program
        if quadratic_component is not None:
            if not hasattr(quadratic_component, 'todok'):
                raise Exception(
                    'quadratic component must be a scipy.sparse type array')

            quadratic_objective = QuadExpr()
            for (index_0,
                 index_1), the_value in quadratic_component.todok().items():
                quadratic_objective.addTerms(the_value, variable_list[index_0],
                                             variable_list[index_1])
            lp.setObjective(quadratic_objective, sense=objective_sense)
        #Constraints are based on mass balance
        #Construct the lin expression lists and then add
        #TODO: Speed this up as it takes about .18 seconds
        #HERE
        for the_metabolite in cobra_model.metabolites:
            constraint_coefficients = []
            constraint_variables = []
            for the_reaction in the_metabolite._reaction:
                constraint_coefficients.append(
                    the_reaction._metabolites[the_metabolite])
                constraint_variables.append(reaction_to_variable[the_reaction])
            #Add the metabolite to the problem
            lp.addConstr(
                LinExpr(constraint_coefficients, constraint_variables),
                sense_dict[the_metabolite._constraint_sense.upper()],
                the_metabolite._bound, the_metabolite.id)
    else:
        #When reusing the basis only assume that the objective coefficients or bounds can change
        if copy_problem:
            lp = the_problem.copy()
        else:
            lp = the_problem
        if not reuse_basis:
            lp.reset()
        for the_variable, the_reaction in zip(lp.getVars(),
                                              cobra_model.reactions):
            the_variable.lb = float(the_reaction.lower_bound)
            the_variable.ub = float(the_reaction.upper_bound)
            the_variable.obj = float(objective_sense *
                                     the_reaction.objective_coefficient)

    if the_problem == 'setup':
        return lp
    if print_solver_time:
        start_time = time()
    lp.update()
    lp.setParam("FeasibilityTol", tolerance_feasibility)
    lp.setParam("OptimalityTol", tolerance_optimality)
    if tolerance_barrier:
        lp.setParam("BarConvTol", tolerance_barrier)

    if quad_precision:
        lp.setParam("Quad", 1)
    lp.setParam("Method", lp_method)

    #Different methods to try if lp_method fails
    the_methods = [0, 2, 1]
    if lp_method in the_methods:
        the_methods.remove(lp_method)
    if not isinstance(the_problem, Model):
        lp.optimize()
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            #Try to find a solution using a different method
            lp.setParam("MarkowitzTol", 1e-2)
            for lp_method in the_methods:
                lp.setParam("Method", lp_method)
                lp.optimize()
                if status_dict[lp.status] == 'optimal':
                    break
    else:
        lp.setParam("TimeLimit", 0.6)
        lp.optimize()
        lp.setParam("TimeLimit", "default")
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp.setParam("MarkowitzTol", 1e-2)
            #Try to find a solution using a different method
            for lp_method in the_methods:
                lp.setParam("Method", lp_method)
                lp.optimize()
                if status_dict[lp.status] == 'optimal':
                    break

            if status_dict[lp.status] != 'optimal':
                lp = optimize_gurobi(
                    cobra_model,
                    new_objective=new_objective,
                    objective_sense=objective_sense,
                    min_norm=min_norm,
                    the_problem=None,
                    print_solver_time=print_solver_time)['the_problem']

    if print_solver_time:
        print 'optimize time: %f' % (time() - start_time)
    x_dict = {}
    y_dict = {}
    y = None
    if lp.status in status_dict:
        status = status_dict[lp.status]
    else:
        status = 'failed'
    if status == 'optimal':
        objective_value = objective_sense * lp.ObjVal
        [x_dict.update({v.VarName: v.X}) for v in lp.getVars()]
        x = array([x_dict[v.id] for v in cobra_model.reactions])
        if lp.isMIP:
            y = y_dict = None  #MIP's don't have duals
        else:
            [y_dict.update({c.ConstrName: c.Pi}) for c in lp.getConstrs()]
            y = array([y_dict[v.id] for v in cobra_model.metabolites])
    else:
        y = y_dict = x = x_dict = None
        objective_value = None
        if error_reporting:
            print 'gurobi failed: %s' % lp.status
    cobra_model.solution = the_solution = Solution(objective_value,
                                                   x=x,
                                                   x_dict=x_dict,
                                                   y=y,
                                                   y_dict=y_dict,
                                                   status=status)
    solution = {'the_problem': lp, 'the_solution': the_solution}
    return solution
Example #2
0
def _optimize_glpk(
        cobra_model,
        new_objective=None,
        objective_sense='maximize',
        min_norm=0,
        the_problem=None,
        tolerance_optimality=1e-6,
        tolerance_feasibility=1e-6,
        tolerance_integer=1e-9,
        error_reporting=None,
        print_solver_time=False,
        lp_method=1,
        quadratic_component=None,
        reuse_basis=True,
        #Not implemented
        tolerance_barrier=None,
        lp_parallel=None,
        copy_problem=None,
        relax_b=None,
        update_problem_reaction_bounds=True):
    """Uses the GLPK (www.gnu.org/software/glpk/) optimizer via pyglpk
    (http://www.tfinley.net/software/pyglpk/release.html) to perform an optimization
    on cobra_model for the objective_coefficients in cobra_model._objective_coefficients
    based on the objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.

    quadratic_component: None.  GLPK cannot solve quadratic programs at the moment.

    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.  Currently, only True is available for GLPK

    
    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX
    
    lp.simplex() with Salmonella model:
         cold start: 0.42 seconds
         hot start: 0.0013 seconds
    """

    from numpy import zeros, array, nan
    #TODO: Speed up problem creation
    if hasattr(quadratic_component, 'todok'):
        raise Exception('GLPK cannot solve quadratic programs please '+\
                        'try using the gurobi or cplex solvers')

    from glpk import LPX
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict
    status_dict = eval(status_dict['glpk'])
    variable_kind_dict = eval(variable_kind_dict['glpk'])

    if new_objective and new_objective != 'update problem':
        update_objective(cobra_model, new_objective)
    #Faster to use these dicts than index lists
    index_to_metabolite = dict(
        zip(range(len(cobra_model.metabolites)), cobra_model.metabolites))
    index_to_reaction = dict(
        zip(range(len(cobra_model.reactions)), cobra_model.reactions))
    reaction_to_index = dict(
        zip(index_to_reaction.values(), index_to_reaction.keys()))
    if the_problem == None or the_problem in ['return', 'setup'] or \
           not isinstance(the_problem, LPX):
        lp = LPX()  # Create empty problem instance
        lp.name = 'cobra'  # Assign symbolic name to problem
        lp.rows.add(len(cobra_model.metabolites))
        lp.cols.add(len(cobra_model.reactions))
        linear_constraints = []
        for r in lp.rows:
            the_metabolite = index_to_metabolite[r.index]
            r.name = the_metabolite.id
            b = float(the_metabolite._bound)
            c = the_metabolite._constraint_sense
            if c == 'E':
                r.bounds = b, b  # Set metabolite to steady state levels
            elif c == 'L':
                r.bounds = None, b
            elif c == 'G':
                r.bounds = b, None
            #Add in the linear constraints

            for the_reaction in the_metabolite._reaction:
                reaction_index = reaction_to_index[the_reaction]
                the_coefficient = the_reaction._metabolites[the_metabolite]
                linear_constraints.append(
                    (r.index, reaction_index, the_coefficient))
        #Need to assign lp.matrix after constructing the whole list
        lp.matrix = linear_constraints
        objective_coefficients = []

        for c in lp.cols:
            the_reaction = index_to_reaction[c.index]
            c.name = the_reaction.id
            the_reaction = index_to_reaction[c.index]
            c.kind = variable_kind_dict[the_reaction.variable_kind]
            c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
            objective_coefficients.append(
                float(the_reaction.objective_coefficient))
        #Add the new objective coefficients to the problem
        lp.obj[:] = objective_coefficients
    else:
        lp = the_problem
        #BUG with changing / unchanging the basis
        if new_objective is not None:
            objective_coefficients = []
            for c in lp.cols:  # Iterate over all rows
                the_reaction = index_to_reaction[c.index]
                c.name = the_reaction.id
                c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
                objective_coefficients.append(
                    float(the_reaction.objective_coefficient))
                c.kind = variable_kind_dict[the_reaction.variable_kind]
            #Add the new objective coefficients to the problem
            lp.obj[:] = objective_coefficients
        else:
            for c in lp.cols:  # Iterate over all rows
                the_reaction = index_to_reaction[c.index]
                c.name = the_reaction.id
                c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
                c.kind = variable_kind_dict[the_reaction.variable_kind]
    if objective_sense.lower() == 'maximize':
        lp.obj.maximize = True  # Set this as a maximization problem
    else:
        lp.obj.maximize = False
    if the_problem == 'setup':
        return lp
    if print_solver_time:
        start_time = time()
    the_methods = [1, 2, 3]
    if lp_method in the_methods:
        the_methods.remove(lp_method)
    else:
        lp_method = 1
    if not isinstance(the_problem, LPX):
        if lp.kind == int:
            lp.simplex(tol_bnd=tolerance_optimality,
                       tol_dj=tolerance_optimality,
                       meth=lp_method)  # we first have to solve the LP?
            lp.integer(tol_int=tolerance_integer)
        else:
            lp.simplex(tol_bnd=tolerance_optimality,
                       tol_dj=tolerance_optimality,
                       meth=lp_method)
        # Solve this LP or MIP with the simplex (depending on if integer variables exist).  Takes about 0.35 s without hot start
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            for lp_method in the_methods:
                lp.simplex(tol_bnd=tolerance_optimality,
                           tol_dj=tolerance_optimality,
                           meth=lp_method)
                if lp.status == 'opt':
                    if lp.kind == int:
                        lp.integer(tol_int=tolerance_integer)
                    break
    else:
        if lp.kind == int:
            lp.simplex(tol_bnd=tolerance_optimality,
                       tol_dj=tolerance_optimality,
                       meth=lp_method,
                       tm_lim=100)  # we first have to solve the LP?
            lp.integer(tol_int=tolerance_integer)
        else:
            lp.simplex(tol_bnd=tolerance_optimality,
                       tol_dj=tolerance_optimality,
                       meth=lp_method,
                       tm_lim=100)

        #If the solver takes more than 0.1 s with a hot start it is likely stuck
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            if lp.kind == int:
                lp.simplex(tol_bnd=tolerance_optimality,
                           tol_dj=tolerance_optimality,
                           meth=lp_method)  # we first have to solve the LP?
                lp.integer(tol_int=tolerance_integer)
            else:
                for lp_method in the_methods:
                    lp.simplex(tol_bnd=tolerance_optimality,
                               tol_dj=tolerance_optimality,
                               meth=lp_method)
                    if lp.status == 'opt':
                        if lp.kind == int:
                            lp.integer(tol_int=tolerance_integer)
                        break
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp = optimize_glpk(
                cobra_model,
                new_objective=new_objective,
                objective_sense=objective_sense,
                min_norm=min_norm,
                the_problem=None,
                print_solver_time=print_solver_time,
                tolerance_optimality=tolerance_optimality,
                tolerance_feasibility=tolerance_feasibility)['the_problem']
            if lp.status == 'opt':
                if lp.kind == int:
                    lp.integer(tol_int=tolerance_integer)

        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp.simplex(tol_bnd=tolerance_optimality,
                       presolve=True,
                       tm_lim=5000)
            if lp.kind == int:
                lp.integer(tol_int=tolerance_integer)

    if print_solver_time:
        print 'simplex time: %f' % (time() - start_time)
    x = []
    y = []
    x_dict = {}
    y_dict = {}
    if lp.status in status_dict:
        status = status_dict[lp.status]
    else:
        status = 'failed'
    if status == 'optimal':
        objective_value = lp.obj.value
        [(x.append(float(c.primal)), x_dict.update({c.name: c.primal}))
         for c in lp.cols]

        if lp.kind == float:
            #return the duals as well as the primals for LPs
            [(y.append(float(c.dual)), y_dict.update({c.name: c.dual}))
             for c in lp.rows]
        else:
            #MIPs don't have duals
            y = y_dict = None
        x = array(x)

    else:
        x = y = x_dict = y_dict = objective_value = None
        if error_reporting:
            print 'glpk failed: %s' % lp.status
    cobra_model.solution = the_solution = Solution(objective_value,
                                                   x=x,
                                                   x_dict=x_dict,
                                                   y=y,
                                                   y_dict=y_dict,
                                                   status=status)
    solution = {'the_problem': lp, 'the_solution': the_solution}

    return solution
Example #3
0
def _optimize_cplex(cobra_model,
                    new_objective=None,
                    objective_sense='maximize',
                    min_norm=0,
                    the_problem=None,
                    tolerance_optimality=1e-6,
                    tolerance_feasibility=1e-6,
                    tolerance_integer=1e-9,
                    tolerance_barrier=1e-8,
                    error_reporting=None,
                    print_solver_time=False,
                    lp_method=1,
                    lp_parallel=0,
                    copy_problem=False,
                    relax_b=None,
                    quadratic_component=None,
                    reuse_basis=True,
                    update_problem_reaction_bounds=True):
    """Uses the ILOG/CPLEX (www.ibm.com/software/integration/optimization/cplex-optimizer/)
    optimizer to perform an optimization on cobra_model for the objective_coefficients in
    cobra_model._objective_coefficients based on the objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.

    quadratic_component: None or 
          scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions))
         If not None:
          Solves quadratic programming problems for cobra_models of the form:
          minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x
          such that,
            cobra_model._lower_bounds <= x <= cobra_model._upper_bounds
            cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b
            
    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.


    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX

    method for linear optimization: 0 = automatic
    1 = primal simplex, 2 = dual simplex, 3 = network simplex,
    4 = barrier, 5 = sifting, 6 = concurrent dual, barrier, and primal
    
    lp.solve() with Salmonella model:
         cold start: 0.05 seconds
         hot start: 0.05 seconds (slow due to copying the LP)

    """
    if relax_b is not None:
        raise Exception('Need to reimplement constraint relaxation')
    from numpy import array, nan, zeros
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict

    if error_reporting == 'time' or print_solver_time:
        from time import time
        start_time = time()
    try:
        from cplex import Cplex, SparsePair
        variable_kind_dict = eval(variable_kind_dict['cplex'])
        status_dict = eval(status_dict['cplex'])
    except ImportError as e:
        import sys
        if 'wrong architecture' in e[0] and sys.maxsize > 2**32:
            print 'CPLEX python API is not 64-bit.  please contact your IBM representative'
        else:
            print e
    if new_objective and new_objective != 'update problem':
        update_objective(cobra_model, new_objective)
    if the_problem == None or the_problem in ['return', 'setup', 'parallel'] \
           or not isinstance(the_problem, Cplex):
        lp = Cplex()
        #Using the new objects
        #NOTE: This might be slow
        objective_coefficients = []
        lower_bounds = []
        upper_bounds = []
        variable_names = []
        variable_kinds = []
        [(objective_coefficients.append(x.objective_coefficient),
          lower_bounds.append(x.lower_bound),
          upper_bounds.append(x.upper_bound), variable_names.append(x.id),
          variable_kinds.append(variable_kind_dict[x.variable_kind]))
         for x in cobra_model.reactions]
        #Cplex decides that the problem is a MIP if variable_kinds are supplied
        #even if there aren't any integers.
        if Cplex.variables.type.integer in variable_kinds:
            lp.variables.add(obj=objective_coefficients,
                             lb=lower_bounds,
                             ub=upper_bounds,
                             names=variable_names,
                             types=variable_kinds)
        else:
            lp.variables.add(obj=objective_coefficients,
                             lb=lower_bounds,
                             ub=upper_bounds,
                             names=variable_names)

        if relax_b:
            raise Exception('need to reimplement relax_b')
            ## range_values = zeros(len(cobra_model.metabolites))
            ## b_values = array([x._bound for x in cobra_model.metabolties])
            ## for the_nonzero in list(b_values.nonzero()[0]):
            ##     range_values[the_nonzero] = -relax_b
        constraint_sense = []
        constraint_names = []
        constraint_limits = []
        [(constraint_sense.append(x._constraint_sense),
          constraint_names.append(x.id), constraint_limits.append(x._bound))
         for x in cobra_model.metabolites]

        the_linear_expressions = []
        #NOTE: This won't work with metabolites that aren't in any reaction
        for the_metabolite in cobra_model.metabolites:
            variable_list = []
            coefficient_list = []
            for the_reaction in the_metabolite._reaction:
                variable_list.append(the_reaction.id)
                coefficient_list.append(
                    the_reaction._metabolites[the_metabolite])
            the_linear_expressions.append(
                SparsePair(ind=variable_list, val=coefficient_list))
        if quadratic_component is not None:
            if not hasattr(quadratic_component, 'todok'):
                raise Exception(
                    'quadratic component must be a scipy.sparse type array')
            quadratic_component_scaled = quadratic_component.todok()

            lp.parameters.emphasis.numerical.set(1)
            for k, v in quadratic_component_scaled.items():
                lp.objective.set_quadratic_coefficients(
                    int(k[0]), int(k[1]), v)

        if relax_b:
            lp.linear_constraints.add(lin_expr=the_linear_expressions,
                                      rhs=constraint_limits,
                                      range_values=list(range_values),
                                      senses=constraint_sense,
                                      names=constraint_names)

        else:
            lp.linear_constraints.add(lin_expr=the_linear_expressions,
                                      rhs=constraint_limits,
                                      senses=constraint_sense,
                                      names=constraint_names)

        if error_reporting == 'time':
            print 'setup new problem: ' + repr(time() - start_time)
            start_time = time()

        #Set the problem type as cplex doesn't appear to do this correctly
        problem_type = Cplex.problem_type.LP
        if Cplex.variables.type.integer in variable_kinds:
            if quadratic_component is not None:
                problem_type = Cplex.problem_type.MIQP
            else:
                problem_type = Cplex.problem_type.MILP
        elif quadratic_component is not None:
            problem_type = Cplex.problem_type.QP
        lp.set_problem_type(problem_type)

    else:
        if copy_problem:
            lp = Cplex(the_problem)
            if error_reporting == 'time':
                print 'copy problem: ' + repr(time() - start_time)
                start_time = time()

        else:
            lp = the_problem

        if new_objective:
            lp.objective.set_linear([(x.id, float(x.objective_coefficient))
                                     for x in cobra_model.reactions])
            if error_reporting == 'time':
                print 'set lp objective: ' + repr(time() - start_time)
                start_time = time()
        #SPEED THIS UP
        if update_problem_reaction_bounds:
            lp.variables.set_upper_bounds([(x.id, float(x.upper_bound))
                                           for x in cobra_model.reactions])
            lp.variables.set_lower_bounds([(x.id, float(x.lower_bound))
                                           for x in cobra_model.reactions])

        if error_reporting == 'time':
            print 'changed all bounds: ' + repr(time() - start_time)
            start_time = time()

    if objective_sense == 'maximize':
        lp.objective.set_sense(lp.objective.sense.maximize)
    else:
        lp.objective.set_sense(lp.objective.sense.minimize)
    if tolerance_optimality < 1e-10:
        lp.parameters.simplex.perturbation.constant.set(1)
        lp.parameters.simplex.pgradient.set(1)
        lp.parameters.emphasis.memory.set(1)
        #lp.parameters.simplex.tolerances.markowitz.set(.01)
        lp.parameters.advance.set(2)

    lp.parameters.simplex.tolerances.optimality.set(tolerance_optimality)
    lp.parameters.simplex.tolerances.feasibility.set(tolerance_feasibility)

    if lp.get_problem_type() in [
            Cplex.problem_type.LP, Cplex.problem_type.MILP
    ]:
        lp.parameters.lpmethod.set(lp_method)
    elif lp.get_problem_type() in [
            Cplex.problem_type.QP, Cplex.problem_type.MIQP
    ]:
        lp.parameters.qpmethod.set(lp_method)

    if lp_parallel > 1:
        lp.parameters.threads.set(lp_parallel)
    #lp.parameters.parallel.set(lp_parallel)
    lp.parameters.barrier.convergetol.set(tolerance_barrier)

    if the_problem == 'setup':
        return lp

    if not error_reporting:
        lp.set_results_stream(None)
        lp.set_warning_stream(None)
    if print_solver_time:
        start_time = time()
    if not isinstance(the_problem, Cplex):
        #TODO: set tolerance
        lp.solve()
        # Solve this LP with the simplex method.  Takes about 0.2 s without hot start
        lp.status = lp.solution.status[lp.solution.get_status()]
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
    else:
        if isinstance(the_problem, Cplex) and reuse_basis:
            try:
                the_basis = the_problem.solution.basis.get_basis()
                lp.start.set_basis(the_basis[0], the_basis[1])
                #TODO: Determine whether the primal or dual works best for the
                #problem of interest.  For the ME matrix the primal appears to
                #work best
                lp_method = 1
                lp.parameters.preprocessing.presolve.set(0)
                lp.parameters.lpmethod.set(lp_method)
            except:
                print 'no basis in the_problem'
        #TODO: set tolerance and time limit
        #lp.parameters.timelimit.set()
        lp.solve()
        #If the solver takes more than 0.1 s with a hot start it is likely stuck
        lp.status = lp.solution.status[lp.solution.get_status()]
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            #Cycle through the different solver options, if a solution is not found
            for lp_method in (1, 2, 3, 4, 5, 6):
                lp = optimize_cplex(
                    cobra_model,
                    new_objective=new_objective,
                    objective_sense=objective_sense,
                    min_norm=min_norm,
                    the_problem=None,
                    print_solver_time=print_solver_time,
                    tolerance_optimality=tolerance_optimality,
                    tolerance_feasibility=tolerance_feasibility,
                    lp_method=lp_method,
                    quadratic_component=quadratic_component)['the_problem']
                lp.status = lp.solution.status[lp.solution.get_status()]
                if lp.status in status_dict:
                    status = status_dict[lp.status]
                else:
                    status = 'failed'
                if status == 'optimal':
                    break
    if error_reporting == 'time':
        print 'solver time: ' + repr(
            time() - start_time) + ' with method ' + repr(lp_method)
        start_time = time()

    if print_solver_time:
        print 'cplex time: %f' % (time() - start_time)
    #TODO: It might be able to speed this up a little.
    if status == 'optimal':
        objective_value = lp.solution.get_objective_value()
        #This can be sped up a little
        x_dict = dict(zip(lp.variables.get_names(), lp.solution.get_values()))
        x = array(lp.solution.get_values())
        x = x.reshape(x.shape[0], 1)
        #MIP's don't have duals
        if lp.get_problem_type() in (Cplex.problem_type.MIQP,
                                     Cplex.problem_type.MILP):

            y = y_dict = None
        else:
            y_dict = dict(
                zip(lp.linear_constraints.get_names(),
                    lp.solution.get_dual_values()))
            y = array(lp.solution.get_dual_values())
            y = y.reshape(y.shape[0], 1)
    else:
        x = y = x_dict = y_dict = objective_value = None
        if error_reporting:
            print 'cplex failed: %s' % lp.status

    cobra_model.solution = the_solution = Solution(objective_value,
                                                   x=x,
                                                   x_dict=x_dict,
                                                   status=status,
                                                   y=y,
                                                   y_dict=y_dict)
    solution = {'the_problem': lp, 'the_solution': the_solution}
    return solution
Example #4
0
def _optimize_glpk(cobra_model, new_objective=None, objective_sense='maximize',
                  min_norm=0, the_problem=None, 
                  tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_integer=1e-9,
                  error_reporting=None, print_solver_time=False,
                 lp_method=1, quadratic_component=None,
                  reuse_basis=True,
                  #Not implemented
                  tolerance_barrier=None, lp_parallel=None,
                  copy_problem=None, relax_b=None,update_problem_reaction_bounds=True):
    """Uses the GLPK (www.gnu.org/software/glpk/) optimizer via pyglpk
    (http://www.tfinley.net/software/pyglpk/release.html) to perform an optimization
    on cobra_model for the objective_coefficients in cobra_model._objective_coefficients
    based on the objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.

    quadratic_component: None.  GLPK cannot solve quadratic programs at the moment.

    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.  Currently, only True is available for GLPK

    
    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX
    
    lp.simplex() with Salmonella model:
         cold start: 0.42 seconds
         hot start: 0.0013 seconds
    """

    from numpy import zeros, array, nan
    #TODO: Speed up problem creation
    if hasattr(quadratic_component, 'todok'):
        raise Exception('GLPK cannot solve quadratic programs please '+\
                        'try using the gurobi or cplex solvers')

    from glpk import LPX
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict
    status_dict = eval(status_dict['glpk'])
    variable_kind_dict = eval(variable_kind_dict['glpk'])

    if new_objective and new_objective != 'update problem':
        update_objective(cobra_model, new_objective)
    #Faster to use these dicts than index lists
    index_to_metabolite = dict(zip(range(len(cobra_model.metabolites)),
                                   cobra_model.metabolites))
    index_to_reaction = dict(zip(range(len(cobra_model.reactions)),
                                 cobra_model.reactions))
    reaction_to_index = dict(zip(index_to_reaction.values(),
                                 index_to_reaction.keys()))
    if the_problem == None or the_problem in ['return', 'setup'] or \
           not isinstance(the_problem, LPX):
        lp = LPX()        # Create empty problem instance
        lp.name = 'cobra'     # Assign symbolic name to problem
        lp.rows.add(len(cobra_model.metabolites))
        lp.cols.add(len(cobra_model.reactions))
        linear_constraints = []
        for r in lp.rows:
            the_metabolite = index_to_metabolite[r.index]
            r.name = the_metabolite.id
            b = float(the_metabolite._bound)
            c = the_metabolite._constraint_sense
            if c == 'E':
                r.bounds = b, b     # Set metabolite to steady state levels
            elif c == 'L':
                r.bounds = None, b
            elif c == 'G':
                r.bounds = b, None
            #Add in the linear constraints

            for the_reaction in the_metabolite._reaction:
                reaction_index = reaction_to_index[the_reaction]
                the_coefficient = the_reaction._metabolites[the_metabolite]
                linear_constraints.append((r.index, reaction_index,
                                           the_coefficient))
        #Need to assign lp.matrix after constructing the whole list
        lp.matrix = linear_constraints
        objective_coefficients = []

        for c in lp.cols:
            the_reaction = index_to_reaction[c.index]
            c.name = the_reaction.id           
            the_reaction = index_to_reaction[c.index]
            c.kind = variable_kind_dict[the_reaction.variable_kind]
            c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
            objective_coefficients.append(float(the_reaction.objective_coefficient))
        #Add the new objective coefficients to the problem
        lp.obj[:] = objective_coefficients
    else:
        lp = the_problem
        #BUG with changing / unchanging the basis
        if new_objective is not None:
            objective_coefficients = []
            for c in lp.cols:      # Iterate over all rows
                the_reaction = index_to_reaction[c.index]
                c.name = the_reaction.id
                c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
                objective_coefficients.append(float(the_reaction.objective_coefficient))
                c.kind = variable_kind_dict[the_reaction.variable_kind]
            #Add the new objective coefficients to the problem
            lp.obj[:] = objective_coefficients
        else:
            for c in lp.cols:      # Iterate over all rows
                the_reaction = index_to_reaction[c.index]
                c.name = the_reaction.id
                c.bounds = the_reaction.lower_bound, the_reaction.upper_bound
                c.kind = variable_kind_dict[the_reaction.variable_kind]
    if objective_sense.lower() == 'maximize':
        lp.obj.maximize = True # Set this as a maximization problem
    else:
        lp.obj.maximize = False
    if the_problem == 'setup':
        return lp
    if  print_solver_time:
        start_time = time()
    the_methods = [1, 2, 3]
    if lp_method in the_methods:
        the_methods.remove(lp_method)
    else:
        lp_method = 1
    if not isinstance(the_problem, LPX):
       if lp.kind == int:
           lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method)  # we first have to solve the LP?
           lp.integer(tol_int=tolerance_integer)
       else:
           lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method)
       # Solve this LP or MIP with the simplex (depending on if integer variables exist).  Takes about 0.35 s without hot start
       if lp.status in status_dict:
           status = status_dict[lp.status]
       else:
           status = 'failed'
       if status != 'optimal':
           for lp_method in the_methods:
               lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method)
               if lp.status == 'opt':
                   if lp.kind == int:
                       lp.integer(tol_int=tolerance_integer)
                   break
    else:
        if lp.kind == int:
            lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100)  # we first have to solve the LP?
            lp.integer(tol_int=tolerance_integer)
        else:
            lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100)
       
        #If the solver takes more than 0.1 s with a hot start it is likely stuck
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            if lp.kind == int:
               lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method)  # we first have to solve the LP?
               lp.integer(tol_int=tolerance_integer)
            else:
               for lp_method in the_methods:
                   lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method)
                   if lp.status == 'opt':
                       if lp.kind == int:
                           lp.integer(tol_int=tolerance_integer) 
                       break
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp = optimize_glpk(cobra_model, new_objective=new_objective,
                               objective_sense=objective_sense,
                               min_norm=min_norm, the_problem=None,
                               print_solver_time=print_solver_time,
                               tolerance_optimality=tolerance_optimality,
                               tolerance_feasibility=tolerance_feasibility)['the_problem']
            if lp.status == 'opt':
                if lp.kind == int:
                    lp.integer(tol_int=tolerance_integer)

        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp.simplex(tol_bnd=tolerance_optimality, presolve=True, tm_lim=5000)
            if lp.kind == int:
                lp.integer(tol_int=tolerance_integer)

    if print_solver_time:
        print 'simplex time: %f'%(time() - start_time)
    x = []
    y = []
    x_dict = {}
    y_dict = {}
    if lp.status in status_dict:
        status = status_dict[lp.status]
    else:
        status = 'failed'
    if status == 'optimal':
        objective_value = lp.obj.value
        [(x.append(float(c.primal)),
          x_dict.update({c.name:c.primal}))
          for c in lp.cols]
        
        if lp.kind == float:
            #return the duals as well as the primals for LPs
            [(y.append(float(c.dual)),
              y_dict.update({c.name:c.dual}))
             for c in lp.rows]
        else:
            #MIPs don't have duals
            y = y_dict = None
        x = array(x)
            
    else:
        x = y = x_dict = y_dict = objective_value = None
        if error_reporting:
            print 'glpk failed: %s'%lp.status
    the_solution = Solution(objective_value, x=x, x_dict=x_dict,
                            y=y, y_dict=y_dict,
                            status=status)
    solution = {'the_problem': lp, 'the_solution': the_solution}

    return solution
Example #5
0
def _optimize_gurobi(cobra_model, new_objective=None, objective_sense='maximize',
                    min_norm=0, the_problem=None,
                    tolerance_optimality=1e-6, tolerance_feasibility=1e-6,
                    tolerance_barrier=None, tolerance_integer=1e-9, error_reporting=None,
                    print_solver_time=False, copy_problem=False, lp_method=0,
                    relax_b=None, quad_precision=False, quadratic_component=None,
                    reuse_basis=True, lp_parallel=None, update_problem_reaction_bounds=True):
    """Uses the gurobi (http://gurobi.com) optimizer to perform an optimization on cobra_model
    for the objective_coefficients in cobra_model._objective_coefficients based
    on objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    quad_precision: Boolean.  Whether or not to used quad precision in calculations

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.


    quadratic_component: None or 
          scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions))
         If not None:
          Solves quadratic programming problems for cobra_models of the form:
          minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x
          such that,
            cobra_model._lower_bounds <= x <= cobra_model._upper_bounds
            cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b

            NOTE: When solving quadratic problems it may be necessary to disable quad_precision
            and use lp_method = 0 for gurobi.

    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.

    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX
    
    lp_parallel: Not implemented

    lp.optimize() with Salmonella model:
         cold start: 0.063 seconds
         hot start: 0.057 seconds (Slow due to copying the LP)
         

    """
    if relax_b is not None:
        raise Exception('Need to reimplement constraint relaxation')
    from numpy import array, nan, zeros
    #TODO: speed this up
    if objective_sense == 'maximize':
        objective_sense = -1
    else:
        objective_sense = 1
    from gurobipy import Model, LinExpr, GRB, QuadExpr
    sense_dict = {'E': GRB.EQUAL,
                  'L': GRB.LESS_EQUAL,
                  'G': GRB.GREATER_EQUAL}
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict

    variable_kind_dict = eval(variable_kind_dict['gurobi'])
    status_dict = eval(status_dict['gurobi'])

    #Update objectives if they are new.
    if new_objective and new_objective != 'update problem':
       update_objective(cobra_model, new_objective)
    #Create a new problem
    if not the_problem or the_problem in ['return', 'setup'] or \
           not isinstance(the_problem, Model):
        lp = Model("cobra")
        lp.Params.OutputFlag = 0
        lp.Params.LogFile = ''
        # Create variables
        #TODO:  Speed this up 
        variable_list = [lp.addVar(lb=float(x.lower_bound),
                                   ub=float(x.upper_bound),
                                   obj=objective_sense*float(x.objective_coefficient),
                                   name=x.id,
                                   vtype=variable_kind_dict[x.variable_kind])
                         for x in cobra_model.reactions]
        reaction_to_variable = dict(zip(cobra_model.reactions,
                                        variable_list))
        # Integrate new variables
        lp.update()
        #Set objective to quadratic program
        if quadratic_component is not None:
            if not hasattr(quadratic_component, 'todok'):
                raise Exception('quadratic component must be a scipy.sparse type array')

            quadratic_objective = QuadExpr()
            for (index_0, index_1), the_value in quadratic_component.todok().items():
                quadratic_objective.addTerms(the_value,
                                       variable_list[index_0],
                                       variable_list[index_1])
            lp.setObjective(quadratic_objective, sense=objective_sense)
        #Constraints are based on mass balance
        #Construct the lin expression lists and then add
        #TODO: Speed this up as it takes about .18 seconds
        #HERE
        for the_metabolite in cobra_model.metabolites:
            constraint_coefficients = []
            constraint_variables = []
            for the_reaction in the_metabolite._reaction:
                constraint_coefficients.append(the_reaction._metabolites[the_metabolite])
                constraint_variables.append(reaction_to_variable[the_reaction])
            #Add the metabolite to the problem
            lp.addConstr(LinExpr(constraint_coefficients, constraint_variables),
                         sense_dict[the_metabolite._constraint_sense.upper()],
                         the_metabolite._bound,
                         the_metabolite.id)
    else:
        #When reusing the basis only assume that the objective coefficients or bounds can change
        if copy_problem:
            lp = the_problem.copy()
        else:
            lp = the_problem
        if not reuse_basis:
            lp.reset()
        for the_variable, the_reaction in zip(lp.getVars(),
                                              cobra_model.reactions):
            the_variable.lb = float(the_reaction.lower_bound)
            the_variable.ub = float(the_reaction.upper_bound)
            the_variable.obj = float(objective_sense*the_reaction.objective_coefficient)

    
    if the_problem == 'setup':
        return lp
    if print_solver_time:
        start_time = time()
    lp.update()
    lp.setParam("FeasibilityTol", tolerance_feasibility)
    lp.setParam("OptimalityTol", tolerance_optimality) 
    if tolerance_barrier:
        lp.setParam("BarConvTol", tolerance_barrier)

    if quad_precision:
            lp.setParam("Quad", 1)
    lp.setParam("Method", lp_method)

    #Different methods to try if lp_method fails
    the_methods = [0, 2, 1]
    if lp_method in the_methods:
        the_methods.remove(lp_method)
    if not isinstance(the_problem, Model):
        lp.optimize()
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            #Try to find a solution using a different method
            lp.setParam("MarkowitzTol", 1e-2)
            for lp_method in the_methods:
                lp.setParam("Method", lp_method)
                lp.optimize()
                if status_dict[lp.status] == 'optimal':
                    break
    else:
        lp.setParam("TimeLimit", 0.6)
        lp.optimize()
        lp.setParam("TimeLimit", "default")
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            lp.setParam("MarkowitzTol", 1e-2)
            #Try to find a solution using a different method
            for lp_method in the_methods:
                lp.setParam("Method", lp_method)
                lp.optimize()
                if status_dict[lp.status] == 'optimal':
                    break
                
            if status_dict[lp.status] != 'optimal':
                lp = optimize_gurobi(cobra_model, new_objective=new_objective, objective_sense=objective_sense,
                                     min_norm=min_norm, the_problem=None, 
                                     print_solver_time=print_solver_time)['the_problem']


    if print_solver_time:
        print 'optimize time: %f'%(time() - start_time)
    x_dict = {}
    y_dict = {}
    y = None
    if lp.status in status_dict:
        status = status_dict[lp.status]
    else:
        status = 'failed'
    if status == 'optimal':
        objective_value = objective_sense*lp.ObjVal
        [x_dict.update({v.VarName: v.X}) for v in lp.getVars()]
        x = array([x_dict[v.id] for v in cobra_model.reactions])
        if lp.isMIP:
            y = y_dict = None #MIP's don't have duals
        else:
            [y_dict.update({c.ConstrName: c.Pi})
             for c in lp.getConstrs()]
            y = array([y_dict[v.id] for v in cobra_model.metabolites])
    else:
        y = y_dict = x = x_dict = None
        objective_value = None
        if error_reporting:
            print 'gurobi failed: %s'%lp.status  
    the_solution = Solution(objective_value, x=x, x_dict=x_dict,
                            y=y, y_dict=y_dict,
                            status=status)
    solution = {'the_problem': lp, 'the_solution': the_solution}
    return solution
Example #6
0
def _optimize_cplex(cobra_model, new_objective=None, objective_sense='maximize',
                   min_norm=0, the_problem=None, 
                   tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_integer=1e-9,
                   tolerance_barrier=1e-8,error_reporting=None, 
                   print_solver_time=False, lp_method=1, lp_parallel=0, copy_problem=False,
                   relax_b=None, quadratic_component=None, reuse_basis=True,
                   update_problem_reaction_bounds=True):
    """Uses the ILOG/CPLEX (www.ibm.com/software/integration/optimization/cplex-optimizer/)
    optimizer to perform an optimization on cobra_model for the objective_coefficients in
    cobra_model._objective_coefficients based on the objective sense.

    cobra_model: A cobra.Model object

    new_objective: Reaction, String, or Integer referring to a reaction in
    cobra_model.reactions to set as the objective.  Currently, only supports single
    objective coeffients.  Will expand to include mixed objectives.

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

    the_problem: None or a problem object for the specific solver that can be used to hot
    start the next solution.

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

    error_reporting: None or True to disable or enable printing errors encountered
    when trying to find the optimal solution.
    
    print_solver_time: False or True.  Indicates if the time to calculate the solution
    should be displayed.

    quadratic_component: None or 
          scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions))
         If not None:
          Solves quadratic programming problems for cobra_models of the form:
          minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x
          such that,
            cobra_model._lower_bounds <= x <= cobra_model._upper_bounds
            cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b
            
    reuse_basis: Boolean.  If True and the_problem is a model object for the solver,
    attempt to hot start the solution.


    update_problem_reaction_bounds: Boolean.  Set to True if you're providing the_problem
    and you've modified reaction bounds on your cobra_model since creating the_problem.  Only
    necessary for CPLEX

    method for linear optimization: 0 = automatic
    1 = primal simplex, 2 = dual simplex, 3 = network simplex,
    4 = barrier, 5 = sifting, 6 = concurrent dual, barrier, and primal
    
    lp.solve() with Salmonella model:
         cold start: 0.05 seconds
         hot start: 0.05 seconds (slow due to copying the LP)

    """
    if relax_b is not None:
        raise Exception('Need to reimplement constraint relaxation')
    from numpy import array, nan, zeros
    from cobra.flux_analysis.objective import update_objective
    from cobra.solvers.legacy import status_dict, variable_kind_dict

    if error_reporting == 'time' or print_solver_time:
        from time import time
        start_time = time()
    try:
        from cplex import Cplex, SparsePair
        variable_kind_dict = eval(variable_kind_dict['cplex'])
        status_dict = eval(status_dict['cplex'])
    except ImportError as e:
        import sys
        if 'wrong architecture' in e[0] and sys.maxsize > 2**32:
            print 'CPLEX python API is not 64-bit.  please contact your IBM representative'
        else:
            print e
    if new_objective and new_objective != 'update problem':
       update_objective(cobra_model, new_objective)
    if the_problem == None or the_problem in ['return', 'setup', 'parallel'] \
           or not isinstance(the_problem, Cplex):
        lp = Cplex()
        #Using the new objects
        #NOTE: This might be slow
        objective_coefficients = []
        lower_bounds = []
        upper_bounds = []
        variable_names = []
        variable_kinds = []
        [(objective_coefficients.append(x.objective_coefficient),
          lower_bounds.append(x.lower_bound),
          upper_bounds.append(x.upper_bound),
          variable_names.append(x.id),
          variable_kinds.append(variable_kind_dict[x.variable_kind]))
         for x in cobra_model.reactions]
        #Cplex decides that the problem is a MIP if variable_kinds are supplied
        #even if there aren't any integers.
        if Cplex.variables.type.integer in variable_kinds:
            lp.variables.add(obj=objective_coefficients,
                             lb=lower_bounds,
                             ub=upper_bounds,
                             names=variable_names,
                             types=variable_kinds)
        else:
            lp.variables.add(obj=objective_coefficients,
                             lb=lower_bounds,
                             ub=upper_bounds,
                             names=variable_names)

        if relax_b:
            raise Exception('need to reimplement relax_b')
            ## range_values = zeros(len(cobra_model.metabolites))
            ## b_values = array([x._bound for x in cobra_model.metabolties])
            ## for the_nonzero in list(b_values.nonzero()[0]):
            ##     range_values[the_nonzero] = -relax_b
        constraint_sense = []
        constraint_names = []
        constraint_limits = []
        [(constraint_sense.append(x._constraint_sense),
          constraint_names.append(x.id),
          constraint_limits.append(x._bound))
         for x in cobra_model.metabolites]
        
        the_linear_expressions = []
        #NOTE: This won't work with metabolites that aren't in any reaction
        for the_metabolite in cobra_model.metabolites:
            variable_list = []
            coefficient_list = []
            for the_reaction in the_metabolite._reaction:
                variable_list.append(the_reaction.id)
                coefficient_list.append(the_reaction._metabolites[the_metabolite])
            the_linear_expressions.append(SparsePair(ind=variable_list,
                                                     val=coefficient_list))
        if quadratic_component is not None:
            if not hasattr(quadratic_component, 'todok'):
                raise Exception('quadratic component must be a scipy.sparse type array')
            quadratic_component_scaled = quadratic_component.todok()

            lp.parameters.emphasis.numerical.set(1)
            for k, v in quadratic_component_scaled.items():
                lp.objective.set_quadratic_coefficients(int(k[0]), int(k[1]), v)
         

        if relax_b:
            lp.linear_constraints.add(lin_expr=the_linear_expressions,
                                      rhs=constraint_limits,
                                      range_values=list(range_values),
                                      senses=constraint_sense,
                                      names=constraint_names)

        else:
            lp.linear_constraints.add(lin_expr=the_linear_expressions,
                                      rhs=constraint_limits,
                                      senses=constraint_sense,
                                      names=constraint_names)

        if error_reporting == 'time':
            print 'setup new problem: ' + repr(time()-start_time)
            start_time = time()
        
        #Set the problem type as cplex doesn't appear to do this correctly
        problem_type = Cplex.problem_type.LP
        if Cplex.variables.type.integer in variable_kinds:
            if quadratic_component is not None:
                problem_type = Cplex.problem_type.MIQP
            else:
                problem_type = Cplex.problem_type.MILP
        elif quadratic_component is not None:
            problem_type = Cplex.problem_type.QP
        lp.set_problem_type(problem_type)

    else:
        if copy_problem:
            lp = Cplex(the_problem)
            if error_reporting == 'time':
                print 'copy problem: ' + repr(time()-start_time)
                start_time = time()

        else:
            lp = the_problem

        if new_objective:
            lp.objective.set_linear([(x.id, float(x.objective_coefficient))
                                     for x in cobra_model.reactions])
            if error_reporting == 'time':
                print 'set lp objective: ' + repr(time()-start_time)
                start_time = time()
        #SPEED THIS UP
        if update_problem_reaction_bounds:
            lp.variables.set_upper_bounds([(x.id, float(x.upper_bound))
                                            for x in cobra_model.reactions])
            lp.variables.set_lower_bounds([(x.id, float(x.lower_bound))
                                            for x in cobra_model.reactions])

        if error_reporting == 'time':
            print 'changed all bounds: ' + repr(time()-start_time)
            start_time = time()

    if objective_sense == 'maximize':
        lp.objective.set_sense(lp.objective.sense.maximize)
    else:
        lp.objective.set_sense(lp.objective.sense.minimize)
    if tolerance_optimality < 1e-10:
        lp.parameters.simplex.perturbation.constant.set(1)
        lp.parameters.simplex.pgradient.set(1)
        lp.parameters.emphasis.memory.set(1)
        #lp.parameters.simplex.tolerances.markowitz.set(.01)
        lp.parameters.advance.set(2)

    lp.parameters.simplex.tolerances.optimality.set(tolerance_optimality)
    lp.parameters.simplex.tolerances.feasibility.set(tolerance_feasibility)


    if lp.get_problem_type() in [Cplex.problem_type.LP,
                                 Cplex.problem_type.MILP]:
        lp.parameters.lpmethod.set(lp_method)
    elif lp.get_problem_type() in [Cplex.problem_type.QP,
                                 Cplex.problem_type.MIQP]:
        lp.parameters.qpmethod.set(lp_method)


    if lp_parallel > 1:
        lp.parameters.threads.set(lp_parallel)
    #lp.parameters.parallel.set(lp_parallel)
    lp.parameters.barrier.convergetol.set(tolerance_barrier)

    if the_problem == 'setup':
        return lp

    if not error_reporting:
        lp.set_results_stream(None)
        lp.set_warning_stream(None)
    if  print_solver_time:
        start_time = time()
    if not isinstance(the_problem, Cplex):
        #TODO: set tolerance
        lp.solve()
        # Solve this LP with the simplex method.  Takes about 0.2 s without hot start
        lp.status = lp.solution.status[lp.solution.get_status()]
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
    else:
        if isinstance(the_problem, Cplex) and reuse_basis:
            try:
                the_basis = the_problem.solution.basis.get_basis()
                lp.start.set_basis(the_basis[0],the_basis[1])
                #TODO: Determine whether the primal or dual works best for the
                #problem of interest.  For the ME matrix the primal appears to
                #work best
                lp_method = 1
                lp.parameters.preprocessing.presolve.set(0)
                lp.parameters.lpmethod.set(lp_method) 
            except:
                print 'no basis in the_problem'
        #TODO: set tolerance and time limit
        #lp.parameters.timelimit.set()
        lp.solve()
        #If the solver takes more than 0.1 s with a hot start it is likely stuck
        lp.status = lp.solution.status[lp.solution.get_status()]
        if lp.status in status_dict:
            status = status_dict[lp.status]
        else:
            status = 'failed'
        if status != 'optimal':
            #Cycle through the different solver options, if a solution is not found
            for lp_method in (1, 2, 3, 4, 5, 6):
                lp = optimize_cplex(cobra_model, new_objective=new_objective,
                                    objective_sense=objective_sense,
                                    min_norm=min_norm, the_problem=None,
                                    print_solver_time=print_solver_time,
                                    tolerance_optimality=tolerance_optimality,
                                    tolerance_feasibility=tolerance_feasibility,
                                    lp_method=lp_method,
                                    quadratic_component=quadratic_component)['the_problem']
                lp.status = lp.solution.status[lp.solution.get_status()]
                if lp.status in status_dict:
                    status = status_dict[lp.status]
                else:
                    status = 'failed'
                if status == 'optimal':
                    break
    if error_reporting == 'time':
        print 'solver time: ' + repr(time()-start_time) + ' with method ' + repr(lp_method)
        start_time = time()

    if print_solver_time:
        print 'cplex time: %f'%(time() - start_time)
    x = []
    x_dict = {}
    #TODO: It might be able to speed this up a little.
    if status == 'optimal':
        objective_value = lp.solution.get_objective_value()
        #This can be sped up a little
        x_dict = dict(zip(lp.variables.get_names(),
                     lp.solution.get_values()))
        x = array(lp.solution.get_values())
        x = x.reshape(x.shape[0],1)
        #MIP's don't have duals
        if lp.get_problem_type() in (Cplex.problem_type.MIQP,
                                     Cplex.problem_type.MILP):

            y = y_dict = None
        else:
            y_dict = dict(zip(lp.linear_constraints.get_names(),
                              lp.solution.get_dual_values()))
            y = array(lp.solution.get_dual_values())
            y = y.reshape(y.shape[0],1)
    else:
        x = y = x_dict = y_dict = objective_value = None
        if error_reporting:
            print 'cplex failed: %s'%lp.status

    the_solution = Solution(objective_value, x=x, x_dict=x_dict,
                            status=status, y=y, y_dict=y_dict)
    solution = {'the_problem': lp, 'the_solution': the_solution}
    return solution    
Example #7
0
    def load_ALEWt(self,anoxic = False, oxic = True, update_ampms2 = True, convert2irreversible = False):
        '''load iJO1366 with the following changes:
	    1. update to AMPMS2 to account for carbon monoxide
	    2. changes to uptake bounds for glucose M9 media
	    3. constrain the model to use 'PFK' instead of 'F6PA', 'DHAPT' when grown on glucose
	    4. constrain the model to use the physiologically perferred glutamate synthesis enzymes
	    5. depending on oxygen availability, constrain the model to use the correct RNR enzymes
	    6. depending on oxygen availability, constrain the model to use the correct Dihydroorotate dehydrogenase (PyrD) enzymes
	    7. constrain fatty acid biosynthesis to use the physiologically preferred enzymes'''
        ijo1366_sbml = settings.workspace_data+"/models/iJO1366.xml"
        # Read in the sbml file and define the model conditions
        cobra_model = create_cobra_model_from_sbml_file(ijo1366_sbml, print_time=True)
        if update_ampms2:
            # Update AMPMS2
            coc = Metabolite('co_c','CO','carbon monoxide','c');
            cop = Metabolite('co_p','CO','carbon monoxide','p');
            coe = Metabolite('co_e','CO','carbon monoxide','e');
            cobra_model.add_metabolites([coc,cop,coe])
            ampms2_mets = {};
            ampms2_mets[cobra_model.metabolites.get_by_id('air_c')] = -1;
            ampms2_mets[cobra_model.metabolites.get_by_id('amet_c')] = -1;
            ampms2_mets[cobra_model.metabolites.get_by_id('dad_DASH_5_c')] = 1;
            ampms2_mets[cobra_model.metabolites.get_by_id('met_DASH_L_c')] = 1;
            ampms2_mets[cobra_model.metabolites.get_by_id('4ampm_c')] = 1;
            ampms2_mets[cobra_model.metabolites.get_by_id('h_c')] = 3;
            ampms2_mets[cobra_model.metabolites.get_by_id('for_c')] = 1;
            ampms2_mets[cobra_model.metabolites.get_by_id('co_c')] = 1;
            ampms2 = Reaction('AMPMS3');
            ampms2.add_metabolites(ampms2_mets);
            copp_mets = {};
            copp_mets[cobra_model.metabolites.get_by_id('co_c')] = -1;
            copp_mets[cobra_model.metabolites.get_by_id('co_p')] = 1;
            copp = Reaction('COtpp');
            copp.add_metabolites(copp_mets);
            coex_mets = {};
            coex_mets[cobra_model.metabolites.get_by_id('co_p')] = -1;
            coex_mets[cobra_model.metabolites.get_by_id('co_e')] = 1;
            coex = Reaction('COtex');
            coex.add_metabolites(coex_mets);
            cotrans_mets = {};
            cotrans_mets[cobra_model.metabolites.get_by_id('co_e')] = -1;
            cotrans = Reaction('EX_co_LPAREN_e_RPAREN_');
            cotrans.add_metabolites(cotrans_mets);
            cobra_model.add_reactions([ampms2,copp,coex,cotrans]);
            cobra_model.remove_reactions(['AMPMS2']);
        # Define the model conditions:
        system_boundaries = [x.id for x in cobra_model.reactions if x.boundary == 'system_boundary'];
        for b in system_boundaries:
                cobra_model.reactions.get_by_id(b).lower_bound = 0.0;
                cobra_model.reactions.get_by_id(b).upper_bound = 0.0;
        # Reset demand reactions
        demand = ['DM_4CRSOL',
                'DM_5DRIB',
                'DM_AACALD',
                'DM_AMOB',
                'DM_MTHTHF',
                'DM_OXAM'];
        for d in demand:
                cobra_model.reactions.get_by_id(d).lower_bound = 0.0;
                cobra_model.reactions.get_by_id(d).upper_bound = 1000.0;
        # Change the objective
        update_objective(cobra_model,{'Ec_biomass_iJO1366_WT_53p95M':1.0})
        # Assign KOs

        # Specify media composition (M9 glucose):
        cobra_model.reactions.get_by_id('EX_glc_LPAREN_e_RPAREN_').lower_bound = -10.0;
        cobra_model.reactions.get_by_id('EX_o2_LPAREN_e_RPAREN_').lower_bound = -18.0;
        #uptake = ['EX_cl_LPAREN_e_RPAREN_',
        #            'EX_so4_LPAREN_e_RPAREN_',
        #            'EX_ca2_LPAREN_e_RPAREN_',
        #            'EX_pi_LPAREN_e_RPAREN_',
        #            'EX_fe2_LPAREN_e_RPAREN_',
        #            'EX_cu2_LPAREN_e_RPAREN_',
        #            'EX_zn2_LPAREN_e_RPAREN_',
        #            'EX_cbl1_LPAREN_e_RPAREN_',
        #            'EX_mobd_LPAREN_e_RPAREN_',
        #            'EX_ni2_LPAREN_e_RPAREN_',
        #            'EX_mn2_LPAREN_e_RPAREN_',
        #            'EX_k_LPAREN_e_RPAREN_',
        #            'EX_nh4_LPAREN_e_RPAREN_',
        #            'EX_cobalt2_LPAREN_e_RPAREN_',
        #            'EX_mg2_LPAREN_e_RPAREN_'];
        uptake = ['EX_ca2_LPAREN_e_RPAREN_',
                    'EX_cbl1_LPAREN_e_RPAREN_',
                    'EX_cl_LPAREN_e_RPAREN_',
                    'EX_co2_LPAREN_e_RPAREN_',
                    'EX_cobalt2_LPAREN_e_RPAREN_',
                    'EX_cu2_LPAREN_e_RPAREN_',
                    'EX_fe2_LPAREN_e_RPAREN_',
                    'EX_fe3_LPAREN_e_RPAREN_',
                    'EX_h_LPAREN_e_RPAREN_',
                    'EX_h2o_LPAREN_e_RPAREN_',
                    'EX_k_LPAREN_e_RPAREN_',
                    'EX_mg2_LPAREN_e_RPAREN_',
                    'EX_mn2_LPAREN_e_RPAREN_',
                    'EX_mobd_LPAREN_e_RPAREN_',
                    'EX_na1_LPAREN_e_RPAREN_',
                    'EX_nh4_LPAREN_e_RPAREN_',
                    'EX_ni2_LPAREN_e_RPAREN_',
                    'EX_pi_LPAREN_e_RPAREN_',
                    'EX_sel_LPAREN_e_RPAREN_',
                    'EX_slnt_LPAREN_e_RPAREN_',
                    'EX_so4_LPAREN_e_RPAREN_',
                    'EX_tungs_LPAREN_e_RPAREN_',
                    'EX_zn2_LPAREN_e_RPAREN_'];
        for u in uptake:
            cobra_model.reactions.get_by_id(u).lower_bound = -1000.0;
        # Specify allowed secretion products
        secrete = ['EX_meoh_LPAREN_e_RPAREN_',
                    'EX_5mtr_LPAREN_e_RPAREN_',
                    'EX_h_LPAREN_e_RPAREN_',
                    'EX_co2_LPAREN_e_RPAREN_',
                    'EX_co_LPAREN_e_RPAREN_',
                    'EX_h2o_LPAREN_e_RPAREN_',
                    'EX_ac_LPAREN_e_RPAREN_',
                    'EX_fum_LPAREN_e_RPAREN_',
                    'EX_for_LPAREN_e_RPAREN_',
                    'EX_etoh_LPAREN_e_RPAREN_',
                    'EX_lac_DASH_L_LPAREN_e_RPAREN_',
                    'EX_pyr_LPAREN_e_RPAREN_',
                    'EX_succ_LPAREN_e_RPAREN_'];
        for s in secrete:
            cobra_model.reactions.get_by_id(s).upper_bound = 1000.0;
        # Constrain specific reactions
        noFlux = ['F6PA', 'DHAPT'];
        ammoniaExcess = ['GLUDy']; # PMCID: 196288
        # RNR control (DOI:10.1111/j.1365-2958.2006.05493.x)
        # Dihydroorotate dehydrogenase (PyrD) (DOI:10.1016/S0076-6879(78)51010-0, PMID: 199252, DOI:S0969212602008316 [pii])
        aerobic = ['RNDR1', 'RNDR2', 'RNDR3', 'RNDR4', 'DHORD2', 'ASPO6','LCARR','PFL','FRD2','FRD3']; # see DOI:10.1111/j.1365-2958.2011.07593.x; see DOI:10.1089/ars.2006.8.773 for a review
        anaerobic = ['RNTR1c2', 'RNTR2c2', 'RNTR3c2', 'RNTR4c2', 'DHORD5', 'ASPO5','PDH','SUCDi']; # see DOI:10.1074/jbc.274.44.31291, DOI:10.1128/JB.00440-07
        if anoxic:
            rxnList = noFlux + ammoniaExcess + anaerobic;
            for rxn in rxnList:
                cobra_model.reactions.get_by_id(rxn).lower_bound = 0.0;
                cobra_model.reactions.get_by_id(rxn).upper_bound = 0.0;
        elif oxic:
            rxnList = noFlux + ammoniaExcess + aerobic;
            for rxn in rxnList:
                cobra_model.reactions.get_by_id(rxn).lower_bound = 0.0;
                cobra_model.reactions.get_by_id(rxn).upper_bound = 0.0;
        else:
            rxnList = noFlux + ammoniaExcess;
            for rxn in rxnList:
                cobra_model.reactions.get_by_id(rxn).lower_bound = 0.0;
                cobra_model.reactions.get_by_id(rxn).upper_bound = 0.0;
        # Set the direction for specific reactions
        # Fatty acid biosynthesis: DOI: 10.1016/j.ymben.2010.10.007, PMCID: 372925
        fattyAcidSynthesis = ['ACCOAC', 'ACOATA', 'HACD1', 'HACD2', 'HACD3', 'HACD4', 'HACD5', 'HACD6', 'HACD7', 'HACD8', 'KAS14', 'KAS15', 'MACPD', 'MCOATA', '3OAR100', '3OAR120', '3OAR121', '3OAR140', '3OAR141', '3OAR160', '3OAR161', '3OAR180', '3OAR181', '3OAR40', '3OAR60', '3OAR80']
        fattyAcidOxidation = ['ACACT1r', 'ACACT2r', 'ACACT3r', 'ACACT4r', 'ACACT5r', 'ACACT6r', 'ACACT7r', 'ACACT8r', 'ACOAD1f', 'ACOAD2f', 'ACOAD3f', 'ACOAD4f', 'ACOAD5f', 'ACOAD6f', 'ACOAD7f', 'ACOAD8f', 'CTECOAI6', 'CTECOAI7', 'CTECOAI8', 'ECOAH1', 'ECOAH2', 'ECOAH3', 'ECOAH4', 'ECOAH5', 'ECOAH6', 'ECOAH7', 'ECOAH8']
        ndpk = ['NDPK1','NDPK2','NDPK3','NDPK4','NDPK5','NDPK7','NDPK8'];
        rxnList = fattyAcidSynthesis + fattyAcidOxidation;
        for rxn in rxnList:
            cobra_model.reactions.get_by_id(rxn).lower_bound = 0.0;
            cobra_model.reactions.get_by_id(rxn).upper_bound = 1000.0;
        # convert to irreversible
        if convert2irreversible: convert_to_irreversible(cobra_model);

        return cobra_model;