Skip to content

Commit

Permalink
Make unrealized SingleQubitQPDGate have definition of None rather…
Browse files Browse the repository at this point in the history
… than raise error (#442)

* Make unrealized `SingleQubitQPDGate` has definition of `None` rather than error

Fixes #417 according to #417 (comment)

* Add smoke test

* Add release note

* Tweak release note

* Mention qpy in release note
  • Loading branch information
garrison authored Nov 2, 2023
1 parent 3318fcf commit 2410efd
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 18 deletions.
16 changes: 5 additions & 11 deletions circuit_knitting/cutting/qpd/instructions/qpd_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__(
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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]:
Expand Down
Original file line number Diff line number Diff line change
@@ -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
<https://github.com/Qiskit-Extensions/circuit-knitting-toolbox/issues/445>`__
for details.
18 changes: 11 additions & 7 deletions test/cutting/qpd/instructions/test_qpd_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()])]
Expand All @@ -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)

0 comments on commit 2410efd

Please sign in to comment.