qiskit/releasenotes/notes/0.22/fix-target-control-flow-rep...

110 lines
5.7 KiB
YAML

---
features:
- |
Add support for representing an operation that has a variable width
to the :class:`~.Target` class. Previously, a :class:`~.Target` object
needed to have an instance of :class:`~Operation` defined for each
operation supported in the target. This was used for both validation
of arguments and parameters of the operation. However, for operations
that have a variable width this wasn't possible because each instance
of an :class:`~Operation` class can only have a fixed number of qubits.
For cases where a backend supports variable width operations the
instruction can be added with the class of the operation instead of an
instance. In such cases the operation will be treated as globally
supported on all qubits. For example, if building a target like::
from qiskit.circuit import Parameter, Measure, IfElseOp, ForLoopOp, WhileLoopOp
from qiskit.circuit.library import IGate, RZGate, SXGate, XGate, CXGate
from qiskit.transpiler import Target, InstructionProperties
theta = Parameter("theta")
ibm_target = Target()
i_props = {
(0,): InstructionProperties(duration=35.5e-9, error=0.000413),
(1,): InstructionProperties(duration=35.5e-9, error=0.000502),
(2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
(3,): InstructionProperties(duration=35.5e-9, error=0.000614),
(4,): InstructionProperties(duration=35.5e-9, error=0.006149),
}
ibm_target.add_instruction(IGate(), i_props)
rz_props = {
(0,): InstructionProperties(duration=0, error=0),
(1,): InstructionProperties(duration=0, error=0),
(2,): InstructionProperties(duration=0, error=0),
(3,): InstructionProperties(duration=0, error=0),
(4,): InstructionProperties(duration=0, error=0),
}
ibm_target.add_instruction(RZGate(theta), rz_props)
sx_props = {
(0,): InstructionProperties(duration=35.5e-9, error=0.000413),
(1,): InstructionProperties(duration=35.5e-9, error=0.000502),
(2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
(3,): InstructionProperties(duration=35.5e-9, error=0.000614),
(4,): InstructionProperties(duration=35.5e-9, error=0.006149),
}
ibm_target.add_instruction(SXGate(), sx_props)
x_props = {
(0,): InstructionProperties(duration=35.5e-9, error=0.000413),
(1,): InstructionProperties(duration=35.5e-9, error=0.000502),
(2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
(3,): InstructionProperties(duration=35.5e-9, error=0.000614),
(4,): InstructionProperties(duration=35.5e-9, error=0.006149),
}
ibm_target.add_instruction(XGate(), x_props)
cx_props = {
(3, 4): InstructionProperties(duration=270.22e-9, error=0.00713),
(4, 3): InstructionProperties(duration=305.77e-9, error=0.00713),
(3, 1): InstructionProperties(duration=462.22e-9, error=0.00929),
(1, 3): InstructionProperties(duration=497.77e-9, error=0.00929),
(1, 2): InstructionProperties(duration=227.55e-9, error=0.00659),
(2, 1): InstructionProperties(duration=263.11e-9, error=0.00659),
(0, 1): InstructionProperties(duration=519.11e-9, error=0.01201),
(1, 0): InstructionProperties(duration=554.66e-9, error=0.01201),
}
ibm_target.add_instruction(CXGate(), cx_props)
measure_props = {
(0,): InstructionProperties(duration=5.813e-6, error=0.0751),
(1,): InstructionProperties(duration=5.813e-6, error=0.0225),
(2,): InstructionProperties(duration=5.813e-6, error=0.0146),
(3,): InstructionProperties(duration=5.813e-6, error=0.0215),
(4,): InstructionProperties(duration=5.813e-6, error=0.0333),
}
ibm_target.add_instruction(Measure(), measure_props)
ibm_target.add_instruction(IfElseOp, name="if_else")
ibm_target.add_instruction(ForLoopOp, name="for_loop")
ibm_target.add_instruction(WhileLoopOp, name="while_loop")
The :class:`~.IfElseOp`, :class:`~.ForLoopOp`, and :class:`~.WhileLoopOp`
operations are globally supported for any number of qubits. This is then
reflected by other calls in the :class:`~.Target` API such as
:meth:`~.Target.instruction_supported`::
ibm_target.instruction_supported(operation_class=WhileLoopOp, qargs=(0, 2, 3, 4))
ibm_target.instruction_supported('if_else', qargs=(0, 1))
both return ``True``.
upgrade:
- |
For :class:`~.Target` objects that only contain globally defined 2 qubit
operations without any connectivity constaints the return from the
:meth:`.Target.build_coupling_map` method will now return ``None`` instead
of a :class:`~.CouplingMap` object that contains ``num_qubits`` nodes
and no edges. This change was made to better reflect the actual
connectivity constraints of the :class:`~.Target` because in this case
there are no connectivity constraints on the backend being modeled by
the :class:`~.Target`, not a lack of connectivity. If you desire the
previous behavior for any reason you can reproduce it by checking for a
``None`` return and manually building a coupling map, for example::
from qiskit.transpiler import Target, CouplingMap
from qiskit.circuit.library import CXGate
target = Target(num_qubits=3)
target.add_instruction(CXGate())
cmap = target.build_coupling_map()
if cmap is None:
cmap = CouplingMap()
for i in range(target.num_qubits):
cmap.add_physical_qubit(i)