Beispiel #1
0
 def _get_expression(self):
     if self.problem is not None and self._expression_expired and len(
             self.problem._variables) > 0:
         grb_obj = self.problem.problem.getObjective()
         variables = self.problem._variables
         if self.problem.problem.IsQP:
             quadratic_expression = symbolics.add([
                 symbolics.Real(grb_obj.getCoeff(i)) *
                 variables[grb_obj.getVar1(i).VarName] *
                 variables[grb_obj.getVar2(i).VarName]
                 for i in range(grb_obj.size())
             ])
             linear_objective = grb_obj.getLinExpr()
         else:
             quadratic_expression = symbolics.Real(0.0)
             linear_objective = grb_obj
         linear_expression = symbolics.add([
             symbolics.Real(linear_objective.getCoeff(i)) *
             variables[linear_objective.getVar(i).VarName]
             for i in range(linear_objective.size())
         ])
         self._expression = (linear_expression + quadratic_expression +
                             getattr(self.problem, "_objective_offset", 0))
         self._expression_expired = False
     return self._expression
Beispiel #2
0
    def __init__(self, problem=None, *args, **kwargs):

        super(Model, self).__init__(*args, **kwargs)

        if problem is None:
            self.problem = gurobipy.Model()
            self.problem.params.OutputFlag = 0
            if self.name is not None:
                self.problem.setAttr('ModelName', self.name)
                self.problem.update()

        elif isinstance(problem, gurobipy.Model):
            self.problem = problem
            variables = []
            for gurobi_variable in self.problem.getVars():
                variables.append(Variable(
                    gurobi_variable.getAttr("VarName"),
                    lb=gurobi_variable.getAttr("lb"),
                    ub=gurobi_variable.getAttr("ub"),
                    problem=self,
                    type=_GUROBI_VTYPE_TO_VTYPE[gurobi_variable.getAttr("vType")]
                ))
            super(Model, self)._add_variables(variables)
            constraints = []
            for gurobi_constraint in self.problem.getConstrs():
                sense = gurobi_constraint.Sense
                name = gurobi_constraint.getAttr("ConstrName")
                rhs = gurobi_constraint.RHS
                row = self.problem.getRow(gurobi_constraint)
                lhs = symbolics.add(
                    [symbolics.Real(row.getCoeff(i)) * self.variables[row.getVar(i).VarName] for i in
                     range(row.size())]
                )

                if sense == '=':
                    constraint = Constraint(lhs, name=name, lb=rhs, ub=rhs, problem=self)
                elif sense == '>':
                    constraint = Constraint(lhs, name=name, lb=rhs, ub=None, problem=self)
                elif sense == '<':
                    constraint = Constraint(lhs, name=name, lb=None, ub=rhs, problem=self)
                else:
                    raise ValueError('{} is not a valid sense'.format(sense))
                constraints.append(constraint)
            super(Model, self)._add_constraints(constraints, sloppy=True)

            gurobi_objective = self.problem.getObjective()
            linear_expression = symbolics.add(
                [symbolics.Real(gurobi_objective.getCoeff(i)) * self.variables[gurobi_objective.getVar(i).VarName]
                 for i in range(gurobi_objective.size())]
            )

            self._objective = Objective(
                linear_expression,
                problem=self,
                direction={1: 'min', -1: 'max'}[self.problem.getAttr('ModelSense')]
            )
        else:
            raise TypeError("Provided problem is not a valid Gurobi model.")

        self.configuration = Configuration(problem=self, verbosity=0)
Beispiel #3
0
 def _get_expression(self):
     if self.problem is not None:
         coefficients_dict = self.problem.problem.objective
         coefficients_dict = {
             self.problem._variables[name]: coef for name, coef in coefficients_dict.items() if name in self.problem._variables
         }
         self._expression = symbolics.add(*(v * k for k, v in coefficients_dict.items())) + self.problem.problem.offset
     return self._expression
Beispiel #4
0
 def _get_expression(self):
     if (self.problem is not None and self._expression_expired
             and len(self.problem._variables) > 0):
         model = self.problem
         vars = model._variables
         expression = add([
             coef * vars[vn]
             for vn, coef in six.iteritems(model.problem.obj_linear_coefs)
         ])
         q_ex = add([
             coef * vars[vn[0]] * vars[vn[1]] for vn, coef in six.iteritems(
                 model.problem.obj_quadratic_coefs)
         ])
         expression += q_ex
         self._expression = expression
         self._expression_expired = False
     return self._expression
Beispiel #5
0
 def _get_expression(self):
     if self.problem is not None:
         variables = self.problem._variables
         all_coefs = self.problem.problem.constraint_coefs
         coefs = [(v, all_coefs.get((self.name, v.name), 0.0))
                  for v in variables]
         expression = add(
             [mul((symbolics.Real(co), v)) for (v, co) in coefs])
         self._expression = expression
     return self._expression
    def test_construct_with_sloppy(self):
        x, y, z, w = self.model.variables[:4]
        obj = self.interface.Objective(
            symbolics.add([symbolics.mul((symbolics.One, var)) for var in [x, y, z]]),
            direction="min",
            sloppy=True
        )
        self.model.objective = obj

        self.assertTrue(obj.get_linear_coefficients([x, y, z, w]) == {x: 1, y: 1, z: 1, w: 0})
Beispiel #7
0
 def _get_expression(self):
     if self.problem is not None and self._expression_expired and len(self.problem._variables) > 0:
         cplex_problem = self.problem.problem
         coeffs = cplex_problem.objective.get_linear()
         expression = add([coeff * var for coeff, var in zip(coeffs, self.problem._variables) if coeff != 0.])
         if cplex_problem.objective.get_num_quadratic_nonzeros() > 0:
             expression += self.problem._get_quadratic_expression(cplex_problem.objective.get_quadratic())
         self._expression = expression + getattr(self.problem, "_objective_offset", 0)
         self._expression_expired = False
     return self._expression
Beispiel #8
0
 def _get_expression(self):
     if self.problem is not None and self._expression_expired and len(self.problem._variables) > 0:
         cplex_problem = self.problem.problem
         coeffs = cplex_problem.objective.get_linear()
         expression = add([coeff * var for coeff, var in zip(coeffs, self.problem._variables) if coeff != 0.])
         if cplex_problem.objective.get_num_quadratic_nonzeros() > 0:
             expression += self.problem._get_quadratic_expression(cplex_problem.objective.get_quadratic())
         self._expression = expression + getattr(self.problem, "_objective_offset", 0)
         self._expression_expired = False
     return self._expression
    def test_construct_with_sloppy(self):
        x, y, z, w = self.model.variables[:4]
        obj = self.interface.Objective(
            symbolics.add([symbolics.mul((symbolics.One, var)) for var in [x, y, z]]),
            direction="min",
            sloppy=True
        )
        self.model.objective = obj

        self.assertTrue(obj.get_linear_coefficients([x, y, z, w]) == {x: 1, y: 1, z: 1, w: 0})
