azure-quantum 3.4.1.dev1__tar.gz → 3.5.0.dev0__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.
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/PKG-INFO +5 -13
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_version.py +1 -1
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/_enums.py +10 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/_models.py +4 -4
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/targets/ionq.py +5 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/job.py +5 -4
- azure_quantum-3.5.0.dev0/azure/quantum/qiskit/backends/_qiskit_ionq.py +377 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/backend.py +370 -138
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/ionq.py +27 -34
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/qci.py +12 -14
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/quantinuum.py +46 -44
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/rigetti.py +10 -14
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/job.py +21 -14
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/provider.py +12 -6
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/pasqal/result.py +1 -1
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/rigetti/result.py +1 -1
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/target.py +4 -56
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/version.py +1 -1
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure_quantum.egg-info/PKG-INFO +5 -13
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure_quantum.egg-info/SOURCES.txt +1 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure_quantum.egg-info/requires.txt +4 -12
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements-dev.txt +1 -0
- azure_quantum-3.5.0.dev0/requirements-qiskit.txt +1 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements.txt +0 -2
- azure_quantum-3.4.1.dev1/requirements-qiskit.txt +0 -5
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/README.md +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_client.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_configuration.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_model_base.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_patch.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/_serialization.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/_patch.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/operations/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/operations/_operations.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/operations/_patch.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_constants.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_workspace_connection_params.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/argument_types/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/argument_types/types.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/job.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/service.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/targets/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/targets/quantinuum.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/cirq/targets/target.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/base_job.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/filtered_job.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/job_failed_with_results_error.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/session.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/workspace_item.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/job/workspace_item_factory.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/qiskit/backends/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/storage.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/ionq.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/params.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/pasqal/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/pasqal/target.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/quantinuum.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/rigetti/__init__.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/rigetti/target.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/target/target_factory.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/workspace.py +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure_quantum.egg-info/dependency_links.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure_quantum.egg-info/top_level.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements-cirq.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements-pulser.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements-qsharp.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/requirements-quil.txt +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/setup.cfg +0 -0
- {azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: azure-quantum
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0.dev0
|
|
4
4
|
Summary: Python client for Azure Quantum
|
|
5
5
|
Home-page: https://github.com/microsoft/azure-quantum-python
|
|
6
6
|
Author: Microsoft
|
|
@@ -16,8 +16,6 @@ Requires-Dist: azure-storage-blob==12.20
|
|
|
16
16
|
Requires-Dist: msrest<1.0,>=0.7.1
|
|
17
17
|
Requires-Dist: numpy>=1.21.0
|
|
18
18
|
Requires-Dist: deprecated<2.0,>=1.2.12
|
|
19
|
-
Requires-Dist: Markdown>=3.4.1
|
|
20
|
-
Requires-Dist: python-markdown-math>=0.8
|
|
21
19
|
Provides-Extra: cirq
|
|
22
20
|
Requires-Dist: cirq-core<=1.4.1,>=1.3.0; extra == "cirq"
|
|
23
21
|
Requires-Dist: cirq-ionq<=1.4.1,>=1.3.0; extra == "cirq"
|
|
@@ -27,14 +25,11 @@ Requires-Dist: pytest-xdist<4.0,>=3.8.0; extra == "dev"
|
|
|
27
25
|
Requires-Dist: vcrpy>=4.3.1; extra == "dev"
|
|
28
26
|
Requires-Dist: azure-devtools<2.0,>=1.2.0; extra == "dev"
|
|
29
27
|
Requires-Dist: graphviz>=0.20.1; extra == "dev"
|
|
28
|
+
Requires-Dist: tox>=4.32.0; extra == "dev"
|
|
30
29
|
Provides-Extra: pulser
|
|
31
30
|
Requires-Dist: pulser<0.19,>=0.18; extra == "pulser"
|
|
32
31
|
Provides-Extra: qiskit
|
|
33
|
-
Requires-Dist: qiskit
|
|
34
|
-
Requires-Dist: qsharp[qiskit]<2.0,>=1.9.0; extra == "qiskit"
|
|
35
|
-
Requires-Dist: pyqir<0.11,>=0.10.6; extra == "qiskit"
|
|
36
|
-
Requires-Dist: Markdown<4.0,>=3.4.1; extra == "qiskit"
|
|
37
|
-
Requires-Dist: python-markdown-math<1.0,>=0.8.0; extra == "qiskit"
|
|
32
|
+
Requires-Dist: qsharp[qiskit]<2.0,>=1.22.0; extra == "qiskit"
|
|
38
33
|
Provides-Extra: qsharp
|
|
39
34
|
Requires-Dist: qsharp<2.0,>=1.0.33; extra == "qsharp"
|
|
40
35
|
Provides-Extra: quil
|
|
@@ -47,12 +42,9 @@ Requires-Dist: pytest-xdist<4.0,>=3.8.0; extra == "all"
|
|
|
47
42
|
Requires-Dist: vcrpy>=4.3.1; extra == "all"
|
|
48
43
|
Requires-Dist: azure-devtools<2.0,>=1.2.0; extra == "all"
|
|
49
44
|
Requires-Dist: graphviz>=0.20.1; extra == "all"
|
|
45
|
+
Requires-Dist: tox>=4.32.0; extra == "all"
|
|
50
46
|
Requires-Dist: pulser<0.19,>=0.18; extra == "all"
|
|
51
|
-
Requires-Dist: qiskit
|
|
52
|
-
Requires-Dist: qsharp[qiskit]<2.0,>=1.9.0; extra == "all"
|
|
53
|
-
Requires-Dist: pyqir<0.11,>=0.10.6; extra == "all"
|
|
54
|
-
Requires-Dist: Markdown<4.0,>=3.4.1; extra == "all"
|
|
55
|
-
Requires-Dist: python-markdown-math<1.0,>=0.8.0; extra == "all"
|
|
47
|
+
Requires-Dist: qsharp[qiskit]<2.0,>=1.22.0; extra == "all"
|
|
56
48
|
Requires-Dist: qsharp<2.0,>=1.0.33; extra == "all"
|
|
57
49
|
Requires-Dist: pyquil==4.13.1; extra == "all"
|
|
58
50
|
|
{azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/_enums.py
RENAMED
|
@@ -33,8 +33,18 @@ class JobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta):
|
|
|
33
33
|
|
|
34
34
|
WAITING = "Waiting"
|
|
35
35
|
"""The job is waiting in the queue to be executed."""
|
|
36
|
+
QUEUED = "Queued"
|
|
37
|
+
"""The job is queued for execution."""
|
|
36
38
|
EXECUTING = "Executing"
|
|
37
39
|
"""The job is being executed."""
|
|
40
|
+
FINISHING = "Finishing"
|
|
41
|
+
"""The job is in the process of finishing."""
|
|
42
|
+
CANCELLATION_REQUESTED = "CancellationRequested"
|
|
43
|
+
"""Cancellation for the job has been requested."""
|
|
44
|
+
CANCELLING = "Cancelling"
|
|
45
|
+
"""The job is in the process of being cancelled."""
|
|
46
|
+
COMPLETED = "Completed"
|
|
47
|
+
"""The job has completed execution."""
|
|
38
48
|
SUCCEEDED = "Succeeded"
|
|
39
49
|
"""The job completed with success."""
|
|
40
50
|
FAILED = "Failed"
|
{azure_quantum-3.4.1.dev1 → azure_quantum-3.5.0.dev0}/azure/quantum/_client/models/_models.py
RENAMED
|
@@ -252,8 +252,8 @@ class JobDetails(ItemDetails, discriminator="Job"):
|
|
|
252
252
|
:vartype input_data_uri: str
|
|
253
253
|
:ivar input_data_format: The format of the input data.
|
|
254
254
|
:vartype input_data_format: str
|
|
255
|
-
:ivar status: The status of the job. Known values are: "Waiting", "Executing", "
|
|
256
|
-
"Failed", and "Cancelled".
|
|
255
|
+
:ivar status: The status of the job. Known values are: "Waiting", "Queued", "Executing", "Finishing", "Completed",
|
|
256
|
+
"Succeeded", "Failed", "Cancelling", "CancellationRequested" and "Cancelled".
|
|
257
257
|
:vartype status: str or ~azure.quantum.models.JobStatus
|
|
258
258
|
:ivar metadata: The job metadata. Metadata provides client the ability to store client-specific
|
|
259
259
|
information.
|
|
@@ -289,8 +289,8 @@ class JobDetails(ItemDetails, discriminator="Job"):
|
|
|
289
289
|
input_data_format: Optional[str] = rest_field(name="inputDataFormat", visibility=["read", "create"])
|
|
290
290
|
"""The format of the input data."""
|
|
291
291
|
status: Optional[Union[str, "_models.JobStatus"]] = rest_field(visibility=["read"])
|
|
292
|
-
"""The status of the job. Known values are: \"Waiting\", \"Executing\", \"
|
|
293
|
-
and \"Cancelled\"."""
|
|
292
|
+
"""The status of the job. Known values are: \"Waiting\", \"Queued\", \"Executing\", \"Finishing\", \"Completed\",
|
|
293
|
+
\"Succeeded\", \"Failed\", \"Cancelling\", \"CancellationRequested\" and \"Cancelled\"."""
|
|
294
294
|
metadata: Optional[Any] = rest_field(visibility=["read", "create", "update"])
|
|
295
295
|
"""The job metadata. Metadata provides client the ability to store client-specific information."""
|
|
296
296
|
cancellation_time: Optional[datetime.datetime] = rest_field(
|
|
@@ -30,10 +30,15 @@ class _IonQClient:
|
|
|
30
30
|
def _to_ionq_status(status: str):
|
|
31
31
|
from azure.quantum._client.models._enums import JobStatus
|
|
32
32
|
_STATUS_DICT = {
|
|
33
|
+
JobStatus.COMPLETED: 'completed',
|
|
33
34
|
JobStatus.SUCCEEDED: 'completed',
|
|
34
35
|
JobStatus.CANCELLED: 'canceled',
|
|
35
36
|
JobStatus.FAILED: 'failed',
|
|
36
37
|
JobStatus.EXECUTING: 'running',
|
|
38
|
+
JobStatus.FINISHING: 'running',
|
|
39
|
+
JobStatus.CANCELLATION_REQUESTED: 'running',
|
|
40
|
+
JobStatus.CANCELLING: 'running',
|
|
41
|
+
JobStatus.QUEUED: 'ready',
|
|
37
42
|
JobStatus.WAITING: 'ready'
|
|
38
43
|
}
|
|
39
44
|
return _STATUS_DICT.get(status, 'submitted')
|
|
@@ -59,7 +59,8 @@ class Job(BaseJob, FilteredJob):
|
|
|
59
59
|
def has_completed(self) -> bool:
|
|
60
60
|
"""Check if the job has completed."""
|
|
61
61
|
return (
|
|
62
|
-
self.details.status == "
|
|
62
|
+
self.details.status == "Completed"
|
|
63
|
+
or self.details.status == "Succeeded"
|
|
63
64
|
or self.details.status == "Failed"
|
|
64
65
|
or self.details.status == "Cancelled"
|
|
65
66
|
)
|
|
@@ -124,7 +125,7 @@ class Job(BaseJob, FilteredJob):
|
|
|
124
125
|
if not self.has_completed():
|
|
125
126
|
self.wait_until_completed(timeout_secs=timeout_secs)
|
|
126
127
|
|
|
127
|
-
if not self.details.status == "Succeeded":
|
|
128
|
+
if not self.details.status == "Succeeded" or self.details.status == "Completed":
|
|
128
129
|
if self.details.status == "Failed" and self._allow_failure_results():
|
|
129
130
|
job_blob_properties = self.download_blob_properties(self.details.output_data_uri)
|
|
130
131
|
if job_blob_properties.size > 0:
|
|
@@ -204,7 +205,7 @@ class Job(BaseJob, FilteredJob):
|
|
|
204
205
|
if not self.has_completed():
|
|
205
206
|
self.wait_until_completed(timeout_secs=timeout_secs)
|
|
206
207
|
|
|
207
|
-
if not self.details.status == "Succeeded":
|
|
208
|
+
if not self.details.status == "Succeeded" or self.details.status == "Completed":
|
|
208
209
|
if self.details.status == "Failed" and self._allow_failure_results():
|
|
209
210
|
job_blob_properties = self.download_blob_properties(self.details.output_data_uri)
|
|
210
211
|
if job_blob_properties.size > 0:
|
|
@@ -287,7 +288,7 @@ class Job(BaseJob, FilteredJob):
|
|
|
287
288
|
if not self.has_completed():
|
|
288
289
|
self.wait_until_completed(timeout_secs=timeout_secs)
|
|
289
290
|
|
|
290
|
-
if not self.details.status == "Succeeded":
|
|
291
|
+
if not self.details.status == "Succeeded" or self.details.status == "Completed":
|
|
291
292
|
if self.details.status == "Failed" and self._allow_failure_results():
|
|
292
293
|
job_blob_properties = self.download_blob_properties(self.details.output_data_uri)
|
|
293
294
|
if job_blob_properties.size > 0:
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# This code is part of Qiskit.
|
|
2
|
+
#
|
|
3
|
+
# (C) Copyright IBM 2017, 2018.
|
|
4
|
+
#
|
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
8
|
+
#
|
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
|
11
|
+
# that they have been altered from the originals.
|
|
12
|
+
|
|
13
|
+
# Copyright 2020 IonQ, Inc. (www.ionq.com)
|
|
14
|
+
#
|
|
15
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
16
|
+
# you may not use this file except in compliance with the License.
|
|
17
|
+
# You may obtain a copy of the License at
|
|
18
|
+
#
|
|
19
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
20
|
+
#
|
|
21
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
22
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
23
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
24
|
+
# See the License for the specific language governing permissions and
|
|
25
|
+
# limitations under the License.
|
|
26
|
+
|
|
27
|
+
# This code is copied from:
|
|
28
|
+
# - <https://github.com/qiskit-community/qiskit-ionq/blob/cea8f9874b992f82a35648582c06958869370c69/qiskit_ionq/helpers.py>
|
|
29
|
+
# - <https://github.com/qiskit-community/qiskit-ionq/blob/cea8f9874b992f82a35648582c06958869370c69/qiskit_ionq/exceptions.py>
|
|
30
|
+
# to enable Qiskit 1 & 2 compatibility as the original package only
|
|
31
|
+
# supports Qiskit 1 OR 2 depending on the package version.
|
|
32
|
+
# Modified by Microsoft Corporation for Azure Quantum integration and BackendV2 support (2025-11-10).
|
|
33
|
+
|
|
34
|
+
# the qiskit gates that the IonQ backend can serialize to our IR
|
|
35
|
+
# not the actual hardware basis gates for the system — we do our own transpilation pass.
|
|
36
|
+
# also not an exact/complete list of the gates IonQ's backend takes
|
|
37
|
+
# by name — please refer to IonQ docs for that.
|
|
38
|
+
#
|
|
39
|
+
# Some of these gates may be deprecated or removed in qiskit 1.0
|
|
40
|
+
ionq_basis_gates = [
|
|
41
|
+
"ccx",
|
|
42
|
+
"ch",
|
|
43
|
+
"cnot",
|
|
44
|
+
"cp",
|
|
45
|
+
"crx",
|
|
46
|
+
"cry",
|
|
47
|
+
"crz",
|
|
48
|
+
"csx",
|
|
49
|
+
"cx",
|
|
50
|
+
"cy",
|
|
51
|
+
"cz",
|
|
52
|
+
"h",
|
|
53
|
+
"i",
|
|
54
|
+
"id",
|
|
55
|
+
"mcp",
|
|
56
|
+
"mcphase",
|
|
57
|
+
"mct",
|
|
58
|
+
"mcx",
|
|
59
|
+
"measure",
|
|
60
|
+
"p",
|
|
61
|
+
"rx",
|
|
62
|
+
"rxx",
|
|
63
|
+
"ry",
|
|
64
|
+
"ryy",
|
|
65
|
+
"rz",
|
|
66
|
+
"rzz",
|
|
67
|
+
"s",
|
|
68
|
+
"sdg",
|
|
69
|
+
"swap",
|
|
70
|
+
"sx",
|
|
71
|
+
"sxdg",
|
|
72
|
+
"t",
|
|
73
|
+
"tdg",
|
|
74
|
+
"toffoli",
|
|
75
|
+
"x",
|
|
76
|
+
"y",
|
|
77
|
+
"z",
|
|
78
|
+
"PauliEvolution",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# https://ionq.com/docs/getting-started-with-native-gates
|
|
82
|
+
ionq_native_basis_gates = [
|
|
83
|
+
"gpi",
|
|
84
|
+
"gpi2",
|
|
85
|
+
"ms", # Pairwise MS gate
|
|
86
|
+
"zz", # ZZ gate
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
# Each language corresponds to a different set of basis gates.
|
|
90
|
+
GATESET_MAP = {
|
|
91
|
+
"qis": ionq_basis_gates,
|
|
92
|
+
"native": ionq_native_basis_gates,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
ionq_api_aliases = { # todo fix alias bug
|
|
96
|
+
"cp": "cz",
|
|
97
|
+
"csx": "cv",
|
|
98
|
+
"mcphase": "cz",
|
|
99
|
+
"ccx": "cx", # just one C for all mcx
|
|
100
|
+
"mcx": "cx", # just one C for all mcx
|
|
101
|
+
"tdg": "ti",
|
|
102
|
+
"p": "z",
|
|
103
|
+
"PauliEvolution": "pauliexp",
|
|
104
|
+
"rxx": "xx",
|
|
105
|
+
"ryy": "yy",
|
|
106
|
+
"rzz": "zz",
|
|
107
|
+
"sdg": "si",
|
|
108
|
+
"sx": "v",
|
|
109
|
+
"sxdg": "vi",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
from qiskit.circuit import (
|
|
113
|
+
controlledgate as q_cgates,
|
|
114
|
+
QuantumCircuit,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
from typing import Literal, Any
|
|
118
|
+
|
|
119
|
+
from qiskit.exceptions import QiskitError
|
|
120
|
+
|
|
121
|
+
class IonQError(QiskitError):
|
|
122
|
+
"""Base class for errors raised by an IonQProvider."""
|
|
123
|
+
|
|
124
|
+
def __str__(self) -> str:
|
|
125
|
+
return f"{self.__class__.__name__}({self.message!r})"
|
|
126
|
+
|
|
127
|
+
def __repr__(self) -> str:
|
|
128
|
+
return repr(str(self))
|
|
129
|
+
|
|
130
|
+
class JobError(QiskitError):
|
|
131
|
+
"""Base class for errors raised by Jobs."""
|
|
132
|
+
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
class IonQGateError(IonQError, JobError):
|
|
136
|
+
"""Errors generated from invalid gate defs
|
|
137
|
+
|
|
138
|
+
Attributes:
|
|
139
|
+
gate_name: The name of the gate which caused this error.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def __init__(self, gate_name: str, gateset: Literal["qis", "native"]):
|
|
143
|
+
self.gate_name = gate_name
|
|
144
|
+
self.gateset = gateset
|
|
145
|
+
super().__init__(
|
|
146
|
+
(
|
|
147
|
+
f"gate '{gate_name}' is not supported on the '{gateset}' IonQ backends. "
|
|
148
|
+
"Please use the qiskit.transpile method, manually rewrite to remove the gate, "
|
|
149
|
+
"or change the gateset selection as appropriate."
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def __repr__(self):
|
|
154
|
+
return f"{self.__class__.__name__}(gate_name={self.gate_name!r}, gateset={self.gateset!r})"
|
|
155
|
+
|
|
156
|
+
class IonQMidCircuitMeasurementError(IonQError, JobError):
|
|
157
|
+
"""Errors generated from attempting mid-circuit measurement, which is not supported.
|
|
158
|
+
Measurement must come after all instructions.
|
|
159
|
+
|
|
160
|
+
Attributes:
|
|
161
|
+
qubit_index: The qubit index to be measured mid-circuit
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def __init__(self, qubit_index: int, gate_name: str):
|
|
165
|
+
self.qubit_index = qubit_index
|
|
166
|
+
self.gate_name = gate_name
|
|
167
|
+
super().__init__(
|
|
168
|
+
f"Attempting to put '{gate_name}' after a measurement on qubit {qubit_index}. "
|
|
169
|
+
"Mid-circuit measurement is not supported."
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def __str__(self):
|
|
173
|
+
kwargs = f"qubit_index={self.qubit_index!r}, gate_name={self.gate_name!r}"
|
|
174
|
+
return f"{self.__class__.__name__}({kwargs})"
|
|
175
|
+
|
|
176
|
+
class IonQPauliExponentialError(IonQError):
|
|
177
|
+
"""Errors generated from improper usage of Pauli exponentials."""
|
|
178
|
+
|
|
179
|
+
def paulis_commute(pauli_terms: list[str]) -> bool:
|
|
180
|
+
"""Check if a list of Pauli terms commute.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
pauli_terms (list): A list of Pauli terms.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
bool: Whether the Pauli terms commute.
|
|
187
|
+
"""
|
|
188
|
+
for i, term in enumerate(pauli_terms):
|
|
189
|
+
for other_term in pauli_terms[i:]:
|
|
190
|
+
assert len(term) == len(other_term)
|
|
191
|
+
anticommutation_parity = 0
|
|
192
|
+
for index, char in enumerate(term):
|
|
193
|
+
other_char = other_term[index]
|
|
194
|
+
if "I" not in (char, other_char):
|
|
195
|
+
if char != other_char:
|
|
196
|
+
anticommutation_parity += 1
|
|
197
|
+
if anticommutation_parity % 2 == 1:
|
|
198
|
+
return False
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
def qiskit_circ_to_ionq_circ(
|
|
202
|
+
input_circuit: QuantumCircuit,
|
|
203
|
+
gateset: Literal["qis", "native"] = "qis",
|
|
204
|
+
ionq_compiler_synthesis: bool = False,
|
|
205
|
+
):
|
|
206
|
+
"""Build a circuit in IonQ's instruction format from qiskit instructions.
|
|
207
|
+
|
|
208
|
+
.. ATTENTION:: This function ignores the following compiler directives:
|
|
209
|
+
* ``barrier``
|
|
210
|
+
|
|
211
|
+
Parameters:
|
|
212
|
+
input_circuit (:class:`qiskit.circuit.QuantumCircuit`): A Qiskit quantum circuit.
|
|
213
|
+
gateset (string): Set of gates to target. It can be QIS (required transpilation pass in
|
|
214
|
+
IonQ backend, which is sent standard gates) or native (only IonQ native gates are
|
|
215
|
+
allowed, in the future we may provide transpilation to these gates in Qiskit).
|
|
216
|
+
ionq_compiler_synthesis (bool): Whether to opt-in to IonQ compiler's intelligent
|
|
217
|
+
trotterization.
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
IonQGateError: If an unsupported instruction is supplied.
|
|
221
|
+
IonQMidCircuitMeasurementError: If a mid-circuit measurement is detected.
|
|
222
|
+
IonQPauliExponentialError: If non-commuting PauliExponentials are found without
|
|
223
|
+
the appropriate flag.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
list[dict]: A list of instructions in a converted dict format.
|
|
227
|
+
int: The number of measurements.
|
|
228
|
+
dict: The measurement map from qubit number to classical bit number.
|
|
229
|
+
"""
|
|
230
|
+
compiler_directives = ["barrier"]
|
|
231
|
+
output_circuit = []
|
|
232
|
+
num_meas = 0
|
|
233
|
+
meas_map = [None] * len(input_circuit.clbits)
|
|
234
|
+
for inst in input_circuit.data:
|
|
235
|
+
instruction, qargs, cargs = inst.operation, inst.qubits, inst.clbits
|
|
236
|
+
|
|
237
|
+
# Don't process compiler directives.
|
|
238
|
+
instruction_name = instruction.name
|
|
239
|
+
if instruction_name in compiler_directives:
|
|
240
|
+
continue
|
|
241
|
+
|
|
242
|
+
# Don't process measurement instructions.
|
|
243
|
+
if instruction_name == "measure":
|
|
244
|
+
meas_map[input_circuit.clbits.index(cargs[0])] = input_circuit.qubits.index(
|
|
245
|
+
qargs[0]
|
|
246
|
+
)
|
|
247
|
+
num_meas += 1
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
# serialized identity gate is a no-op
|
|
251
|
+
if instruction_name == "id":
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
# Raise out for instructions we don't support.
|
|
255
|
+
if instruction_name not in GATESET_MAP[gateset]:
|
|
256
|
+
raise IonQGateError(instruction_name, gateset)
|
|
257
|
+
|
|
258
|
+
# Process the instruction and convert.
|
|
259
|
+
rotation: dict[str, Any] = {}
|
|
260
|
+
if len(instruction.params) > 0:
|
|
261
|
+
if gateset == "qis" or (
|
|
262
|
+
len(instruction.params) == 1 and instruction_name != "zz"
|
|
263
|
+
):
|
|
264
|
+
# The float is here to cast Qiskit ParameterExpressions to numbers
|
|
265
|
+
rotation = {
|
|
266
|
+
("rotation" if gateset == "qis" else "phase"): float(
|
|
267
|
+
instruction.params[0]
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
if instruction_name == "PauliEvolution":
|
|
271
|
+
# rename rotation to time
|
|
272
|
+
rotation["time"] = rotation.pop("rotation")
|
|
273
|
+
elif instruction_name in {"zz"}:
|
|
274
|
+
rotation = {"angle": instruction.params[0]}
|
|
275
|
+
else:
|
|
276
|
+
rotation = {
|
|
277
|
+
"phases": [float(t) for t in instruction.params[:2]],
|
|
278
|
+
"angle": instruction.params[2],
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Default conversion is simple, just gate & target(s).
|
|
282
|
+
targets = [input_circuit.qubits.index(qargs[0])]
|
|
283
|
+
if instruction_name in {"ms", "zz"}:
|
|
284
|
+
targets.append(input_circuit.qubits.index(qargs[1]))
|
|
285
|
+
|
|
286
|
+
converted = (
|
|
287
|
+
{"gate": instruction_name, "targets": targets}
|
|
288
|
+
if instruction_name not in {"gpi", "gpi2"}
|
|
289
|
+
else {
|
|
290
|
+
"gate": instruction_name,
|
|
291
|
+
"target": targets[0],
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# re-alias certain names
|
|
296
|
+
if instruction_name in ionq_api_aliases:
|
|
297
|
+
instruction_name = ionq_api_aliases[instruction_name]
|
|
298
|
+
converted["gate"] = instruction_name
|
|
299
|
+
|
|
300
|
+
# Make sure uncontrolled multi-targets use all qargs.
|
|
301
|
+
if instruction.num_qubits > 1 and not hasattr(instruction, "num_ctrl_qubits"):
|
|
302
|
+
converted["targets"] = [
|
|
303
|
+
input_circuit.qubits.index(qargs[i])
|
|
304
|
+
for i in range(instruction.num_qubits)
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
# If this is a controlled gate, make sure to set control qubits.
|
|
308
|
+
if isinstance(instruction, q_cgates.ControlledGate):
|
|
309
|
+
gate = instruction_name[1:] # trim the leading c
|
|
310
|
+
controls = [input_circuit.qubits.index(qargs[0])]
|
|
311
|
+
targets = [input_circuit.qubits.index(qargs[1])]
|
|
312
|
+
# If this is a multi-control, use more than one qubit.
|
|
313
|
+
if instruction.num_ctrl_qubits > 1:
|
|
314
|
+
controls = [
|
|
315
|
+
input_circuit.qubits.index(qargs[i])
|
|
316
|
+
for i in range(instruction.num_ctrl_qubits)
|
|
317
|
+
]
|
|
318
|
+
targets = [
|
|
319
|
+
input_circuit.qubits.index(qargs[instruction.num_ctrl_qubits])
|
|
320
|
+
]
|
|
321
|
+
if gate == "swap":
|
|
322
|
+
# If this is a cswap, we have two targets:
|
|
323
|
+
targets = [
|
|
324
|
+
input_circuit.qubits.index(qargs[-2]),
|
|
325
|
+
input_circuit.qubits.index(qargs[-1]),
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
# Update converted gate values.
|
|
329
|
+
converted.update(
|
|
330
|
+
{
|
|
331
|
+
"gate": gate,
|
|
332
|
+
"controls": controls,
|
|
333
|
+
"targets": targets,
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
if instruction_name == "pauliexp":
|
|
338
|
+
imag_coeff = any(coeff.imag for coeff in instruction.operator.coeffs)
|
|
339
|
+
assert not imag_coeff, (
|
|
340
|
+
"PauliEvolution gate must have real coefficients, "
|
|
341
|
+
f"but got {imag_coeff}"
|
|
342
|
+
)
|
|
343
|
+
terms = [term[0] for term in instruction.operator.to_list()]
|
|
344
|
+
if not ionq_compiler_synthesis and not paulis_commute(terms):
|
|
345
|
+
raise IonQPauliExponentialError(
|
|
346
|
+
f"You have included a PauliEvolutionGate with non-commuting terms: {terms}."
|
|
347
|
+
"To decompose it with IonQ hardware-aware synthesis, resubmit with the "
|
|
348
|
+
"IONQ_COMPILER_SYNTHESIS flag."
|
|
349
|
+
)
|
|
350
|
+
targets = [
|
|
351
|
+
input_circuit.qubits.index(qargs[i])
|
|
352
|
+
for i in range(instruction.num_qubits)
|
|
353
|
+
]
|
|
354
|
+
coefficients = [coeff.real for coeff in instruction.operator.coeffs]
|
|
355
|
+
gate = {
|
|
356
|
+
"gate": instruction_name,
|
|
357
|
+
"targets": targets,
|
|
358
|
+
"terms": terms,
|
|
359
|
+
"coefficients": coefficients,
|
|
360
|
+
}
|
|
361
|
+
converted.update(gate)
|
|
362
|
+
|
|
363
|
+
# if there's a valid instruction after a measurement,
|
|
364
|
+
if num_meas > 0:
|
|
365
|
+
# see if any of the involved qubits have been measured,
|
|
366
|
+
# and raise if so — no mid-circuit measurement!
|
|
367
|
+
controls_and_targets = converted.get("targets", []) + converted.get(
|
|
368
|
+
"controls", []
|
|
369
|
+
)
|
|
370
|
+
if any(i in meas_map for i in controls_and_targets):
|
|
371
|
+
raise IonQMidCircuitMeasurementError(
|
|
372
|
+
input_circuit.qubits.index(qargs[0]), instruction_name
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
output_circuit.append({**converted, **rotation})
|
|
376
|
+
|
|
377
|
+
return output_circuit, num_meas, meas_map
|