qoro-divi 0.2.0b1__py3-none-any.whl → 0.6.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 +10 -0
- divi/backends/_backend_properties_conversion.py +227 -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 +13 -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 +391 -0
- divi/{qasm.py → circuits/_qasm_conversion.py} +73 -14
- divi/circuits/_qasm_validation.py +694 -0
- divi/qprog/__init__.py +27 -8
- divi/qprog/_expectation.py +181 -0
- divi/qprog/_hamiltonians.py +281 -0
- divi/qprog/algorithms/__init__.py +16 -0
- divi/qprog/algorithms/_ansatze.py +368 -0
- divi/qprog/algorithms/_custom_vqa.py +263 -0
- divi/qprog/algorithms/_pce.py +262 -0
- divi/qprog/algorithms/_qaoa.py +579 -0
- divi/qprog/algorithms/_vqe.py +262 -0
- divi/qprog/batch.py +387 -74
- divi/qprog/checkpointing.py +556 -0
- divi/qprog/exceptions.py +9 -0
- divi/qprog/optimizers.py +1014 -43
- divi/qprog/quantum_program.py +243 -412
- divi/qprog/typing.py +62 -0
- divi/qprog/variational_quantum_algorithm.py +1208 -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 +221 -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 +155 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info}/METADATA +43 -15
- qoro_divi-0.6.0.dist-info/RECORD +47 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info}/WHEEL +1 -1
- qoro_divi-0.6.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.6.0.dist-info/licenses}/LICENSE +0 -0
- {qoro_divi-0.2.0b1.dist-info → qoro_divi-0.6.0.dist-info/licenses}/LICENSES/Apache-2.0.txt +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from rich.logging import RichHandler
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CustomRichFormatter(logging.Formatter):
|
|
11
|
+
"""
|
|
12
|
+
A custom log formatter that removes '._reporter' from the logger name.
|
|
13
|
+
Works with RichHandler.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def format(self, record):
|
|
17
|
+
# Modify the record's name attribute in place
|
|
18
|
+
if record.name.endswith("._reporter"):
|
|
19
|
+
record.name = record.name.removesuffix("._reporter")
|
|
20
|
+
return super().format(record)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def enable_logging(level=logging.INFO):
|
|
24
|
+
"""
|
|
25
|
+
Enable logging for the divi package with Rich formatting.
|
|
26
|
+
|
|
27
|
+
Sets up a RichHandler that provides colorized, formatted log output
|
|
28
|
+
and removes the '._reporter' suffix from logger names.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
level (int, optional): Logging level to set (e.g., logging.INFO,
|
|
32
|
+
logging.DEBUG). Defaults to logging.INFO.
|
|
33
|
+
|
|
34
|
+
Note:
|
|
35
|
+
This function clears any existing handlers and sets up a new handler
|
|
36
|
+
with custom formatting.
|
|
37
|
+
"""
|
|
38
|
+
root_logger = logging.getLogger(__name__.split(".")[0])
|
|
39
|
+
|
|
40
|
+
handler = RichHandler(
|
|
41
|
+
rich_tracebacks=True,
|
|
42
|
+
show_time=True,
|
|
43
|
+
show_path=False,
|
|
44
|
+
markup=True,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Use a simpler formatter since RichHandler handles time display
|
|
48
|
+
formatter = CustomRichFormatter(
|
|
49
|
+
"%(name)s - %(levelname)s - %(message)s",
|
|
50
|
+
)
|
|
51
|
+
handler.setFormatter(formatter)
|
|
52
|
+
|
|
53
|
+
root_logger.setLevel(level)
|
|
54
|
+
root_logger.handlers.clear()
|
|
55
|
+
root_logger.addHandler(handler)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def disable_logging():
|
|
59
|
+
"""
|
|
60
|
+
Disable all logging for the divi package.
|
|
61
|
+
|
|
62
|
+
Removes all handlers and sets the logging level to above CRITICAL,
|
|
63
|
+
effectively suppressing all log messages. This is useful when using
|
|
64
|
+
progress bars that provide visual feedback.
|
|
65
|
+
"""
|
|
66
|
+
root_logger = logging.getLogger(__name__.split(".")[0])
|
|
67
|
+
root_logger.handlers.clear()
|
|
68
|
+
root_logger.setLevel(logging.CRITICAL + 1)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import atexit
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from queue import Queue
|
|
10
|
+
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProgressReporter(ABC):
|
|
17
|
+
"""An abstract base class for reporting progress of a quantum program."""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def update(self, **kwargs) -> None:
|
|
21
|
+
"""Provides a progress update."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def info(self, message: str, **kwargs) -> None:
|
|
26
|
+
"""Provides a simple informational message.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
message: The message to display.
|
|
30
|
+
**kwargs: Additional keyword arguments for subclasses.
|
|
31
|
+
"""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class QueueProgressReporter(ProgressReporter):
|
|
36
|
+
"""Reports progress by putting structured dictionaries onto a Queue."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, job_id: str, progress_queue: Queue):
|
|
39
|
+
self._job_id = job_id
|
|
40
|
+
self._queue = progress_queue
|
|
41
|
+
|
|
42
|
+
def update(self, **kwargs):
|
|
43
|
+
payload = {"job_id": self._job_id, "progress": 1}
|
|
44
|
+
self._queue.put(payload)
|
|
45
|
+
|
|
46
|
+
def info(self, message: str, **kwargs):
|
|
47
|
+
payload = {"job_id": self._job_id, "progress": 0, "message": message}
|
|
48
|
+
|
|
49
|
+
if "Finished successfully!" in message:
|
|
50
|
+
payload["final_status"] = "Success"
|
|
51
|
+
|
|
52
|
+
if "poll_attempt" in kwargs:
|
|
53
|
+
# For polling, remove the message key so the last message persists.
|
|
54
|
+
del payload["message"]
|
|
55
|
+
payload["poll_attempt"] = kwargs["poll_attempt"]
|
|
56
|
+
payload["max_retries"] = kwargs["max_retries"]
|
|
57
|
+
payload["service_job_id"] = kwargs["service_job_id"]
|
|
58
|
+
payload["job_status"] = kwargs["job_status"]
|
|
59
|
+
else:
|
|
60
|
+
# For any other message, explicitly reset the polling attempt counter.
|
|
61
|
+
payload["poll_attempt"] = 0
|
|
62
|
+
|
|
63
|
+
self._queue.put(payload)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class LoggingProgressReporter(ProgressReporter):
|
|
67
|
+
"""Reports progress by logging messages to the console."""
|
|
68
|
+
|
|
69
|
+
_atexit_registered = False
|
|
70
|
+
|
|
71
|
+
def __init__(self):
|
|
72
|
+
# Use the same console instance that RichHandler uses to avoid interference
|
|
73
|
+
self._console = Console(file=None) # file=None uses stdout, same as RichHandler
|
|
74
|
+
self._status = None # Track active status for overwriting messages
|
|
75
|
+
self._current_msg = None # Track current main message
|
|
76
|
+
self._polling_msg = None # Track current polling message
|
|
77
|
+
self._disable_progress = self._should_disable_progress()
|
|
78
|
+
|
|
79
|
+
def _ensure_atexit_hook(self):
|
|
80
|
+
if self._disable_progress or LoggingProgressReporter._atexit_registered:
|
|
81
|
+
return
|
|
82
|
+
atexit.register(self._close_status)
|
|
83
|
+
LoggingProgressReporter._atexit_registered = True
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _should_disable_progress() -> bool:
|
|
87
|
+
disable_env = os.getenv("DIVI_DISABLE_PROGRESS", "").strip().lower()
|
|
88
|
+
return disable_env in {"1", "true", "yes", "on"}
|
|
89
|
+
|
|
90
|
+
def _close_status(self):
|
|
91
|
+
"""Close any active status."""
|
|
92
|
+
if self._status:
|
|
93
|
+
self._status.__exit__(None, None, None)
|
|
94
|
+
self._status = None
|
|
95
|
+
self._current_msg = None
|
|
96
|
+
self._polling_msg = None
|
|
97
|
+
|
|
98
|
+
def _build_status_msg(self) -> str:
|
|
99
|
+
"""Build combined status message from current message and polling info."""
|
|
100
|
+
parts = []
|
|
101
|
+
if self._current_msg:
|
|
102
|
+
parts.append(self._current_msg)
|
|
103
|
+
if self._polling_msg:
|
|
104
|
+
parts.append(self._polling_msg)
|
|
105
|
+
return " - ".join(parts) if parts else ""
|
|
106
|
+
|
|
107
|
+
def _update_or_create_status(self):
|
|
108
|
+
"""Update existing status or create a new one with combined message."""
|
|
109
|
+
if self._disable_progress:
|
|
110
|
+
return
|
|
111
|
+
status_msg = self._build_status_msg()
|
|
112
|
+
if not status_msg:
|
|
113
|
+
return
|
|
114
|
+
self._ensure_atexit_hook()
|
|
115
|
+
if self._status:
|
|
116
|
+
self._status.update(status_msg)
|
|
117
|
+
else:
|
|
118
|
+
self._status = self._console.status(status_msg, spinner="aesthetic")
|
|
119
|
+
self._status.__enter__()
|
|
120
|
+
|
|
121
|
+
def update(self, **kwargs):
|
|
122
|
+
# Close any active status before logging
|
|
123
|
+
self._close_status()
|
|
124
|
+
logger.info(f"Finished Iteration #{kwargs['iteration']}")
|
|
125
|
+
|
|
126
|
+
def info(self, message: str, overwrite: bool = False, **kwargs):
|
|
127
|
+
if self._disable_progress:
|
|
128
|
+
logger.info(message)
|
|
129
|
+
return
|
|
130
|
+
# A special check for iteration updates to use Rich's status for overwriting
|
|
131
|
+
if "poll_attempt" in kwargs:
|
|
132
|
+
self._polling_msg = (
|
|
133
|
+
f"Job [cyan]{kwargs['service_job_id'].split('-')[0]}[/cyan] is "
|
|
134
|
+
f"{kwargs['job_status']}. Polling attempt {kwargs['poll_attempt']} / "
|
|
135
|
+
f"{kwargs['max_retries']}"
|
|
136
|
+
)
|
|
137
|
+
self._update_or_create_status()
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
# Use Rich's status for iteration messages to enable overwriting
|
|
141
|
+
if "iteration" in kwargs:
|
|
142
|
+
self._current_msg = f"Iteration #{kwargs['iteration'] + 1}: {message}"
|
|
143
|
+
self._update_or_create_status()
|
|
144
|
+
return
|
|
145
|
+
|
|
146
|
+
# Use Rich's status for messages that should overwrite
|
|
147
|
+
if overwrite:
|
|
148
|
+
# Set current message, keep polling state so it can be concatenated
|
|
149
|
+
self._current_msg = message
|
|
150
|
+
self._update_or_create_status()
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
# Close status for normal messages
|
|
154
|
+
self._close_status()
|
|
155
|
+
logger.info(message)
|
|
@@ -1,32 +1,38 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: qoro-divi
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: A Python library to automate generating, parallelizing, and executing quantum programs.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
License-File: LICENSES/.license-header
|
|
7
|
+
License-File: LICENSES/Apache-2.0.txt
|
|
5
8
|
Author: Ahmed Darwish
|
|
6
9
|
Author-email: ahmed@qoroquantum.de
|
|
7
10
|
Requires-Python: >=3.11,<3.13
|
|
8
11
|
Classifier: Programming Language :: Python :: 3
|
|
9
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: basis-set-exchange (>=0.11,<0.12)
|
|
15
|
+
Requires-Dist: cirq-core (>=1.6,<2.0)
|
|
12
16
|
Requires-Dist: dill (>=0.4.0,<0.5.0)
|
|
17
|
+
Requires-Dist: dwave-hybrid (>=0.6.14,<0.7.0)
|
|
13
18
|
Requires-Dist: matplotlib (>=3.10.3,<4.0.0)
|
|
14
|
-
Requires-Dist: mitiq (>=0.
|
|
19
|
+
Requires-Dist: mitiq (>=0.48,<0.49)
|
|
15
20
|
Requires-Dist: networkx (>=3.5,<4.0)
|
|
16
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: pennylane (>=0.43,<0.44)
|
|
23
|
+
Requires-Dist: pennylane-qiskit (>=0.43,<0.44)
|
|
17
24
|
Requires-Dist: ply (>=3.11,<4.0)
|
|
25
|
+
Requires-Dist: pydantic (>=2.5.0,<2.10)
|
|
18
26
|
Requires-Dist: pymetis (>=2025.1.1,<2026.0.0)
|
|
19
|
-
Requires-Dist:
|
|
27
|
+
Requires-Dist: pymoo (>=0.6,<0.7)
|
|
20
28
|
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
21
|
-
Requires-Dist: qiskit (
|
|
22
|
-
Requires-Dist: qiskit-aer
|
|
23
|
-
Requires-Dist: qiskit-
|
|
24
|
-
Requires-Dist: qiskit-ibm-runtime (>=0.37,<0.38)
|
|
25
|
-
Requires-Dist: qiskit-optimization (>=0.6.1,<0.7.0)
|
|
29
|
+
Requires-Dist: qiskit (>=2.1,<2.3)
|
|
30
|
+
Requires-Dist: qiskit-aer
|
|
31
|
+
Requires-Dist: qiskit-ibm-runtime (>=0.41,<0.42)
|
|
26
32
|
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
27
33
|
Requires-Dist: rich (>=14.0.0,<15.0.0)
|
|
28
34
|
Requires-Dist: scikit-learn (>=1.7.0,<2.0.0)
|
|
29
|
-
Requires-Dist: scipy (
|
|
35
|
+
Requires-Dist: scipy (>=1.16,<2.0)
|
|
30
36
|
Requires-Dist: sympy (>=1.14.0,<2.0.0)
|
|
31
37
|
Description-Content-Type: text/markdown
|
|
32
38
|
|
|
@@ -38,6 +44,9 @@ Divi is designed to allow researchers, students, and enterprises to deploy quant
|
|
|
38
44
|
|
|
39
45
|
---
|
|
40
46
|
|
|
47
|
+
> [!IMPORTANT]
|
|
48
|
+
> Divi is under active development and in early stages. Users should expect frequent changes that are likely to be incompatible with previously published versions.
|
|
49
|
+
|
|
41
50
|
## 🚀 Features
|
|
42
51
|
|
|
43
52
|
- 🧠 **Smart Job Parallelization**: Automatically parallelizes your quantum programs based on task structure.
|
|
@@ -49,9 +58,28 @@ Divi is designed to allow researchers, students, and enterprises to deploy quant
|
|
|
49
58
|
|
|
50
59
|
## 📦 Installation
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
Divi can be easily installed from Pypi
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install qoro-divi
|
|
65
|
+
```
|
|
53
66
|
|
|
54
67
|
## 📚 Documentation
|
|
55
68
|
|
|
56
|
-
Full documentation is available at: <https://docs.qoroquantum.net/divi>
|
|
69
|
+
- Full documentation is available at: <https://docs.qoroquantum.net/divi>
|
|
70
|
+
- Tutorials can be found in the `tutorials` folder.
|
|
71
|
+
|
|
72
|
+
## 🧪 Testing
|
|
73
|
+
|
|
74
|
+
To run the test suite:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Run all tests
|
|
78
|
+
pytest
|
|
79
|
+
|
|
80
|
+
# Run only API tests (requires API token)
|
|
81
|
+
pytest --run-api-tests
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Note:** Some tests require a Qoro API token to test the cloud REST API. Set the `QORO_API_KEY` environment variable or use the `--api-token` option. For local development, you can create a `.env`.
|
|
57
85
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
divi/__init__.py,sha256=SyBWflbDS6qGEtHg-AfzD1TRNgfXoW2H5qTYGJ-W3XQ,167
|
|
2
|
+
divi/backends/__init__.py,sha256=AdWc8kKYZIfO6cL7BI1uut8DHTTxfXSDDFluxM4rsuI,484
|
|
3
|
+
divi/backends/_backend_properties_conversion.py,sha256=UQoKy6FNpwZexlCcCnJYymZA6UfyKSaO8SV-kYV59v8,8204
|
|
4
|
+
divi/backends/_circuit_runner.py,sha256=BOLLyZTVvj-YzqPDQh9tbOdD4crBqGdxAZdtgLmMGLU,2130
|
|
5
|
+
divi/backends/_execution_result.py,sha256=1p7l-e7Opxq7SU433fYmIMedoyO-mvH_jC927GUI7zE,2614
|
|
6
|
+
divi/backends/_parallel_simulator.py,sha256=vjaopHKzFoCV5gCI2z4g33REIbxx9dFkNaEmuPUuvK8,18318
|
|
7
|
+
divi/backends/_qoro_service.py,sha256=n_gbllNlwwgHGhlBIrjS_00qKJfKooB4HoiIzp68FJk,24418
|
|
8
|
+
divi/backends/_qpu_system.py,sha256=mo0SIlih5TEgJ9XdW_JFVbRP8pcNQ9jqzwK-08WzkiI,3065
|
|
9
|
+
divi/backends/_results_processing.py,sha256=2yakh9-kDEiW7cJvfClzE5fbgRumJZ-jGSTKdUdgHCY,3873
|
|
10
|
+
divi/circuits/__init__.py,sha256=ZPabkWuAnXor82rkymjgYhYC386rvu7GqvvtWSjUSmI,371
|
|
11
|
+
divi/circuits/_cirq/__init__.py,sha256=EtdMjq4MGwpR7GnJb5WrqhlmXEoV284QA4nM6K5bmtU,220
|
|
12
|
+
divi/circuits/_cirq/_parser.py,sha256=4VVUG-BQuGEyfiX3sJGUTDFZcO_awcm_FjlwWjq3D-A,3746
|
|
13
|
+
divi/circuits/_cirq/_qasm_export.py,sha256=32h5a-m_7tVfje6MmEgwRNPd9U0ximqddbCsOIqVg6U,2944
|
|
14
|
+
divi/circuits/_core.py,sha256=fVZkEPFWXVOGmvkgHU6ll2Asz8L2TZpm1Bbw89fmC-A,15898
|
|
15
|
+
divi/circuits/_qasm_conversion.py,sha256=-ZXVWmcetgP7N-YeSpxX6E2MhazuhdTqlyZEhPjC-tQ,9665
|
|
16
|
+
divi/circuits/_qasm_validation.py,sha256=A4LqllrYzzMgWVuAVdVUBlU6A99pw5qqLyWiRXkDScE,22704
|
|
17
|
+
divi/circuits/qem.py,sha256=o6rMPUcxLuCBitBb8-QcxveUiKZVsP3HMamxyVFLi6M,6805
|
|
18
|
+
divi/qprog/__init__.py,sha256=DxtUdJDHmbZuvGjEyTVKZKW5OpI-srSeCXaJMcJqHWk,834
|
|
19
|
+
divi/qprog/_expectation.py,sha256=2Imgdng8gU1ImVXHprMUS1YbpAY0eI19Mp08Vw5lGvU,7395
|
|
20
|
+
divi/qprog/_hamiltonians.py,sha256=UHiCRo1k3h3cPQcIrRYhd82n-vS78I8U1LYT6AjJkdc,9419
|
|
21
|
+
divi/qprog/algorithms/__init__.py,sha256=V2gWqMIaSxG0c4X9QrDv2MwXiL1PCrPfVcoLk1hPbgg,380
|
|
22
|
+
divi/qprog/algorithms/_ansatze.py,sha256=gSAf4S5QgRw7-WKpE_Vf6okiZ02rIvKiKWa771I_v5w,13329
|
|
23
|
+
divi/qprog/algorithms/_custom_vqa.py,sha256=eVMsuqqN3PQEDoleSqIdI-KUU99yIq5D_7W582b_qFg,10092
|
|
24
|
+
divi/qprog/algorithms/_pce.py,sha256=XQmUnVc0Gv7bn3I5qTOvcdk1gEoUXOKzTO2kycCT0OA,9870
|
|
25
|
+
divi/qprog/algorithms/_qaoa.py,sha256=i-li-6VYWZC_F3BO7Bt6kNyw1ifWCwNd1z08t8Drqsc,22497
|
|
26
|
+
divi/qprog/algorithms/_vqe.py,sha256=Hq1kXgje5mifobHeEfMe7nJ9m-RiE9AufdyAy7Krzsc,10234
|
|
27
|
+
divi/qprog/batch.py,sha256=1aYH0jlw2mU5jeEiZUu5sET2fpic0gsrIHw3PJ_gfSk,20622
|
|
28
|
+
divi/qprog/checkpointing.py,sha256=g0I5fV4LMVjZZ-780WsojlwgQmJvY6nxZILAkUrOwk0,17369
|
|
29
|
+
divi/qprog/exceptions.py,sha256=2VvUf8qgNBw60Q4wyt_2nbE4JHHMmZiT2JaGmWChp2o,231
|
|
30
|
+
divi/qprog/optimizers.py,sha256=BdjJl1Fw56RMdXiVcNedNH1uOCxdmj-en4s_cbixl5U,39104
|
|
31
|
+
divi/qprog/quantum_program.py,sha256=qa_tU--YrT5cmd9q5FkyRDM5rBbkNAAwQHr52g7P8nU,12174
|
|
32
|
+
divi/qprog/typing.py,sha256=-1xQxzrJBq1-KL2YCEFcD5yN25Vc_25Sg1FrJ-Wi9E0,2072
|
|
33
|
+
divi/qprog/variational_quantum_algorithm.py,sha256=n8A1YPOcCP0gdim0vwpe5iX9DP1psrYwelMiRjrQcM0,46798
|
|
34
|
+
divi/qprog/workflows/__init__.py,sha256=_GAFsZsgj9p61E1xUXasa1aspwcOWp4s8i6hA6mQ9eg,320
|
|
35
|
+
divi/qprog/workflows/_graph_partitioning.py,sha256=nTxpPom7Aulfndlqws0FkaTvs1siRCeixiBkwRqV1Xc,24435
|
|
36
|
+
divi/qprog/workflows/_qubo_partitioning.py,sha256=JHF1m7MI3-BLeG4rYJ9bPelFd_KIAFY2Ihyy3IZV6K8,8431
|
|
37
|
+
divi/qprog/workflows/_vqe_sweep.py,sha256=rT79jYex04linD42mdXCM54LdZ83eFCwUGAKnX1PQSM,19658
|
|
38
|
+
divi/reporting/__init__.py,sha256=gaBUZrhNxR53VHojZxfjvQRDl-eDHo901vLE8I95kIw,290
|
|
39
|
+
divi/reporting/_pbar.py,sha256=of9vI37puHWVPCUwRbwtiT1cDQVCpUbpbxNx__hF7mE,4180
|
|
40
|
+
divi/reporting/_qlogger.py,sha256=d16eT_n8Me83Qn1QOFmzEoVnRYTePM5l_I1GeNVCo4o,1990
|
|
41
|
+
divi/reporting/_reporter.py,sha256=KlYgKuNl-3rkAqgi8PQRutvtHyoMDezR_Zfn4LhJTnU,5492
|
|
42
|
+
qoro_divi-0.6.0.dist-info/METADATA,sha256=CP5PvpfmWFC4_ie2i36oJDhKdIg3tQttw6rIZkTUxgQ,2992
|
|
43
|
+
qoro_divi-0.6.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
44
|
+
qoro_divi-0.6.0.dist-info/licenses/LICENSE,sha256=NS4JlQrgNwg1bvB3kE5shE-P4cJgnntgl-kClbOpG_Q,10760
|
|
45
|
+
qoro_divi-0.6.0.dist-info/licenses/LICENSES/.license-header,sha256=2jN_xtJscqP8LG-NaveY2KHUkfRCC543Y_XjOyKEfWY,105
|
|
46
|
+
qoro_divi-0.6.0.dist-info/licenses/LICENSES/Apache-2.0.txt,sha256=yoILHpvVuguUBpk8UwMnzJbcHUUyst9iGNNuEwUtWVc,10270
|
|
47
|
+
qoro_divi-0.6.0.dist-info/RECORD,,
|
divi/_pbar.py
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
from rich.progress import (
|
|
8
|
-
BarColumn,
|
|
9
|
-
MofNCompleteColumn,
|
|
10
|
-
Progress,
|
|
11
|
-
ProgressColumn,
|
|
12
|
-
SpinnerColumn,
|
|
13
|
-
TextColumn,
|
|
14
|
-
)
|
|
15
|
-
from rich.text import Text
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ConditionalSpinnerColumn(ProgressColumn):
|
|
19
|
-
def __init__(self):
|
|
20
|
-
super().__init__()
|
|
21
|
-
self.spinner = SpinnerColumn("point")
|
|
22
|
-
|
|
23
|
-
def render(self, task):
|
|
24
|
-
status = task.fields.get("final_status")
|
|
25
|
-
|
|
26
|
-
if status in ("Success", "Failed"):
|
|
27
|
-
return Text("")
|
|
28
|
-
|
|
29
|
-
return self.spinner.render(task)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class PhaseStatusColumn(ProgressColumn):
|
|
33
|
-
def __init__(self, max_retries: int, table_column=None):
|
|
34
|
-
super().__init__(table_column)
|
|
35
|
-
|
|
36
|
-
self._max_retries = max_retries
|
|
37
|
-
self._last_message = ""
|
|
38
|
-
|
|
39
|
-
def render(self, task):
|
|
40
|
-
final_status = task.fields.get("final_status")
|
|
41
|
-
|
|
42
|
-
if final_status == "Success":
|
|
43
|
-
return Text("• Success! ✅", style="bold green")
|
|
44
|
-
elif final_status == "Failed":
|
|
45
|
-
return Text("• Failed! ❌", style="bold red")
|
|
46
|
-
|
|
47
|
-
message = task.fields.get("message")
|
|
48
|
-
if message != "":
|
|
49
|
-
self._last_message = message
|
|
50
|
-
|
|
51
|
-
poll_attempt = task.fields.get("poll_attempt")
|
|
52
|
-
if poll_attempt > 0:
|
|
53
|
-
return Text(
|
|
54
|
-
f"[{self._last_message}] Polling {poll_attempt}/{self._max_retries}"
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
return Text(f"[{self._last_message}]")
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def make_progress_bar(
|
|
61
|
-
max_retries: Optional[int] = None, is_jupyter: bool = False
|
|
62
|
-
) -> Progress:
|
|
63
|
-
return Progress(
|
|
64
|
-
TextColumn("[bold blue]{task.fields[job_name]}"),
|
|
65
|
-
BarColumn(),
|
|
66
|
-
MofNCompleteColumn(),
|
|
67
|
-
ConditionalSpinnerColumn(),
|
|
68
|
-
PhaseStatusColumn(max_retries=max_retries),
|
|
69
|
-
# For jupyter notebooks, refresh manually instead
|
|
70
|
-
auto_refresh=not is_jupyter,
|
|
71
|
-
# Give a dummy positive value if is_jupyter
|
|
72
|
-
refresh_per_second=10 if not is_jupyter else 999,
|
|
73
|
-
)
|
divi/circuits.py
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
from copy import deepcopy
|
|
7
|
-
from itertools import product
|
|
8
|
-
from typing import Literal, Optional
|
|
9
|
-
|
|
10
|
-
import dill
|
|
11
|
-
import pennylane as qml
|
|
12
|
-
from pennylane.transforms.core.transform_program import TransformProgram
|
|
13
|
-
from qiskit.qasm2 import dumps
|
|
14
|
-
|
|
15
|
-
from divi.qasm import to_openqasm
|
|
16
|
-
from divi.qem import QEMProtocol
|
|
17
|
-
|
|
18
|
-
TRANSFORM_PROGRAM = TransformProgram()
|
|
19
|
-
TRANSFORM_PROGRAM.add_transform(qml.transforms.split_to_single_terms)
|
|
20
|
-
TRANSFORM_PROGRAM.add_transform(qml.transforms.split_non_commuting)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class Circuit:
|
|
24
|
-
_id_counter = 0
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
main_circuit,
|
|
29
|
-
tags: list[str],
|
|
30
|
-
qasm_circuits: list[str] = None,
|
|
31
|
-
):
|
|
32
|
-
self.main_circuit = main_circuit
|
|
33
|
-
self.circuit_type = main_circuit.__module__.split(".")[0]
|
|
34
|
-
self.tags = tags
|
|
35
|
-
|
|
36
|
-
self.qasm_circuits = qasm_circuits
|
|
37
|
-
|
|
38
|
-
if self.qasm_circuits is None:
|
|
39
|
-
self.convert_to_qasm()
|
|
40
|
-
|
|
41
|
-
self.circuit_id = Circuit._id_counter
|
|
42
|
-
Circuit._id_counter += 1
|
|
43
|
-
|
|
44
|
-
def __str__(self):
|
|
45
|
-
return f"Circuit: {self.circuit_id}"
|
|
46
|
-
|
|
47
|
-
def convert_to_qasm(self):
|
|
48
|
-
if self.circuit_type == "pennylane":
|
|
49
|
-
self.qasm_circuits = to_openqasm(
|
|
50
|
-
self.main_circuit,
|
|
51
|
-
measurement_groups=[self.main_circuit.measurements],
|
|
52
|
-
return_measurements_separately=False,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
elif self.circuit_type == "qiskit":
|
|
56
|
-
self.qasm_circuits = [dumps(self.main_circuit)]
|
|
57
|
-
|
|
58
|
-
else:
|
|
59
|
-
raise ValueError(
|
|
60
|
-
f"Invalid circuit type. Circuit type {self.circuit_type} not currently supported."
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class MetaCircuit:
|
|
65
|
-
def __init__(
|
|
66
|
-
self,
|
|
67
|
-
main_circuit,
|
|
68
|
-
symbols,
|
|
69
|
-
grouping_strategy: Optional[Literal["wires", "default", "qwc"]] = None,
|
|
70
|
-
qem_protocol: Optional[QEMProtocol] = None,
|
|
71
|
-
):
|
|
72
|
-
self.main_circuit = main_circuit
|
|
73
|
-
self.symbols = symbols
|
|
74
|
-
self.qem_protocol = qem_protocol
|
|
75
|
-
|
|
76
|
-
transform_program = deepcopy(TRANSFORM_PROGRAM)
|
|
77
|
-
transform_program[1].kwargs["grouping_strategy"] = grouping_strategy
|
|
78
|
-
|
|
79
|
-
qscripts, self.postprocessing_fn = transform_program((main_circuit,))
|
|
80
|
-
|
|
81
|
-
self.compiled_circuits_bodies, self.measurements = to_openqasm(
|
|
82
|
-
main_circuit,
|
|
83
|
-
measurement_groups=[qsc.measurements for qsc in qscripts],
|
|
84
|
-
return_measurements_separately=True,
|
|
85
|
-
# TODO: optimize later
|
|
86
|
-
measure_all=True,
|
|
87
|
-
symbols=self.symbols,
|
|
88
|
-
qem_protocol=qem_protocol,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
# Need to store the measurement groups for computing
|
|
92
|
-
# expectation values later on, stripped of the `qml.expval` wrapper
|
|
93
|
-
self.measurement_groups = [
|
|
94
|
-
[meas.obs for meas in qsc.measurements] for qsc in qscripts
|
|
95
|
-
]
|
|
96
|
-
|
|
97
|
-
def __getstate__(self):
|
|
98
|
-
state = self.__dict__.copy()
|
|
99
|
-
state["postprocessing_fn"] = dill.dumps(self.postprocessing_fn)
|
|
100
|
-
return state
|
|
101
|
-
|
|
102
|
-
def __setstate__(self, state):
|
|
103
|
-
state["postprocessing_fn"] = dill.loads(state["postprocessing_fn"])
|
|
104
|
-
|
|
105
|
-
self.__dict__.update(state)
|
|
106
|
-
|
|
107
|
-
def initialize_circuit_from_params(
|
|
108
|
-
self, param_list, tag_prefix: str = "", precision: int = 8
|
|
109
|
-
) -> Circuit:
|
|
110
|
-
mapping = dict(
|
|
111
|
-
zip(
|
|
112
|
-
map(lambda x: re.escape(str(x)), self.symbols),
|
|
113
|
-
map(lambda x: f"{x:.{precision}f}", param_list),
|
|
114
|
-
)
|
|
115
|
-
)
|
|
116
|
-
pattern = re.compile("|".join(k for k in mapping.keys()))
|
|
117
|
-
|
|
118
|
-
final_qasm_strs = []
|
|
119
|
-
for circuit_body in self.compiled_circuits_bodies:
|
|
120
|
-
final_qasm_strs.append(
|
|
121
|
-
pattern.sub(lambda match: mapping[match.group(0)], circuit_body)
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
tags = []
|
|
125
|
-
qasm_circuits = []
|
|
126
|
-
for (i, body_str), (j, meas_str) in product(
|
|
127
|
-
enumerate(final_qasm_strs), enumerate(self.measurements)
|
|
128
|
-
):
|
|
129
|
-
qasm_circuits.append(body_str + meas_str)
|
|
130
|
-
|
|
131
|
-
nonempty_subtags = filter(
|
|
132
|
-
None,
|
|
133
|
-
[tag_prefix, f"{self.qem_protocol.name}:{i}", str(j)],
|
|
134
|
-
)
|
|
135
|
-
tags.append("_".join(nonempty_subtags))
|
|
136
|
-
|
|
137
|
-
# Note: The main circuit's parameters are still in symbol form.
|
|
138
|
-
# Not sure if it is necessary for any useful application to parameterize them.
|
|
139
|
-
return Circuit(self.main_circuit, qasm_circuits=qasm_circuits, tags=tags)
|