Beispiel #10
0
    def test_construct_with_sloppy(self):
        x, y, z, w = self.model.variables[:4]
        const = self.interface.Constraint(
            symbolics.add([symbolics.mul(symbolics.One, var) for var in [x, y, z]]),
            lb=0,
            sloppy=True
        )
        self.model.add(const)
        self.model.update()

        self.assertTrue(const.get_linear_coefficients([x, y, z, w]) == {x: 1, y: 1, z: 1, w: 0})
    def test_construct_with_sloppy(self):
        x, y, z, w = self.model.variables[:4]
        const = self.interface.Constraint(
            symbolics.add([symbolics.mul(symbolics.One, var) for var in [x, y, z]]),
            lb=0,
            sloppy=True
        )
        self.model.add(const)
        self.model.update()

        self.assertTrue(const.get_linear_coefficients([x, y, z, w]) == {x: 1, y: 1, z: 1, w: 0})
Beispiel #12
0
 def _get_expression(self):
     if self.problem is not None:
         cplex_problem = self.problem.problem
         cplex_row = cplex_problem.linear_constraints.get_rows(self.name)
         variables = self.problem._variables
         expression = add([
             mul((symbolics.Real(cplex_row.val[i]), variables[ind]))
             for i, ind in enumerate(cplex_row.ind)
         ])
         self._expression = expression
     return self._expression
Beispiel #13
0
 def set_linear_coefficients(self, coefficients):
     if self.problem is not None:
         self.problem.update()
         lb, ub = self.lb, self.ub
         self.lb, self.ub = None, None
         coefficients_dict = self.coefficient_dict(names=False)
         coefficients_dict.update(coefficients)
         self._expression = symbolics.add(*(v * k for k, v in coefficients_dict.items()))
         self.lb = lb
         self.ub = ub
     else:
         raise Exception("Can't change coefficients if constraint is not associated with a model.")
 def _get_expression(self):
     if self.problem is not None:
         coefficients_dict = self.problem.problem.objective
         coefficients_dict = {
             self.problem._variables[name]: coef
             for name, coef in coefficients_dict.items()
             if name in self.problem._variables
         }
         self._expression = symbolics.add(
             *(v * k for k, v in coefficients_dict.items()
               )) + self.problem.problem.offset
     return self._expression
Beispiel #15
0
 def _get_expression(self):
     if self.problem is not None and self._expression_expired and len(self.problem._variables) > 0:
         grb_obj = self.problem.problem.getObjective()
         terms = []
         variables = self.problem._variables
         for i in range(grb_obj.size()):
             terms.append(grb_obj.getCoeff(i) * variables[grb_obj.getVar(i).getAttr('VarName')])
         expression = symbolics.add(terms)
         # TODO implement quadratic objectives
         self._expression = expression + getattr(self.problem, "_objective_offset", 0)
         self._expression_expired = False
     return self._expression
Beispiel #16
0
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         constraint_variables = [self.problem._variables[glp_get_col_name(self.problem.problem, ia[i])] for i in
                                 range(1, nnz + 1)]
         expression = symbolics.add(
             [symbolics.mul((symbolics.Real(da[i]), constraint_variables[i - 1])) for i in
              range(1, nnz + 1)])
         self._expression = expression
     return self._expression
Beispiel #17
0
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         constraint_variables = [self.problem._variables[glp_get_col_name(self.problem.problem, ia[i])] for i in
                                 range(1, nnz + 1)]
         expression = symbolics.add(
             [symbolics.mul((symbolics.Real(da[i]), constraint_variables[i - 1])) for i in
              range(1, nnz + 1)])
         self._expression = expression
     return self._expression
Beispiel #18
0
    def _get_expression(self):
        if self.problem is not None and self._expression_expired:
            variables = self.problem._variables

            def term_generator():
                for index in range(1, glp_get_num_cols(self.problem.problem) + 1):
                    coeff = glp_get_obj_coef(self.problem.problem, index)
                    if coeff != 0.:
                        yield (symbolics.Real(coeff), variables[index - 1])

            expression = symbolics.add([symbolics.mul(term) for term in term_generator()])
            self._expression = expression + getattr(self.problem, "_objective_offset", 0)
            self._expression_expired = False
        return self._expression
Beispiel #19
0
 def _get_expression(self):
     if self.problem is not None and self._expression_expired and len(self.problem._variables) > 0:
         grb_obj = self.problem.problem.getObjective()
         variables = self.problem._variables
         if self.problem.problem.IsQP:
             quadratic_expression = symbolics.add(
                 [symbolics.Real(grb_obj.getCoeff(i)) *
                  variables[grb_obj.getVar1(i).VarName] *
                  variables[grb_obj.getVar2(i).VarName]
                  for i in range(grb_obj.size())])
             linear_objective = grb_obj.getLinExpr()
         else:
             quadratic_expression = symbolics.Real(0.0)
             linear_objective = grb_obj
         linear_expression = symbolics.add(
             [symbolics.Real(linear_objective.getCoeff(i)) *
              variables[linear_objective.getVar(i).VarName]
              for i in range(linear_objective.size())]
         )
         self._expression = (linear_expression + quadratic_expression +
                             getattr(self.problem, "_objective_offset", 0))
         self._expression_expired = False
     return self._expression
Beispiel #20
0
    def _get_expression(self):
        if self.problem is not None and self._expression_expired:
            variables = self.problem._variables

            def term_generator():
                for index in range(1, glp_get_num_cols(self.problem.problem) + 1):
                    coeff = glp_get_obj_coef(self.problem.problem, index)
                    if coeff != 0.:
                        yield (symbolics.Real(coeff), variables[index - 1])

            expression = symbolics.add([symbolics.mul(term) for term in term_generator()])
            self._expression = expression + getattr(self.problem, "_objective_offset", 0)
            self._expression_expired = False
        return self._expression
 def set_linear_coefficients(self, coefficients):
     if self.problem is not None:
         lb, ub = self.lb, self.ub
         self.lb, self.ub = None, None
         coefficients_dict = self.coefficient_dict(names=False)
         coefficients_dict.update(coefficients)
         self._expression = symbolics.add(
             *(v * k for k, v in coefficients_dict.items()))
         self.lb = lb
         self.ub = ub
     else:
         raise Exception(
             "Can't change coefficients if constraint is not associated with a model."
         )
Beispiel #22
0
 def _get_expression(self):
     if self.problem is not None:
         gurobi_problem = self.problem.problem
         gurobi_constraint = self._internal_constraint
         row = gurobi_problem.getRow(gurobi_constraint)
         terms = []
         for i in range(row.size()):
             internal_var_name = row.getVar(i).VarName
             if internal_var_name == self.name + '_aux':
                 continue
             variable = self.problem._variables[internal_var_name]
             coeff = symbolics.Real(row.getCoeff(i))
             terms.append(symbolics.mul((coeff, variable)))
         self._expression = symbolics.add(terms)
     return self._expression
