Exemple #1
0
    def __init__(self, model=None):
        Solver.__init__(self)
        self.problem = Cplex()

        self.status_mapping = {
            self.problem.solution.status.optimal:
            Status.OPTIMAL,
            self.problem.solution.status.optimal_tolerance:
            Status.OPTIMAL,
            self.problem.solution.status.unbounded:
            Status.UNBOUNDED,
            self.problem.solution.status.infeasible:
            Status.INFEASIBLE,
            self.problem.solution.status.infeasible_or_unbounded:
            Status.INF_OR_UNB,
            self.problem.solution.status.MIP_optimal:
            Status.OPTIMAL,
            self.problem.solution.status.MIP_unbounded:
            Status.UNBOUNDED,
            self.problem.solution.status.MIP_infeasible:
            Status.INFEASIBLE,
            self.problem.solution.status.MIP_infeasible_or_unbounded:
            Status.INF_OR_UNB
        }

        self.vartype_mapping = {
            VarType.BINARY: self.problem.variables.type.binary,
            VarType.INTEGER: self.problem.variables.type.integer,
            VarType.CONTINUOUS: self.problem.variables.type.continuous
        }

        self.parameter_mapping = {
            Parameter.TIME_LIMIT: self.problem.parameters.timelimit,
            Parameter.FEASIBILITY_TOL:
            self.problem.parameters.simplex.tolerances.feasibility,
            Parameter.OPTIMALITY_TOL:
            self.problem.parameters.simplex.tolerances.optimality,
            Parameter.INT_FEASIBILITY_TOL:
            self.problem.parameters.mip.tolerances.integrality,
            Parameter.MIP_ABS_GAP:
            self.problem.parameters.mip.tolerances.mipgap,
            Parameter.MIP_REL_GAP:
            self.problem.parameters.mip.tolerances.absmipgap,
            Parameter.POOL_SIZE: self.problem.parameters.mip.limits.populate,
            Parameter.POOL_GAP: self.problem.parameters.mip.pool.relgap
        }

        self.set_parameters(default_parameters)

        self.set_logging(False)
        self._cached_lin_obj = {}
        self._cached_sense = None
        self._cached_lower_bounds = {}
        self._cached_upper_bounds = {}
        self._cached_vars = []
        self._cached_constrs = []

        if model:
            self.build_problem(model)
Exemple #2
0
    def solve(problem: cplex.Cplex, dataset: Dataset):
        global best_solution, best_score
        # Ищем решение с текущими ограничениями
        problem.solve()
        # Если решение не удовлетворяет ограничениям, не идем в эту ветку
        if (problem.solution.get_status() is not 1):
            print("Broken model")
            return None
        obj = problem.solution.get_objective_value()
        # Если решение хуже лучшего, не идем в эту ветку
        if (obj <= best_score):
            return None
        prev_ans = obj
        add_constr = lambda constraint: problem.linear_constraints.add(
            lin_expr=
            [cplex.SparsePair(constraint, val=[1.0] * len(constraint))],
            rhs=[1.0],
            names=["c_" + str(np.random.randint(low=10, high=1000000))],
            senses=['L'])
        while True:
            constraint = BranchAndCut.separation(dataset,
                                                 problem.solution.get_values())
            if (len(constraint) <= 1):
                break
            add_constr(constraint)

            problem.solve()
            obj = problem.solution.get_objective_value()
            if (obj < best_score):
                return None
            elif np.isclose(prev_ans, obj, atol=10e-6):
                break
            prev_ans = obj

        solution = problem.solution.get_values()
        if BranchAndCut.validate_integer_solution(solution):
            constraints = BranchAndCut.check_solution(problem, dataset)
            if len(constraints) == 0:
                if obj > best_score:
                    best_solution = solution
                    best_score = obj
                    print("New best result: ", best_score)
            else:
                for constr in constraints:
                    add_constr(constr)
                BranchAndCut.solve(problem, dataset)
            return

        branching_var = BranchAndCut.get_branching_var(solution)
        branching_var = [int(branching_var)]
        for val in [1.0, 0.0]:
            constr = problem.linear_constraints.add(
                lin_expr=[cplex.SparsePair(branching_var, val=[1.0])],
                rhs=[val],
                names=["e_" + str(np.random.randint(low=10, high=1000000))],
                senses=['E'])
            BranchAndCut.solve(problem, dataset)
            problem.linear_constraints.delete(constr)
Exemple #3
0
 def __init__(self, cplex=None):
     if cplex:
         self._model = Cplex(cplex._model)
     else:
         self._model = Cplex()
     self._init_lin()
     # to avoid a variable with index 0
     self._model.variables.add(
         names=['_dummy_'], types=[self._model.variables.type.continuous])
     self._var_id = {'_dummy_': 0}
Exemple #4
0
 def __init__(self, problem):
     #instance variable: the solution set found by solver
     self.cplexSolutionSet = []
     #instance variable: the solution map, the key is the solution obj values, the value is the solution
     self.cplexResultMap = {}
     #instance variable: the map of the solutions in the pareto front
     self.cplexParetoSet = {}
     # problem
     self.problem = problem
     # solver
     self.solver = Cplex()
Exemple #5
0
    def create_cplex(cls, verbose=False):
        cpx = Cplex()
        # see if we want it to be verbose sometimes
        if not verbose:
            cpx.set_log_stream(None)
            cpx.set_results_stream(None)
            cpx.set_error_stream(None)
            cpx.set_warning_stream(None)

        # disable datacheck
        cpx_datacheck_id = 1056
        setintparam(cpx._env._e, cpx_datacheck_id, 0)
        return cpx
Exemple #6
0
    def __init__(self, cplex=None):
        try:
            if cplex:
                self._model = Cplex(cplex._model)
            else:
                self._model = Cplex()
        except NameError:
            raise NameError('CPLEX is not installed. See https://www.ibm.com/support/knowledgecenter/SSSA5P_12.8.0/ilog.odms.studio.help/Optimization_Studio/topics/COS_home.html')

        self._init_lin()
        # to avoid a variable with index 0
        self._model.variables.add(names=['_dummy_'], types=[self._model.variables.type.continuous])
        self._var_id = {'_dummy_': 0}
def set_cplex_objective(cpx: cplex.Cplex,
                        c,
                        Q=None,
                        epsilon: float = 1e-4) -> cplex.Cplex:
    """
    set_cplex_objective(cpx, c, Q) sets the objective of cplex object cpx
    to have linear objective coefficients c
    and quadratic objective coefficients Q
    essentially sets problem to have objective of the form

    min cTx + xT Q x

    with original constraints etc
    :param cpx: cplex object to modify
    :param c: linear objective coefficients
    :param Q: quadratic objective coefficients
    :return: cplex object with set objective coefficients
    """
    n = cpx.variables.get_num()

    assert len(c) == n, "c must have {} items but len(c) is {}".format(
        n, len(c))

    # set linear coefficients
    #       cTx
    for i in range(n):
        cpx.objective.set_linear(i, float(c[i]))

    if Q is not None and len(Q.nonzero()[0]) > 0:
        assert len(Q) == n, "Q must have {} items but len(Q) is {}".format(
            n, len(Q))
        # quadratic coefficients
        #     x.T * Q * x
        quadratic_coefs = []
        for i in range(Q.shape[0]):
            indices = Q[i].nonzero()[0].tolist()
            if len(indices) == 0:
                sparse_pair = cplex.SparsePair(ind=[], val=[])
            else:
                vals = Q[i, indices].tolist()
                sparse_pair = cplex.SparsePair(ind=indices, val=vals)
            quadratic_coefs.append(sparse_pair)

        cpx.objective.set_quadratic(quadratic_coefs)
    else:
        cpx.set_problem_type(cpx.problem_type.MILP)

    cpx.objective.set_sense(cpx.objective.sense.minimize)
    cpx.cleanup(epsilon=epsilon)
    return cpx
Exemple #8
0
def copy_cplex(cpx):
    cpx_copy = Cplex(cpx)
    cpx_parameters = cpx.parameters.get_changed()
    for (pname, pvalue) in cpx_parameters:
        phandle = reduce(getattr, str(pname).split("."), cpx_copy)
        phandle.set(pvalue)
    return cpx_copy
Exemple #9
0
    def __init__(self, cplex=None):
        if not _HAS_CPLEX:
            raise MissingOptionalLibraryError(
                libname='CPLEX',
                name='SimpleCPLEX',
                pip_install='pip install qiskit-aqua[cplex]')

        if cplex:
            self._model = Cplex(cplex._model)
        else:
            self._model = Cplex()

        self._init_lin()
        # to avoid a variable with index 0
        self._model.variables.add(names=['_dummy_'], types=[self._model.variables.type.continuous])
        self._var_id = {'_dummy_': 0}
Exemple #10
0
 def branching(self, problem: cplex.Cplex):
     try:
         problem.solve()
         solution_values = problem.solution.get_values()
     except cplex.exceptions.CplexSolverError:
         return list()
     if sum(solution_values) > self.current_max_clique_size:
         branching_variable = self.get_branching_variable(solution_values)
         if branching_variable is None:
             current_clique = list(index for index, value in enumerate(solution_values) if value == 1.0)
             self.current_max_clique_size = len(current_clique) if self.current_max_clique_size \
                                                                   < len(current_clique)else self.current_max_clique_size
             return current_clique
         return max(self.branching(self.add_constraint(cplex.Cplex(problem), branching_variable, 1.0)),
                    self.branching(self.add_constraint(cplex.Cplex(problem), branching_variable, 0.0)),
                    key=lambda list: len(list))
     return list()
Exemple #11
0
    def __init__(self, A):
        self.upper_bound = 1000
        self.eps = 1e-10
        self.dimension = 0

        try:
            self.cpl = Cplex()
        except NameError, CplexSolverError:
            raise CplexNotInstalledError()
Exemple #12
0
def lp(a, b, c):
    # number of equations (m) and unknowns (n)
    m, n = a.shape
    # objective function and lower bounds
    obj = c.copy()
    lb = zeros(n)
    # constraints
    count = 0
    sense = ""
    rows = []
    cols = []
    vals = []
    rhs = []
    for i in range(m):
        rows.extend([count for k in range(n)])
        cols.extend([k for k in range(n)])
        vals.extend(a[i, :])
        rhs.append(b[i])
        sense += "L"
        count += 1
    # cplex problem variable
    prob = Cplex()
    # quiet results
    #prob.set_results_stream(None)
    # maximiation problem
    prob.objective.set_sense(prob.objective.sense.maximize)
    # problem variables
    prob.variables.add(obj=obj, lb=lb)
    #for j in range(prob.variables.get_num()):
    #    prob.variables.set_types(j,prob.variables.type.integer)
    # linear constraints
    prob.linear_constraints.add(rhs=rhs, senses=sense)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))
    # alg method
    alg = prob.parameters.lpmethod.values
    prob.parameters.lpmethod.set(alg.auto)
    # solve problem
    prob.solve()
    # solution variables
    var = prob.solution.get_values()
    x = var[0:n]
    opt = prob.solution.get_objective_value()
    # return
    return opt, x
def modelisation():

    # Variables

    m, L, li, qi = read_instance_file(argv[1])

    # Modèle pour résoudre le problème de minimisation des planches utilisées

    model = Cplex()
    model.set_results_stream(None)

    # Variables de décision du modèle

    model_variables = list(range(len(li)))
    model.variables.add(obj=[1 for j in model_variables])

    # Contraintes du modèle

    model_contraintes = range(len(qi))

    model.linear_constraints.add(
        lin_expr=[SparsePair() for j in model_contraintes],
        senses=["G" for j in model_contraintes],
        rhs=qi)

    for var_index in model_variables:
        model.linear_constraints.set_coefficients(var_index, var_index,
                                                  int(L / li[var_index]))

    # Modèle utilisé pour générer des pattern en utilisant
    # la méthode Column generation de Gilmore-Gomory

    pattern_model = Cplex()
    pattern_model.set_results_stream(None)

    # Variable de décision

    panneaux_indices = range(len(li))
    pattern_model.variables.add(
        types=[pattern_model.variables.type.integer for j in panneaux_indices])

    pattern_model.variables.add(obj=[1], lb=[1], ub=[1])

    # L'unique contrainte ici est que la taille total des panneaux ne peut être
    # plus grande que la longueur de la planche L.
    pattern_model.linear_constraints.add(
        lin_expr=[SparsePair(ind=panneaux_indices, val=li)],
        senses=["L"],
        rhs=[L])

    # Définir l'objectif (Minimisation)
    pattern_model.objective.set_sense(pattern_model.objective.sense.minimize)

    return m, model, pattern_model, model_contraintes, model_variables, panneaux_indices
Exemple #14
0
 def formulate(self):
     self.set_aux()
     self.M = Cplex() if self.solver == 'cplex' else Model()
     self.addVars()
     self.addCons()
     self.setObj()
     self.p, self.a, self.obj, self.converged, self.tot_its = None,None,None,False,0
     if self.verbose: 
         print 'solving with', self.solver
         print '%2s %10s %8s %4s %3s %10s' % ('it', 'worst line', 'viol', 'stat', 
                 'its', 'obj')
