diff --git a/docs/changelog.rst b/docs/changelog.rst index 18d2bebd..ce059b0f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,7 @@ Unreleased * Require qiskit >= 1.2.0. * Add conversion of controlled unitary gates from qiskit to tket. * Initialize `TketAutoPass` with a `BackendV2`. +* Update `TketBackend` to derive from `BackendV2`. 0.55.0 (July 2024) ------------------ diff --git a/pytket/extensions/qiskit/tket_backend.py b/pytket/extensions/qiskit/tket_backend.py index b44a03f0..47e598bd 100644 --- a/pytket/extensions/qiskit/tket_backend.py +++ b/pytket/extensions/qiskit/tket_backend.py @@ -12,36 +12,41 @@ # See the License for the specific language governing permissions and # limitations under the License. +import inspect from typing import Optional, Any +from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping # type: ignore from qiskit.circuit.quantumcircuit import QuantumCircuit # type: ignore -from qiskit.providers.backend import BackendV1 # type: ignore -from qiskit.providers.models import QasmBackendConfiguration # type: ignore +from qiskit.providers.backend import BackendV2 # type: ignore from qiskit.providers import Options # type: ignore +from qiskit.transpiler import CouplingMap, Target # type: ignore from pytket.extensions.qiskit import AerStateBackend, AerUnitaryBackend from pytket.extensions.qiskit.qiskit_convert import qiskit_to_tk, _gate_str_2_optype_rev from pytket.extensions.qiskit.tket_job import TketJob, JobInfo from pytket.backends import Backend from pytket.passes import BasePass -from pytket.predicates import ( - NoClassicalControlPredicate, - GateSetPredicate, - CompilationUnit, -) +from pytket.predicates import GateSetPredicate, CompilationUnit from pytket.architecture import FullyConnected def _extract_basis_gates(backend: Backend) -> list[str]: + standard_gate_mapping = get_standard_gate_name_mapping() for pred in backend.required_predicates: - if type(pred) == GateSetPredicate: - return [ - _gate_str_2_optype_rev[optype] - for optype in pred.gate_set - if optype in _gate_str_2_optype_rev.keys() - ] + if type(pred) is GateSetPredicate: + basis_gates = [] + # Restrict to the gate set accepted by the backend, the converters, + # and the Target.from_configuration() method. + for optype in pred.gate_set: + if optype in _gate_str_2_optype_rev.keys(): + gate_name = _gate_str_2_optype_rev[optype] + if gate_name in standard_gate_mapping: + gate_obj = standard_gate_mapping[gate_name] + if gate_obj.num_qubits in [1, 2] or inspect.isclass(gate_obj): + basis_gates.append(gate_name) + return basis_gates return [] -class TketBackend(BackendV1): +class TketBackend(BackendV2): """Wraps a :py:class:`Backend` as a :py:class:`qiskit.providers.BaseBackend` for use within the Qiskit software stack. @@ -87,31 +92,27 @@ def __init__(self, backend: Backend, comp_pass: Optional[BasePass] = None): [[n.index[0], m.index[0]] for n, m in arch.coupling] if arch else None ) - config = QasmBackendConfiguration( - backend_name=("statevector_" if backend.supports_state else "") + super().__init__( + name=("statevector_" if backend.supports_state else "") + "pytket/" + str(type(backend)), backend_version="0.0.1", - n_qubits=len(arch.nodes) if arch and arch.nodes else 40, - basis_gates=_extract_basis_gates(backend), - gates=[], - local=False, - simulator=False, - conditional=not any( - ( - type(pred) == NoClassicalControlPredicate - for pred in backend.required_predicates - ) - ), - open_pulse=False, - memory=backend.supports_shots, - max_shots=10000, - coupling_map=coupling, - max_experiments=10000, ) - super().__init__(configuration=config, provider=None) self._backend = backend self._comp_pass = comp_pass + self._target = Target.from_configuration( + basis_gates=_extract_basis_gates(backend), + num_qubits=len(arch.nodes) if arch and arch.nodes else 40, + coupling_map=CouplingMap(coupling), + ) + + @property + def target(self) -> Target: + return self._target + + @property + def max_circuits(self) -> int: + return 10000 @classmethod def _default_options(cls) -> Options: diff --git a/pytket/extensions/qiskit/tket_job.py b/pytket/extensions/qiskit/tket_job.py index e9304773..2e2dbece 100644 --- a/pytket/extensions/qiskit/tket_job.py +++ b/pytket/extensions/qiskit/tket_job.py @@ -93,8 +93,8 @@ def result(self, **kwargs: KwargTypes) -> Result: self._result = Result.from_dict( { "results": result_list, - "backend_name": self._backend.configuration().backend_name, - "backend_version": self._backend.configuration().backend_version, + "backend_name": self._backend.name, + "backend_version": self._backend.backend_version, "job_id": self._job_id, "qobj_id": ", ".join(str(hand) for hand in self._handles), "success": True,