Exemple #1
0
    def set_linear_coefficients(self, coefficients):
        if self.problem is not None:
            problem = self.problem.problem
            self.problem.update()

            num_cols = glp_get_num_cols(problem)

            ia = intArray(num_cols + 1)
            va = doubleArray(num_cols + 1)

            num_rows = glp_get_mat_row(self.problem.problem, self._index, ia, va)
            variables_and_coefficients = {var.name: coeff for var, coeff in six.iteritems(coefficients)}

            final_variables_and_coefficients = {
                glp_get_col_name(problem, ia[i]): va[i] for i in range(1, num_rows + 1)
            }
            final_variables_and_coefficients.update(variables_and_coefficients)

            ia = intArray(num_cols + 1)
            va = doubleArray(num_cols + 1)

            for i, (name, coeff) in enumerate(six.iteritems(final_variables_and_coefficients)):
                ia[i + 1] = self.problem._variables[name]._index
                va[i + 1] = float(coeff)

            glp_set_mat_row(problem, self._index, len(final_variables_and_coefficients), ia, va)
        else:
            raise Exception("Can't change coefficients if constraint is not associated with a model.")
    def set_linear_coefficients(self, coefficients):
        if self.problem is not None:
            problem = self.problem.problem

            num_cols = glp_get_num_cols(problem)

            ia = intArray(num_cols + 1)
            va = doubleArray(num_cols + 1)

            num_rows = glp_get_mat_row(self.problem.problem, self._index, ia, va)
            variables_and_coefficients = {var.name: coeff for var, coeff in six.iteritems(coefficients)}

            final_variables_and_coefficients = {
                glp_get_col_name(problem, ia[i]): va[i] for i in range(1, num_rows + 1)
            }
            final_variables_and_coefficients.update(variables_and_coefficients)

            ia = intArray(num_cols + 1)
            va = doubleArray(num_cols + 1)

            for i, (name, coeff) in enumerate(six.iteritems(final_variables_and_coefficients)):
                ia[i + 1] = self.problem._variables[name]._index
                va[i + 1] = coeff

            glp_set_mat_row(problem, self._index, len(final_variables_and_coefficients), ia, va)
        else:
            raise Exception("Can't change coefficients if constraint is not associated with a model.")
	def test_swiglpk(self):
		"""Test the underlying GLPK lib and its SWIG interface based on
		the example from https://github.com/biosustain/swiglpk
		"""
		ia = glp.intArray(1 + 1000)
		ja = glp.intArray(1 + 1000)
		ar = glp.doubleArray(1 + 1000)

		lp = glp.glp_create_prob()
		smcp = glp.glp_smcp()
		glp.glp_init_smcp(smcp)
		smcp.msg_lev = glp.GLP_MSG_ALL  # use GLP_MSG_ERR?

		glp.glp_set_prob_name(lp, "sample")
		glp.glp_set_obj_dir(lp, glp.GLP_MAX)

		glp.glp_add_rows(lp, 3)
		glp.glp_set_row_name(lp, 1, "p")
		glp.glp_set_row_bnds(lp, 1, glp.GLP_UP, 0.0, 100.0)
		glp.glp_set_row_name(lp, 2, "q")
		glp.glp_set_row_bnds(lp, 2, glp.GLP_UP, 0.0, 600.0)
		glp.glp_set_row_name(lp, 3, "r")
		glp.glp_set_row_bnds(lp, 3, glp.GLP_UP, 0.0, 300.0)
		glp.glp_add_cols(lp, 3)
		glp.glp_set_col_name(lp, 1, "x1")
		glp.glp_set_col_bnds(lp, 1, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 1, 10.0)
		glp.glp_set_col_name(lp, 2, "x2")
		glp.glp_set_col_bnds(lp, 2, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 2, 6.0)
		glp.glp_set_col_name(lp, 3, "x3")
		glp.glp_set_col_bnds(lp, 3, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 3, 4.0)

		ia[1] = 1; ja[1] = 1; ar[1] = 1.0  # a[1,1] = 1
		ia[2] = 1; ja[2] = 2; ar[2] = 1.0  # a[1,2] = 1
		ia[3] = 1; ja[3] = 3; ar[3] = 1.0  # a[1,3] = 1
		ia[4] = 2; ja[4] = 1; ar[4] = 10.0  # a[2,1] = 10
		ia[5] = 3; ja[5] = 1; ar[5] = 2.0  # a[3,1] = 2
		ia[6] = 2; ja[6] = 2; ar[6] = 4.0  # a[2,2] = 4
		ia[7] = 3; ja[7] = 2; ar[7] = 2.0  # a[3,2] = 2
		ia[8] = 2; ja[8] = 3; ar[8] = 5.0  # a[2,3] = 5
		ia[9] = 3; ja[9] = 3; ar[9] = 6.0  # a[3,3] = 6

		glp.glp_load_matrix(lp, 9, ia, ja, ar)
		glp.glp_simplex(lp, smcp)

		Z = glp.glp_get_obj_val(lp)
		x1 = glp.glp_get_col_prim(lp, 1)
		x2 = glp.glp_get_col_prim(lp, 2)
		x3 = glp.glp_get_col_prim(lp, 3)

		self.assertAlmostEqual(Z, 733.3333, 4)
		self.assertAlmostEqual(x1, 33.3333, 4)
		self.assertAlmostEqual(x2, 66.6667, 4)
		self.assertAlmostEqual(x3, 0)

		glp.glp_delete_prob(lp)
