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.
'''
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._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))
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)
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):
self_weights = self._weights
return self_weights if self_weights is not None else list(range(1, len(self) + 1))
@weights.setter
def weights(self, new_weights):
self._set_weights(new_weights)
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)