qoro-divi 0.3.1b0__tar.gz → 0.3.3__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.
Potentially problematic release.
This version of qoro-divi might be problematic. Click here for more details.
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/PKG-INFO +3 -3
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/_pbar.py +13 -14
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/__init__.py +1 -1
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_validator.py +1 -1
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qlogger.py +6 -5
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qoro_service.py +26 -13
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/__init__.py +1 -1
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_graph_partitioning.py +4 -7
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_qaoa.py +15 -25
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_qubo_partitioning.py +4 -5
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_vqe.py +6 -5
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_vqe_sweep.py +3 -4
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/batch.py +23 -15
- qoro_divi-0.3.3/divi/qprog/optimizers.py +201 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/quantum_program.py +128 -193
- qoro_divi-0.3.3/divi/reporter.py +90 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/pyproject.toml +3 -3
- qoro_divi-0.3.1b0/divi/qprog/optimizers.py +0 -75
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSE +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSES/.license-header +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSES/Apache-2.0.txt +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/README.md +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/__init__.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/circuits.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_lexer.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_parser.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_qasm_export.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_qasm_import.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/exception.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/_cobyla.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/LICENCE.txt +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/__init__.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/__init__.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/cobyla.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/cobylb.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/geometry.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/initialize.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/trustregion.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/update.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/__init__.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_bounds.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_linear_constraints.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_nonlinear_constraints.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_project.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/checkbreak.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/consts.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/evaluate.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/history.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/infos.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/linalg.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/message.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/powalg.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/preproc.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/present.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/ratio.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/redrho.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/selectx.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/interfaces.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/parallel_simulator.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qasm.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qem.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qpu_system.py +0 -0
- {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qoro-divi
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A Python library to automate generating, parallelizing, and executing quantum programs.
|
|
5
5
|
Author: Ahmed Darwish
|
|
6
6
|
Author-email: ahmed@qoroquantum.de
|
|
@@ -14,14 +14,14 @@ Requires-Dist: dwave-hybrid (>=0.6.14,<0.7.0)
|
|
|
14
14
|
Requires-Dist: matplotlib (>=3.10.3,<4.0.0)
|
|
15
15
|
Requires-Dist: mitiq (>=0.46,<0.47)
|
|
16
16
|
Requires-Dist: networkx (>=3.5,<4.0)
|
|
17
|
-
Requires-Dist: pennylane (>=0.
|
|
17
|
+
Requires-Dist: pennylane (>=0.42.3,<0.43.0)
|
|
18
18
|
Requires-Dist: ply (>=3.11,<4.0)
|
|
19
19
|
Requires-Dist: pymetis (>=2025.1.1,<2026.0.0)
|
|
20
20
|
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
21
21
|
Requires-Dist: qiskit (<2.0)
|
|
22
22
|
Requires-Dist: qiskit-aer (>=0.17.1,<0.18.0)
|
|
23
23
|
Requires-Dist: qiskit-ibm-runtime (>=0.37,<0.38)
|
|
24
|
-
Requires-Dist: qiskit-optimization (>=0.
|
|
24
|
+
Requires-Dist: qiskit-optimization[cplex] (>=0.7.0,<0.8.0)
|
|
25
25
|
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
26
26
|
Requires-Dist: rich (>=14.0.0,<15.0.0)
|
|
27
27
|
Requires-Dist: scikit-learn (>=1.7.0,<2.0.0)
|
|
@@ -28,12 +28,9 @@ class ConditionalSpinnerColumn(ProgressColumn):
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class PhaseStatusColumn(ProgressColumn):
|
|
31
|
-
def __init__(self,
|
|
31
|
+
def __init__(self, table_column=None):
|
|
32
32
|
super().__init__(table_column)
|
|
33
33
|
|
|
34
|
-
self._max_retries = max_retries
|
|
35
|
-
self._last_message = ""
|
|
36
|
-
|
|
37
34
|
def render(self, task):
|
|
38
35
|
final_status = task.fields.get("final_status")
|
|
39
36
|
|
|
@@ -43,27 +40,29 @@ class PhaseStatusColumn(ProgressColumn):
|
|
|
43
40
|
return Text("• Failed! ❌", style="bold red")
|
|
44
41
|
|
|
45
42
|
message = task.fields.get("message")
|
|
46
|
-
if message != "":
|
|
47
|
-
self._last_message = message
|
|
48
43
|
|
|
49
44
|
poll_attempt = task.fields.get("poll_attempt")
|
|
45
|
+
polling_str = ""
|
|
46
|
+
service_job_id = ""
|
|
50
47
|
if poll_attempt > 0:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
48
|
+
max_retries = task.fields.get("max_retries")
|
|
49
|
+
service_job_id = task.fields.get("service_job_id").split("-")[0]
|
|
50
|
+
job_status = task.fields.get("job_status")
|
|
51
|
+
polling_str = f" [Job {service_job_id} is {job_status}. Polling attempt {poll_attempt} / {max_retries}]"
|
|
52
|
+
|
|
53
|
+
final_text = Text(f"[{message}]{polling_str}")
|
|
54
|
+
final_text.highlight_words([service_job_id], "blue")
|
|
54
55
|
|
|
55
|
-
return
|
|
56
|
+
return final_text
|
|
56
57
|
|
|
57
58
|
|
|
58
|
-
def make_progress_bar(
|
|
59
|
-
max_retries: int | None = None, is_jupyter: bool = False
|
|
60
|
-
) -> Progress:
|
|
59
|
+
def make_progress_bar(is_jupyter: bool = False) -> Progress:
|
|
61
60
|
return Progress(
|
|
62
61
|
TextColumn("[bold blue]{task.fields[job_name]}"),
|
|
63
62
|
BarColumn(),
|
|
64
63
|
MofNCompleteColumn(),
|
|
65
64
|
ConditionalSpinnerColumn(),
|
|
66
|
-
PhaseStatusColumn(
|
|
65
|
+
PhaseStatusColumn(),
|
|
67
66
|
# For jupyter notebooks, refresh manually instead
|
|
68
67
|
auto_refresh=not is_jupyter,
|
|
69
68
|
# Give a dummy positive value if is_jupyter
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
# TODO: delete whole module once Cirq properly supports parameters in openqasm 3.0
|
|
6
6
|
from . import _qasm_export # Does nothing, just initiates the patch
|
|
7
7
|
from ._qasm_import import cirq_circuit_from_qasm
|
|
8
|
-
from ._validator import is_valid_qasm
|
|
8
|
+
from ._validator import is_valid_qasm, validate_qasm_raise
|
|
@@ -558,7 +558,7 @@ class Parser:
|
|
|
558
558
|
self._expr_power(allow_id)
|
|
559
559
|
|
|
560
560
|
def _expr_unary(self, allow_id: bool):
|
|
561
|
-
|
|
561
|
+
while self.peek().type in ("PLUS", "MINUS"):
|
|
562
562
|
self.match(self.peek().type)
|
|
563
563
|
self._expr_atom(allow_id)
|
|
564
564
|
|
|
@@ -44,22 +44,23 @@ class OverwriteStreamHandler(logging.StreamHandler):
|
|
|
44
44
|
|
|
45
45
|
def emit(self, record):
|
|
46
46
|
msg = self.format(record)
|
|
47
|
+
append = getattr(record, "append", False)
|
|
47
48
|
|
|
48
|
-
if
|
|
49
|
-
|
|
50
|
-
msg = f"{msg.
|
|
49
|
+
if append:
|
|
50
|
+
space = " " if self._last_record else ""
|
|
51
|
+
msg = f"{msg[:msg.index(record.message)]}{self._last_record}{space}[{record.message[:-2]}]\r"
|
|
51
52
|
|
|
52
53
|
if msg.endswith("\r\n"):
|
|
53
54
|
overwrite_and_newline = True
|
|
54
55
|
clean_msg = msg[:-2]
|
|
55
56
|
|
|
56
|
-
if not
|
|
57
|
+
if not append:
|
|
57
58
|
self._last_record = record.message[:-2]
|
|
58
59
|
elif msg.endswith("\r"):
|
|
59
60
|
overwrite_and_newline = False
|
|
60
61
|
clean_msg = msg[:-1]
|
|
61
62
|
|
|
62
|
-
if not
|
|
63
|
+
if not append:
|
|
63
64
|
self._last_record = record.message[:-1]
|
|
64
65
|
else:
|
|
65
66
|
# Normal message - no overwriting
|
|
@@ -15,7 +15,7 @@ import requests
|
|
|
15
15
|
from dotenv import dotenv_values
|
|
16
16
|
from requests.adapters import HTTPAdapter, Retry
|
|
17
17
|
|
|
18
|
-
from divi.exp.cirq import
|
|
18
|
+
from divi.exp.cirq import validate_qasm_raise
|
|
19
19
|
from divi.interfaces import CircuitRunner
|
|
20
20
|
from divi.qpu_system import QPU, QPUSystem
|
|
21
21
|
|
|
@@ -241,8 +241,9 @@ class QoroService(CircuitRunner):
|
|
|
241
241
|
raise ValueError("Only one circuit allowed for circuit-cutting jobs.")
|
|
242
242
|
|
|
243
243
|
for key, circuit in circuits.items():
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
validate_qasm_raise(circuit)
|
|
245
|
+
# if not is_valid_qasm(circuit):
|
|
246
|
+
# raise ValueError(f"Circuit {key} is not a valid QASM string.")
|
|
246
247
|
|
|
247
248
|
circuit_chunks = self._split_circuits(circuits)
|
|
248
249
|
|
|
@@ -342,7 +343,7 @@ class QoroService(CircuitRunner):
|
|
|
342
343
|
loop_until_complete: bool = False,
|
|
343
344
|
on_complete: Callable | None = None,
|
|
344
345
|
verbose: bool = True,
|
|
345
|
-
|
|
346
|
+
poll_callback: Callable[[int, str], None] | None = None,
|
|
346
347
|
):
|
|
347
348
|
"""
|
|
348
349
|
Get the status of a job and optionally execute function *on_complete* on the results
|
|
@@ -354,13 +355,28 @@ class QoroService(CircuitRunner):
|
|
|
354
355
|
on_complete (optional): A function to be called when the job is completed
|
|
355
356
|
polling_interval (optional): The time to wait between retries
|
|
356
357
|
verbose (optional): A flag to print the when retrying
|
|
357
|
-
|
|
358
|
+
poll_callback (optional): A function for updating progress bars while polling.
|
|
359
|
+
Definition should be `poll_callback(retry_count: int, status: str) -> None`.
|
|
358
360
|
Returns:
|
|
359
361
|
status: The status of the job
|
|
360
362
|
"""
|
|
361
363
|
if not isinstance(job_ids, list):
|
|
362
364
|
job_ids = [job_ids]
|
|
363
365
|
|
|
366
|
+
# Decide once at the start
|
|
367
|
+
if poll_callback:
|
|
368
|
+
update_fn = poll_callback
|
|
369
|
+
elif verbose:
|
|
370
|
+
CYAN = "\033[36m"
|
|
371
|
+
RESET = "\033[0m"
|
|
372
|
+
|
|
373
|
+
update_fn = lambda retry_count, status: logger.info(
|
|
374
|
+
rf"Job {CYAN}{job_ids[0].split('-')[0]}{RESET} is {status}. Polling attempt {retry_count} / {self.max_retries}\r",
|
|
375
|
+
extra={"append": True},
|
|
376
|
+
)
|
|
377
|
+
else:
|
|
378
|
+
update_fn = lambda _, __: None
|
|
379
|
+
|
|
364
380
|
if not loop_until_complete:
|
|
365
381
|
statuses = [
|
|
366
382
|
self._make_request(
|
|
@@ -386,7 +402,10 @@ class QoroService(CircuitRunner):
|
|
|
386
402
|
timeout=200,
|
|
387
403
|
)
|
|
388
404
|
|
|
389
|
-
if response.json()["status"]
|
|
405
|
+
if response.json()["status"] in (
|
|
406
|
+
JobStatus.COMPLETED.value,
|
|
407
|
+
JobStatus.FAILED.value,
|
|
408
|
+
):
|
|
390
409
|
pending_job_ids.remove(job_id)
|
|
391
410
|
responses.append(response)
|
|
392
411
|
|
|
@@ -396,13 +415,7 @@ class QoroService(CircuitRunner):
|
|
|
396
415
|
|
|
397
416
|
time.sleep(self.polling_interval)
|
|
398
417
|
|
|
399
|
-
|
|
400
|
-
if pbar_update_fn:
|
|
401
|
-
pbar_update_fn(retry_count)
|
|
402
|
-
else:
|
|
403
|
-
logger.info(
|
|
404
|
-
rf"\cPolling {retry_count} / {self.max_retries} retries\r"
|
|
405
|
-
)
|
|
418
|
+
update_fn(retry_count, response.json()["status"])
|
|
406
419
|
|
|
407
420
|
if not pending_job_ids:
|
|
408
421
|
if on_complete:
|
|
@@ -10,4 +10,4 @@ from ._vqe import VQE, VQEAnsatz
|
|
|
10
10
|
from ._graph_partitioning import GraphPartitioningQAOA, PartitioningConfig
|
|
11
11
|
from ._qubo_partitioning import QUBOPartitioningQAOA
|
|
12
12
|
from ._vqe_sweep import VQEHyperparameterSweep, MoleculeTransformer
|
|
13
|
-
from .optimizers import
|
|
13
|
+
from .optimizers import ScipyOptimizer, ScipyMethod, MonteCarloOptimizer
|
|
@@ -21,16 +21,14 @@ from pymetis import part_graph
|
|
|
21
21
|
from sklearn.cluster import SpectralClustering
|
|
22
22
|
|
|
23
23
|
from divi.interfaces import CircuitRunner
|
|
24
|
-
from divi.qprog import QAOA, ProgramBatch
|
|
24
|
+
from divi.qprog import QAOA, ProgramBatch, QuantumProgram
|
|
25
25
|
from divi.qprog._qaoa import (
|
|
26
26
|
_SUPPORTED_INITIAL_STATES_LITERAL,
|
|
27
27
|
GraphProblem,
|
|
28
28
|
GraphProblemTypes,
|
|
29
29
|
draw_graph_solution_nodes,
|
|
30
30
|
)
|
|
31
|
-
from divi.qprog.
|
|
32
|
-
|
|
33
|
-
from .optimizers import Optimizer
|
|
31
|
+
from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
|
|
34
32
|
|
|
35
33
|
AggregateFn = Callable[
|
|
36
34
|
[list[int], str, nx.Graph | rx.PyGraph, dict[int, int]], list[int]
|
|
@@ -390,7 +388,6 @@ def dominance_aggregation(
|
|
|
390
388
|
|
|
391
389
|
|
|
392
390
|
def _run_and_compute_solution(program: QuantumProgram):
|
|
393
|
-
|
|
394
391
|
program.run()
|
|
395
392
|
|
|
396
393
|
final_sol_circuit_count, final_sol_run_time = program.compute_final_solution()
|
|
@@ -408,7 +405,7 @@ class GraphPartitioningQAOA(ProgramBatch):
|
|
|
408
405
|
partitioning_config: PartitioningConfig,
|
|
409
406
|
initial_state: _SUPPORTED_INITIAL_STATES_LITERAL = "Recommended",
|
|
410
407
|
aggregate_fn: AggregateFn = linear_aggregation,
|
|
411
|
-
optimizer=
|
|
408
|
+
optimizer: Optimizer | None = None,
|
|
412
409
|
max_iterations=10,
|
|
413
410
|
**kwargs,
|
|
414
411
|
):
|
|
@@ -452,7 +449,7 @@ class GraphPartitioningQAOA(ProgramBatch):
|
|
|
452
449
|
QAOA,
|
|
453
450
|
initial_state=initial_state,
|
|
454
451
|
graph_problem=graph_problem,
|
|
455
|
-
optimizer=optimizer,
|
|
452
|
+
optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
|
|
456
453
|
max_iterations=self.max_iterations,
|
|
457
454
|
backend=self.backend,
|
|
458
455
|
n_layers=n_layers,
|
|
@@ -23,7 +23,7 @@ from qiskit_optimization.problems import VarType
|
|
|
23
23
|
|
|
24
24
|
from divi.circuits import MetaCircuit
|
|
25
25
|
from divi.qprog import QuantumProgram
|
|
26
|
-
from divi.qprog.optimizers import Optimizer
|
|
26
|
+
from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
|
|
27
27
|
from divi.utils import convert_qubo_matrix_to_pennylane_ising
|
|
28
28
|
|
|
29
29
|
logger = logging.getLogger(__name__)
|
|
@@ -153,10 +153,11 @@ class QAOA(QuantumProgram):
|
|
|
153
153
|
def __init__(
|
|
154
154
|
self,
|
|
155
155
|
problem: GraphProblemTypes | QUBOProblemTypes,
|
|
156
|
+
*,
|
|
156
157
|
graph_problem: GraphProblem | None = None,
|
|
157
158
|
n_layers: int = 1,
|
|
158
159
|
initial_state: _SUPPORTED_INITIAL_STATES_LITERAL = "Recommended",
|
|
159
|
-
optimizer: Optimizer =
|
|
160
|
+
optimizer: Optimizer | None = None,
|
|
160
161
|
max_iterations: int = 10,
|
|
161
162
|
**kwargs,
|
|
162
163
|
):
|
|
@@ -221,11 +222,11 @@ class QAOA(QuantumProgram):
|
|
|
221
222
|
|
|
222
223
|
# Local Variables
|
|
223
224
|
self.n_layers = n_layers
|
|
224
|
-
self.optimizer = optimizer
|
|
225
225
|
self.max_iterations = max_iterations
|
|
226
226
|
self.current_iteration = 0
|
|
227
227
|
self.n_params = 2
|
|
228
228
|
self._is_compute_probabilites = False
|
|
229
|
+
self.optimizer = optimizer if optimizer is not None else MonteCarloOptimizer()
|
|
229
230
|
|
|
230
231
|
# Shared Variables
|
|
231
232
|
self.probs = kwargs.pop("probs", {})
|
|
@@ -245,10 +246,17 @@ class QAOA(QuantumProgram):
|
|
|
245
246
|
)
|
|
246
247
|
self.problem_metadata = problem_metadata[0] if problem_metadata else {}
|
|
247
248
|
|
|
248
|
-
|
|
249
|
+
if "constant" in self.problem_metadata:
|
|
250
|
+
self.loss_constant = self.problem_metadata.get("constant")
|
|
251
|
+
try:
|
|
252
|
+
self.loss_constant = self.loss_constant.item()
|
|
253
|
+
except AttributeError:
|
|
254
|
+
pass
|
|
255
|
+
else:
|
|
256
|
+
self.loss_constant = 0.0
|
|
249
257
|
|
|
250
258
|
kwargs.pop("is_constrained", None)
|
|
251
|
-
super().__init__(**kwargs)
|
|
259
|
+
super().__init__(has_final_computation=True, **kwargs)
|
|
252
260
|
|
|
253
261
|
self._meta_circuits = self._create_meta_circuits_dict()
|
|
254
262
|
|
|
@@ -387,16 +395,7 @@ class QAOA(QuantumProgram):
|
|
|
387
395
|
- float: The total runtime of the optimization process.
|
|
388
396
|
"""
|
|
389
397
|
|
|
390
|
-
|
|
391
|
-
self._progress_queue.put(
|
|
392
|
-
{
|
|
393
|
-
"job_id": self.job_id,
|
|
394
|
-
"message": "🏁 Computing Final Solution 🏁",
|
|
395
|
-
"progress": 0,
|
|
396
|
-
}
|
|
397
|
-
)
|
|
398
|
-
else:
|
|
399
|
-
logger.info("🏁 Computing Final Solution 🏁")
|
|
398
|
+
self.reporter.info(message="🏁 Computing Final Solution 🏁")
|
|
400
399
|
|
|
401
400
|
# Convert losses dict to list to apply ordinal operations
|
|
402
401
|
final_losses_list = list(self.losses[-1].values())
|
|
@@ -440,16 +439,7 @@ class QAOA(QuantumProgram):
|
|
|
440
439
|
m.start() for m in re.finditer("1", best_solution_bitstring)
|
|
441
440
|
]
|
|
442
441
|
|
|
443
|
-
|
|
444
|
-
self._progress_queue.put(
|
|
445
|
-
{
|
|
446
|
-
"job_id": self.job_id,
|
|
447
|
-
"progress": 0,
|
|
448
|
-
"final_status": "Success",
|
|
449
|
-
}
|
|
450
|
-
)
|
|
451
|
-
else:
|
|
452
|
-
logger.info(f"Computed Solution!")
|
|
442
|
+
self.reporter.info(message="Computed Final Solution!")
|
|
453
443
|
|
|
454
444
|
return self._total_circuit_count, self._total_run_time
|
|
455
445
|
|
|
@@ -15,7 +15,7 @@ from dimod import BinaryQuadraticModel
|
|
|
15
15
|
from divi.interfaces import CircuitRunner
|
|
16
16
|
from divi.qprog._qaoa import QAOA, QUBOProblemTypes
|
|
17
17
|
from divi.qprog.batch import ProgramBatch
|
|
18
|
-
from divi.qprog.optimizers import Optimizer
|
|
18
|
+
from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
|
|
19
19
|
from divi.qprog.quantum_program import QuantumProgram
|
|
20
20
|
|
|
21
21
|
|
|
@@ -50,7 +50,6 @@ def _sanitize_problem_input(qubo: T) -> tuple[T, BinaryQuadraticModel]:
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def _run_and_compute_solution(program: QuantumProgram):
|
|
53
|
-
|
|
54
53
|
program.run()
|
|
55
54
|
|
|
56
55
|
final_sol_circuit_count, final_sol_run_time = program.compute_final_solution()
|
|
@@ -66,8 +65,8 @@ class QUBOPartitioningQAOA(ProgramBatch):
|
|
|
66
65
|
n_layers: int,
|
|
67
66
|
backend: CircuitRunner,
|
|
68
67
|
composer: hybrid.traits.SubsamplesComposer = hybrid.SplatComposer(),
|
|
69
|
-
optimizer=
|
|
70
|
-
max_iterations=10,
|
|
68
|
+
optimizer: Optimizer | None = None,
|
|
69
|
+
max_iterations: int = 10,
|
|
71
70
|
**kwargs,
|
|
72
71
|
):
|
|
73
72
|
"""
|
|
@@ -101,7 +100,7 @@ class QUBOPartitioningQAOA(ProgramBatch):
|
|
|
101
100
|
|
|
102
101
|
self._constructor = partial(
|
|
103
102
|
QAOA,
|
|
104
|
-
optimizer=optimizer,
|
|
103
|
+
optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
|
|
105
104
|
max_iterations=self.max_iterations,
|
|
106
105
|
backend=self.backend,
|
|
107
106
|
n_layers=n_layers,
|
|
@@ -10,7 +10,7 @@ import sympy as sp
|
|
|
10
10
|
|
|
11
11
|
from divi.circuits import MetaCircuit
|
|
12
12
|
from divi.qprog import QuantumProgram
|
|
13
|
-
from divi.qprog.optimizers import Optimizer
|
|
13
|
+
from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class VQEAnsatz(Enum):
|
|
@@ -50,7 +50,7 @@ class VQE(QuantumProgram):
|
|
|
50
50
|
n_electrons: int | None = None,
|
|
51
51
|
n_layers: int = 1,
|
|
52
52
|
ansatz=VQEAnsatz.HARTREE_FOCK,
|
|
53
|
-
optimizer=
|
|
53
|
+
optimizer: Optimizer | None = None,
|
|
54
54
|
max_iterations=10,
|
|
55
55
|
**kwargs,
|
|
56
56
|
) -> None:
|
|
@@ -71,10 +71,11 @@ class VQE(QuantumProgram):
|
|
|
71
71
|
self.n_layers = n_layers
|
|
72
72
|
self.results = {}
|
|
73
73
|
self.ansatz = ansatz
|
|
74
|
-
self.optimizer = optimizer
|
|
75
74
|
self.max_iterations = max_iterations
|
|
76
75
|
self.current_iteration = 0
|
|
77
76
|
|
|
77
|
+
self.optimizer = optimizer if optimizer is not None else MonteCarloOptimizer()
|
|
78
|
+
|
|
78
79
|
self._process_problem_input(
|
|
79
80
|
hamiltonian=hamiltonian, molecule=molecule, n_electrons=n_electrons
|
|
80
81
|
)
|
|
@@ -137,8 +138,8 @@ class VQE(QuantumProgram):
|
|
|
137
138
|
)
|
|
138
139
|
)
|
|
139
140
|
|
|
140
|
-
self.loss_constant =
|
|
141
|
-
map(lambda x: hamiltonian[x].scalar, constant_terms_idx)
|
|
141
|
+
self.loss_constant = float(
|
|
142
|
+
sum(map(lambda x: hamiltonian[x].scalar, constant_terms_idx))
|
|
142
143
|
)
|
|
143
144
|
|
|
144
145
|
for idx in constant_terms_idx:
|
|
@@ -15,8 +15,7 @@ import numpy as np
|
|
|
15
15
|
import pennylane as qml
|
|
16
16
|
|
|
17
17
|
from divi.qprog import VQE, ProgramBatch, VQEAnsatz
|
|
18
|
-
|
|
19
|
-
from .optimizers import Optimizer
|
|
18
|
+
from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
def _ctor_attrs(obj):
|
|
@@ -395,7 +394,7 @@ class VQEHyperparameterSweep(ProgramBatch):
|
|
|
395
394
|
self,
|
|
396
395
|
ansatze: Sequence[VQEAnsatz],
|
|
397
396
|
molecule_transformer: MoleculeTransformer,
|
|
398
|
-
optimizer: Optimizer =
|
|
397
|
+
optimizer: Optimizer | None = None,
|
|
399
398
|
max_iterations: int = 10,
|
|
400
399
|
**kwargs,
|
|
401
400
|
):
|
|
@@ -424,7 +423,7 @@ class VQEHyperparameterSweep(ProgramBatch):
|
|
|
424
423
|
|
|
425
424
|
self._constructor = partial(
|
|
426
425
|
VQE,
|
|
427
|
-
optimizer=optimizer,
|
|
426
|
+
optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
|
|
428
427
|
max_iterations=self.max_iterations,
|
|
429
428
|
backend=self.backend,
|
|
430
429
|
**kwargs,
|
|
@@ -10,6 +10,7 @@ from multiprocessing import Event, Manager
|
|
|
10
10
|
from multiprocessing.synchronize import Event as EventClass
|
|
11
11
|
from queue import Empty, Queue
|
|
12
12
|
from threading import Lock, Thread
|
|
13
|
+
from typing import Any
|
|
13
14
|
from warnings import warn
|
|
14
15
|
|
|
15
16
|
from rich.console import Console
|
|
@@ -32,7 +33,7 @@ def queue_listener(
|
|
|
32
33
|
):
|
|
33
34
|
while not done_event.is_set():
|
|
34
35
|
try:
|
|
35
|
-
msg = queue.get(timeout=0.1)
|
|
36
|
+
msg: dict[str, Any] = queue.get(timeout=0.1)
|
|
36
37
|
except Empty:
|
|
37
38
|
continue
|
|
38
39
|
except Exception as e:
|
|
@@ -42,14 +43,25 @@ def queue_listener(
|
|
|
42
43
|
with lock:
|
|
43
44
|
task_id = pb_task_map[msg["job_id"]]
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
# Prepare update arguments, starting with progress.
|
|
47
|
+
update_args = {"advance": msg["progress"]}
|
|
48
|
+
|
|
49
|
+
if "poll_attempt" in msg:
|
|
50
|
+
update_args["poll_attempt"] = msg.get("poll_attempt", 0)
|
|
51
|
+
if "max_retries" in msg:
|
|
52
|
+
update_args["max_retries"] = msg.get("max_retries")
|
|
53
|
+
if "service_job_id" in msg:
|
|
54
|
+
update_args["service_job_id"] = msg.get("service_job_id")
|
|
55
|
+
if "job_status" in msg:
|
|
56
|
+
update_args["job_status"] = msg.get("job_status")
|
|
57
|
+
if msg.get("message"):
|
|
58
|
+
update_args["message"] = msg.get("message")
|
|
59
|
+
if "final_status" in msg:
|
|
60
|
+
update_args["final_status"] = msg.get("final_status", "")
|
|
61
|
+
|
|
62
|
+
update_args["refresh"] = is_jupyter
|
|
63
|
+
|
|
64
|
+
progress_bar.update(task_id, **update_args)
|
|
53
65
|
|
|
54
66
|
|
|
55
67
|
def _default_task_function(program: QuantumProgram):
|
|
@@ -182,10 +194,7 @@ class ProgramBatch(ABC):
|
|
|
182
194
|
raise RuntimeError("No programs to run.")
|
|
183
195
|
|
|
184
196
|
self._progress_bar = (
|
|
185
|
-
make_progress_bar(
|
|
186
|
-
max_retries=None if self._is_local else self.backend.max_retries,
|
|
187
|
-
is_jupyter=self._is_jupyter,
|
|
188
|
-
)
|
|
197
|
+
make_progress_bar(is_jupyter=self._is_jupyter)
|
|
189
198
|
if hasattr(self, "max_iterations")
|
|
190
199
|
else None
|
|
191
200
|
)
|
|
@@ -217,8 +226,7 @@ class ProgramBatch(ABC):
|
|
|
217
226
|
if not blocking:
|
|
218
227
|
# Arm safety net
|
|
219
228
|
atexit.register(self._atexit_cleanup_hook)
|
|
220
|
-
|
|
221
|
-
if blocking:
|
|
229
|
+
else:
|
|
222
230
|
self.join()
|
|
223
231
|
|
|
224
232
|
return self
|