Exemple #4
0
def set_coefficients(lp, C):
    elements_count = np.count_nonzero(C)
    i_C = glpk.intArray(1 + elements_count)
    j_C = glpk.intArray(1 + elements_count)
    a_C = glpk.doubleArray(1 + elements_count)

    for idx, (i, j) in enumerate(zip(*C.nonzero()), 1):
        i_C[idx] = int(i + 1)
        j_C[idx] = int(j + 1)
        a_C[idx] = float(C[i, j])

    glpk.glp_load_matrix(lp, elements_count, i_C, j_C, a_C)
    def get_row(self, row):
        '''get a row of the LP matrix as a csr_matrix
        '''

        lp_rows = self.get_num_rows()
        lp_cols = self.get_num_cols()

        assert 0 <= row < lp_rows

        inds_row = glpk.intArray(lp_cols + 1)
        vals_row = glpk.doubleArray(lp_cols + 1)

        got_len = glpk.glp_get_mat_row(self.lp, row+1, inds_row, vals_row)

        data = np.zeros((got_len,), dtype=float)
        inds = np.zeros((got_len,), dtype=np.int32)
        data_index = 0

        for i in range(1, got_len + 1):
            data[data_index] = vals_row[i]
            inds[data_index] = inds_row[i] - 1
            data_index += 1

        indptr = [0, data_index]
        csr_mat = csr_matrix((data, inds, indptr), shape=(1, lp_cols), dtype=float)
        csr_mat.check_format()

        return csr_mat
Exemple #6
0
    def get_full_constraints(self):
        '''get the LP matrix as a csr_matrix
        '''

        lp_rows = self.get_num_rows()
        lp_cols = self.get_num_cols()
        nnz = glpk.glp_get_num_nz(self.lp)

        data = np.zeros((nnz, ), dtype=float)
        inds = np.zeros((nnz, ), dtype=np.int32)
        indptr = np.zeros((lp_rows + 1, ), dtype=np.int32)

        inds_row = glpk.intArray(lp_cols + 1)
        vals_row = glpk.doubleArray(lp_cols + 1)
        data_index = 0
        indptr[0] = 0

        for row in range(1, lp_rows + 1):
            got_len = glpk.glp_get_mat_row(self.lp, row, inds_row, vals_row)

            for i in range(1, got_len + 1):
                data[data_index] = vals_row[i]
                inds[data_index] = inds_row[i] - 1
                data_index += 1

            indptr[row] = data_index

        csr_mat = csr_matrix((data, inds, indptr),
                             shape=(lp_rows, lp_cols),
                             dtype=float)
        csr_mat.check_format()

        return csr_mat
 def _remove_constraints(self, constraints):
     if len(constraints) > 0:
         constraint_indices = [constraint.index for constraint in constraints]
         super(Model, self)._remove_constraints(constraints)
         num = intArray(len(constraints) + 1)
         for i, constraint_index in enumerate(constraint_indices):
             num[i + 1] = constraint_index
         glp_del_rows(self.problem, len(constraints), num)
Exemple #8
0
 def _remove_constraints(self, constraints):
     if len(constraints) > 0:
         constraint_indices = [constraint._index for constraint in constraints]
         super(Model, self)._remove_constraints(constraints)
         num = intArray(len(constraints) + 1)
         for i, constraint_index in enumerate(constraint_indices):
             num[i + 1] = constraint_index
         glp_del_rows(self.problem, len(constraints), num)
Exemple #9
0
    def get_int_array(cls, size):
        'get a int array of the requested size (or greater)'

        if size > cls.int_array_size:
            cls.int_array_size = 2**math.ceil(math.log(
                size, 2))  # allocate in multiples of two
            cls.int_array = glpk.intArray(cls.int_array_size)

            #print(f"allocated int array of size {cls.int_array_size} (requested {size})")

        return cls.int_array
 def test_set_linear_coefficients_constraint(self):
     constraint = self.model.constraints.M_atp_c
     constraint.set_linear_coefficients({self.model.variables.R_Biomass_Ecoli_core_w_GAM: 666.})
     num_cols = glp_get_num_cols(self.model.problem)
     ia = intArray(num_cols + 1)
     da = doubleArray(num_cols + 1)
     index = constraint._index
     num = glp_get_mat_row(self.model.problem, index, ia, da)
     for i in range(1, num + 1):
         col_name = glp_get_col_name(self.model.problem, ia[i])
         if col_name == 'R_Biomass_Ecoli_core_w_GAM':
             self.assertEqual(da[i], 666.)
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self.index, ia, da)
         constraint_variables = [self.problem._variables[glp_get_col_name(self.problem.problem, ia[i])] for i in
                                 range(1, nnz + 1)]
         expression = sympy.Add._from_args(
             [sympy.Mul._from_args((sympy.RealNumber(da[i]), constraint_variables[i - 1])) for i in
              range(1, nnz + 1)])
         self._expression = expression
     return self._expression
 def test_set_linear_coefficients_constraint(self):
     constraint = self.model.constraints.M_atp_c
     constraint.set_linear_coefficients(
         {self.model.variables.R_Biomass_Ecoli_core_w_GAM: 666.})
     num_cols = glp_get_num_cols(self.model.problem)
     ia = intArray(num_cols + 1)
     da = doubleArray(num_cols + 1)
     index = constraint._index
     num = glp_get_mat_row(self.model.problem, index, ia, da)
     for i in range(1, num + 1):
         col_name = glp_get_col_name(self.model.problem, ia[i])
         if col_name == 'R_Biomass_Ecoli_core_w_GAM':
             self.assertEqual(da[i], 666.)
Exemple #13
0
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         constraint_variables = [self.problem._variables[glp_get_col_name(self.problem.problem, ia[i])] for i in
                                 range(1, nnz + 1)]
         expression = symbolics.add(
             [symbolics.mul((symbolics.Real(da[i]), constraint_variables[i - 1])) for i in
              range(1, nnz + 1)])
         self._expression = expression
     return self._expression
Exemple #14
0
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         constraint_variables = [self.problem._variables[glp_get_col_name(self.problem.problem, ia[i])] for i in
                                 range(1, nnz + 1)]
         expression = symbolics.add(
             [symbolics.mul((symbolics.Real(da[i]), constraint_variables[i - 1])) for i in
              range(1, nnz + 1)])
         self._expression = expression
     return self._expression
