qoro-divi 0.2.0b1__py3-none-any.whl → 0.5.0__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.
- divi/__init__.py +1 -2
- divi/backends/__init__.py +9 -0
- divi/backends/_circuit_runner.py +70 -0
- divi/backends/_execution_result.py +70 -0
- divi/backends/_parallel_simulator.py +486 -0
- divi/backends/_qoro_service.py +663 -0
- divi/backends/_qpu_system.py +101 -0
- divi/backends/_results_processing.py +133 -0
- divi/circuits/__init__.py +8 -0
- divi/{exp/cirq → circuits/_cirq}/__init__.py +1 -2
- divi/circuits/_cirq/_parser.py +110 -0
- divi/circuits/_cirq/_qasm_export.py +78 -0
- divi/circuits/_core.py +369 -0
- divi/{qasm.py → circuits/_qasm_conversion.py} +73 -14
- divi/circuits/_qasm_validation.py +694 -0
- divi/qprog/__init__.py +24 -6
- divi/qprog/_expectation.py +181 -0
- divi/qprog/_hamiltonians.py +281 -0
- divi/qprog/algorithms/__init__.py +14 -0
- divi/qprog/algorithms/_ansatze.py +356 -0
- divi/qprog/algorithms/_qaoa.py +572 -0
- divi/qprog/algorithms/_vqe.py +249 -0
- divi/qprog/batch.py +383 -73
- divi/qprog/checkpointing.py +556 -0
- divi/qprog/exceptions.py +9 -0
- divi/qprog/optimizers.py +1014 -43
- divi/qprog/quantum_program.py +231 -413
- divi/qprog/variational_quantum_algorithm.py +995 -0
- divi/qprog/workflows/__init__.py +10 -0
- divi/qprog/{_graph_partitioning.py → workflows/_graph_partitioning.py} +139 -95
- divi/qprog/workflows/_qubo_partitioning.py +220 -0
- divi/qprog/workflows/_vqe_sweep.py +560 -0
- divi/reporting/__init__.py +7 -0
- divi/reporting/_pbar.py +127 -0
- divi/reporting/_qlogger.py +68 -0
- divi/reporting/_reporter.py +133 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.5.0.dist-info}/METADATA +43 -15
- qoro_divi-0.5.0.dist-info/RECORD +43 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.5.0.dist-info}/WHEEL +1 -1
- qoro_divi-0.5.0.dist-info/licenses/LICENSES/.license-header +3 -0
- divi/_pbar.py +0 -73
- divi/circuits.py +0 -139
- divi/exp/cirq/_lexer.py +0 -126
- divi/exp/cirq/_parser.py +0 -889
- divi/exp/cirq/_qasm_export.py +0 -37
- divi/exp/cirq/_qasm_import.py +0 -35
- divi/exp/cirq/exception.py +0 -21
- divi/exp/scipy/_cobyla.py +0 -342
- divi/exp/scipy/pyprima/LICENCE.txt +0 -28
- divi/exp/scipy/pyprima/__init__.py +0 -263
- divi/exp/scipy/pyprima/cobyla/__init__.py +0 -0
- divi/exp/scipy/pyprima/cobyla/cobyla.py +0 -599
- divi/exp/scipy/pyprima/cobyla/cobylb.py +0 -849
- divi/exp/scipy/pyprima/cobyla/geometry.py +0 -240
- divi/exp/scipy/pyprima/cobyla/initialize.py +0 -269
- divi/exp/scipy/pyprima/cobyla/trustregion.py +0 -540
- divi/exp/scipy/pyprima/cobyla/update.py +0 -331
- divi/exp/scipy/pyprima/common/__init__.py +0 -0
- divi/exp/scipy/pyprima/common/_bounds.py +0 -41
- divi/exp/scipy/pyprima/common/_linear_constraints.py +0 -46
- divi/exp/scipy/pyprima/common/_nonlinear_constraints.py +0 -64
- divi/exp/scipy/pyprima/common/_project.py +0 -224
- divi/exp/scipy/pyprima/common/checkbreak.py +0 -107
- divi/exp/scipy/pyprima/common/consts.py +0 -48
- divi/exp/scipy/pyprima/common/evaluate.py +0 -101
- divi/exp/scipy/pyprima/common/history.py +0 -39
- divi/exp/scipy/pyprima/common/infos.py +0 -30
- divi/exp/scipy/pyprima/common/linalg.py +0 -452
- divi/exp/scipy/pyprima/common/message.py +0 -336
- divi/exp/scipy/pyprima/common/powalg.py +0 -131
- divi/exp/scipy/pyprima/common/preproc.py +0 -393
- divi/exp/scipy/pyprima/common/present.py +0 -5
- divi/exp/scipy/pyprima/common/ratio.py +0 -56
- divi/exp/scipy/pyprima/common/redrho.py +0 -49
- divi/exp/scipy/pyprima/common/selectx.py +0 -346
- divi/interfaces.py +0 -25
- divi/parallel_simulator.py +0 -258
- divi/qlogger.py +0 -119
- divi/qoro_service.py +0 -343
- divi/qprog/_mlae.py +0 -182
- divi/qprog/_qaoa.py +0 -440
- divi/qprog/_vqe.py +0 -275
- divi/qprog/_vqe_sweep.py +0 -144
- divi/utils.py +0 -116
- qoro_divi-0.2.0b1.dist-info/RECORD +0 -58
- /divi/{qem.py → circuits/qem.py} +0 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.5.0.dist-info/licenses}/LICENSE +0 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.5.0.dist-info/licenses}/LICENSES/Apache-2.0.txt +0 -0
divi/qprog/_vqe.py
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from enum import Enum
|
|
6
|
-
|
|
7
|
-
import numpy as np
|
|
8
|
-
import pennylane as qml
|
|
9
|
-
import sympy as sp
|
|
10
|
-
|
|
11
|
-
from divi.circuits import MetaCircuit
|
|
12
|
-
from divi.qprog import QuantumProgram
|
|
13
|
-
from divi.qprog.optimizers import Optimizer
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class VQEAnsatz(Enum):
|
|
17
|
-
UCCSD = "UCCSD"
|
|
18
|
-
RY = "RY"
|
|
19
|
-
RYRZ = "RYRZ"
|
|
20
|
-
HW_EFFICIENT = "HW_EFFICIENT"
|
|
21
|
-
QAOA = "QAOA"
|
|
22
|
-
HARTREE_FOCK = "HF"
|
|
23
|
-
|
|
24
|
-
def describe(self):
|
|
25
|
-
return self.name, self.value
|
|
26
|
-
|
|
27
|
-
def n_params(self, n_qubits, **kwargs):
|
|
28
|
-
if self in (VQEAnsatz.UCCSD, VQEAnsatz.HARTREE_FOCK):
|
|
29
|
-
singles, doubles = qml.qchem.excitations(
|
|
30
|
-
kwargs.pop("n_electrons"), n_qubits
|
|
31
|
-
)
|
|
32
|
-
s_wires, d_wires = qml.qchem.excitations_to_wires(singles, doubles)
|
|
33
|
-
|
|
34
|
-
return len(s_wires) + len(d_wires)
|
|
35
|
-
elif self == VQEAnsatz.RY:
|
|
36
|
-
return n_qubits
|
|
37
|
-
elif self == VQEAnsatz.RYRZ:
|
|
38
|
-
return 2 * n_qubits
|
|
39
|
-
elif self == VQEAnsatz.HW_EFFICIENT:
|
|
40
|
-
raise NotImplementedError
|
|
41
|
-
elif self == VQEAnsatz.QAOA:
|
|
42
|
-
return qml.QAOAEmbedding.shape(n_layers=1, n_wires=n_qubits)[1]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class VQE(QuantumProgram):
|
|
46
|
-
def __init__(
|
|
47
|
-
self,
|
|
48
|
-
symbols,
|
|
49
|
-
bond_length: float,
|
|
50
|
-
coordinate_structure: list[tuple[float, float, float]],
|
|
51
|
-
charge: float = 0,
|
|
52
|
-
n_layers: int = 1,
|
|
53
|
-
ansatz=VQEAnsatz.HARTREE_FOCK,
|
|
54
|
-
optimizer=Optimizer.MONTE_CARLO,
|
|
55
|
-
max_iterations=10,
|
|
56
|
-
**kwargs,
|
|
57
|
-
) -> None:
|
|
58
|
-
"""
|
|
59
|
-
Initialize the VQE problem.
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
symbols (list): The symbols of the atoms in the molecule
|
|
63
|
-
bond_length (float): The bond length to consider
|
|
64
|
-
coordinate_structure (list): The coordinate structure of the molecule, represented in unit lengths
|
|
65
|
-
charge (float): the charge of the molecule. Defaults to 0.
|
|
66
|
-
ansatz (VQEAnsatz): The ansatz to use for the VQE problem
|
|
67
|
-
optimizer (Optimizers): The optimizer to use.
|
|
68
|
-
max_iterations (int): Maximum number of iteration optimizers.
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
|
-
# Local Variables
|
|
72
|
-
self.symbols = symbols
|
|
73
|
-
self.coordinate_structure = coordinate_structure
|
|
74
|
-
self.bond_length = bond_length
|
|
75
|
-
self.charge = charge
|
|
76
|
-
if len(self.coordinate_structure) != len(self.symbols):
|
|
77
|
-
raise ValueError(
|
|
78
|
-
"The number of symbols must match the number of coordinates"
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
self.n_layers = n_layers
|
|
82
|
-
self.results = {}
|
|
83
|
-
self.ansatz = ansatz
|
|
84
|
-
self.optimizer = optimizer
|
|
85
|
-
self.max_iterations = max_iterations
|
|
86
|
-
self.current_iteration = 0
|
|
87
|
-
|
|
88
|
-
self.cost_hamiltonian = self._generate_hamiltonian_operations()
|
|
89
|
-
|
|
90
|
-
super().__init__(**kwargs)
|
|
91
|
-
|
|
92
|
-
self._meta_circuits = self._create_meta_circuits_dict()
|
|
93
|
-
|
|
94
|
-
def _generate_hamiltonian_operations(self) -> qml.operation.Operator:
|
|
95
|
-
"""
|
|
96
|
-
Generate the Hamiltonian operators for the given bond length.
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
The Hamiltonian corresponding to the VQE problem.
|
|
100
|
-
"""
|
|
101
|
-
|
|
102
|
-
coordinates = [
|
|
103
|
-
(
|
|
104
|
-
coord_0 * self.bond_length,
|
|
105
|
-
coord_1 * self.bond_length,
|
|
106
|
-
coord_2 * self.bond_length,
|
|
107
|
-
)
|
|
108
|
-
for (coord_0, coord_1, coord_2) in self.coordinate_structure
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
coordinates = np.array(coordinates)
|
|
112
|
-
molecule = qml.qchem.Molecule(self.symbols, coordinates, charge=self.charge)
|
|
113
|
-
hamiltonian, qubits = qml.qchem.molecular_hamiltonian(molecule)
|
|
114
|
-
|
|
115
|
-
self.n_qubits = qubits
|
|
116
|
-
self.n_electrons = molecule.n_electrons
|
|
117
|
-
|
|
118
|
-
self.n_params = self.ansatz.n_params(
|
|
119
|
-
self.n_qubits, n_electrons=self.n_electrons
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
constant_terms_idx = list(
|
|
123
|
-
filter(
|
|
124
|
-
lambda x: all(
|
|
125
|
-
isinstance(term, qml.I) for term in hamiltonian[x].terms()[1]
|
|
126
|
-
),
|
|
127
|
-
range(len(hamiltonian)),
|
|
128
|
-
)
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
self.loss_constant = sum(
|
|
132
|
-
map(lambda x: hamiltonian[x].scalar.item(), constant_terms_idx)
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
for idx in constant_terms_idx:
|
|
136
|
-
hamiltonian -= hamiltonian[idx]
|
|
137
|
-
|
|
138
|
-
return hamiltonian.simplify()
|
|
139
|
-
|
|
140
|
-
def _create_meta_circuits_dict(self) -> dict[str, MetaCircuit]:
|
|
141
|
-
weights_syms = sp.symarray("w", (self.n_layers, self.n_params))
|
|
142
|
-
|
|
143
|
-
def _prepare_circuit(ansatz, hamiltonian, params):
|
|
144
|
-
"""
|
|
145
|
-
Prepare the circuit for the VQE problem.
|
|
146
|
-
Args:
|
|
147
|
-
ansatz (Ansatze): The ansatz to use
|
|
148
|
-
hamiltonian (qml.Hamiltonian): The Hamiltonian to use
|
|
149
|
-
params (list): The parameters to use for the ansatz
|
|
150
|
-
"""
|
|
151
|
-
self._set_ansatz(ansatz, params)
|
|
152
|
-
|
|
153
|
-
# Even though in principle we want to sample from a state,
|
|
154
|
-
# we are applying an `expval` operation here to make it compatible
|
|
155
|
-
# with the pennylane transforms down the line, which complain about
|
|
156
|
-
# the `sample` operation.
|
|
157
|
-
return qml.expval(hamiltonian)
|
|
158
|
-
|
|
159
|
-
return {
|
|
160
|
-
"cost_circuit": self._meta_circuit_factory(
|
|
161
|
-
qml.tape.make_qscript(_prepare_circuit)(
|
|
162
|
-
self.ansatz, self.cost_hamiltonian, weights_syms
|
|
163
|
-
),
|
|
164
|
-
symbols=weights_syms.flatten(),
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
def _set_ansatz(self, ansatz: VQEAnsatz, params):
|
|
169
|
-
"""
|
|
170
|
-
Set the ansatz for the VQE problem.
|
|
171
|
-
Args:
|
|
172
|
-
ansatz (Ansatze): The ansatz to use
|
|
173
|
-
params (list): The parameters to use for the ansatz
|
|
174
|
-
n_layers (int): The number of layers to use for the ansatz
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
def _add_hw_efficient_ansatz(params):
|
|
178
|
-
raise NotImplementedError
|
|
179
|
-
|
|
180
|
-
def _add_qaoa_ansatz(params):
|
|
181
|
-
# This infers layers automatically from the parameters shape
|
|
182
|
-
qml.QAOAEmbedding(
|
|
183
|
-
features=[],
|
|
184
|
-
weights=params.reshape(self.n_layers, -1),
|
|
185
|
-
wires=range(self.n_qubits),
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
def _add_ry_ansatz(params):
|
|
189
|
-
qml.layer(
|
|
190
|
-
qml.AngleEmbedding,
|
|
191
|
-
self.n_layers,
|
|
192
|
-
params.reshape(self.n_layers, -1),
|
|
193
|
-
wires=range(self.n_qubits),
|
|
194
|
-
rotation="Y",
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
def _add_ryrz_ansatz(params):
|
|
198
|
-
def _ryrz(params, wires):
|
|
199
|
-
ry_rots, rz_rots = params.reshape(2, -1)
|
|
200
|
-
qml.AngleEmbedding(ry_rots, wires=wires, rotation="Y")
|
|
201
|
-
qml.AngleEmbedding(rz_rots, wires=wires, rotation="Z")
|
|
202
|
-
|
|
203
|
-
qml.layer(
|
|
204
|
-
_ryrz,
|
|
205
|
-
self.n_layers,
|
|
206
|
-
params.reshape(self.n_layers, -1),
|
|
207
|
-
wires=range(self.n_qubits),
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
def _add_uccsd_ansatz(params):
|
|
211
|
-
hf_state = qml.qchem.hf_state(self.n_electrons, self.n_qubits)
|
|
212
|
-
|
|
213
|
-
singles, doubles = qml.qchem.excitations(self.n_electrons, self.n_qubits)
|
|
214
|
-
s_wires, d_wires = qml.qchem.excitations_to_wires(singles, doubles)
|
|
215
|
-
|
|
216
|
-
qml.UCCSD(
|
|
217
|
-
params.reshape(self.n_layers, -1),
|
|
218
|
-
wires=range(self.n_qubits),
|
|
219
|
-
s_wires=s_wires,
|
|
220
|
-
d_wires=d_wires,
|
|
221
|
-
init_state=hf_state,
|
|
222
|
-
n_repeats=self.n_layers,
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
def _add_hartree_fock_ansatz(params):
|
|
226
|
-
singles, doubles = qml.qchem.excitations(self.n_electrons, self.n_qubits)
|
|
227
|
-
hf_state = qml.qchem.hf_state(self.n_electrons, self.n_qubits)
|
|
228
|
-
|
|
229
|
-
qml.layer(
|
|
230
|
-
qml.AllSinglesDoubles,
|
|
231
|
-
self.n_layers,
|
|
232
|
-
params.reshape(self.n_layers, -1),
|
|
233
|
-
wires=range(self.n_qubits),
|
|
234
|
-
hf_state=hf_state,
|
|
235
|
-
singles=singles,
|
|
236
|
-
doubles=doubles,
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
# Reset the BasisState operations after the first layer
|
|
240
|
-
# for behaviour similar to UCCSD ansatz
|
|
241
|
-
for op in qml.QueuingManager.active_context().queue[1:]:
|
|
242
|
-
op._hyperparameters["hf_state"] = 0
|
|
243
|
-
|
|
244
|
-
if ansatz in VQEAnsatz:
|
|
245
|
-
locals()[f"_add_{ansatz.name.lower()}_ansatz"](params)
|
|
246
|
-
else:
|
|
247
|
-
raise ValueError(f"Invalid Ansatz Value. Got {ansatz}.")
|
|
248
|
-
|
|
249
|
-
def _generate_circuits(self):
|
|
250
|
-
"""
|
|
251
|
-
Generate the circuits for the VQE problem.
|
|
252
|
-
|
|
253
|
-
In this method, we generate bulk circuits based on the selected parameters.
|
|
254
|
-
We generate circuits for each bond length and each ansatz and optimization choice.
|
|
255
|
-
|
|
256
|
-
The structure of the circuits is as follows:
|
|
257
|
-
- For each bond length:
|
|
258
|
-
- For each ansatz:
|
|
259
|
-
- Generate the circuit
|
|
260
|
-
"""
|
|
261
|
-
|
|
262
|
-
for p, params_group in enumerate(self._curr_params):
|
|
263
|
-
circuit = self._meta_circuits[
|
|
264
|
-
"cost_circuit"
|
|
265
|
-
].initialize_circuit_from_params(params_group, tag_prefix=f"{p}")
|
|
266
|
-
|
|
267
|
-
self.circuits.append(circuit)
|
|
268
|
-
|
|
269
|
-
def _run_optimization_circuits(self, store_data, data_file):
|
|
270
|
-
if self.cost_hamiltonian is None or len(self.cost_hamiltonian) == 0:
|
|
271
|
-
raise RuntimeError(
|
|
272
|
-
"Hamiltonian operators must be generated before running the VQE"
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
return super()._run_optimization_circuits(store_data, data_file)
|
divi/qprog/_vqe_sweep.py
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from functools import partial
|
|
6
|
-
from itertools import product
|
|
7
|
-
from typing import Literal
|
|
8
|
-
|
|
9
|
-
import matplotlib.pyplot as plt
|
|
10
|
-
|
|
11
|
-
from divi.qprog import VQE, ProgramBatch, VQEAnsatz
|
|
12
|
-
|
|
13
|
-
from .optimizers import Optimizer
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class VQEHyperparameterSweep(ProgramBatch):
|
|
17
|
-
"""Allows user to carry out a grid search across different values
|
|
18
|
-
for the ansatz and the bond length used in a VQE program.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
bond_lengths: list[float],
|
|
24
|
-
ansatze: list[VQEAnsatz],
|
|
25
|
-
symbols: list[str],
|
|
26
|
-
coordinate_structure: list[tuple[float, float, float]],
|
|
27
|
-
charge: float = 0,
|
|
28
|
-
optimizer: Optimizer = Optimizer.MONTE_CARLO,
|
|
29
|
-
max_iterations: int = 10,
|
|
30
|
-
**kwargs,
|
|
31
|
-
):
|
|
32
|
-
"""Initiates the class.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
bond_lengths (list): The bond lengths to consider.
|
|
36
|
-
ansatze (list): The ansatze to use for the VQE problem.
|
|
37
|
-
symbols (list): The symbols of the atoms in the molecule.
|
|
38
|
-
coordinate_structure (list): The coordinate structure of the molecule.
|
|
39
|
-
optimizer (Optimizers): The optimizer to use.
|
|
40
|
-
max_iterations (int): Maximum number of iteration optimizers.
|
|
41
|
-
"""
|
|
42
|
-
super().__init__(backend=kwargs.pop("backend"))
|
|
43
|
-
|
|
44
|
-
self.ansatze = ansatze
|
|
45
|
-
self.bond_lengths = [round(bnd, 9) for bnd in bond_lengths]
|
|
46
|
-
self.max_iterations = max_iterations
|
|
47
|
-
|
|
48
|
-
self._constructor = partial(
|
|
49
|
-
VQE,
|
|
50
|
-
symbols=symbols,
|
|
51
|
-
coordinate_structure=coordinate_structure,
|
|
52
|
-
charge=charge,
|
|
53
|
-
optimizer=optimizer,
|
|
54
|
-
max_iterations=self.max_iterations,
|
|
55
|
-
backend=self.backend,
|
|
56
|
-
**kwargs,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
def create_programs(self):
|
|
60
|
-
if len(self.programs) > 0:
|
|
61
|
-
raise RuntimeError(
|
|
62
|
-
"Some programs already exist. "
|
|
63
|
-
"Clear the program dictionary before creating new ones by using batch.reset()."
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
super().create_programs()
|
|
67
|
-
|
|
68
|
-
for ansatz, bond_length in product(self.ansatze, self.bond_lengths):
|
|
69
|
-
_job_id = (ansatz, bond_length)
|
|
70
|
-
self.programs[_job_id] = self._constructor(
|
|
71
|
-
job_id=_job_id,
|
|
72
|
-
bond_length=bond_length,
|
|
73
|
-
ansatz=ansatz,
|
|
74
|
-
losses=self._manager.list(),
|
|
75
|
-
final_params=self._manager.list(),
|
|
76
|
-
progress_queue=self._queue,
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
def aggregate_results(self):
|
|
80
|
-
if len(self.programs) == 0:
|
|
81
|
-
raise RuntimeError("No programs to aggregate. Run create_programs() first.")
|
|
82
|
-
|
|
83
|
-
if self._executor is not None:
|
|
84
|
-
self.wait_for_all()
|
|
85
|
-
|
|
86
|
-
if any(len(program.losses) == 0 for program in self.programs.values()):
|
|
87
|
-
raise RuntimeError(
|
|
88
|
-
"Some/All programs have empty losses. Did you call run()?"
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
all_energies = {key: prog.losses[-1] for key, prog in self.programs.items()}
|
|
92
|
-
|
|
93
|
-
smallest_key = min(all_energies, key=lambda k: min(all_energies[k].values()))
|
|
94
|
-
smallest_value = min(all_energies[smallest_key].values())
|
|
95
|
-
|
|
96
|
-
return smallest_key, smallest_value
|
|
97
|
-
|
|
98
|
-
def visualize_results(self, graph_type: Literal["line", "scatter"] = "line"):
|
|
99
|
-
"""
|
|
100
|
-
Visualize the results of the VQE problem.
|
|
101
|
-
"""
|
|
102
|
-
if graph_type not in ["line", "scatter"]:
|
|
103
|
-
raise ValueError(
|
|
104
|
-
f"Invalid graph type: {graph_type}. Choose between 'line' and 'scatter'."
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
if self._executor is not None:
|
|
108
|
-
self.wait_for_all()
|
|
109
|
-
|
|
110
|
-
data = []
|
|
111
|
-
colors = ["blue", "g", "r", "c", "m", "y", "k"]
|
|
112
|
-
|
|
113
|
-
ansatz_list = list(VQEAnsatz)
|
|
114
|
-
|
|
115
|
-
if graph_type == "scatter":
|
|
116
|
-
for ansatz, bond_length in self.programs.keys():
|
|
117
|
-
min_energies = []
|
|
118
|
-
|
|
119
|
-
curr_energies = self.programs[(ansatz, bond_length)].losses[-1]
|
|
120
|
-
min_energies.append(
|
|
121
|
-
(
|
|
122
|
-
bond_length,
|
|
123
|
-
min(curr_energies.values()),
|
|
124
|
-
colors[ansatz_list.index(ansatz)],
|
|
125
|
-
)
|
|
126
|
-
)
|
|
127
|
-
data.extend(min_energies)
|
|
128
|
-
|
|
129
|
-
x, y, z = zip(*data)
|
|
130
|
-
plt.scatter(x, y, color=z, label=ansatz)
|
|
131
|
-
|
|
132
|
-
elif graph_type == "line":
|
|
133
|
-
for ansatz in self.ansatze:
|
|
134
|
-
energies = []
|
|
135
|
-
for bond_length in self.bond_lengths:
|
|
136
|
-
energies.append(
|
|
137
|
-
min(self.programs[(ansatz, bond_length)].losses[-1].values())
|
|
138
|
-
)
|
|
139
|
-
plt.plot(self.bond_lengths, energies, label=ansatz)
|
|
140
|
-
|
|
141
|
-
plt.xlabel("Bond length")
|
|
142
|
-
plt.ylabel("Energy level")
|
|
143
|
-
plt.legend()
|
|
144
|
-
plt.show()
|
divi/utils.py
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from functools import reduce
|
|
6
|
-
from warnings import warn
|
|
7
|
-
|
|
8
|
-
import numpy as np
|
|
9
|
-
import pennylane as qml
|
|
10
|
-
import scipy.sparse as sps
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _is_sanitized(
|
|
14
|
-
qubo_matrix: np.ndarray | sps.spmatrix,
|
|
15
|
-
) -> np.ndarray | sps.spmatrix:
|
|
16
|
-
# Sanitize the QUBO matrix to ensure it is either symmetric or upper triangular.
|
|
17
|
-
|
|
18
|
-
is_sparse = sps.issparse(qubo_matrix)
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
(
|
|
22
|
-
((qubo_matrix != qubo_matrix.T).nnz == 0)
|
|
23
|
-
or ((qubo_matrix != sps.triu(qubo_matrix)).nnz == 0)
|
|
24
|
-
)
|
|
25
|
-
if is_sparse
|
|
26
|
-
else (
|
|
27
|
-
np.allclose(qubo_matrix, qubo_matrix.T)
|
|
28
|
-
or np.allclose(qubo_matrix, np.triu(qubo_matrix))
|
|
29
|
-
)
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def convert_qubo_matrix_to_pennylane_ising(
|
|
34
|
-
qubo_matrix: np.ndarray | sps.spmatrix,
|
|
35
|
-
) -> tuple[qml.operation.Operator, float]:
|
|
36
|
-
"""Convert QUBO matrix to Ising Hamiltonian in Pennylane.
|
|
37
|
-
|
|
38
|
-
The conversion follows the mapping:
|
|
39
|
-
- QUBO variables x_i ∈ {0,1} map to Ising variables s_i ∈ {-1,1} via s_i = 2x_i - 1
|
|
40
|
-
- This transforms a QUBO problem into an equivalent Ising problem
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
qubo_matrix: The QUBO matrix Q where the objective is to minimize x^T Q x
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
A tuple of (Ising Hamiltonian as a PennyLane operator, constant term)
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
if not _is_sanitized(qubo_matrix):
|
|
50
|
-
warn(
|
|
51
|
-
"The QUBO matrix is neither symmetric nor upper triangular."
|
|
52
|
-
" Symmetrizing it for the Ising Hamiltonian creation."
|
|
53
|
-
)
|
|
54
|
-
qubo_matrix = (qubo_matrix + qubo_matrix.T) / 2
|
|
55
|
-
|
|
56
|
-
is_sparse = sps.issparse(qubo_matrix)
|
|
57
|
-
backend = sps if is_sparse else np
|
|
58
|
-
|
|
59
|
-
# Gather non-zero indices in the upper triangle of the matrix
|
|
60
|
-
triu_matrix = backend.triu(
|
|
61
|
-
qubo_matrix,
|
|
62
|
-
**(
|
|
63
|
-
{"format": qubo_matrix.format if qubo_matrix.format != "coo" else "csc"}
|
|
64
|
-
if is_sparse
|
|
65
|
-
else {}
|
|
66
|
-
),
|
|
67
|
-
)
|
|
68
|
-
rows, cols = triu_matrix.nonzero()
|
|
69
|
-
values = triu_matrix[rows, cols].A1 if is_sparse else triu_matrix[rows, cols]
|
|
70
|
-
|
|
71
|
-
n = qubo_matrix.shape[0]
|
|
72
|
-
linear_terms = np.zeros(n)
|
|
73
|
-
constant_term = 0.0
|
|
74
|
-
ising_terms = []
|
|
75
|
-
ising_weights = []
|
|
76
|
-
|
|
77
|
-
for i, j, weight in zip(rows, cols, values):
|
|
78
|
-
weight = float(weight)
|
|
79
|
-
i, j = int(i), int(j)
|
|
80
|
-
|
|
81
|
-
if i == j:
|
|
82
|
-
# Diagonal elements
|
|
83
|
-
linear_terms[i] -= weight / 2
|
|
84
|
-
constant_term += weight / 2
|
|
85
|
-
else:
|
|
86
|
-
# Off-diagonal elements (i < j since we're using triu)
|
|
87
|
-
ising_terms.append([i, j])
|
|
88
|
-
ising_weights.append(weight / 4)
|
|
89
|
-
|
|
90
|
-
# Update linear terms
|
|
91
|
-
linear_terms[i] -= weight / 4
|
|
92
|
-
linear_terms[j] -= weight / 4
|
|
93
|
-
|
|
94
|
-
# Update constant term
|
|
95
|
-
constant_term += weight / 4
|
|
96
|
-
|
|
97
|
-
# Add the linear terms (Z operators)
|
|
98
|
-
for i, curr_lin_term in filter(lambda x: x[1] != 0, enumerate(linear_terms)):
|
|
99
|
-
ising_terms.append([i])
|
|
100
|
-
ising_weights.append(float(curr_lin_term))
|
|
101
|
-
|
|
102
|
-
# Construct the Ising Hamiltonian as a PennyLane operator
|
|
103
|
-
pauli_string = qml.Identity(0) * 0
|
|
104
|
-
for term, weight in zip(ising_terms, ising_weights):
|
|
105
|
-
if len(term) == 1:
|
|
106
|
-
# Single-qubit term (Z operator)
|
|
107
|
-
curr_term = qml.Z(term[0]) * weight
|
|
108
|
-
else:
|
|
109
|
-
# Two-qubit term (ZZ interaction)
|
|
110
|
-
curr_term = (
|
|
111
|
-
reduce(lambda x, y: x @ y, map(lambda x: qml.Z(x), term)) * weight
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
pauli_string += curr_term
|
|
115
|
-
|
|
116
|
-
return pauli_string.simplify(), constant_term
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
divi/__init__.py,sha256=WNAlzdjio0M5la_NTGk4-0AFqItI6HEBExRs6ck9j0Y,203
|
|
2
|
-
divi/_pbar.py,sha256=YDTXMPa8INGzY2zJRloUj5YVINg6TYDqKDY4Yt1qtek,2051
|
|
3
|
-
divi/circuits.py,sha256=tNNCZ61w06aaysOkr_1-USaeIDu63MbF1k1Ry7Y_T6g,4492
|
|
4
|
-
divi/exp/cirq/__init__.py,sha256=TLt2WskG9j-y17Lv0Zgsg-gQgmZGFbp_lwHQYpj2GsM,312
|
|
5
|
-
divi/exp/cirq/_lexer.py,sha256=x5UArrnN_JEyiq7E02ikq0wdmqZ2vEQ3_FADL1LIhQI,3187
|
|
6
|
-
divi/exp/cirq/_parser.py,sha256=z_bSn4m03-sfRlN8eL99Mo4LnjY-zmR-Xt6UrjzstZc,29279
|
|
7
|
-
divi/exp/cirq/_qasm_export.py,sha256=8C5xLYvIIkQTWWAAYo7ZjwtQjvYXNSflbf5UyUx6YUE,1024
|
|
8
|
-
divi/exp/cirq/_qasm_import.py,sha256=HbehrgfLl3iDdRyWr4o26Bek3ZpN-_dvNVSexl5-aVE,969
|
|
9
|
-
divi/exp/cirq/exception.py,sha256=w1w2vSubOGMRmyKBFqXejxfeIAzkPZ6V7gSrDX_ap4A,765
|
|
10
|
-
divi/exp/scipy/_cobyla.py,sha256=cnCf5AsOM8JWIMiujuUbWMNOgmUr3ZET9y04hUyumHs,10937
|
|
11
|
-
divi/exp/scipy/pyprima/LICENCE.txt,sha256=mXN5ssG_U6OR0v0yldznW_PJTtKNZIgu3jDRtRjLDdY,1533
|
|
12
|
-
divi/exp/scipy/pyprima/__init__.py,sha256=WHV_bPKPLakKdP2TdecrbtMrZ7KR3qb1E3m5VkCjLSo,8956
|
|
13
|
-
divi/exp/scipy/pyprima/cobyla/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
divi/exp/scipy/pyprima/cobyla/cobyla.py,sha256=zIHjhLDkzhijMrzypObgYjQQfelUdxp6VOKQd34m_oU,22281
|
|
15
|
-
divi/exp/scipy/pyprima/cobyla/cobylb.py,sha256=DhOW4SnJ8ihLHybC4-1BK2X-5BFZlndEduuagmXQOVY,42091
|
|
16
|
-
divi/exp/scipy/pyprima/cobyla/geometry.py,sha256=YtGsY-lXAKmsuBj_D59H97Z8acDl7fAJGt4QTEigsiU,10789
|
|
17
|
-
divi/exp/scipy/pyprima/cobyla/initialize.py,sha256=QT9rpkO8IjlljA-z5wPxg7KFWtB_ae38Z7Ww0S-fMpU,9964
|
|
18
|
-
divi/exp/scipy/pyprima/cobyla/trustregion.py,sha256=AD_tdF7VCt6xBrduv0KFr7VgyUoGdIIz4mwde_9dk0g,26021
|
|
19
|
-
divi/exp/scipy/pyprima/cobyla/update.py,sha256=VuwqaE3wXxsGopPAkOAATmesLDUH-8WZrw3iRqu3jzs,14353
|
|
20
|
-
divi/exp/scipy/pyprima/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
divi/exp/scipy/pyprima/common/_bounds.py,sha256=0tY542ERqX53I5lreyVUy9XVXfNFvt1bx9peKM70U3U,1683
|
|
22
|
-
divi/exp/scipy/pyprima/common/_linear_constraints.py,sha256=piTatWAMPQo-nwFB14VpRQ6JphBgrBL8OjLysBrTlhI,2160
|
|
23
|
-
divi/exp/scipy/pyprima/common/_nonlinear_constraints.py,sha256=evfY-4FWXKcGae658NXfrlSpCtkHRxCqSG-MyO-WDx4,2180
|
|
24
|
-
divi/exp/scipy/pyprima/common/_project.py,sha256=dnQURl2ztxjGDvoYgMZGnEqUGLUoNUvBaLS12p9-qN0,8541
|
|
25
|
-
divi/exp/scipy/pyprima/common/checkbreak.py,sha256=WrW_dAjZI_3iKvvG3eLTJCxcj5HkIksUBtQQ9BUdB_E,3549
|
|
26
|
-
divi/exp/scipy/pyprima/common/consts.py,sha256=PiGCfDRy9fZjmGJBeCg25gULDfe1cv2HkjS6CQujphg,1313
|
|
27
|
-
divi/exp/scipy/pyprima/common/evaluate.py,sha256=vzjNPdGiAFdD8qpUVp_V1b5f3t2pFyr2N-sMSnTE6OI,3156
|
|
28
|
-
divi/exp/scipy/pyprima/common/history.py,sha256=m0cQ7VOGefWWKTPweqx3dvGZiyzGClTB0BjaKY5mOtQ,1362
|
|
29
|
-
divi/exp/scipy/pyprima/common/infos.py,sha256=MzhS3XciMW5fg4ccW8ubZ3Mkdp2qT6sq56GAkYZikXI,704
|
|
30
|
-
divi/exp/scipy/pyprima/common/linalg.py,sha256=HYoy6vYR2AMUVGSKbA8xj9tjvloMofk_s26N34qiFNk,14516
|
|
31
|
-
divi/exp/scipy/pyprima/common/message.py,sha256=G2_hmqxKvZg0aGCXqw3VmXDxrle8k0Grujzb4iiuPLI,10086
|
|
32
|
-
divi/exp/scipy/pyprima/common/powalg.py,sha256=Azla5UC3oPppDcSTub_1auLS_QXQ_aY1Djm4RT3HkV4,6825
|
|
33
|
-
divi/exp/scipy/pyprima/common/preproc.py,sha256=Ye62rhEilf3ah9aiGc6cSLZg77_qAi3FPK2r4XvPxGk,14929
|
|
34
|
-
divi/exp/scipy/pyprima/common/present.py,sha256=caedmqSB5ggGXNfky0A6v6FAdyaEGrbMEJqNh5Cf6l4,147
|
|
35
|
-
divi/exp/scipy/pyprima/common/ratio.py,sha256=taadehpW0c3ULUggH5frIMpvTom53dsEhvFaXrIKvOI,1833
|
|
36
|
-
divi/exp/scipy/pyprima/common/redrho.py,sha256=J6rJILcOoCeo942LUAXxpUvKLarUGNCGdC-zcmIlVHE,1264
|
|
37
|
-
divi/exp/scipy/pyprima/common/selectx.py,sha256=mXVS2L6AuTmbOhpp1KlXwOBR54ttnbjwagYfnXhezJY,14713
|
|
38
|
-
divi/interfaces.py,sha256=P-8lekQIGwbhHv4ewfMFtKYIjmQHu7nmscwAmxsx72U,594
|
|
39
|
-
divi/parallel_simulator.py,sha256=SjL23zcS-AKyxHG8TeAowDFytpXAshhy64GEkEUnogs,8988
|
|
40
|
-
divi/qasm.py,sha256=agHSRqkIYdfVx1w0zcaIXYe_KDpNz38tni-cu20SMN4,7418
|
|
41
|
-
divi/qem.py,sha256=o6rMPUcxLuCBitBb8-QcxveUiKZVsP3HMamxyVFLi6M,6805
|
|
42
|
-
divi/qlogger.py,sha256=VaCnw-u8VkR7JukjOp39r0V89wO-SSpDj5l50ejnHUg,3801
|
|
43
|
-
divi/qoro_service.py,sha256=Ry7Pt7EZCpnwwLJ_5Fx2WhXHiFmI6z23zUdAaygkx3Y,11386
|
|
44
|
-
divi/qprog/__init__.py,sha256=z8OTd_PdcnEvrcRGvoGsPjj8WYU8HuMHhNyuVMBsNAE,457
|
|
45
|
-
divi/qprog/_graph_partitioning.py,sha256=61bkhz5VTS_pYHSEKCcnvaawD5p0AHk8Fh1EtEjdLkE,22006
|
|
46
|
-
divi/qprog/_mlae.py,sha256=eLEJqYESZG3oI-XsRjgA5aoNs7Er_CspnJ0wJBX0qdU,5769
|
|
47
|
-
divi/qprog/_qaoa.py,sha256=pDMf5RJQ2YHVYiHBpSPu0WkwD4JjF1ARubRD6xbtceA,15445
|
|
48
|
-
divi/qprog/_vqe.py,sha256=JAow9uDTsAOa-n-N5t4CrA04uVuAbGi20s9qB-FSqYU,9427
|
|
49
|
-
divi/qprog/_vqe_sweep.py,sha256=eKvF6sUeqkyRDKuRxd_k-WoQa9ARkzoOLKolLqkpd5s,4873
|
|
50
|
-
divi/qprog/batch.py,sha256=lXID75p4xU88UbukhGIIv6SI1ZrPHsTBzS9u6fPVyhE,7960
|
|
51
|
-
divi/qprog/optimizers.py,sha256=l19zIyt1l0IhUbLofEXlwE9XnsILk7ANlwACi3KKN4w,2034
|
|
52
|
-
divi/qprog/quantum_program.py,sha256=ZMGPFLYZeLiOiU5S7NSlCPAY5vl0R_bv5SRYdEArjSM,16952
|
|
53
|
-
divi/utils.py,sha256=EEyGakoz33AvU0Rq7iijL8AULMg4FGcGBtmOlpSw-tY,3603
|
|
54
|
-
qoro_divi-0.2.0b1.dist-info/LICENSE,sha256=NS4JlQrgNwg1bvB3kE5shE-P4cJgnntgl-kClbOpG_Q,10760
|
|
55
|
-
qoro_divi-0.2.0b1.dist-info/LICENSES/Apache-2.0.txt,sha256=yoILHpvVuguUBpk8UwMnzJbcHUUyst9iGNNuEwUtWVc,10270
|
|
56
|
-
qoro_divi-0.2.0b1.dist-info/METADATA,sha256=8EdyoSoykA9n-MUceXeOP3YjJvXfkZ8lm_MM_iVl940,2073
|
|
57
|
-
qoro_divi-0.2.0b1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
58
|
-
qoro_divi-0.2.0b1.dist-info/RECORD,,
|
/divi/{qem.py → circuits/qem.py}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|