Ejemplo n.º 1
0
 def check_vars_domain(self, lbs, ubs, names):
     l_ubs = len(ubs)
     l_lbs = len(lbs)
     if l_lbs and l_ubs:
         names = names or generate_constant(None, max(l_lbs, l_ubs))
         for lb, ub, varname in izip(lbs, ubs, names):
             self.check_var_domain(lb, ub, varname)
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
    def _make_expr_from_vars_coefs(cls, mdl, dvars, coefs, offset=0):
        terms_dict = mdl._lfactory._new_term_dict()

        for dv, k in izip(dvars, coefs):
            if k:
                terms_dict[dv] = k
        return mdl._lfactory.linear_expr(arg=terms_dict, constant=offset, safe=True)
Ejemplo n.º 4
0
 def _sparse_make_exprs(self, sp_mat, dvars, nb_exprs):
     lfactory = self._linear_factory
     exprs = [lfactory.linear_expr() for _ in range(nb_exprs)]
     coo_mat = sp_mat.tocoo()
     for coef, row, col in izip(coo_mat.data, coo_mat.row, coo_mat.col):
         exprs[row]._add_term(dvars[col], coef)
     return exprs
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
        def __add__(self, arg):
            if isinstance(arg, PwlFunction._PwlAsBreaks):
                all_x_coord = sorted({br[0] for br in self.breaksxy + arg.breaksxy})
                all_breaks_left = self._get_all_breaks(all_x_coord)
                all_breaks_right = arg._get_all_breaks(all_x_coord)
                result_breaksxy = []
                # Both lists have same size, with same x-coord for breaks ==> perform the addition on each break
                for br_l, br_r in izip(all_breaks_left, all_breaks_right):
                    if isinstance(br_l, tuple) and isinstance(br_r, tuple):
                        result_breaksxy.append((br_l[0], br_l[1] + br_r[1]))
                    else:
                        if isinstance(br_l, tuple):
                            # br_r is a list containing 2 tuple pairs
                            result_breaksxy.append((br_l[0], br_l[1] + br_r[0][1]))
                            result_breaksxy.append((br_l[0], br_l[1] + br_r[1][1]))
                        elif isinstance(br_r, tuple):
                            # br_l is a list containing 2 tuple pairs
                            result_breaksxy.append((br_r[0], br_l[0][1] + br_r[1]))
                            result_breaksxy.append((br_r[0], br_l[1][1] + br_r[1]))
                        else:
                            # br_l and br_r are two lists, each containing 2 tuple pairs
                            result_breaksxy.append((br_l[0][0], br_l[0][1] + br_r[0][1]))
                            result_breaksxy.append((br_l[0][0], br_l[1][1] + br_r[1][1]))
                result_preslope = self.preslope + arg.preslope
                result_postslope = self.postslope + arg.postslope
                return PwlFunction._PwlAsBreaks(*self._remove_useless_intermediate_breaks(
                    result_preslope, result_breaksxy, result_postslope))

            elif is_number(arg):
                return PwlFunction._PwlAsBreaks(
                    self.preslope, [(br[0], br[1] + arg) for br in self.breaksxy], self.postslope)

            else:
                raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Ejemplo n.º 7
0
 def notify_obj_indices(self, objs, indices):
     # take the last one??
     if indices:
         idxmap = self._index_map
         if idxmap is not None:
             for obj, idx in izip(objs, indices):
                 idxmap[idx] = obj
Ejemplo n.º 8
0
 def build_matrix_range_model_and_solve(cls, var_count, var_lbs, var_ubs,
                                        var_types, var_names,
                                        cts_mat, range_mins, range_maxs,
                                        objsense, costs,
                                        cast_to_float,
                                        solution_maker=make_solution,
                                        **transform_params):
     cpx = cls.create_cplex()
     # varlist = mdl.continuous_var_list(var_count, lb=var_lbs, ub=var_ubs, name=var_names)
     cls.create_column_vars(cpx, var_count, var_lbs, var_ubs, var_types, var_names)
     var_indices = list(range(var_count))
     gen_rows = ModelAggregator.generate_rows(cts_mat)
     cpx_rows = []
     for row in gen_rows:
         # need this step as cplex may crash with np types.
         frow = [float(k) for k in row] if cast_to_float else row
         cpx_rows.append([var_indices, frow])
     nb_rows = len(cpx_rows)
     if nb_rows:
         #ctsense = ComparisonType.parse(transform_params.get('sense', 'le'))
         cpx_senses = 'R' * nb_rows
         cpx_ranges = [float(rmin - rmax) for rmin, rmax in izip(range_mins, range_maxs)]
         # rhs is UB
         cpx_rhss = [float(rmax) for rmax in range_maxs]
         add_linear(cpx, cpx_rows, cpx_senses, rhs=cpx_rhss, names=[], ranges=cpx_ranges)
     if costs is not None:
         # set linear objective for all variables.
         fcosts = [float(k) for k in costs]
         static_fast_set_linear_obj(cpx, var_indices, fcosts)
         cpx.objective.set_sense(objsense.cplex_coef)
     # here we go to solve...
     return cls._solve(cpx, var_names, solution_maker=solution_maker, **transform_params)
Ejemplo n.º 9
0
 def notify_obj_indices(self, objs, indices):
     # take the last one??
     if indices:
         _AutomaticSymbolGenerator.notify_new_index(self, max(indices))
         idxmap = self._index_map
         if idxmap is not None:
             for obj, idx in izip(objs, indices):
                 idxmap[idx] = obj
Ejemplo n.º 10
0
 def check_vars_domain(self, lbs, ubs, names):
     l_ubs = len(ubs)
     l_lbs = len(lbs)
     if l_lbs and l_ubs:
         names = names or generate_constant(None, max(l_lbs, l_ubs))
         # noinspection PyArgumentList,PyArgumentList
         for lb, ub, varname in izip(lbs, ubs, names):
             self.check_var_domain(lb, ub, varname)
Ejemplo n.º 11
0
    def _make_expr_from_varmap_coefs(cls, lfactory, varmap, dvarxs, coefs, offset=0):
        terms_dict = lfactory._new_term_dict()

        for dvx, k in izip(dvarxs, coefs):
            dv = varmap.get(dvx)
            if dv is not None and k:
                terms_dict[dv] = k
        return lfactory.linear_expr(arg=terms_dict, constant=offset, safe=True)
Ejemplo n.º 12
0
 def vector_compare(self, left_exprs, right_exprs, sense):
     lfactory = self._linear_factory
     assert len(left_exprs) == len(right_exprs)
     cts = [
         lfactory._new_binary_constraint(left, sense, right)
         for left, right in izip(left_exprs, right_exprs)
     ]
     return cts
