Skip to content

Commit c6efb76

Browse files
mtreinishElePT
andauthored
Deprecate the condition attribute and related functionality (#13223)
* Deprecate the condition attribute and related functionality This commit deprecates the Instruction.condition and c_if() method for removal in 2.0. This functionality has been superseded by the more sophisiticated `IfElseOp` for some time now. Removing the condition property will simplify the Qiskit data model as it is implemented in a kind of ad-hoc manner that adds additional overhead to manually check it in many places. For the unittest modifications the deprecation warning for the .condtion getter is suppressed for the entire suite because this gets triggered internally by the transpiler and a lot of other places, including from rust code as until it is removed we need to use it to check that piece of the data model. Fixes #9556 * Add missing assertWarns * Handle deprecation warnings in visual tests too * Apply suggestions from code review Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Use private attribute in py->rust conversion * Avoid deprecation warning in non-deprecated code This commit fixes some places in the code where we were using the deprecated functionality where it needed a path to persist the behavior or where the deprecation warning became a performance bottleneck. The code is updated accordingly and to catch issues like this in the future the warning filters are adjusted to be more selective. * Add missing test updates * Add filter for aer's condition usage and dag drawer * Fix lint --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>
1 parent 4e6fd36 commit c6efb76

111 files changed

Lines changed: 2231 additions & 1127 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/circuit/src/circuit_instruction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython {
656656
ob.getattr(intern!(py, "label"))?.extract()?,
657657
duration,
658658
unit,
659-
ob.getattr(intern!(py, "condition"))?.extract()?,
659+
ob.getattr(intern!(py, "_condition"))?.extract()?,
660660
))
661661
};
662662

qiskit/circuit/barrier.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from __future__ import annotations
2020

2121
from qiskit.exceptions import QiskitError
22+
from qiskit.utils import deprecate_func
2223
from .instruction import Instruction
2324

2425

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

48+
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
4749
def c_if(self, classical, val):
4850
raise QiskitError("Barriers are compiler directives and cannot be conditional.")

qiskit/circuit/controlflow/builder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def _copy_mutable_properties(self, instruction: Instruction) -> Instruction:
284284
The same instruction instance that was passed, but mutated to propagate the tracked
285285
changes to this class.
286286
"""
287-
instruction.condition = self.condition
287+
instruction._condition = self._condition
288288
return instruction
289289

290290
# Provide some better error messages, just in case something goes wrong during development and
@@ -639,8 +639,8 @@ def update_registers(index, op):
639639
# a register is already present, so we use our own tracking.
640640
self.add_register(register)
641641
out.add_register(register)
642-
if getattr(op, "condition", None) is not None:
643-
for register in condition_resources(op.condition).cregs:
642+
if getattr(op, "_condition", None) is not None:
643+
for register in condition_resources(op._condition).cregs:
644644
if register not in self.registers:
645645
self.add_register(register)
646646
out.add_register(register)

qiskit/circuit/controlflow/if_else.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,20 @@ def __init__(
8787

8888
super().__init__("if_else", num_qubits, num_clbits, [true_body, false_body], label=label)
8989

90-
self.condition = validate_condition(condition)
90+
self._condition = validate_condition(condition)
9191

9292
@property
9393
def params(self):
9494
return self._params
9595

96+
@property
97+
def condition(self):
98+
return self._condition
99+
100+
@condition.setter
101+
def condition(self, value):
102+
self._condition = value
103+
96104
@params.setter
97105
def params(self, parameters):
98106
# pylint: disable=cyclic-import
@@ -152,7 +160,7 @@ def replace_blocks(self, blocks: Iterable[QuantumCircuit]) -> "IfElseOp":
152160
true_body, false_body = (
153161
ablock for ablock, _ in itertools.zip_longest(blocks, range(2), fillvalue=None)
154162
)
155-
return IfElseOp(self.condition, true_body, false_body=false_body, label=self.label)
163+
return IfElseOp(self._condition, true_body, false_body=false_body, label=self.label)
156164

157165
def c_if(self, classical, val):
158166
raise NotImplementedError(
@@ -200,7 +208,7 @@ def __init__(
200208
"if_else", len(self.__resources.qubits), len(self.__resources.clbits), [], label=label
201209
)
202210
# Set the condition after super().__init__() has initialized it to None.
203-
self.condition = validate_condition(condition)
211+
self._condition = validate_condition(condition)
204212

205213
def with_false_block(self, false_block: ControlFlowBuilderBlock) -> "IfElsePlaceholder":
206214
"""Return a new placeholder instruction, with the false block set to the given value,
@@ -225,7 +233,7 @@ def with_false_block(self, false_block: ControlFlowBuilderBlock) -> "IfElsePlace
225233
false_bits = false_block.qubits() | false_block.clbits()
226234
true_block.add_bits(false_bits - true_bits)
227235
false_block.add_bits(true_bits - false_bits)
228-
return type(self)(self.condition, true_block, false_block, label=self.label)
236+
return type(self)(self._condition, true_block, false_block, label=self.label)
229237

