Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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
15 changes: 10 additions & 5 deletions qiskit/circuit/library/standard_gates/i.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
class IGate(Gate):
r"""Identity gate.

Identity gate corresponds to a single-qubit gate wait cycle,
and should not be optimized or unrolled (it is an opaque gate).
Logically this gate is a quantum no-op and the transpiler will largely treat it as such, but
some older hardware may choose to interpret it as a short-hand for the shortest-possible delay

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
some older hardware may choose to interpret it as a short-hand for the shortest-possible delay
some backends may choose to interpret it as a short-hand for the shortest-possible delay

cycle.
Comment thread
jakelishman marked this conversation as resolved.
Outdated

Can be applied to a :class:`~qiskit.circuit.QuantumCircuit`
with the :meth:`~qiskit.circuit.QuantumCircuit.i` and
:meth:`~qiskit.circuit.QuantumCircuit.id` methods.
Can be applied to a :class:`~qiskit.circuit.QuantumCircuit` with the
:meth:`~qiskit.circuit.QuantumCircuit.i` and :meth:`~qiskit.circuit.QuantumCircuit.id` methods.

**Matrix Representation:**

Expand All @@ -48,6 +48,11 @@ def __init__(self, label: Optional[str] = None):
"""Create new Identity gate."""
super().__init__("id", 1, [], label=label)

def _define(self) -> None:
Comment thread
jakelishman marked this conversation as resolved.
from qiskit.circuit import QuantumCircuit # pylint: disable=cyclic-import

self.definition = QuantumCircuit(1, name=self.name)
Comment thread
kdk marked this conversation as resolved.

def inverse(self):
"""Invert this gate."""
return IGate() # self-inverse
Expand Down
24 changes: 24 additions & 0 deletions releasenotes/notes/fix-igate-definition-7385cff02e663867.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fixes:
- |
Fixed a bug where certain operations, such as
:meth:`.QuantumCircuit.control`, would crash if an identity operation
represented by an :class:`.IGate` was present in a :class:`.QuantumCircuit`.
For example, the following code was previously an error, but will now function
correctly::

from qiskit import QuantumCircuit

qc = QuantumCircuit(1)
qc.i(0)
controlled = qc.control()
Comment thread
jakelishman marked this conversation as resolved.
upgrade:
- |
Qiskit Terra will now generally treat the identity gate :class:`.IGate` (with corresponding
circuit method :meth:`.QuantumCircuit.i`) as a quantum no-op, and more aggressively remove it
during calls to :func:`.transpile`. This is a change to previous behaviour that supported
legacy IBM Quantum systems where the ``id`` instruction was a short-hand for the shortest
possible delay cycle.
Comment thread
jakelishman marked this conversation as resolved.
Outdated

This changes removes a lot of surprises when working with :class:`.IGate` at a high-level;
various circuit and synthesis operations would previously be unable to handle the gate because
it appeared as a "magic" opaque instruction.
21 changes: 21 additions & 0 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,27 @@ def test_control_implementation(self):

self.assertEqual(ref, c_qc)

def test_control_primitive_gates(self):
"""Test that circuits containing primitive gates (with no definition) can be controlled
during `QuantumCircuit.control`.

Regression test of gh-7399."""
qc = QuantumCircuit(2)
qc.u(0.2, 0.3, 0.4, 0)
qc.i(1)
controlled = qc.control()

# The identity gate should have no effect.
expected = QuantumCircuit(
QuantumRegister(1, name="control"), QuantumRegister(2, name="target")
)
expected.cu(0.2, 0.3, 0.4, 0, 0, 1)

self.assertIsInstance(controlled, QuantumCircuit)
self.assertEqual(len(controlled.data), 1)
instruction, _, _ = controlled.data[0]
self.assertEqual(instruction.definition, expected)

@data("gate", "instruction")
def test_repeat_appended_type(self, subtype):
"""Test repeat appends Gate if circuit contains only gates and Instructions otherwise."""
Expand Down