예제 #1
0
    def quad_matrix_sum(self, matrix, dvars, symmetric=False):
        """
        Creates a quadratic expression equal to the quadratic form of a list of decision variables and
        a matrix of coefficients.

        This method sums all quadratic terms built by multiplying the [i,j]th coefficient in the matrix
        by the product of the i_th and j_th variables in `dvars`; in mathematical terms, the expression formed
        by x'Qx.

        :param matrix: A accepts either a list of lists of numbers, a numpy array, a pandas dataframe, or
            a scipy sparse matrix in COO format. T
            The resulting matrix must be square with size (N,N) where N is the number of variables.
        :param dvars: A list or an iterator on variables.
        :param symmetric: A boolean indicating whether the matrix is symmetric or not (default is False).
            No check is done.

        :return: An instance of :class:`docplex.mp.quad.QuadExpr` or 0.

        Note:
           The matrix must be square but not necessarily symmetric. The number of rows of the matrix must be equal
           to the size of the variable sequence.

           The symmetric flag only explores half of the matrix and doubles non-diagonal factors. No actual check is done.
           This flag has no effect on scipy sparse matrix.

        Example:
            `Model.quad_matrix_sum([[[1, 2], [3, 4]], [x, y])` returns the expression `x^2+4y^2+5x*yt`.
        """
        lvars = AdvModel._to_list(dvars, caller='Model.quad_matrix_sum')
        self._checker.typecheck_var_seq(lvars)
        if is_scipy_sparse(matrix):
            return self._aggregator._sparse_quad_matrix_sum(
                matrix, lvars, symmetric=symmetric)
        else:
            return self._aggregator.quad_matrix_sum(matrix,
                                                    lvars,
                                                    symmetric=symmetric)
예제 #2
0
    def matrix_ranges(self, coef_mat, dvars, lbs, ubs):
        """
        Creates a list of range constraints
        from a matrix of coefficients, a sequence of variables, and two sequence of numbers.

        This method returns the list of range constraints built from

            L <= Ax <= U

        where A is the coefficient matrix (of size (M,N)), X is the variable sequence (size N),
        L and B are sequence of numbers (resp. the lower and upper bounds of the ranges) both with size M.


        :param coef_mat: A matrix of coefficients with M rows and N columns. This argument accepts
            either a list of lists of numbers, a `numpy` array with size (M,N), or a `scipy` sparse matrix.
        :param dvars: An ordered sequence of decision variables: accepts a Python list, `numpy` array,
            or a `pandas` series. The size of the sequence must match the number of columns in the matrix.
        :param lbs: A sequence of numbers: accepts a Python list, a `numpy` array,
            or a `pandas` series. The size of the sequence must match the number of rows in the matrix.
        :param ubs: A sequence of numbers: accepts a Python list, a `numpy` array,
            or a `pandas` series. The size of the sequence must match the number of rows in the matrix.

        :returns: A list of range constraints.

        Example::

            If A is a matrix of coefficients with 2 rows and 3 columns:

                    A = [[1, 2, 3],
                         [4, 5, 6]],
                    X = [x, y, z] where x, y, and z are decision variables (size 3), and

                    L = [101. 102], a sequence of numbers (size 2),
                    U = [201, 202]

            then::

                `mdl.range_constraints(A, X, L, U)` returns a list of two ranges
                [(101 <= x + 2y+3z <= 102), (201 <= 4x + 5y +6z <= 202)].

        Note:
            If the dimensions of the matrix and variables or of the matrix and number sequence do not match,
            an error is raised.

        """
        checker = self._checker
        if is_pandas_dataframe(coef_mat) or is_numpy_matrix(
                coef_mat) or is_scipy_sparse(coef_mat):
            nb_rows, nb_cols = coef_mat.shape
        else:
            # a sequence of sequences
            a_mat = list(coef_mat)
            nb_rows = len(a_mat)
            nb_cols = None
            try:
                shared_len = None
                for r in a_mat:
                    checker.check_ordered_sequence(r, 'matrix_constraints')
                    r_len = len(r)
                    if shared_len is None:
                        shared_len = r_len
                    elif r_len != shared_len:
                        self.fatal(
                            'All columns should have same length found  {0} != {1}'
                            .format(shared_len, r_len))
                nb_cols = shared_len if shared_len is not None else 0
            except AttributeError:
                self.fatal('All columns should have a len()')

        s_dvars = self._to_list(dvars, caller='Model.range_constraints()')
        s_lbs = self._to_list(lbs, caller='Model.range_constraints()')
        s_ubs = self._to_list(ubs, caller='Model.range_constraints()')
        # check

        checker.typecheck_var_seq(s_dvars)
        checker.typecheck_num_seq(s_lbs)
        checker.typecheck_num_seq(s_ubs)

        # ---
        # check dimensions and whether to transpose or not.
        # ---
        nb_vars = len(s_dvars)
        nb_lbs = len(s_lbs)
        nb_ubs = len(s_ubs)
        if nb_lbs != nb_rows:
            self.fatal(
                'Incorrect size for range lower bounds, expecting: {1}, got: {0},'
                .format(nb_lbs, nb_rows))
        if nb_ubs != nb_rows:
            self.fatal(
                'Incorrect size for range upper bounds, expecting: {1}, got: {0}'
                .format(nb_ubs, nb_rows))
        if nb_cols != nb_vars:
            self.fatal(
                'Incorrect number of variables, expecting: {1}, got: {0},  matrix is ({0},{1})'
                .format(nb_vars, nb_cols, nb_rows, nb_cols))

        if is_scipy_sparse(coef_mat):
            return self._aggregator._sparse_matrix_ranges(
                coef_mat, s_dvars, s_lbs, s_ubs)
        else:
            return self._aggregator._matrix_ranges(coef_mat, s_dvars, s_lbs,
                                                   s_ubs)
