Skip to content
Merged
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
2 changes: 2 additions & 0 deletions qiskit/circuit/barrier.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from __future__ import annotations

from qiskit.exceptions import QiskitError
from qiskit.utils import deprecate_func
from .instruction import Instruction


Expand All @@ -44,5 +45,6 @@ def inverse(self, annotated: bool = False):
"""Special case. Return self."""
return Barrier(self.num_qubits)

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical, val):
raise QiskitError("Barriers are compiler directives and cannot be conditional.")
2 changes: 2 additions & 0 deletions qiskit/circuit/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from qiskit.circuit.gate import Gate
from qiskit.circuit import _utils
from qiskit.circuit.parameterexpression import ParameterExpression
from qiskit.utils import deprecate_func


@_utils.with_gate_array(np.eye(2, dtype=complex))
Expand All @@ -42,6 +43,7 @@ def inverse(self, annotated: bool = False):
"""Special case. Return self."""
return self

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical, val):
raise CircuitError("Conditional Delay is not yet implemented.")

Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def to_mutable(self):
return self.copy()

@property
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0", is_property=True)
def condition(self):
"""The classical condition on the instruction."""
return self._condition
Expand Down Expand Up @@ -499,6 +500,7 @@ def inverse(self, annotated: bool = False):
inverse_gate.definition = inverse_definition
return inverse_gate

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical, val):
"""Set a classical equality condition on this instruction between the register or cbit
``classical`` and value ``val``.
Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/instructionset.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from typing import Callable

from qiskit.circuit.exceptions import CircuitError
from qiskit.utils import deprecate_func
from .classicalregister import Clbit, ClassicalRegister
from .operation import Operation
from .quantumcircuitdata import CircuitInstruction
Expand Down Expand Up @@ -105,6 +106,7 @@ def inverse(self, annotated: bool = False):
)
return self

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical: Clbit | ClassicalRegister | int, val: int) -> "InstructionSet":
"""Set a classical equality condition on all the instructions in this set between the
:obj:`.ClassicalRegister` or :obj:`.Clbit` ``classical`` and value ``val``.
Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/singleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class XGate(Gate, metaclass=_SingletonMeta, overrides=_SingletonGateOverrides):

import functools

from qiskit.utils import deprecate_func
from .instruction import Instruction
from .gate import Gate
from .controlledgate import ControlledGate, _ctrl_state_to_int
Expand Down Expand Up @@ -489,6 +490,7 @@ class they are providing overrides for has more lazy attributes or user-exposed
instruction._params = _frozenlist(instruction._params)
return instruction

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical, val):
return self.to_mutable().c_if(classical, val)

Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import typing

from qiskit.utils import deprecate_func
from .exceptions import CircuitError
from .classical import expr, types
from .instruction import Instruction
Expand Down Expand Up @@ -88,6 +89,7 @@ def rvalue(self):
"""Get the r-value :class:`~.expr.Expr` node that is being written into the l-value."""
return self.params[1]

@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
def c_if(self, classical, val):
""":meta hidden:"""
raise NotImplementedError(
Expand Down
17 changes: 16 additions & 1 deletion qiskit/qasm2/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# that they have been altered from the originals.

"""Python-space bytecode interpreter for the output of the main Rust parser logic."""

import warnings
import dataclasses
import math
from typing import Iterable, Callable
Expand Down Expand Up @@ -255,19 +255,34 @@ def from_bytecode(bytecode, custom_instructions: Iterable[CustomInstruction]):
CircuitInstruction(gates[gate_id](*parameters), [qubits[q] for q in op_qubits])
)
elif opcode == OpCode.ConditionedGate:
warnings.warn(
"Conditioned gates in qasm2 will be loaded as an IfElseOp starting in Qiskit 2.0",
FutureWarning,
stacklevel=3,
)
gate_id, parameters, op_qubits, creg, value = op.operands
gate = gates[gate_id](*parameters).c_if(qc.cregs[creg], value)
qc._append(CircuitInstruction(gate, [qubits[q] for q in op_qubits]))
elif opcode == OpCode.Measure:
qubit, clbit = op.operands
qc._append(CircuitInstruction(Measure(), (qubits[qubit],), (clbits[clbit],)))
elif opcode == OpCode.ConditionedMeasure:
warnings.warn(
"Conditioned measurements in qasm2 will be loaded as an IfElseOp starting in Qiskit 2.0",
FutureWarning,
stacklevel=3,
)
qubit, clbit, creg, value = op.operands
measure = Measure().c_if(qc.cregs[creg], value)
qc._append(CircuitInstruction(measure, (qubits[qubit],), (clbits[clbit],)))
elif opcode == OpCode.Reset:
qc._append(CircuitInstruction(Reset(), (qubits[op.operands[0]],)))
elif opcode == OpCode.ConditionedReset:
warnings.warn(
"Conditioned resets in qasm2 will be loaded as an IfElseOp starting in Qiskit 2.0",
FutureWarning,
stacklevel=3,
)
qubit, creg, value = op.operands
reset = Reset().c_if(qc.cregs[creg], value)
qc._append(CircuitInstruction(reset, (qubits[qubit],)))
Expand Down
13 changes: 13 additions & 0 deletions qiskit/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ def _read_instruction(
use_symengine,
standalone_vars,
)
if condition is not None:
warnings.warn(
f"The .condition attribute on {gate_name} will be loaded as an IfElseOp "
"starting in Qiskit 2.0",
FutureWarning,
stacklevel=3,
)
inst_obj.condition = condition
if instruction.label_size > 0:
inst_obj.label = label
Expand Down Expand Up @@ -414,6 +421,12 @@ def _read_instruction(
gate = gate_class(*params)
if condition:
if not isinstance(gate, ControlFlowOp):
warnings.warn(
f"The .condition attribute on {gate} will be loaded as an "
"IfElseOp starting in Qiskit 2.0",
FutureWarning,
stacklevel=3,
)
gate = gate.c_if(*condition)
else:
gate.condition = condition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
)
from qiskit.dagcircuit import DAGCircuit
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.utils import deprecate_func


class ConvertConditionsToIfOps(TransformationPass):
Expand All @@ -31,6 +32,10 @@ class ConvertConditionsToIfOps(TransformationPass):
This is a simple pass aimed at easing the conversion from the old style of using
:meth:`.InstructionSet.c_if` into the new style of using more complex conditional logic."""

@deprecate_func(since="1.3.0", removal_timeline="in Qiskit 2.0.0")
def __init__(self):
super().__init__()

def _run_inner(self, dag):
"""Run the pass on one :class:`.DAGCircuit`, mutating it. Returns ``True`` if the circuit
was modified and ``False`` if not."""
Expand Down
38 changes: 38 additions & 0 deletions releasenotes/notes/deprecate-condition_c_if-9548e5522814fe9c.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
deprecations_circuits:
- |
Deprecated the :attr:`.Instruction.condition` attribute and the
:meth:`.Instruction.c_if` method. They will be removed
in Qiskit 2.0, along with any uses in the Qiskit data
model. This functionality has been superseded by the :class:`.IfElseOp` class
which can be used to describe a classical condition in a circuit. For
example, a circuit using :meth:`.Instruction.c_if` like::

from qiskit.circuit import QuantumCircuit

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.x(0).c_if(0, 1)
qc.z(1.c_if(1, 0)
qc.measure(0, 0)
qc.measure(1, 1)

can be rewritten as::

qc = QuantumCircuit(2, 2)
qc.h(0)
with expected.if_test((expected.clbits[0], True)):
qc.x(0)
with expected.if_test((expected.clbits[1], False)):
qc.z(1)
qc.measure(0, 0)
qc.measure(1, 1)
Comment on lines +13 to +29
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I just started addressing this deprecation warning and noticed some issues here. I think it should be qc.z(1) (missing parenthesis). Also, I think expected should be qc?


The now deprecated :class:`.ConvertConditionsToIfOps` transpiler pass can
be used to automate this conversion for existing circuits.
deprecations_transpiler:
- |
The transpiler pass :class:`.ConvertConditionsToIfOps` has been deprecated
and will be removed in Qiskit 2.0.0. This class is now deprecated because
the underlying data model for :attr:`.Instruction.condition` which this
pass is converting from has been deprecated and will be removed in 2.0.0.
12 changes: 8 additions & 4 deletions test/python/circuit/classical/test_expr_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def test_lift_legacy_condition(self):
clbit = Clbit()

inst = Instruction("custom", 1, 0, [])
inst.c_if(cr, 7)
with self.assertWarns(DeprecationWarning):
inst.c_if(cr, 7)
self.assertEqual(
expr.lift_legacy_condition(inst.condition),
expr.Binary(
Expand All @@ -38,7 +39,8 @@ def test_lift_legacy_condition(self):
)

inst = Instruction("custom", 1, 0, [])
inst.c_if(cr, 255)
with self.assertWarns(DeprecationWarning):
inst.c_if(cr, 255)
self.assertEqual(
expr.lift_legacy_condition(inst.condition),
expr.Binary(
Expand All @@ -50,7 +52,8 @@ def test_lift_legacy_condition(self):
)

inst = Instruction("custom", 1, 0, [])
inst.c_if(clbit, False)
with self.assertWarns(DeprecationWarning):
inst.c_if(clbit, False)
self.assertEqual(
expr.lift_legacy_condition(inst.condition),
expr.Unary(
Expand All @@ -61,7 +64,8 @@ def test_lift_legacy_condition(self):
)

inst = Instruction("custom", 1, 0, [])
inst.c_if(clbit, True)
with self.assertWarns(DeprecationWarning):
inst.c_if(clbit, True)
self.assertEqual(
expr.lift_legacy_condition(inst.condition),
expr.Var(clbit, types.Bool()),
Expand Down
3 changes: 2 additions & 1 deletion test/python/circuit/library/test_permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ def test_reverse_ops(self):
def test_conditional(self):
"""Test adding conditional permutations."""
qc = QuantumCircuit(5, 1)
qc.append(PermutationGate([1, 2, 0]), [2, 3, 4]).c_if(0, 1)
with self.assertWarns(DeprecationWarning):
qc.append(PermutationGate([1, 2, 0]), [2, 3, 4]).c_if(0, 1)
self.assertIsNotNone(qc.data[0].operation.condition)

def test_qasm(self):
Expand Down
3 changes: 2 additions & 1 deletion test/python/circuit/library/test_qft.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ def test_reverse_ops(self):
def test_conditional(self):
"""Test adding conditional to a QFTGate."""
qc = QuantumCircuit(5, 1)
qc.append(QFTGate(4), [1, 2, 0, 4]).c_if(0, 1)
with self.assertWarns(DeprecationWarning):
qc.append(QFTGate(4), [1, 2, 0, 4]).c_if(0, 1)
self.assertIsNotNone(qc.data[0].operation.condition)

def test_qasm(self):
Expand Down
40 changes: 26 additions & 14 deletions test/python/circuit/test_circuit_load_from_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,13 @@ def test_qpy_full_path(self):
def test_circuit_with_conditional(self):
"""Test that instructions with conditions are correctly serialized."""
qc = QuantumCircuit(1, 1)
qc.x(0).c_if(qc.cregs[0], 1)
with self.assertWarns(DeprecationWarning):
qc.x(0).c_if(qc.cregs[0], 1)
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circ = load(qpy_file)[0]
with self.assertWarns(DeprecationWarning):
new_circ = load(qpy_file)[0]
self.assertEqual(qc, new_circ)
self.assertDeprecatedBitProperties(qc, new_circ)

Expand Down Expand Up @@ -408,13 +410,15 @@ def test_multiple_circuits(self):
"""Test multiple circuits can be serialized together."""
circuits = []
for i in range(10):
circuits.append(
random_circuit(10, 10, measure=True, conditional=True, reset=True, seed=42 + i)
)
with self.assertWarns(DeprecationWarning):
circuits.append(
random_circuit(10, 10, measure=True, conditional=True, reset=True, seed=42 + i)
)
qpy_file = io.BytesIO()
dump(circuits, qpy_file)
qpy_file.seek(0)
new_circs = load(qpy_file)
with self.assertWarns(DeprecationWarning):
new_circs = load(qpy_file)
self.assertEqual(circuits, new_circs)
for old, new in zip(circuits, new_circs):
self.assertDeprecatedBitProperties(old, new)
Expand Down Expand Up @@ -674,12 +678,14 @@ def test_circuit_with_conditional_with_label(self):
"""Test that instructions with conditions are correctly serialized."""
qc = QuantumCircuit(1, 1)
gate = XGate(label="My conditional x gate")
gate.c_if(qc.cregs[0], 1)
with self.assertWarns(DeprecationWarning):
gate.c_if(qc.cregs[0], 1)
qc.append(gate, [0])
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circ = load(qpy_file)[0]
with self.assertWarns(DeprecationWarning):
new_circ = load(qpy_file)[0]
self.assertEqual(qc, new_circ)
self.assertEqual(
[x.operation.label for x in qc.data], [x.operation.label for x in new_circ.data]
Expand Down Expand Up @@ -755,12 +761,14 @@ def test_single_bit_teleportation(self):
qc = QuantumCircuit(qr, cr, name="Reset Test")
qc.x(0)
qc.measure(0, cr[0])
qc.x(0).c_if(cr[0], 1)
with self.assertWarns(DeprecationWarning):
qc.x(0).c_if(cr[0], 1)
qc.measure(0, cr[1])
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circ = load(qpy_file)[0]
with self.assertWarns(DeprecationWarning):
new_circ = load(qpy_file)[0]
self.assertEqual(qc, new_circ)
self.assertEqual(
[x.operation.label for x in qc.data], [x.operation.label for x in new_circ.data]
Expand Down Expand Up @@ -1138,11 +1146,13 @@ def test_qpy_with_for_loop(self):
qc.h(0)
qc.cx(0, 1)
qc.measure(0, 0)
qc.break_loop().c_if(0, True)
with self.assertWarns(DeprecationWarning):
qc.break_loop().c_if(0, True)
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circuit = load(qpy_file)[0]
with self.assertWarns(DeprecationWarning):
new_circuit = load(qpy_file)[0]
self.assertEqual(qc, new_circuit)
self.assertDeprecatedBitProperties(qc, new_circuit)

Expand All @@ -1154,11 +1164,13 @@ def test_qpy_with_for_loop_iterator(self):
qc.h(0)
qc.cx(0, 1)
qc.measure(0, 0)
qc.break_loop().c_if(0, True)
with self.assertWarns(DeprecationWarning):
qc.break_loop().c_if(0, True)
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circuit = load(qpy_file)[0]
with self.assertWarns(DeprecationWarning):
new_circuit = load(qpy_file)[0]
self.assertEqual(qc, new_circuit)
self.assertDeprecatedBitProperties(qc, new_circuit)

Expand Down
Loading