eqc-models 0.9.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. eqc_models-0.9.8.data/platlib/compile_extensions.py +23 -0
  2. eqc_models-0.9.8.data/platlib/eqc_models/__init__.py +15 -0
  3. eqc_models-0.9.8.data/platlib/eqc_models/algorithms/__init__.py +4 -0
  4. eqc_models-0.9.8.data/platlib/eqc_models/algorithms/base.py +10 -0
  5. eqc_models-0.9.8.data/platlib/eqc_models/algorithms/penaltymultiplier.py +169 -0
  6. eqc_models-0.9.8.data/platlib/eqc_models/allocation/__init__.py +6 -0
  7. eqc_models-0.9.8.data/platlib/eqc_models/allocation/allocation.py +367 -0
  8. eqc_models-0.9.8.data/platlib/eqc_models/allocation/portbase.py +128 -0
  9. eqc_models-0.9.8.data/platlib/eqc_models/allocation/portmomentum.py +137 -0
  10. eqc_models-0.9.8.data/platlib/eqc_models/assignment/__init__.py +5 -0
  11. eqc_models-0.9.8.data/platlib/eqc_models/assignment/qap.py +82 -0
  12. eqc_models-0.9.8.data/platlib/eqc_models/assignment/setpartition.py +170 -0
  13. eqc_models-0.9.8.data/platlib/eqc_models/base/__init__.py +72 -0
  14. eqc_models-0.9.8.data/platlib/eqc_models/base/base.py +150 -0
  15. eqc_models-0.9.8.data/platlib/eqc_models/base/constraints.py +276 -0
  16. eqc_models-0.9.8.data/platlib/eqc_models/base/operators.py +201 -0
  17. eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.c +11363 -0
  18. eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.cpython-310-darwin.so +0 -0
  19. eqc_models-0.9.8.data/platlib/eqc_models/base/polyeval.pyx +72 -0
  20. eqc_models-0.9.8.data/platlib/eqc_models/base/polynomial.py +274 -0
  21. eqc_models-0.9.8.data/platlib/eqc_models/base/quadratic.py +250 -0
  22. eqc_models-0.9.8.data/platlib/eqc_models/decoding.py +20 -0
  23. eqc_models-0.9.8.data/platlib/eqc_models/graph/__init__.py +5 -0
  24. eqc_models-0.9.8.data/platlib/eqc_models/graph/base.py +63 -0
  25. eqc_models-0.9.8.data/platlib/eqc_models/graph/hypergraph.py +307 -0
  26. eqc_models-0.9.8.data/platlib/eqc_models/graph/maxcut.py +155 -0
  27. eqc_models-0.9.8.data/platlib/eqc_models/graph/maxkcut.py +184 -0
  28. eqc_models-0.9.8.data/platlib/eqc_models/ml/__init__.py +15 -0
  29. eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierbase.py +99 -0
  30. eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierqboost.py +423 -0
  31. eqc_models-0.9.8.data/platlib/eqc_models/ml/classifierqsvm.py +237 -0
  32. eqc_models-0.9.8.data/platlib/eqc_models/ml/clustering.py +323 -0
  33. eqc_models-0.9.8.data/platlib/eqc_models/ml/clusteringbase.py +112 -0
  34. eqc_models-0.9.8.data/platlib/eqc_models/ml/decomposition.py +363 -0
  35. eqc_models-0.9.8.data/platlib/eqc_models/ml/forecast.py +255 -0
  36. eqc_models-0.9.8.data/platlib/eqc_models/ml/forecastbase.py +139 -0
  37. eqc_models-0.9.8.data/platlib/eqc_models/ml/regressor.py +220 -0
  38. eqc_models-0.9.8.data/platlib/eqc_models/ml/regressorbase.py +97 -0
  39. eqc_models-0.9.8.data/platlib/eqc_models/ml/reservoir.py +106 -0
  40. eqc_models-0.9.8.data/platlib/eqc_models/sequence/__init__.py +5 -0
  41. eqc_models-0.9.8.data/platlib/eqc_models/sequence/tsp.py +217 -0
  42. eqc_models-0.9.8.data/platlib/eqc_models/solvers/__init__.py +12 -0
  43. eqc_models-0.9.8.data/platlib/eqc_models/solvers/qciclient.py +707 -0
  44. eqc_models-0.9.8.data/platlib/eqc_models/utilities/__init__.py +6 -0
  45. eqc_models-0.9.8.data/platlib/eqc_models/utilities/fileio.py +38 -0
  46. eqc_models-0.9.8.data/platlib/eqc_models/utilities/polynomial.py +137 -0
  47. eqc_models-0.9.8.data/platlib/eqc_models/utilities/qplib.py +375 -0
  48. eqc_models-0.9.8.dist-info/LICENSE.txt +202 -0
  49. eqc_models-0.9.8.dist-info/METADATA +139 -0
  50. eqc_models-0.9.8.dist-info/RECORD +52 -0
  51. eqc_models-0.9.8.dist-info/WHEEL +5 -0
  52. eqc_models-0.9.8.dist-info/top_level.txt +2 -0