예제 #3
0
    def matrix_constraints(self, coef_mat, dvars, rhs, sense='le'):
        """
        Creates a list of linear constraints
        from a matrix of coefficients, a sequence of variables, and a sequence of numbers.

        This method returns the list of constraints built from

            A.X <op> B

        where A is the coefficient matrix (of size (M,N)), X is the variable sequence (size N),
        and B is the sequence of right-hand side values (of size M).

        <op> is the comparison operator that defines the sense of the constraint. By default, this generates
        a 'less-than-or-equal' constraint.

        Example:
            `Model.scal_prod_vars_triple([x, y], [z, t], [2, 3])` returns the expression `2xz + 3yt`.

        :param coef_mat: A matrix of coefficients with M rows and N columns. This argument accepts
            either a list of lists of numbers, a `numpy` array with size (M,N), or a `scipy` sparse matrix.
        :param dvars: An ordered sequence of decision variables: accepts a Python list, `numpy` array,
            or a `pandas` series. The size of the sequence must match the number of columns in the matrix.
        :param rhs: A sequence of numbers: accepts a Python list, a `numpy` array,
            or a `pandas` series. The size of the sequence must match the number of rows in the matrix.
        :param sense: A constraint sense \; accepts either a
            value of type `ComparisonType` or a string (e.g 'le', 'eq', 'ge').

        :returns: A list of linear constraints.

        Example:

            If A is a matrix of coefficients with 2 rows and 3 columns::

                    A = [[1, 2, 3],
                         [4, 5, 6]],
                    X = [x, y, z] where x, y, and z are decision variables (size 3), and

                    B = [100, 200], a sequence of numbers (size 2),

            then::

                `mdl.matrix_constraint(A, X, B, 'GE')` returns a list of two constraints
                [(x + 2y+3z <= 100), (4x + 5y +6z <= 200)].

        Note:
            If the dimensions of the matrix and variables or of the matrix and number sequence do not match,
            an error is raised.

        """
        checker = self._checker
        if is_pandas_dataframe(coef_mat) or is_numpy_matrix(
                coef_mat) or is_scipy_sparse(coef_mat):
            nb_rows, nb_cols = coef_mat.shape
        else:
            # a sequence of sequences
            a_mat = list(coef_mat)
            nb_rows = len(a_mat)
            nb_cols = None
            try:
                shared_len = None
                for r in a_mat:
                    checker.check_ordered_sequence(r, 'matrix_constraints')
                    r_len = len(r)
                    if shared_len is None:
                        shared_len = r_len
                    elif r_len != shared_len:
                        self.fatal(
                            'All columns should have same length found  {0} != {1}'
                            .format(shared_len, r_len))
                nb_cols = shared_len if shared_len is not None else 0
            except AttributeError:
                self.fatal('All columns should have a len()')

        s_dvars = self._to_list(dvars, caller='Model.matrix-constraints()')
        s_rhs = self._to_list(rhs, caller='Model.matrix-constraints()')
        # check

        checker.typecheck_var_seq(s_dvars)
        for k in s_rhs:
            checker.typecheck_num(k)

        op = ComparisonType.parse(sense)
        # ---
        # check dimensions and whether to transpose or not.
        # ---
        nb_rhs = len(s_rhs)
        nb_vars = len(s_dvars)
        if (nb_rows, nb_cols) != (nb_rhs, nb_vars):
            self.fatal(
                'Dimension error, matrix is ({0},{1}), expecting ({3}, {2})'.
                format(nb_rows, nb_cols, nb_vars, nb_rhs))

        if is_scipy_sparse(coef_mat):
            return self._aggregator._sparse_matrix_constraints(
                coef_mat, s_dvars, s_rhs, op)
        else:
            return self._aggregator._matrix_constraints(
                coef_mat, s_dvars, s_rhs, op)