예제 #1
0
 def _subtract_quad(self, other_quad):
     # subtract quad
     quadterms = self._quadterms
     for oqv, oqk in other_quad.iter_quads():
         update_dict_from_item_value(quadterms, oqv, -oqk)
     # subtract linear part
     self._linexpr.subtract(other_quad._linexpr)
예제 #2
0
    def new_linexpr_product(self, linexpr, other):
        if isinstance(other, Var):
            return self.new_var_product(other, linexpr)

        elif isinstance(other, MonomialExpr):
            return self.new_monomial_product(other, linexpr)

        elif isinstance(other, LinearExpr):
            cst1 = linexpr.constant
            cst2 = other.constant

            fcc = self.term_dict_type()
            for lv1, lk1 in linexpr.iter_terms():
                for lv2, lk2 in other.iter_terms():
                    update_dict_from_item_value(fcc, VarPair(lv1, lv2), lk1 * lk2)
            # this is quad
            qlinexpr = self.new_linear_expr()
            # add cst2 * linexp1
            qlinexpr._add_expr_scaled(expr=linexpr, factor=cst2)
            # add cst1 * linexpr2
            qlinexpr._add_expr_scaled(expr=other, factor=cst1)

            # and that's it
            # fix the constant
            qlinexpr.constant = cst1 * cst2
            quad = QuadExpr(self._model, quads=fcc, linexpr=qlinexpr, safe=True)
            return quad

        else:
            self._unexpected_product_error(linexpr, other)
예제 #3
0
    def quad_matrix_sum(self, matrix, lvars, symmetric=False):
        # assume matrix is a NxN matrix
        # vars is a N-vector of variables
        dcc = self._quad_factory.term_dict_type
        qterms = dcc()

        gen_rows = self.generate_rows(matrix)

        for i, mrow in enumerate(gen_rows):
            vi = lvars[i]
            for j, k in enumerate(mrow):
                if k:
                    vj = lvars[j]
                    if i == j:
                        qterms[VarPair(vi)] = k
                    elif symmetric:
                        if i < j:
                            update_dict_from_item_value(
                                qterms, VarPair(vi, vj), 2 * k)
                        elif i > j:
                            continue
                    else:
                        update_dict_from_item_value(qterms, VarPair(vi, vj), k)

        return self._to_expr(qcc=qterms)
예제 #4
0
    def _sum_with_iter(self, args):
        sum_of_nums = 0
        lcc = self.counter_type()
        checker = self._checker
        qcc = None
        number_validation_fn = checker.get_number_validation_fn()
        for item in args:
            if isinstance(item, LinearOperand):
                for lv, lk in item.iter_terms():
                    update_dict_from_item_value(lcc, lv, lk)
                itc = item.get_constant()
                if itc:
                    sum_of_nums += itc
            elif is_number(item):
                sum_of_nums += number_validation_fn(item) if number_validation_fn else item
            elif isinstance(item, QuadExpr):
                for lv, lk in item.linear_part.iter_terms():
                    update_dict_from_item_value(lcc, lv, lk)
                if qcc is None:
                    qcc = self.counter_type()
                for qvp, qk in item.iter_quads():
                    update_dict_from_item_value(qcc, qvp, qk)
                sum_of_nums += item.get_constant()

            else:
                try:
                    expr = item.to_linear_expr()
                    sum_of_nums += expr.get_constant()
                    for dv, k in expr.iter_terms():
                        update_dict_from_item_value(lcc, dv, k)
                except AttributeError:
                    self._model.fatal("Model.sum() expects numbers/variables/expressions, got: {0!s}", item)

        return self._to_expr(qcc, lcc, sum_of_nums)
예제 #5
0
    def _sparse_quad_matrix_sum(self, sp_coef_mat, lvars, symmetric=False):
        # assume matrix is a NxN matrix
        # vars is a N-vector of variables
        dcc = self._quad_factory.term_dict_type
        qterms = dcc()

        for e in range(sp_coef_mat.nnz):
            k = sp_coef_mat.data[e]
            if k:
                row = sp_coef_mat.row[e]
                col = sp_coef_mat.col[e]
                vi = lvars[row]
                vj = lvars[col]
                update_dict_from_item_value(qterms, VarPair(vi, vj), k)

        return self._to_expr(qcc=qterms)
