qaoalib 0.2.1__tar.gz → 0.3.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.
@@ -0,0 +1 @@
1
+ include requirements.txt
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: qaoalib
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: A package for QAOA Maxcut calculations
5
5
  Home-page: https://github.com/xenoicwyce/qaoalib
6
6
  Author: Xinwei Lee
@@ -13,23 +13,30 @@ Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: qiskit
15
15
  Requires-Dist: qiskit_optimization
16
+ Requires-Dist: qiskit_algorithms
16
17
  Requires-Dist: qiskit_aer
17
- Requires-Dist: numpy==1.26.0
18
+ Requires-Dist: numpy
18
19
  Requires-Dist: scipy
19
20
  Requires-Dist: pytest
20
21
  Requires-Dist: pytest-cov
21
22
  Requires-Dist: matplotlib
22
23
  Requires-Dist: networkx
23
24
  Requires-Dist: pydantic
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
24
35
 
25
36
  # qaoalib
26
- A package for QAOA Max-cut Calculations.
37
+ Implementations of VQA simulations for combinatorial optimization (mainly with graph and Max-cut).
27
38
 
28
- Packages required:
29
- - numpy
30
- - networkx
31
- - matplotlib
32
- - qiskit
39
+ v0.2 works towards adapting the circuit simulations with new Qiskit primitives: `Sampler` and `Estimator` (starting from Qiskit 1.0).
33
40
 
34
41
  # How to install
35
42
  You can install from the PyPI:
@@ -38,6 +45,21 @@ pip install --upgrade qaoalib
38
45
  ```
39
46
 
40
47
  # Usage
48
+ Solving Max-cut with VQE:
49
+ ```
50
+ import networkx as nx
51
+ from qaoalib.solver import VQE
52
+ from qiskit_optimization.applications import Maxcut
53
+
54
+ G = nx.random_regular_graph(3, 6) # 3-regular graph wtih 6 nodes
55
+ qp = Maxcut(G).to_quadratic_program()
56
+ ansatz = # some preferred ansatz
57
+ solver = VQE(qp, ansatz)
58
+ result = solver.solve()
59
+ print(result)
60
+ ```
61
+
62
+ # Usage (legacy)
41
63
  Calculate Max-cut expectation with `Qmc` or `QmcFastKron` (faster version):
42
64
  ```
43
65
  import networkx as nx
@@ -1,11 +1,7 @@
1
1
  # qaoalib
2
- A package for QAOA Max-cut Calculations.
2
+ Implementations of VQA simulations for combinatorial optimization (mainly with graph and Max-cut).
3
3
 
4
- Packages required:
5
- - numpy
6
- - networkx
7
- - matplotlib
8
- - qiskit
4
+ v0.2 works towards adapting the circuit simulations with new Qiskit primitives: `Sampler` and `Estimator` (starting from Qiskit 1.0).
9
5
 
10
6
  # How to install
11
7
  You can install from the PyPI:
@@ -14,6 +10,21 @@ pip install --upgrade qaoalib
14
10
  ```
15
11
 
16
12
  # Usage
13
+ Solving Max-cut with VQE:
14
+ ```
15
+ import networkx as nx
16
+ from qaoalib.solver import VQE
17
+ from qiskit_optimization.applications import Maxcut
18
+
19
+ G = nx.random_regular_graph(3, 6) # 3-regular graph wtih 6 nodes
20
+ qp = Maxcut(G).to_quadratic_program()
21
+ ansatz = # some preferred ansatz
22
+ solver = VQE(qp, ansatz)
23
+ result = solver.solve()
24
+ print(result)
25
+ ```
26
+
27
+ # Usage (legacy)
17
28
  Calculate Max-cut expectation with `Qmc` or `QmcFastKron` (faster version):
18
29
  ```
19
30
  import networkx as nx