@@ -0,0 +1,128 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ # Import libs
3
+ import os
4
+ import sys
5
+ import time
6
+ import datetime
7
+ import json
8
+ import warnings
9
+ from functools import wraps
10
+ import numpy as np
11
+ import pandas as pd
12
+
13
+ from ..base import ConstraintsMixIn
14
+ from eqc_models import QuadraticModel
15
+
16
+
17
+ class PortBase(ConstraintsMixIn, QuadraticModel):
18
+ def __init__(
19
+ self,
20
+ stocks: list,
21
+ stock_data_dir: str,
22
+ adj_date: str,
23
+ lookback_days: int = 60,
24
+ ):
25
+ self.stocks = stocks
26
+ self.data_dir = stock_data_dir
27
+ self.adj_date = adj_date
28
+ self.lookback_days = lookback_days
29
+
30
+ self._H = self.build()
31
+
32
+ def get_stock_returns(self, min_date, max_date):
33
+ stocks = self.stocks
34
+ min_date = pd.to_datetime(min_date)
35
+ max_date = pd.to_datetime(max_date)
36
+
37
+ return_df = None
38
+ for stock in stocks:
39
+ stock_df = pd.read_csv(
40
+ os.path.join(self.data_dir, "%s.csv" % stock)
41
+ )
42
+ stock_df["Date"] = stock_df["Date"].astype("datetime64[ns]")
43
+ stock_df = (
44
+ stock_df.fillna(method="ffill")
45
+ .fillna(method="bfill")
46
+ .fillna(0)
47
+ )
48
+ stock_df[stock] = stock_df[stock].pct_change()
49
+ stock_df = stock_df.dropna()
50
+
51
+ stock_df = stock_df[
52
+ (stock_df["Date"] >= min_date)
53
+ & (stock_df["Date"] <= max_date)
54
+ ]
55
+
56
+ if return_df is None:
57
+ return_df = stock_df
58
+ else:
59
+ return_df = return_df.merge(
60
+ stock_df,
61
+ how="outer",
62
+ on="Date",
63
+ )
64
+
65
+ return_df = (
66
+ return_df.fillna(method="ffill")
67
+ .fillna(method="bfill")
68
+ .fillna(0)
69
+ )
70
+
71
+ return return_df
72
+
73
+ def get_hamiltonian(
74
+ self,
75
+ return_df,
76
+ min_date,
77
+ max_date,
78
+ ):
79
+ pass
80
+
81
+ def build(self):
82
+ # Get dates
83
+ adj_date = pd.to_datetime(self.adj_date)
84
+ min_date = adj_date - datetime.timedelta(days=self.lookback_days)
85
+ max_date = adj_date - datetime.timedelta(days=1)
86
+
87
+ # Get return dataframe
88
+ return_df = self.get_stock_returns(min_date, max_date)
89
+ return_df = return_df.sort_values("Date")
90
+ return_df = return_df.fillna(method="ffill").fillna(0)
91
+
92
+ # Get and set hamiltonian
93
+ J, C, sum_constraint = self.get_hamiltonian(
94
+ return_df,
95
+ min_date,
96
+ max_date,
97
+ )
98
+ self._C = C
99
+ self._J = J
100
+ self._sum_constraint = sum_constraint
101
+
102
+ # Set domain
103
+ num_variables = C.shape[0]
104
+ self.upper_bound = sum_constraint * np.ones((num_variables,))
105
+
106
+ return C, J
107
+
108
+ def get_dynamic_range(self):
109
+ C = self._C
110
+ J = self._J
111
+
112
+ if C is None:
113
+ return
114
+
115
+ if J is None:
116
+ return
117
+
118
+ absc = np.abs(C)
119
+ absj = np.abs(J)
120
+ minc = np.min(absc[absc > 0])
121
+ maxc = np.max(absc)
122
+ minj = np.min(absj[absj > 0])
123
+ maxj = np.max(absj)
124
+
125
+ minval = min(minc, minj)
126
+ maxval = max(maxc, maxj)
127
+
128
+ return 10 * np.log10(maxval / minval)
@@ -0,0 +1,137 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ # Import libs
3
+ import os
4
+ import sys
5
+ import time
6
+ import datetime
7
+ import json
8
+ import warnings
9
+ from functools import wraps
10
+ import numpy as np
11
+ import pandas as pd
12
+
13
+ from .portbase import PortBase
14
+
15
+
16
+ class PortMomentum(PortBase):
17
+ def __init__(
18
+ self,
19
+ stocks: list,
20
+ stock_data_dir: str,
21
+ adj_date: str,
22
+ lookback_days: int = 60,
23
+ window_days: int = 30,
24
+ window_overlap_days: int = 15,
25
+ weight_upper_limit: float = 0.08,
26
+ r_base: float = 0.05 / 365,
27
+ alpha: float = 5.0,
28
+ beta: float = 1.0,
29
+ xi: float = 1.0,
30
+ ):
31
+ self.stocks = stocks
32
+ self.data_dir = stock_data_dir
33
+ self.adj_date = adj_date
34
+ self.lookback_days = lookback_days
35
+
36
+ self.window_days = window_days
37
+ self.window_overlap_days = window_overlap_days
38
+ self.weight_upper_limit = weight_upper_limit
39
+ self.r_base = r_base
40
+ self.alpha = alpha
41
+ self.beta = beta
42
+ self.xi = xi
43
+
44
+ self._H = self.build()
45
+
46
+ def get_hamiltonian(
47
+ self,
48
+ return_df,
49
+ min_date,
50
+ max_date,
51
+ ):
52
+ stocks = self.stocks
53
+ xi = self.xi
54
+ window_days = self.window_days
55
+ window_overlap_days = self.window_overlap_days
56
+ weight_upper_limit = self.weight_upper_limit
57
+
58
+ # Set some params
59
+ K = len(stocks)
60
+
61
+ # Calculate Q and p_vec
62
+ Q = np.zeros(shape=(K, K), dtype=np.float32)
63
+ p_vec = np.zeros(shape=(K), dtype=np.float32)
64
+
65
+ m = 0
66
+ min_date = pd.to_datetime(min_date)
67
+ max_date = pd.to_datetime(max_date)
68
+ tmp_date = min_date
69
+ while tmp_date <= max_date:
70
+ tmp_min_date = tmp_date
71
+ tmp_max_date = tmp_date + datetime.timedelta(days=window_days)
72
+ tmp_df = return_df[
73
+ (return_df["Date"] >= tmp_min_date)
74
+ & (return_df["Date"] <= tmp_max_date)
75
+ ]
76
+
77
+ r_list = []
78
+ for i in range(K):
79
+ r_list.append(np.array(tmp_df[stocks[i]]))
80
+
81
+ Q_tmp = np.cov(r_list)
82
+ for i in range(K):
83
+ p_vec[i] += -self.r_base * np.mean(r_list[i])
84
+ for j in range(K):
85
+ Q[i][j] += Q_tmp[i][j]
86
+
87
+ tmp_date += datetime.timedelta(
88
+ days=window_days - window_overlap_days,
89
+ )
90
+ m += 1
91
+
92
+ fct = m
93
+ if fct > 0:
94
+ fct = 1.0 / fct
95
+
96
+ p_vec = fct * p_vec
97
+ Q = fct * Q
98
+
99
+ # Calculate the Hamiltonian
100
+ J_no_limit = xi * Q
101
+ C_no_limit = p_vec
102
+
103
+ # make sure J is symmetric up to machine precision
104
+ J_no_limit = 0.5 * (J_no_limit + J_no_limit.transpose())
105
+
106
+ if weight_upper_limit is None:
107
+ return J_no_limit, C_no_limit, 100.0
108
+
109
+ W_max = 100.0 * weight_upper_limit
110
+
111
+ J = np.zeros(shape=(2 * K, 2 * K), dtype=np.float32)
112
+ C = np.zeros(shape=(2 * K), dtype=np.float32)
113
+
114
+ for i in range(K):
115
+ for j in range(K):
116
+ J[i][j] = J_no_limit[i][j] + self.alpha
117
+
118
+ J[i][i] += self.beta
119
+ J[i][i + K] += self.beta
120
+ J[i + K][i] += self.beta
121
+ J[i + K][i + K] += self.beta
122
+ C[i] = (
123
+ C_no_limit[i] - 200.0 * self.alpha - 2 * self.beta * W_max
124
+ )
125
+ C[i + K] = -2 * self.beta * W_max
126
+
127
+ C = C.reshape((C.shape[0], 1))
128
+
129
+ # Check hamiltonian dims
130
+ stocks = self.stocks
131
+ K = len(stocks)
132
+
133
+ assert J.shape[0] == K or J.shape[0] == 2 * K
134
+ assert J.shape[1] == K or J.shape[0] == 2 * K
135
+ assert C.shape[0] == K or C.shape[0] == 2 * K
136
+
137
+ return J, C, K * W_max
@@ -0,0 +1,5 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+
3
+ from .qap import QAPModel
4
+
5
+ __all__ = ["QAPModel"]
@@ -0,0 +1,82 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ import numpy as np
3
+ from eqc_models.base import ConstrainedQuadraticModel
4
+
5
+ class QAPModel(ConstrainedQuadraticModel):
6
+ """
7
+ Parameters
8
+ ----------
9
+
10
+ A : np.array
11
+ matrix of distances or costs between locations
12
+ B : np.array
13
+ matrix of flows between facilities
14
+ C : np.array
15
+ matrix pf fixed costs of assigning facilities to locations
16
+
17
+
18
+ Formulates a quadratic programming model from three inputs. The inputs are composed of:
19
+ a matrix which describes the unit cost of moving a single asset between locations. This
20
+ matrix can describe asynchronous costs that differ by direction of flow; a matrix which
21
+ describes the quantity of flow between facilities. This matrix describes the quantity
22
+ in the direction of flow; a matrix which desribes the fixed cost of assigning a facility
23
+ to a location.
24
+
25
+ Using these flows and costs, an optimization problem is formulated to determine a
26
+ solution which minimizes the total cost for positioning facilities at locations. The
27
+ facilities do not have to be buildings or campuses and the locations do not have to be
28
+ geographical locations. See Beckmann and and Koopmans (1957) for the original reference.
29
+
30
+ >>> A = np.array([[0, 5, 8, 0, 1],
31
+ ... [0, 0, 0, 10, 15],
32
+ ... [0, 0, 0, 13, 18],
33
+ ... [0, 0, 0, 0, 0.],
34
+ ... [0, 0, 0, 1, 0.]])
35
+ >>> B = np.array([[0, 8.54, 6.4, 10, 8.94],
36
+ ... [8.54, 0, 4.47, 5.39, 6.49],
37
+ ... [6.4, 4.47, 0, 3.61, 3.0],
38
+ ... [10, 5.39, 3.61, 0, 2.0],
39
+ ... [8.94, 6.49, 3.0, 2.0, 0.]])
40
+ >>> C = np.array([[2, 3, 6, 3, 7],
41
+ ... [3, 9, 2, 5, 9],
42
+ ... [2, 6, 4, 1, 2],
43
+ ... [7, 5, 8, 5, 7],
44
+ ... [1, 9, 2, 9, 2.]])
45
+ >>> model = QAPModel(A, B, C)
46
+ >>> model.penalty_multiplier = 105.625
47
+ >>> Q = model.qubo.Q
48
+ >>> np.sum(Q)
49
+ 24318.03
50
+
51
+ """
52
+
53
+ def __init__(self, A : np.ndarray, B : np.ndarray, C: np.ndarray):
54
+
55
+ self.A = A
56
+ self.B = B
57
+ self.C = C
58
+ # N is the number of facilities (same as locations)
59
+ # n is the number of variables (N ** 2)
60
+ self.N = N = A.shape[0]
61
+ self.upper_bound = np.ones((N**2,), dtype=np.int64)
62
+
63
+ # objective
64
+ A = self.A
65
+ B = self.B
66
+ C = self.C
67
+ n = self.N ** 2
68
+
69
+ objective = np.kron(A, B) + np.diag(C.reshape((n, )))
70
+ objective += objective.T
71
+ objective /= 2.
72
+ self.quad_objective = objective
73
+ self.linear_objective = np.zeros((n,))
74
+ # G
75
+ m = 2 * self.N
76
+ G = np.zeros((m, n), dtype=np.float32)
77
+ for i in range(self.N):
78
+ G[i, i::self.N] = 1
79
+ G[self.N + i, i*self.N:(i+1)*self.N] = 1
80
+ h = np.ones((m,))
81
+ self.lhs = G
82
+ self.rhs = h
@@ -0,0 +1,170 @@
1
+ from typing import List, Tuple, Dict, Union
2
+ import numpy as np
3
+ from eqc_models.base import ConstraintsMixIn, PolynomialModel
4
+
5
+ class SetPartitionModel(ConstraintsMixIn, PolynomialModel):
6
+ """
7
+ This class represents a set partitioning model for optimization problems that require selecting subsets
8
+ to partition a universal set while minimizing an objective function defined by weights. Given a collection
9
+ of subsets, a weight is assigned to each subset, and the goal is to determine an optimal selection of subsets
10
+ to fully cover the universal set with minimized total weight.
11
+
12
+ Parameters
13
+ ----------
14
+
15
+ subsets : List of sets
16
+ List of sets (subsets) defining the collection to partition.
17
+ Each element in this list represents a subset containing elements from the universal set.
18
+
19
+ weights : List of floats
20
+ List of weights corresponding to each subset. The length of this list should be equal to
21
+ the number of subsets, with each weight indicating the cost or weight associated with selecting
22
+ a particular subset.
23
+
24
+ Attributes
25
+ ----------
26
+
27
+ H : tuple of np.ndarray
28
+ Tuple containing the linear (h) and quadratic (J) coefficients for the Hamiltonian representation
29
+ of the quadratic problem formulation.
30
+
31
+ penalty_multiplier : float
32
+ Value for weighting the penalties formed from the equality constraints.
33
+
34
+ polynomial : Polynomial
35
+ Polynomial operator representation for the model, constructed from the penalty terms
36
+ to encode the set partition constraints.
37
+
38
+ linear_objective : np.ndarray
39
+ Array representing the linear objective function coefficients based on the weights of subsets.
40
+
41
+ quad_objective : np.ndarray
42
+ Quadratic objective function matrix initialized as zeros (no quadratic terms for objective).
43
+
44
+ constraints : tuple of np.ndarray
45
+ Matrix `A` and vector `b` representing constraints for the set partition problem:
46
+ - `A`: Binary matrix indicating subset membership of elements in the universal set.
47
+ - `b`: Vector of ones, enforcing full coverage of the universal set by the selected subsets.
48
+
49
+ universal_set : set
50
+ Set containing all unique elements present across the input subsets, representing the elements
51
+ that must be fully covered in the partition solution.
52
+
53
+ Example
54
+ --------
55
+
56
+ Given a list of subsets representing a set partition problem, each with an associated weight:
57
+
58
+ >>> import numpy as np
59
+ >>> np.random.seed(21)
60
+ >>> subsets = [{"A", "B", "C"}, {"D", "E", "F"}, {"A", "F"}, {"B", "E"}, {"C", "D"}, {"A"},
61
+ {"B"}, {"C", "D", "E"}, {"B", "C"}]
62
+ >>> weights = [100 * np.random.random() for _ in subsets]
63
+
64
+ We can construct and use the `SetPartitionModel` as follows:
65
+
66
+ >>> model = SetPartitionModel(subsets=subsets, weights=weights)
67
+ >>> solution = np.random.randint(0, 2, len(subsets)) # Random binary solution vector
68
+ >>> print("Objective Value:", model.evaluateObjective(solution)) # Evaluate solution cost
69
+
70
+ This approach builds the constraints matrix and penalties automatically, enabling efficient
71
+ optimization using solvers like `Dirac3CloudSolver`.
72
+ """
73
+ def __init__(self, subsets: List[set], weights: List[float]) -> None:
74
+ # Combine subsets to form the universal set
75
+ self.universal_set = set()
76
+ for subset in subsets:
77
+ self.universal_set = self.universal_set.union(subset)
78
+
79
+ # Create the constraint matrix A and vector b
80
+ A = []
81
+ for x in self.universal_set:
82
+ row = [1 if x in subset else 0 for subset in subsets]
83
+ A.append(row)
84
+ A = np.array(A)
85
+ b = np.ones((A.shape[0],))
86
+
87
+ # Define penalty terms
88
+ J = A.T @ A
89
+ h = -2 * b.T @ A
90
+ n = h.shape[0]
91
+ h = h.reshape((n, 1))
92
+ offset = b.T @ b
93
+
94
+ # Assign the constraints to the mixin's properties
95
+ self.constraints = (A, b)
96
+
97
+ # Initialize PolynomialModel with J and h, properly formatted as indices and coefficients
98
+ indices, coefficients = self._construct_polynomial_terms(h, J)
99
+ super().__init__(coefficients, indices)
100
+
101
+ # Define the linear objective function based on subset weights
102
+ self.linear_objective = np.array(weights).reshape((n, 1))
103
+ self.quad_objective = np.zeros_like(J)
104
+
105
+ def _construct_polynomial_terms(self, h: np.ndarray, J: np.ndarray) -> Tuple[List[List[int]], List[np.ndarray]]:
106
+ """
107
+ Constructs the polynomial terms (indices and coefficients) needed for the quadratic
108
+ Hamiltonian representation of the problem.
109
+
110
+ Parameters
111
+ ----------
112
+ h : np.ndarray
113
+ Linear term of the penalty function as a 1D array.
114
+
115
+ J : np.ndarray
116
+ Quadratic term of the penalty function as a 2D array.
117
+
118
+ Returns
119
+ -------
120
+ Tuple[List[List[int]], List[float]]
121
+ A tuple where:
122
+ - The first element is a list of index lists, representing terms in polynomial format.
123
+ - The second element is a list of float coefficients corresponding to each term.
124
+ """
125
+ indices = []
126
+ coefficients = []
127
+
128
+ # Linear terms
129
+ for i in range(h.shape[0]):
130
+ if h[i, 0] != 0:
131
+ indices.append([0, i + 1]) # 1-based index
132
+ coefficients.append(h[i, 0])
133
+
134
+ # Quadratic terms
135
+ for i in range(J.shape[0]):
136
+ for j in range(i, J.shape[1]):
137
+ if J[i, j] != 0:
138
+ indices.append([i + 1, j + 1]) # 1-based indices
139
+ coefficients.append(J[i, j])
140
+
141
+ return indices, coefficients
142
+
143
+ @property
144
+ def H(self) -> Tuple[np.ndarray, np.ndarray]:
145
+ """
146
+ Hamiltonian representation as a polynomial, returning the coefficients and indices.
147
+
148
+ Returns
149
+ -------
150
+ Tuple[np.ndarray, np.ndarray]
151
+ Tuple where the first element is an array of coefficients, and the second element
152
+ is an array of indices, each representing polynomial terms for the Hamiltonian.
153
+ """
154
+ return self.coefficients, self.indices
155
+
156
+ def evaluateObjective(self, solution: np.ndarray) -> float:
157
+ """
158
+ Evaluate the objective function by calculating the weighted sum of selected subsets.
159
+
160
+ Parameters
161
+ ----------
162
+ solution : np.ndarray
163
+ Binary array where each element indicates if a subset is selected (1) or not (0).
164
+
165
+ Returns
166
+ -------
167
+ float
168
+ The value of the objective function, representing the total weight of selected subsets.
169
+ """
170
+ return float(np.squeeze(solution).T @ np.squeeze(self.linear_objective))
@@ -0,0 +1,72 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ """
3
+ This subpackage contains the building blocks for formulating and solving models
4
+ with EQC devices. Many well known models in the space of quantum computing use
5
+ quadratic operators. Two generally accepted formats for quadratic models are
6
+ Ising Hamiltonian and QUBO operators. Ising models are not explicitly supported
7
+ because of the simple equivalence to QUBO models. Converters from Ising to QUBO
8
+ are readily available and may be added as a utility function in the future, but
9
+ for now are left out of the package. Other quadratic models, such as integer
10
+ or floating point models are supported using the domain and upper bound of the
11
+ model variables and the solver choice.
12
+
13
+ Polynomial models are used to support higher order interactions between
14
+ variables. These models are defined over non-negative variables with the
15
+ highest power interaction being the only restriction on variable interactions.
16
+ This is also known as all-to-all connectivity.
17
+
18
+ Subpackages
19
+ -----------
20
+
21
+ constraints
22
+ This module defines support for linear equality and inequality constraints.
23
+ It can be paired with the penalty multiplier algorithm to choose multiplier
24
+ values which satisfy the enforcement of constraints as penalties. The mixin
25
+ pattern is used to allow more complex classes to be built from these bases.
26
+
27
+ - ConstraintMixIn
28
+ - ConstraintModel
29
+ - InequalitiesMixIn
30
+ - InequalityConstraintModel
31
+
32
+ quadratic
33
+ This module defines the methods required to convert a linear vector and
34
+ quadratic matrix into the required operator, either QUBO or Polynomial, for
35
+ solving with EQC. The support for constraints is also incorporated.
36
+
37
+ - ConstrainedQuadraticModel
38
+ - QuadraticModel
39
+
40
+ polynomial
41
+ This module defines the classes and methods for conversion from arrays of
42
+ coefficients and indices to operators for solving with EQC. The support for
43
+ constriants is also incorporated.
44
+
45
+ - PolynomialModel
46
+ - ConstrainedPolynomialModel
47
+
48
+ base
49
+ This module defines abstract base classes for models and solvers.
50
+
51
+ - EqcModel
52
+ - ModelSolver
53
+
54
+ operators
55
+ This module defines the operator types to use for passing problems to EQC
56
+ devices.
57
+
58
+ - Polynomial
59
+ - QUBO
60
+
61
+ """
62
+ from .constraints import (ConstraintModel, ConstraintsMixIn, InequalitiesMixin,
63
+ InequalityConstraintModel)
64
+ from .quadratic import (ConstrainedQuadraticModel, QuadraticModel)
65
+ from .polynomial import (PolynomialModel, ConstrainedPolynomialModel)
66
+ from .base import (ModelSolver, EqcModel)
67
+ from .operators import (QUBO, Polynomial)
68
+
69
+ __all__ = ["ConstraintsMixIn", "ConstraintModel", "ConstrainedQuadraticModel",
70
+ "QuadraticModel", "PolynomialModel", "ConstrainedPolynomialModel",
71
+ "InequalitiesMixin", "InequalityConstraintModel",
72
+ "EqcModel", "ModelSolver", "QUBO", "Polynomial"]