def select_winners(ads, max_duration):
    '''
    Computes the set of winners that has the maximum total price.
    The numbers of winners are returned.
    '''
    from cplex import Cplex
    prob = Cplex()
    prob.variables.add([ad['bid'] for ad in ads], types=prob.variables.type.binary * len(ads))
    prob.linear_constraints.add([[range(len(ads)), [ad['duration'] for ad in ads]]], 'L', [max_duration])
    prob.objective.set_sense(prob.objective.sense.maximize)
    prob.solve()
    winners = set()
    losers = set()
    sol = prob.solution.get_values()
    print sol
    for i, ad in enumerate(ads):
        if sol[i] > 0.5:
            winners.add(ad)
        else:
            losers.add(ad)
    return winners, losers
def copy_cplex(cpx):
    """
    Copy a Cplex object
    :param cpx: Cplex object
    :return: Copy of Cplex object
    """
    cpx_copy = Cplex(cpx)
    cpx_parameters = cpx.parameters.get_changed()
    for (pname, pvalue) in cpx_parameters:
        phandle = reduce(getattr, str(pname).split("."), cpx_copy)
        phandle.set(pvalue)
    return cpx_copy
Exemple #17
0
def branch_and_bound(model: cplex.Cplex, optimal_objective_value, optimal_values):
    if check_timeout():
        global is_timeout
        is_timeout = True
        return optimal_objective_value, optimal_values

    model.solve()

    new_result = model.solution.get_objective_value()
    new_variables = model.solution.get_values()

    integer_new_result = round_with_eps(new_result)

    if not is_result_improved(optimal_objective_value, integer_new_result):
        # print("BOUND:\tSolution became worse from:\t{}\tto\t{}".format(optimal_objective_value, new_result))
        return optimal_objective_value, optimal_values
    if is_result_integer(new_variables):
        print("\nFound better integer solution:\tmax clique size:\t{}\n".format(new_result))
        return integer_new_result, new_variables

    branching_var = branching(new_variables)
    # print("BRANCHING:\t\tmax clique float size:\t{}\t\t\t\t\t\t{}".format(new_result, branching_var))

    up, down = build_new_constrains(branching_var)

    add_constraint(up, model)
    optimal_objective_value, optimal_values = branch_and_bound(model,
                                                               optimal_objective_value,
                                                               optimal_values)
    delete_constraint(up['names'][0], model)

    add_constraint(down, model)
    optimal_objective_value, optimal_values = branch_and_bound(model,
                                                               optimal_objective_value,
                                                               optimal_values)
    delete_constraint(down['names'][0], model)

    return optimal_objective_value, optimal_values
Exemple #18
0
    def __init_optimization_problem(self):

        problem = Cplex()

        sense = problem.objective.sense
        problem.objective.set_sense(sense=sense.maximize)

        variables = self.__build_variables()
        # self.__log('Variables: ', variables)

        objective = self.__build_objective(variables)
        # self.__log('Objective: ', objective)

        problem.variables.add(names=variables,
                              types=['C'] * len(variables),
                              ub=[1.0] * self.__problem.vertices_num(),
                              obj=objective)

        constraints = self.__build_constraints(variables)
        # self.__log('Constraints count: ', len(constraints))
        self.__set_constraints(problem, constraints)

        self.__optimization_problem = problem
def run_docplex_check_list():
    check_platform()

    # check requirements
    check_import("six")
    check_import("enum")
    check_import("cloudpickle")

    # check cplex
    try:
        from cplex import Cplex

        cpx = Cplex()
        del cpx
    except ImportError:
        print("Cplex DLL not found, if present , you must add it to PYTHNPATH")

    # check pandas
    try:
        import pandas as pd
        from pandas import DataFrame, Series
        dd = DataFrame({})
    except ImportError:
        print("-- pandas is not present, some features might be unavailable.")
Exemple #20
0
class SimpleCPLEX:
    def __init__(self, cplex=None):
        if cplex:
            self._model = Cplex(cplex._model)
        else:
            self._model = Cplex()
        self._init_lin()
        # to avoid a variable with index 0
        self._model.variables.add(
            names=['_dummy_'], types=[self._model.variables.type.continuous])
        self._var_id = {'_dummy_': 0}

    def _init_lin(self):
        self._lin = {
            'lin_expr': [],
            'senses': [],
            'rhs': [],
            'range_values': [],
            'names': []
        }

    def register_variables(self, prefix, ranges, var_type, lb=None, ub=None):
        if not ranges:  # None or []
            return self._register_variable(prefix, var_type, lb, ub)

        variables = {}
        for keys in product(*ranges):
            name = '_'.join([prefix] + [str(e) for e in keys])
            index = self._register_variable(name, var_type, lb, ub)
            if len(keys) == 1:
                keys = keys[0]
            variables[keys] = index
        return variables

    def _register_variable(self, name, var_type, lb, ub):
        self._model.variables.add(names=[name],
                                  types=[var_type],
                                  lb=[] if lb is None else [lb],
                                  ub=[] if ub is None else [ub])
        if name in self._var_id:
            logger.info('Variable %s is already registered. Overwritten', name)
        index = len(self._var_id)
        self._var_id[name] = index
        return index

    def model(self):
        return self._model

    @property
    def parameters(self):
        return self._model.parameters

    @property
    def variables(self):
        return self._model.variables

    @property
    def objective(self):
        return self._model.objective

    @property
    def problem_type(self):
        return self._model.problem_type

    @property
    def solution(self):
        return self._model.solution

    @property
    def version(self):
        return self._model.get_version()

    def maximize(self):
        self._model.objective.set_sense(self._model.objective.sense.maximize)

    def minimize(self):
        self._model.objective.set_sense(self._model.objective.sense.minimize)

    def set_problem_type(self, problem_type):
        self._model.set_problem_type(problem_type)

    def tune_problem(self, options):
        self._model.set_results_stream(None)
        self._model.parameters.tune_problem(options)
        self._model.set_results_stream(stdout)

    def solve(self):
        self._model.solve()

    def populate(self):
        self._model.solve()
        self._model.populate_solution_pool()

    def variable(self, name):
        """
        :param name: variable name
        :type name: str
        :return: variable index in CPLEX model
        :rtype: int
        """
        return self._var_id[name]

    def get_values(self, lst, idx=None):
        if idx:
            return self._model.solution.pool.get_values(idx, lst)
        else:
            return self._model.solution.get_values(lst)

    def get_objective_value(self, idx=None):
        if idx:
            return self._model.solution.pool.get_objective_value(idx)
        else:
            return self._model.solution.get_objective_value()

    @property
    def num_solutions(self):
        return self._model.solution.pool.get_num()

    @staticmethod
    def _convert_sense(sense):
        # Note: ignore 'R' range case
        assert sense in ['E', 'L', 'G', '>=', '=', '==', '<=']
        if sense == '<=':
            sense = 'L'
        elif sense == '=' or sense == '==':
            sense = 'E'
        elif sense == '>=':
            sense = 'G'
        return sense

    def set_objective(self, lst):
        """
        :type lst: list[int or (int, float) or (int, int, float)] or float
        """
        if isinstance(lst, float):
            self._model.objective.set_offset(lst)
            return

        linear = []
        quad = []
        assert isinstance(lst, list)
        for e in lst:
            assert isinstance(e, int) or isinstance(e, tuple)
            if isinstance(e, int):
                if e > 0:
                    linear.append((e, 1))
                elif e < 0:
                    linear.append((-e, -1))
                else:
                    raise RuntimeError('invalid variable ID')
            elif len(e) == 2:
                linear.append(e)
            else:
                assert len(e) == 3
                e = (min(e[0], e[1]), max(e[0], e[1]), e[2])
                quad.append(e)
        if linear:
            self._model.objective.set_linear(linear)
        if quad:
            self._model.objective.set_quadratic_coefficients(quad)

    @staticmethod
    def _convert_coefficients(coef):
        """
        Convert 'x', and '-x' into ('x', 1) and ('x', -1), respectively.

        :type coef: list[(int, float) or int]
        :rtype: (list[int], list[float])
        """
        ind = []
        val = []
        for e in coef:
            if isinstance(e, tuple):
                assert len(e) == 2
                ind.append(e[0])
                val.append(e[1])
            elif isinstance(e, int):
                if e >= 0:
                    ind.append(e)
                    val.append(1)
                else:
                    ind.append(-e)
                    val.append(-1)
            else:
                raise RuntimeError('unsupported type:' + str(e))
        return ind, val

    def add_linear_constraint(self, coef, sense, rhs):
        """
        :type coef: list[(int, float)]
        :type sense: string
        :type rhs: float
        :rtype: None
        """
        if not coef:
            logger.warning('empty linear constraint')
            return
        ind, val = self._convert_coefficients(coef)
        sense = self._convert_sense(sense)
        c = self._lin
        c['lin_expr'].append(SparsePair(ind, val))
        c['senses'].append(sense)
        c['rhs'].append(rhs)
        c['range_values'].append(0)
        c['names'].append('c' + str(len(self._lin['names'])))
        # logger.debug('%s %s %s %s', c['names'][-1], c['lin_expr'][-1], c['senses'][-1], c['rhs'][-1])

    def add_indicator_constraint(self, indvar, complemented, coef, sense, rhs):
        """
        :type indvar: int
        :type complemented: int
        :type coef: list[(int, float)]
        :type sense: string
        :type rhs: float
        :rtype: None
        """
        ind, val = self._convert_coefficients(coef)
        sense = self._convert_sense(sense)
        c = {
            'lin_expr': SparsePair(ind, val),
            'sense': sense,
            'rhs': rhs,
            'name': 'i' + str(self._model.indicator_constraints.get_num()),
            'indvar': indvar,
            'complemented': complemented
        }

        self._model.indicator_constraints.add(**c)

    def add_sos(self, coef):
        """
        :type coef: list[(int, float)]
        """
        ind, val = self._convert_coefficients(coef)
        c = {
            'type': '1',
            'SOS': SparsePair(ind, val),
            'name': 'sos' + str(self._model.SOS.get_num()),
        }

        self._model.SOS.add(**c)

    def add_quadratic_constraint(self, lin, quad, sense, rhs):
        """
        :type lin: list[(int, float)]
        :type quad: list[(int, int, float)]
        :type sense: string
        :type rhs: float
        :rtype: None
        """
        ind, val = self._convert_coefficients(lin)
        ind1 = [e[0] for e in quad]
        ind2 = [e[1] for e in quad]
        val2 = [e[2] for e in quad]
        sense = self._convert_sense(sense)
        c = {
            'lin_expr': SparsePair(ind, val),
            'quad_expr': SparseTriple(ind1, ind2, val2),
            'sense': sense,
            'rhs': rhs,
            'name': 'q' + str(self._model.quadratic_constraints.get_num())
        }

        self._model.quadratic_constraints.add(**c)

    def build_model(self):
        self._model.linear_constraints.add(**self._lin)
        self._init_lin()

    def write(self, filename, filetype=''):
        self._model.write(filename, filetype)