@@ -0,0 +1,222 @@
1
+ import numpy as np
2
+ import networkx as nx
3
+
4
+ from qiskit import QuantumCircuit
5
+ from qiskit.quantum_info import SparsePauliOp
6
+ from qiskit.circuit import ParameterVector
7
+ from qiskit.circuit.library import PauliEvolutionGate
8
+
9
+
10
+ def generate_sum_x_pauli_str(length):
11
+ ret = []
12
+ for i in range(length):
13
+ paulis = ['I'] * length
14
+ paulis[i] = 'X'
15
+ ret.append(''.join(paulis))
16
+
17
+ return ret
18
+
19
+ def qaoa(problem_ham: SparsePauliOp, reps: int = 1) -> QuantumCircuit:
20
+ r"""
21
+ Input:
22
+ - problem_ham: Problem Hamiltonian to construct the QAOA circuit.
23
+ Standard procedure would be:
24
+ ```
25
+ hamiltonian, offset = qubo.to_ising()
26
+ qc = qaoa_circuit_from_qubo(hamiltonian)
27
+ ```
28
+
29
+ Returns:
30
+ - qc: A QuantumCircuit object representing the QAOA circuit e^{-i\beta H_M} e^{-i\gamma H_C}.
31
+ """
32
+ num_qubits = problem_ham.num_qubits
33
+
34
+ gamma = ParameterVector(name=r'$\gamma$', length=reps)
35
+ beta = ParameterVector(name=r'$\beta$', length=reps)
36
+
37
+ mixer_ham = SparsePauliOp(generate_sum_x_pauli_str(num_qubits))
38
+
39
+ qc = QuantumCircuit(num_qubits)
40
+ qc.h(range(num_qubits))
41
+
42
+ for p in range(reps):
43
+ exp_gamma = PauliEvolutionGate(problem_ham, time=gamma[p])
44
+ exp_beta = PauliEvolutionGate(mixer_ham, time=beta[p])
45
+ qc.append(exp_gamma, qargs=range(num_qubits))
46
+ qc.append(exp_beta, qargs=range(num_qubits))
47
+
48
+ return qc
49
+
50
+ def multi_angle_qaoa(problem_ham: SparsePauliOp, reps: int = 1) -> QuantumCircuit:
51
+ r"""
52
+ Input:
53
+ - problem_ham: Problem Hamiltonian to construct the QAOA circuit.
54
+ Standard procedure would be:
55
+ ```
56
+ hamiltonian, offset = qubo.to_ising()
57
+ qc = qaoa_circuit_from_qubo(hamiltonian)
58
+ ```
59
+
60
+ Returns:
61
+ - qc: A QuantumCircuit object representing the QAOA circuit e^{-i\beta H_M} e^{-i\gamma H_C}.
62
+ """
63
+ num_qubits = problem_ham.num_qubits
64
+
65
+ gamma = ParameterVector(name=r'$\gamma$', length=len(problem_ham) * reps)
66
+ beta = ParameterVector(name=r'$\beta$', length=num_qubits * reps)
67
+
68
+ qc = QuantumCircuit(num_qubits)
69
+ qc.h(range(num_qubits))
70
+
71
+ for p in range(reps):
72
+ for idx, term in enumerate(problem_ham):
73
+ exp_gamma = PauliEvolutionGate(term, time=gamma[p * num_qubits + idx])
74
+ qc.append(exp_gamma, qargs=range(num_qubits))
75
+ for i in range(num_qubits):
76
+ qc.rx(beta[p * num_qubits + i], i)
77
+
78
+ return qc
79
+
80
+ def two_local(num_qubits: int, reps: int = 1, entanglement: str = 'linear') -> QuantumCircuit:
81
+ # only linear or circular entanglement
82
+ if entanglement not in ['linear', 'circular']:
83
+ raise ValueError(f'Entanglment must be linear or circular, got {entanglement} instead.')
84
+
85
+ qc = QuantumCircuit(num_qubits)
86
+ params = ParameterVector('θ', num_qubits * (reps + 1))
87
+
88
+ for i in range(num_qubits):
89
+ qc.ry(params[i], i)
90
+
91
+ for r in range(1, reps + 1):
92
+ for i in range(num_qubits - 1):
93
+ qc.cz(i, i+1)
94
+ if entanglement == 'circular':
95
+ qc.cz(num_qubits - 1, 0)
96
+ for i in range(num_qubits):
97
+ qc.ry(params[r * num_qubits + i], i)
98
+
99
+ return qc
100
+
101
+ def _det_warm_start_angle(ci: float, epsilon: float):
102
+ if ci <= epsilon:
103
+ return 2 * np.arcsin(np.sqrt(epsilon))
104
+ elif ci >= 1 - epsilon:
105
+ return 2 * np.arcsin(np.sqrt(1 - epsilon))
106
+ else:
107
+ return 2 * np.arcsin(np.sqrt(ci))
108
+
109
+ def warm_start_qaoa(
110
+ problem_ham: SparsePauliOp,
111
+ relaxed_qp_solution: list[float],
112
+ depth: int = 1,
113
+ regularization: float = 0.01,
114
+ flip_solution_indices: bool = False,
115
+ ) -> QuantumCircuit:
116
+ r"""
117
+ Input:
118
+ - problem_ham: Problem Hamiltonian to construct the QAOA circuit.
119
+ - relaxed_qp_solution: The solution for the relaxed quadratic program.
120
+
121
+ Returns:
122
+ - qc: A QuantumCircuit object representing the QAOA circuit e^{-i\beta H_M} e^{-i\gamma H_C}.
123
+ """
124
+ num_qubits = problem_ham.num_qubits
125
+ if num_qubits != len(relaxed_qp_solution):
126
+ raise ValueError(f'The number of qubits and the length of the solution must be equal.')
127
+
128
+ # try setting this to True if doesn't work, as Qiskit works with reversed indices.
129
+ if flip_solution_indices:
130
+ relaxed_qp_solution = relaxed_qp_solution[::-1]
131
+
132
+ gamma = ParameterVector(name=r'$\gamma$', length=depth)
133
+ beta = ParameterVector(name=r'$\beta$', length=depth)
134
+
135
+ # calculate the thetas for warm start
136
+ reg_warm_start_angle = lambda ci: _det_warm_start_angle(ci, regularization)
137
+ theta = list(map(reg_warm_start_angle, relaxed_qp_solution))
138
+
139
+ qc = QuantumCircuit(num_qubits)
140
+
141
+ # initial layer
142
+ for i in range(num_qubits):
143
+ qc.ry(theta[i], i)
144
+
145
+ for p in range(depth):
146
+ # phase separation
147
+ exp_gamma = PauliEvolutionGate(problem_ham, time=gamma[p])
148
+ qc.append(exp_gamma, qargs=range(num_qubits))
149
+
150
+ # mixer
151
+ for i in range(num_qubits):
152
+ qc.ry(-theta[i], i)
153
+ qc.rz(beta[p], i)
154
+ qc.ry(theta[i], i)
155
+
156
+ return qc
157
+
158
+ def rzy_gate(theta: float) -> QuantumCircuit:
159
+ """
160
+ Add RZY gate to QuantumCircuit object, with Z acting on q1 and Y acting on q0 (following qiskit convention).
161
+ RZY(theta) = exp(-i * theta * kron(Y, Z)).
162
+ """
163
+ qc = QuantumCircuit(2, name='Rzy')
164
+ qc.rx(np.pi/2, 1)
165
+ qc.cx(0, 1)
166
+ qc.rz(theta, 1)
167
+ qc.cx(0, 1)
168
+ qc.rx(-np.pi/2, 1)
169
+ return qc
170
+
171
+ def drop_weights(G: nx.Graph) -> nx.Graph:
172
+ G_unweighted = G.copy()
173
+ for _, _, data in G_unweighted.edges(data=True):
174
+ data['weights'] = 1.0
175
+
176
+ return G_unweighted
177
+
178
+ def ihva_from_graph(G: nx.Graph, reps: int = 1, weighted_gates: bool = False) -> QuantumCircuit:
179
+ num_nodes = len(G.nodes)
180
+ num_edges = len(G.edges)
181
+ edge_buffer = []
182
+ G_unweighted = drop_weights(G)
183
+ while G_unweighted.edges:
184
+ tree = nx.maximum_spanning_tree(G_unweighted)
185
+ edge_buffer += list(tree.edges)
186
+ G_unweighted.remove_edges_from(tree.edges)
187
+
188
+ qc = QuantumCircuit(num_nodes)
189
+ qc.h(range(num_nodes))
190
+ params = ParameterVector('θ', num_edges * reps)
191
+ for r in range(reps):
192
+ for idx, edge in enumerate(edge_buffer):
193
+ if r % 2 == 0:
194
+ i, j = edge
195
+ else:
196
+ j, i = edge
197
+ gate_weight = G[i][j]['weight'] if weighted_gates else 1.0
198
+ qc.append(rzy_gate(gate_weight * params [r * num_edges + idx] ), qargs=[i, j])
199
+
200
+ return qc
201
+
202
+ def linear_ansatz(num_qubits: int, reps: int = 1) -> QuantumCircuit:
203
+ qc = QuantumCircuit(num_qubits)
204
+ params = ParameterVector('θ', num_qubits * reps)
205
+
206
+ # initial state
207
+ qc.h(range(num_qubits - 1)) # leave the last qubit with state |0>
208
+
209
+ for r in range(reps):
210
+ for i in range(num_qubits):
211
+ qc.ry(params[r * num_qubits + i], i)
212
+
213
+ return qc
214
+
215
+ def pure_rx_ansatz(num_qubits: int) -> QuantumCircuit:
216
+ params = ParameterVector('θ', num_qubits)
217
+ qc = QuantumCircuit(num_qubits)
218
+
219
+ for i in range(num_qubits):
220
+ qc.rx(params[i], i)
221
+
222
+ return qc
@@ -0,0 +1,118 @@
1
+ import numpy as np
2
+
3
+ from qiskit import QuantumCircuit
4
+ from qiskit.circuit import ParameterVector
5
+ from qiskit.quantum_info import SparsePauliOp, Pauli
6
+ from qiskit_optimization import QuadraticProgram
7
+
8
+ from .vqe import VQE
9
+
10
+ class LCCVQE(VQE):
11
+ """
12
+ LCC for VQE ansatz with circular entanglement.
13
+ * Only works for one-local (Z) or two-local (ZZ) operations.
14
+ * Currently only consider the TwoLocal ansatz with RY rotation, CZ entanglement, and reps=1.
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ quadratic_program: QuadraticProgram,
20
+ shots: int = None,
21
+ sampler=None,
22
+ estimator=None,
23
+ optimizer=None,
24
+ ) -> None:
25
+ super().__init__(
26
+ quadratic_program,
27
+ reps=1,
28
+ shots=shots,
29
+ sampler=sampler,
30
+ estimator=estimator,
31
+ optimizer=optimizer,
32
+ )
33
+
34
+ @staticmethod
35
+ def get_pauli_indices(pauli: Pauli) -> list[int]:
36
+ return np.argwhere(pauli.z).reshape(-1).tolist()
37
+
38
+ @staticmethod
39
+ def generate_local_ansatz(num_qubits: int) -> QuantumCircuit:
40
+ qc = QuantumCircuit(num_qubits)
41
+ theta = ParameterVector('θ', 2 * num_qubits)
42
+
43
+ # First layer RY
44
+ for k in range(num_qubits):
45
+ qc.ry(theta[k], k)
46
+
47
+ # Entangling CNOT
48
+ if num_qubits == 6:
49
+ for j, k in [(0, 1), (1, 2), (3, 4), (4, 5)]:
50
+ qc.cz(j, k)
51
+ else:
52
+ for k in range(num_qubits - 1):
53
+ qc.cz(k, k + 1)
54
+
55
+ # Second layer RY
56
+ for k in range(num_qubits):
57
+ qc.ry(theta[num_qubits + k], k)
58
+
59
+ return qc
60
+
61
+ def _distance(self, i, j):
62
+ return min(abs(i - j), abs(i + self.num_qubits - j), abs(j - i + self.num_qubits))
63
+
64
+ def generate_pubs(
65
+ self,
66
+ params: list[float] | np.ndarray,
67
+ ) -> list[tuple[QuantumCircuit, SparsePauliOp, np.ndarray]]:
68
+ pubs = []
69
+
70
+ for observable in self.hamiltonian:
71
+ pauli_indices = self.get_pauli_indices(observable.paulis[0])
72
+ if len(pauli_indices) == 1:
73
+ # one-local, 3-qubit
74
+ qc = self.generate_local_ansatz(3)
75
+ local_ob = SparsePauliOp('IZI', observable.coeffs[0])
76
+ i = pauli_indices[0]
77
+ first_layer = np.array([(i - 1), i, (i + 1)]) % self.num_qubits
78
+
79
+ elif len(pauli_indices) == 2:
80
+ # two-local
81
+ i, j = pauli_indices
82
+ if self._distance(i, j) == 1:
83
+ # 4-qubit
84
+
85
+ qc = self.generate_local_ansatz(4)
86
+ local_ob = SparsePauliOp('IZZI', observable.coeffs[0])
87
+
88
+ if i == 0 and j == self.num_qubits - 1:
89
+ first_layer = np.array([j - 1, j, i, i + 1]) % self.num_qubits
90
+ else:
91
+ first_layer = np.array([i - 1, i, j, j + 1]) % self.num_qubits
92
+
93
+ elif self._distance(i, j) == 2:
94
+ # 5-qubit
95
+ qc = self.generate_local_ansatz(5)
96
+ local_ob = SparsePauliOp('IZIZI', observable.coeffs[0])
97
+
98
+ if i + 2 == j:
99
+ first_layer = np.array([i - 1, i, i + 1, j, j + 1]) % self.num_qubits
100
+ else:
101
+ first_layer = np.array([j - 1, j, i - 1, i, i + 1]) % self.num_qubits
102
+
103
+ elif self._distance(i, j) > 2:
104
+ # 6-qubit
105
+ qc = self.generate_local_ansatz(6)
106
+ local_ob = SparsePauliOp('IZIIZI', observable.coeffs[0])
107
+ first_layer = np.array([i - 1, i, i + 1, j - 1, j, j + 1]) % self.num_qubits
108
+ else:
109
+ raise ValueError(f'Pauli indices must be of 1 or 2 length. Got {len(pauli_indices)} instead.')
110
+
111
+ second_layer = first_layer + self.num_qubits
112
+ param_indices = np.hstack([first_layer, second_layer]).tolist()
113
+
114
+ # construct pub
115
+ params = np.asarray(params)
116
+ pubs.append((qc, local_ob, params[param_indices]))
117
+
118
+ return pubs
@@ -21,12 +21,11 @@ class VQE:
21
21
  def __init__(
22
22
  self,
23
23
  quadratic_program: QuadraticProgram,
24
- ansatz: QuantumCircuit = None,
25
- reps: int = 1,
24
+ ansatz: QuantumCircuit,
26
25
  shots: int = None,
27
26
  sampler=None,
28
27
  estimator=None,
29
- optimizer=None,
28
+ optimizer=None,
30
29
  ) -> None:
31
30
  self.qp = quadratic_program
32
31
  self.converter = QuadraticProgramToQubo()
@@ -37,7 +36,7 @@ class VQE:
37
36
  self.offset: float = offset
38
37
 
39
38
  self.num_qubits = hamiltonian.num_qubits
40
- self.ansatz = self.generate_full_ansatz(hamiltonian.num_qubits, reps) if ansatz is None else ansatz
39
+ self.ansatz = ansatz
41
40
 
42
41
  backend_sv = AerSimulator(method='statevector')
43
42
  backend_mps = AerSimulator(method='matrix_product_state')
@@ -48,33 +47,16 @@ class VQE:
48
47
 
49
48
  self.optimal_params = None
50
49
  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
-
50
+
69
51
  def generate_random_params(self, scale=TWO_PI):
70
52
  return np.random.rand(self.ansatz.num_parameters) * scale
71
-
53
+
72
54
  def generate_pubs(
73
- self,
55
+ self,
74
56
  params: list[float] | np.ndarray,
75
57
  ) -> list[tuple[QuantumCircuit, SparsePauliOp, np.ndarray]]:
76
58
  return [(self.ansatz, self.hamiltonian, params)]
77
-
59
+
78
60
  def compute_energy(self, params: list[float] | np.ndarray) -> float:
79
61
  """
