Source code for qiskit.transpiler.passes.utils.convert_conditions_to_if_ops
# This code is part of Qiskit.
#
# (C) Copyright IBM 2022.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Replace conditional instructions with equivalent :class:`.IfElseOp` objects."""
from qiskit.converters import dag_to_circuit, circuit_to_dag
from qiskit.circuit import (
CircuitInstruction,
ClassicalRegister,
Clbit,
ControlFlowOp,
IfElseOp,
QuantumCircuit,
)
from qiskit.dagcircuit import DAGCircuit
from qiskit.transpiler import TransformationPass
[docs]class ConvertConditionsToIfOps(TransformationPass):
"""Convert instructions whose ``condition`` attribute is set to a non-``None`` value into the
equivalent single-statement :class:`.IfElseBlock`.
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."""
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."""
modified = False
for node in dag.op_nodes():
if isinstance(node.op, ControlFlowOp):
modified_blocks = False
new_dags = []
for block in node.op.blocks:
new_dag = circuit_to_dag(block)
modified_blocks |= self._run_inner(new_dag)
new_dags.append(new_dag)
if not modified_blocks:
continue
dag.substitute_node(
node,
node.op.replace_blocks(dag_to_circuit(block) for block in new_dags),
inplace=True,
)
elif getattr(node.op, "condition", None) is None:
continue
else:
target, value = node.op.condition
clbits = list(node.cargs)
condition_clbits = [target] if isinstance(target, Clbit) else list(target)
clbits_set = set(clbits)
clbits += [bit for bit in condition_clbits if bit not in clbits_set]
block_body = QuantumCircuit(list(node.qargs) + clbits)
if isinstance(target, ClassicalRegister):
block_body.add_register(target)
new_op = node.op.copy()
new_op.condition = None
block_body._append(CircuitInstruction(new_op, node.qargs, node.cargs))
# Despite only being a node-for-node replacement, control-flow ops contain the
# condition bits in their cargs, which requires slightly different handling in the
# DAGCircuit methods right now.
replacement = DAGCircuit()
replacement.add_qubits(block_body.qubits)
replacement.add_clbits(block_body.clbits)
if isinstance(target, ClassicalRegister):
replacement.add_creg(target)
replacement.apply_operation_back(
IfElseOp((target, value), block_body),
block_body.qubits,
block_body.clbits,
check=False,
)
wire_map = {bit: bit for bit in block_body.qubits + block_body.clbits}
dag.substitute_node_with_dag(node, replacement, wire_map, propagate_condition=False)
modified = True
return modified
[docs] def run(self, dag):
self._run_inner(dag)
return dag