Ejemplo n.º 13
0
 def _make_expr_from_varmap_coefs(cls,
                                  lfactory,
                                  varmap,
                                  var_indices,
                                  coefs,
                                  offset=0):
     if Environment.env_is_python36:
         terms_dict = {
             varmap.get(dvx): k
             for dvx, k in izip(var_indices, coefs)
         }
     else:
         terms_dict = lfactory._new_term_dict()
         for dvx, k in izip(var_indices, coefs):
             dv = varmap.get(dvx)
             if dv is not None:
                 terms_dict[dv] = k
     return lfactory.linear_expr(arg=terms_dict, constant=offset, safe=True)
Ejemplo n.º 14
0
 def make_solution_from_vars(self, dvars):
     # build a solution object from array of solution values
     # noinspection PyUnresolvedReferences
     if dvars:
         indices = [v._index for v in dvars]
         var_values = super(ModelCallbackMixin, self).get_values(indices)
         var_value_dict = {v: val for v, val in izip(dvars, var_values)}
     else:
         var_value_dict = {}
     return self.model.new_solution(var_value_dict)
Ejemplo n.º 15
0
    def _matrix_ranges(self, coef_mat, svars, lbs, ubs):
        row_gen = self.generate_rows(coef_mat)
        lfactory = self._linear_factory

        return [
            lfactory.new_range_constraint(expr=self._scal_prod(svars, row),
                                          lb=lb,
                                          ub=ub)
            for row, lb, ub in izip(row_gen, lbs, ubs)
        ]
Ejemplo n.º 16
0
    def _scal_prod_vars_all_different(self, terms, coefs):
        checker = self._checker
        if not is_iterable(coefs, accept_string=False):
            checker.typecheck_num(coefs)
            return coefs * self._sum_vars_all_different(terms)
        else:
            # coefs is iterable
            lcc_type = self.counter_type
            lcc = lcc_type()
            lcc_setitem = lcc_type.__setitem__
            number_validation_fn = checker.get_number_validation_fn()
            if number_validation_fn:
                for dvar, coef in izip(terms, coefs):
                    lcc_setitem(lcc, dvar, number_validation_fn(coef))
            else:
                for dvar, coef in izip(terms, coefs):
                    lcc_setitem(lcc, dvar, coef)

            return self._to_expr(qcc=None, lcc=lcc)
Ejemplo n.º 17
0
    def _matrix_constraints(self, coef_mat, svars, srhs, op):
        row_gen = self.generate_rows(coef_mat)
        lfactory = self._linear_factory

        return [
            lfactory._new_binary_constraint(lhs=self._scal_prod(svars, row),
                                            sense=op,
                                            rhs=rhs)
            for row, rhs in izip(row_gen, srhs)
        ]
Ejemplo n.º 18
0
def compile_naming_function(keys,
                            user_name,
                            dimension=1,
                            key_format=None,
                            _default_key_format='_%s',
                            stringifier=str_flatten_tuple):
    # INTERNAL
    # builds a naming rule from an input , a dimension, and an optional meta-format
    # Makes sure the format string does contain the right number of format slots
    assert user_name is not None

    if is_string(user_name):
        if key_format is None:
            used_key_format = _default_key_format
        elif is_string(key_format):
            # -- make sure some %s is inside, otherwise add it
            if '%s' in key_format:
                used_key_format = key_format
            else:
                used_key_format = key_format + '%s'
        else:  # pragma: no cover
            raise DOcplexException(
                "key format expects string format or None, got: {0!r}".format(
                    key_format))

        fixed_format_string = fix_format_string(user_name, dimension,
                                                used_key_format)
        if 1 == dimension:
            return lambda k: fixed_format_string % stringifier(k)
        else:
            # here keys are tuples of size >= 2
            return lambda key_tuple: fixed_format_string % key_tuple

    elif is_function(user_name):
        return user_name

    elif is_iterable(user_name):
        # check that the iterable has same len as keys,
        # otherwise thereis no more default naming and None cannot appear in CPLEX name arrays
        list_names = list(user_name)
        if len(list_names) < len(keys):
            raise DOcplexException(
                "An array of names should have same len as keys, expecting: {0}, go: {1}"
                .format(len(keys), len(list_names)))
        key_to_names_dict = {k: nm for k, nm in izip(keys, list_names)}
        # use a closure
        return lambda k: key_to_names_dict[
            k]  # if k in key_to_names_dict else default_fn()

    else:
        raise DOcplexException(
            'Cannot use this for naming variables: {0!r} - expecting string, function or iterable'
            .format(user_name))
Ejemplo n.º 19
0
 def make_solution_from_vars(self, dvars):
     # build a solution object from array of solution values
     # noinspection PyUnresolvedReferences
     m = self.model
     if dvars:
         indices = [v._index for v in dvars]
         # this calls the Cplex callback method get_values, which crashes if called with empty list
         var_values = super(ModelCallbackMixin, self).get_values(indices)
         var_value_dict = {v: val for v, val in izip(dvars, var_values)}
     else:
         var_value_dict = {}
     return m.new_solution(var_value_dict)
Ejemplo n.º 20
0
 def _print_sos_block(self, wrapper, mdl):
     if mdl.number_of_sos > 0:
         wrapper.write('SOS')
         wrapper.flush(print_newline=True)
         name_fn = self._var_print_name
         for s, sos in enumerate(mdl.iter_sos(), start=1):
             # always print a name string, s1, s2, ... if no name
             sos_name = sos.get_name() or 's%d' % s
             wrapper.write('%s:' % sos_name)
             wrapper.write('S%d ::' % sos.sos_type.value)  # 1 or 2
             ranks = sos.weights
             # noinspection PyArgumentList
             for rank, sos_var in izip(ranks, sos._variables):
                 wrapper.write('%s : %d' % (name_fn(sos_var), rank))
             wrapper.flush(print_newline=True)
Ejemplo n.º 21
0
    def make_solution_from_vars(self, dvars):
        """ Creates an intermediate solution from a list of variables.

        :param dvars: a list of DOcplex variables.
        :return: a :class:`docplex.mp.solution.SolveSolution` object.
        """
        if dvars:
            indices = [v._index for v in dvars]
            # this calls the Cplex callback method get_values, which crashes if called with empty list
            # noinspection PyUnresolvedReferences
            var_values = super(ModelCallbackMixin, self).get_values(indices)
            # noinspection PyArgumentList
            var_value_dict = {v: val for v, val in izip(dvars, var_values)}
        else:  # pragma: no cover
            var_value_dict = {}
        return self.model.new_solution(var_value_dict)
