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,217 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ """
3
+ # Traveling Salesman Problem
4
+
5
+ ## Class listing
6
+
7
+ `class TSPModel` - a base class
8
+ `class MTZTSPModel` - a concrete class for the MTZ formulation of a TSP
9
+
10
+ MTZ has been chosen for a demonstration of the integer capability of the
11
+ Dirac devices. A feasible solution will produce the valid sequence of
12
+ visits by simply ordering the nodes by the $s_i$ variables. In the literature,
13
+ the ordering variables are named with $u$, but this is avoided because the
14
+ graph notation with $u$ being a tail node and $v$ being a head node is used
15
+ here. In conjunction with this notation, the variables $x_{ij}$ reference the
16
+ node index where the index of node $u$ is $i$ and the index of node $v$ is
17
+ $j$.
18
+
19
+ """
20
+
21
+ from typing import (Dict, Tuple)
22
+ import numpy as np
23
+ from eqc_models.base import ConstrainedPolynomialModel, InequalitiesMixin
24
+ from eqc_models.base.operators import Polynomial
25
+
26
+ class TSPModel(ConstrainedPolynomialModel):
27
+ """
28
+ The TSPModel class implements the basics for building different formualtions of
29
+ TSP models.
30
+
31
+ """
32
+
33
+ def __init__(self, D : Dict[Tuple[int, int], float]):
34
+ self.D = D
35
+ self.nodes = nodes = set()
36
+ self.edges = edges = set()
37
+ for (u, v) in D.keys():
38
+ nodes.add(u)
39
+ nodes.add(v)
40
+ assert (u, v) not in edges, "Only a single edge from tail to head is allowed"
41
+ edges.add((u, v))
42
+ # set N to the number of nodes
43
+ self.N = len(nodes)
44
+ self.variables = None
45
+
46
+ def distance(self, i : int, j : int) -> float:
47
+ """
48
+ Parameters
49
+ ----------
50
+ i: int
51
+ index of first node
52
+ Returns
53
+ -------
54
+
55
+ float
56
+
57
+ Retrieves the distance between nodes at indexes i and j. Supports asymmetric
58
+ (D[i, j] <> D[j, i]) distances.
59
+
60
+
61
+ """
62
+
63
+ return self.D[i, j]
64
+
65
+ def cost(self, solution : np.ndarray) -> float:
66
+ """
67
+ Solution cost is the sum of all D values where (i,j) is chosen
68
+
69
+ Parameters:
70
+ :solution: np.ndarray - An array of of 0,1 values which describe a route
71
+ depending on the formulation chosen.
72
+ Returns: float
73
+
74
+ """
75
+ raise NotImplementedError("Subclass must implement cost method")
76
+
77
+ class MTZTSPModel(InequalitiesMixin, TSPModel):
78
+ """
79
+ Using the Miller Tucker Zemlin (1960) formulation of TSP, create a model
80
+ instance that contains variables for node order (to eliminate subtours)
81
+ and edge choices.
82
+
83
+ >>> D = {(1, 2): 1, (2, 1): 1, (1, 3): 2, (3, 1): 2, (2, 3): 3, (3, 2): 3}
84
+ >>> model = MTZTSPModel(D)
85
+ >>> model.penalty_multiplier = 10
86
+ >>> model.distance(1, 2)
87
+ 1
88
+ >>> model.distance(3, 2)
89
+ 3
90
+ >>> solution = np.array([1, 0, 0, 1, 1, 0, 1, 2, 3, 4, 4, 2, 5])
91
+ >>> model.cost(solution)
92
+ 6
93
+ >>> lhs, rhs = model.constraints
94
+ >>> (lhs@solution - rhs == 0).all()
95
+ True
96
+ >>> poly = model.polynomial
97
+ >>> poly.evaluate(solution) + model.alpha * model.offset
98
+ 6.0
99
+ >>> infeasible = np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 2, 5])
100
+ >>> Pl, Pq = -2 * rhs.T@lhs, lhs.T@lhs
101
+ >>> Pl.T@solution + solution.T@Pq@solution + model.offset
102
+ 0.0
103
+ >>> Pl.T@infeasible + infeasible.T@Pq@infeasible + model.offset > 0
104
+ True
105
+ >>> poly.evaluate(infeasible) + model.alpha * model.offset > 0
106
+ True
107
+ >>> infeasible = 1 - np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
108
+ >>> poly.evaluate(infeasible) + model.alpha * model.offset > 6
109
+ True
110
+ >>> val1 = poly.evaluate(infeasible) + model.alpha * model.offset
111
+ >>> model.penalty_multiplier *= 2
112
+ >>> poly2 = model.polynomial
113
+ >>> val2 = poly2.evaluate(infeasible) + model.alpha * model.offset
114
+ >>> val1 < val2
115
+ True
116
+
117
+ """
118
+
119
+ def __init__(self, D : Dict[Tuple[int, int], float]) -> None:
120
+ super(MTZTSPModel, self).__init__(D)
121
+ self.variables = variables = []
122
+ coefficients = []
123
+ indices = []
124
+ for (u, v) in D.keys():
125
+ varname = f"x_{u}_{v}"
126
+ varidx = len(variables)
127
+ variables.append(varname)
128
+ indices.append((0, varidx+1))
129
+ coefficients.append(D[(u, v)])
130
+ for u in self.nodes:
131
+ variables.append(f"s_{u}")
132
+ self.coefficients = coefficients
133
+ self.indices = indices
134
+ self.max_order = 2
135
+
136
+ @property
137
+ def constraints(self) -> Tuple[np.ndarray, np.ndarray]:
138
+ """
139
+ Build the constraints: Two constraints for every node, one for the
140
+ edge chosen to enter and another for the edge chosen to leave.
141
+ One constraint for every edge not leading to the depot.
142
+
143
+ Returns: 2-Tuple of numpy arrays, one as lefthand side and the other
144
+ for the righthand side. $Ax = b$
145
+
146
+ """
147
+ # choose a depot node
148
+ depot = list(self.nodes)[0]
149
+ depot_in = [uv for uv in self.edges if uv[-1] == depot]
150
+ m = 2*self.N+len(self.edges) - len(depot_in)
151
+ lhs = np.ndarray((m, self.n), dtype=np.int32)
152
+ rhs = np.ndarray((m,), dtype=np.int32)
153
+ senses = ["EQ" for i in range(m)]
154
+ for idx, node in enumerate(self.nodes):
155
+ rhs[idx] = 1
156
+ rhs[self.N + idx] = 1
157
+ for (u, v) in self.edges:
158
+ if v == node:
159
+ varname = f"x_{u}_{v}"
160
+ varidx = self.variables.index(varname)
161
+ lhs[idx, varidx] = 1
162
+ elif u == node:
163
+ varname = f"x_{u}_{v}"
164
+ varidx = self.variables.index(varname)
165
+ lhs[self.N+idx, varidx] = 1
166
+ # build these subtour elimination constraints
167
+ # s_i - s_j + N x_{ij} <= N - 1
168
+ idx = 0
169
+ for (u, v) in self.edges:
170
+ if v != depot:
171
+ senses[2*self.N + idx] = "LE"
172
+ lhs[2*self.N + idx, varidx] = self.N - 1
173
+ vidx = self.variables.index(f"s_{v}")
174
+ lhs[2*self.N + idx, vidx] = -1
175
+ uidx = self.variables.index(f"s_{u}")
176
+ lhs[2*self.N + idx, uidx] = 1
177
+ rhs[2*self.N + idx] = self.N
178
+ idx += 1
179
+ # update the constraint senses
180
+ self.senses = senses
181
+ self.lhs = lhs
182
+ self.rhs = rhs
183
+ # let the superclass handle the rest
184
+ return super(MTZTSPModel, self).constraints
185
+
186
+ def cost(self, solution : np.ndarray) -> float:
187
+ """
188
+ Solution cost is the sum of all D values where (i,j) is chosen
189
+
190
+ Parameters:
191
+ :solution: np.ndarray - An array of of 0,1 values which describe a route
192
+ by setting variables representing active edges to 1.
193
+ Returns: float
194
+
195
+ """
196
+
197
+ # get the route selection variables
198
+ cost_val = 0
199
+ for (u, v) in self.edges:
200
+ varname = f"x_{u}_{v}"
201
+ varidx = self.variables.index(varname)
202
+ cost_val += solution[varidx] * self.D[(u, v)]
203
+ return cost_val
204
+
205
+ @property
206
+ def upper_bound(self) -> np.ndarray:
207
+ """
208
+ For all route variables, the domain is {0, 1}. The sequence variables
209
+ can take on values in [0, 1, 2, ..., N].
210
+
211
+ """
212
+ # Since the sequence variables are all required, but the route variables
213
+ # are not, just reference the count from the end to specify the sequence vars
214
+ upper_bound = np.ones((len(self.variables),))
215
+ upper_bound[-self.N:] = self.N
216
+ return upper_bound
217
+
@@ -0,0 +1,12 @@
1
+ # (C) Quantum Computing Inc., 2024.
2
+ try:
3
+ from .eqcdirect import Dirac3DirectSolver, EqcDirectSolver
4
+ except ImportError:
5
+ # eqc-direct is not available
6
+ Dirac3DirectSolver = None
7
+ from .qciclient import (Dirac1CloudSolver, Dirac3CloudSolver, QciClientSolver,
8
+ Dirac3IntegerCloudSolver, Dirac3ContinuousCloudSolver)
9
+
10
+ __all__ = ["Dirac3DirectSolver", "Dirac1CloudSolver", "Dirac3CloudSolver",
11
+ "EqcDirectSolver", "QciClientSolver", "Dirac3IntegerCloudSolver",
12
+ "Dirac3ContinuousCloudSolver"]