Exemple #15
0
    def get_sequential_int_array(cls, size):
        'creates or returns a swig int array that counts from 1, 2, 3, 4, .. size'

        if size > (cls.seq_array_size - 1):
            cls.seq_array_size = 1 + 2**math.ceil(math.log(
                size, 2))  # allocate in multiples of two
            cls.seq_array = glpk.intArray(cls.seq_array_size)

            #print(f"allocated seq array of size {cls.seq_array_size} (requested {size})")

            for i in range(cls.seq_array_size):
                cls.seq_array[i] = i

        return cls.seq_array
Exemple #16
0
def _toIndexArray(array):
    """Convert an array to a GLPK IntArray of indexes: Convert the indexes to
	int, add 1 to each, and prepend a dummy value.
	"""
    # TODO(Jerry): IF this is a performance issue, try caching the array, or
    # calling glp.as_intArray(list) to quickly convert a list of int (it
    # prepends 1 uninitialized element but we still need to add 1 to each
    # element), or making an ndarray(dtype=int32) and using NumPy to add 1 to
    # each element and then calling glp.intArray_frompointer(ndarray.data).
    ia = glp.intArray(len(array) + 1)
    ia[0] = -1
    for (i, value) in enumerate(array):
        ia[i + 1] = int(value) + 1
    return ia
