/
control_flow.py
74 lines (56 loc) · 2.56 KB
/
control_flow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
#
# 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.
"Container to encapsulate all control flow operations."
from __future__ import annotations
import typing
from abc import ABC, abstractmethod
from qiskit.circuit.instruction import Instruction
from qiskit.circuit.exceptions import CircuitError
if typing.TYPE_CHECKING:
from qiskit.circuit import QuantumCircuit
class ControlFlowOp(Instruction, ABC):
"""Abstract class to encapsulate all control flow operations.
All subclasses of :class:`ControlFlowOp` have an internal attribute,
:attr:`~ControlFlowOp.blocks`, which exposes the inner subcircuits used in the different blocks
of the control flow.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for block in self.blocks:
if block.num_input_vars:
raise CircuitError("control-flow blocks cannot contain input variables")
@property
@abstractmethod
def blocks(self) -> tuple[QuantumCircuit, ...]:
"""Tuple of :class:`.QuantumCircuit`\\ s which may be executed as part of the
execution of this :class:`ControlFlowOp`."""
@abstractmethod
def replace_blocks(self, blocks: typing.Iterable[QuantumCircuit]) -> ControlFlowOp:
"""Return a new version of this control-flow operations with the :attr:`blocks` mapped to
the given new ones.
Typically this is used in a workflow such as::
existing_op = ...
def map_block(block: QuantumCircuit) -> QuantumCircuit:
new_block = block.copy_empty_like()
# ... do something to `new_block` ...
return new_block
new_op = existing_op.replace_blocks(
map_block(block) for block in existing_op.blocks
)
It is the caller's responsibility to ensure that the mapped blocks are defined over a
unified set of circuit resources, much like constructing a :class:`ControlFlowOp` using its
default constructor.
Args:
blocks: the new subcircuit blocks to use.
Returns:
New :class:`ControlFlowOp` with replaced blocks.
"""