Source code for eqc_models.combinatorics.setcover
- r"""
- SetCoverModel solves the mathematical programming problem
- $$
- \mathrm{minimize}_x \sum_{x_i:X_i \in X} c_i x_i
- $$
- Subject to
- $$
- \sum_{i:a\in X_i} x_j \geq 1 \, \forall a \in A}
- $$$
- and 
- $$
- x_i \in \{0, 1\} \forall {x_i: X_i \in X}
- $$
- Where $S$ is a set of all elements, $X$ is a collection of sets $X_i$, and the union of all is equal to $S$. 
- """
- from typing import List
- import numpy as np
- from eqc_models.base import ConstrainedQuadraticModel
- [docs]
- class SetCoverModel(ConstrainedQuadraticModel):
-     """
-     Parameters
-     -------------
-     subsets : List
-         List of sets where the union of all sets is S
-     weights : List
-         List of weights where each weight is the cost of choosing the subset
-         corresponding to the index of the weight.
-     >>> X = [set(['A', 'B']), set(['B', 'C']), set(['C'])]
-     >>> weights = [2, 2, 1]
-     >>> model = SetCoverModel(X, weights)
-     >>> model.penalty_multiplier = 2
-     >>> from eqc_models.solvers import Dirac3IntegerCloudSolver
-     >>> solver = Dirac3IntegerCloudSolver()
-     >>> response = solver.solve(model, relaxation_schedule=1, num_samples=5) #doctest: +ELLIPSIS
-     20...
-     >>> solutions = response["results"]["solutions"]
-     >>> solutions[0]
-     [1, 0, 1, 0, 0, 0]
-     >>> model.decode(solutions[0])
-     [{'B', 'A'}, {'C'}]
-     """
-     def __init__(self, subsets, weights):
-         
-         self.X = X = list(subsets)
-         self.S = S = set()
-         for x in subsets:
-             S = S.union(x)
-         
-         elements = [a for a in S]
-         elements.sort()
-         
-         A = []
-         b = []
-         variables = [f'x_{i}' for i in range(len(X))]
-         pos = 0
-         for a in elements:
-             variables.append(f"s_{pos}")
-             constraint = [1 if a in X[i] else 0 for i in range(len(X))]
-             slacks = [0 for i in range(len(S))]
-             slacks[pos] = -1
-             A.append(constraint + slacks)
-             pos += 1
-             b.append(1)
-         n = len(variables)
-         J = np.zeros((n, n))
-         h = np.zeros((n, ))
-         h[:len(weights)] = weights
-         
-         super(SetCoverModel, self).__init__(h, J, np.array(A), np.array(b))
-         
-         self.upper_bound = np.array([1 for i in range(len(weights))] + [len(X)-1 for i in range(n-len(weights))])
- [docs]
-     def decode(self, solution) -> List:
-         xbar = []
-         for i in range(len(self.X)):
-             if solution[i] > 0.5:
-                 xbar.append(self.X[i])
-         return xbar