Exemple #17
0
 def get_linear_coefficients(self, variables):
     if self.problem is not None:
         num_cols = glp_get_num_cols(self.problem.problem)
         ia = intArray(num_cols + 1)
         da = doubleArray(num_cols + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         return {
             self.problem._variables[ia[i + 1] - 1]: da[i + 1]
             for i in range(nnz)
         }
     else:
         raise Exception(
             "Can't get coefficients from solver if constraint is not in a model"
         )
Exemple #18
0
 def get_linear_coefficients(self, variables):
     if self.problem is not None:
         self.problem.update()
         num_cols = glp_get_num_cols(self.problem.problem)
         ia = intArray(num_cols + 1)
         da = doubleArray(num_cols + 1)
         nnz = glp_get_mat_row(self.problem.problem, self._index, ia, da)
         coefs = dict.fromkeys(variables, 0.0)
         coefs.update({
             self.problem._variables[ia[i + 1] - 1]: da[i + 1]
             for i in range(nnz)
             if self.problem._variables[ia[i + 1] - 1] in variables})
         return coefs
     else:
         raise Exception("Can't get coefficients from solver if constraint is not in a model")
 def _add_constraints(self, constraints, sloppy=False):
     super(Model, self)._add_constraints(constraints, sloppy=sloppy)
     for constraint in constraints:
         constraint._problem = None  # This needs to be dones in order to not trigger constraint._get_expression()
         glp_add_rows(self.problem, 1)
         index = glp_get_num_rows(self.problem)
         glp_set_row_name(self.problem, index, str(constraint.name))
         num_cols = glp_get_num_cols(self.problem)
         index_array = intArray(num_cols + 1)
         value_array = doubleArray(num_cols + 1)
         num_vars = 0  # constraint.variables is too expensive for large problems
         if constraint.expression.is_Atom and constraint.expression.is_Symbol:
             var = constraint.expression
             index_array[1] = var.index
             value_array[1] = 1
             num_vars += 1
         elif constraint.expression.is_Mul:
             args = constraint.expression.args
             if len(args) > 2:
                 raise Exception(
                     "Term(s) %s from constraint %s is not a proper linear term." % (args, constraint))
             coeff = float(args[0])
             var = args[1]
             index_array[1] = var.index
             value_array[1] = coeff
             num_vars += 1
         else:
             for i, term in enumerate(constraint.expression.args):
                 args = term.args
                 if args == ():
                     assert term.is_Symbol
                     coeff = 1
                     var = term
                 elif len(args) == 2:
                     assert args[0].is_Number
                     assert args[1].is_Symbol
                     var = args[1]
                     coeff = float(args[0])
                 elif len(args) > 2:
                     raise Exception(
                         "Term %s from constraint %s is not a proper linear term." % (term, constraint))
                 index_array[i + 1] = var.index
                 value_array[i + 1] = coeff
                 num_vars += 1
         glp_set_mat_row(self.problem, index, num_vars,
                         index_array, value_array)
         constraint._problem = self
         self._glpk_set_row_bounds(constraint)
Exemple #20
0
 def _get_expression(self):
     if self.problem is not None:
         col_num = glp_get_num_cols(self.problem.problem)
         ia = intArray(col_num + 1)
         da = doubleArray(col_num + 1)
         nnz = glp_get_mat_row(self.problem.problem, self.index, ia, da)
         constraint_variables = [
             self.problem._variables[glp_get_col_name(
                 self.problem.problem, ia[i])] for i in range(1, nnz + 1)
         ]
         expression = sympy.Add._from_args([
             sympy.Mul._from_args(
                 (sympy.RealNumber(da[i]), constraint_variables[i - 1]))
             for i in range(1, nnz + 1)
         ])
         self._expression = expression
     return self._expression
Exemple #21
0
    def _remove_variables(self, variables):
        if len(variables) > 0:
            if len(variables) > 350:
                delete_indices = [variable._index - 1 for variable in variables]
                keep_indices = [i for i in range(0, len(self._variables)) if i not in delete_indices]
                self._variables = self._variables.fromkeys(keep_indices)
            else:
                for variable in variables:
                    del self._variables[variable.name]

            num = intArray(len(variables) + 1)
            for i, variable in enumerate(variables):
                num[i + 1] = variable._index
            glp_del_cols(self.problem, len(variables), num)

            for variable in variables:
                del self._variables_to_constraints_mapping[variable.name]
                variable.problem = None
    def _remove_variables(self, variables):
        if len(variables) > 0:
            if len(variables) > 350:
                delete_indices = [variable.index - 1 for variable in variables]
                keep_indices = [i for i in range(0, len(self.variables)) if i not in delete_indices]
                self._variables = self.variables.fromkeys(keep_indices)
            else:
                for variable in variables:
                    del self._variables[variable.name]

            num = intArray(len(variables) + 1)
            for i, variable in enumerate(variables):
                num[i + 1] = variable.index
            glp_del_cols(self.problem, len(variables), num)

            for variable in variables:
                del self._variables_to_constraints_mapping[variable.name]
                variable.problem = None
Exemple #23
0
def setup_col(
    problem: SwigPyObject,
    j: int,
    recipe: 'Recipe',
    resource_indices: Dict[str, int],
    min_clock: Optional[int] = None,
    fixed_clock: Optional[int] = None,
):
    lp.glp_set_col_name(problem, j, recipe.name)

    # The game's clock scaling resolution is one percentage point, so we
    # ask for integers with an implicit scale of 100
    lp.glp_set_col_kind(problem, j, lp.GLP_IV)

    # All recipes are currently weighed the same
    lp.glp_set_obj_coef(problem, j, 1)

    if fixed_clock is None:
        # All recipes must have at least 0 instances
        lp.glp_set_col_bnds(
            problem,
            j,
            lp.GLP_LO,
            min_clock or 0,
            float('inf'),  # Lower and upper boundaries
        )
    else:
        # Set our desired (fixed) outputs
        lp.glp_set_col_bnds(
            problem,
            j,
            lp.GLP_FX,
            fixed_clock,
            fixed_clock,  # Boundaries are equal (variable is fixed)
        )

    # The constraint coefficients are just the recipe rates
    n_sparse = len(recipe.rates)
    ind = lp.intArray(n_sparse + 1)
    val = lp.doubleArray(n_sparse + 1)
    for i, (resource, rate) in enumerate(recipe.rates.items(), 1):
        ind[i] = resource_indices[resource]
        val[i] = rate
    lp.glp_set_mat_col(problem, j, n_sparse, ind, val)
 def _set_coefficients_low_level(self, variables_coefficients_dict):
     if self.problem is not None:
         problem = self.problem.problem
         indices_coefficients_dict = dict(
             [(variable.index, coefficient) for variable, coefficient in six.iteritems(variables_coefficients_dict)])
         num_cols = glp_get_num_cols(problem)
         ia = intArray(num_cols + 1)
         da = doubleArray(num_cols + 1)
         index = self.index
         num = glp_get_mat_row(self.problem.problem, index, ia, da)
         for i in range(1, num + 1):
             try:
                 da[i] = indices_coefficients_dict[ia[i]]
             except KeyError:
                 pass
         glp_set_mat_row(self.problem.problem, index, num, ia, da)
     else:
         raise Exception(
             '_set_coefficients_low_level works only if a constraint is associated with a solver instance.')
Exemple #25
0
    def _add_constraints(self, relation):
        """Add the given relation as one or more constraints.

        Return a list of the names of the constraints added.
        """

        expression = relation.expression
        constr_count = sum(True for _ in expression.value_sets())
        if constr_count == 0:
            return []

        row_indices = count(swiglpk.glp_add_rows(self._p, constr_count))

        names = []
        for i, value_set in zip(row_indices, expression.value_sets()):
            value_set = list(value_set)
            var_indices = swiglpk.intArray(1 + len(value_set))
            var_values = swiglpk.doubleArray(1 + len(value_set))
            for j, (variable, coeff) in enumerate(value_set):
                var_indices[1 + j] = self._variables[variable]
                var_values[1 + j] = float(coeff)

            swiglpk.glp_set_mat_row(self._p, i, len(value_set), var_indices,
                                    var_values)

            if relation.sense == RelationSense.Greater:
                swiglpk.glp_set_row_bnds(self._p, i, swiglpk.GLP_LO,
                                         -float(expression.offset), 0)
            elif relation.sense == RelationSense.Less:
                swiglpk.glp_set_row_bnds(self._p, i, swiglpk.GLP_UP, 0,
                                         -float(expression.offset))
            else:
                swiglpk.glp_set_row_bnds(self._p, i, swiglpk.GLP_FX,
                                         -float(expression.offset), 0)

            names.append(i)

        self._do_presolve = True

        return names
Exemple #26
0
    def _add_constraints(self, relation):
        """Add the given relation as one or more constraints.

        Return a list of the names of the constraints added.
        """

        expression = relation.expression
        constr_count = sum(True for _ in expression.value_sets())
        if constr_count == 0:
            return []

        row_indices = count(swiglpk.glp_add_rows(self._p, constr_count))

        names = []
        for i, value_set in zip(row_indices, expression.value_sets()):
            value_set = list(value_set)
            var_indices = swiglpk.intArray(1 + len(value_set))
            var_values = swiglpk.doubleArray(1 + len(value_set))
            for j, (variable, coeff) in enumerate(value_set):
                var_indices[1 + j] = self._variables[variable]
                var_values[1 + j] = float(coeff)

            swiglpk.glp_set_mat_row(
                self._p, i, len(value_set), var_indices, var_values)

            if relation.sense == RelationSense.Greater:
                swiglpk.glp_set_row_bnds(
                    self._p, i, swiglpk.GLP_LO, -float(expression.offset), 0)
            elif relation.sense == RelationSense.Less:
                swiglpk.glp_set_row_bnds(
                    self._p, i, swiglpk.GLP_UP, 0, -float(expression.offset))
            else:
                swiglpk.glp_set_row_bnds(
                    self._p, i, swiglpk.GLP_FX, -float(expression.offset), 0)

            names.append(i)

        self._do_presolve = True

        return names
Exemple #27
0
    def _add_constraints(self, constraints, sloppy=False):
        super(Model, self)._add_constraints(constraints, sloppy=sloppy)
        for constraint in constraints:
            constraint._problem = None  # This needs to be done in order to not trigger constraint._get_expression()
            glp_add_rows(self.problem, 1)
            index = glp_get_num_rows(self.problem)
            glp_set_row_name(self.problem, index, str(constraint.name))
            num_cols = glp_get_num_cols(self.problem)
            index_array = intArray(num_cols + 1)
            value_array = doubleArray(num_cols + 1)
            num_vars = 0  # constraint.variables is too expensive for large problems

            offset, coef_dict, _ = parse_optimization_expression(constraint, linear=True)

            num_vars = len(coef_dict)
            for i, (var, coef) in enumerate(coef_dict.items()):
                index_array[i + 1] = var._index
                value_array[i + 1] = float(coef)

            glp_set_mat_row(self.problem, index, num_vars,
                            index_array, value_array)
            constraint._problem = self
            self._glpk_set_row_bounds(constraint)
    def _add_constraints(self, constraints, sloppy=False):
        super(Model, self)._add_constraints(constraints, sloppy=sloppy)
        for constraint in constraints:
            constraint._problem = None  # This needs to be done in order to not trigger constraint._get_expression()
            glp_add_rows(self.problem, 1)
            index = glp_get_num_rows(self.problem)
            glp_set_row_name(self.problem, index, str(constraint.name))
            num_cols = glp_get_num_cols(self.problem)
            index_array = intArray(num_cols + 1)
            value_array = doubleArray(num_cols + 1)
            num_vars = 0  # constraint.variables is too expensive for large problems

            coef_dict, _ = parse_optimization_expression(constraint, linear=True)

            num_vars = len(coef_dict)
            for i, (var, coef) in enumerate(coef_dict.items()):
                index_array[i + 1] = var._index
                value_array[i + 1] = float(coef)

            glp_set_mat_row(self.problem, index, num_vars,
                            index_array, value_array)
            constraint._problem = self
            self._glpk_set_row_bounds(constraint)
Exemple #29
0
    def get_dense_constraints(self, x, y, w, h):
        'get a subconstraint matrix from the lpi as a dense matrix'

        rv = np.zeros((h, w))

        lp_rows = self.get_num_rows()
        lp_cols = self.get_num_cols()

        assert x >= 0 and w >= 0 and x + w <= lp_cols, "invalid x range requested"
        assert y >= 0 and h >= 0 and y + h <= lp_rows, "invalid y range requested"

        inds_row = glpk.intArray(lp_cols + 1)
        vals_row = glpk.doubleArray(lp_cols + 1)

        for row in range(y + 1, y + h + 1):
            row_offset = row - (y + 1)
            got_len = glpk.glp_get_mat_row(self.lp, row, inds_row, vals_row)

            for i in range(1, got_len + 1):
                if inds_row[i] > x and inds_row[i] <= x + w:
                    col_offset = inds_row[i] - (x + 1)
                    rv[row_offset, col_offset] = vals_row[i]

        return rv
Exemple #30
0
    def _constraints_str(self, bm_print, input_print, zero_print):
        'get the constraints matrix lines for __str__'

        rv = ""
        lp = self.lp
        rows = self.get_num_rows()
        cols = self.get_num_cols()
        
        stat_labels = ["?(0)?", "BS", "NL", "NU", "NF", "NS", "?(6)?"]
        inds = glpk.intArray(cols + 1)
        vals = glpk.doubleArray(cols + 1)

        for row in range(1, rows + 1):
            rv += "{:2}: {} ".format(row-1, stat_labels[glpk.glp_get_row_stat(lp, row)])

            num_inds = glpk.glp_get_mat_row(lp, row, inds, vals)

            for col in range(1, cols + 1):
                val = 0

                for index in range(1, num_inds+1):
                    if inds[index] == col:
                        val = vals[index]
                        break

                num = str(val)
                if len(num) < 6:
                    num = (" " * (6 - len(num))) + num
                else:
                    num = num[0:6]

                if self.basis_mat_pos[0] <= row - 1 < self.basis_mat_pos[0] + self.dims and \
                        self.basis_mat_pos[1] <= col - 1 < self.basis_mat_pos[1] + self.dims:
                    rv += bm_print(num) + " "
                elif self.input_effects_offsets is not None and \
                        self.input_effects_offsets[0] <= row - 1 < self.input_effects_offsets[0] + self.dims and \
                        self.input_effects_offsets[1] <= col - 1 < self.input_effects_offsets[1] + self.dims:
                    rv += input_print(num) + " "
                else:
                    rv += (zero_print(num) if val == 0 else num) + " "

            row_type = glpk.glp_get_row_type(lp, row)

            if row_type == glpk.GLP_FX:
                val = glpk.glp_get_row_ub(lp, row)
                rv += " == "
            elif row_type == glpk.GLP_UP:
                val = glpk.glp_get_row_ub(lp, row)
                rv += " <= "
            elif row_type == glpk.GLP_LO:
                val = glpk.glp_get_row_lb(lp, row)
                rv += " >= "
            else:
                rv += " <?> (unknown bounds)"
                val = '?'

            num = str(val)
            if len(num) < 6:
                num = (" " * (6 - len(num))) + num
            else:
                num = num[0:6]

            rv += (zero_print(num) if val == 0 else num) + " "

            rv += "\n"

        return rv
    def __init__(self, problem=None, *args, **kwargs):

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

        self.configuration = Configuration()

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

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

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

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

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

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

            term_generator = (
                (glp_get_obj_coef(self.problem, index), variables[index - 1])
                for index in range(1, glp_get_num_cols(problem) + 1)
            )
            self._objective = Objective(
                _unevaluated_Add(
                    *[_unevaluated_Mul(sympy.RealNumber(term[0]), term[1]) for term in term_generator if
                      term[0] != 0.]),
                problem=self,
                direction={GLP_MIN: 'min', GLP_MAX: 'max'}[glp_get_obj_dir(self.problem)])
        glp_scale_prob(self.problem, GLP_SF_AUTO)
Exemple #32
0
    def _initialize_model_from_problem(self, problem):
        try:
            self.problem = problem
            glp_create_index(self.problem)
        except TypeError:
            raise TypeError("Provided problem is not a valid GLPK model.")
        row_num = glp_get_num_rows(self.problem)
        col_num = glp_get_num_cols(self.problem)
        for i in range(1, col_num + 1):
            var = Variable(
                glp_get_col_name(self.problem, i),
                lb=glp_get_col_lb(self.problem, i),
                ub=glp_get_col_ub(self.problem, i),
                problem=self,
                type=_GLPK_VTYPE_TO_VTYPE[
                    glp_get_col_kind(self.problem, i)]
            )
            # This avoids adding the variable to the glpk problem
            super(Model, self)._add_variables([var])
        variables = self.variables

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

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

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

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

        term_generator = (
            (glp_get_obj_coef(self.problem, index), variables[index - 1])
            for index in range(1, glp_get_num_cols(problem) + 1)
        )
        self._objective = Objective(
            symbolics.add(
                [symbolics.mul((symbolics.Real(term[0]), term[1])) for term in term_generator if
                 term[0] != 0.]
            ),
            problem=self,
            direction={GLP_MIN: 'min', GLP_MAX: 'max'}[glp_get_obj_dir(self.problem)])
        glp_scale_prob(self.problem, GLP_SF_AUTO)
Exemple #33
0
    def _constraints_str(self, bm_print, input_print, zero_print):
        'get the constraints matrix lines for __str__'

        rv = ""
        lp = self.lp
        rows = self.get_num_rows()
        cols = self.get_num_cols()

        stat_labels = ["?(0)?", "BS", "NL", "NU", "NF", "NS"]
        inds = glpk.intArray(cols + 1)
        vals = glpk.doubleArray(cols + 1)

        for row in range(1, rows + 1):
            stat = glpk.glp_get_row_stat(lp, row)
            assert 0 <= stat <= len(stat_labels)
            rv += "{:2}: {} ".format(row, stat_labels[stat])

            num_inds = glpk.glp_get_mat_row(lp, row, inds, vals)

            for col in range(1, cols + 1):
                val = 0

                for index in range(1, num_inds + 1):
                    if inds[index] == col:
                        val = vals[index]
                        break

                num = str(val)
                if len(num) < 6:
                    num = (" " * (6 - len(num))) + num
                else:
                    num = num[0:6]

                if self.basis_mat_rect[1] <= row - 1 < self.basis_mat_rect[0] + self.basis_mat_rect[3] and \
                        self.basis_mat_rect[0] <= col - 1 < self.basis_mat_rect[1] + self.basis_mat_rect[2]:
                    rv += bm_print(num) + " "
                else:
                    rv += (zero_print(num) if val == 0 else num) + " "

            row_type = glpk.glp_get_row_type(lp, row)

            if row_type == glpk.GLP_FX:
                val = glpk.glp_get_row_ub(lp, row)
                rv += " == "
            else:
                assert row_type == glpk.GLP_UP

                val = glpk.glp_get_row_ub(lp, row)
                rv += " <= "

            num = str(val)
            if len(num) < 6:
                num = (" " * (6 - len(num))) + num
            else:
                num = num[0:6]

            rv += (zero_print(num) if val == 0 else num) + " "

            rv += "\n"

        return rv
Exemple #34
0
def solve(nutrition_target, foods):
    '''
    Calculate food amounts to reach the nutrition target
    
    Parameters
    ----------
    nutrition_target : soylent_recipes.nutrition_target.NormalizedNutritionTarget
        The desired nutrition
    foods : np.array
        The foods to use to achieve the nutrition target. Contains exactly the
        nutrients required by the nutrition target in the exact same order. Rows
        represent foods, columns represent nutrients.
        
    Returns
    -------
    amounts : np.array(int) or None
        The amounts of each food to use to optimally achieve the nutrition
        target. ``amounts[i]`` is the amount of the i-th food to use. If the
        nutrition target cannot be achieved, returns None.
    '''
    # Implementation: using the GLPK C library via ecyglpki Python library binding
    # GLPK documentation: download it and look inside the package (http://ftp.gnu.org/gnu/glpk/)
    # GLPK wikibook: https://en.wikibooks.org/wiki/GLPK
    #
    # GPLK lingo: rows and columns refer to Ax=b where b_i are auxiliary
    # variables, x_i are structural variables. Setting constraints on rows, set
    # constraints on b_i, while column constraints are applied to x_i.
    
    # Note: glpk is powerful. We're using mostly the default settings.
    # Performance likely can be improved by tinkering with the settings; or even
    # by providing the solution to the least squares equivalent, with amounts
    # rounded afterwards, as starting point could improve performance.
    
    nutrition_target = nutrition_target.values
    
    problem = glp.glp_create_prob()
    try:
        glp.glp_add_rows(problem, len(nutrition_target))
        glp.glp_add_cols(problem, len(foods))
        
        # Configure columns/amounts
        for i in range(len(foods)):
            glp.glp_set_col_kind(problem, i+1, glp.GLP_IV)  # int
            glp.glp_set_col_bnds(problem, i+1, glp.GLP_LO, 0.0, np.nan)  # >=0
        
        # Configure rows/nutrients
        for i, extrema in enumerate(nutrition_target):
            if np.isnan(extrema[0]):
                bounds_type = glp.GLP_UP
            elif np.isnan(extrema[1]):
                bounds_type = glp.GLP_LO
            else:
                # Note: a nutrition target has either min, max or both and min!=max
                bounds_type = glp.GLP_DB
            glp.glp_set_row_bnds(problem, i+1, bounds_type, *extrema)
            
        # Load A of our Ax=b
        non_zero_count = foods.size
        row_indices = glp.intArray(non_zero_count+1)  # +1 because (insane) 1-indexing
        column_indices = glp.intArray(non_zero_count+1)
        values = glp.doubleArray(non_zero_count+1)
        for i, ((row, column), value) in enumerate(np.ndenumerate(foods.transpose())):
            row_indices[i+1] = row+1
            column_indices[i+1] = column+1
            values[i+1] = value
        glp.glp_load_matrix(problem, non_zero_count, row_indices, column_indices, values)
        
        # Solve
        int_opt_args = glp.glp_iocp()
        glp.glp_init_iocp(int_opt_args)
        int_opt_args.presolve = glp.GLP_ON  # without this, you have to provide an LP relaxation basis
        int_opt_args.msg_lev = glp.GLP_MSG_OFF  # be quiet, no stdout
        glp.glp_intopt(problem, int_opt_args)  # returns an error code; can safely ignore
        
        # Check we've got a valid solution
        #
        # Note: glp_intopt returns whether the algorithm completed successfully.
        # This does not imply you've got a good solution, it could even be
        # infeasible. glp_mip_status returns whether the solution is optimal,
        # feasible, infeasible or undefined. An optimal/feasible solution is not
        # necessarily a good solution. An optimal solution may even violate
        # bounds constraints. The thing you actually need to use is
        # glp_check_kkt and check that the solution satisfies KKT.PB (all within
        # bounds)
        max_error = glp.doubleArray(1)
        glp.glp_check_kkt(problem, glp.GLP_MIP, glp.GLP_KKT_PB, max_error, None, None, None)
        if not np.isclose(max_error[0], 0.0):
            # A row/column value exceeds its bounds
            return None
        
        # Return solution
        amounts = np.fromiter((glp.glp_mip_col_val(problem, i+1) for i in range(len(foods))), int)
        
        return amounts
    finally:
        glp.glp_delete_prob(problem)
    def test_add_constraints(self):
        x = self.interface.Variable('x', lb=0, ub=1, type='binary')
        y = self.interface.Variable('y', lb=-181133.3, ub=12000., type='continuous')
        z = self.interface.Variable('z', lb=0., ub=10., type='integer')
        constr1 = self.interface.Constraint(0.3 * x + 0.4 * y + 66. * z, lb=-100, ub=0., name='test')
        constr2 = self.interface.Constraint(2.333 * x + y + 3.333, ub=100.33, name='test2')
        constr3 = self.interface.Constraint(2.333 * x + y + z, lb=-300)
        constr4 = self.interface.Constraint(x, lb=-300, ub=-300)
        constr5 = self.interface.Constraint(3 * x)
        self.model.add(constr1)
        self.model.add(constr2)
        self.model.add(constr3)
        self.model.add([constr4, constr5])
        self.assertIn(constr1.name, self.model.constraints)
        self.assertIn(constr2.name, self.model.constraints)
        self.assertIn(constr3.name, self.model.constraints)
        self.assertIn(constr4.name, self.model.constraints)
        self.assertIn(constr5.name, self.model.constraints)
        # constr1
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr1._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 0.3, 'y': 0.4, 'z': 66.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr1._index), GLP_DB)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr1._index), -100)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr1._index), 0)
        # constr2
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr2._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 2.333, 'y': 1.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr2._index), GLP_UP)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr2._index), -1.7976931348623157e+308)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr2._index), 96.997)
        # constr3
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr3._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 2.333, 'y': 1., 'z': 1.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr3._index), GLP_LO)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr3._index), -300)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr3._index), 1.7976931348623157e+308)
        # constr4
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr4._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 1})
        self.assertEqual(glp_get_row_type(self.model.problem, constr4._index), GLP_FX)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr4._index), -300)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr4._index), -300)

        # constr5
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr5._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 3})
        self.assertEqual(glp_get_row_type(self.model.problem, constr5._index), GLP_FR)
        self.assertLess(glp_get_row_lb(self.model.problem, constr5._index), -1e30)
        self.assertGreater(glp_get_row_ub(self.model.problem, constr5._index), 1e30)
    def test_add_constraints(self):
        x = Variable('x', lb=0, ub=1, type='binary')
        y = Variable('y', lb=-181133.3, ub=12000., type='continuous')
        z = Variable('z', lb=0., ub=10., type='integer')
        constr1 = Constraint(0.3 * x + 0.4 * y + 66. * z,
                             lb=-100,
                             ub=0.,
                             name='test')
        constr2 = Constraint(2.333 * x + y + 3.333, ub=100.33, name='test2')
        constr3 = Constraint(2.333 * x + y + z, lb=-300)
        constr4 = Constraint(x, lb=-300, ub=-300)
        constr5 = Constraint(3 * x)
        self.model.add(constr1)
        self.model.add(constr2)
        self.model.add(constr3)
        self.model.add([constr4, constr5])
        self.assertIn(constr1.name, self.model.constraints)
        self.assertIn(constr2.name, self.model.constraints)
        self.assertIn(constr3.name, self.model.constraints)
        self.assertIn(constr4.name, self.model.constraints)
        self.assertIn(constr5.name, self.model.constraints)
        # constr1
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr1._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 0.3, 'y': 0.4, 'z': 66.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr1._index),
                         GLP_DB)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr1._index),
                         -100)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr1._index), 0)
        # constr2
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr2._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 2.333, 'y': 1.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr2._index),
                         GLP_UP)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr2._index),
                         -1.7976931348623157e+308)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr2._index),
                         96.997)
        # constr3
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr3._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 2.333, 'y': 1., 'z': 1.})
        self.assertEqual(glp_get_row_type(self.model.problem, constr3._index),
                         GLP_LO)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr3._index),
                         -300)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr3._index),
                         1.7976931348623157e+308)
        # constr4
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr4._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 1})
        self.assertEqual(glp_get_row_type(self.model.problem, constr4._index),
                         GLP_FX)
        self.assertEqual(glp_get_row_lb(self.model.problem, constr4._index),
                         -300)
        self.assertEqual(glp_get_row_ub(self.model.problem, constr4._index),
                         -300)

        # constr5
        ia = intArray(glp_get_num_rows(self.model.problem) + 1)
        da = doubleArray(glp_get_num_rows(self.model.problem) + 1)
        nnz = glp_get_mat_row(self.model.problem, constr5._index, ia, da)
        coeff_dict = dict()
        for i in range(1, nnz + 1):
            coeff_dict[glp_get_col_name(self.model.problem, ia[i])] = da[i]
        self.assertDictEqual(coeff_dict, {'x': 3})
        self.assertEqual(glp_get_row_type(self.model.problem, constr5._index),
                         GLP_FR)
        self.assertLess(glp_get_row_lb(self.model.problem, constr5._index),
                        -1e30)
        self.assertGreater(glp_get_row_ub(self.model.problem, constr5._index),
                           1e30)
