From 2410efd0db901e826f89450a0efe6c45a1ee309d Mon Sep 17 00:00:00 2001 From: Jim Garrison Date: Thu, 2 Nov 2023 16:47:39 -0400 Subject: [PATCH] Make unrealized `SingleQubitQPDGate` have definition of `None` rather than raise error (#442) * Make unrealized `SingleQubitQPDGate` has definition of `None` rather than error Fixes #417 according to https://github.com/Qiskit-Extensions/circuit-knitting-toolbox/issues/417#issuecomment-1783385101 * Add smoke test * Add release note * Tweak release note * Mention qpy in release note --- .../cutting/qpd/instructions/qpd_gate.py | 16 +++++----------- ...qpdgate-serialization-710ce2fc6ab898e0.yaml | 9 +++++++++ test/cutting/qpd/instructions/test_qpd_gate.py | 18 +++++++++++------- 3 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 releasenotes/notes/qpdgate-serialization-710ce2fc6ab898e0.yaml diff --git a/circuit_knitting/cutting/qpd/instructions/qpd_gate.py b/circuit_knitting/cutting/qpd/instructions/qpd_gate.py index 76571d0b4..840cd0874 100644 --- a/circuit_knitting/cutting/qpd/instructions/qpd_gate.py +++ b/circuit_knitting/cutting/qpd/instructions/qpd_gate.py @@ -14,14 +14,12 @@ from __future__ import annotations -from abc import ABC, abstractmethod - from qiskit.circuit import QuantumCircuit, Instruction, CircuitInstruction from ..qpd_basis import QPDBasis -class BaseQPDGate(Instruction, ABC): +class BaseQPDGate(Instruction): """Base class for a gate to be decomposed using quasiprobability decomposition.""" def __init__( @@ -101,11 +99,6 @@ def __eq__(self, other): and self.label == other.label ) - @abstractmethod - def _define(self) -> None: - """Generate a decomposed gate.""" - raise NotImplementedError # pragma: no cover - class TwoQubitQPDGate(BaseQPDGate): """Two qubit gate to be decomposed using quasiprobability decomposition.""" @@ -198,9 +191,10 @@ def _set_qubit_id(self, qubit_id: int) -> None: def _define(self) -> None: if self.basis_id is None: - raise ValueError( - "Missing 'basis_id': unable to realize SingleQubitQPDGate." - ) + # With basis_id is not set, it does not make sense to define this + # operation in terms of more fundamental instructions, so we have + # self.definition remain as None. + return qc = QuantumCircuit(1) base = self.basis.maps[self.basis_id] for op in base[self.qubit_id]: diff --git a/releasenotes/notes/qpdgate-serialization-710ce2fc6ab898e0.yaml b/releasenotes/notes/qpdgate-serialization-710ce2fc6ab898e0.yaml new file mode 100644 index 000000000..6fb1c45ac --- /dev/null +++ b/releasenotes/notes/qpdgate-serialization-710ce2fc6ab898e0.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + It is now possible to serialize :class:`.SingleQubitQPDGate`\ s + using :mod:`~qiskit.qpy`, + but some other issues with serialization and deserialization still + remain. See issue `#455 + `__ + for details. diff --git a/test/cutting/qpd/instructions/test_qpd_gate.py b/test/cutting/qpd/instructions/test_qpd_gate.py index 114d62477..65064ce03 100644 --- a/test/cutting/qpd/instructions/test_qpd_gate.py +++ b/test/cutting/qpd/instructions/test_qpd_gate.py @@ -13,9 +13,11 @@ import unittest import copy +import io import pytest -from qiskit.circuit.library.standard_gates import XGate, YGate, ZGate +from qiskit import QuantumCircuit, qpy +from qiskit.circuit.library.standard_gates import CXGate, XGate, YGate, ZGate from circuit_knitting.cutting.qpd import ( QPDBasis, @@ -92,12 +94,7 @@ def test_qubit_id_out_of_range(self): def test_missing_basis_id(self): maps = [([XGate()], [YGate()])] basis = QPDBasis(maps, [1.0]) - with pytest.raises(ValueError) as e_info: - SingleQubitQPDGate(basis=basis, qubit_id=0).definition - self.assertEqual( - "Missing 'basis_id': unable to realize SingleQubitQPDGate.", - e_info.value.args[0], - ) + assert SingleQubitQPDGate(basis=basis, qubit_id=0).definition is None def test_compare_1q_and_2q(self): maps = [([XGate()], [YGate()])] @@ -107,3 +104,10 @@ def test_compare_1q_and_2q(self): # Call both eq methods, since single qubit implements a slightly different equivalence self.assertFalse(inst_2q == inst_1q) self.assertFalse(inst_1q == inst_2q) + + def test_qpy_serialization(self): + qc = QuantumCircuit(2) + qc.append(TwoQubitQPDGate.from_instruction(CXGate()), [0, 1]) + + f = io.BytesIO() + qpy.dump(qc, f)