230238
def registers(self):
231239
"""Get the registers used by the interior blocks."""
@@ -288,7 +296,7 @@ def concrete_instruction(self, qubits, clbits):
288296
)
289297
return (
290298
self._copy_mutable_properties(
291-
IfElseOp(self.condition, true_body, false_body, label=self.label)
299+
IfElseOp(self._condition, true_body, false_body, label=self.label)
292300
),
293301
InstructionResources(
294302
qubits=tuple(true_body.qubits),

qiskit/circuit/controlflow/while_loop.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,20 @@ def __init__(
5353
num_clbits = body.num_clbits
5454

5555
super().__init__("while_loop", num_qubits, num_clbits, [body], label=label)
56-
self.condition = validate_condition(condition)
56+
self._condition = validate_condition(condition)
5757

5858
@property
5959
def params(self):
6060
return self._params
6161

62+
@property
63+
def condition(self):
64+
return self._condition
65+
66+
@condition.setter
67+
def condition(self, value):
68+
self._condition = value
69+
6270
@params.setter
6371
def params(self, parameters):
6472
# pylint: disable=cyclic-import
@@ -88,7 +96,7 @@ def blocks(self):
8896

8997
def replace_blocks(self, blocks):
9098
(body,) = blocks
91-
return WhileLoopOp(self.condition, body, label=self.label)
99+
return WhileLoopOp(self._condition, body, label=self.label)
92100

93101
def c_if(self, classical, val):
94102
raise NotImplementedError(

qiskit/circuit/delay.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from qiskit.circuit.gate import Gate
2020
from qiskit.circuit import _utils
2121
from qiskit.circuit.parameterexpression import ParameterExpression
22+
from qiskit.utils import deprecate_func
2223

2324

2425
@_utils.with_gate_array(np.eye(2, dtype=complex))
@@ -46,6 +47,7 @@ def inverse(self, annotated: bool = False):
4647
"""Special case. Return self."""
4748
return self
4849

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

qiskit/circuit/instruction.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def to_mutable(self):
176176
return self.copy()
177177

178178
@property
179+
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0", is_property=True)
179180
def condition(self):
180181
"""The classical condition on the instruction."""
181182
return self._condition
@@ -410,8 +411,8 @@ def _assemble(self):
410411
# Add condition parameters for assembler. This is needed to convert
411412
# to a qobj conditional instruction at assemble time and after
412413
# conversion will be deleted by the assembler.
413-
if self.condition:
414-
instruction._condition = self.condition
414+
if self._condition:
415+
instruction._condition = self._condition
415416
return instruction
416417

417418
@property
@@ -517,6 +518,7 @@ def inverse(self, annotated: bool = False):
517518
inverse_gate.definition = inverse_definition
518519
return inverse_gate
519520

521+
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
520522
def c_if(self, classical, val):
521523
"""Set a classical equality condition on this instruction between the register or cbit
522524
``classical`` and value ``val``.
@@ -632,26 +634,27 @@ def repeat(self, n):
632634
qargs = tuple(qc.qubits)
633635
cargs = tuple(qc.clbits)
634636
base = self.copy()
635-
if self.condition:
637+
if self._condition:
636638
# Condition is handled on the outer instruction.
637639
base = base.to_mutable()
638640
base.condition = None
639641
for _ in [None] * n:
640642
qc._append(CircuitInstruction(base, qargs, cargs))
641643

642644
instruction.definition = qc
643-
if self.condition:
644-
instruction = instruction.c_if(*self.condition)
645+
if self._condition:
646+
instruction = instruction.c_if(*self._condition)
645647
return instruction
646648

647649
@property
650+
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0", is_property=True)
648651
def condition_bits(self) -> List[Clbit]:
649652
"""Get Clbits in condition."""
650653
from qiskit.circuit.controlflow import condition_resources # pylint: disable=cyclic-import
651654

652-
if self.condition is None:
655+
if self._condition is None:
653656
return []
654-
return list(condition_resources(self.condition).clbits)
657+
return list(condition_resources(self._condition).clbits)
655658

656659
@property
657660
def name(self):

qiskit/circuit/instructionset.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from typing import Callable
2121

2222
from qiskit.circuit.exceptions import CircuitError
23+
from qiskit.utils import deprecate_func
2324
from .classicalregister import Clbit, ClassicalRegister
2425
from .operation import Operation
2526
from .quantumcircuitdata import CircuitInstruction
@@ -105,6 +106,7 @@ def inverse(self, annotated: bool = False):
105106
)
106107
return self
107108

109+
@deprecate_func(since="1.3.0", removal_timeline="in 2.0.0")
108110
def c_if(self, classical: Clbit | ClassicalRegister | int, val: int) -> "InstructionSet":
109111
"""Set a classical equality condition on all the instructions in this set between the
110112
:obj:`.ClassicalRegister` or :obj:`.Clbit` ``classical`` and value ``val``.

qiskit/circuit/quantumcircuit.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,14 +2102,14 @@ def map_vars(op):
21022102
is_control_flow = isinstance(n_op, ControlFlowOp)
21032103
if (
21042104
not is_control_flow
2105-
and (condition := getattr(n_op, "condition", None)) is not None
2105+
and (condition := getattr(n_op, "_condition", None)) is not None
21062106
):
21072107
n_op = n_op.copy() if n_op is op and copy else n_op
21082108
n_op.condition = variable_mapper.map_condition(condition)
21092109
elif is_control_flow:
21102110
n_op = n_op.replace_blocks(recurse_block(block) for block in n_op.blocks)
21112111
if isinstance(n_op, (IfElseOp, WhileLoopOp)):
2112-
n_op.condition = variable_mapper.map_condition(n_op.condition)
2112+
n_op.condition = variable_mapper.map_condition(n_op._condition)
21132113
elif isinstance(n_op, SwitchCaseOp):
21142114
n_op.target = variable_mapper.map_target(n_op.target)
21152115
elif isinstance(n_op, Store):
@@ -3520,7 +3520,7 @@ def update_from_expr(objects, node):
35203520

35213521
for instruction in self._data:
35223522
objects = set(itertools.chain(instruction.qubits, instruction.clbits))
3523-
if (condition := getattr(instruction.operation, "condition", None)) is not None:
3523+
if (condition := getattr(instruction.operation, "_condition", None)) is not None:
35243524
objects.update(_builder_utils.condition_resources(condition).clbits)
35253525
if isinstance(condition, expr.Expr):
35263526
update_from_expr(objects, condition)
@@ -3623,7 +3623,7 @@ def num_connected_components(self, unitary_only: bool = False) -> int:
36233623
else:
36243624
args = instruction.qubits + instruction.clbits
36253625
num_qargs = len(args) + (
3626-
1 if getattr(instruction.operation, "condition", None) else 0
3626+
1 if getattr(instruction.operation, "_condition", None) else 0
36273627
)
36283628

36293629
if num_qargs >= 2 and not getattr(instruction.operation, "_directive", False):

qiskit/circuit/singleton.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ class XGate(Gate, metaclass=_SingletonMeta, overrides=_SingletonGateOverrides):
251251

252252
import functools
253253

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

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

0 commit comments

Comments
 (0)