qaoalib 0.1.10__tar.gz → 0.2.0__tar.gz
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.
- {qaoalib-0.1.10 → qaoalib-0.2.0}/PKG-INFO +8 -3
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/models/result.py +23 -0
- qaoalib-0.2.0/qaoalib/solver/__init__.py +1 -0
- qaoalib-0.2.0/qaoalib/solver/vqe.py +137 -0
- qaoalib-0.2.0/qaoalib/version.py +1 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib.egg-info/PKG-INFO +8 -3
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib.egg-info/SOURCES.txt +2 -0
- qaoalib-0.2.0/qaoalib.egg-info/requires.txt +10 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/setup.py +8 -3
- qaoalib-0.1.10/qaoalib/version.py +0 -1
- qaoalib-0.1.10/qaoalib.egg-info/requires.txt +0 -5
- {qaoalib-0.1.10 → qaoalib-0.2.0}/LICENSE +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/README.md +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/__init__.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/json.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/math.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/models/__init__.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/__init__.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/landscape/__init__.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/landscape/base.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/landscape/direct_numpy.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/landscape/hadamard_test.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/landscape/hybrid_fast.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/layerwise.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/qis.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/qmc.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/strategy.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/qaoa/utils.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib/utils.py +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib.egg-info/dependency_links.txt +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/qaoalib.egg-info/top_level.txt +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/setup.cfg +0 -0
- {qaoalib-0.1.10 → qaoalib-0.2.0}/test/test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qaoalib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A package for QAOA Maxcut calculations
|
|
5
5
|
Home-page: https://github.com/xenoicwyce/qaoalib
|
|
6
6
|
Author: Xinwei Lee
|
|
@@ -11,10 +11,15 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: qiskit
|
|
15
|
+
Requires-Dist: qiskit_optimization
|
|
16
|
+
Requires-Dist: qiskit_aer
|
|
17
|
+
Requires-Dist: numpy==1.26.0
|
|
18
|
+
Requires-Dist: scipy
|
|
19
|
+
Requires-Dist: pytest
|
|
20
|
+
Requires-Dist: pytest-cov
|
|
15
21
|
Requires-Dist: matplotlib
|
|
16
22
|
Requires-Dist: networkx
|
|
17
|
-
Requires-Dist: qiskit>=0.25.0
|
|
18
23
|
Requires-Dist: pydantic
|
|
19
24
|
|
|
20
25
|
# qaoalib
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import networkx as nx
|
|
2
3
|
import json
|
|
3
4
|
|
|
4
5
|
from pydantic import BaseModel, Field
|
|
@@ -19,8 +20,22 @@ class BaseResult(BaseModel):
|
|
|
19
20
|
G = graph_from_name(self.name)
|
|
20
21
|
self.true_obj, _ = maxcut_brute(G)
|
|
21
22
|
|
|
23
|
+
def solve_gurobi(self) -> None:
|
|
24
|
+
from qiskit_optimization.algorithms import GurobiOptimizer
|
|
25
|
+
from qiskit_optimization.applications import Maxcut
|
|
26
|
+
|
|
27
|
+
G = graph_from_name(self.name)
|
|
28
|
+
w = nx.adjacency_matrix(G)
|
|
29
|
+
maxcut = Maxcut(w)
|
|
30
|
+
qp = maxcut.to_quadratic_program()
|
|
31
|
+
|
|
32
|
+
grb_result = GurobiOptimizer().solve(qp)
|
|
33
|
+
self.true_obj = int(grb_result.fval)
|
|
34
|
+
|
|
22
35
|
def dump(self, target_dir='.') -> None:
|
|
23
36
|
target_dir = Path(target_dir)
|
|
37
|
+
if not target_dir.exists():
|
|
38
|
+
target_dir.mkdir(parents=True)
|
|
24
39
|
with open(target_dir/f'{self.name}.json', 'w') as f:
|
|
25
40
|
json.dump(self.dict(), f, default=to_serializable)
|
|
26
41
|
|
|
@@ -61,3 +76,11 @@ class MultipleTrialResult(BaseResult):
|
|
|
61
76
|
|
|
62
77
|
class ItlwResult(MultipleTrialResult):
|
|
63
78
|
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class VQEResult(BaseResult):
|
|
82
|
+
expectations: list[float] = Field(default_factory=list)
|
|
83
|
+
nfevs: list[int] = Field(default_factory=list)
|
|
84
|
+
initial_params: list[list[float]] = Field(default_factory=list)
|
|
85
|
+
opt_params: list[list[float]] = Field(default_factory=list)
|
|
86
|
+
alphas: list[float] = Field(default_factory=list)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from vqe import VQE
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from qiskit import QuantumCircuit
|
|
4
|
+
from qiskit.circuit import ParameterVector
|
|
5
|
+
from qiskit.primitives import (
|
|
6
|
+
BackendSamplerV2 as BackendSampler,
|
|
7
|
+
BackendEstimatorV2 as BackendEstimator,
|
|
8
|
+
)
|
|
9
|
+
from qiskit.quantum_info import SparsePauliOp, Pauli
|
|
10
|
+
|
|
11
|
+
from qiskit_optimization import QuadraticProgram
|
|
12
|
+
from qiskit_optimization.converters import QuadraticProgramToQubo
|
|
13
|
+
from qiskit_optimization.algorithms import GurobiOptimizer
|
|
14
|
+
from qiskit_algorithms.optimizers import COBYLA, OptimizerResult
|
|
15
|
+
from qiskit_aer import AerSimulator
|
|
16
|
+
|
|
17
|
+
TWO_PI = 2 * np.pi
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class VQE:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
quadratic_program: QuadraticProgram,
|
|
24
|
+
ansatz: QuantumCircuit = None,
|
|
25
|
+
reps: int = 1,
|
|
26
|
+
shots: int = None,
|
|
27
|
+
sampler=None,
|
|
28
|
+
estimator=None,
|
|
29
|
+
optimizer=None,
|
|
30
|
+
) -> None:
|
|
31
|
+
self.qp = quadratic_program
|
|
32
|
+
self.converter = QuadraticProgramToQubo()
|
|
33
|
+
self.qubo = self.converter.convert(self.qp)
|
|
34
|
+
|
|
35
|
+
hamiltonian, offset = self.qubo.to_ising()
|
|
36
|
+
self.hamiltonian: SparsePauliOp = hamiltonian
|
|
37
|
+
self.offset: float = offset
|
|
38
|
+
|
|
39
|
+
self.num_qubits = hamiltonian.num_qubits
|
|
40
|
+
self.ansatz = self.generate_full_ansatz(hamiltonian.num_qubits, reps) if ansatz is None else ansatz
|
|
41
|
+
|
|
42
|
+
backend_sv = AerSimulator(method='statevector')
|
|
43
|
+
backend_mps = AerSimulator(method='matrix_product_state')
|
|
44
|
+
self.sampler = BackendSampler(backend=backend_mps) if sampler is None else sampler
|
|
45
|
+
self.estimator = BackendEstimator(backend=backend_sv) if estimator is None else estimator
|
|
46
|
+
self.optimizer = COBYLA() if optimizer is None else optimizer
|
|
47
|
+
self.shots = shots
|
|
48
|
+
|
|
49
|
+
self.optimal_params = None
|
|
50
|
+
self.optimal_solution = None
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def generate_full_ansatz(num_qubits: int, reps: int) -> QuantumCircuit:
|
|
54
|
+
qc = QuantumCircuit(num_qubits)
|
|
55
|
+
theta = ParameterVector('θ', (reps + 1) * num_qubits)
|
|
56
|
+
|
|
57
|
+
for k in range(num_qubits):
|
|
58
|
+
qc.ry(theta[k], k)
|
|
59
|
+
|
|
60
|
+
for r in range(1, reps + 1):
|
|
61
|
+
for k in range(num_qubits):
|
|
62
|
+
qc.cz(k, (k + 1) % num_qubits)
|
|
63
|
+
|
|
64
|
+
for k in range(num_qubits):
|
|
65
|
+
qc.ry(theta[r * num_qubits + k], k)
|
|
66
|
+
|
|
67
|
+
return qc
|
|
68
|
+
|
|
69
|
+
def generate_random_params(self, scale=TWO_PI):
|
|
70
|
+
return np.random.rand(self.ansatz.num_parameters) * scale
|
|
71
|
+
|
|
72
|
+
def generate_pubs(
|
|
73
|
+
self,
|
|
74
|
+
params: list[float] | np.ndarray,
|
|
75
|
+
) -> list[tuple[QuantumCircuit, SparsePauliOp, np.ndarray]]:
|
|
76
|
+
return [(self.ansatz, self.hamiltonian, params)]
|
|
77
|
+
|
|
78
|
+
def compute_energy(self, params: list[float] | np.ndarray) -> float:
|
|
79
|
+
"""
|
|
80
|
+
Computes the sum of expectation of the ZZ terms.
|
|
81
|
+
"""
|
|
82
|
+
pubs = self.generate_pubs(params)
|
|
83
|
+
results = self.estimator.run(pubs).result()
|
|
84
|
+
evs = [result.data.evs for result in results]
|
|
85
|
+
return sum(evs)
|
|
86
|
+
|
|
87
|
+
def _sample_optimal_circuit(self) -> dict[str, int]:
|
|
88
|
+
"""
|
|
89
|
+
Run the full circuit with sampler to get the solution.
|
|
90
|
+
"""
|
|
91
|
+
if self.optimal_params is None:
|
|
92
|
+
raise ValueError('Problem not yet solved. Run LCCVQE.solve() to solve the problem.')
|
|
93
|
+
|
|
94
|
+
ansatz = self.ansatz.copy()
|
|
95
|
+
ansatz.measure_all()
|
|
96
|
+
result = self.sampler.run([(ansatz, self.optimal_params)], shots=self.shots).result()[0]
|
|
97
|
+
return result.data.meas.get_counts()
|
|
98
|
+
|
|
99
|
+
def _sample_most_likely(self) -> list[int]:
|
|
100
|
+
counts = self._sample_optimal_circuit()
|
|
101
|
+
highest_count = max(counts.values())
|
|
102
|
+
|
|
103
|
+
for bit_string, count in counts.items():
|
|
104
|
+
if count == highest_count:
|
|
105
|
+
return list(map(int, bit_string[::-1])) # flip the bit-string due to qiskit ordering
|
|
106
|
+
|
|
107
|
+
def get_qp_solution(self) -> list[float]:
|
|
108
|
+
qubo_solution = self._sample_most_likely()
|
|
109
|
+
return self.converter.interpret(qubo_solution)
|
|
110
|
+
|
|
111
|
+
def solve(
|
|
112
|
+
self,
|
|
113
|
+
initial_point: list[float] | np.ndarray = None,
|
|
114
|
+
run_sampler: bool = False,
|
|
115
|
+
) -> OptimizerResult:
|
|
116
|
+
"""
|
|
117
|
+
Calls the Scipy minimize function and returns the OptimizerResult object.
|
|
118
|
+
"""
|
|
119
|
+
if initial_point is None:
|
|
120
|
+
initial_point = self.generate_random_params()
|
|
121
|
+
else:
|
|
122
|
+
assert np.asarray(initial_point).shape[0] == self.ansatz.num_parameters, 'Parameter length does not match.'
|
|
123
|
+
|
|
124
|
+
def obj_func(params):
|
|
125
|
+
return self.compute_energy(params)
|
|
126
|
+
|
|
127
|
+
result = self.optimizer.minimize(obj_func, initial_point)
|
|
128
|
+
self.optimal_params = result.x
|
|
129
|
+
|
|
130
|
+
if run_sampler:
|
|
131
|
+
self.optimal_solution = self.get_qp_solution()
|
|
132
|
+
|
|
133
|
+
return result
|
|
134
|
+
|
|
135
|
+
def solve_gurobi(self) -> float:
|
|
136
|
+
result = GurobiOptimizer().solve(self.qp)
|
|
137
|
+
return result.fval
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.2.0'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qaoalib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A package for QAOA Maxcut calculations
|
|
5
5
|
Home-page: https://github.com/xenoicwyce/qaoalib
|
|
6
6
|
Author: Xinwei Lee
|
|
@@ -11,10 +11,15 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: qiskit
|
|
15
|
+
Requires-Dist: qiskit_optimization
|
|
16
|
+
Requires-Dist: qiskit_aer
|
|
17
|
+
Requires-Dist: numpy==1.26.0
|
|
18
|
+
Requires-Dist: scipy
|
|
19
|
+
Requires-Dist: pytest
|
|
20
|
+
Requires-Dist: pytest-cov
|
|
15
21
|
Requires-Dist: matplotlib
|
|
16
22
|
Requires-Dist: networkx
|
|
17
|
-
Requires-Dist: qiskit>=0.25.0
|
|
18
23
|
Requires-Dist: pydantic
|
|
19
24
|
|
|
20
25
|
# qaoalib
|
|
@@ -22,10 +22,15 @@ setup(
|
|
|
22
22
|
packages=find_packages(exclude=["test*"]),
|
|
23
23
|
python_requires=">=3.9",
|
|
24
24
|
install_requires=[
|
|
25
|
-
"
|
|
25
|
+
"qiskit",
|
|
26
|
+
"qiskit_optimization",
|
|
27
|
+
"qiskit_aer",
|
|
28
|
+
"numpy==1.26.0",
|
|
29
|
+
"scipy",
|
|
30
|
+
"pytest",
|
|
31
|
+
"pytest-cov",
|
|
26
32
|
"matplotlib",
|
|
27
33
|
"networkx",
|
|
28
|
-
"qiskit>=0.25.0",
|
|
29
34
|
"pydantic",
|
|
30
|
-
]
|
|
35
|
+
],
|
|
31
36
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.1.10'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|