Source code for docplex.mp.sosvarset

# --------------------------------------------------------------------------
# Source file provided under Apache License, Version 2.0, January 2004,
# http://www.apache.org/licenses/
# (c) Copyright IBM Corp. 2015, 2022
# --------------------------------------------------------------------------
from docplex.mp.basic import IndexableObject, _AbstractBendersAnnotated
from docplex.mp.constants import CplexScope


[docs]class SOSVariableSet(IndexableObject, _AbstractBendersAnnotated): ''' This class models :index:`Special Ordered Sets` (SOS) of decision variables. An SOS has a type (SOS1, SOS2) and an ordered list of variables. This class is not meant to be instantiated directly. To create an SOS, use the :func:`docplex.mp.model.Model.add_sos`, :func:`docplex.mp.model.Model.add_sos1`, and :func:`docplex.mp.model.Model.add_sos2` methods in Model. ''' __slots__ = ('_sos_type', '_variables', '_weights') def __init__(self, model, variable_sequence, sos_type, weights=None, name=None): IndexableObject.__init__(self, model, name) self._sos_type = sos_type self._variables = variable_sequence[:] # copy sequence self._weights = None self._set_weights(weights) def _set_weights(self, new_weights): if new_weights is None: self._weights = None else: checker = self._model._checker checked_weights = checker.typecheck_num_seq(new_weights) weight_list = list(checked_weights) nb_vars = len(self._variables) if len(weight_list) != nb_vars: self._model.fatal("Expecting {0} SOS weights, a list with size {1} was passed", nb_vars, len(weight_list)) # check weights are unique def _find_duplicate(wlist_): wset_ = set() for w in wlist_: if w in wset_: return w else: wset_.add(w) return None setof_weights = set(weight_list) if len(setof_weights) != nb_vars: dupw = _find_duplicate(weight_list) self._model.fatal("SOS weights must be unique, duplicate weight: {}", dupw) self._weights = weight_list[:] @property def cplex_scope(self): return CplexScope.SOS_SCOPE @property def sos_type(self): ''' This property returns the type of the SOS variable set. :returns: An enumerated value of type :class:`docplex.mp.constants.SOSType`. ''' return self._sos_type
[docs] def iter_variables(self): ''' Iterates over the variables in the SOS. Note that the sequence of variables cannot be empty. Returns: An iterator. ''' return iter(self._variables)
def __len__(self): ''' This special method makes it possible to call the `len()` function on an SOS, returning the number of variables in the SOS. Returns: The number of variables in the SOS. ''' return len(self._variables) @property def size(self): return len(self._variables) def __getitem__(self, item): ''' This special method enables the [] operator on special ordered sets, Args: item: an integer from 0 to the number of variables -1 Returns: The variable in the set at location <item> ''' return self._variables[item]
[docs] def to_string(self): ''' Converts an SOS of variables to a string. This function is used by the `__str__()` method Returns: A string representation of the SOS of variables. ''' vars_s = ', '.join(str(v) for v in self.iter_variables()) name_s = '(\'%s\')' % self._name if self._name else '' return '{0!s}{2}[{1:s}]'.format(self._sos_type.name, vars_s, name_s)
@property def weights(self): return self.get_cplex_weights() # @weights.setter # def weights(self, new_weights): # self._set_weights(new_weights) def get_cplex_weights(self): self_weights = self._weights return self_weights if self_weights is not None else self._model._get_cached_sos_weights(self.size) def as_constraint(self): mdl = self._model lfactory = mdl.lfactory lhs = mdl.sum_vars(self._variables) rhs = lfactory.constant_expr(self.sos_type.value) return lfactory.new_binary_constraint(lhs, "le", rhs, name=self.name) def __str__(self): ''' Redefine the standard __str__ method of Python objects to customize string conversion. Returns: A string representation of the SOS of variables. ''' return self.to_string() def __repr__(self): name_s = ', name=\'%s\'' % self._name if self._name else '' vars_s = ', '.join(str(v) for v in self.iter_variables()) repr_s = 'docplex.mp.SOSVariableSet(type={0}{1}{2})'.format(self.sos_type.value, vars_s, name_s) return repr_s def copy(self, target_model, var_mapping): copy_variables = [var_mapping[v] for v in self.iter_variables()] return SOSVariableSet(model=target_model, variable_sequence=copy_variables, sos_type=self.sos_type, weights=self._weights, name=self.name) @property def benders_annotation(self): """ This property is used to get or set the Benders annotation of a SOS variable set. The value of the annotation must be a positive integer """ return self.get_benders_annotation() @benders_annotation.setter def benders_annotation(self, new_anno): self.set_benders_annotation(new_anno)