Skip to content

Commit

Permalink
use pytket-qir for qir generation (#24)
Browse files Browse the repository at this point in the history
* use pytket-qir for qir generation

* allow longer queue

* fix mypy

* Update pytket/extensions/azure/backends/azure.py

Co-authored-by: Alec Edgington <[email protected]>

* requested changes

* remove qiskit, update changelog and version

* clean up

* Update pytket/extensions/azure/backends/azure.py

Co-authored-by: Alec Edgington <[email protected]>

* format

---------

Co-authored-by: Alec Edgington <[email protected]>
  • Loading branch information
cqc-melf and cqc-alec authored Dec 20, 2024
1 parent b9d7091 commit b6872f8
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 34 deletions.
2 changes: 1 addition & 1 deletion _metadata.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__extension_version__ = "0.3.0"
__extension_version__ = "0.4.0"
__extension_name__ = "pytket-azure"
9 changes: 8 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
Changelog
~~~~~~~~~

0.4.0 (unreleased)
------------------

* Update minimum pytket version to 1.37.0.
* Update minimum pytket-qir version to 0.19.0.
* Use pytket-qir for the QIR generation
* remove qiskit-qir and pytket-qiskit as dependencies

0.3.0 (October 2024)
--------------------

Expand All @@ -11,7 +19,6 @@ Changelog
* Update minimum pytket version to 1.34.0.
* Update minimum pytket-qiskit version to 0.58.0.


0.2.0 (October 2024)
---------------------

Expand Down
99 changes: 82 additions & 17 deletions pytket/extensions/azure/backends/azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
from functools import cache
from typing import Any, Optional, Union, cast

from qiskit_qir import to_qir_module

from azure.quantum import Job, Workspace
from pytket.backends import Backend, CircuitStatus, ResultHandle, StatusEnum
from pytket.backends.backend import KwargTypes
Expand All @@ -30,9 +28,9 @@
from pytket.backends.resulthandle import _ResultIdTuple
from pytket.circuit import Circuit, OpType
from pytket.extensions.azure._metadata import __extension_version__
from pytket.extensions.qiskit import tk_to_qiskit
from pytket.passes import AutoRebase, BasePass
from pytket.predicates import GateSetPredicate, Predicate
from pytket.qir import QIRFormat, QIRProfile, pytket_to_qir
from pytket.utils import OutcomeArray

from .config import AzureConfig
Expand Down Expand Up @@ -78,6 +76,26 @@ def _get_workspace(
}


_ADDITIONAL_GATES = {
OpType.Reset,
OpType.Measure,
OpType.Barrier,
OpType.RangePredicate,
OpType.MultiBit,
OpType.ExplicitPredicate,
OpType.ExplicitModifier,
OpType.SetBits,
OpType.CopyBits,
OpType.ClassicalExpBox,
OpType.ClExpr,
OpType.WASM,
}


_ALL_GATES = _ADDITIONAL_GATES.copy()
_ALL_GATES.update(_GATE_SET)


class AzureBackend(Backend):
"""Interface to Azure Quantum."""

Expand Down Expand Up @@ -129,14 +147,16 @@ def __init__(
)
_persistent_handles = False
self._jobs: dict[ResultHandle, Job] = {}
self._result_bits: dict[ResultHandle, list] = {}
self._result_c_regs: dict[ResultHandle, list] = {}

@property
def backend_info(self) -> BackendInfo:
return self._backendinfo

@property
def required_predicates(self) -> list[Predicate]:
return [GateSetPredicate(_GATE_SET)]
return [GateSetPredicate(_ALL_GATES)]

def rebase_pass(self) -> BasePass:
return AutoRebase(gateset=_GATE_SET)
Expand Down Expand Up @@ -177,18 +197,38 @@ def process_circuits(

handles = []
for i, (c, n_shots) in enumerate(zip(circuits, n_shots_list)):
qkc = tk_to_qiskit(c)
module, entry_points = to_qir_module(qkc)
assert len(entry_points) == 1

input_params = {
"entryPoint": entry_points[0],
"entryPoint": "main",
"arguments": [],
"count": n_shots,
}

if (
self._backendinfo.device_name
and self._backendinfo.device_name[:11] == "quantinuum."
):

module_bitcode = pytket_to_qir(
c,
qir_format=QIRFormat.BINARY,
int_type=64,
cut_pytket_register=False,
profile=QIRProfile.AZUREADAPTIVE,
)
else:
module_bitcode = pytket_to_qir(
c,
qir_format=QIRFormat.BINARY,
int_type=64,
cut_pytket_register=False,
profile=QIRProfile.AZUREBASE,
)

if option_params is not None:
input_params.update(option_params) # type: ignore
job = self._target.submit(
input_data=module.bitcode,
input_data=module_bitcode,
input_data_format="qir.v1",
output_data_format="microsoft.quantum-results.v1",
name=f"job_{i}",
Expand All @@ -198,6 +238,8 @@ def process_circuits(
handle = ResultHandle(jobid)
handles.append(handle)
self._jobs[handle] = job
self._result_bits[handle] = c.bits
self._result_c_regs[handle] = c.c_registers
for handle in handles:
self._cache[handle] = dict()
return handles
Expand All @@ -210,15 +252,38 @@ def _update_cache_result(
else:
self._cache[handle] = result_dict

def _make_backend_result(self, results: Any, job: Job) -> BackendResult:
def _make_backend_result(
self, results: Any, job: Job, handle: ResultHandle
) -> BackendResult:
n_shots = job.details.input_params["count"]
counts: Counter[OutcomeArray] = Counter()
for s, p in results.items():
outcome = literal_eval(s)
n = int(n_shots * p + 0.5)
oa = OutcomeArray.from_readouts([outcome])
counts[oa] = n
return BackendResult(counts=counts)
if (
self._backendinfo.device_name
and self._backendinfo.device_name[:11] == "quantinuum."
):
for s, p in results.items():
outcome = literal_eval(s)
n = int(n_shots * p + 0.5)
assert len(outcome) == len(self._result_c_regs[handle])
list_bits: list = []
for res, creg in zip(outcome, self._result_c_regs[handle]):
long_res = bin(int(res)).replace(
"0b",
"0000000000000000000000000000000000000\
00000000000000000000000000", # 0 * 63
)
list_bits.append(long_res[-creg.size :])
all_bits = "".join(list_bits)

counts[OutcomeArray.from_readouts([[int(x) for x in all_bits]])] = n
return BackendResult(counts=counts, c_bits=self._result_bits[handle])
else:
for s, p in results.items():
outcome = literal_eval(s)
n = int(n_shots * p + 0.5)
oa = OutcomeArray.from_readouts([outcome])
counts[oa] = n
return BackendResult(counts=counts)

def circuit_status(self, handle) -> CircuitStatus:
job = self._jobs[handle]
Expand All @@ -228,7 +293,7 @@ def circuit_status(self, handle) -> CircuitStatus:
results = job.get_results()
self._update_cache_result(
handle,
{"result": self._make_backend_result(results, job)},
{"result": self._make_backend_result(results, job, handle)},
)
return CircuitStatus(StatusEnum.COMPLETED)
elif status == "Waiting":
Expand Down
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@
include_package_data=True,
install_requires=[
"azure-quantum >= 2.2.0",
"pytket >= 1.34.0",
"pytket-qiskit >= 0.58.0",
"qiskit-qir >= 0.5.0",
"pytket >= 1.37.0",
"pytket-qir >= 0.19.0",
],
classifiers=[
"Environment :: Console",
Expand Down
Loading

0 comments on commit b6872f8

Please sign in to comment.