80
62
  Computes the sum of expectation of the ZZ terms.
@@ -83,14 +65,14 @@ class VQE:
83
65
  results = self.estimator.run(pubs).result()
84
66
  evs = [result.data.evs for result in results]
85
67
  return sum(evs)
86
-
68
+
87
69
  def _sample_optimal_circuit(self) -> dict[str, int]:
88
70
  """
89
- Run the full circuit with sampler to get the solution.
71
+ Run the full circuit with sampler to get the solution.
90
72
  """
91
73
  if self.optimal_params is None:
92
74
  raise ValueError('Problem not yet solved. Run LCCVQE.solve() to solve the problem.')
93
-
75
+
94
76
  ansatz = self.ansatz.copy()
95
77
  ansatz.measure_all()
96
78
  result = self.sampler.run([(ansatz, self.optimal_params)], shots=self.shots).result()[0]
@@ -103,13 +85,13 @@ class VQE:
103
85
  for bit_string, count in counts.items():
104
86
  if count == highest_count:
105
87
  return list(map(int, bit_string[::-1])) # flip the bit-string due to qiskit ordering
106
-
88
+
107
89
  def get_qp_solution(self) -> list[float]:
108
90
  qubo_solution = self._sample_most_likely()
109
91
  return self.converter.interpret(qubo_solution)