Beispiel #23
0
 def _get_expression(self):
     if self.problem is not None:
         gurobi_problem = self.problem.problem
         gurobi_constraint = self._internal_constraint
         row = gurobi_problem.getRow(gurobi_constraint)
         terms = []
         for i in range(row.size()):
             internal_var_name = row.getVar(i).VarName
             if internal_var_name == self.name + '_aux':
                 continue
             variable = self.problem._variables[internal_var_name]
             coeff = symbolics.Real(row.getCoeff(i))
             terms.append(symbolics.mul((coeff, variable)))
         self._expression = symbolics.add(terms)
     return self._expression
Beispiel #24
0
 def _get_expression(self):
     if self.problem is not None:
         cplex_problem = self.problem.problem
         try:
             cplex_row = cplex_problem.linear_constraints.get_rows(self.name)
         except CplexSolverError as e:
             if 'CPLEX Error  1219:' not in str(e):
                 raise e
             else:
                 cplex_row = cplex_problem.indicator_constraints.get_linear_components(self.name)
         variables = self.problem._variables
         expression = add(
             [mul((symbolics.Real(cplex_row.val[i]), variables[ind])) for i, ind in
              enumerate(cplex_row.ind)])
         self._expression = expression
     return self._expression
Beispiel #25
0
 def _get_expression(self):
     if self.problem is not None:
         cplex_problem = self.problem.problem
         try:
             cplex_row = cplex_problem.linear_constraints.get_rows(self.name)
         except CplexSolverError as e:
             if 'CPLEX Error  1219:' not in str(e):
                 raise e
             else:
                 cplex_row = cplex_problem.indicator_constraints.get_linear_components(self.name)
         variables = self.problem._variables
         expression = add(
             [mul((symbolics.Real(cplex_row.val[i]), variables[ind])) for i, ind in
              enumerate(cplex_row.ind)])
         self._expression = expression
     return self._expression
Beispiel #26
0
 def _get_quadratic_expression(self, quadratic=None):
     if quadratic is None:
         try:
             quadratic = self.problem.objective.get_quadratic()
         except IndexError:
             return Zero
     terms = []
     for i, sparse_pair in enumerate(quadratic):
         for j, val in zip(sparse_pair.ind, sparse_pair.val):
             i_name, j_name = self.problem.variables.get_names([i, j])
             if i < j:
                 terms.append(val * self._variables[i_name] * self._variables[j_name])
             elif i == j:
                 terms.append(0.5 * val * self._variables[i_name] ** 2)
             else:
                 pass  # Only look at upper triangle
     return add(terms)
Beispiel #27
0
 def _get_quadratic_expression(self, quadratic=None):
     if quadratic is None:
         try:
             quadratic = self.problem.objective.get_quadratic()
         except IndexError:
             return Zero
     terms = []
     for i, sparse_pair in enumerate(quadratic):
         for j, val in zip(sparse_pair.ind, sparse_pair.val):
             i_name, j_name = self.problem.variables.get_names([i, j])
             if i < j:
                 terms.append(val * self._variables[i_name] * self._variables[j_name])
             elif i == j:
                 terms.append(0.5 * val * self._variables[i_name] ** 2)
             else:
                 pass  # Only look at upper triangle
     return add(terms)
Beispiel #28
0
def add_reaction_constraints(model, reactions, Constraint):
    """
    Add the stoichiometric coefficients as constraints.

    Parameters
    ----------
    model : optlang.Model
        The transposed stoichiometric matrix representation.
    reactions : iterable
        Container of `cobra.Reaction` instances.
    Constraint : optlang.Constraint
        The constraint class for the specific interface.

    """
    constraints = []
    for rxn in reactions:
        expression = add(
            [c * model.variables[m.id] for m, c in rxn.metabolites.items()])
        constraints.append(Constraint(expression, lb=0, ub=0, name=rxn.id))
    model.add(constraints)
def add_reaction_constraints(model, reactions, Constraint):
    """
    Add the stoichiometric coefficients as constraints.

    Parameters
    ----------
    model : optlang.Model
        The transposed stoichiometric matrix representation.
    reactions : iterable
        Container of `cobra.Reaction` instances.
    Constraint : optlang.Constraint
        The constraint class for the specific interface.

    """
    constraints = []
    for rxn in reactions:
        expression = add(
            [c * model.variables[m.id] for m, c in rxn.metabolites.items()])
        constraints.append(Constraint(expression, lb=0, ub=0, name=rxn.id))
    model.add(constraints)
Beispiel #30
0
    def _get_expression(self):
        if (self.problem is not None and self._changed_expression
                and len(self.problem._variables) > 0):

            coeffs = self._expression.as_coefficients_dict()

            new_vars = set(self._changed_expression) - set(coeffs)

            self._expression += symbolics.add(
                [var * self._changed_expression[var] for var in new_vars])

            # Substitute var in expression with var * coef / old_coef
            updates = {
                var: var * coef / coeffs[var]
                for var, coef in self._changed_expression.items()
                if var not in new_vars
            }

            self._expression = self._expression.subs(updates)
            self._changed_expression = {}

        return self._expression
Beispiel #31
0
def parse_expr(expr, local_dict=None):
    """
    Parses a json-object created with 'expr_to_json' into a Sympy expression.

    If a local_dict argument is passed, symbols with be looked up by name, and a new symbol will
    be created only if the name is not in local_dict.
    """
    if local_dict is None:
        local_dict = {}
    if expr["type"] == "Add":
        return add([parse_expr(arg, local_dict) for arg in expr["args"]])
    elif expr["type"] == "Mul":
        return mul([parse_expr(arg, local_dict) for arg in expr["args"]])
    elif expr["type"] == "Pow":
        return Pow(parse_expr(arg, local_dict) for arg in expr["args"])
    elif expr["type"] == "Symbol":
        try:
            return local_dict[expr["name"]]
        except KeyError:
            return symbolics.Symbol(expr["name"])
    elif expr["type"] == "Number":
        return symbolics.sympify(expr["value"])
    else:
        raise NotImplementedError(expr["type"] + " is not implemented")
Beispiel #32
0
def parse_expr(expr, local_dict=None):
    """
    Parses a json-object created with 'expr_to_json' into a Sympy expression.

    If a local_dict argument is passed, symbols with be looked up by name, and a new symbol will
    be created only if the name is not in local_dict.
    """
    if local_dict is None:
        local_dict = {}
    if expr["type"] == "Add":
        return add([parse_expr(arg, local_dict) for arg in expr["args"]])
    elif expr["type"] == "Mul":
        return mul([parse_expr(arg, local_dict) for arg in expr["args"]])
    elif expr["type"] == "Pow":
        return Pow(parse_expr(arg, local_dict) for arg in expr["args"])
    elif expr["type"] == "Symbol":
        try:
            return local_dict[expr["name"]]
        except KeyError:
            return symbolics.Symbol(expr["name"])
    elif expr["type"] == "Number":
        return symbolics.sympify(expr["value"])
    else:
        raise NotImplementedError(expr["type"] + " is not implemented")