Exemple #37
0
    def _import_problem(self):
        import swiglpk as glpk

        if self.verbosity() >= 1:
            glpk.glp_term_out(glpk.GLP_ON)
        else:
            glpk.glp_term_out(glpk.GLP_OFF)

        # Create a problem instance.
        p = self.int = glpk.glp_create_prob();

        # Set the objective.
        if self.ext.objective[0] in ("find", "min"):
            glpk.glp_set_obj_dir(p, glpk.GLP_MIN)
        elif self.ext.objective[0] is "max":
            glpk.glp_set_obj_dir(p, glpk.GLP_MAX)
        else:
            raise NotImplementedError("Objective '{0}' not supported by GLPK."
                .format(self.ext.objective[0]))

        # Set objective function shift
        if self.ext.objective[1] is not None \
        and self.ext.objective[1].constant is not None:
            if not isinstance(self.ext.objective[1], AffinExp):
                raise NotImplementedError("Non-linear objective function not "
                    "supported by GLPK.")

            if self.ext.objective[1].constant.size != (1,1):
                raise NotImplementedError("Non-scalar objective function not "
                    "supported by GLPK.")

            glpk.glp_set_obj_coef(p, 0, self.ext.objective[1].constant[0])

        # Add variables.
        # Multideminsional variables are split into multiple scalar variables
        # represented as matrix columns within GLPK.
        for varName in self.ext.varNames:
            var = self.ext.variables[varName]

            # Add a column for every scalar variable.
            numCols = var.size[0] * var.size[1]
            glpk.glp_add_cols(p, numCols)

            for localIndex, picosIndex \
            in enumerate(range(var.startIndex, var.endIndex)):
                glpkIndex = self._picos2glpk_variable_index(picosIndex)

                # Assign a name to the scalar variable.
                scalarName = varName
                if numCols > 1:
                    x = localIndex // var.size[0]
                    y = localIndex % var.size[0]
                    scalarName += "_{:d}_{:d}".format(x + 1, y + 1)
                glpk.glp_set_col_name(p, glpkIndex, scalarName)

                # Assign bounds to the scalar variable.
                lower, upper = var.bnd.get(localIndex, (None, None))
                if lower is not None and upper is not None:
                    if lower == upper:
                        glpk.glp_set_col_bnds(
                            p, glpkIndex, glpk.GLP_FX, lower, upper)
                    else:
                        glpk.glp_set_col_bnds(
                            p, glpkIndex, glpk.GLP_DB, lower, upper)
                elif lower is not None and upper is None:
                    glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_LO, lower, 0)
                elif lower is None and upper is not None:
                    glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_UP, 0, upper)
                else:
                    glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_FR, 0, 0)

                # Assign a type to the scalar variable.
                if var.vtype in ("continuous", "symmetric"):
                    glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_CV)
                elif var.vtype == "integer":
                    glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_IV)
                elif var.vtype == "binary":
                    glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_BV)
                else:
                    raise NotImplementedError("Variable type '{0}' not "
                        "supported by GLPK.".format(var.vtype()))

                # Set objective function coefficient of the scalar variable.
                if self.ext.objective[1] is not None \
                and var in self.ext.objective[1].factors:
                    glpk.glp_set_obj_coef(p, glpkIndex,
                        self.ext.objective[1].factors[var][localIndex])

        # Add constraints.
        # Multideminsional constraints are split into multiple scalar
        # constraints represented as matrix rows within GLPK.
        rowOffset = 1
        for constraintNum, constraint in enumerate(self.ext.constraints):
            if not isinstance(constraint, AffineConstraint):
                raise NotImplementedError(
                    "Non-linear constraints not supported by GLPK.")

            # Add a row for every scalar constraint.
            # Internally, GLPK uses an auxiliary variable for every such row,
            # bounded by the right hand side of the scalar constraint in a
            # canonical form.
            numRows = len(constraint)
            glpk.glp_add_rows(p, numRows)

            self._debug("Handling PICOS Constraint: " + str(constraint))

            # Split multidimensional constraints into multiple scalar ones.
            for localConIndex, (glpkVarIndices, coefficients, rhs) in \
                    enumerate(constraint.sparse_Ab_rows(
                    None, indexFunction = lambda picosVar, i:
                    self._picos2glpk_variable_index(picosVar.startIndex + i))):
                # Determine GLPK's row index of the scalar constraint.
                glpkConIndex = rowOffset + localConIndex
                numColumns   = len(glpkVarIndices)

                # Name the auxiliary variable associated with the current row.
                if constraint.name:
                    name = constraint.name
                else:
                    name = "rhs_{:d}".format(constraintNum)
                if numRows > 1:
                    x = localConIndex // constraint.size[0]
                    y = localConIndex % constraint.size[0]
                    name += "_{:d}_{:d}".format(x + 1, y + 1)
                glpk.glp_set_row_name(p, glpkConIndex, name)

                # Assign bounds to the auxiliary variable.
                if constraint.is_equality():
                    glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_FX, rhs,rhs)
                elif constraint.is_increasing():
                    glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_UP, 0, rhs)
                elif constraint.is_decreasing():
                    glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_LO, rhs, 0)
                else:
                    assert False, "Unexpected constraint relation."

                # Set coefficients for current row.
                # Note that GLPK requires a glpk.intArray containing column
                # indices and a glpk.doubleArray of same size containing the
                # coefficients for the listed column index. The first element
                # of both arrays (with index 0) is skipped by GLPK.
                glpkVarIndicesArray = glpk.intArray(numColumns + 1)
                for i in range(numColumns):
                    glpkVarIndicesArray[i + 1] = glpkVarIndices[i]

                coefficientsArray = glpk.doubleArray(numColumns + 1)
                for i in range(numColumns):
                    coefficientsArray[i + 1] = coefficients[i]

                glpk.glp_set_mat_row(p, glpkConIndex, numColumns,
                    glpkVarIndicesArray, coefficientsArray)

            rowOffset += numRows