Exemple #21
0
def create_risk_slim(coef_set, input):
    """
    create RiskSLIM MIP object

    Parameters
    ----------
    input - dictionary of RiskSLIM parameters and formulation

    Returns
    -------
    mip - RiskSLIM surrogate MIP without 0 cuts

    Issues
    ----
    no support for non-integer Lset "values"
    only drops intercept index for variable_names that match '(Intercept)'
    """
    assert isinstance(coef_set, CoefficientSet)
    assert isinstance(input, dict)

    # setup printing and loading
    function_print_flag = input.get('print_flag', False)
    print_from_function = lambda msg: print_log(msg) if function_print_flag else lambda msg: None
    update_parameter = lambda pname, pvalue: get_or_set_default(input, pname, pvalue, print_flag = function_print_flag)

    # set default parameters
    input = update_parameter('w_pos', 1.0)
    input = update_parameter('w_neg', 2.0 - input['w_pos'])
    input = update_parameter('C_0', 0.01)
    input = update_parameter('include_auxillary_variable_for_objval', True)
    input = update_parameter('include_auxillary_variable_for_L0_norm', True)
    input = update_parameter('loss_min', 0.00)
    input = update_parameter('loss_max', float(CPX_INFINITY))
    input = update_parameter('L0_min', 0)
    input = update_parameter('L0_max', len(coef_set))
    input = update_parameter('objval_min', 0.00)
    input = update_parameter('objval_max', float(CPX_INFINITY))
    input = update_parameter('relax_integer_variables', False)
    input = update_parameter('drop_variables', True)
    input = update_parameter('tight_formulation', False)
    input = update_parameter('set_cplex_cutoffs', True)

    # variables
    P = len(coef_set)
    w_pos, w_neg = input['w_pos'], input['w_neg']
    C_0j = np.copy(coef_set.c0)
    L0_reg_ind = np.isnan(C_0j)
    C_0j[L0_reg_ind] = input['C_0']
    C_0j = C_0j.tolist()
    C_0_rho = np.copy(C_0j)
    trivial_L0_min = 0
    trivial_L0_max = np.sum(L0_reg_ind)

    rho_ub = list(coef_set.ub)
    rho_lb = list(coef_set.lb)
    rho_type = ''.join(list(coef_set.vtype))

    # calculate min/max values for loss
    loss_min = max(0.0, float(input['loss_min']))
    loss_max = min(CPX_INFINITY, float(input['loss_max']))

    # calculate min/max values for model size
    L0_min = max(input['L0_min'], 0.0)
    L0_max = min(input['L0_max'], trivial_L0_max)
    L0_min = ceil(L0_min)
    L0_max = floor(L0_max)
    assert L0_min <= L0_max

    # calculate min/max values for objval
    objval_min = max(input['objval_min'], 0.0)
    objval_max = min(input['objval_max'], CPX_INFINITY)
    assert objval_min <= objval_max

    # include constraint on min/max model size?
    nontrivial_L0_min = L0_min > trivial_L0_min
    nontrivial_L0_max = L0_max < trivial_L0_max
    include_auxillary_variable_for_L0_norm = input['include_auxillary_variable_for_L0_norm'] or \
                                             nontrivial_L0_min or \
                                             nontrivial_L0_max

    # include constraint on min/max objective value?
    nontrivial_objval_min = objval_min > 0.0
    nontrivial_objval_max = objval_max < CPX_INFINITY
    include_auxillary_variable_for_objval = input['include_auxillary_variable_for_objval'] or \
                                            nontrivial_objval_min or \
                                            nontrivial_objval_max

    has_intercept = '(Intercept)' in coef_set.variable_names
    """
    RiskSLIM MIP Formulation
    
    minimize w_pos*loss_pos + w_neg *loss_minus + 0*rho_j + C_0j*alpha_j
    
    such that 
    
    L0_min <= L0 <= L0_max
    -rho_min * alpha_j < lambda_j < rho_max * alpha_j

    L_0 in 0 to P
    rho_j in [rho_min_j, rho_max_j]
    alpha_j in {0,1}

    x = [loss_pos, loss_neg, rho_j, alpha_j]

    optional constraints:
    objval = w_pos * loss_pos + w_neg * loss_min + sum(C_0j * alpha_j) (required for callback)
    L0_norm = sum(alpha_j) (required for callback)


    Changes for Tight Formulation (included when input['tight_formulation'] = True):

    sigma_j in {0,1} for j s.t. lambda_j has free sign and alpha_j exists
    lambda_j >= delta_pos_j if alpha_j = 1 and sigma_j = 1
    lambda_j <= -delta_neg_j if alpha_j = 1 and sigma_j = 0
    lambda_j >= alpha_j for j such that lambda_j >= 0
    lambda_j <= -alpha_j for j such that lambda_j <= 0
    
    """

    # create MIP object
    mip = Cplex()
    vars = mip.variables
    cons = mip.linear_constraints

    # set sense
    mip.objective.set_sense(mip.objective.sense.minimize)

    # add main variables
    loss_obj = [w_pos]
    loss_ub = [loss_max]
    loss_lb = [loss_min]
    loss_type = 'C'
    loss_names = ['loss']

    obj = loss_obj + [0.0] * P + C_0j
    ub = loss_ub + rho_ub + [1.0] * P
    lb = loss_lb + rho_lb + [0.0] * P
    ctype = loss_type + rho_type + 'B' * P

    rho_names = ['rho_%d' % j for j in range(P)]
    alpha_names = ['alpha_%d' % j for j in range(P)]
    varnames = loss_names + rho_names + alpha_names

    if include_auxillary_variable_for_objval:
        objval_auxillary_name = ['objval']
        objval_auxillary_ub = [objval_max]
        objval_auxillary_lb = [objval_min]
        objval_type = 'C'

        print_from_function("adding auxiliary variable for objval s.t. %1.4f <= objval <= %1.4f" % (objval_min, objval_max))
        obj += [0.0]
        ub += objval_auxillary_ub
        lb += objval_auxillary_lb
        varnames += objval_auxillary_name
        ctype += objval_type


    if include_auxillary_variable_for_L0_norm:
        L0_norm_auxillary_name = ['L0_norm']
        L0_norm_auxillary_ub = [L0_max]
        L0_norm_auxillary_lb = [L0_min]
        L0_norm_type = 'I'

        print_from_function("adding auxiliary variable for L0_norm s.t. %d <= L0_norm <= %d" % (L0_min, L0_max))
        obj += [0.0]
        ub += L0_norm_auxillary_ub
        lb += L0_norm_auxillary_lb
        varnames += L0_norm_auxillary_name
        ctype += L0_norm_type

    if input['relax_integer_variables']:
        ctype = ctype.replace('I', 'C')
        ctype = ctype.replace('B', 'C')

    vars.add(obj = obj, lb = lb, ub = ub, types = ctype, names = varnames)

    # 0-Norm LB Constraints:
    # lambda_j,lb * alpha_j <= lambda_j <= Inf
    # 0 <= lambda_j - lambda_j,lb * alpha_j < Inf
    for j in range(P):
        cons.add(names = ["L0_norm_lb_" + str(j)],
                 lin_expr = [SparsePair(ind=[rho_names[j], alpha_names[j]], val=[1.0, -rho_lb[j]])],
                 senses = "G",
                 rhs = [0.0])

    # 0-Norm UB Constraints:
    # lambda_j <= lambda_j,ub * alpha_j
    # 0 <= -lambda_j + lambda_j,ub * alpha_j
    for j in range(P):
        cons.add(names = ["L0_norm_ub_" + str(j)],
                 lin_expr =[SparsePair(ind=[rho_names[j], alpha_names[j]], val=[-1.0, rho_ub[j]])],
                 senses = "G",
                 rhs = [0.0])

    # objval_max constraint
    # loss_var + sum(C_0j .* alpha_j) <= objval_max
    if include_auxillary_variable_for_objval:
        print_from_function("adding constraint so that objective value <= " + str(objval_max))
        cons.add(names = ["objval_def"],
                 lin_expr = [SparsePair(ind = objval_auxillary_name + loss_names + alpha_names, val=[-1.0] + loss_obj + C_0j)],
                 senses = "E",
                 rhs = [0.0])

    # Auxiliary L0_norm variable definition:
    # L0_norm = sum(alpha_j)
    # L0_norm - sum(alpha_j) = 0
    if include_auxillary_variable_for_L0_norm:
        cons.add(names = ["L0_norm_def"],
                 lin_expr = [SparsePair(ind = L0_norm_auxillary_name + alpha_names, val = [1.0] + [-1.0] * P)],
                 senses = "E",
                 rhs = [0.0])


    # drop L0_norm_lb constraint for any variable with rho_lb >= 0
    dropped_variables = []
    constraints_to_drop = []

    # drop alpha / L0_norm_ub / L0_norm_lb for ('Intercept')
    if input['drop_variables']:
        # drop L0_norm_ub/lb constraint for any variable with rho_ub/rho_lb >= 0
        sign_pos_ind = np.flatnonzero(coef_set.sign > 0)
        sign_neg_ind = np.flatnonzero(coef_set.sign < 0)
        constraints_to_drop.extend(["L0_norm_lb_" + str(j) for j in sign_pos_ind])
        constraints_to_drop.extend(["L0_norm_ub_" + str(j) for j in sign_neg_ind])

        # drop alpha for any variable where rho_ub = rho_lb = 0
        fixed_value_ind = np.flatnonzero(coef_set.ub == coef_set.lb)
        variables_to_drop = ["alpha_" + str(j) for j in fixed_value_ind]
        vars.delete(variables_to_drop)
        dropped_variables += variables_to_drop
        alpha_names = [alpha_names[j] for j in range(P) if alpha_names[j] not in dropped_variables]

    if has_intercept:
        intercept_idx = coef_set.variable_names.index('(Intercept)')
        intercept_alpha_name = 'alpha_' + str(intercept_idx)
        vars.delete([intercept_alpha_name])

        alpha_names.remove(intercept_alpha_name)
        dropped_variables.append(intercept_alpha_name)

        print_from_function("dropped L0 indicator for '(Intercept)'")
        constraints_to_drop.extend(["L0_norm_ub_" + str(intercept_idx), "L0_norm_lb_" + str(intercept_idx)])

    if len(constraints_to_drop) > 0:
        constraints_to_drop = list(set(constraints_to_drop))
        cons.delete(constraints_to_drop)

    # indices
    indices = {
        'n_variables': vars.get_num(),
        'n_constraints': cons.get_num(),
        'names': vars.get_names(),
        'loss_names': loss_names,
        'rho_names': rho_names,
        'alpha_names': alpha_names,
        'loss': vars.get_indices(loss_names),
        'rho': vars.get_indices(rho_names),
        'alpha': vars.get_indices(alpha_names),
        'L0_reg_ind': L0_reg_ind,
        'C_0_rho': C_0_rho,
        'C_0_alpha': mip.objective.get_linear(alpha_names) if len(alpha_names) > 0 else [],
        }

    if include_auxillary_variable_for_objval:
        indices.update({
            'objval_name': objval_auxillary_name,
            'objval': vars.get_indices(objval_auxillary_name)[0],
            })

    if include_auxillary_variable_for_L0_norm:
        indices.update({
            'L0_norm_name': L0_norm_auxillary_name,
            'L0_norm': vars.get_indices(L0_norm_auxillary_name)[0],
            })

    # officially change the problem to LP if variables are relaxed
    if input['relax_integer_variables']:
        old_problem_type = mip.problem_type[mip.get_problem_type()]
        mip.set_problem_type(mip.problem_type.LP)
        new_problem_type = mip.problem_type[mip.get_problem_type()]
        print_from_function("changed problem type from %s to %s" % (old_problem_type, new_problem_type))

    if input['set_cplex_cutoffs'] and not input['relax_integer_variables']:
        mip.parameters.mip.tolerances.lowercutoff.set(objval_min)
        mip.parameters.mip.tolerances.uppercutoff.set(objval_max)

    return mip, indices