Beispiel #33
0
    def _initialize_model_from_problem(self, problem):
        try:
            self.problem = problem
            glp_create_index(self.problem)
        except TypeError:
            raise TypeError("Provided problem is not a valid GLPK model.")
        row_num = glp_get_num_rows(self.problem)
        col_num = glp_get_num_cols(self.problem)
        for i in range(1, col_num + 1):
            var = Variable(
                glp_get_col_name(self.problem, i),
                lb=glp_get_col_lb(self.problem, i),
                ub=glp_get_col_ub(self.problem, i),
                problem=self,
                type=_GLPK_VTYPE_TO_VTYPE[
                    glp_get_col_kind(self.problem, i)]
            )
            # This avoids adding the variable to the glpk problem
            super(Model, self)._add_variables([var])
        variables = self.variables

        for j in range(1, row_num + 1):
            ia = intArray(col_num + 1)
            da = doubleArray(col_num + 1)
            nnz = glp_get_mat_row(self.problem, j, ia, da)
            constraint_variables = [variables[ia[i] - 1] for i in range(1, nnz + 1)]

            # Since constraint expressions are lazily retrieved from the solver they don't have to be built here
            # lhs = _unevaluated_Add(*[da[i] * constraint_variables[i - 1]
            #                         for i in range(1, nnz + 1)])
            lhs = 0

            glpk_row_type = glp_get_row_type(self.problem, j)
            if glpk_row_type == GLP_FX:
                row_lb = glp_get_row_lb(self.problem, j)
                row_ub = row_lb
            elif glpk_row_type == GLP_LO:
                row_lb = glp_get_row_lb(self.problem, j)
                row_ub = None
            elif glpk_row_type == GLP_UP:
                row_lb = None
                row_ub = glp_get_row_ub(self.problem, j)
            elif glpk_row_type == GLP_DB:
                row_lb = glp_get_row_lb(self.problem, j)
                row_ub = glp_get_row_ub(self.problem, j)
            elif glpk_row_type == GLP_FR:
                row_lb = None
                row_ub = None
            else:
                raise Exception(
                    "Currently, optlang does not support glpk row type %s"
                    % str(glpk_row_type)
                )
                log.exception()
            if isinstance(lhs, int):
                lhs = symbolics.Integer(lhs)
            elif isinstance(lhs, float):
                lhs = symbolics.Real(lhs)
            constraint_id = glp_get_row_name(self.problem, j)
            for variable in constraint_variables:
                try:
                    self._variables_to_constraints_mapping[variable.name].add(constraint_id)
                except KeyError:
                    self._variables_to_constraints_mapping[variable.name] = set([constraint_id])

            super(Model, self)._add_constraints(
                [Constraint(lhs, lb=row_lb, ub=row_ub, name=constraint_id, problem=self, sloppy=True)],
                sloppy=True
            )

        term_generator = (
            (glp_get_obj_coef(self.problem, index), variables[index - 1])
            for index in range(1, glp_get_num_cols(problem) + 1)
        )
        self._objective = Objective(
            symbolics.add(
                [symbolics.mul((symbolics.Real(term[0]), term[1])) for term in term_generator if
                 term[0] != 0.]
            ),
            problem=self,
            direction={GLP_MIN: 'min', GLP_MAX: 'max'}[glp_get_obj_dir(self.problem)])
        glp_scale_prob(self.problem, GLP_SF_AUTO)
Beispiel #34
0
    def __init__(self, problem=None, *args, **kwargs):

        super(Model, self).__init__(*args, **kwargs)

        if problem is None:
            self.problem = cplex.Cplex()

        elif isinstance(problem, cplex.Cplex):
            self.problem = problem
            zipped_var_args = zip(self.problem.variables.get_names(),
                                  self.problem.variables.get_lower_bounds(),
                                  self.problem.variables.get_upper_bounds(),
                                  # self.problem.variables.get_types(), # TODO uncomment when cplex is fixed
                                  )
            for name, lb, ub in zipped_var_args:
                var = Variable(name, lb=lb, ub=ub, problem=self)  # Type should also be in there
                super(Model, self)._add_variables([var])  # This avoids adding the variable to the glpk problem
            zipped_constr_args = zip(self.problem.linear_constraints.get_names(),
                                     self.problem.linear_constraints.get_rows(),
                                     self.problem.linear_constraints.get_senses(),
                                     self.problem.linear_constraints.get_rhs()

                                     )
            variables = self._variables
            for name, row, sense, rhs in zipped_constr_args:
                constraint_variables = [variables[i - 1] for i in row.ind]

                # Since constraint expressions are lazily retrieved from the solver they don't have to be built here
                # lhs = _unevaluated_Add(*[val * variables[i - 1] for i, val in zip(row.ind, row.val)])
                lhs = symbolics.Integer(0)
                if sense == 'E':
                    constr = Constraint(lhs, lb=rhs, ub=rhs, name=name, problem=self)
                elif sense == 'G':
                    constr = Constraint(lhs, lb=rhs, name=name, problem=self)
                elif sense == 'L':
                    constr = Constraint(lhs, ub=rhs, name=name, problem=self)
                elif sense == 'R':
                    range_val = self.problem.linear_constraints.get_range_values(name)
                    if range_val > 0:
                        constr = Constraint(lhs, lb=rhs, ub=rhs + range_val, name=name, problem=self)
                    else:
                        constr = Constraint(lhs, lb=rhs + range_val, ub=rhs, name=name, problem=self)
                else:  # pragma: no cover
                    raise Exception('%s is not a recognized constraint sense.' % sense)

                for variable in constraint_variables:
                    try:
                        self._variables_to_constraints_mapping[variable.name].add(name)
                    except KeyError:
                        self._variables_to_constraints_mapping[variable.name] = set([name])

                super(Model, self)._add_constraints(
                    [constr],
                    sloppy=True
                )
            try:
                objective_name = self.problem.objective.get_name()
            except CplexSolverError as e:
                if 'CPLEX Error  1219:' not in str(e):
                    raise e
            else:
                linear_expression = add(
                    [mul(symbolics.Real(coeff), variables[index]) for index, coeff in enumerate(self.problem.objective.get_linear()) if coeff != 0.]
                )
                try:
                    quadratic = self.problem.objective.get_quadratic()
                except IndexError:
                    quadratic_expression = Zero
                else:
                    quadratic_expression = self._get_quadratic_expression(quadratic)

                self._objective = Objective(
                    linear_expression + quadratic_expression,
                    problem=self,
                    direction=
                    {self.problem.objective.sense.minimize: 'min', self.problem.objective.sense.maximize: 'max'}[
                        self.problem.objective.get_sense()],
                    name=objective_name
                )
        else:
            raise TypeError("Provided problem is not a valid CPLEX model.")
        self.configuration = Configuration(problem=self, verbosity=0)
