# --------------------------------------------------------------------------
# File: _anno.py
# ---------------------------------------------------------------------------
# Licensed Materials - Property of IBM
# 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
# Copyright IBM Corporation 2008, 2024. All Rights Reserved.
#
# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with
# IBM Corp.
# ------------------------------------------------------------------------
"""Annotation API"""
from ._baseinterface import BaseInterface
from . import _procedural as _proc
from . import _aux_functions as _aux
from . import _constants
from ..constant_class import ConstantClass
[docs]
class AnnotationObjectType(ConstantClass):
"""Constants defining annotation object types."""
objective = _constants.CPX_ANNOTATIONOBJ_OBJ
variable = _constants.CPX_ANNOTATIONOBJ_COL
row = _constants.CPX_ANNOTATIONOBJ_ROW
sos_constraint = _constants.CPX_ANNOTATIONOBJ_SOS
indicator_constraint = _constants.CPX_ANNOTATIONOBJ_IND
quadratic_constraint = _constants.CPX_ANNOTATIONOBJ_QC
[docs]
class AnnotationInterface(BaseInterface):
"""Methods for adding, querying, and modifying annotations."""
object_type = AnnotationObjectType()
"""See `AnnotationObjectType()` """
def _getnumobjtype(self, objtype):
switcher = {
# NB: For now, it is documented that multiobj is not supported.
self.object_type.objective: lambda env, lp: 1,
self.object_type.variable: _proc.getnumcols,
self.object_type.row: _proc.getnumrows,
self.object_type.sos_constraint: _proc.getnumsos,
self.object_type.indicator_constraint: _proc.getnumindconstrs,
self.object_type.quadratic_constraint: _proc.getnumqconstrs
}
func = switcher[objtype]
return func(self._env._e, self._cplex._lp)
[docs]
class LongAnnotationInterface(AnnotationInterface):
"""Methods for adding, querying, and modifying long annotations."""
benders_annotation = _constants.CPX_BENDERS_ANNOTATION
"""String constant for the name of the Benders annotation."""
benders_mastervalue = _constants.CPX_BENDERS_MASTERVALUE
"""Default value for the Benders master partition."""
[docs]
def __init__(self, cpx):
"""Creates a new LongAnnotationInterface.
The long annotation interface is exposed by the top-level `Cplex`
class as `Cplex.long_annotations`. This constructor is not meant
to be used externally.
"""
super().__init__(cplex=cpx, getindexfunc=_proc.getlongannoindex)
[docs]
def get_num(self):
"""Returns the number of long annotations in the problem.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> c.long_annotations.get_num()
0
>>> idx = c.long_annotations.add('ann1', 0)
>>> c.long_annotations.get_num()
1
"""
return _proc.getnumlonganno(self._env._e, self._cplex._lp)
[docs]
def add(self, name, defval):
"""Adds an annotation to the problem.
name: the name of the annotation.
defval: the default value for annotation objects.
Returns the index of the added annotation.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.long_annotations.add(name='ann1', defval=0)
>>> c.long_annotations.get_num()
1
"""
# For Python 2.7, int() will automatically upconvert to long
# if necessary. For 3.x, there is only int (they have been
# unified).
def _add(name, defval):
_proc.newlonganno(
self._env._e, self._cplex._lp, name, int(defval))
return self._add_single(self.get_num, _add, name, defval)
[docs]
def delete(self, *args):
"""Deletes long annotations from the problem.
There are four forms by which long_annotations.delete may be
called.
long_annotations.delete()
deletes all long annotations from the problem.
long_annotations.delete(i)
i must be an annotation name or index. Deletes the long
annotation whose index or name is i.
long_annotations.delete(seq)
seq must be a sequence of annotation names or indices.
Deletes the long annotations with names or indices contained
within s. Equivalent to [long_annotations.delete(i) for i in s].
long_annotations.delete(begin, end)
begin and end must be annotation indices or annotation names.
Deletes the long annotations with indices between begin and
end, inclusive of end. Equivalent to
long_annotations.delete(range(begin, end + 1)). This will give
the best performance when deleting batches of long annotations.
See CPXdellongannotations in the Callable Library Reference
Manual for more detail.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.long_annotations.add('ann1', 0)
>>> c.long_annotations.get_num()
1
>>> c.long_annotations.delete(idx)
>>> c.long_annotations.get_num()
0
"""
def _delete(begin, end=None):
_proc.dellonganno(self._env._e, self._cplex._lp, begin, end)
_aux.delete_set_by_range(_delete, self._conv, self.get_num(), *args)
[docs]
def get_names(self, *args):
"""Returns the names of a set of long annotations.
May be called by four forms.
long_annotations.get_names()
return the names of all long annotations in the problem.
long_annotations.get_names(i)
i must be an annotation name or index. Returns the name of
long annotation i.
long_annotations.get_names(seq)
seq must be a sequence of annotation names or indices.
Returns the names of long annotations with names or indices in
s. Equivalent to
[long_annotations.get_names(i) for i in s]
long_annotations.get_names(begin, end)
begin and end must be annotation indices or annotation names.
Returns the names of long annotations with indices between
begin and end, inclusive of end. Equivalent to
long_annotations.get_names(range(begin, end + 1))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> [c.long_annotations.add('ann{0}'.format(i), i)
... for i in range(1, 6)]
[0, 1, 2, 3, 4]
>>> c.long_annotations.get_names()
['ann1', 'ann2', 'ann3', 'ann4', 'ann5']
>>> c.long_annotations.get_names(0)
'ann1'
>>> c.long_annotations.get_names([0, 2, 4])
['ann1', 'ann3', 'ann5']
>>> c.long_annotations.get_names(1, 3)
['ann2', 'ann3', 'ann4']
"""
def _get_names(idx):
return _proc.getlongannoname(
self._env._e, self._cplex._lp, idx)
return _aux.apply_freeform_one_arg(
_get_names, self._conv, self.get_num(), args)
[docs]
def get_default_values(self, *args):
"""Returns the default value of a set of long annotations.
May be called by four forms.
long_annotations.get_default_values()
return the default values of all long annotations in the
problem.
long_annotations.get_default_values(i)
i must be an annotation name or index. Returns the default
value of long annotation i.
long_annotations.get_default_values(seq)
seq must be a sequence of annotation names or indices.
Returns the default values of long annotations with names or
indices in s. Equivalent to
[long_annotations.get_default_values(i) for i in s]
long_annotations.get_default_values(begin, end)
begin and end must be annotation indices or annotation names.
Returns the default values of long annotations with indices
between begin and end, inclusive of end. Equivalent to
long_annotations.get_default_values(list(range(begin, end + 1)))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx1 = c.long_annotations.add(name='ann1', defval=0)
>>> idx2 = c.long_annotations.add(name='ann2', defval=1)
>>> c.long_annotations.get_default_values()
[0, 1]
"""
def _getdefval(idx):
return _proc.getlongannodefval(
self._env._e, self._cplex._lp, idx)
return _aux.apply_freeform_one_arg(
_getdefval, self._conv, self.get_num(), args)
[docs]
def set_values(self, idx, objtype, *args):
"""Sets the values for objects in the specified long annotation.
idx: the long annotation index or name.
objtype: the annotation object type.
Can be called by two forms:
long_annotations.set_values(idx, objtype, i, val)
i must be a name or index. Changes the long annotation value
of the object identified by i.
long_annotations.set_values(idx, objtype, seq)
seq is a sequence of pairs (i, val) as described above.
Changes the long annotation values for the specified objects.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.long_annotations.add('ann1', 0)
>>> objtype = c.long_annotations.object_type.objective
>>> c.long_annotations.set_values(idx, objtype, 0, 1)
>>> c.long_annotations.get_values(idx, objtype, 0)
1
>>> indices = c.variables.add(names=['v1', 'v2', 'v3'])
>>> objtype = c.long_annotations.object_type.variable
>>> c.long_annotations.set_values(idx, objtype,
... [(i, 1) for i in indices])
>>> c.long_annotations.get_values(idx, objtype)
[1, 1, 1]
"""
def _set_values(ind, val):
_proc.setlonganno(self._env._e, self._cplex._lp,
self._conv(idx), objtype, ind, val)
_aux.apply_pairs(_set_values, self._conv, *args)
[docs]
def get_values(self, idx, objtype, *args):
"""Returns the long annotation values for the specified objects.
idx: the long annotation index or name.
objtype: the annotation object type.
Can be called by four forms:
long_annotations.get_values(idx, objtype)
return the values of all objects for a given annotation.
long_annotations.get_values(idx, objtype, i)
i must be a name or index. Returns the long annotation value
of the object identified by i.
long_annotations.get_values(idx, objtype, seq)
seq is a sequence of object names or indices. Returns the
long annotation values for the specified objects. Equivalent
to
[long_annotations.get_values(idx, objtype, i) for i in seq]
long_annotations.get_values(idx, objtype, begin, end)
begin and end must be object indices or object names. Returns
the long annotation values of objects with indices between
begin and end, inclusive of end. Equivalent to
long_annotations.get_values(range(begin, end + 1))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.long_annotations.add('ann1', 0)
>>> objtype = c.long_annotations.object_type.objective
>>> c.long_annotations.set_values(idx, objtype, 0, 1)
>>> c.long_annotations.get_values(idx, objtype, 0)
1
>>> indices = c.variables.add(names=['v1', 'v2', 'v3'])
>>> objtype = c.long_annotations.object_type.variable
>>> c.long_annotations.set_values(idx, objtype,
... [(i, 1) for i in indices])
>>> c.long_annotations.get_values(idx, objtype, list(indices))
[1, 1, 1]
"""
def _get_values(begin, end=self._getnumobjtype(objtype) - 1):
return _proc.getlonganno(self._env._e, self._cplex._lp,
self._conv(idx), objtype,
begin, end)
return _aux.apply_freeform_two_args(
_get_values, self._conv, args)
[docs]
class DoubleAnnotationInterface(AnnotationInterface):
"""Methods for adding, querying, and modifying double annotations."""
[docs]
def __init__(self, cpx):
"""Creates a new DoubleAnnotationInterface.
The double annotation interface is exposed by the top-level
`Cplex` class as `Cplex.double_annotations`. This constructor is
not meant to be used externally.
"""
super().__init__(cplex=cpx, getindexfunc=_proc.getdblannoindex)
[docs]
def get_num(self):
"""Returns the number of double annotations in the problem.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> c.double_annotations.get_num()
0
>>> idx = c.double_annotations.add('ann1', 0.0)
>>> c.double_annotations.get_num()
1
"""
return _proc.getnumdblanno(self._env._e, self._cplex._lp)
[docs]
def add(self, name, defval):
"""Adds an annotation to the problem.
name: the name of the annotation.
defval: the default value for annotation objects.
Returns the index of the added annotation.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.double_annotations.add(name='ann1', defval=0.0)
>>> c.double_annotations.get_num()
1
"""
def _add(name, defval):
_proc.newdblanno(
self._env._e, self._cplex._lp, name, float(defval))
return self._add_single(self.get_num, _add, name, defval)
[docs]
def delete(self, *args):
"""Deletes double annotations from the problem.
There are four forms by which double_annotations.delete may be
called.
double_annotations.delete()
deletes all double annotations from the problem.
double_annotations.delete(i)
i must be an annotation name or index. Deletes the double
annotation whose index or name is i.
double_annotations.delete(seq)
seq must be a sequence of annotation names or indices.
Deletes the double annotations with names or indices contained
within s. Equivalent to
[double_annotations.delete(i) for i in s].
double_annotations.delete(begin, end)
begin and end must be annotation indices or annotation names.
Deletes the double annotations with indices between begin and
end, inclusive of end. Equivalent to
double_annotations.delete(range(begin, end + 1)). This will
give the best performance when deleting batches of double
annotations.
See CPXdeldblannotations in the Callable Library Reference Manual
for more detail.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.double_annotations.add('ann1', 0.0)
>>> c.double_annotations.get_num()
1
>>> c.double_annotations.delete(idx)
>>> c.double_annotations.get_num()
0
"""
def _delete(begin, end=None):
_proc.deldblanno(self._env._e, self._cplex._lp, begin, end)
_aux.delete_set_by_range(_delete, self._conv, self.get_num(), *args)
[docs]
def get_names(self, *args):
"""Returns the names of a set of double annotations.
May be called by four forms.
double_annotations.get_names()
return the names of all double annotations in the problem.
double_annotations.get_names(i)
i must be an annotation name or index. Returns the name of
double annotation i.
double_annotations.get_names(seq)
seq must be a sequence of annotation names or indices.
Returns the names of double annotations with names or indices
in s. Equivalent to
[double_annotations.get_names(i) for i in s]
double_annotations.get_names(begin, end)
begin and end must be annotation indices or annotation names.
Returns the names of double annotations with indices between
begin and end, inclusive of end. Equivalent to
double_annotations.get_names(range(begin, end + 1))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> [c.double_annotations.add('ann{0}'.format(i), i)
... for i in range(1, 6)]
[0, 1, 2, 3, 4]
>>> c.double_annotations.get_names()
['ann1', 'ann2', 'ann3', 'ann4', 'ann5']
>>> c.double_annotations.get_names(0)
'ann1'
>>> c.double_annotations.get_names([0, 2, 4])
['ann1', 'ann3', 'ann5']
>>> c.double_annotations.get_names(1, 3)
['ann2', 'ann3', 'ann4']
"""
def _get_names(idx):
return _proc.getdblannoname(
self._env._e, self._cplex._lp, idx)
return _aux.apply_freeform_one_arg(
_get_names, self._conv, self.get_num(), args)
[docs]
def get_default_values(self, *args):
"""Returns the default value of a set of double annotations.
May be called by four forms.
double_annotations.get_default_values()
return the default values of all double annotations in the
problem.
double_annotations.get_default_values(i)
i must be an annotation name or index. Returns the default
value of double annotation i.
double_annotations.get_default_values(seq)
seq must be a sequence of annotation names or indices.
Returns the default values of double annotations with names or
indices in s. Equivalent to
[double_annotations.get_default_values(i) for i in s]
double_annotations.get_default_values(begin, end)
begin and end must be annotation indices or annotation names.
Returns the default values of double annotations with indices
between begin and end, inclusive of end. Equivalent to
double_annotations.get_default_values(list(range(begin, end + 1)))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx1 = c.double_annotations.add(name='ann1', defval=0.0)
>>> idx2 = c.double_annotations.add(name='ann2', defval=1.0)
>>> c.double_annotations.get_default_values()
[0.0, 1.0]
"""
def _getdefval(idx):
return _proc.getdblannodefval(
self._env._e, self._cplex._lp, idx)
return _aux.apply_freeform_one_arg(
_getdefval, self._conv, self.get_num(), args)
[docs]
def set_values(self, idx, objtype, *args):
"""Sets the values for objects in the specified double annotation.
idx: the double annotation index or name.
objtype: the annotation object type.
Can be called by two forms:
double_annotations.set_values(idx, objtype, i, val)
i must be a name or index. Changes the double annotation
value of the object identified by i.
double_annotations.set_values(idx, objtype, seq)
seq is a sequence of pairs (i, val) as described above.
Changes the double annotation values for the specified
objects.
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.double_annotations.add('ann1', 0.0)
>>> objtype = c.double_annotations.object_type.objective
>>> c.double_annotations.set_values(idx, objtype, 0, 1.0)
>>> c.double_annotations.get_values(idx, objtype, 0)
1.0
>>> indices = c.variables.add(names=['v1', 'v2', 'v3'])
>>> objtype = c.double_annotations.object_type.variable
>>> c.double_annotations.set_values(idx, objtype,
... [(i, 1.0) for i in indices])
>>> c.double_annotations.get_values(idx, objtype)
[1.0, 1.0, 1.0]
"""
def _set_values(ind, val):
_proc.setdblanno(self._env._e, self._cplex._lp,
self._conv(idx), objtype, ind, val)
_aux.apply_pairs(_set_values, self._conv, *args)
[docs]
def get_values(self, idx, objtype, *args):
"""Returns the double annotation values for the specified objects.
idx: the double annotation index or name.
objtype: the annotation object type.
Can be called by four forms:
double_annotations.get_values(idx, objtype)
return the values of all objects for a given annotation.
double_annotations.get_values(idx, objtype, i)
i must be a name or index. Returns the double annotation
value of the object identified by i.
double_annotations.get_values(idx, objtype, seq)
seq is a sequence of object names or indices. Returns the
double annotation values for the specified objects.
Equivalent to
[double_annotations.get_values(idx, objtype, i) for i in seq]
double_annotations.get_values(idx, objtype, begin, end)
begin and end must be object indices or object names. Returns
the double annotation values of objects with indices between
begin and end, inclusive of end. Equivalent to
double_annotations.get_values(range(begin, end + 1))
Example usage:
>>> import cplex
>>> c = cplex.Cplex()
>>> idx = c.double_annotations.add('ann1', 0.0)
>>> objtype = c.double_annotations.object_type.objective
>>> c.double_annotations.set_values(idx, objtype, 0, 1.0)
>>> c.double_annotations.get_values(idx, objtype, 0)
1.0
>>> indices = c.variables.add(names=['v1', 'v2', 'v3'])
>>> objtype = c.double_annotations.object_type.variable
>>> c.double_annotations.set_values(idx, objtype,
... [(i, 1.0) for i in indices])
>>> c.double_annotations.get_values(idx, objtype, list(indices))
[1.0, 1.0, 1.0]
"""
def _get_values(begin, end=self._getnumobjtype(objtype) - 1):
return _proc.getdblanno(self._env._e, self._cplex._lp,
self._conv(idx), objtype,
begin, end)
return _aux.apply_freeform_two_args(
_get_values, self._conv, args)