110
92
 
111
93
  def solve(
112
- self,
94
+ self,
113
95
  initial_point: list[float] | np.ndarray = None,
114
96
  run_sampler: bool = False,
115
97
  ) -> OptimizerResult:
@@ -120,7 +102,7 @@ class VQE:
120
102
  initial_point = self.generate_random_params()
121
103
  else:
122
104
  assert np.asarray(initial_point).shape[0] == self.ansatz.num_parameters, 'Parameter length does not match.'
123
-
105
+
124
106
  def obj_func(params):
125
107
  return self.compute_energy(params)
126
108
 
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: qaoalib
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: A package for QAOA Maxcut calculations
5
5
  Home-page: https://github.com/xenoicwyce/qaoalib
6
6
  Author: Xinwei Lee
@@ -13,23 +13,30 @@ Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: qiskit
15
15
  Requires-Dist: qiskit_optimization
16
+ Requires-Dist: qiskit_algorithms
16
17
  Requires-Dist: qiskit_aer
17
- Requires-Dist: numpy==1.26.0
18
+ Requires-Dist: numpy
18
19
  Requires-Dist: scipy
19
20
  Requires-Dist: pytest
20
21
  Requires-Dist: pytest-cov
21
22
  Requires-Dist: matplotlib
22
23
  Requires-Dist: networkx