Beispiel #35
0
    def __init__(self, problem=None, *args, **kwargs):

        super(Model, self).__init__(*args, **kwargs)

        if problem is None:
            self.problem = gurobipy.Model()
            self.problem.params.OutputFlag = 0
            if self.name is not None:
                self.problem.setAttr('ModelName', self.name)
                self.problem.update()

        elif isinstance(problem, gurobipy.Model):
            self.problem = problem
            variables = []
            for gurobi_variable in self.problem.getVars():
                variables.append(Variable(
                    gurobi_variable.getAttr("VarName"),
                    lb=gurobi_variable.getAttr("lb"),
                    ub=gurobi_variable.getAttr("ub"),
                    problem=self,
                    type=_GUROBI_VTYPE_TO_VTYPE[gurobi_variable.getAttr("vType")]
                ))
            super(Model, self)._add_variables(variables)
            constraints = []
            for gurobi_constraint in self.problem.getConstrs():
                sense = gurobi_constraint.Sense
                name = gurobi_constraint.getAttr("ConstrName")
                rhs = gurobi_constraint.RHS
                row = self.problem.getRow(gurobi_constraint)
                lhs = symbolics.add(
                    [symbolics.Real(row.getCoeff(i)) * self.variables[row.getVar(i).VarName] for i in
                     range(row.size())]
                )

                if sense == '=':
                    constraint = Constraint(lhs, name=name, lb=rhs, ub=rhs, problem=self)
                elif sense == '>':
                    constraint = Constraint(lhs, name=name, lb=rhs, ub=None, problem=self)
                elif sense == '<':
                    constraint = Constraint(lhs, name=name, lb=None, ub=rhs, problem=self)
                else:
                    raise ValueError('{} is not a valid sense'.format(sense))
                constraints.append(constraint)
            super(Model, self)._add_constraints(constraints, sloppy=True)

            gurobi_objective = self.problem.getObjective()
            if self.problem.IsQP:
                quadratic_expression = symbolics.add(
                    [symbolics.Real(gurobi_objective.getCoeff(i)) *
                     self.variables[gurobi_objective.getVar1(i).VarName] *
                     self.variables[gurobi_objective.getVar2(i).VarName]
                     for i in range(gurobi_objective.size())])
                linear_objective = gurobi_objective.getLinExpr()
            else:
                quadratic_expression = symbolics.Real(0.0)
                linear_objective = gurobi_objective
            linear_expression = symbolics.add(
                [symbolics.Real(linear_objective.getCoeff(i)) *
                 self.variables[linear_objective.getVar(i).VarName]
                 for i in range(linear_objective.size())]
            )

            self._objective = Objective(
                quadratic_expression + linear_expression,
                problem=self,
                direction={1: 'min', -1: 'max'}[self.problem.getAttr('ModelSense')]
            )
        else:
            raise TypeError("Provided problem is not a valid Gurobi model.")

        self.configuration = Configuration(problem=self, verbosity=0)
def flux_mode_constraints(model, c=1):
    """ Add indicator constraints to allow the enumeration of k-shortest
    elementary flux modes, as described in [1]_.
    Parameters
    ----------
    model: cobra.core.model
        Model for which to compute elementary flux modes
    c : float
        The minimum allowable flux through a given elementary flux mode.
        Defaults to 1.
    Yields
    ------
    model
        The input model with additional constraints added.
    indicator_variables : dict
        A dictionary of optlang.Variable objects corresponding to the added
        indicator variables.
    """
    with model:

        indicator_variables = dict()
        indicator_constraints = list()

        Variable = model.problem.Variable
        Constraint = model.problem.Constraint

        for reaction in model.reactions:

            if reaction.upper_bound > 0:

                fwd_id = 'y_fwd_' + reaction.id
                y_fwd = Variable(fwd_id, type='binary')
                indicator_variables[fwd_id] = y_fwd

                indicator_constraints += [
                    Constraint(reaction.forward_variable,
                               indicator_variable=y_fwd,
                               active_when=0,
                               lb=0,
                               ub=0,
                               name='indicator_constraint_fwd_1_{}'.format(
                                   reaction.id))
                ]

                indicator_constraints += [
                    Constraint(reaction.forward_variable,
                               indicator_variable=y_fwd,
                               active_when=1,
                               lb=c,
                               name='indicator_constraint_fwd_2_{}'.format(
                                   reaction.id))
                ]

            # Only if y is reversible
            if reaction.lower_bound < 0:

                rev_id = 'y_rev_' + reaction.id
                y_rev = Variable(rev_id, type='binary')
                indicator_variables[rev_id] = y_rev

                indicator_constraints += [
                    Constraint(reaction.reverse_variable,
                               indicator_variable=y_rev,
                               active_when=0,
                               lb=0,
                               ub=0,
                               name='indicator_constraint_rev_1_{}'.format(
                                   reaction.id))
                ]

                indicator_constraints += [
                    Constraint(reaction.reverse_variable,
                               indicator_variable=y_rev,
                               active_when=1,
                               lb=c,
                               name='indicator_constraint_rev_2_{}'.format(
                                   reaction.id))
                ]

            if reaction.reversibility:

                indicator_constraints += [
                    Constraint(y_fwd + y_rev,
                               lb=0,
                               ub=1,
                               name='one_direction_constraint_{}'.format(
                                   reaction.id))
                ]

        indicator_constraints += [
            Constraint(add(*indicator_variables.values()),
                       lb=1,
                       name='an_EM_must_constain_at_least_one_active_reaction')
        ]

        model.add_cons_vars(
            list(indicator_variables.values()) + indicator_constraints)

        model.objective = add(*indicator_variables.values())
        model.objective_direction = 'min'

        model._indicator_variables = indicator_variables

        yield model

        # Clean up additional model attribute
        del model._indicator_variables
Beispiel #37
0
def add_moma(model, solution=None, linear=True):
    r"""Add constraints and objective representing for MOMA.

    This adds variables and constraints for the minimization of metabolic
    adjustment (MOMA) to the model.

    Parameters
    ----------
    model : cobra.Model
        The model to add MOMA constraints and objective to.
    solution : cobra.Solution, optional
        A previous solution to use as a reference. If no solution is given,
        one will be computed using pFBA.
    linear : bool, optional
        Whether to use the linear MOMA formulation or not (default True).

    Notes
    -----
    In the original MOMA [1]_ specification one looks for the flux distribution
    of the deletion (v^d) closest to the fluxes without the deletion (v).
    In math this means:

    minimize \sum_i (v^d_i - v_i)^2
    s.t. Sv^d = 0
         lb_i <= v^d_i <= ub_i

    Here, we use a variable transformation v^t := v^d_i - v_i. Substituting
    and using the fact that Sv = 0 gives:

    minimize \sum_i (v^t_i)^2
    s.t. Sv^d = 0
         v^t = v^d_i - v_i
         lb_i <= v^d_i <= ub_i

    So basically we just re-center the flux space at the old solution and then
    find the flux distribution closest to the new zero (center). This is the
    same strategy as used in cameo.

    In the case of linear MOMA [2]_, we instead minimize \sum_i abs(v^t_i). The
    linear MOMA is typically significantly faster. Also quadratic MOMA tends
    to give flux distributions in which all fluxes deviate from the reference
    fluxes a little bit whereas linear MOMA tends to give flux distributions
    where the majority of fluxes are the same reference with few fluxes
    deviating a lot (typical effect of L2 norm vs L1 norm).

    The former objective function is saved in the optlang solver interface as
    ``"moma_old_objective"`` and this can be used to immediately extract the
    value of the former objective after MOMA optimization.

    See Also
    --------
    pfba : parsimonious FBA

    References
    ----------
    .. [1] Segrè, Daniel, Dennis Vitkup, and George M. Church. “Analysis of
           Optimality in Natural and Perturbed Metabolic Networks.”
           Proceedings of the National Academy of Sciences 99, no. 23
           (November 12, 2002): 15112. https://doi.org/10.1073/pnas.232349399.
    .. [2] Becker, Scott A, Adam M Feist, Monica L Mo, Gregory Hannum,
           Bernhard Ø Palsson, and Markus J Herrgard. “Quantitative
           Prediction of Cellular Metabolism with Constraint-Based Models:
           The COBRA Toolbox.” Nature Protocols 2 (March 29, 2007): 727.
    """
    if 'moma_old_objective' in model.solver.variables:
        raise ValueError('model is already adjusted for MOMA')

    # Fall back to default QP solver if current one has no QP capability
    if not linear:
        model.solver = sutil.choose_solver(model, qp=True)

    if solution is None:
        solution = pfba(model)
    prob = model.problem
    v = prob.Variable("moma_old_objective")
    c = prob.Constraint(model.solver.objective.expression - v,
                        lb=0.0,
                        ub=0.0,
                        name="moma_old_objective_constraint")
    to_add = [v, c]
    model.objective = prob.Objective(Zero, direction="min", sloppy=True)
    obj_vars = []
    for r in model.reactions:
        flux = solution.fluxes[r.id]
        if linear:
            components = sutil.add_absolute_expression(model,
                                                       r.flux_expression,
                                                       name="moma_dist_" +
                                                       r.id,
                                                       difference=flux,
                                                       add=False)
            to_add.extend(components)
            obj_vars.append(components.variable)
        else:
            dist = prob.Variable("moma_dist_" + r.id)
            const = prob.Constraint(r.flux_expression - dist,
                                    lb=flux,
                                    ub=flux,
                                    name="moma_constraint_" + r.id)
            to_add.extend([dist, const])
            obj_vars.append(dist**2)
    model.add_cons_vars(to_add)
    if linear:
        model.objective.set_linear_coefficients({v: 1.0 for v in obj_vars})
    else:
        model.objective = prob.Objective(add(obj_vars),
                                         direction="min",
                                         sloppy=True)
Beispiel #38
0
def to_symbolic_expr(coeffs):
    """Converts coeffs dict to symbolic expression."""
    return symbolics.add([
        var * coef for var, coef in coeffs.items()
        if not isclose(0, to_float(coef))
    ])
Beispiel #39
0
    def _initialize_model_from_problem(self, problem):
        if isinstance(problem, gurobipy.Model):
            self.problem = problem
            variables = []
            for gurobi_variable in self.problem.getVars():
                variables.append(
                    Variable(gurobi_variable.getAttr("VarName"),
                             lb=gurobi_variable.getAttr("lb"),
                             ub=gurobi_variable.getAttr("ub"),
                             problem=self,
                             type=_GUROBI_VTYPE_TO_VTYPE[
                                 gurobi_variable.getAttr("vType")]))
            super(Model, self)._add_variables(variables)
            constraints = []
            for gurobi_constraint in self.problem.getConstrs():
                sense = gurobi_constraint.Sense
                name = gurobi_constraint.getAttr("ConstrName")
                rhs = gurobi_constraint.RHS
                row = self.problem.getRow(gurobi_constraint)
                lhs = symbolics.add([
                    symbolics.Real(row.getCoeff(i)) *
                    self.variables[row.getVar(i).VarName]
                    for i in range(row.size())
                ])

                if sense == '=':
                    constraint = Constraint(lhs,
                                            name=name,
                                            lb=rhs,
                                            ub=rhs,
                                            problem=self)
                elif sense == '>':
                    constraint = Constraint(lhs,
                                            name=name,
                                            lb=rhs,
                                            ub=None,
                                            problem=self)
                elif sense == '<':
                    constraint = Constraint(lhs,
                                            name=name,
                                            lb=None,
                                            ub=rhs,
                                            problem=self)
                else:
                    raise ValueError('{} is not a valid sense'.format(sense))
                constraints.append(constraint)
            super(Model, self)._add_constraints(constraints, sloppy=True)

            gurobi_objective = self.problem.getObjective()
            if self.problem.IsQP:
                quadratic_expression = symbolics.add([
                    symbolics.Real(gurobi_objective.getCoeff(i)) *
                    self.variables[gurobi_objective.getVar1(i).VarName] *
                    self.variables[gurobi_objective.getVar2(i).VarName]
                    for i in range(gurobi_objective.size())
                ])
                linear_objective = gurobi_objective.getLinExpr()
            else:
                quadratic_expression = symbolics.Real(0.0)
                linear_objective = gurobi_objective
            linear_expression = symbolics.add([
                symbolics.Real(linear_objective.getCoeff(i)) *
                self.variables[linear_objective.getVar(i).VarName]
                for i in range(linear_objective.size())
            ])

            self._objective = Objective(quadratic_expression +
                                        linear_expression,
                                        problem=self,
                                        direction={
                                            1: 'min',
                                            -1: 'max'
                                        }[self.problem.getAttr('ModelSense')])
        else:
            raise TypeError("Provided problem is not a valid Gurobi model.")
Beispiel #40
0
    def _initialize_model_from_problem(self,
                                       problem,
                                       vc_mapping=None,
                                       offset=0):
        if not isinstance(problem, OSQPProblem):
            raise TypeError("Provided problem is not a valid OSQP model.")
        self.problem = problem
        for name in self.problem.variables:
            var = Variable(
                name,
                lb=self.problem.variable_lbs[name],
                ub=self.problem.variable_ubs[name],
                problem=self,
            )
            super(Model, self)._add_variables([var])

        for name in self.problem.constraints:
            # Since constraint expressions are lazily retrieved from the
            # solver they don't have to be built here
            lhs = symbolics.Integer(0)
            constr = Constraint(
                lhs,
                lb=self.problem.constraint_lbs[name],
                ub=self.problem.constraint_ubs[name],
                name=name,
                problem=self,
            )

            super(Model, self)._add_constraints([constr], sloppy=True)

        if vc_mapping is None:
            for constr in self.constraints:
                name = constr.name
                for variable in constr.variables:
                    try:
                        self._variables_to_constraints_mapping[
                            variable.name].add(name)
                    except KeyError:
                        self._variables_to_constraints_mapping[
                            variable.name] = set([name])
        else:
            self._variables_to_constraints_mapping = vc_mapping

        linear_expression = add([
            coef * self._variables[vn]
            for vn, coef in six.iteritems(self.problem.obj_linear_coefs)
        ])
        quadratic_expression = add([
            coef * self._variables[vn[0]] * self._variables[vn[1]]
            for vn, coef in six.iteritems(self.problem.obj_quadratic_coefs)
        ])

        self._objective_offset = offset
        self._objective = Objective(
            linear_expression + quadratic_expression + offset,
            problem=self,
            direction={
                -1: "max",
                1: "min"
            }[self.problem.direction],
            name="osqp_objective",
        )
Beispiel #41
0
    def set_objective(self, linear=None, quadratic=None, minimize=True):
        """ Set a predefined objective for this problem.

        Args:
            linear (dict): linear coefficients (optional)
            quadratic (dict): quadratic coefficients (optional)
            minimize (bool): solve a minimization problem (default: True)

        Notes:
            Setting the objective is optional. It can also be passed directly when calling **solve**.

        """

        if linear is None:
            linear = {}

        if quadratic is None:
            quadratic = {}

        if linear and not quadratic:
            objective = {}

            if isinstance(linear, str):
                objective = {self.problem.variables[linear]: 1}
                if linear not in self.var_ids:
                    warn(
                        f"Objective variable not previously declared: {linear}"
                    )
            else:
                for r_id, val in linear.items():
                    if r_id not in self.var_ids:
                        warn(
                            f"Objective variable not previously declared: {r_id}"
                        )
                    elif val != 0:
                        objective[self.problem.variables[r_id]] = val

            self.problem.objective = Objective(
                Zero, direction=('min' if minimize else 'max'), sloppy=True)
            self.problem.objective.set_linear_coefficients(objective)
        else:
            objective = []

            for r_id, val in linear.items():
                if r_id not in self.var_ids:
                    warn(f"Objective variable not previously declared: {r_id}")
                elif val != 0:
                    objective.append(val * self.problem.variables[r_id])

            for (r_id1, r_id2), val in quadratic.items():
                if r_id1 not in self.var_ids:
                    warn(
                        f"Objective variable not previously declared: {r_id1}")
                elif r_id2 not in self.var_ids:
                    warn(
                        f"Objective variable not previously declared: {r_id2}")
                elif val != 0:
                    objective.append(val * self.problem.variables[r_id1] *
                                     self.problem.variables[r_id2])

            objective_expr = add(objective)
            self.problem.objective = Objective(
                objective_expr,
                direction=('min' if minimize else 'max'),
                sloppy=True)
Beispiel #42
0
    def __init__(self, problem=None, *args, **kwargs):

        super(Model, self).__init__(*args, **kwargs)

        self.configuration = Configuration()

        if problem is None:
            self.problem = glp_create_prob()
            glp_create_index(self.problem)
            if self.name is not None:
                _glpk_validate_id(self.name)
                glp_set_prob_name(self.problem, str(self.name))

        else:
            try:
                self.problem = problem
                glp_create_index(self.problem)
            except TypeError:
                raise TypeError("Provided problem is not a valid GLPK model.")
            row_num = glp_get_num_rows(self.problem)
            col_num = glp_get_num_cols(self.problem)
            for i in range(1, col_num + 1):
                var = Variable(
                    glp_get_col_name(self.problem, i),
                    lb=glp_get_col_lb(self.problem, i),
                    ub=glp_get_col_ub(self.problem, i),
                    problem=self,
                    type=_GLPK_VTYPE_TO_VTYPE[
                        glp_get_col_kind(self.problem, i)]
                )
                # This avoids adding the variable to the glpk problem
                super(Model, self)._add_variables([var])
            variables = self.variables

            for j in range(1, row_num + 1):
                ia = intArray(col_num + 1)
                da = doubleArray(col_num + 1)
                nnz = glp_get_mat_row(self.problem, j, ia, da)
                constraint_variables = [variables[ia[i] - 1] for i in range(1, nnz + 1)]

                # Since constraint expressions are lazily retrieved from the solver they don't have to be built here
                # lhs = _unevaluated_Add(*[da[i] * constraint_variables[i - 1]
                #                         for i in range(1, nnz + 1)])
                lhs = 0

                glpk_row_type = glp_get_row_type(self.problem, j)
                if glpk_row_type == GLP_FX:
                    row_lb = glp_get_row_lb(self.problem, j)
                    row_ub = row_lb
                elif glpk_row_type == GLP_LO:
                    row_lb = glp_get_row_lb(self.problem, j)
                    row_ub = None
                elif glpk_row_type == GLP_UP:
                    row_lb = None
                    row_ub = glp_get_row_ub(self.problem, j)
                elif glpk_row_type == GLP_DB:
                    row_lb = glp_get_row_lb(self.problem, j)
                    row_ub = glp_get_row_ub(self.problem, j)
                elif glpk_row_type == GLP_FR:
                    row_lb = None
                    row_ub = None
                else:
                    raise Exception(
                        "Currently, optlang does not support glpk row type %s"
                        % str(glpk_row_type)
                    )
                    log.exception()
                if isinstance(lhs, int):
                    lhs = symbolics.Integer(lhs)
                elif isinstance(lhs, float):
                    lhs = symbolics.Real(lhs)
                constraint_id = glp_get_row_name(self.problem, j)
                for variable in constraint_variables:
                    try:
                        self._variables_to_constraints_mapping[variable.name].add(constraint_id)
                    except KeyError:
                        self._variables_to_constraints_mapping[variable.name] = set([constraint_id])

                super(Model, self)._add_constraints(
                    [Constraint(lhs, lb=row_lb, ub=row_ub, name=constraint_id, problem=self, sloppy=True)],
                    sloppy=True
                )

            term_generator = (
                (glp_get_obj_coef(self.problem, index), variables[index - 1])
                for index in range(1, glp_get_num_cols(problem) + 1)
            )
            self._objective = Objective(
                symbolics.add(
                    [symbolics.mul((symbolics.Real(term[0]), term[1])) for term in term_generator if
                     term[0] != 0.]
                ),
                problem=self,
                direction={GLP_MIN: 'min', GLP_MAX: 'max'}[glp_get_obj_dir(self.problem)])
        glp_scale_prob(self.problem, GLP_SF_AUTO)
Beispiel #43
0
    def __init__(self, problem=None, *args, **kwargs):

        super(Model, self).__init__(*args, **kwargs)

        if problem is None:
            self.problem = cplex.Cplex()

        elif isinstance(problem, cplex.Cplex):
            self.problem = problem
            zipped_var_args = zip(
                self.problem.variables.get_names(),
                self.problem.variables.get_lower_bounds(),
                self.problem.variables.get_upper_bounds(),
                # self.problem.variables.get_types(), # TODO uncomment when cplex is fixed
            )
            for name, lb, ub in zipped_var_args:
                var = Variable(name, lb=lb, ub=ub,
                               problem=self)  # Type should also be in there
                super(Model, self)._add_variables([
                    var
                ])  # This avoids adding the variable to the glpk problem
            zipped_constr_args = zip(
                self.problem.linear_constraints.get_names(),
                self.problem.linear_constraints.get_rows(),
                self.problem.linear_constraints.get_senses(),
                self.problem.linear_constraints.get_rhs())
            variables = self._variables
            for name, row, sense, rhs in zipped_constr_args:
                constraint_variables = [variables[i - 1] for i in row.ind]

                # Since constraint expressions are lazily retrieved from the solver they don't have to be built here
                # lhs = _unevaluated_Add(*[val * variables[i - 1] for i, val in zip(row.ind, row.val)])
                lhs = symbolics.Integer(0)
                if sense == 'E':
                    constr = Constraint(lhs,
                                        lb=rhs,
                                        ub=rhs,
                                        name=name,
                                        problem=self)
                elif sense == 'G':
                    constr = Constraint(lhs, lb=rhs, name=name, problem=self)
                elif sense == 'L':
                    constr = Constraint(lhs, ub=rhs, name=name, problem=self)
                elif sense == 'R':
                    range_val = self.problem.linear_constraints.get_range_values(
                        name)
                    if range_val > 0:
                        constr = Constraint(lhs,
                                            lb=rhs,
                                            ub=rhs + range_val,
                                            name=name,
                                            problem=self)
                    else:
                        constr = Constraint(lhs,
                                            lb=rhs + range_val,
                                            ub=rhs,
                                            name=name,
                                            problem=self)
                else:  # pragma: no cover
                    raise Exception(
                        '%s is not a recognized constraint sense.' % sense)

                for variable in constraint_variables:
                    try:
                        self._variables_to_constraints_mapping[
                            variable.name].add(name)
                    except KeyError:
                        self._variables_to_constraints_mapping[
                            variable.name] = set([name])

                super(Model, self)._add_constraints([constr], sloppy=True)
            try:
                objective_name = self.problem.objective.get_name()
            except CplexSolverError as e:
                if 'CPLEX Error  1219:' not in str(e):
                    raise e
            else:
                linear_expression = add([
                    mul(symbolics.Real(coeff), variables[index]) for index,
                    coeff in enumerate(self.problem.objective.get_linear())
                    if coeff != 0.
                ])
                try:
                    quadratic = self.problem.objective.get_quadratic()
                except IndexError:
                    quadratic_expression = Zero
                else:
                    quadratic_expression = self._get_quadratic_expression(
                        quadratic)

                self._objective = Objective(
                    linear_expression + quadratic_expression,
                    problem=self,
                    direction={
                        self.problem.objective.sense.minimize: 'min',
                        self.problem.objective.sense.maximize: 'max'
                    }[self.problem.objective.get_sense()],
                    name=objective_name)
        else:
            raise TypeError("Provided problem is not a valid CPLEX model.")
        self.configuration = Configuration(problem=self, verbosity=0)
Beispiel #44
0
def add_moma(model, solution=None, linear=True):
    r"""Add constraints and objective representing for MOMA.

    This adds variables and constraints for the minimization of metabolic
    adjustment (MOMA) to the model.

    Parameters
    ----------
    model : cobra.Model
        The model to add MOMA constraints and objective to.
    solution : cobra.Solution, optional
        A previous solution to use as a reference. If no solution is given,
        one will be computed using pFBA.
    linear : bool, optional
        Whether to use the linear MOMA formulation or not (default True).

    Notes
    -----
    In the original MOMA [1]_ specification one looks for the flux distribution
    of the deletion (v^d) closest to the fluxes without the deletion (v).
    In math this means:

    minimize \sum_i (v^d_i - v_i)^2
    s.t. Sv^d = 0
         lb_i <= v^d_i <= ub_i

    Here, we use a variable transformation v^t := v^d_i - v_i. Substituting
    and using the fact that Sv = 0 gives:

    minimize \sum_i (v^t_i)^2
    s.t. Sv^d = 0
         v^t = v^d_i - v_i
         lb_i <= v^d_i <= ub_i

    So basically we just re-center the flux space at the old solution and then
    find the flux distribution closest to the new zero (center). This is the
    same strategy as used in cameo.

    In the case of linear MOMA [2]_, we instead minimize \sum_i abs(v^t_i). The
    linear MOMA is typically significantly faster. Also quadratic MOMA tends
    to give flux distributions in which all fluxes deviate from the reference
    fluxes a little bit whereas linear MOMA tends to give flux distributions
    where the majority of fluxes are the same reference with few fluxes
    deviating a lot (typical effect of L2 norm vs L1 norm).

    The former objective function is saved in the optlang solver interface as
    ``"moma_old_objective"`` and this can be used to immediately extract the
    value of the former objective after MOMA optimization.

    See Also
    --------
    pfba : parsimonious FBA

    References
    ----------
    .. [1] Segrè, Daniel, Dennis Vitkup, and George M. Church. “Analysis of
           Optimality in Natural and Perturbed Metabolic Networks.”
           Proceedings of the National Academy of Sciences 99, no. 23
           (November 12, 2002): 15112. https://doi.org/10.1073/pnas.232349399.
    .. [2] Becker, Scott A, Adam M Feist, Monica L Mo, Gregory Hannum,
           Bernhard Ø Palsson, and Markus J Herrgard. “Quantitative
           Prediction of Cellular Metabolism with Constraint-Based Models:
           The COBRA Toolbox.” Nature Protocols 2 (March 29, 2007): 727.
    """
    if 'moma_old_objective' in model.solver.variables:
        raise ValueError('model is already adjusted for MOMA')

    # Fall back to default QP solver if current one has no QP capability
    if not linear:
        model.solver = sutil.choose_solver(model, qp=True)

    if solution is None:
        solution = pfba(model)
    prob = model.problem
    v = prob.Variable("moma_old_objective")
    c = prob.Constraint(model.solver.objective.expression - v,
                        lb=0.0, ub=0.0, name="moma_old_objective_constraint")
    to_add = [v, c]
    model.objective = prob.Objective(Zero, direction="min", sloppy=True)
    obj_vars = []
    for r in model.reactions:
        flux = solution.fluxes[r.id]
        if linear:
            components = sutil.add_absolute_expression(
                model, r.flux_expression, name="moma_dist_" + r.id,
                difference=flux, add=False)
            to_add.extend(components)
            obj_vars.append(components.variable)
        else:
            dist = prob.Variable("moma_dist_" + r.id)
            const = prob.Constraint(r.flux_expression - dist, lb=flux, ub=flux,
                                    name="moma_constraint_" + r.id)
            to_add.extend([dist, const])
            obj_vars.append(dist ** 2)
    model.add_cons_vars(to_add)
    if linear:
        model.objective.set_linear_coefficients({v: 1.0 for v in obj_vars})
    else:
        model.objective = prob.Objective(
            add(obj_vars), direction="min", sloppy=True)