def __init__(self): """Creates a new BaseInterface. This class is not meant to be instantiated directly nor used externally. """ if type(self) == BaseInterface: raise TypeError("BaseInterface must be sub-classed") self._index = NameIndex()
def __init__(self, varindex): """Creates a new LinearConstraintInterface. The linear constraints interface is exposed by the top-level `OptimizationProblem` class as `OptimizationProblem.linear_constraints`. This constructor is not meant to be used externally. """ super(LinearConstraintInterface, self).__init__() self._rhs = [] self._senses = [] self._range_values = [] self._names = [] self._lin_expr = [] self._index = NameIndex() self._varindex = varindex
def __init__(self): """Creates a new VariablesInterface. The variables interface is exposed by the top-level `OptimizationProblem` class as `OptimizationProblem.variables`. This constructor is not meant to be used externally. """ super(VariablesInterface, self).__init__() self._names = [] self._lb = [] self._ub = [] self._types = [] # self._obj = [] # self._columns = [] self._index = NameIndex()
def test_name_index2(self): a = NameIndex() a.build(['1', '2', '3']) self.assertEqual(a.convert('1'), 0) self.assertListEqual(a.convert(), [0, 1, 2]) self.assertListEqual(a.convert('1', '3'), [0, 1, 2]) self.assertListEqual(a.convert('1', '2'), [0, 1])
class LinearConstraintInterface(BaseInterface): """Methods for adding, modifying, and querying linear constraints.""" def __init__(self, varindex): """Creates a new LinearConstraintInterface. The linear constraints interface is exposed by the top-level `OptimizationProblem` class as `OptimizationProblem.linear_constraints`. This constructor is not meant to be used externally. """ super(LinearConstraintInterface, self).__init__() self._rhs = [] self._senses = [] self._range_values = [] self._names = [] self._lin_expr = [] self._index = NameIndex() self._varindex = varindex def get_num(self): """Returns the number of linear constraints. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c1", "c2", "c3"]) >>> op.linear_constraints.get_num() 3 """ return len(self._names) def add(self, lin_expr=None, senses="", rhs=None, range_values=None, names=None): """Adds linear constraints to the problem. linear_constraints.add accepts the keyword arguments lin_expr, senses, rhs, range_values, and names. If more than one argument is specified, all arguments must have the same length. lin_expr may be either a list of SparsePair instances or a matrix in list-of-lists format. Note The entries of lin_expr must not contain duplicate indices. If an entry of lin_expr references a variable more than once, either by index, name, or a combination of index and name, an exception will be raised. senses must be either a list of single-character strings or a string containing the senses of the linear constraints. Each entry must be one of 'G', 'L', 'E', and 'R', indicating greater-than, less-than, equality, and ranged constraints, respectively. rhs is a list of floats, specifying the righthand side of each linear constraint. range_values is a list of floats, specifying the difference between lefthand side and righthand side of each linear constraint. If range_values[i] > 0 (zero) then the constraint i is defined as rhs[i] <= rhs[i] + range_values[i]. If range_values[i] < 0 (zero) then constraint i is defined as rhs[i] + range_value[i] <= a*x <= rhs[i]. names is a list of strings. Returns an iterator containing the indices of the added linear constraints. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.variables.add(names = ["x1", "x2", "x3"]) >>> indices = op.linear_constraints.add(\ lin_expr = [SparsePair(ind = ["x1", "x3"], val = [1.0, -1.0]),\ SparsePair(ind = ["x1", "x2"], val = [1.0, 1.0]),\ SparsePair(ind = ["x1", "x2", "x3"], val = [-1.0] * 3),\ SparsePair(ind = ["x2", "x3"], val = [10.0, -2.0])],\ senses = ["E", "L", "G", "R"],\ rhs = [0.0, 1.0, -1.0, 2.0],\ range_values = [0.0, 0.0, 0.0, -10.0],\ names = ["c0", "c1", "c2", "c3"]) >>> op.linear_constraints.get_rhs() [0.0, 1.0, -1.0, 2.0] """ arg_list = init_list_args(lin_expr, senses, rhs, range_values, names) arg_lengths = [len(x) for x in arg_list] if len(arg_lengths) == 0: return range(0) max_length = max(arg_lengths) for arg_length in arg_lengths: if arg_length > 0 and arg_length != max_length: raise QiskitOptimizationError( "inconsistent arguments in linear_constraints.add().") if max_length == 0: return range(len(self._names), len(self._names)) assert max_length > 0 if not rhs: rhs = [0.0] * max_length self._rhs.extend(rhs) if not senses: senses = "E" * max_length self._senses.extend(senses) if not range_values: range_values = [0.0] * max_length self._range_values.extend(range_values) if not names: names = [ "c" + str(cnt) for cnt in range(len(self._names), len(self._names) + max_length) ] self._names.extend(names) self._index.build(self._names) if not lin_expr: lin_expr = [SparsePair()] * max_length for sp in lin_expr: lin_expr_dict = {} if isinstance(sp, SparsePair): zip_iter = zip(sp.ind, sp.val) elif isinstance(sp, Sequence) and len(sp) == 2: zip_iter = zip(sp[0], sp[1]) else: raise QiskitOptimizationError( 'Invalid lin_expr: {}'.format(lin_expr)) for i, val in zip_iter: i = self._varindex(i) if i in lin_expr_dict: raise QiskitOptimizationError( 'Variables should only appear once in linear constraint.' ) lin_expr_dict[i] = val self._lin_expr.append(lin_expr_dict) return range(len(self._names) - max_length, len(self._names)) def delete(self, *args): """Removes linear constraints from the problem. There are four forms by which linear_constraints.delete may be called. linear_constraints.delete() deletes all linear constraints from the problem. linear_constraints.delete(i) i must be a linear constraint name or index. Deletes the linear constraint whose index or name is i. linear_constraints.delete(s) s must be a sequence of linear constraint names or indices. Deletes the linear constraints with names or indices contained within s. Equivalent to [linear_constraints.delete(i) for i in s]. linear_constraints.delete(begin, end) begin and end must be linear constraint indices or linear constraint names. Deletes the linear constraints with indices between begin and end, inclusive of end. Equivalent to linear_constraints.delete(range(begin, end + 1)). This will give the best performance when deleting batches of linear constraints. See CPXdelrows in the Callable Library Reference Manual for more detail. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names=[str(i) for i in range(10)]) >>> op.linear_constraints.get_num() 10 >>> op.linear_constraints.delete(8) >>> op.linear_constraints.get_names() ['0', '1', '2', '3', '4', '5', '6', '7', '9'] >>> op.linear_constraints.delete("1", 3) >>> op.linear_constraints.get_names() ['0', '4', '5', '6', '7', '9'] >>> op.linear_constraints.delete([2, "0", 5]) >>> op.linear_constraints.get_names() ['4', '6', '7'] >>> op.linear_constraints.delete() >>> op.linear_constraints.get_names() [] """ if len(args) == 0: # Delete all self._rhs = [] self._senses = [] self._names = [] self._lin_expr = [] self._range_values = [] self._index = NameIndex() keys = self._index.convert(*args) if isinstance(keys, int): keys = [keys] for i in sorted(keys, reverse=True): del self._rhs[i] del self._senses[i] del self._names[i] del self._lin_expr[i] del self._range_values[i] self._index.build(self._names) def set_rhs(self, *args): """Sets the righthand side of a set of linear constraints. There are two forms by which linear_constraints.set_rhs may be called. linear_constraints.set_rhs(i, rhs) i must be a row name or index and rhs must be a real number. Sets the righthand side of the row whose index or name is i to rhs. linear_constraints.set_rhs(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, rhs) pairs, each of which consists of a row name or index and a real number. Sets the righthand side of the specified rows to the corresponding values. Equivalent to [linear_constraints.set_rhs(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> op.linear_constraints.get_rhs() [0.0, 0.0, 0.0, 0.0] >>> op.linear_constraints.set_rhs("c1", 1.0) >>> op.linear_constraints.get_rhs() [0.0, 1.0, 0.0, 0.0] >>> op.linear_constraints.set_rhs([("c3", 2.0), (2, -1.0)]) >>> op.linear_constraints.get_rhs() [0.0, 1.0, -1.0, 2.0] """ def _set(i, v): self._rhs[self._index.convert(i)] = v self._setter(_set, *args) def set_names(self, *args): """Sets the name of a linear constraint or set of linear constraints. There are two forms by which linear_constraints.set_names may be called. linear_constraints.set_names(i, name) i must be a linear constraint name or index and name must be a string. linear_constraints.set_names(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, name) pairs, each of which consists of a linear constraint name or index and a string. Sets the name of the specified linear constraints to the corresponding strings. Equivalent to [linear_constraints.set_names(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> op.linear_constraints.set_names("c1", "second") >>> op.linear_constraints.get_names(1) 'second' >>> op.linear_constraints.set_names([("c3", "last"), (2, "middle")]) >>> op.linear_constraints.get_names() ['c0', 'second', 'middle', 'last'] """ def _set(i, v): self._names[self._index.convert(i)] = v self._setter(_set, *args) def set_senses(self, *args): """Sets the sense of a linear constraint or set of linear constraints. There are two forms by which linear_constraints.set_senses may be called. linear_constraints.set_senses(i, type) i must be a row name or index and name must be a single-character string. linear_constraints.set_senses(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, sense) pairs, each of which consists of a row name or index and a single-character string. Sets the sense of the specified rows to the corresponding strings. Equivalent to [linear_constraints.set_senses(pair[0], pair[1]) for pair in seq_of_pairs]. The senses of the constraints must be one of 'G', 'L', 'E', and 'R', indicating greater-than, less-than, equality, and ranged constraints, respectively. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> op.linear_constraints.get_senses() ['E', 'E', 'E', 'E'] >>> op.linear_constraints.set_senses("c1", "G") >>> op.linear_constraints.get_senses(1) 'G' >>> op.linear_constraints.set_senses([("c3", "L"), (2, "R")]) >>> op.linear_constraints.get_senses() ['E', 'G', 'R', 'L'] """ def _set(i, v): v = v.upper() if v in ["G", "L", "E", "R"]: self._senses[self._index.convert(i)] = v else: raise QiskitOptimizationError("Wrong sense {}".format(v)) self._setter(_set, *args) def set_linear_components(self, *args): """Sets a linear constraint or set of linear constraints. There are two forms by which this method may be called: linear_constraints.set_linear_components(i, lin) i must be a row name or index and lin must be either a SparsePair or a pair of sequences, the first of which consists of variable names or indices, the second of which consists of floats. linear_constraints.set_linear_components(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, lin) pairs, each of which consists of a row name or index and a vector as described above. Sets the specified rows to the corresponding vector. Equivalent to [linear_constraints.set_linear_components(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> indices = op.variables.add(names = ["x0", "x1"]) >>> op.linear_constraints.set_linear_components("c0", [["x0"], [1.0]]) >>> op.linear_constraints.get_rows("c0") SparsePair(ind = [0], val = [1.0]) >>> op.linear_constraints.set_linear_components([ ("c3", SparsePair(ind = ["x1"], val = [-1.0])),\ (2, [[0, 1], [-2.0, 3.0]])]) >>> op.linear_constraints.get_rows() [SparsePair(ind = [0], val = [1.0]), SparsePair(ind = [], val = []), SparsePair(ind = [0, 1], val = [-2.0, 3.0]), SparsePair(ind = [1], val = [-1.0])] """ def _set(i, v): if isinstance(v, SparsePair): zip_iter = zip(v.ind, v.val) elif isinstance(v, Sequence) and len(v) == 2: zip_iter = zip(v[0], v[1]) else: raise QiskitOptimizationError( "Wrong linear expression. A SparsePair is expected: {}". format(v)) i = self._index.convert(i) for j, w in zip_iter: j = self._varindex(j) if w == 0: if j in self._lin_expr[i]: del self._lin_expr[i][j] else: self._lin_expr[i][j] = w self._setter(_set, *args) def set_range_values(self, *args): """Sets the range values for a set of linear constraints. That is, this method sets the lefthand side (lhs) for each ranged constraint of the form lhs <= lin_expr <= rhs. The range values are a list of floats, specifying the difference between lefthand side and righthand side of each linear constraint. If range_values[i] > 0 (zero) then the constraint i is defined as rhs[i] <= rhs[i] + range_values[i]. If range_values[i] < 0 (zero) then constraint i is defined as rhs[i] + range_value[i] <= a*x <= rhs[i]. Note that changing the range values will not change the sense of a constraint; you must call the method set_senses() of the class LinearConstraintInterface to change the sense of a ranged row if the previous range value was 0 (zero) and the constraint sense was not 'R'. Similarly, changing the range coefficient from a nonzero value to 0 (zero) will not change the constraint sense from 'R" to "E"; an additional call of setsenses() is required to accomplish that. There are two forms by which linear_constraints.set_range_values may be called. linear_constraints.set_range_values(i, range) i must be a row name or index and range must be a real number. Sets the range value of the row whose index or name is i to range. linear_constraints.set_range_values(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, range) pairs, each of which consists of a row name or index and a real number. Sets the range values for the specified rows to the corresponding values. Equivalent to [linear_constraints.set_range_values(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> op.linear_constraints.set_range_values("c1", 1.0) >>> op.linear_constraints.get_range_values() [0.0, 1.0, 0.0, 0.0] >>> op.linear_constraints.set_range_values([("c3", 2.0), (2, -1.0)]) >>> op.linear_constraints.get_range_values() [0.0, 1.0, -1.0, 2.0] """ def _set(i, v): self._range_values[self._index.convert(i)] = v # TODO: raise QiskitOptimizationError("Wrong range!") self._setter(_set, *args) def set_coefficients(self, *args): """Sets individual coefficients of the linear constraint matrix. There are two forms by which linear_constraints.set_coefficients may be called. linear_constraints.set_coefficients(row, col, val) row and col must be indices or names of a linear constraint and variable, respectively. The corresponding coefficient is set to val. linear_constraints.set_coefficients(coefficients) coefficients must be a list of (row, col, val) triples as described above. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"]) >>> indices = op.variables.add(names = ["x0", "x1"]) >>> op.linear_constraints.set_coefficients("c0", "x1", 1.0) >>> op.linear_constraints.get_rows(0) SparsePair(ind = [1], val = [1.0]) >>> op.linear_constraints.set_coefficients([("c2", "x0", 2.0),\ ("c2", "x1", -1.0)]) >>> op.linear_constraints.get_rows("c2") SparsePair(ind = [0, 1], val = [2.0, -1.0]) """ if len(args) == 3: arg_list = [args] elif len(args) == 1 and isinstance(args[0], Sequence): arg_list = args[0] else: raise QiskitOptimizationError("Invalid arguments {}".format(args)) for i, j, v in arg_list: i = self._index.convert(i) j = self._varindex(j) if v == 0: if j in self._lin_expr[i]: del self._lin_expr[i][j] else: self._lin_expr[i][j] = v def get_rhs(self, *args): """Returns the righthand side of constraints from the problem. Can be called by four forms. linear_constraints.get_rhs() return the righthand side of all linear constraints from the problem. linear_constraints.get_rhs(i) i must be a linear constraint name or index. Returns the righthand side of the linear constraint whose index or name is i. linear_constraints.get_rhs(s) s must be a sequence of linear constraint names or indices. Returns the righthand side of the linear constraints with indices the members of s. Equivalent to [linear_constraints.get_rhs(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(rhs = [1.5 * i for i in range(10)],\ names = [str(i) for i in range(10)]) >>> op.linear_constraints.get_num() 10 >>> op.linear_constraints.get_rhs(8) 12.0 >>> op.linear_constraints.get_rhs([2,"0",5]) [3.0, 0.0, 7.5] >>> op.linear_constraints.get_rhs() [0.0, 1.5, 3.0, 4.5, 6.0, 7.5, 9.0, 10.5, 12.0, 13.5] """ def _get(i): return self._rhs[i] if len(args) == 0: return copy.deepcopy(self._rhs) keys = self._index.convert(*args) return self._getter(_get, keys) def get_senses(self, *args): """Returns the senses of constraints from the problem. Can be called by four forms. linear_constraints.get_senses() return the senses of all linear constraints from the problem. linear_constraints.get_senses(i) i must be a linear constraint name or index. Returns the sense of the linear constraint whose index or name is i. linear_constraints.get_senses(s) s must be a sequence of linear constraint names or indices. Returns the senses of the linear constraints with indices the members of s. Equivalent to [linear_constraints.get_senses(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add( ... senses=["E", "G", "L", "R"], ... names=[str(i) for i in range(4)]) >>> op.linear_constraints.get_num() 4 >>> op.linear_constraints.get_senses(1) 'G' >>> op.linear_constraints.get_senses("1",3) ['G', 'L', 'R'] >>> op.linear_constraints.get_senses([2,"0",1]) ['L', 'E', 'G'] >>> op.linear_constraints.get_senses() ['E', 'G', 'L', 'R'] """ def _get(i): return self._senses[i] if len(args) == 0: return copy.deepcopy(self._senses) keys = self._index.convert(*args) return self._getter(_get, keys) def get_range_values(self, *args): """Returns the range values of linear constraints from the problem. That is, this method returns the lefthand side (lhs) for each ranged constraint of the form lhs <= lin_expr <= rhs. This method makes sense only for ranged constraints, that is, linear constraints of sense 'R'. The range values are a list of floats, specifying the difference between lefthand side and righthand side of each linear constraint. If range_values[i] > 0 (zero) then the constraint i is defined as rhs[i] <= rhs[i] + range_values[i]. If range_values[i] < 0 (zero) then constraint i is defined as rhs[i] + range_value[i] <= a*x <= rhs[i]. Can be called by four forms. linear_constraints.get_range_values() return the range values of all linear constraints from the problem. linear_constraints.get_range_values(i) i must be a linear constraint name or index. Returns the range value of the linear constraint whose index or name is i. linear_constraints.get_range_values(s) s must be a sequence of linear constraint names or indices. Returns the range values of the linear constraints with indices the members of s. Equivalent to [linear_constraints.get_range_values(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(\ range_values = [1.5 * i for i in range(10)],\ senses = ["R"] * 10,\ names = [str(i) for i in range(10)]) >>> op.linear_constraints.get_num() 10 >>> op.linear_constraints.get_range_values(8) 12.0 >>> op.linear_constraints.get_range_values("1",3) [1.5, 3.0, 4.5] >>> op.linear_constraints.get_range_values([2,"0",5]) [3.0, 0.0, 7.5] >>> op.linear_constraints.get_range_values() [0.0, 1.5, 3.0, 4.5, 6.0, 7.5, 9.0, 10.5, 12.0, 13.5] """ def _get(i): return self._range_values[i] if len(args) == 0: return copy.deepcopy(self._range_values) keys = self._index.convert(*args) return self._getter(_get, keys) def get_coefficients(self, *args): """Returns coefficients by row, column coordinates. There are three forms by which linear_constraints.get_coefficients may be called. Without arguments, it returns a dictionary indexed first by constraints and second by variables. With two arguments, linear_constraints.get_coefficients(row, col) returns the coefficient. With one argument, linear_constraints.get_coefficients(sequence_of_pairs) returns a list of coefficients. >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.variables.add(names = ["x0", "x1"]) >>> indices = op.linear_constraints.add(\ names = ["c0", "c1"],\ lin_expr = [[[1], [1.0]], [[0, 1], [2.0, -1.0]]]) >>> op.linear_constraints.get_coefficients("c0", "x1") 1.0 >>> op.linear_constraints.get_coefficients([("c1", "x0"), ("c1", "x1")]) [2.0, -1.0] """ def _get(args): i, j = args return self._lin_expr[i].get(j, 0) if len(args) == 0: return copy.deepcopy(self._lin_expr) elif len(args) == 1 and isinstance(args[0], Sequence): i, j = zip(*args[0]) i = self._index.convert(i) j = self._varindex(j) return self._getter(_get, *zip(i, j)) elif len(args) == 2: i, j = args i = self._index.convert(i) j = self._varindex(j) return _get((i, j)) else: raise QiskitOptimizationError( "Wrong number of arguments. Please use 2 or one list of pairs: {}" .format(args)) def get_rows(self, *args): """Returns a set of rows of the linear constraint matrix. Returns a list of SparsePair instances or a single SparsePair instance, depending on the form by which it was called. There are four forms by which linear_constraints.get_rows may be called. linear_constraints.get_rows() return the entire linear constraint matrix. linear_constraints.get_rows(i) i must be a row name or index. Returns the ith row of the linear constraint matrix. linear_constraints.get_rows(s) s must be a sequence of row names or indices. Returns the rows of the linear constraint matrix indexed by the members of s. Equivalent to [linear_constraints.get_rows(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.variables.add(names = ["x1", "x2", "x3"]) >>> indices = op.linear_constraints.add(\ names = ["c0", "c1", "c2", "c3"],\ lin_expr = [SparsePair(ind = ["x1", "x3"], val = [1.0, -1.0]),\ SparsePair(ind = ["x1", "x2"], val = [1.0, 1.0]),\ SparsePair(ind = ["x1", "x2", "x3"], val = [-1.0] * 3),\ SparsePair(ind = ["x2", "x3"], val = [10.0, -2.0])]) >>> op.linear_constraints.get_rows(0) SparsePair(ind = [0, 2], val = [1.0, -1.0]) >>> op.linear_constraints.get_rows(["c2", 0]) [SparsePair(ind = [0, 1, 2], val = [-1.0, -1.0, -1.0]), SparsePair(ind = [0, 2], val = [1.0, -1.0])] >>> op.linear_constraints.get_rows() [ SparsePair(ind = [0, 2], val = [1.0, -1.0]), SparsePair(ind = [0, 1], val = [1.0, 1.0]), SparsePair(ind = [0, 1, 2], val = [-1.0, -1.0, -1.0]), SparsePair(ind = [1, 2], val = [10.0, -2.0]) ] """ def _get(i): keys = list(self._lin_expr[i].keys()) keys.sort() return SparsePair(keys, [self._lin_expr[i][k] for k in keys]) keys = self._index.convert(*args) return self._getter(_get, keys) def get_num_nonzeros(self): """Returns the number of nonzeros in the linear constraint matrix. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.variables.add(names = ["x1", "x2", "x3"]) >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2", "c3"],\ lin_expr = [SparsePair(ind = ["x1", "x3"], val = [1.0, -1.0]),\ SparsePair(ind = ["x1", "x2"], val = [1.0, 1.0]),\ SparsePair(ind = ["x1", "x2", "x3"], val = [-1.0] * 3),\ SparsePair(ind = ["x2", "x3"], val = [10.0, -2.0])]) >>> op.linear_constraints.get_num_nonzeros() 9 """ nnz = 0 for c in self._lin_expr: for e in c.values(): if e != 0.0: nnz += 1 return nnz def get_names(self, *args): """Returns the names of linear constraints from the problem. There are four forms by which linear_constraints.get_names may be called. linear_constraints.get_names() return the names of all linear constraints from the problem. linear_constraints.get_names(i) i must be a linear constraint index. Returns the name of row i. linear_constraints.get_names(s) s must be a sequence of row indices. Returns the names of the linear constraints with indices the members of s. Equivalent to [linear_constraints.get_names(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c" + str(i) for i in range(10)]) >>> op.linear_constraints.get_num() 10 >>> op.linear_constraints.get_names(8) 'c8' >>> op.linear_constraints.get_names([2, 0, 5]) ['c2', 'c0', 'c5'] >>> op.linear_constraints.get_names() ['c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9'] """ def _get(i): return self._names[i] if len(args) == 0: return self._names keys = self._index.convert(*args) return self._getter(_get, keys) def get_histogram(self): raise NotImplementedError("histrogram is not implemented")
def delete(self, *args): """Removes linear constraints from the problem. There are four forms by which linear_constraints.delete may be called. linear_constraints.delete() deletes all linear constraints from the problem. linear_constraints.delete(i) i must be a linear constraint name or index. Deletes the linear constraint whose index or name is i. linear_constraints.delete(s) s must be a sequence of linear constraint names or indices. Deletes the linear constraints with names or indices contained within s. Equivalent to [linear_constraints.delete(i) for i in s]. linear_constraints.delete(begin, end) begin and end must be linear constraint indices or linear constraint names. Deletes the linear constraints with indices between begin and end, inclusive of end. Equivalent to linear_constraints.delete(range(begin, end + 1)). This will give the best performance when deleting batches of linear constraints. See CPXdelrows in the Callable Library Reference Manual for more detail. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = qiskit.optimization.OptimizationProblem() >>> indices = op.linear_constraints.add(names=[str(i) for i in range(10)]) >>> op.linear_constraints.get_num() 10 >>> op.linear_constraints.delete(8) >>> op.linear_constraints.get_names() ['0', '1', '2', '3', '4', '5', '6', '7', '9'] >>> op.linear_constraints.delete("1", 3) >>> op.linear_constraints.get_names() ['0', '4', '5', '6', '7', '9'] >>> op.linear_constraints.delete([2, "0", 5]) >>> op.linear_constraints.get_names() ['4', '6', '7'] >>> op.linear_constraints.delete() >>> op.linear_constraints.get_names() [] """ if len(args) == 0: # Delete all self._rhs = [] self._senses = [] self._names = [] self._lin_expr = [] self._range_values = [] self._index = NameIndex() keys = self._index.convert(*args) if isinstance(keys, int): keys = [keys] for i in sorted(keys, reverse=True): del self._rhs[i] del self._senses[i] del self._names[i] del self._lin_expr[i] del self._range_values[i] self._index.build(self._names)
def test_name_index3(self): a = NameIndex() with self.assertRaises(QiskitOptimizationError): a.convert({}) with self.assertRaises(QiskitOptimizationError): a.convert(1, 2, 3)
class BaseInterface(object): """Common methods for sub-interfaces within Qiskit Optimization.""" def __init__(self): """Creates a new BaseInterface. This class is not meant to be instantiated directly nor used externally. """ if type(self) == BaseInterface: raise TypeError("BaseInterface must be sub-classed") self._index = NameIndex() def get_indices(self, *name) -> Union[int, List[int]]: """Converts from names to indices. If name is a string, get_indices returns the index of the object with that name. If no such object exists, an exception is raised. If name is a sequence of strings, get_indices returns a list of the indices corresponding to the strings in name. Equivalent to map(self.get_indices, name). See `NameIndex.convert` for details. If the subclass does not provide an index function (i.e., the interface is not indexed), then a NotImplementedError is raised. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names=["a", "b"]) >>> op.variables.get_indices("a") 0 >>> op.variables.get_indices(["a", "b"]) [0, 1] """ return self._index.convert(*name) @staticmethod def _setter(setfunc: Callable[[Union[str, int], Any], None], *args) -> None: """A generic setter method Args: setfunc(index, val): A setter function of two parameters: `index` and `val`. Since `index` can be a string, users need to convert it into an appropriate index by applying `NameIndex.convert`. *args: A pair of index and value or a list of pairs of index and value. `setfunc` is invoked with `args`. Returns: None """ # check for all elements in args whether they are types if len(args) == 1 and \ all(isinstance(pair, Sequence) and len(pair) == 2 for pair in args[0]): for pair in args[0]: setfunc(*pair) elif len(args) == 2: setfunc(*args) else: raise QiskitOptimizationError("Invalid arguments: {}".format(args)) @staticmethod def _getter(getfunc: Callable[[int], Any], *args) -> Any: """A generic getter method Args: getfunc(index): A getter function with an argument `index`. `index` should be already converted by `NameIndex.convert`. *args: A single index or a list of indices. `getfunc` is invoked with args. Returns: if `args` is a single index, this returns a single value genereted by `getfunc`. If `args` is a list of indices, this returns a list of values. """ if len(args) == 0: raise QiskitOptimizationError('Empty arguments should be handled in the caller') if len(args) == 1: if isinstance(args[0], Sequence): args = args[0] else: return getfunc(args[0]) return [getfunc(k) for k in args]
class VariablesInterface(BaseInterface): """Methods for adding, querying, and modifying variables. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names = ["x0", "x1", "x2"]) >>> # default values for lower_bounds are 0.0 >>> op.variables.get_lower_bounds() [0.0, 0.0, 0.0] >>> # values can be set either one at a time or many at a time >>> op.variables.set_lower_bounds(0, 1.0) >>> op.variables.set_lower_bounds([("x1", -1.0), (2, 3.0)]) >>> # values can be queried as a range >>> op.variables.get_lower_bounds(0, "x1") [1.0, -1.0] >>> # values can be queried as a sequence in arbitrary order >>> op.variables.get_lower_bounds(["x1", "x2", 0]) [-1.0, 3.0, 1.0] >>> # can query the number of variables >>> op.variables.get_num() 3 >>> op.variables.set_types(0, op.variables.type.binary) >>> op.variables.get_num_binary() 1 """ type = VarTypes() """See `VarTypes()` """ def __init__(self): """Creates a new VariablesInterface. The variables interface is exposed by the top-level `OptimizationProblem` class as `OptimizationProblem.variables`. This constructor is not meant to be used externally. """ super(VariablesInterface, self).__init__() self._names = [] self._lb = [] self._ub = [] self._types = [] # self._obj = [] # self._columns = [] self._index = NameIndex() def get_num(self): """Returns the number of variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.continuous, t.binary, t.integer]) >>> op.variables.get_num() 3 """ return len(self._names) def get_num_continuous(self): """Returns the number of continuous variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.continuous, t.binary, t.integer]) >>> op.variables.get_num_continuous() 1 """ return self._types.count(VarTypes.continuous) def get_num_integer(self): """Returns the number of integer variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.continuous, t.binary, t.integer]) >>> op.variables.get_num_integer() 1 """ return self._types.count(VarTypes.integer) def get_num_binary(self): """Returns the number of binary variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.semi_continuous, t.binary, t.integer]) >>> op.variables.get_num_binary() 1 """ return self._types.count(VarTypes.binary) def get_num_semicontinuous(self): """Returns the number of semi-continuous variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.semi_continuous, t.semi_integer, t.semi_integer]) >>> op.variables.get_num_semicontinuous() 1 """ return self._types.count(VarTypes.semi_continuous) def get_num_semiinteger(self): """Returns the number of semi-integer variables in the problem. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.semi_continuous, t.semi_integer, t.semi_integer]) >>> op.variables.get_num_semiinteger() 2 """ return self._types.count(VarTypes.semi_integer) def add(self, obj=None, lb=None, ub=None, types="", names=None, columns=None): """Adds variables and related data to the problem. variables.add accepts the keyword arguments obj, lb, ub, types, names, and columns. If more than one argument is specified, all arguments must have the same length. Note `obj` and `columns` have not been supported yet. Use `objective` and `linear_constraint` instead. Args: obj: a list of floats specifying the linear objective coefficients of the variables. lb: a list of floats specifying the lower bounds on the variables. ub: a list of floats specifying the upper bounds on the variables. types: must be either a list of single-character strings or a string containing the types of the variables. Note If types is specified, the problem type will be a MIP, even if all variables are specified to be continuous. names: a list of strings. columns: may be either a list of sparse vectors or a matrix in list-of-lists format. Note The entries of columns must not contain duplicate indices. If an entry of columns references a row more than once, either by index, name, or a combination of index and name, an exception will be raised. Returns: an iterator containing the indices of the added variables. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> from cplex import SparsePair, infinity >>> op = OptimizationProblem() >>> indices = op.linear_constraints.add(names = ["c0", "c1", "c2"]) >>> indices = op.variables.add(obj = [1.0, 2.0, 3.0],\ types = [op.variables.type.integer] * 3) >>> indices = op.variables.add(obj = [1.0, 2.0, 3.0],\ lb = [-1.0, 1.0, 0.0],\ ub = [100.0, infinity, infinity],\ types = [op.variables.type.integer] * 3,\ names = ["0", "1", "2"],\ columns = [SparsePair(ind = ['c0', 2], val = [1.0, -1.0]),\ [['c2'],[2.0]],\ SparsePair(ind = [0, 1], val = [3.0, 4.0])]) >>> op.variables.get_lower_bounds() [0.0, 0.0, 0.0, -1.0, 1.0, 0.0] >>> op.variables.get_cols("1") SparsePair(ind = [2], val = [2.0]) """ if obj: raise QiskitOptimizationError( "Please use ObjectiveInterface instead of obj.") if columns: raise QiskitOptimizationError( "Please use LinearConstraintInterface instead of columns.") arg_list = init_list_args(lb, ub, types, names) arg_lengths = [len(x) for x in arg_list] if len(arg_lengths) == 0: return range(0) max_length = max(arg_lengths) for arg_length in arg_lengths: if arg_length > 0 and arg_length != max_length: raise QiskitOptimizationError("inconsistent arguments") if not lb: lb = [0.0] * max_length self._lb.extend(lb) if not ub: ub = [infinity] * max_length self._ub.extend(ub) if not types: types = [VarTypes.continuous] * max_length for i, t in enumerate(types): if t == VarTypes.binary: self._ub[i] = 1.0 self._types.extend(types) if not names: names = [ "x" + str(cnt) for cnt in range(len(self._names), len(self._names) + max_length) ] self._names.extend(names) self._index.build(self._names) return range(len(self._names) - max_length, len(self._names)) def delete(self, *args): """Deletes variables from the problem. There are four forms by which variables.delete may be called. variables.delete() deletes all variables from the problem. variables.delete(i) i must be a variable name or index. Deletes the variable whose index or name is i. variables.delete(s) s must be a sequence of variable names or indices. Deletes the variables with names or indices contained within s. Equivalent to [variables.delete(i) for i in s]. variables.delete(begin, end) begin and end must be variable indices or variable names. Deletes the variables with indices between begin and end, inclusive of end. Equivalent to variables.delete(range(begin, end + 1)). This will give the best performance when deleting batches of variables. See CPXdelcols in the Callable Library Reference Manual for more detail. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names=[str(i) for i in range(10)]) >>> op.variables.get_num() 10 >>> op.variables.delete(8) >>> op.variables.get_names() ['0', '1', '2', '3', '4', '5', '6', '7', '9'] >>> op.variables.delete("1", 3) >>> op.variables.get_names() ['0', '4', '5', '6', '7', '9'] >>> op.variables.delete([2, "0", 5]) >>> op.variables.get_names() ['4', '6', '7'] >>> op.variables.delete() >>> op.variables.get_names() [] """ def _delete(i): del self._names[i] del self._ub[i] del self._lb[i] del self._types[i] if len(args) == 0: # Delete all self._names = [] self._ub = [] self._lb = [] self._types = [] # self._columns = [] self._index = NameIndex() keys = self._index.convert(*args) if isinstance(keys, int): keys = [keys] for i in sorted(keys, reverse=True): _delete(i) self._index.build(self._names) def set_lower_bounds(self, *args): """Sets the lower bound for a variable or set of variables. There are two forms by which variables.set_lower_bounds may be called. variables.set_lower_bounds(i, lb) i must be a variable name or index and lb must be a real number. Sets the lower bound of the variable whose index or name is i to lb. variables.set_lower_bounds(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, lb) pairs, each of which consists of a variable name or index and a real number. Sets the lower bound of the specified variables to the corresponding values. Equivalent to [variables.set_lower_bounds(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names = ["x0", "x1", "x2"]) >>> op.variables.set_lower_bounds(0, 1.0) >>> op.variables.get_lower_bounds() [1.0, 0.0, 0.0] >>> op.variables.set_lower_bounds([(2, 3.0), ("x1", -1.0)]) >>> op.variables.get_lower_bounds() [1.0, -1.0, 3.0] """ def _set(i, v): self._lb[self._index.convert(i)] = v self._setter(_set, *args) def set_upper_bounds(self, *args): """Sets the upper bound for a variable or set of variables. There are two forms by which variables.set_upper_bounds may be called. variables.set_upper_bounds(i, ub) i must be a variable name or index and ub must be a real number. Sets the upper bound of the variable whose index or name is i to ub. variables.set_upper_bounds(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, ub) pairs, each of which consists of a variable name or index and a real number. Sets the upper bound of the specified variables to the corresponding values. Equivalent to [variables.set_upper_bounds(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names = ["x0", "x1", "x2"]) >>> op.variables.set_upper_bounds(0, 1.0) >>> op.variables.set_upper_bounds([("x1", 10.0), (2, 3.0)]) >>> op.variables.get_upper_bounds() [1.0, 10.0, 3.0] """ def _set(i, v): self._ub[self._index.convert(i)] = v self._setter(_set, *args) def set_names(self, *args): """Sets the name of a variable or set of variables. There are two forms by which variables.set_names may be called. variables.set_names(i, name) i must be a variable name or index and name must be a string. variables.set_names(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, name) pairs, each of which consists of a variable name or index and a string. Sets the name of the specified variables to the corresponding strings. Equivalent to [variables.set_names(pair[0], pair[1]) for pair in seq_of_pairs]. >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(types = [t.continuous, t.binary, t.integer]) >>> op.variables.set_names(0, "first") >>> op.variables.set_names([(2, "third"), (1, "second")]) >>> op.variables.get_names() ['first', 'second', 'third'] """ def _set(i, v): self._names[self._index.convert(i)] = v self._setter(_set, *args) self._index.build(self._names) def set_types(self, *args): """Sets the type of a variable or set of variables. There are two forms by which variables.set_types may be called. variables.set_types(i, type) i must be a variable name or index and name must be a single-character string. variables.set_types(seq_of_pairs) seq_of_pairs must be a list or tuple of (i, type) pairs, each of which consists of a variable name or index and a single-character string. Sets the type of the specified variables to the corresponding strings. Equivalent to [variables.set_types(pair[0], pair[1]) for pair in seq_of_pairs]. Note If the types are set, the problem will be treated as a MIP, even if all variable types are continuous. >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names = [str(i) for i in range(5)]) >>> op.variables.set_types(0, op.variables.type.continuous) >>> op.variables.set_types([("1", op.variables.type.integer),\ ("2", op.variables.type.binary),\ ("3", op.variables.type.semi_continuous),\ ("4", op.variables.type.semi_integer)]) >>> op.variables.get_types() ['C', 'I', 'B', 'S', 'N'] >>> op.variables.type[op.variables.get_types(0)] 'continuous' """ def _set(i, v): if v not in [ CPX_CONTINUOUS, CPX_BINARY, CPX_INTEGER, CPX_SEMICONT, CPX_SEMIINT ]: raise QiskitOptimizationError( "Second argument must be a string, as per VarTypes constants." ) self._types[self._index.convert(i)] = v self._setter(_set, *args) def get_lower_bounds(self, *args): """Returns the lower bounds on variables from the problem. There are four forms by which variables.get_lower_bounds may be called. variables.get_lower_bounds() return the lower bounds on all variables from the problem. variables.get_lower_bounds(i) i must be a variable name or index. Returns the lower bound on the variable whose index or name is i. variables.get_lower_bounds(s) s must be a sequence of variable names or indices. Returns the lower bounds on the variables with indices the members of s. Equivalent to [variables.get_lower_bounds(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(lb = [1.5 * i for i in range(10)],\ names = [str(i) for i in range(10)]) >>> op.variables.get_num() 10 >>> op.variables.get_lower_bounds(8) 12.0 >>> op.variables.get_lower_bounds("1",3) [1.5, 3.0, 4.5] >>> op.variables.get_lower_bounds([2,"0",5]) [3.0, 0.0, 7.5] >>> op.variables.get_lower_bounds() [0.0, 1.5, 3.0, 4.5, 6.0, 7.5, 9.0, 10.5, 12.0, 13.5] """ def _get(i): return self._lb[i] if len(args) == 0: return copy.deepcopy(self._lb) keys = self._index.convert(*args) return self._getter(_get, keys) def get_upper_bounds(self, *args): """Returns the upper bounds on variables from the problem. There are four forms by which variables.get_upper_bounds may be called. variables.get_upper_bounds() return the upper bounds on all variables from the problem. variables.get_upper_bounds(i) i must be a variable name or index. Returns the upper bound on the variable whose index or name is i. variables.get_upper_bounds(s) s must be a sequence of variable names or indices. Returns the upper bounds on the variables with indices the members of s. Equivalent to [variables.get_upper_bounds(i) for i in s] variables.get_upper_bounds(begin, end) begin and end must be variable indices or variable names. Returns the upper bounds on the variables with indices between begin and end, inclusive of end. Equivalent to variables.get_upper_bounds(range(begin, end + 1)). >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(ub = [(1.5 * i) + 1.0 for i in range(10)],\ names = [str(i) for i in range(10)]) >>> op.variables.get_num() 10 >>> op.variables.get_upper_bounds(8) 13.0 >>> op.variables.get_upper_bounds("1",3) [2.5, 4.0, 5.5] >>> op.variables.get_upper_bounds([2,"0",5]) [4.0, 1.0, 8.5] >>> op.variables.get_upper_bounds() [1.0, 2.5, 4.0, 5.5, 7.0, 8.5, 10.0, 11.5, 13.0, 14.5] """ def _get(i): return self._ub[i] if len(args) == 0: return copy.deepcopy(self._ub) keys = self._index.convert(*args) return self._getter(_get, keys) def get_names(self, *args): """Returns the names of variables from the problem. There are four forms by which variables.get_names may be called. variables.get_names() return the names of all variables from the problem. variables.get_names(i) i must be a variable index. Returns the name of variable i. variables.get_names(s) s must be a sequence of variable indices. Returns the names of the variables with indices the members of s. Equivalent to [variables.get_names(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names = ['x' + str(i) for i in range(10)]) >>> op.variables.get_num() 10 >>> op.variables.get_names(8) 'x8' >>> op.variables.get_names(1,3) ['x1', 'x2', 'x3'] >>> op.variables.get_names([2,0,5]) ['x2', 'x0', 'x5'] >>> op.variables.get_names() ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9'] """ def _get(i): return self._names[i] if len(args) == 0: return copy.deepcopy(self._names) keys = self._index.convert(*args) return self._getter(_get, keys) def get_types(self, *args): """Returns the types of variables from the problem. There are four forms by which variables.types may be called. variables.types() return the types of all variables from the problem. variables.types(i) i must be a variable name or index. Returns the type of the variable whose index or name is i. variables.types(s) s must be a sequence of variable names or indices. Returns the types of the variables with indices the members of s. Equivalent to [variables.get_types(i) for i in s] >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> t = op.variables.type >>> indices = op.variables.add(names = [str(i) for i in range(5)],\ types = [t.continuous, t.integer,\ t.binary, t.semi_continuous, t.semi_integer]) >>> op.variables.get_num() 5 >>> op.variables.get_types(3) 'S' >>> op.variables.get_types(1,3) ['I', 'B', 'S'] >>> op.variables.get_types([2,0,4]) ['B', 'C', 'N'] >>> op.variables.get_types() ['C', 'I', 'B', 'S', 'N'] """ def _get(i): return self._types[i] if len(args) == 0: return copy.deepcopy(self._types) keys = self._index.convert(*args) return self._getter(_get, keys) def get_cols(self, *args): raise NotImplementedError( "Please use LinearConstraintInterface instead.") def get_obj(self, *args): raise NotImplementedError("Please use ObjectiveInterface instead.")
def delete(self, *args): """Deletes variables from the problem. There are four forms by which variables.delete may be called. variables.delete() deletes all variables from the problem. variables.delete(i) i must be a variable name or index. Deletes the variable whose index or name is i. variables.delete(s) s must be a sequence of variable names or indices. Deletes the variables with names or indices contained within s. Equivalent to [variables.delete(i) for i in s]. variables.delete(begin, end) begin and end must be variable indices or variable names. Deletes the variables with indices between begin and end, inclusive of end. Equivalent to variables.delete(range(begin, end + 1)). This will give the best performance when deleting batches of variables. See CPXdelcols in the Callable Library Reference Manual for more detail. Example usage: >>> from qiskit.optimization import OptimizationProblem >>> op = OptimizationProblem() >>> indices = op.variables.add(names=[str(i) for i in range(10)]) >>> op.variables.get_num() 10 >>> op.variables.delete(8) >>> op.variables.get_names() ['0', '1', '2', '3', '4', '5', '6', '7', '9'] >>> op.variables.delete("1", 3) >>> op.variables.get_names() ['0', '4', '5', '6', '7', '9'] >>> op.variables.delete([2, "0", 5]) >>> op.variables.get_names() ['4', '6', '7'] >>> op.variables.delete() >>> op.variables.get_names() [] """ def _delete(i): del self._names[i] del self._ub[i] del self._lb[i] del self._types[i] if len(args) == 0: # Delete all self._names = [] self._ub = [] self._lb = [] self._types = [] # self._columns = [] self._index = NameIndex() keys = self._index.convert(*args) if isinstance(keys, int): keys = [keys] for i in sorted(keys, reverse=True): _delete(i) self._index.build(self._names)