Ejemplo n.º 22
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)
Ejemplo n.º 23
0
        def __add__(self, arg):
            if isinstance(arg, PwlFunction._PwlAsSlopes):
                all_x_coord = sorted({sbr[1] for sbr in self.slopebreaksx + arg.slopebreaksx})
                all_slopebreaks_left = self._get_all_slopebreaks(all_x_coord)
                all_slopebreaks_right = arg._get_all_slopebreaks(all_x_coord)
                result_slopebreaksxy = []
                # Both lists have same size, with same x-coord for slopebreaks
                #   ==> perform the addition of slopes on each break
                for sbr_l, sbr_r in izip(all_slopebreaks_left, all_slopebreaks_right):
                    if isinstance(sbr_l, tuple) and isinstance(sbr_r, tuple):
                        result_slopebreaksxy.append((sbr_l[0] + sbr_r[0], sbr_l[1]))
                    else:
                        if isinstance(sbr_l, tuple):
                            # sbr_r is a list containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0] + sbr_r[0][0], sbr_l[1]))
                            result_slopebreaksxy.append((sbr_r[1][0], sbr_l[1]))
                        elif isinstance(sbr_r, tuple):
                            # sbr_l is a list containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0][0] + sbr_r[0], sbr_r[1]))
                            result_slopebreaksxy.append((sbr_l[1][0], sbr_r[1]))
                        else:
                            # sbr_l and sbr_r are two lists, each containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0][0] + sbr_r[0][0], sbr_l[0][1]))
                            result_slopebreaksxy.append((sbr_l[1][0] + sbr_r[1][0], sbr_l[0][1]))
                result_lastslope = self.lastslope + arg.lastslope

                if self.anchor[0] == arg.anchor[0]:
                    result_anchor = (self.anchor[0], self.anchor[1] + arg.anchor[1])
                else:
                    # Compute a new anchor based on the last x-coord in the slopebreakx list + anchor point
                    anchor_l = self._get_safe_xy_anchor()
                    anchor_r = arg._get_safe_xy_anchor()
                    delta = anchor_r[0] - anchor_l[0]
                    if anchor_l[0] < anchor_r[0]:
                        result_anchor = (anchor_r[0], anchor_l[1] + anchor_r[1] + delta * self.lastslope)
                    else:
                        result_anchor = (anchor_l[0], anchor_l[1] + anchor_r[1] - delta * arg.lastslope)

                return PwlFunction._PwlAsSlopes(*self._remove_useless_intermediate_slopes(
                    result_slopebreaksxy, result_lastslope, result_anchor))

            elif is_number(arg):
                return PwlFunction._PwlAsSlopes(copy.deepcopy(self.slopebreaksx),
                                                self.lastslope, (self.anchor[0], self.anchor[1] + arg))
            else:
                raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Ejemplo n.º 24
0
    def equals(self,
               other,
               check_models=False,
               obj_precision=1e-3,
               var_precision=1e-6):
        from itertools import dropwhile
        if check_models and (self.model != other.model):
            return False

        if is_iterable(self.objective_value) and is_iterable(
                other.objective_value):
            if len(self.objective_value) == len(other.objective_value):
                for self_obj_val, other_obj_val in zip(self.objective_value,
                                                       other.objective_value):
                    if abs(self_obj_val - other_obj_val) >= obj_precision:
                        return False
            else:  # Different number of objectives
                return False
        elif not is_iterable(self.objective_value) and not is_iterable(
                other.objective_value):
            if abs(self.objective_value -
                   other.objective_value) >= obj_precision:
                return False
        else:  # One solution is for multi-objective, and not the other
            return False

        # noinspection PyPep8
        this_triplets = [(dv.index, dv.name, svalue)
                         for dv, svalue in dropwhile(lambda dvv: not dvv[1],
                                                     self.iter_var_values())]
        other_triplets = [(dv.index, dv.name, svalue)
                          for dv, svalue in dropwhile(lambda dvv: not dvv[1],
                                                      other.iter_var_values())]
        # noinspection PyArgumentList
        res = True
        for this_triple, other_triple in izip(this_triplets, other_triplets):
            this_index, this_name, this_val = this_triple
            other_index, other_name, other_val = other_triple
            if other_index != this_index or this_name != other_name or \
                    abs(this_val - other_val) >= var_precision:
                res = False
                break
        return res
Ejemplo n.º 25
0
    def new_range_block(self, lbs, exprs, ubs, names):
        try:
            n_exprs = len(exprs)
            if n_exprs != len(lbs):  # pragma: no cover
                self.fatal(
                    'incorrect number of expressions: expecting {0}, got: {1}'.
                    format(len(lbs), n_exprs))

        except TypeError:
            pass  # no len available.
        if not names:
            names = generate_constant(None, None)

        ranges = [
            self.new_range_constraint(lb, exp, ub, name)
            for lb, exp, ub, name in izip(lbs, exprs, ubs, names)
        ]
        # else:
        #     ranges = [self.new_range_constraint(lb, exp, ub) for lb, exp, ub in izip(lbs, exprs, ubs)]
        self._post_constraint_block(ranges)
        return ranges
Ejemplo n.º 26
0
    def new_var_df(self,
                   keys1,
                   keys2,
                   vartype,
                   lb=None,
                   ub=None,
                   name=None):  # pragma: no cover
        try:
            from pandas import DataFrame
        except ImportError:
            DataFrame = None
            self.fatal('make_var_df() requires pandas module - not found')

        _, row_keys = self.make_key_seq(keys1, name)
        _, col_keys = self.make_key_seq(keys2, name)
        matrix_keys = [(k1, k2) for k1 in row_keys for k2 in col_keys]
        ctn = self._new_var_container(vartype,
                                      key_list=matrix_keys,
                                      lb=lb,
                                      ub=ub,
                                      name=name)
        lvars = self.new_var_list(ctn,
                                  matrix_keys,
                                  vartype,
                                  lb,
                                  ub,
                                  name,
                                  dimension=2,
                                  key_format=None)
        # TODO: see how to do without this temp dict
        dd = dict(izip(matrix_keys, lvars))
        # row-oriented dict
        rowd = {
            row_k: [dd[row_k, col_k] for col_k in col_keys]
            for row_k in row_keys
        }
        vdtf = DataFrame.from_dict(rowd, orient='index', dtype='object')
        # convert to string or not?
        vdtf.columns = col_keys
        return vdtf
Ejemplo n.º 27
0
 def new_batch_indicator_constraints(self, bvars, linear_cts, active_values,
                                     names):
     return [
         self.new_indicator_constraint(bv, lct, active, name) for bv, lct,
         active, name in izip(bvars, linear_cts, active_values, names)
     ]
Ejemplo n.º 28
0
 def _build_linear_expr_from_sparse_pair(lfactory, var_map, cpx_sparsepair):
     expr = lfactory.linear_expr(arg=0, safe=True)
     for ix, k in izip(cpx_sparsepair.ind, cpx_sparsepair.val):
         dv = var_map[ix]
         expr._add_term(dv, k)
     return expr
