Example #1
0
    def solve_sat(self, expression=None, callback=None,
                  return_processor=None, kwargs={}):
        """Runs a solve sat with a callback.  This is similar to the
        other SAT solving procedures in this test suite, with some
        modifications to enable testing of the MIP callback
        functionality.

        expression is the expression argument, and defaults to the
        expression declared in the MIPCallbackTest.

        callback is the callback instance being tested.

        return_processor is a function called with the retval from the
        lp.integer call, and the lp, e.g., return_processor(retval,
        lp), prior to any further processing of the results.

        kwargs is a dictionary of other optional keyword arguments and
        their values which is passed to the lp.integer solution
        procedure."""
        if expression is None:
            expression = self.expression
        if len(expression) == 0:
            return []
        numvars = max(max(abs(v) for v in clause) for clause in expression)
        lp = LPX()
        lp.cols.add(2*numvars)
        for col in lp.cols:
            col.bounds = 0.0, 1.0

        def lit2col(lit):
            if lit > 0:
                return 2*lit-2
            return 2*(-lit)-1

        for i in range(1, numvars+1):
            lp.cols[lit2col(i)].name = 'x_%d' % i
            lp.cols[lit2col(-i)].name = '!x_%d' % i
            lp.rows.add(1)
            lp.rows[-1].matrix = [(lit2col(i), 1.0), (lit2col(-i), 1.0)]
            lp.rows[-1].bounds = 1.0
        for clause in expression:
            lp.rows.add(1)
            lp.rows[-1].matrix = [(lit2col(lit), 1.0) for lit in clause]
            lp.rows[-1].bounds = 1, None
        retval = lp.simplex()
        if retval is not None:
            return None
        if lp.status != 'opt':
            return None
        for col in lp.cols:
            col.kind = int
        retval = lp.integer(callback=callback, **kwargs)
        if return_processor:
            return_processor(retval, lp)
        if retval is not None:
            return None
        if lp.status != 'opt':
            return None
        return [col.value > 0.99 for col in lp.cols[::2]]
Example #2
0
    def solve_sat(self, expression):
        """Attempts to satisfy a formula of conjunction of disjunctions.

        If there are n variables in the expression, this will return a
        list of length n, all elements booleans.  The truth of element i-1
        corresponds to the truth of variable i.

        If no satisfying assignment could be found, None is returned."""
        if len(expression) == 0:
            return []
        numvars = max(max(abs(v) for v in clause) for clause in expression)
        lp = LPX()
        lp.cols.add(2*numvars)
        for col in lp.cols:
            col.bounds = 0.0, 1.0

        def lit2col(lit):
            if lit > 0:
                return 2*lit-2
            return 2*(-lit)-1

        for i in range(1, numvars+1):
            lp.cols[lit2col(i)].name = 'x_%d' % i
            lp.cols[lit2col(-i)].name = '!x_%d' % i
            lp.rows.add(1)
            lp.rows[-1].matrix = [(lit2col(i), 1.0), (lit2col(-i), 1.0)]
            lp.rows[-1].bounds = 1.0
        for clause in expression:
            lp.rows.add(1)
            lp.rows[-1].matrix = [(lit2col(lit), 1.0) for lit in clause]
            lp.rows[-1].bounds = 1, None
        retval = lp.simplex()
        if retval is not None:
            return None
        if lp.status != 'opt':
            return None
        for col in lp.cols:
            col.kind = int
        retval = lp.integer()
        if retval is not None:
            return None
        if lp.status != 'opt':
            return None
        return [col.value > 0.99 for col in lp.cols[::2]]
Example #3
0
    def testLpxInteger(self):
        lp = LPX()

        with self.assertRaises(RuntimeError) as cm:
            lp.integer()
        self.assertIn(
            'integer solver without presolve requires existing optimal basic '
            'solution',
            str(cm.exception)
        )

        with self.assertRaises(ValueError) as cm:
            lp.integer(ps_tm_lim=-1, presolve=True)
        self.assertIn('ps_tm_lim must be nonnegative', str(cm.exception))

        with self.assertRaises(ValueError) as cm:
            lp.integer(mip_gap=-1, presolve=True)
        self.assertIn('mip_gap must be non-negative', str(cm.exception))
Example #4
0
def _optimize_glpk(
        cobra_model,
        new_objective=None,
        objective_sense='maximize',
        min_norm=0,
        the_problem=None,
        tolerance_optimality=1e-6,
        tolerance_feasibility=1e-6,
        tolerance_integer=1e-9,
        error_reporting=None,
        print_solver_time=False,
        lp_method=1,
        quadratic_component=None,
        reuse_basis=True,
        #Not implemented
        tolerance_barrier=None,
        lp_parallel=None,
        copy_problem=None,
        relax_b=None,
        update_problem_reaction_bounds=True):
    """Uses the GLPK (www.gnu.org/software/glpk/) optimizer via pyglpk
    (http://www.tfinley.net/software/pyglpk/release.html) to perform an optimization
    on cobra_model for the objective_coefficients in cobra_model._objective_coefficients
    based on the objective sense.

    cobra_model: A cobra.Model object

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

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

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

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    cobra_model: A cobra.Model object

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

    objective_sense: 'maximize' or 'minimize'

    min_norm: not implemented

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

    tolerance_optimality: Solver tolerance for optimality.

    tolerance_feasibility: Solver tolerance for feasibility.

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

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

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

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

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

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

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

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

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

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

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

    return solution