Skip to content
Closed
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
17 changes: 12 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,14 @@
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).
This gate is a quantum no-op and represents an identity channel on a single qubit. It will not
have a logical effect on the qubit state, and will likely be optimized away by the compiler at
all optimization levels (except zero, if ``id`` is specified in the basis of the target).
Certain hardware backends *may* choose to implement this instruction with a potentially non-zero
idle duration, for example a delay of length equal to that of a single-qubit gate.

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 +50,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 a delay of the
same duration as a non-virtual single-qubit gate (usually ``sx``).

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