예제 #6
0
 def _scal_prod_triple_vars(self, coefs, left_terms, right_terms):
     # INTERNAL
     # assuming all arguments are iterable.
     dcc = self.counter_type
     qcc = dcc()
     number_validation_fn = self._checker.get_number_validation_fn()
     if number_validation_fn:
         for coef, lterm, rterm in izip(coefs, left_terms, right_terms):
             safe_coef = number_validation_fn(
                 coef) if number_validation_fn else coef
             update_dict_from_item_value(qcc, VarPair(lterm, rterm),
                                         safe_coef)
     else:
         for coef, lterm, rterm in izip(coefs, left_terms, right_terms):
             update_dict_from_item_value(qcc, VarPair(lterm, rterm), coef)
     return self._to_expr(qcc=qcc)
예제 #7
0
    def _scal_prod(self, terms, coefs):
        # INTERNAL
        checker = self._checker
        total_num = 0
        lcc = self.counter_type()
        qcc = None

        number_validation_fn = checker.get_number_validation_fn()

        for item, coef in izip(terms, coefs):
            if not coef:
                continue

            safe_coef = number_validation_fn(
                coef) if number_validation_fn else coef
            if isinstance(item, Var):
                update_dict_from_item_value(lcc, item, safe_coef)

            elif isinstance(item, AbstractLinearExpr):
                total_num += safe_coef * item.get_constant()
                for lv, lk in item.iter_terms():
                    update_dict_from_item_value(lcc, lv, lk * safe_coef)

            elif isinstance(item, QuadExpr):
                if qcc is None:
                    qcc = self.counter_type()
                for qv, qk in item.iter_quads():
                    update_dict_from_item_value(qcc, qv, qk * safe_coef)
                qlin = item.get_linear_part()
                for v, k in qlin.iter_terms():
                    update_dict_from_item_value(lcc, v, k * safe_coef)

                total_num += safe_coef * qlin.constant

            # --- try conversion ---
            else:
                try:
                    e = item.to_linear_expr()
                    total_num += e.get_constant()
                    for dv, k, in e.iter_terms():
                        update_dict_from_item_value(lcc, dv, k * safe_coef)
                except AttributeError:
                    self._model.fatal(
                        "scal_prod accepts variables, expressions, numbers, not: {0!s}",
                        item)

        return self._to_expr(qcc, lcc, total_num)
예제 #8
0
    def _varlist_to_terms(self, var_list):
        # INTERNAL: converts a sum of vars to a dict, sorting if needed.
        linear_term_dict_type = self._linear_factory.term_dict_type
        try:
            assume_no_dups = len(var_list) == len(set(var_list))
        except TypeError:
            assume_no_dups = False

        if assume_no_dups:
            varsum_terms = linear_term_dict_type()
            linear_terms_setitem = linear_term_dict_type.__setitem__
            for v in var_list:
                linear_terms_setitem(varsum_terms, v, 1)
        else:
            # there might be repeated variables.
            varsum_terms = linear_term_dict_type()
            for v in var_list:
                update_dict_from_item_value(varsum_terms, v, 1)
        return varsum_terms
예제 #9
0
    def _scal_prod_f_gen(self, dvars, coef_fn, var_key_iter):
        # var_map is a dictionary of variables.
        # coef_fn is a function accepting dictionary keys
        lcc_type = self.counter_type
        lcc = lcc_type()
        number_validation_fn = self._checker.get_number_validation_fn()
        if number_validation_fn:
            for k, dvar in var_key_iter(dvars):
                fcoeff = coef_fn(k)
                safe_coeff = number_validation_fn(fcoeff)
                if safe_coeff:
                    update_dict_from_item_value(lcc, dvar, safe_coeff)
        else:
            for k, dvar in var_key_iter(dvars):
                fcoeff = coef_fn(k)
                if fcoeff:
                    update_dict_from_item_value(lcc, dvar, fcoeff)

        return self._to_expr(qcc=None, lcc=lcc)
예제 #10
0
    def _scal_prod_triple(self, coefs, left_terms, right_terms):
        # INTERNAL
        accumulated_ct = 0
        qcc = self.counter_type()
        lcc = self.counter_type()
        number_validation_fn = self._checker.get_number_validation_fn()
        for coef, lterm, rterm in izip(coefs, left_terms, right_terms):
            if coef:
                safe_coef = number_validation_fn(
                    coef) if number_validation_fn else coef
                lcst = lterm.get_constant()
                rcst = rterm.get_constant()
                accumulated_ct += safe_coef * lcst * rcst
                for lv, lk in lterm.iter_terms():
                    for rv, rk in rterm.iter_terms():
                        coef3 = safe_coef * lk * rk
                        update_dict_from_item_value(qcc, VarPair(lv, rv),
                                                    coef3)
                if rcst:
                    for lv, lk in lterm.iter_terms():
                        update_dict_from_item_value(lcc, lv,
                                                    safe_coef * lk * rcst)
                if lcst:
                    for rv, rk in rterm.iter_terms():
                        update_dict_from_item_value(lcc, rv,
                                                    safe_coef * rk * lcst)

        return self._to_expr(qcc, lcc, constant=accumulated_ct)
예제 #11
0
    def _scal_prod_f(self, var_map, coef_fn, assume_alldifferent):
        if assume_alldifferent:
            return self._scal_prod_f_alldifferent(var_map, coef_fn)
        else:
            # var_map is a dictionary of variables.
            # coef_fn is a function accepting dictionary keys
            lcc_type = self.counter_type
            lcc = lcc_type()
            number_validation_fn = self._checker.get_number_validation_fn()
            if number_validation_fn:
                for k, dvar in iteritems(var_map):
                    fcoeff = coef_fn(k)
                    safe_coeff = number_validation_fn(fcoeff)
                    if safe_coeff:
                        update_dict_from_item_value(lcc, dvar, safe_coeff)
            else:
                for k, dvar in iteritems(var_map):
                    fcoeff = coef_fn(k)
                    if fcoeff:
                        update_dict_from_item_value(lcc, dvar, fcoeff)

            return self._to_expr(qcc=None, lcc=lcc)
예제 #12
0
    def _sumsq(self, args):
        accumulated_ct = 0
        number_validation_fn = self._checker.get_number_validation_fn()
        qcc = self._quad_factory.term_dict_type()
        lcc = self._linear_factory.term_dict_type()

        for item in args:
            if isinstance(item, Var):
                update_dict_from_item_value(qcc, VarPair(item, item), 1)
            elif isinstance(item, MonomialExpr):
                mcoef = item._coef
                # noinspection PyPep8
                mvar = item._dvar
                update_dict_from_item_value(qcc, VarPair(mvar, mvar), mcoef**2)

            elif isinstance(item, LinearExpr):
                cst = item.get_constant()
                accumulated_ct += cst**2
                for lv1, lk1 in item.iter_terms():
                    for lv2, lk2 in item.iter_terms():
                        if lv1 is lv2:
                            update_dict_from_item_value(
                                qcc, VarPair(lv1, lv1), lk1 * lk1)
                        elif lv1._index < lv2._index:
                            update_dict_from_item_value(
                                qcc, VarPair(lv1, lv2), 2 * lk1 * lk2)
                        else:
                            pass

                    if cst:
                        update_dict_from_item_value(lcc, lv1, 2 * cst * lk1)
            elif isinstance(item, _IAdvancedExpr):
                fvar = item.functional_var
                update_dict_from_item_value(qcc, VarPair(fvar), 1)

            elif isinstance(item, ZeroExpr):
                pass

            elif is_number(item):
                safe_item = number_validation_fn(
                    item) if number_validation_fn else item
                accumulated_ct += safe_item**2

            else:
                self._model.fatal(
                    "Model.sumsq() expects numbers/variables/linear expressions, got: {0!s}",
                    item)

        return self._to_expr(qcc, lcc, constant=accumulated_ct)
예제 #13
0
 def _sumsq_vars(self, dvars):
     qcc = self._quad_factory.term_dict_type()
     for v in dvars:
         update_dict_from_item_value(qcc, VarPair(v), 1)
     return self._to_expr(qcc=qcc)