23
24
  Requires-Dist: pydantic
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
24
35
 
25
36
  # qaoalib
26
- A package for QAOA Max-cut Calculations.
37
+ Implementations of VQA simulations for combinatorial optimization (mainly with graph and Max-cut).
27
38
 
28
- Packages required:
29
- - numpy
30
- - networkx
31
- - matplotlib
32
- - qiskit
39
+ v0.2 works towards adapting the circuit simulations with new Qiskit primitives: `Sampler` and `Estimator` (starting from Qiskit 1.0).
33
40
 
34
41
  # How to install
35
42
  You can install from the PyPI:
@@ -38,6 +45,21 @@ pip install --upgrade qaoalib
38
45
  ```
39
46
 
40
47
  # Usage
48
+ Solving Max-cut with VQE:
49
+ ```
50
+ import networkx as nx
51
+ from qaoalib.solver import VQE
52
+ from qiskit_optimization.applications import Maxcut
53
+
54
+ G = nx.random_regular_graph(3, 6) # 3-regular graph wtih 6 nodes
55
+ qp = Maxcut(G).to_quadratic_program()
56
+ ansatz = # some preferred ansatz
57
+ solver = VQE(qp, ansatz)
58
+ result = solver.solve()
59
+ print(result)
60
+ ```
61
+
62
+ # Usage (legacy)
41
63
  Calculate Max-cut expectation with `Qmc` or `QmcFastKron` (faster version):
42
64
  ```