Exemple #22
0
    def Quadratic_constraint(self):
        """Adds Quadratic constraint to the model's Gurobi/Cplex Interface.
        (x-mu).T @ inv(cov) @ (x-mu) <= chi-square
        Note: This one creates one ellipsoidal constraint for all the metabolites that has non zero or non 'nan' formation energy, irrespective of the magnitude of variance. if the model is infeasible after adding this constraint, refer to util_func.py, find_correlated metabolites to add different ellipsoidal constraints to high variance and normal compounds to avoid possible numerical issues.

        Unable to retrieve quadratic constraints in Gurobi model, can see the QC when printed.

        :raises NotImplementedError: Implemented only for Gurobi/Cplex interfaces.
        :return: [description]
        :rtype: [type]
        """

        # Pick indices of components present in the current model
        model_component_indices = [
            i for i in range(self.compound_vector_matrix.shape[1])
            if np.any(self.compound_vector_matrix[:, i])
        ]

        # Reduced the compound_vector to contain only the non zero entries
        model_compound_vector = self.compound_vector_matrix[:,
                                                            model_component_indices]

        # Now extract the sub covariance matrix containing only the components present in the model
        component_model_covariance = covariance[:, model_component_indices][
            model_component_indices, :]

        # Now separate the compounds that have variance > 1000 and others to avoid numerical issues
        high_variance_indices = np.where(
            np.diag(component_model_covariance) > 1000)[0]
        low_variance_indices = np.where(
            np.diag(component_model_covariance) < 1000)[0]

        # Calculate cholesky matrix for two different covariance matrices
        if len(low_variance_indices) > 0:
            small_component_covariance = component_model_covariance[:, low_variance_indices][
                low_variance_indices, :]
            cholesky_small_variance = matrix_decomposition(
                small_component_covariance)
            chi2_value_small = stats.chi2.isf(
                q=0.05, df=cholesky_small_variance.shape[1]
            )  # Chi-square value to map confidence interval

            for i in high_variance_indices:
                zeros_axis = np.zeros((cholesky_small_variance.shape[1], ))
                cholesky_small_variance = np.insert(cholesky_small_variance,
                                                    i,
                                                    zeros_axis,
                                                    axis=0)

            metabolite_sphere_small = (
                model_compound_vector @ cholesky_small_variance
            )  # This is a fixed term compound_vector @ cholesky

        if len(high_variance_indices) > 0:
            large_component_covariance = component_model_covariance[:, high_variance_indices][
                high_variance_indices, :]  # Covariance matrix for the high variance components

            cholesky_large_variance = matrix_decomposition(
                large_component_covariance)
            chi2_value_high = stats.chi2.isf(
                q=0.05, df=cholesky_large_variance.shape[1])

            # Insert empty rows for the low_variance_components
            for i in low_variance_indices:
                zeros_axis = np.zeros((cholesky_large_variance.shape[1], ))
                cholesky_large_variance = np.insert(cholesky_large_variance,
                                                    i,
                                                    zeros_axis,
                                                    axis=0)
            metabolite_sphere_large = (
                model_compound_vector @ cholesky_large_variance
            )  # This is a fixed term compound_vector @ cholesky

        proton_indices = [
            self.metabolites.index(metabolite)
            for metabolite in self.metabolites
            if metabolite.equilibrator_accession is not None
            if metabolite.equilibrator_accession.inchi_key == PROTON_INCHI_KEY
        ]  # Get indices of protons in metabolite list to avoid double correcting them for concentrations

        if self.solver.__class__.__module__ == "optlang.cplex_interface":

            from cplex import Cplex, SparsePair, SparseTriple

            # Instantiate Cplex model
            cplex_model = Cplex()

            rand_str = "".join(
                choices(string.ascii_lowercase + string.digits, k=6))
            # write cplex model to mps file in random directory and re read
            with tempfile.TemporaryDirectory() as td:
                temp_filename = os.path.join(td, rand_str + ".mps")
                self.solver.problem.write(temp_filename)
                cplex_model.read(temp_filename)

            # Stop printing output in cplex
            cplex_model.set_log_stream(None)
            cplex_model.set_error_stream(None)
            cplex_model.set_warning_stream(None)
            cplex_model.set_results_stream(None)

            # Remove the unnecessary variables and constraints
            remove_vars = [
                var for var in cplex_model.variables.get_names()
                if var.startswith("component_") or var.startswith("dG_err_")
            ]  # Remove error variables

            remove_constrs = [
                cons for cons in cplex_model.linear_constraints.get_names()
                if cons.startswith("delG_") or cons.startswith("std_dev_")
            ]  # Remove delG constraint and re-add with component variables

            cplex_model.linear_constraints.delete(
                remove_constrs)  # Removing constr
            cplex_model.variables.delete(remove_vars)  # Removing Vars

            # QC for small variance components
            if len(low_variance_indices) > 0:
                indices_sphere1 = cplex_model.variables.add(
                    names=[
                        "Sphere1_{}".format(i)
                        for i in range(cholesky_small_variance.shape[1])
                    ],
                    lb=[-1] * cholesky_small_variance.shape[1],
                    ub=[1] * cholesky_small_variance.shape[1],
                )  # Adding independent component variables to the model, store the variable indices

                # Add the Sphere constraint
                cplex_model.quadratic_constraints.add(
                    quad_expr=SparseTriple(
                        ind1=indices_sphere1,
                        ind2=indices_sphere1,
                        val=len(indices_sphere1) * [1],
                    ),
                    sense="L",
                    rhs=1,
                    name="unit_normal_small_variance",
                )
            else:
                indices_sphere1 = [
                ]  # Just to adjust the matrix dimensions later

            # QC for large variance components
            if len(high_variance_indices) > 0:
                indices_sphere2 = cplex_model.variables.add(
                    names=[
                        "Sphere2_{}".format(i)
                        for i in range(cholesky_large_variance.shape[1])
                    ],
                    lb=[-1] * cholesky_large_variance.shape[1],
                    ub=[1] * cholesky_large_variance.shape[1],
                )  # Independent large variance components

                cplex_model.quadratic_constraints.add(
                    quad_expr=SparseTriple(
                        ind1=indices_sphere2,
                        ind2=indices_sphere2,
                        val=len(indices_sphere2) * [1],
                    ),
                    rhs=1,
                    sense="L",
                    name="unit_normal_high_variance",
                )
            else:
                indices_sphere2 = []  # Balancing matrix dimensions

            concentration_variables = [
                "lnc_{}".format(metabolite.id)
                for metabolite in self.metabolites
            ]

            # Add the delG constraints
            for reaction in self.reactions:
                if reaction.id in self.Exclude_reactions:
                    continue
                rxn_stoichiometry = reaction.cal_stoichiometric_matrix()
                rxn_stoichiometry = rxn_stoichiometry[np.newaxis, :]

                if len(low_variance_indices) > 0:
                    coefficient_matrix_small_variance = (
                        np.sqrt(chi2_value_small) *
                        rxn_stoichiometry @ metabolite_sphere_small
                    )  # Coefficient array for small variance ellipsoid
                else:
                    coefficient_matrix_small_variance = np.array(())

                if len(high_variance_indices) > 0:
                    coefficient_matrix_large_variance = (
                        np.sqrt(chi2_value_high) *
                        rxn_stoichiometry @ metabolite_sphere_large
                    )  # Coefficient array for large variance ellipsoid
                else:
                    coefficient_matrix_large_variance = np.array(())

                concentration_coefficients = RT * rxn_stoichiometry
                concentration_coefficients[0, proton_indices] = 0

                coefficients_forward = np.hstack((
                    np.array((1)),
                    -1 * concentration_coefficients.flatten(),
                    -1 * coefficient_matrix_small_variance.flatten(),
                    -1 * coefficient_matrix_large_variance.flatten(),
                ))

                coefficients_reverse = np.hstack((
                    np.array((1)),
                    concentration_coefficients.flatten(),
                    coefficient_matrix_small_variance.flatten(),
                    coefficient_matrix_large_variance.flatten(),
                ))

                variable_order_forward = (
                    ["dG_{}".format(reaction.forward_variable.name)] +
                    concentration_variables + list(indices_sphere1) +
                    list(indices_sphere2))
                variable_order_reverse = (
                    ["dG_{}".format(reaction.reverse_variable.name)] +
                    concentration_variables + list(indices_sphere1) +
                    list(indices_sphere2))

                rhs = reaction.delG_prime + reaction.delG_transport

                cplex_model.linear_constraints.add(
                    lin_expr=[
                        SparsePair(
                            ind=variable_order_forward,
                            val=coefficients_forward.tolist(),
                        )
                    ],
                    senses=["E"],
                    rhs=[rhs],
                    names=["delG_{}".format(reaction.forward_variable.name)],
                )  # delG constraint for forward reaction

                cplex_model.linear_constraints.add(
                    lin_expr=[
                        SparsePair(
                            ind=variable_order_reverse,
                            val=coefficients_reverse.tolist(),
                        )
                    ],
                    senses=["E"],
                    rhs=[-rhs],
                    names=["delG_{}".format(reaction.reverse_variable.name)],
                )  # delG constraint for reverse reaction

            return cplex_model

        elif self.solver.__class__.__module__ == "optlang.gurobi_interface":
            from gurobipy import GRB, LinExpr

            gurobi_model = self.solver.problem.copy()

            # Remove unnecessary variables and constraints and rebuild  appropriate ones
            remove_vars = [
                var for var in gurobi_model.getVars()
                if var.VarName.startswith("component_")
                or var.VarName.startswith("dG_err_")
            ]

            remove_constrs = [
                cons for cons in gurobi_model.getConstrs()
                if cons.ConstrName.startswith("delG_")
                or cons.ConstrName.startswith("std_dev_")
            ]

            gurobi_model.remove(remove_constrs + remove_vars)

            # Add sphere variables for smaller set and larger set separately
            if len(low_variance_indices) > 0:
                for i in range(cholesky_small_variance.shape[1]):
                    gurobi_model.addVar(lb=-1,
                                        ub=1,
                                        name="Sphere1_{}".format(i))

                gurobi_model.update()
                sphere1_variables = [
                    var for var in gurobi_model.getVars()
                    if var.VarName.startswith("Sphere1_")
                ]

                gurobi_model.addQConstr(
                    np.sum(np.square(np.array(sphere1_variables))) <= 1,
                    name="unit_normal_small_variance",
                )
                gurobi_model.update()
            else:
                sphere1_variables = []

            # QC for large variance components
            if len(high_variance_indices) > 0:
                for i in range(cholesky_large_variance.shape[1]):
                    gurobi_model.addVar(lb=-1,
                                        ub=1,
                                        name="Sphere2_{}".format(i))

                gurobi_model.update()
                sphere2_variables = [
                    var for var in gurobi_model.getVars()
                    if var.VarName.startswith("Sphere2_")
                ]

                gurobi_model.addQConstr(
                    np.sum(np.square(np.array(sphere2_variables))) <= 1,
                    name="unit_normal_high_variance",
                )
                gurobi_model.update()
            else:
                sphere2_variables = []

            # Create a list of metabolite concentration variables
            concentration_variables = []
            for metabolite in self.metabolites:
                varname = "lnc_{}".format(metabolite.id)
                conc_var = gurobi_model.getVarByName(varname)
                concentration_variables.append(conc_var)

            # Add the delG constraints
            for reaction in self.reactions:
                if reaction.id in self.Exclude_reactions:
                    continue
                rxn_stoichiometry = reaction.cal_stoichiometric_matrix()
                rxn_stoichiometry = rxn_stoichiometry[np.newaxis, :]

                if len(low_variance_indices) > 0:
                    coefficient_matrix_small_variance = (
                        np.sqrt(chi2_value_small) *
                        rxn_stoichiometry @ metabolite_sphere_small
                    )  # Coefficient array for small variance ellipsoid
                else:
                    coefficient_matrix_small_variance = np.array(())

                if len(high_variance_indices) > 0:
                    coefficient_matrix_large_variance = (
                        np.sqrt(chi2_value_high) *
                        rxn_stoichiometry @ metabolite_sphere_large
                    )  # Coefficient array for large variance ellipsoid
                else:
                    coefficient_matrix_large_variance = np.array(())

                concentration_coefficients = RT * rxn_stoichiometry
                concentration_coefficients[0, proton_indices] = 0

                coefficients_forward = np.hstack((
                    -1 * concentration_coefficients.flatten(),
                    -1 * coefficient_matrix_small_variance.flatten(),
                    -1 * coefficient_matrix_large_variance.flatten(),
                ))

                coefficients_reverse = np.hstack((
                    concentration_coefficients.flatten(),
                    coefficient_matrix_small_variance.flatten(),
                    coefficient_matrix_large_variance.flatten(),
                ))

                variable_order = (concentration_variables + sphere1_variables +
                                  sphere2_variables)

                delG_err_forward = LinExpr(coefficients_forward.tolist(),
                                           variable_order)
                delG_err_reverse = LinExpr(coefficients_reverse.tolist(),
                                           variable_order)

                delG_for_var = gurobi_model.getVarByName("dG_{}".format(
                    reaction.forward_variable.name))
                delG_rev_var = gurobi_model.getVarByName("dG_{}".format(
                    reaction.reverse_variable.name))
                rhs = reaction.delG_prime + reaction.delG_transport

                gurobi_model.addConstr(
                    delG_for_var + delG_err_forward,
                    GRB.EQUAL,
                    rhs,
                    name="delG_{}".format(reaction.forward_variable.name),
                )

                gurobi_model.addConstr(
                    delG_rev_var + delG_err_reverse,
                    GRB.EQUAL,
                    -rhs,
                    name="delG_{}".format(reaction.reverse_variable.name),
                )

            gurobi_model.update()

            return gurobi_model

        else:
            raise NotImplementedError("Current solver doesn't support QC")
            logging.error(
                "Current solver doesnt support problesm of type MIQC")
Exemple #23
0
 def __init__(self):
     Cplex.__init__(self)