Ejemplo n.º 29
0
    def read(cls,
             filename,
             model_name=None,
             verbose=False,
             model_class=None,
             **kwargs):
        """ Reads a model from a CPLEX export file.

        Accepts all formats exported by CPLEX: LP, SAV, MPS.

        If an error occurs while reading the file, the message of the exception
        is printed and the function returns None.

        Args:
            filename: The file to read.
            model_name: An optional name for the newly created model. If None,
                the model name will be the path basename.
            verbose: An optional flag to print informative messages, default is False.
            model_class: An optional class type; must be a subclass of Model.
                The returned model is built using this model_class and the keyword arguments kwargs, if any.
                By default, the model is class is `Model` (see
            kwargs: A dict of keyword-based arguments that are used when creating the model
                instance.

        Example:
            `m = read_model("c:/temp/foo.mps", model_name="docplex_foo", solver_agent="docloud", output_level=100)`

        Returns:
            An instance of Model, or None if an exception is raised.

        See Also:
            :class:`docplex.mp.model.Model`

        """
        if not os.path.exists(filename):
            raise IOError("* file not found: {0}".format(filename))

        # extract basename
        if model_name:
            name_to_use = model_name
        else:
            basename = os.path.basename(filename)
            if '.' not in filename:
                raise RuntimeError(
                    'ModelReader.read_model(): path has no extension: {}'.
                    format(filename))
            dotpos = basename.find(".")
            if dotpos > 0:
                name_to_use = basename[:dotpos]
            else:  # pragma: no cover
                name_to_use = basename

        model_class = model_class or Model

        if 0 == os.stat(filename).st_size:
            print("* file is empty: {0} - exiting".format(filename))
            return model_class(name=name_to_use, **kwargs)

        if verbose:
            print("-> CPLEX starts reading file: {0}".format(filename))
        cpx_adapter = cls._read_cplex(filename)
        cpx = cpx_adapter.cpx
        if verbose:
            print("<- CPLEX finished reading file: {0}".format(filename))

        if not cpx:  # pragma: no cover
            return None

        final_output_level = kwargs.get("output_level", "info")
        debug_read = kwargs.get("debug", False)

        try:
            # force no tck
            if 'checker' in kwargs:
                final_checker = kwargs['checker']
            else:
                final_checker = 'default'
            # build the model with no checker, then restore final_checker in the end.
            kwargs['checker'] = 'off'

            ignore_names = kwargs.get('ignore_names', False)
            # -------------

            mdl = model_class(name=name_to_use, **kwargs)
            lfactory = mdl._lfactory
            qfactory = mdl._qfactory
            mdl.set_quiet()  # output level set to ERROR
            vartype_cont = mdl.continuous_vartype
            vartype_map = {
                'B': mdl.binary_vartype,
                'I': mdl.integer_vartype,
                'C': mdl.continuous_vartype,
                'S': mdl.semicontinuous_vartype
            }
            # 1 upload variables
            cpx_nb_vars = cpx.variables.get_num()

            def make_constant_expr(k):
                if k:
                    return lfactory._new_safe_constant_expr(k)
                else:
                    return lfactory.new_zero_expr()

            if verbose:
                print("-- uploading {0} variables...".format(cpx_nb_vars))

            cpx_var_names = [] if ignore_names else cls._safe_call_get_names(
                cpx_adapter, cpx.variables.get_names)

            if cpx._is_MIP():
                cpx_vartypes = [
                    vartype_map.get(cpxt, vartype_cont)
                    for cpxt in cpx.variables.get_types()
                ]
            else:
                cpx_vartypes = [vartype_cont] * cpx_nb_vars
            cpx_var_lbs = cpx.variables.get_lower_bounds()
            cpx_var_ubs = cpx.variables.get_upper_bounds()
            # map from cplex variable indices to docplex's
            # use to skip range vars
            # cplex : [x, Rg1, y] -> {0:0, 2: 1}

            if cpx_var_names:
                model_varnames = cpx_var_names
            else:
                model_varnames = [None] * cpx_nb_vars
            model_lbs = cpx_var_lbs
            model_ubs = cpx_var_ubs
            model_types = cpx_vartypes

            # vars
            model_vars = lfactory.new_multitype_var_list(
                cpx_nb_vars, model_types, model_lbs, model_ubs, model_varnames)

            # inverse map from indices to docplex vars
            cpx_var_index_to_docplex = {
                v: model_vars[v]
                for v in range(cpx_nb_vars)
            }

            # 2. upload linear constraints and ranges (mixed in cplex)
            cpx_linearcts = cpx.linear_constraints
            nb_linear_cts = cpx_linearcts.get_num()
            # all_rows1 = cpx_linearcts.get_rows()
            all_rows = cpx_adapter.fast_get_rows(cpx)
            all_rhs = cpx_linearcts.get_rhs()
            all_senses = cpx_linearcts.get_senses()
            all_range_values = cpx_linearcts.get_range_values()
            cpx_ctnames = [] if ignore_names else cls._safe_call_get_names(
                cpx_adapter, cpx_linearcts.get_names)

            deferred_cts = []

            if verbose:
                print("-- uploading {0} linear constraints...".format(
                    nb_linear_cts))
            for c in range(nb_linear_cts):
                row = all_rows[c]
                sense = all_senses[c]
                rhs = all_rhs[c]
                ctname = cpx_ctnames[c] if cpx_ctnames else None
                range_val = all_range_values[c]

                indices, coefs = row
                expr = cls._make_expr_from_varmap_coefs(
                    lfactory, cpx_var_index_to_docplex, indices, coefs)

                if sense == 'R':
                    # rangeval can be negative !!! issue 52
                    if range_val >= 0:
                        range_lb = rhs
                        range_ub = rhs + range_val
                    else:
                        range_ub = rhs
                        range_lb = rhs + range_val

                    rgct = mdl.range_constraint(lb=range_lb,
                                                ub=range_ub,
                                                expr=expr,
                                                rng_name=ctname)
                    deferred_cts.append(rgct)
                else:
                    op = cls.parse_sense(sense)
                    rhs_expr = make_constant_expr(rhs)

                    ct = LinearConstraint(mdl, expr, op, rhs_expr, ctname)
                    deferred_cts.append(ct)
            if deferred_cts:
                # add constraint as a block
                lfactory._post_constraint_block(posted_cts=deferred_cts)

            # 3. upload Quadratic constraints
            cpx_quadraticcts = cpx.quadratic_constraints
            nb_quadratic_cts = cpx_quadraticcts.get_num()
            if nb_quadratic_cts:
                all_rhs = cpx_quadraticcts.get_rhs()
                all_linear_nb_non_zeros = cpx_quadraticcts.get_linear_num_nonzeros(
                )
                all_linear_components = cpx_quadraticcts.get_linear_components(
                )
                all_quadratic_nb_non_zeros = cpx_quadraticcts.get_quad_num_nonzeros(
                )
                all_quadratic_components = cpx_quadraticcts.get_quadratic_components(
                )
                all_senses = cpx_quadraticcts.get_senses()
                cpx_ctnames = [] if ignore_names else cls._safe_call_get_names(
                    cpx_adapter, cpx_quadraticcts.get_names)

                for c in range(nb_quadratic_cts):
                    rhs = all_rhs[c]
                    linear_nb_non_zeros = all_linear_nb_non_zeros[c]
                    linear_component = all_linear_components[c]
                    quadratic_nb_non_zeros = all_quadratic_nb_non_zeros[c]
                    quadratic_component = all_quadratic_components[c]
                    sense = all_senses[c]
                    ctname = cpx_ctnames[c] if cpx_ctnames else None

                    if linear_nb_non_zeros > 0:
                        indices, coefs = linear_component.unpack()
                        # linexpr = mdl._aggregator._scal_prod((cpx_var_index_to_docplex[idx] for idx in indices), coefs)
                        linexpr = cls._make_expr_from_varmap_coefs(
                            lfactory, cpx_var_index_to_docplex, indices, coefs)
                    else:
                        linexpr = None

                    if quadratic_nb_non_zeros > 0:
                        qfactory = mdl._qfactory
                        ind1, ind2, coefs = quadratic_component.unpack()
                        quads = qfactory.term_dict_type()
                        for idx1, idx2, coef in izip(ind1, ind2, coefs):
                            quads[VarPair(
                                cpx_var_index_to_docplex[idx1],
                                cpx_var_index_to_docplex[idx2])] = coef

                    else:  # pragma: no cover
                        # should not happen, but who knows
                        quads = None

                    quad_expr = mdl._aggregator._quad_factory.new_quad(
                        quads=quads, linexpr=linexpr, safe=True)
                    op = ComparisonType.cplex_ctsense_to_python_op(sense)
                    ct = op(quad_expr, rhs)
                    mdl.add_constraint(ct, ctname)

            # 4. upload indicators
            cpx_indicators = cpx.indicator_constraints
            nb_indicators = cpx_indicators.get_num()
            if nb_indicators:
                all_ind_names = [] if ignore_names else cls._safe_call_get_names(
                    cpx_adapter, cpx_indicators.get_names)

                all_ind_bvars = cpx_indicators.get_indicator_variables()
                all_ind_rhs = cpx_indicators.get_rhs()
                all_ind_linearcts = cpx_indicators.get_linear_components()
                all_ind_senses = cpx_indicators.get_senses()
                all_ind_complemented = cpx_indicators.get_complemented()
                all_ind_types = cpx_indicators.get_types()
                ind_equiv_type = 3

                for i in range(nb_indicators):
                    ind_bvar = all_ind_bvars[i]
                    ind_name = all_ind_names[i] if all_ind_names else None
                    ind_rhs = all_ind_rhs[i]
                    ind_linear = all_ind_linearcts[i]  # SparsePair(ind, val)
                    ind_sense = all_ind_senses[i]
                    ind_complemented = all_ind_complemented[i]
                    ind_type = all_ind_types[i]
                    # 1 . check the bvar is ok
                    ind_bvar = cpx_var_index_to_docplex[ind_bvar]
                    # each var appears once
                    ind_linexpr = cls._build_linear_expr_from_sparse_pair(
                        lfactory, cpx_var_index_to_docplex, ind_linear)
                    op = ComparisonType.cplex_ctsense_to_python_op(ind_sense)
                    ind_lct = op(ind_linexpr, ind_rhs)
                    if ind_type == ind_equiv_type:
                        logct = lfactory.new_equivalence_constraint(
                            ind_bvar,
                            ind_lct,
                            true_value=1 - ind_complemented,
                            name=ind_name)
                    else:
                        logct = lfactory.new_indicator_constraint(
                            ind_bvar,
                            ind_lct,
                            true_value=1 - ind_complemented,
                            name=ind_name)
                    mdl.add(logct)

            # 5. upload Piecewise linear constraints
            try:
                cpx_pwl = cpx.pwl_constraints
                cpx_pwl_defs = cpx_pwl.get_definitions()
                pwl_fallback_names = [""] * cpx_pwl.get_num()
                cpx_pwl_names = pwl_fallback_names if ignore_names else cls._safe_call_get_names(
                    cpx_adapter, cpx_pwl.get_names, pwl_fallback_names)
                for (vary_idx, varx_idx, preslope, postslope, breakx,
                     breaky), pwl_name in izip(cpx_pwl_defs, cpx_pwl_names):
                    varx = cpx_var_index_to_docplex.get(varx_idx, None)
                    vary = cpx_var_index_to_docplex.get(vary_idx, None)
                    breakxy = [(brkx, brky)
                               for brkx, brky in zip(breakx, breaky)]
                    pwl_func = mdl.piecewise(preslope,
                                             breakxy,
                                             postslope,
                                             name=pwl_name)
                    pwl_expr = mdl._lfactory.new_pwl_expr(
                        pwl_func,
                        varx,
                        0,
                        add_counter_suffix=False,
                        resolve=False)
                    pwl_expr._f_var = vary
                    pwl_expr._ensure_resolved()

            except AttributeError:  # pragma: no cover
                pass  # Do not check for PWLs if Cplex version does not support them

            # 6. upload objective

            # noinspection PyPep8
            try:
                cpx_multiobj = cpx.multiobj
            except AttributeError:  # pragma: no cover
                # pre-12.9 version
                cpx_multiobj = None

            if cpx_multiobj is None or cpx_multiobj.get_num() <= 1:
                cpx_obj = cpx.objective
                cpx_sense = cpx_obj.get_sense()

                cpx_all_lin_obj_coeffs = cpx_obj.get_linear()
                all_obj_vars = []
                all_obj_coefs = []

                for v in range(cpx_nb_vars):
                    if v in cpx_var_index_to_docplex:
                        obj_coeff = cpx_all_lin_obj_coeffs[v]
                        all_obj_coefs.append(obj_coeff)
                        all_obj_vars.append(cpx_var_index_to_docplex[v])

                # obj_expr = mdl._aggregator._scal_prod(all_obj_vars, all_obj_coefs)
                obj_expr = cls._make_expr_from_vars_coefs(
                    mdl, all_obj_vars, all_obj_coefs)

                if cpx_obj.get_num_quadratic_variables() > 0:
                    cpx_all_quad_cols_coeffs = cpx_obj.get_quadratic()
                    quads = qfactory.term_dict_type()
                    for v, col_coefs in izip(cpx_var_index_to_docplex,
                                             cpx_all_quad_cols_coeffs):
                        var1 = cpx_var_index_to_docplex[v]
                        indices, coefs = col_coefs.unpack()
                        for idx, coef in izip(indices, coefs):
                            vp = VarPair(var1, cpx_var_index_to_docplex[idx])
                            quads[vp] = quads.get(vp, 0) + coef / 2

                    obj_expr += qfactory.new_quad(quads=quads, linexpr=None)

                obj_expr += cpx.objective.get_offset()
                is_maximize = cpx_sense == cpx_adapter.cplex_module._internal._subinterfaces.ObjSense.maximize

                if is_maximize:
                    mdl.maximize(obj_expr)
                else:
                    mdl.minimize(obj_expr)
            else:
                # we have multiple objective
                nb_multiobjs = cpx_multiobj.get_num()
                exprs = [0] * nb_multiobjs
                priorities = [1] * nb_multiobjs
                weights = [1] * nb_multiobjs
                abstols = [0] * nb_multiobjs
                reltols = [0] * nb_multiobjs
                names = cpx_multiobj.get_names()

                for m in range(nb_multiobjs):
                    (obj_coeffs, obj_offset, weight, prio, abstol,
                     reltol) = cpx_multiobj.get_definition(m)
                    obj_expr = cls._make_expr_from_coef_vector(
                        mdl, cpx_var_index_to_docplex, obj_coeffs, obj_offset)
                    exprs[m] = obj_expr
                    priorities[m] = prio
                    weights[m] = weight
                    abstols[m] = abstol
                    reltols[m] = reltol
                sense = cpx_multiobj.get_sense()
                mdl.set_multi_objective(sense, exprs, priorities, weights,
                                        abstols, reltols, names)

            # upload sos
            cpx_sos = cpx.SOS
            cpx_sos_num = cpx_sos.get_num()
            if cpx_sos_num > 0:
                cpx_sos_types = cpx_sos.get_types()
                cpx_sos_indices = cpx_sos.get_sets()
                cpx_sos_names = cpx_sos.get_names()
                if not cpx_sos_names:
                    cpx_sos_names = [None] * cpx_sos_num
                for sostype, sos_sparse, sos_name in izip(
                        cpx_sos_types, cpx_sos_indices, cpx_sos_names):
                    sos_var_indices = sos_sparse.ind
                    sos_weights = sos_sparse.val
                    isostype = int(sostype)
                    sos_vars = [
                        cpx_var_index_to_docplex[var_ix]
                        for var_ix in sos_var_indices
                    ]
                    mdl.add_sos(dvars=sos_vars,
                                sos_arg=isostype,
                                name=sos_name,
                                weights=sos_weights)

            # upload lazy constraints
            cpx_linear_advanced = cpx.linear_constraints.advanced
            cpx_lazyct_num = cpx_linear_advanced.get_num_lazy_constraints()
            if cpx_lazyct_num:
                print(
                    "WARNING: found {0} lazy constraints that cannot be uploaded to DOcplex"
                    .format(cpx_lazyct_num))

            mdl.output_level = final_output_level
            if final_checker:
                # need to restore checker
                mdl.set_checker(final_checker)

        except cpx_adapter.CplexError as cpx_e:  # pragma: no cover
            print("* CPLEX error: {0!s} reading file {1}".format(
                cpx_e, filename))
            mdl = None
            if debug_read:
                raise

        except ModelReaderError as mre:  # pragma: no cover
            print("! Model reader error: {0!s} while reading file {1}".format(
                mre, filename))
            mdl = None
            if debug_read:
                raise

        except DOcplexException as doe:  # pragma: no cover
            print("! Internal DOcplex error: {0!s} while reading file {1}".
                  format(doe, filename))
            mdl = None
            if debug_read:
                raise

        # except Exception as any_e:  # pragma: no cover
        #     print("Internal exception raised: {0} msg={1!s} while reading file '{2}'".format(type(any_e), any_e, filename))
        #     mdl = None
        #     if debug_read:
        #         raise

        finally:
            # clean up CPLEX instance...
            cpx.end()

        return mdl