43
65
  import networkx as nx
@@ -1,7 +1,10 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
4
+ requirements.txt
3
5
  setup.py
4
6
  qaoalib/__init__.py
7
+ qaoalib/ansatz.py
5
8
  qaoalib/json.py
6
9
  qaoalib/math.py
7
10
  qaoalib/utils.py
@@ -14,5 +17,5 @@ qaoalib.egg-info/top_level.txt
14
17
  qaoalib/models/__init__.py
15
18
  qaoalib/models/result.py
16
19
  qaoalib/solver/__init__.py
17
- qaoalib/solver/vqe.py
18
- test/test.py
20
+ qaoalib/solver/lcc_vqe.py
21
+ qaoalib/solver/vqe.py
@@ -1,7 +1,8 @@
1
1
  qiskit
2
2
  qiskit_optimization
3
+ qiskit_algorithms
3
4
  qiskit_aer
4
- numpy==1.26.0
5
+ numpy
5
6
  scipy
6
7
  pytest
7
8
  pytest-cov
@@ -0,0 +1,11 @@
1
+ qiskit
2
+ qiskit_optimization
3
+ qiskit_algorithms
4
+ qiskit_aer
5
+ numpy
6
+ scipy
7
+ pytest
8
+ pytest-cov
9
+ matplotlib
10
+ networkx
11
+ pydantic
@@ -3,7 +3,11 @@ from setuptools import setup, find_packages
3
3
  with open("README.md", "r", encoding="utf-8") as fh:
4
4
  long_description = fh.read()
5
5
 
6
- exec(open('qaoalib/version.py').read()) # puts __version__ into the namespace
6
+ with open("qaoalib/version.py", "r") as f:
7
+ __version__ = f.read().strip()
8
+
9
+ with open("requirements.txt", "r") as f:
10
+ requirements = [package.strip() for package in f]
7
11
 
8
12
  setup(
9
13
  name="qaoalib",
@@ -21,16 +25,5 @@ setup(
21
25
  ],
22
26
  packages=find_packages(exclude=["test*"]),
23
27
  python_requires=">=3.9",
24
- install_requires=[
25
- "qiskit",
26
- "qiskit_optimization",
27
- "qiskit_aer",
28
- "numpy==1.26.0",
29
- "scipy",
30
- "pytest",
31
- "pytest-cov",
32
- "matplotlib",
33
- "networkx",
34
- "pydantic",
35
- ],
28
+ install_requires=requirements,
36
29
  )
@@ -1 +0,0 @@
1
- __version__ = '0.2.1'
@@ -1,5 +0,0 @@
1
- from qaoalib import *
2
- from qaoalib.models import *
3
- from qaoalib.solver import *
4
- # from qaoalib.qaoa import *
5
- # from qaoalib.qaoa.landscape import *
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes