Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update TketBackend to derive from BackendV2 #389

Merged
merged 4 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
------------------
Expand Down
67 changes: 34 additions & 33 deletions pytket/extensions/qiskit/tket_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps worth adding a comment explaining what these "if" statements are for?

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):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://github.com/Qiskit/qiskit/blob/2ef371ae0d159a6dfd643805f3e5e5fdec37ab88/qiskit/transpiler/target.py#L1066 -- have to restrict the gateset to match what is accepted by the Target method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that the gate_obj variable is not always a class? Presumably thats why the inspect check is needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, some gates such as CCX were rejected when I omitted this check. I am not sure when gate_obj is a class, but simply copied that from the code linked above.

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.

Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions pytket/extensions/qiskit/tket_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down