Exemple #24
0
def create_problem(cobra_model, quadratic_component=None, **kwargs):
    """Solver-specific method for constructing a solver problem from
    a cobra.Model.  This can be tuned for performance using kwargs


    """
    # Process parameter defaults
    the_parameters = parameter_defaults
    if kwargs:
        the_parameters = parameter_defaults.copy()
        the_parameters.update(kwargs)
    if 'relax_b' in the_parameters:
        relax_b = the_parameters.pop("relax_b")
        warn('need to reimplement relax_b')
        relax_b = False
    else:
        relax_b = False

    # Begin problem creation
    lp = Cplex()
    for k, v in iteritems(the_parameters):
        set_parameter(lp, k, v)
    objective_coefficients = [
        float(x.objective_coefficient) for x in cobra_model.reactions
    ]
    lower_bounds = [_float(x.lower_bound) for x in cobra_model.reactions]
    upper_bounds = [_float(x.upper_bound) for x in cobra_model.reactions]
    variable_names = cobra_model.reactions.list_attr("id")
    variable_kinds = [
        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 variable_kind_dict['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)

    constraint_sense = []
    constraint_names = []
    constraint_limits = []

    for x in cobra_model.metabolites:
        constraint_sense.append(x._constraint_sense)
        constraint_names.append(x.id)
        constraint_limits.append(float(x._bound))

    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(
                _float(the_reaction._metabolites[the_metabolite]))
        the_linear_expressions.append(
            SparsePair(ind=variable_list, val=coefficient_list))
    # Set objective to quadratic program
    if quadratic_component is not None:
        set_quadratic_objective(lp, quadratic_component)

    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)

    # 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)
    return (lp)
Exemple #25
0
class CCOPF:
    def __init__(self, conf='conf9', data_dir='data', solver='cplex', verbose=True):
        if verbose: print 'loading problem data'
        self.conf = conf
        self.solver = solver
        self.tol = 1e-5
        self.verbose = verbose
        bus, branch, Bbus, Binv, self.line_nu, self.gen_nu = loadfiles.load(
                self.conf, data_dir)
        self.data = [bus, branch, Bbus, Binv]

    def set_aux(self):
        ''' Helper variables built from the input data. Call this after
        changing the data; don't modify these directly '''
        bus, branch, Bbus, Binv = self.data 
        n = Bbus.shape[0] # number of buses
        nl = len(branch) # number of lines
        d = [bus[b]['d'] for b in bus] # demand
        mu = [bus[b].get('avg', 0) for b in bus] # mean wind power
        winds = {b for b in bus if 'std' in bus[b]} # wind source bus IDs
        sigma = {b: bus[b]['std'] for b in bus if b in winds} # std wind power
        gens = {b for b in bus if bus[b]['type'] == 2} # generator bus IDs
        self.aux = [n, nl, d, mu, winds, sigma, gens]

    def formulate(self):
        self.set_aux()
        self.M = Cplex() if self.solver == 'cplex' else Model()
        self.addVars()
        self.addCons()
        self.setObj()
        self.p, self.a, self.obj, self.converged, self.tot_its = None,None,None,False,0
        if self.verbose: 
            print 'solving with', self.solver
            print '%2s %10s %8s %4s %3s %10s' % ('it', 'worst line', 'viol', 'stat', 
                    'its', 'obj')

    def addVars(self):
        bus,branch,_,_, n,nl,_,_,_,_,gens = self.data + self.aux
        if self.verbose: print 'defining variables'
        INF = 1e100
        if self.solver == 'cplex':
            p = ['p_%d'%i for i in gens]
            a = ['a_%d'%i for i in gens]
            D = ['D_%d'%i for i in bus]
            t = ['t_%d'%i for i in bus]
            m = ['m{}'.format(i['id']) for i in branch] 
            s = ['s{}'.format(i['id']) for i in branch]
            self.M.variables.add(names = p + a)
            self.M.variables.add(names = D + t, lb = [-INF]*2*n)
            #self.M.variables.add(names = m, lb = [-INF]*nl)
            #self.M.variables.add(names = s)
            self.M.variables.add(names = m + s, lb = [-INF]*2*nl)
            D, t = arr(D), arr(t)
            self.var = (p, a, D, t, m, s)
        else:
            p = {i: self.M.addVar(name='pbar_%d'%i) for i in gens}
            a = {i: self.M.addVar(name='alpha_%d'%i) for i in gens}
            D = {i: self.M.addVar(lb=-INF, name='delta_%d'%i) for i in bus}
            t = {i: self.M.addVar(lb=-INF, name='theta_%d'%i) for i in bus}
            m = {i['id']: self.M.addVar(lb=-INF, name='fbar{}'.format(i['id'])) for 
                    i in branch}
            s = {i['id']: self.M.addVar(lb=-INF, name='std{}'.format(i['id'])) for 
                    i in branch}
            self.var = (p, a, D, t, m, s)
            self.M.update()

    def addCons(self):
        bus,branch,Bbus,_, line_nu,gen_nu, n,_,d,mu,winds,sigma,gens = self.data + \
                [self.line_nu, self.gen_nu] + self.aux
        if self.verbose: print 'defining constraints'
        p, a, D, t, m, s = self.var 
        sumvar = sum(sigma[b]**2 for b in winds)
        if self.solver == 'cplex':
            ng = len(gens)
            self.M.linear_constraints.add(lin_expr = [sp(ind = a, val = [1.0]*ng)], 
                    rhs = [1.0], names=['sum_alpha'])
            self.M.linear_constraints.add(lin_expr = [sp(ind = p, val = [1.0]*ng)], 
                    rhs = [sum(d)-sum(mu)], names=['power_balance'])
            for i in xrange(n-1):
                Bi = Bbus[i,:-1].tocoo()
                J,V = Bi.col, Bi.data
                if i in gens:
                    pi, ai, Di, ti = 'p_%d'%i, 'a_%d'%i, 'delta_%d'%i, 'theta_%d'%i
                    self.M.linear_constraints.add(lin_expr = 
                            [sp(ind = list(D[J])+[ai], val = list(V)+[-1]),
                            sp(ind = list(t[J])+[pi], val = list(V)+[-1])], 
                            rhs=[0, mu[i]-d[i]], names=[Di, ti], senses='EE')
                    self.M.linear_constraints.add(lin_expr = 
                            [sp(ind = [pi,ai], val = [1, sumvar**.5*gen_nu]), 
                            sp(ind = [pi,ai], val = [1, -sumvar**.5*gen_nu])], 
                            rhs=[bus[i]['pmax'], bus[i]['pmin']], 
                            names=['gen+_%d'%i, 'gen-_%d'%i], senses='LG')
                else:
                    self.M.linear_constraints.add(lin_expr = 
                            [sp(ind = D[J], val = V), sp(ind = t[J], val = V)], 
                            rhs=[0, mu[i]-d[i]], names=['delta_%d'%i, 'theta_%d'%i], 
                            senses='EE')
            self.M.linear_constraints.add(lin_expr = 
                    [sp(ind = [D[n-1]], val = [1.0]), sp(ind = [t[n-1]], val = [1.0])], 
                    rhs = [0,0], names=['delta_%d'%(n-1), 'theta_%d'%(n-1)], senses='EE')
            for line in branch:
                ID = line['id']
                ij = line['ij']
                i,j = ij
                mij, sij = 'm{}'.format(ID), 's{}'.format(ID)
                self.M.linear_constraints.add(lin_expr = 
                        [sp(ind = [mij, t[i], t[j]], val = [1.0, -line['y'], line['y']])], 
                        rhs = [0], names=['line_avg_{}'.format(ID)], senses='E')
                self.M.linear_constraints.add(lin_expr = 
                        [sp(ind = [mij, sij], val = [-1.0, line_nu]),
                        sp(ind = [mij, sij], val = [1.0, line_nu])], 
                        names=['line+_{}'.format(ID), 'line-_{}'.format(ID)],
                        rhs = [line['fmax'], line['fmax']], senses='LL')
        else: # gurobi is much nicer
            self.M.addConstr(qs(a[i] for i in gens) == 1, 'sum_alpha_1')
            self.M.addConstr(qs(p[i] for i in gens) + sum(mu) == sum(d), 'power_balance')
            for i in xrange(n-1):
                Bi = Bbus[i,:-1].tocoo()
                Bi = zip(Bi.col, Bi.data)
                if i in gens:
                    self.M.addConstr(qs(v*D[j] for j,v in Bi) == a[i], 'delta_%d'%i)
                    self.M.addConstr(qs(v*t[j] for j,v in Bi) == p[i]+mu[i]-d[i], 
                            'theta_%d'%i)
                    self.M.addConstr(sumvar**.5*a[i]*gen_nu <= bus[i]['pmax']-p[i], 
                            'gen+_%d'%i)
                    self.M.addConstr(sumvar**.5*a[i]*gen_nu <= -bus[i]['pmin']+p[i], 
                            'gen-_%d'%i)
                else:
                    self.M.addConstr(qs(v*D[j] for j,v in Bi) == 0, 'delta_%d'%i)
                    self.M.addConstr(qs(v*t[j] for j,v in Bi) == mu[i]-d[i], 'theta_%d'%i)
            self.M.addConstr(D[n-1] == 0, 'delta')
            self.M.addConstr(t[n-1] == 0, 'theta')
            for line in branch:
                ID = line['id']
                ij = line['ij']
                i,j = ij
                self.M.addConstr(m[ID] == line['y']*(t[i]-t[j]), 
                        'line_avg_{}'.format(ID))
                self.M.addConstr(s[ID]*line_nu <= line['fmax'] - m[ID], 
                        'line+_{}'.format(ID))
                self.M.addConstr(s[ID]*line_nu <= line['fmax'] + m[ID], 
                        'line-_{}'.format(ID))

    def setObj(self):
        bus,_,_,_, _,_,_,_,winds,sigma,gens = self.data + self.aux
        p, a, D, t, m, s = self.var 
        cost = {b: bus[b]['cost'] for b in bus if b in gens}
        sumvar = sum(sigma[b]**2 for b in winds)
        if self.solver == 'cplex':
            ng = len(gens)
            nv = self.M.variables.get_num()
            cost = [2*cost[i] for i in gens] + [2*sumvar*cost[i] for i in gens] + \
                    [0.0]*(nv-2*ng)
            self.M.objective.set_quadratic(cost)
            self.M.set_results_stream(None)
        else:
            self.M.setObjective(qs(cost[i]*(p[i]*p[i] + sumvar*a[i]*a[i]) for i in gens))

    def solve_subproblem(self):
        if self.solver == 'cplex':
            self.M.solve()
            sol = self.M.solution
            self.obj = sol.get_objective_value()
            stat = sol.get_status()
            if stat == sol.status.optimal: 
                self.status = 'good'
            elif stat == sol.status.num_best:
                self.status = 'okay'
            else:
                self.status = 'fail'
                self.statcode = stat
            self.its = sol.progress.get_num_barrier_iterations()
            self.sol = sol
        else:
            self.M.params.outputFlag = 0
            self.M.optimize()
            self.obj = None
            if self.M.status == GRB.OPTIMAL:
                self.status = 'good'
                self.obj = self.M.ObjVal
            elif self.M.status == GRB.SUBOPTIMAL:
                self.status = 'okay'
                self.obj = self.M.ObjVal
            else:
                self.status = 'fail'
                self.statcode = self.M.status
            self.its = self.M.BarIterCount
        self.tot_its += self.its

    def compute_max_viol(self, it):
        tol, _,branch,_,Binv, line_nu, n,_,_,_,winds,sigma,gens = [self.tol] + \
                self.data + [self.line_nu] + self.aux
        p, a, D, t, m, s = self.var 
        self.worst = {'line': -1, 'val': 0}
        for index, line in enumerate(branch):
            ID = line['id']
            i,j = line['ij']
            y, fmax = line['y'], line['fmax']
            if self.solver == 'cplex':
                Di, Dj, mij = self.sol.get_values([D[i], D[j], 'm{}'.format(ID)])
            else:
                Di, Dj, mij = D[i].x, D[j].x, m[ID].x
            x = arr([y*(Binv[k][i]-Binv[k][j]-Di+Dj)*sigma[k] for k in winds])
            violation = (abs(mij)+line_nu*norm(x)-fmax)/fmax
            if violation > self.worst['val']:
                self.worst = {'line': index, 'val': violation}
        if self.worst['val'] < tol:
            self.converged = True
            self.p, self.a = zeros(n), zeros(n)
            for i in gens:
                if self.solver == 'cplex':
                    pi, ai = 'p_%d'%i, 'a_%d'%i
                    self.p[i], self.a[i] = self.sol.get_values(pi), self.sol.get_values(ai)
                else:
                    self.p[i], self.a[i] = p[i].x, a[i].x
        if self.verbose: 
            i = self.worst['line']
            print '%2d %4d->%-4d %8.2e %4s %3d %10.4e' % (it+1, branch[i]['ij'][0], 
                    branch[i]['ij'][1], self.worst['val'], self.status, self.its, self.obj)

    def add_cut(self, it):
        _,branch,_,Binv, _,_,_,_,winds,sigma,_ = self.data + self.aux
        p, a, D, t, m, s = self.var 
        index = self.worst['line']
        ID = branch[index]['id']
        i,j = branch[index]['ij']
        y = branch[index]['y']
        if self.solver == 'cplex':
            Di, Dj = self.sol.get_values([D[i], D[j]])
            sij = 's{}'.format(ID)
            Bij = {k: Binv[k][i]-Binv[k][j] for k in winds}
            rhs = y**2*sum([sigma[k]**2*Bij[k]*(Bij[k]-Di+Dj) for k in winds])
            coeff = y**2*sum([sigma[k]**2*(Bij[k]-Di+Dj) for k in winds])
            x = arr([y*(Bij[k]-Di+Dj)*sigma[k] for k in winds])
            #self.M.linear_constraints.add(lin_expr = [sp(ind = [sij], val = [1.0])], 
                    #rhs = [0], names=['cut_help%d'%it], senses='G')
            self.M.linear_constraints.add(lin_expr = 
                    [sp(ind = [sij, D[i], D[j]], val = [norm(x), coeff, -coeff])], 
                    rhs = [rhs], names=['cut_%d'%it], senses='G')
        else:
            x = arr([y*(Binv[k][i]-Binv[k][j]-D[i].x+D[j].x)*sigma[k] for k in winds])
            self.M.addConstr(s[ID] >= 0, 'cut_%d_help'%(it+1))
            self.M.addConstr(qs(x[l]*y*(Binv[k][i]-Binv[k][j]-D[i]+D[j])*sigma[k]
                    for l,k in enumerate(winds)) <= s[ID]*norm(x), 'cut_%d'%it)

    def set_mean(self, mu):
        ''' mu is a dictionary {busID: mean wind} '''
        bus = self.data[0] 
        winds = {b for b in bus if 'avg' in bus[b]}
        if winds != set(mu.keys()):
            print 'error: mu is different'
            return None
        for i, mean in mu.iteritems():
            bus[i]['avg'] = mean
        self.set_aux()

    def set_std(self, sigma):
        ''' sigma is a dictionary {busID: std wind} '''
        bus = self.data[0] 
        winds = {b for b in bus if 'std' in bus[b]}
        if winds != set(sigma.keys()):
            print 'error: sigma is different'
            return None
        for i, std in sigma.iteritems():
            bus[i]['std'] = std
        self.set_aux()

    def scale_load(self, alpha):
        bus = self.data[0] 
        for i in bus:
            bus[i]['d'] *= alpha
        self.set_aux()

    def scale_lim(self, alpha):
        branch = self.data[1] 
        for line in branch:
            line['fmax'] *= alpha
        self.set_aux()
Exemple #26
0
#!/usr/bin/env python3

import cplex
from cplex import Cplex
from cplex.exceptions import CplexError
import numpy as np
import matplotlib.pyplot as plt

mip_solver = Cplex()

# mip_solver.set_results_stream(None)
# mip_solver.set_warning_stream(None)
# mip_solver.set_error_stream(None)
#mip_solver.parameters.threads.set(1)

hidden_weights = np.load("hidden_weights.npy")
hidden_bias = np.load("hidden_bias.npy")
output_weights = np.load("output_weights.npy")
output_bias = np.load("output_bias.npy")

input_dim = 28 * 28
hidden_nodes = 20

#mip_solver.objective.set_sense(mip_solver.objective.sense.minimize)
mip_solver.objective.set_sense(mip_solver.objective.sense.maximize)

# Set the value of the output variable as objective function
mip_solver.variables.add(obj=[1],
                         lb=[-cplex.infinity],
                         ub=[cplex.infinity],
                         types="C",
Exemple #27
0
def run_docplex_check_list():
    check_platform()
    from docplex.version import latest_cplex_major, latest_cplex_minor
    cplex_latest_version_as_tuple = (latest_cplex_major, latest_cplex_minor)

    diagnostics = []

    # check requirements
    for rm in ["six", "enum", "cloudpickle"]:
        if not check_import(rm):
            diagnostics.append(
                "Module {0} is missing, run: pip install {0}".format(rm))

    # check pandas
    try:
        import pandas as pd  # @UnusedImport
        # noinspection PyUnresolvedReferences
        from pandas import DataFrame
        DataFrame({})
    except ImportError:
        print("-- pandas is not present, some features might be unavailable.")

    from docplex.mp.environment import Environment
    Environment().print_information()

    # check cplex
    try:
        # noinspection PyUnresolvedReferences
        from cplex import Cplex

        cpx = Cplex()
        cpxv = cpx.get_version()
        cpxvt = tuple(float(x) for x in cpx.get_version().split("."))[:2]
        lcpxv = ".".join(str(z) for z in cplex_latest_version_as_tuple)
        if cpxvt < cplex_latest_version_as_tuple:
            print(
                "Warning: Your cplex version {0} is not the latest, {1} is available"
                .format(cpxv, lcpxv))
        elif cpxvt > cplex_latest_version_as_tuple:
            print(
                "* Your cplex version {0} is ahead of the latest DOcplex-compatible version {1}, this might not be compatible."
                .format(cpxv, lcpxv))
        else:
            print("* Your cplex version {0} is the latest available".format(
                cpxv))
        cpx.end()

    except ImportError as ie:
        Cplex = None
        diagnostics.append("No local installation of CPLEX has been found.")
        print("Cplex DLL not found, error importing cplex: {0!s}".format(ie))
        check_python_path(diagnostics)
    # check creation of an empty model...

    try:
        if Cplex:
            # noinspection PyUnresolvedReferences
            from docplex.mp.model import Model
            Model()
            # promotional?
            if Model.is_cplex_ce():
                print(
                    "! Cplex promotional version, limited to 1000 variables, 1000 constraints"
                )
                diagnostics.append(
                    "Your local CPLEX edition is limited. Consider purchasing a full license."
                )

    except ImportError:
        print("Docplex is not present: cannot import class docplex.mp.model")
        diagnostics.append("Your installation of DOcplex may be corrupted.")
    except Exception as e:
        print(
            "Exception raised when creating one model instance: {0!s}".format(
                e))
        diagnostics.append("Your installation of DOcplex may be corrupted.")

    if diagnostics:
        print("\n!! diagnostics: {0}".format(len(diagnostics)))
        for s in diagnostics:
            print("  -- {0}".format(s))
    else:
        print("> No problem found: you're all set!")
Exemple #28
0
class CplexSolver(Solver):
    """ Implements the solver interface using CPLEX. """
    def __init__(self, model=None):
        Solver.__init__(self)
        self.problem = Cplex()

        self.status_mapping = {
            self.problem.solution.status.optimal:
            Status.OPTIMAL,
            self.problem.solution.status.optimal_tolerance:
            Status.OPTIMAL,
            self.problem.solution.status.unbounded:
            Status.UNBOUNDED,
            self.problem.solution.status.infeasible:
            Status.INFEASIBLE,
            self.problem.solution.status.infeasible_or_unbounded:
            Status.INF_OR_UNB,
            self.problem.solution.status.MIP_optimal:
            Status.OPTIMAL,
            self.problem.solution.status.MIP_unbounded:
            Status.UNBOUNDED,
            self.problem.solution.status.MIP_infeasible:
            Status.INFEASIBLE,
            self.problem.solution.status.MIP_infeasible_or_unbounded:
            Status.INF_OR_UNB
        }

        self.vartype_mapping = {
            VarType.BINARY: self.problem.variables.type.binary,
            VarType.INTEGER: self.problem.variables.type.integer,
            VarType.CONTINUOUS: self.problem.variables.type.continuous
        }

        self.parameter_mapping = {
            Parameter.TIME_LIMIT: self.problem.parameters.timelimit,
            Parameter.FEASIBILITY_TOL:
            self.problem.parameters.simplex.tolerances.feasibility,
            Parameter.OPTIMALITY_TOL:
            self.problem.parameters.simplex.tolerances.optimality,
            Parameter.INT_FEASIBILITY_TOL:
            self.problem.parameters.mip.tolerances.integrality,
            Parameter.MIP_ABS_GAP:
            self.problem.parameters.mip.tolerances.mipgap,
            Parameter.MIP_REL_GAP:
            self.problem.parameters.mip.tolerances.absmipgap,
            Parameter.POOL_SIZE: self.problem.parameters.mip.limits.populate,
            Parameter.POOL_GAP: self.problem.parameters.mip.pool.relgap
        }

        self.set_logging()
        self.set_parameters(default_parameters)

        #        self.problem.parameters.randomseed.set(0)
        #        self.problem.parameters.mip.strategy.search.set(1)

        self._cached_lin_obj = {}
        self._cached_sense = None
        self._cached_lower_bounds = {}
        self._cached_upper_bounds = {}
        self._cached_vars = []
        self._cached_constrs = []

        if model:
            self.build_problem(model)

    def add_variable(self,
                     var_id,
                     lb=None,
                     ub=None,
                     vartype=VarType.CONTINUOUS,
                     persistent=True,
                     update_problem=True):
        """ Add a variable to the current problem.

        Arguments:
            var_id (str): variable identifier
            lb (float): lower bound
            ub (float): upper bound
            vartype (VarType): variable type (default: CONTINUOUS)
            persistent (bool): if the variable should be reused for multiple calls (default: true)
            update_problem (bool): update problem immediately
        """

        if update_problem:
            self.add_variables([var_id], [lb], [ub], [vartype])
        else:
            self._cached_vars.append((var_id, lb, ub, vartype))

        if not persistent:
            self.temp_vars.add(var_id)

    def add_variables(self, var_ids, lbs, ubs, vartypes):
        """ Add multiple variables to the current problem.

        Arguments:
            var_ids (list): variable identifier
            lbs (list): lower bounds
            ubs (list): upper bounds
            vartypes (list): variable types (default: CONTINUOUS)
        """

        lbs = [lb if lb is not None else -infinity for lb in lbs]
        ubs = [ub if ub is not None else infinity for ub in ubs]

        if set(vartypes) == {VarType.CONTINUOUS}:
            self.problem.variables.add(names=var_ids, lb=lbs, ub=ubs)
        else:
            vartypes = [self.vartype_mapping[vartype] for vartype in vartypes]
            self.problem.variables.add(names=var_ids,
                                       lb=lbs,
                                       ub=ubs,
                                       types=vartypes)

        self.var_ids.extend(var_ids)
        self._cached_lower_bounds.update(dict(zip(var_ids, lbs)))
        self._cached_upper_bounds.update(dict(zip(var_ids, ubs)))
        self._cached_lin_obj.update({var_id: 0.0 for var_id in var_ids})

    def add_constraint(self,
                       constr_id,
                       lhs,
                       sense='=',
                       rhs=0,
                       persistent=True,
                       update_problem=True):
        """ Add a constraint to the current problem.

        Arguments:
            constr_id (str): constraint identifier
            lhs (dict): variables and respective coefficients
            sense (str): constraint sense (any of: '<', '=', '>'; default '=')
            rhs (float): right-hand side of equation (default: 0)
            persistent (bool): if the variable should be reused for multiple calls (default: True)
            update_problem (bool): update problem immediately
        """

        if update_problem:
            self.add_constraints([constr_id], [lhs], [sense], [rhs])
        else:
            self._cached_constrs.append((constr_id, lhs, sense, rhs))

        if not persistent:
            self.temp_constrs.add(constr_id)

    def add_constraints(self, constr_ids, lhs, senses, rhs):
        """ Add a list of constraints to the current problem.

        Arguments:
            constr_ids (list): constraint identifiers
            lhs (list): variables and respective coefficients
            senses (list): constraint senses (default: '=')
            rhs (list): right-hand side of equations (default: 0)
        """

        map_sense = {'=': 'E', '<': 'L', '>': 'G'}

        exprs = [
            SparsePair(ind=list(constr.keys()), val=list(constr.values()))
            for constr in lhs
        ]
        senses = [map_sense[sense] for sense in senses]

        self.problem.linear_constraints.add(lin_expr=exprs,
                                            senses=senses,
                                            rhs=rhs,
                                            names=constr_ids)
        self.constr_ids.extend(constr_ids)

    def remove_variable(self, var_id):
        """ Remove a variable from the current problem.

        Arguments:
            var_id (str): variable identifier
        """
        self.remove_variables([var_id])

    def remove_variables(self, var_ids):
        """ Remove variables from the current problem.

        Arguments:
            var_ids (list): variable identifiers
        """

        found = []
        for var_id in var_ids:
            if var_id in self.var_ids:
                found.append(var_id)
                self.var_ids.remove(var_id)

        self.problem.variables.delete(found)

    def remove_constraint(self, constr_id):
        """ Remove a constraint from the current problem.

        Arguments:
            constr_id (str): constraint identifier
        """
        self.remove_constraints([constr_id])

    def remove_constraints(self, constr_ids):
        """ Remove constraints from the current problem.

        Arguments:
            constr_ids (list): constraint identifiers
        """

        found = []
        for constr_id in constr_ids:
            if constr_id in self.constr_ids:
                found.append(constr_id)
                self.constr_ids.remove(constr_id)

        self.problem.linear_constraints.delete(found)

    def update(self):
        """ Update internal structure. Used for efficient lazy updating. """

        if self._cached_vars:
            var_ids, lbs, ubs, vartypes = list(zip(*self._cached_vars))
            self.add_variables(var_ids, lbs, ubs, vartypes)
            self._cached_vars = []

        if self._cached_constrs:
            constr_ids, lhs, senses, rhs = list(zip(*self._cached_constrs))
            self.add_constraints(constr_ids, lhs, senses, rhs)
            self._cached_constrs = []

    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:
            updated_coeffs = {}

            for var_id in self.var_ids:
                if var_id in linear and linear[var_id] != self._cached_lin_obj[
                        var_id]:
                    updated_coeffs[var_id] = linear[var_id]
                if var_id not in linear and self._cached_lin_obj[var_id] != 0.0:
                    updated_coeffs[var_id] = 0.0

            if updated_coeffs:
                self.problem.objective.set_linear(list(updated_coeffs.items()))
                self._cached_lin_obj.update(updated_coeffs)

        if quadratic:
            self.problem.objective.set_quadratic(
                [0.0] * len(self.var_ids))  #TODO: is this really necessary ?
            quad_coeffs = [(r_id1, r_id2, coeff)
                           for (r_id1, r_id2), coeff in quadratic.items()]
            self.problem.objective.set_quadratic_coefficients(quad_coeffs)

        if minimize != self._cached_sense:
            if minimize:
                sense = self.problem.objective.sense.minimize
            else:
                sense = self.problem.objective.sense.maximize
            self.problem.objective.set_sense(sense)
            self._cached_sense = minimize

    def build_problem(self, model):
        """ Create problem structure for a given model.

        Arguments:
            model : CBModel
        """

        var_ids = list(model.reactions.keys())
        lbs = [rxn.lb for rxn in model.reactions.values()]
        ubs = [rxn.ub for rxn in model.reactions.values()]

        var_types = [VarType.CONTINUOUS] * len(var_ids)
        self.add_variables(var_ids, lbs, ubs, var_types)

        constr_ids = list(model.metabolites.keys())
        table = model.metabolite_reaction_lookup(force_recalculate=True)
        lhs = list(table.values())
        senses = ['='] * len(constr_ids)
        rhs = [0] * len(constr_ids)
        self.add_constraints(constr_ids, lhs, senses, rhs)

    def solve(self,
              linear=None,
              quadratic=None,
              minimize=None,
              model=None,
              constraints=None,
              get_values=True,
              get_shadow_prices=False,
              get_reduced_costs=False,
              pool_size=0,
              pool_gap=None):
        """ Solve the optimization problem.

        Arguments:
            linear (dict): linear objective (optional)
            quadratic (dict): quadratic objective (optional)
            minimize (bool): solve a minimization problem (default: True)
            model (CBModel): model (optional, leave blank to reuse previous model structure)
            constraints (dict): additional constraints (optional)
            get_values (bool or list): set to false for speedup if you only care about the objective value (default: True)
            get_shadow_prices (bool): return shadow prices if available (default: False)
            get_reduced_costs (bool): return reduced costs if available (default: False)
            pool_size (int): calculate solution pool of given size (only for MILP problems)
            pool_gap (float): maximum relative gap for solutions in pool (optional)

        Returns:
            Solution: solution
        """

        if model:
            self.build_problem(model)

        problem = self.problem

        if constraints:
            changed_lb, changed_ub = self.temporary_bounds(constraints)

        self.set_objective(linear, quadratic, minimize)

        #        from datetime import datetime
        #        self.write_to_file(f"{datetime.now()}.lp")

        #run the optimization

        if pool_size == 0:

            problem.solve()

            status = self.status_mapping.get(problem.solution.get_status(),
                                             Status.UNKNOWN)
            message = str(problem.solution.get_status_string())

            if status == Status.OPTIMAL:
                fobj = problem.solution.get_objective_value()
                values, shadow_prices, reduced_costs = None, None, None

                if get_values:
                    if isinstance(get_values, Iterable):
                        get_values = list(get_values)
                        values = OrderedDict(
                            zip(get_values,
                                problem.solution.get_values(get_values)))
                    else:
                        values = OrderedDict(
                            zip(self.var_ids, problem.solution.get_values()))

                if get_shadow_prices:
                    shadow_prices = OrderedDict(
                        zip(self.constr_ids,
                            problem.solution.get_dual_values(self.constr_ids)))

                if get_reduced_costs:
                    reduced_costs = OrderedDict(
                        zip(self.var_ids,
                            problem.solution.get_reduced_costs(self.var_ids)))

                solution = Solution(status, message, fobj, values,
                                    shadow_prices, reduced_costs)
            else:
                solution = Solution(status, message)

        else:
            pool_pmap = {
                'SolnPoolIntensity': problem.parameters.mip.pool.intensity,
                'PopulateLim': problem.parameters.mip.limits.populate,
                'SolnPoolCapacity': problem.parameters.mip.pool.capacity,
                'SolnPoolReplace': problem.parameters.mip.pool.replace,
                'SolnPoolGap': problem.parameters.mip.pool.relgap,
                'SolnPoolAGap': problem.parameters.mip.pool.absgap
            }

            default_params = {
                'SolnPoolIntensity': 3,
                'PopulateLim': 10 * pool_size,
                'SolnPoolCapacity': pool_size,
                'SolnPoolReplace': 1
            }

            for param, val in default_params.items():
                pool_pmap[param].set(val)

            if pool_gap:
                pool_pmap['SolnPoolGap'].set(pool_gap)

            problem.populate_solution_pool()

            status = self.status_mapping.get(problem.solution.get_status(),
                                             Status.UNKNOWN)

            if status == Status.OPTIMAL or status == Status.UNKNOWN:
                solution = self.get_solution_pool(get_values)
            else:
                solution = []

        if constraints:
            self.reset_bounds(changed_lb, changed_ub)

        return solution

    def temporary_bounds(self, constraints):

        lower_bounds, upper_bounds = {}, {}
        lb_new, ub_new = {}, {}

        def _dict_diff(dict1, dict2):
            return set(dict1.items()) - set(dict2.items())

        for r_id, x in constraints.items():
            if r_id in self.var_ids:
                lb, ub = x if isinstance(x, tuple) else (x, x)
                lower_bounds[r_id] = lb if lb is not None else -infinity
                upper_bounds[r_id] = ub if ub is not None else infinity
            else:
                warnings.warn(
                    "Constrained variable '{}' not previously declared".format(
                        r_id), RuntimeWarning)

        if lower_bounds != self._cached_lower_bounds:
            lb_new = _dict_diff(lower_bounds, self._cached_lower_bounds)
            if len(lb_new) > 0:
                self.problem.variables.set_lower_bounds(lb_new)

        if upper_bounds != self._cached_upper_bounds:
            ub_new = _dict_diff(upper_bounds, self._cached_upper_bounds)
            if len(ub_new) > 0:
                self.problem.variables.set_upper_bounds(ub_new)

        return lb_new, ub_new

    def get_solution_pool(self, get_values=True):
        """ Return a solution pool for MILP problems.
        Must be called after using solve with pool_size argument > 0.

        Arguments:
            get_values (bool or list): set to false for speedup if you only care about the objective value (default: True)

        Returns:
            list: list of Solution objects

        """
        pool = self.problem.solution.pool
        solutions = []

        for i in range(pool.get_num()):
            obj = pool.get_objective_value(i)
            # TODO: remove all OrderedDicts when migrating to python 3.7
            #            values = OrderedDict([(r_id, pool.get_values(i, r_id)) for r_id in self.var_ids])
            if get_values:
                if isinstance(get_values, Iterable):
                    get_values = list(get_values)
                    values = dict(
                        zip(get_values, pool.get_values(i, get_values)))
                else:
                    values = dict(zip(self.var_ids, pool.get_values(i)))
            else:
                values = None
            sol = Solution(fobj=obj, values=values)
            solutions.append(sol)

        return solutions

    def reset_bounds(self, updated_lb, updated_ub):
        if updated_lb:
            lb_old = [(r_id, self._cached_lower_bounds[r_id])
                      for r_id, _ in updated_lb]
            self.problem.variables.set_lower_bounds(lb_old)
        if updated_ub:
            ub_old = [(r_id, self._cached_upper_bounds[r_id])
                      for r_id, _ in updated_ub]
            self.problem.variables.set_upper_bounds(ub_old)

    def set_lower_bounds(self, bounds_dict):
        self.problem.variables.set_lower_bounds([
            (var_id, lb if lb is not None else -infinity)
            for var_id, lb in bounds_dict.items()
        ])

    def set_upper_bounds(self, bounds_dict):
        self.problem.variables.set_lower_bounds([
            (var_id, ub if ub is not None else infinity)
            for var_id, ub in bounds_dict.items()
        ])

    def set_bounds(self, bounds_dict):
        self.problem.variables.set_lower_bounds([
            (var_id, bounds[0] if bounds[0] is not None else -infinity)
            for var_id, bounds in bounds_dict.items()
        ])
        self.problem.variables.set_upper_bounds([
            (var_id, bounds[1] if bounds[1] is not None else infinity)
            for var_id, bounds in bounds_dict.items()
        ])

    def update_coefficient(self, coeff, var_id, value):
        self.problem.linear_constraints.set_coefficients([(coeff, var_id,
                                                           value)])

    def update_coefficients(self, coefficients):
        self.problem.linear_constraints.set_coefficients(coefficients)

    def set_parameter(self, parameter, value):
        """ Set a parameter value for this optimization problem

        Arguments:
            parameter (Parameter): parameter type
            value (float): parameter value
        """

        if parameter in self.parameter_mapping:
            self.parameter_mapping[parameter].set(value)
        else:
            raise Exception('Parameter unknown (or not yet supported).')

    def set_logging(self, enabled=False):
        """ Enable or disable log output:

        Arguments:
            enabled (bool): turn logging on (default: False)
        """

        if enabled:
            self.problem.set_log_stream(sys.stdout)
            self.problem.set_error_stream(sys.stderr)
            self.problem.set_warning_stream(sys.stderr)
            self.problem.set_results_stream(sys.stdout)
        else:
            self.problem.set_log_stream(None)
            self.problem.set_error_stream(None)
            self.problem.set_warning_stream(None)
            self.problem.set_results_stream(None)

    def write_to_file(self, filename):
        """ Write problem to file:

        Arguments:
            filename (str): file path
        """

        self.problem.write(filename)
Exemple #29
0
def variability_legacy_cplex(
    model,
    variable_list=None,
    params=False,
):
    """Custom function to perform TVA on MIQC problem using gurobi.

    Parameters
    ----------
    model : multitfa.core.tmodel
        multitfa model after thermodynamic constraints are added
    variable_list : List, optional
        List of variables to perform TVA on, by default None
    params : Bool, optional
        If True sets the Timelimit option to 300 sec and reduced the mip gap to 0.005

    Returns
    -------
    pd.DataFrame
        Dataframe of min max ranges of variables

    Raises
    ------
    ValueError
        [description]
    """
    # Instead of copying the whole model, just copy the cplex solver object by writing to a file and reading again.
    from cplex import Cplex, SparsePair

    tmp_dir = (os.path.normpath(os.path.dirname(os.path.abspath(__file__))) +
               os.sep + os.pardir + os.sep + "tmp")
    if not os.path.exists(tmp_dir):
        os.makedirs(tmp_dir)

    # Instantiate Cplex model
    cplex_model = Cplex()
    rand_str = "".join(choices(string.ascii_lowercase + string.digits, k=6))

    # write cplex model to mps file and re read
    with tempfile.TemporaryDirectory() as td:
        temp_filename = os.path.join(td, rand_str + ".mps")
        model.cplex_interface.write(temp_filename)
        cplex_model.read(temp_filename)

    cplex_model.set_log_stream(None)
    cplex_model.set_error_stream(None)
    cplex_model.set_warning_stream(None)
    cplex_model.set_results_stream(None)

    if params:
        # print("lol")
        cplex_model.parameters.mip.tolerances.mipgap = 0.005
        cplex_model.parameters.timelimit = 300
        cplex_model.parameters.mip.limits.probetime = 300

    # Make shorts for sense
    max_sense = cplex_model.objective.sense.maximize
    min_sense = cplex_model.objective.sense.minimize

    if variable_list == None:
        variables = model.cplex_interface.variables.get_names()
    else:
        variables = [var for var in variable_list]

    vars_list_cplex = cplex_model.variables.get_names()

    fluxes_min = np.empty(len(variables))
    fluxes_max = np.empty(len(variables))
    rxn_name = list()

    rxn_ids = [rxn.id for rxn in model.reactions]

    for i in range(len(variables)):
        # Reset objective vector for each iteration
        for varname in vars_list_cplex:
            cplex_model.objective.set_linear(varname, 0)

        # if the variable is reactions optimize for forward - reverse variables else optimize for the variable
        if variables[i] in rxn_ids:
            rxn = model.reactions.get_by_id(variables[i])
            cplex_model.objective.set_linear([(rxn.forward_variable.name, 1),
                                              (rxn.reverse_variable.name, -1)])

        else:
            cplex_model.objective.set_linear(variables[i], 1)

        rxn_name.append(variables[i])

        # minimization
        cplex_model.objective.set_sense(min_sense)
        cplex_model.solve()
        objective_value = cplex_model.solution.get_objective_value()
        fluxes_min[i] = objective_value

        # maximiztion
        cplex_model.objective.set_sense(max_sense)
        cplex_model.solve()
        objective_value = cplex_model.solution.get_objective_value()
        fluxes_max[i] = objective_value

    return DataFrame({
        "minimum": Series(index=rxn_name, data=fluxes_min),
        "maximum": Series(index=rxn_name, data=fluxes_max),
    })
Exemple #30
0
#!/usr/bin/env python3

import cplex
from cplex import Cplex
from cplex.exceptions import CplexError
import numpy as np
import matplotlib.pyplot as plt

mip_solver = Cplex()

mip_solver.set_results_stream(None)
mip_solver.set_warning_stream(None)
mip_solver.set_error_stream(None)
# mip_solver.parameters.threads.set(1)

hidden_weights = [np.load("hidden_weights_1.npy"), np.load("hidden_weights_2.npy")]
hidden_bias = [np.load("hidden_bias_1.npy"), np.load("hidden_bias_2.npy")]
output_weights = np.load("output_weights.npy")
output_bias = np.load("output_bias.npy")

#mip_solver.objective.set_sense(mip_solver.objective.sense.minimize)

input_dim = 28*28
hidden_nodes = [10,10]
output_nodes = 10

# output variables
mip_solver.variables.add(
    lb = [-cplex.infinity]*output_nodes,
    ub = [cplex.infinity]*output_nodes,
    types = "C"*output_nodes,
Exemple #31
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
Exemple #32
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    
Exemple #33
0
def qps_cplex(H, c, A, l, u, xmin, xmax, x0, opt):
    """Quadratic Program Solver based on CPLEX.

    A wrapper function providing a PYPOWER standardized interface for using
    C{cplexqp} or C{cplexlp} to solve the following QP (quadratic programming)
    problem::

        min 1/2 X'*H*x + c'*x
         x

    subject to::

        l <= A*x <= u       (linear constraints)
        xmin <= x <= xmax   (variable bounds)

    Inputs (all optional except C{H}, C{c}, C{A} and C{l}):
        - C{H} : matrix (possibly sparse) of quadratic cost coefficients
        - C{c} : vector of linear cost coefficients
        - C{A, l, u} : define the optional linear constraints. Default
        values for the elements of L and U are -Inf and Inf, respectively.
        - C{xmin, xmax} : optional lower and upper bounds on the
        C{x} variables, defaults are -Inf and Inf, respectively.
        - C{x0} : optional starting value of optimization vector C{x}
        - C{opt} : optional options structure with the following fields,
        all of which are also optional (default values shown in parentheses)
            - C{verbose} (0) - controls level of progress output displayed
                - 0 = no progress output
                - 1 = some progress output
                - 2 = verbose progress output
            - C{cplex_opt} - options dict for CPLEX, value in
            verbose overrides these options
        - C{problem} : The inputs can alternatively be supplied in a single
        C{problem} dict with fields corresponding to the input arguments
        described above: C{H, c, A, l, u, xmin, xmax, x0, opt}

    Outputs:
        - C{x} : solution vector
        - C{f} : final objective function value
        - C{exitflag} : CPLEXQP/CPLEXLP exit flag
        (see C{cplexqp} and C{cplexlp} documentation for details)
        - C{output} : CPLEXQP/CPLEXLP output dict
        (see C{cplexqp} and C{cplexlp} documentation for details)
        - C{lmbda} : dict containing the Langrange and Kuhn-Tucker
        multipliers on the constraints, with fields:
            - mu_l - lower (left-hand) limit on linear constraints
            - mu_u - upper (right-hand) limit on linear constraints
            - lower - lower bound on optimization variables
            - upper - upper bound on optimization variables

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ##----- input argument handling  -----
    ## gather inputs
    if isinstance(H, dict):  ## problem struct
        p = H
        if 'opt' in p: opt = p['opt']
        if 'x0' in p: x0 = p['x0']
        if 'xmax' in p: xmax = p['xmax']
        if 'xmin' in p: xmin = p['xmin']
        if 'u' in p: u = p['u']
        if 'l' in p: l = p['l']
        if 'A' in p: A = p['A']
        if 'c' in p: c = p['c']
        if 'H' in p: H = p['H']
    else:  ## individual args
        assert H is not None
        assert c is not None
        assert A is not None
        assert l is not None

    if opt is None:
        opt = {}
#    if x0 is None:
#        x0 = array([])
#    if xmax is None:
#        xmax = array([])
#    if xmin is None:
#        xmin = array([])

## define nx, set default values for missing optional inputs
    if len(H) == 0 or not any(any(H)):
        if len(A) == 0 and len(xmin) == 0 and len(xmax) == 0:
            stderr.write(
                'qps_cplex: LP problem must include constraints or variable bounds\n'
            )
        else:
            if len(A) > 0:
                nx = shape(A)[1]
            elif len(xmin) > 0:
                nx = len(xmin)
            else:  # if len(xmax) > 0
                nx = len(xmax)
    else:
        nx = shape(H)[0]

    if len(c) == 0:
        c = zeros(nx)

    if  len(A) > 0 and (len(l) == 0 or all(l == -Inf)) and \
                       (len(u) == 0 or all(u ==  Inf)):
        A = None  ## no limits => no linear constraints

    nA = shape(A)[0]  ## number of original linear constraints
    if len(u) == 0:  ## By default, linear inequalities are ...
        u = Inf * ones(nA)  ## ... unbounded above and ...

    if len(l) == 0:
        l = -Inf * ones(nA)  ## ... unbounded below.

    if len(xmin) == 0:  ## By default, optimization variables are ...
        xmin = -Inf * ones(nx)  ## ... unbounded below and ...

    if len(xmax) == 0:
        xmax = Inf * ones(nx)  ## ... unbounded above.

    if len(x0) == 0:
        x0 = zeros(nx)

    ## default options
    if 'verbose' in opt:
        verbose = opt['verbose']
    else:
        verbose = 0

    #if 'max_it' in opt:
    #    max_it = opt['max_it']
    #else:
    #    max_it = 0

    ## split up linear constraints
    ieq = find(abs(u - l) <= EPS)  ## equality
    igt = find(u >= 1e10 & l > -1e10)  ## greater than, unbounded above
    ilt = find(l <= -1e10 & u < 1e10)  ## less than, unbounded below
    ibx = find((abs(u - l) > EPS) & (u < 1e10) & (l > -1e10))
    Ae = A[ieq, :]
    be = u[ieq]
    Ai = r_[A[ilt, :], -A[igt, :], A[ibx, :] - A[ibx, :]]
    bi = r_[u[ilt], -l[igt], u[ibx], -l[ibx]]

    ## grab some dimensions
    nlt = len(ilt)  ## number of upper bounded linear inequalities
    ngt = len(igt)  ## number of lower bounded linear inequalities
    nbx = len(ibx)  ## number of doubly bounded linear inequalities

    ## set up options struct for CPLEX
    if 'cplex_opt' in opt:
        cplex_opt = cplex_options(opt['cplex_opt'])
    else:
        cplex_opt = cplex_options

    cplex = Cplex('null')
    vstr = cplex.getVersion
    s, e, tE, m, t = re.compile(vstr, '(\d+\.\d+)\.')
    vnum = int(t[0][0])
    vrb = max([0, verbose - 1])
    cplex_opt['barrier']['display'] = vrb
    cplex_opt['conflict']['display'] = vrb
    cplex_opt['mip']['display'] = vrb
    cplex_opt['sifting']['display'] = vrb
    cplex_opt['simplex']['display'] = vrb
    cplex_opt['tune']['display'] = vrb
    if vrb and (vnum > 12.2):
        cplex_opt['diagnostics'] = 'on'
    #if max_it:
    #    cplex_opt.    ## not sure what to set here

    if len(Ai) == 0 and len(Ae) == 0:
        unconstrained = 1
        Ae = sparse((1, nx))
        be = 0
    else:
        unconstrained = 0

    ## call the solver
    if verbose:
        methods = [
            'default', 'primal simplex', 'dual simplex', 'network simplex',
            'barrier', 'sifting', 'concurrent'
        ]

    if len(H) == 0 or not any(any(H)):
        if verbose:
            stdout.write('CPLEX Version %s -- %s LP solver\n' %
                         (vstr, methods[cplex_opt['lpmethod'] + 1]))

        x, f, eflag, output, lam = \
            cplexlp(c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)
    else:
        if verbose:
            stdout.write('CPLEX Version %s --  %s QP solver\n' %
                         (vstr, methods[cplex_opt['qpmethod'] + 1]))
        ## ensure H is numerically symmetric
        if H != H.T:
            H = (H + H.T) / 2

        x, f, eflag, output, lam = \
            cplexqp(H, c, Ai, bi, Ae, be, xmin, xmax, x0, cplex_opt)

    ## check for empty results (in case optimization failed)
    if len(x) == 0:
        x = NaN * zeros(nx)

    if len(f) == 0:
        f = NaN

    if len(lam) == 0:
        lam['ineqlin'] = NaN * zeros(len(bi))
        lam['eqlin'] = NaN * zeros(len(be))
        lam['lower'] = NaN * zeros(nx)
        lam['upper'] = NaN * zeros(nx)
        mu_l = NaN * zeros(nA)
        mu_u = NaN * zeros(nA)
    else:
        mu_l = zeros(nA)
        mu_u = zeros(nA)

    if unconstrained:
        lam['eqlin'] = array([])

    ## negate prices depending on version
    if vnum < 12.3:
        lam['eqlin'] = -lam['eqlin']
        lam['ineqlin'] = -lam['ineqlin']

    ## repackage lambdas
    kl = find(lam.eqlin < 0)  ## lower bound binding
    ku = find(lam.eqlin > 0)  ## upper bound binding

    mu_l[ieq[kl]] = -lam['eqlin'][kl]
    mu_l[igt] = lam['ineqlin'][nlt + arange(ngt)]
    mu_l[ibx] = lam['ineqlin'][nlt + ngt + nbx + arange(nbx)]

    mu_u[ieq[ku]] = lam['eqlin'][ku]
    mu_u[ilt] = lam['ineqlin'][:nlt]
    mu_u[ibx] = lam['ineqlin'][nlt + ngt + arange(nbx)]

    lmbda = {
        'mu_l': mu_l,
        'mu_u': mu_u,
        'lower': lam.lower,
        'upper': lam.upper
    }

    return x, f, eflag, output, lmbda
Exemple #34
0
def create_problem(cobra_model, quadratic_component=None, **kwargs):
    """Solver-specific method for constructing a solver problem from
    a cobra.Model.  This can be tuned for performance using kwargs


    """
    # Process parameter defaults
    the_parameters = parameter_defaults
    if kwargs:
        the_parameters = parameter_defaults.copy()
        the_parameters.update(kwargs)
    if 'relax_b' in the_parameters:
        relax_b = the_parameters.pop("relax_b")
        warn('need to reimplement relax_b')
        relax_b = False
    else:
        relax_b = False

    # Begin problem creation
    lp = Cplex()
    for k, v in iteritems(the_parameters):
        set_parameter(lp, k, v)
    objective_coefficients = [float(x.objective_coefficient)
                              for x in cobra_model.reactions]
    lower_bounds = [float(x.lower_bound) for x in cobra_model.reactions]
    upper_bounds = [float(x.upper_bound) for x in cobra_model.reactions]
    variable_names = cobra_model.reactions.list_attr("id")
    variable_kinds = [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 variable_kind_dict['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:
        ## 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(float(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(float(the_reaction._metabolites[the_metabolite]))
        the_linear_expressions.append(SparsePair(ind=variable_list,
                                                 val=coefficient_list))
    # Set objective to quadratic program
    if quadratic_component is not None:
        set_quadratic_objective(lp, quadratic_component)

    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)

    #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)
    return(lp)
Exemple #35
0
from cplex import Cplex, infinity
from cplex.exceptions import CplexError

problem = Cplex()

problem.objective.set_sense(problem.objective.sense.minimize)

objective = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]

constraints_matrix = [
    [1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0],
    [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
    [1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0],
    [0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0],
    [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0],
    [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0],
    [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0],
    [0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0],
]

col_names = [
    "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12"
]

row_names = [
    "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12"
]
Exemple #36
0
def fair_partial_assignment_lp_solver(df, centers, color_flag, alpha, beta,
                                      cost_fun_string):

    # There are primarily five steps:
    # 1. Initiate a model for cplex
    # 2. Declare if it is minimization or maximization problem
    # 3. Add variables to the model. The variables are generally named.
    #    The upper bounds and lower bounds on the range for the variables
    #    are also mentioned at this stage. The coefficient of the objective
    #    functions are also entered at this step
    # 4. Add the constraints to the model. The constraint matrix, denoted by A,
    #    can be added in three ways - row wise, column wise or non-zero entry wise.
    # 5. Finally, call the solver.

    # Step 1. Initiate a model for cplex.

    print("Initializing Cplex model")
    problem = Cplex()

    # Step 2. Declare that this is a minimization problem

    problem.objective.set_sense(problem.objective.sense.minimize)

    # Step 3.   Declare and  add variables to the model. The function
    #           prepare_to_add_variables (points, center) prepares all the
    #           required information for this stage.
    #
    #    objective: a list of coefficients (float) in the linear objective function
    #    lower bounds: a list of floats containing the lower bounds for each variable
    #    upper bounds: a list of floats containing the upper bounds for each variable
    #    variable_name: a list of strings that contains the name of the variables

    print("Starting to add variables...")
    print("HERE???")
    t1 = time.monotonic()
    objective, lower_bounds, upper_bounds, variable_names = prepare_to_add_variables(
        df, centers, cost_fun_string)
    problem.variables.add(obj=objective,
                          lb=lower_bounds,
                          ub=upper_bounds,
                          names=variable_names)
    t2 = time.monotonic()
    print("Completed. Time for creating and adding variable = {}".format(t2 -
                                                                         t1))

    # Step 4.   Declare and add constraints to the model.
    #           There are few ways of adding constraints: rwo wise, col wise and non-zero entry wise.
    #           Assume the constraint matrix is A. We add the constraints row wise.
    #           The function prepare_to_add_constraints_by_entry(points,center,colors,alpha,beta)
    #           prepares the required data for this step.
    #
    #  constraints_row: Encoding of each row of the constraint matrix
    #  senses: a list of strings that identifies whether the corresponding constraint is
    #          an equality or inequality. "E" : equals to (=), "L" : less than (<=), "G" : greater than equals (>=)
    #  rhs: a list of floats corresponding to the rhs of the constraints.
    #  constraint_names: a list of string corresponding to the name of the constraint

    print("Starting to add constraints...")
    t1 = time.monotonic()
    objects_returned = prepare_to_add_constraints(df, centers, color_flag,
                                                  beta, alpha)
    constraints_row, senses, rhs, constraint_names = objects_returned
    problem.linear_constraints.add(lin_expr=constraints_row,
                                   senses=senses,
                                   rhs=rhs,
                                   names=constraint_names)
    t2 = time.monotonic()
    print(
        "Completed. Time for creating and adding constraints = {}".format(t2 -
                                                                          t1))

    # Optional: We can set various parameters to optimize the performance of the lp solver
    # As an example, the following sets barrier method as the lp solving method
    # The other available methods are: auto, primal, dual, sifting, concurrent

    #problem.parameters.lpmethod.set(problem.parameters.lpmethod.values.barrier)

    return problem, objective
def solveit(max_duration, ads):
    # get the winners
    winners, losers = select_winners(ads, max_duration)

    # add a fake winner if needed.
    total_dur = sum([winner.duration for winner in winners])
    if total_dur < max_duration:
        winners.add(Ad(bid = 0.0001, duration =max_duration - total_dur))

    # get the upper contour for the losers
    bar = [i[1] for i in get_coutour(losers, max_duration, True)]
    print len(winners)

    winners = sorted(winners, key = lambda winner: (winner.duration, winner.bid))
    id2num = {id(winner):k for k, winner in enumerate(winners)}
    prob = Cplex()
    lb = [bar[winner.duration] for winner in winners]
    ub = [winner.bid for winner in winners]
    prob.objective.set_sense(prob.objective.sense.minimize)
    obj = [1] * len(winners)
    prob.variables.add(obj, lb, ub)

    # monotone requirement (optional)
    # for i, x in enumerate(winners):
    #     ceil = 1e9
    #     for k, y in enumerate(winners[i+1:]):
    #         j = i + 1 + k
    #         if y.bid == x.bid:
    #             if x.duration == y.duration:
    #                 prob.linear_constraints.add([[[i, j], [1,-1]]], ['E'], [0])
    #             else:
    #                 prob.linear_constraints.add([[[i, j],[1,-1]]],['L'],[0])
    #             break
    #         if y.bid > x.bid and y.bid < ceil:
    #             ceil = y.bid
    #             prob.linear_constraints.add([[[i,j],[1,-1]]],['L'],[0])

    n_iteration = 0
    last_obj = -1
    while True:
        n_iteration += 1
        prob.solve()
        obj = prob.solution.get_objective_value()
        last_obj = obj
        prices = prob.solution.get_values()
        for i, winner in enumerate(winners):
            winner.price = prices[i]
        lower_coutour = get_coutour(winners, max_duration, False)
        finish = True
        for k, tmp in enumerate(lower_coutour):
            ads, min_value = tmp
            if len(ads) == 0:
                continue
            if min_value < bar[k]:
                tmp = [id2num[id(ad)] for ad in ads]
                print prob.linear_constraints.get_num()
                prob.linear_constraints.add([[[id2num[id(ad)] for ad in ads], [1] * len(ads)]],\
                    ['G'], [bar[k]])
                finish = False
        if finish:
            break
    return sum(prob.solution.get_values()), len(winners), n_iteration