Example #1
0
    def setFlowMaterialCoeff(self, flow, material, coefficient):
        if self._eqConstBuilt:
            if material not in self._materialIdxLookup:
                raise Exception("Invalid material")
            if flow not in self._flows:
                raise Exception("Invalid flow")
            materialIdx = self._materialIdxLookup[material]
            flowIdx = self._flows[flow]
            coeffs, flowIdxs = zip(*self._materialCoeffs[material])
            coeffs = list(coeffs)
            flowLoc = flowIdxs.index(flowIdx)
            coeffs[flowLoc] = coefficient
            self._materialCoeffs[material] = zip(coeffs, flowIdxs)

            rowIdx = int(materialIdx + 1)
            length = len(flowIdxs)
            if length != len(coeffs):
                raise ValueError("Array sizes must match")

            colIdxs = _toIndexArray(flowIdxs)
            data = _toDoubleArray(coeffs)
            glp.glp_set_mat_row(self._lp, rowIdx, length, colIdxs, data)
        else:
            idx = self._getVar(flow)
            self._materialCoeffs[material].append((coefficient, idx))

        self._solved = False
Example #2
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.")
Example #3
0
    def set_constraints_csr(self, data, glpk_indices, indptr, shape):
        '''
        set the constrains row by row to be equal to the passed-in csr matrix attribues

        glpk_indices is already offset by one
        '''

        Timers.tic('set_constraints_csr')
        assert shape[0] <= self.get_num_rows()
        assert shape[1] <= self.get_num_cols()

        # actually set the constraints row by row
        assert isinstance(data, list), "data was not a list"

        for row in range(shape[0]):
            # we must copy the indices since glpk is offset by 1 :(
            count = int(indptr[row + 1] - indptr[row])

            #indices_list = glpk_indices[indptr[row]:indptr[row+1]]
            #indices_vec = SwigArray.as_int_array(indices_list)
            indices_vec = SwigArray.as_int_array(
                glpk_indices[indptr[row]:indptr[row + 1]], count)

            #data_row_list = [float(d) for d in data[indptr[row]:indptr[row+1]]]
            #data_vec = SwigArray.as_double_array(data_row_list)
            data_vec = SwigArray.as_double_array(
                data[indptr[row]:indptr[row + 1]], count)

            glpk.glp_set_mat_row(self.lp, 1 + row, count, indices_vec,
                                 data_vec)

        Timers.toc('set_constraints_csr')
Example #4
0
    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.")
Example #5
0
    def set_constraints_swigvec_rows(self, data_vec_list, indices_vec_list, count_list, row_offset):
        '''An optimized / lower level way to set row constraints compared with set_constraints_csr

        The passed in fields are a list of swig data vector and indices vectors (one for each row), as
        well as a row offset.
        '''

        Timers.tic('set_constraints_swigvec_rows')

        for row, (data, indices, count) in enumerate(zip(data_vec_list, indices_vec_list, count_list)):
            glpk.glp_set_mat_row(self.lp, 1 + row_offset + row, count, indices, data)

        Timers.toc('set_constraints_swigvec_rows')
Example #6
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 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)
Example #7
0
    def set_constraints_csr(self, csr_mat, offset=None):
        '''set the constrains row by row to be equal to the passed-in csr matrix

        offset is an optional tuple (num_rows, num_cols) which tells you the top-left offset for the assignment
        '''

        assert isinstance(csr_mat, csr_matrix)
        assert csr_mat.dtype == float

        if offset is None:
            offset = (0, 0)

        assert len(
            offset) == 2, "offset should be a 2-tuple (num_rows, num_cols)"

        # check that the matrix is in bounds
        lp_rows = self.get_num_rows()
        lp_cols = self.get_num_cols()

        if offset[0] < 0 or offset[1] < 0 or \
                            offset[0] + csr_mat.shape[0] > lp_rows or offset[1] + csr_mat.shape[1] > lp_cols:
            raise RuntimeError("Error: set constraints matrix out of bounds (offset was " + \
                "{}, matrix size was {}), but lp size was ({}, {})".format(
                    offset, csr_mat.shape, lp_rows, lp_cols))

        # actually set the constraints row by row
        indptr = csr_mat.indptr
        indices = csr_mat.indices
        data_list = csr_mat.data.tolist()

        for row in range(csr_mat.shape[0]):
            # we must copy the indices since glpk is offset by 1 :(
            count = int(indptr[row + 1] - indptr[row])

            indices_list = [
                1 + offset[1] + int(indices[index])
                for index in range(indptr[row], indptr[row + 1])
            ]
            indices_vec = SwigArray.as_int_array(indices_list)

            data_row_list = data_list[indptr[row]:indptr[row + 1]]
            data_vec = SwigArray.as_double_array(data_row_list)

            glpk.glp_set_mat_row(self.lp, offset[0] + row + 1, count,
                                 indices_vec, data_vec)
Example #8
0
 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.')
Example #9
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
Example #10
0
File: glpk.py Project: jonls/psamm
    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
Example #11
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)
Example #12
0
    def add_dense_row(self, vec, rhs):
        '''
        add a row from a dense nd.array, row <= rhs
        '''

        Timers.tic('add_dense_row')

        assert isinstance(vec, np.ndarray)
        assert len(vec.shape) == 1 or vec.shape[0] == 1
        assert len(vec) == self.get_num_cols(
        ), f"vec had {len(vec)} values, but lpi has {self.get_num_cols()} cols"

        rows_before = self.get_num_rows()

        self.add_rows_less_equal([rhs])

        data_vec = SwigArray.as_double_array(vec, vec.size)
        indices_vec = SwigArray.get_sequential_int_array(vec.size)

        glpk.glp_set_mat_row(self.lp, rows_before + 1, vec.size, indices_vec,
                             data_vec)

        Timers.toc('add_dense_row')
Example #13
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

            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)
Example #14
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