Ejemplo n.º 30
0
    def read_model(self,
                   filename,
                   model_name=None,
                   verbose=False,
                   model_class=None,
                   **kwargs):
        """ Reads a model from a CPLEX export file.

        Accepts all formats exported by CPLEX: LP, SAV, MPS.

        If an error occurs while reading the file, the message of the exception
        is printed and the function returns None.

        Args:
            filename: The file to read.
            model_name: An optional name for the newly created model. If None,
                the model name will be the path basename.
            verbose: An optional flag to print informative messages, default is False.
            model_class: An optional class type; must be a subclass of Model.
                The returned model is built using this model_class and the keyword arguments kwargs, if any.
                By default, the model is class is `Model` (see
            kwargs: A dict of keyword-based arguments that are used when creating the model
                instance.

        Example:
            `m = read_model("c:/temp/foo.mps", model_name="docplex_foo", solver_agent="docloud", output_level=100)`

        Returns:
            An instance of Model, or None if an exception is raised.

        See Also:
            :class:`docplex.mp.model.Model`

        """
        if not Cplex:  # pragma: no cover
            raise RuntimeError(
                "ModelReader.read_model() requires CPLEX runtime.")

        if not os.path.exists(filename):
            raise IOError("* file not found: {0}".format(filename))

        # extract basename
        if model_name:
            name_to_use = model_name
        else:
            basename = os.path.basename(filename)
            dotpos = basename.find(".")
            if dotpos > 0:
                name_to_use = basename[:dotpos]
            else:
                name_to_use = basename

        model_class = model_class or Model

        if 0 == os.stat(filename).st_size:
            print("* file is empty: {0} - exiting".format(filename))
            return model_class(name=name_to_use, **kwargs)

        # print("-> start reading file: {0}".format(filename))
        cpx = self._cplex_read(filename, verbose=verbose)

        if not cpx:  # pragma: no cover
            return None

        range_map = {}
        final_output_level = kwargs.get("output_level", "info")
        debug_read = kwargs.get("debug", False)

        try:
            # force no tck
            if 'checker' in kwargs:
                final_checker = kwargs['checker']
            else:
                final_checker = 'default'
            # build the model with no checker, then restore final_checker in the end.
            kwargs['checker'] = 'off'
            # -------------

            mdl = model_class(name=name_to_use, **kwargs)
            lfactory = mdl._lfactory
            qfactory = mdl._qfactory
            mdl.set_quiet()  # output level set to ERROR
            vartype_cont = mdl.continuous_vartype
            vartype_map = {
                'B': mdl.binary_vartype,
                'I': mdl.integer_vartype,
                'C': mdl.continuous_vartype,
                'S': mdl.semicontinuous_vartype
            }
            # 1 upload variables
            cpx_nb_vars = cpx.variables.get_num()
            cpx_var_names = self._safe_call_get_names(cpx.variables)

            if cpx._is_MIP():
                cpx_vartypes = [
                    vartype_map.get(cpxt, vartype_cont)
                    for cpxt in cpx.variables.get_types()
                ]
            else:
                cpx_vartypes = [vartype_cont] * cpx_nb_vars
            cpx_var_lbs = cpx.variables.get_lower_bounds()
            cpx_var_ubs = cpx.variables.get_upper_bounds()
            # map from cplex variable indices to docplex's
            # use to skip range vars
            # cplex : [x, Rg1, y] -> {0:0, 2: 1}
            var_index_map = {}

            d = 0
            model_varnames = []
            model_lbs = []
            model_ubs = []
            model_types = []
            for v in range(cpx_nb_vars):
                varname = cpx_var_names[v] if cpx_var_names else None

                if varname and varname.startswith("Rg"):
                    # generated var for ranges
                    range_map[v] = self._RangeData(var_index=v,
                                                   var_name=varname,
                                                   ub=cpx_var_ubs[v])
                else:
                    # docplex_var = lfactory.new_var(vartype, lb, ub, varname)
                    var_index_map[v] = d
                    model_varnames.append(varname)
                    model_types.append(cpx_vartypes[v])
                    model_lbs.append(cpx_var_lbs[v])
                    model_ubs.append(cpx_var_ubs[v])
                    d += 1

            # vars
            model_vars = lfactory.new_multitype_var_list(
                d, model_types, model_lbs, model_ubs, model_varnames)

            cpx_var_index_to_docplex = {
                v: model_vars[var_index_map[v]]
                for v in var_index_map.keys()
            }

            # 2. upload linear constraints and ranges (mixed in cplex)
            cpx_linearcts = cpx.linear_constraints
            nb_linear_cts = cpx_linearcts.get_num()
            all_rows = cpx_linearcts.get_rows()
            all_rhs = cpx_linearcts.get_rhs()
            all_senses = cpx_linearcts.get_senses()
            all_range_values = cpx_linearcts.get_range_values()
            cpx_ctnames = self._safe_call_get_names(cpx_linearcts)

            has_range = range_map or any(s == "R" for s in all_senses)
            deferred_cts = []

            for c in range(nb_linear_cts):
                row = all_rows[c]
                sense = all_senses[c]
                rhs = all_rhs[c]
                ctname = cpx_ctnames[c] if cpx_ctnames else None
                range_val = all_range_values[c]

                indices = row.ind
                coefs = row.val
                range_data = None

                if not has_range:
                    expr = mdl._aggregator._scal_prod(
                        (cpx_var_index_to_docplex[idx] for idx in indices),
                        coefs)
                    op = ComparisonType.parse(sense)
                    ct = lfactory._new_binary_constraint(lhs=expr,
                                                         rhs=rhs,
                                                         sense=op)
                    ct.name = ctname
                    deferred_cts.append(ct)

                else:
                    expr = lfactory.linear_expr()
                    rcoef = 1
                    for idx, koef in izip(indices, coefs):
                        var = cpx_var_index_to_docplex.get(idx, None)
                        if var:
                            expr._add_term(var, koef)
                        elif idx in range_map:
                            # this is a range: coeff must be 1 or -1
                            abscoef = koef if koef >= 0 else -koef
                            rcoef = koef
                            assert abscoef == 1, "range var has coef different from 1: {}".format(
                                koef)
                            assert range_data is None, "range_data is not None: {0!s}".format(
                                range_data)  # cannot use two range vars
                            range_data = range_map[idx]
                        else:  # pragma: no cover
                            # this is an internal error.
                            raise ModelReaderError(
                                "ERROR: index not in var map or range map: {0}"
                                .format(idx))

                    if range_data:
                        label = ctname or 'c#%d' % (c + 1)
                        if sense not in "EL":  # pragma: no cover
                            raise ModelReaderError(
                                "{0} range sense is not E: {1!s}".format(
                                    label, sense))
                        if rcoef < 0:  # -1 actually
                            rng_lb = rhs
                            rng_ub = rhs + range_data.ub
                        elif rcoef > 0:  # koef is 1 here
                            rng_lb = rhs - range_data.ub
                            rng_ub = rhs
                        else:  # pragma: no cover
                            raise ModelReaderError(
                                "unexpected range coef: {}".format(rcoef))

                        mdl.add_range(lb=rng_lb,
                                      expr=expr,
                                      ub=rng_ub,
                                      rng_name=ctname)
                    else:
                        if sense == 'R':
                            # range min is rangeval
                            range_lb = rhs
                            range_ub = rhs + range_val
                            mdl.add_range(lb=range_lb,
                                          ub=range_ub,
                                          expr=expr,
                                          rng_name=ctname)
                        else:
                            op = ComparisonType.cplex_ctsense_to_python_op(
                                sense)
                            ct = op(expr, rhs)
                            mdl.add_constraint(ct, ctname)
            if deferred_cts:
                # add constraint as a block
                lfactory._post_constraint_block(posted_cts=deferred_cts)

            # 3. upload Quadratic constraints
            cpx_quadraticcts = cpx.quadratic_constraints
            nb_quadratic_cts = cpx_quadraticcts.get_num()
            all_rhs = cpx_quadraticcts.get_rhs()
            all_linear_nb_non_zeros = cpx_quadraticcts.get_linear_num_nonzeros(
            )
            all_linear_components = cpx_quadraticcts.get_linear_components()
            all_quadratic_nb_non_zeros = cpx_quadraticcts.get_quad_num_nonzeros(
            )
            all_quadratic_components = cpx_quadraticcts.get_quadratic_components(
            )
            all_senses = cpx_quadraticcts.get_senses()
            cpx_ctnames = self._safe_call_get_names(cpx_quadraticcts)

            for c in range(nb_quadratic_cts):
                rhs = all_rhs[c]
                linear_nb_non_zeros = all_linear_nb_non_zeros[c]
                linear_component = all_linear_components[c]
                quadratic_nb_non_zeros = all_quadratic_nb_non_zeros[c]
                quadratic_component = all_quadratic_components[c]
                sense = all_senses[c]
                ctname = cpx_ctnames[c] if cpx_ctnames else None

                if linear_nb_non_zeros > 0:
                    indices, coefs = linear_component.unpack()
                    linexpr = mdl._aggregator._scal_prod(
                        (cpx_var_index_to_docplex[idx] for idx in indices),
                        coefs)
                else:
                    linexpr = None

                if quadratic_nb_non_zeros > 0:
                    qfactory = mdl._qfactory
                    ind1, ind2, coefs = quadratic_component.unpack()
                    quads = qfactory.term_dict_type()
                    for idx1, idx2, coef in izip(ind1, ind2, coefs):
                        quads[VarPair(cpx_var_index_to_docplex[idx1],
                                      cpx_var_index_to_docplex[idx2])] = coef

                else:  # pragma: no cover
                    # should not happen, but who knows
                    quads = None

                quad_expr = mdl._aggregator._quad_factory.new_quad(
                    quads=quads, linexpr=linexpr, safe=True)
                op = ComparisonType.cplex_ctsense_to_python_op(sense)
                ct = op(quad_expr, rhs)
                mdl.add_constraint(ct, ctname)

            # 4. upload indicators
            cpx_indicators = cpx.indicator_constraints
            nb_indicators = cpx_indicators.get_num()
            all_ind_names = self._safe_call_get_names(cpx_indicators)

            all_ind_bvars = cpx_indicators.get_indicator_variables()
            all_ind_rhs = cpx_indicators.get_rhs()
            all_ind_linearcts = cpx_indicators.get_linear_components()
            all_ind_senses = cpx_indicators.get_senses()
            all_ind_complemented = cpx_indicators.get_complemented()
            lfactory = mdl._lfactory
            for i in range(nb_indicators):
                ind_bvar = all_ind_bvars[i]
                ind_name = all_ind_names[i] if all_ind_names else None
                ind_rhs = all_ind_rhs[i]
                ind_linear = all_ind_linearcts[i]  # SparsePair(ind, val)
                ind_sense = all_ind_senses[i]
                ind_complemented = all_ind_complemented[i]
                # 1 . check the bvar is ok
                ind_bvar = cpx_var_index_to_docplex[ind_bvar]
                # each var appears once
                ind_linexpr = self._build_linear_expr_from_sparse_pair(
                    lfactory, cpx_var_index_to_docplex, ind_linear)
                op = ComparisonType.cplex_ctsense_to_python_op(ind_sense)
                ind_ct = op(ind_linexpr, ind_rhs)
                indct = lfactory.new_indicator_constraint(ind_bvar,
                                                          ind_ct,
                                                          active_value=1 -
                                                          ind_complemented,
                                                          name=ind_name)
                mdl.add(indct)

            # 5. upload Piecewise linear constraints
            try:
                cpx_pwl = cpx.pwl_constraints
                cpx_pwl_defs = cpx_pwl.get_definitions()
                pwl_fallback_names = [""] * cpx_pwl.get_num()
                cpx_pwl_names = self._safe_call_get_names(
                    cpx_pwl, pwl_fallback_names)
                for (vary_idx, varx_idx, preslope, postslope, breakx,
                     breaky), pwl_name in izip(cpx_pwl_defs, cpx_pwl_names):
                    varx = cpx_var_index_to_docplex.get(varx_idx, None)
                    vary = cpx_var_index_to_docplex.get(vary_idx, None)
                    breakxy = [(brkx, brky)
                               for brkx, brky in zip(breakx, breaky)]
                    pwl_func = mdl.piecewise(preslope,
                                             breakxy,
                                             postslope,
                                             name=pwl_name)
                    pwl_expr = mdl._lfactory.new_pwl_expr(
                        pwl_func,
                        varx,
                        0,
                        add_counter_suffix=False,
                        resolve=False)
                    pwl_expr._f_var = vary
                    pwl_expr._ensure_resolved()

            except AttributeError:  # pragma: no cover
                pass  # Do not check for PWLs if Cplex version does not support them

            # 6. upload objective
            cpx_obj = cpx.objective
            cpx_sense = cpx_obj.get_sense()

            cpx_all_lin_obj_coeffs = cpx_obj.get_linear()
            # noinspection PyPep8
            all_obj_vars = []
            all_obj_coefs = []

            for v in range(cpx_nb_vars):
                if v in cpx_var_index_to_docplex:
                    obj_coeff = cpx_all_lin_obj_coeffs[v]
                    all_obj_coefs.append(obj_coeff)
                    all_obj_vars.append(cpx_var_index_to_docplex[v])
                    #  obj_expr._add_term(idx_to_var_map[v], cpx_all_obj_coeffs[v])
            obj_expr = mdl._aggregator._scal_prod(all_obj_vars, all_obj_coefs)

            if cpx_obj.get_num_quadratic_variables() > 0:
                cpx_all_quad_cols_coeffs = cpx_obj.get_quadratic()
                quads = qfactory.term_dict_type()
                for v, col_coefs in izip(cpx_var_index_to_docplex,
                                         cpx_all_quad_cols_coeffs):
                    var1 = cpx_var_index_to_docplex[v]
                    indices, coefs = col_coefs.unpack()
                    for idx, coef in izip(indices, coefs):
                        vp = VarPair(var1, cpx_var_index_to_docplex[idx])
                        quads[vp] = quads.get(vp, 0) + coef / 2

                obj_expr += qfactory.new_quad(quads=quads, linexpr=None)

            obj_expr += cpx.objective.get_offset()
            is_maximize = cpx_sense == ObjSense.maximize

            if is_maximize:
                mdl.maximize(obj_expr)
            else:
                mdl.minimize(obj_expr)

            # upload sos
            cpx_sos = cpx.SOS
            cpx_sos_num = cpx_sos.get_num()
            if cpx_sos_num > 0:
                cpx_sos_types = cpx_sos.get_types()
                cpx_sos_indices = cpx_sos.get_sets()
                cpx_sos_names = cpx_sos.get_names()
                if not cpx_sos_names:
                    cpx_sos_names = [None] * cpx_sos_num
                for sostype, sos_sparse, sos_name in izip(
                        cpx_sos_types, cpx_sos_indices, cpx_sos_names):
                    sos_var_indices = sos_sparse.ind
                    isostype = int(sostype)
                    sos_vars = [
                        cpx_var_index_to_docplex[var_ix]
                        for var_ix in sos_var_indices
                    ]
                    mdl.add_sos(dvars=sos_vars,
                                sos_arg=isostype,
                                name=sos_name)

            # upload lazy constraints
            cpx_linear_advanced = cpx.linear_constraints.advanced
            cpx_lazyct_num = cpx_linear_advanced.get_num_lazy_constraints()
            if cpx_lazyct_num:
                print(
                    "WARNING: found {0} lazy constraints that cannot be uploaded to DOcplex"
                    .format(cpx_lazyct_num))

            mdl.output_level = final_output_level
            if final_checker:
                # need to restore checker
                mdl.set_checker(final_checker)

        except CplexError as cpx_e:  # pragma: no cover
            print("* CPLEX error: {0!s} reading file {1}".format(
                cpx_e, filename))
            mdl = None
            if debug_read:
                raise

        except ModelReaderError as mre:  # pragma: no cover
            print("! Model reader error: {0!s} while reading file {1}".format(
                mre, filename))
            mdl = None
            if debug_read:
                raise

        except DOcplexException as doe:  # pragma: no cover
            print("! Internal DOcplex error: {0!s} while reading file {1}".
                  format(doe, filename))
            mdl = None
            if debug_read:
                raise

        except Exception as any_e:  # pragma: no cover
            print("Internal exception raised: {0!s} while reading file {1}".
                  format(any_e, filename))
            mdl = None
            if debug_read:
                raise

        finally:
            # clean up CPLEX instance...
            del cpx

        return mdl