qiskit 1.2.0rc1__cp38-abi3-macosx_10_9_universal2.whl → 1.2.2__cp38-abi3-macosx_10_9_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +15 -2
- qiskit/circuit/library/basis_change/qft.py +3 -1
- qiskit/circuit/library/data_preparation/initializer.py +5 -2
- qiskit/circuit/library/data_preparation/state_preparation.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +1 -0
- qiskit/circuit/library/standard_gates/__init__.py +32 -25
- qiskit/circuit/quantumcircuit.py +43 -18
- qiskit/compiler/transpiler.py +1 -1
- qiskit/dagcircuit/dagcircuit.py +1 -1
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +9 -1
- qiskit/providers/basic_provider/basic_simulator.py +1 -1
- qiskit/providers/fake_provider/fake_openpulse_2q.py +3 -3
- qiskit/providers/fake_provider/fake_openpulse_3q.py +2 -3
- qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
- qiskit/providers/fake_provider/fake_qasm_backend.py +2 -1
- qiskit/providers/fake_provider/generic_backend_v2.py +434 -18
- qiskit/providers/models/__init__.py +47 -21
- qiskit/pulse/builder.py +16 -7
- qiskit/pulse/instructions/directives.py +5 -0
- qiskit/pulse/library/symbolic_pulses.py +4 -3
- qiskit/pulse/schedule.py +5 -9
- qiskit/pulse/transforms/alignments.py +3 -1
- qiskit/pulse/transforms/dag.py +7 -0
- qiskit/qasm2/parse.py +29 -0
- qiskit/qasm3/exporter.py +20 -7
- qiskit/qpy/__init__.py +1 -1
- qiskit/quantum_info/operators/operator.py +24 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -0
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +6 -1
- qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -1
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +1 -1
- qiskit/synthesis/linear/cnot_synth.py +1 -1
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +2 -1
- qiskit/synthesis/permutation/permutation_full.py +2 -2
- qiskit/synthesis/permutation/permutation_lnn.py +3 -1
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +2 -2
- qiskit/transpiler/__init__.py +6 -1
- qiskit/transpiler/instruction_durations.py +4 -0
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +2 -1
- qiskit/transpiler/passes/calibration/rx_builder.py +1 -1
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +7 -1
- qiskit/transpiler/passes/optimization/elide_permutations.py +2 -2
- qiskit/transpiler/passes/optimization/hoare_opt.py +12 -8
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +16 -20
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +9 -3
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +3 -0
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +16 -6
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +1 -1
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +12 -55
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +9 -0
- qiskit/utils/optionals.py +173 -150
- qiskit/visualization/bloch.py +44 -1
- qiskit/visualization/dag_visualization.py +10 -3
- qiskit/visualization/gate_map.py +28 -6
- qiskit/visualization/pass_manager_visualization.py +3 -14
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/METADATA +20 -20
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/RECORD +67 -67
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/WHEEL +1 -1
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/entry_points.txt +0 -0
- {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/top_level.txt +0 -0
qiskit/pulse/schedule.py
CHANGED
@@ -81,6 +81,7 @@ class Schedule:
|
|
81
81
|
|
82
82
|
.. code-block:: python
|
83
83
|
|
84
|
+
from qiskit.pulse import Schedule, Gaussian, DriveChannel, Play
|
84
85
|
sched = Schedule()
|
85
86
|
sched += Play(Gaussian(160, 0.1, 40), DriveChannel(0))
|
86
87
|
|
@@ -653,8 +654,6 @@ class Schedule:
|
|
653
654
|
|
654
655
|
sched += pulse.Schedule(old)
|
655
656
|
|
656
|
-
sched = sched.flatten()
|
657
|
-
|
658
657
|
sched = sched.replace(old, new)
|
659
658
|
|
660
659
|
assert sched == pulse.Schedule(new)
|
@@ -899,11 +898,8 @@ class ScheduleBlock:
|
|
899
898
|
pulse.reference("grand_child")
|
900
899
|
pulse.play(pulse.Constant(200, amp2), pulse.DriveChannel(0))
|
901
900
|
|
902
|
-
|
903
|
-
|
904
|
-
.. code-block::
|
905
|
-
|
906
|
-
sched_outer.assign_references({("grand_child", ): sched_inner})
|
901
|
+
# Now assign the inner pulse program to this reference
|
902
|
+
sched_outer.assign_references({("grand_child",): sched_inner})
|
907
903
|
print(sched_outer.parameters)
|
908
904
|
|
909
905
|
.. parsed-literal::
|
@@ -1459,7 +1455,7 @@ class ScheduleBlock:
|
|
1459
1455
|
|
1460
1456
|
from qiskit import pulse
|
1461
1457
|
|
1462
|
-
with pulse.build() as
|
1458
|
+
with pulse.build() as nested_prog:
|
1463
1459
|
pulse.delay(10, pulse.DriveChannel(0))
|
1464
1460
|
|
1465
1461
|
with pulse.build() as sub_prog:
|
@@ -1490,7 +1486,7 @@ class ScheduleBlock:
|
|
1490
1486
|
.. code-block:: python
|
1491
1487
|
|
1492
1488
|
main_prog.assign_references({("B", ): sub_prog}, inplace=True)
|
1493
|
-
main_prog.references[("B", )].assign_references({"A": nested_prog}, inplace=True)
|
1489
|
+
main_prog.references[("B", )].assign_references({("A", ): nested_prog}, inplace=True)
|
1494
1490
|
|
1495
1491
|
Here :attr:`.references` returns a dict-like object, and you can
|
1496
1492
|
mutably update the nested reference of the particular subroutine.
|
qiskit/pulse/transforms/dag.py
CHANGED
@@ -32,6 +32,11 @@ def block_to_dag(block: ScheduleBlock) -> rx.PyDAG:
|
|
32
32
|
|
33
33
|
.. code-block:: python
|
34
34
|
|
35
|
+
from qiskit import pulse
|
36
|
+
|
37
|
+
my_gaussian0 = pulse.Gaussian(100, 0.5, 20)
|
38
|
+
my_gaussian1 = pulse.Gaussian(100, 0.3, 10)
|
39
|
+
|
35
40
|
with pulse.build() as sched1:
|
36
41
|
with pulse.align_left():
|
37
42
|
pulse.play(my_gaussian0, pulse.DriveChannel(0))
|
@@ -51,6 +56,8 @@ def block_to_dag(block: ScheduleBlock) -> rx.PyDAG:
|
|
51
56
|
|
52
57
|
.. code-block:: python
|
53
58
|
|
59
|
+
from qiskit import pulse
|
60
|
+
|
54
61
|
with pulse.build() as sched:
|
55
62
|
with pulse.align_left():
|
56
63
|
pulse.shift_phase(1.57, pulse.DriveChannel(1))
|
qiskit/qasm2/parse.py
CHANGED
@@ -89,6 +89,35 @@ class CustomInstruction:
|
|
89
89
|
There is a final ``builtin`` field. This is optional, and if set true will cause the
|
90
90
|
instruction to be defined and available within the parsing, even if there is no definition in
|
91
91
|
any included OpenQASM 2 file.
|
92
|
+
|
93
|
+
Examples:
|
94
|
+
|
95
|
+
Instruct the importer to use Qiskit's :class:`.ECRGate` and :class:`.RZXGate` objects to
|
96
|
+
interpret ``gate`` statements that are known to have been created from those same objects
|
97
|
+
during OpenQASM 2 export::
|
98
|
+
|
99
|
+
from qiskit import qasm2
|
100
|
+
from qiskit.circuit import QuantumCircuit, library
|
101
|
+
|
102
|
+
qc = QuantumCircuit(2)
|
103
|
+
qc.ecr(0, 1)
|
104
|
+
qc.rzx(0.3, 0, 1)
|
105
|
+
qc.rzx(0.7, 1, 0)
|
106
|
+
qc.rzx(1.5, 0, 1)
|
107
|
+
qc.ecr(1, 0)
|
108
|
+
|
109
|
+
# This output string includes `gate ecr q0, q1 { ... }` and `gate rzx(p) q0, q1 { ... }`
|
110
|
+
# statements, since `ecr` and `rzx` are neither built-in gates nor in ``qelib1.inc``.
|
111
|
+
dumped = qasm2.dumps(qc)
|
112
|
+
|
113
|
+
# Tell the importer how to interpret the `gate` statements, which we know are safe
|
114
|
+
# because we controlled the input OpenQASM 2 source.
|
115
|
+
custom = [
|
116
|
+
qasm2.CustomInstruction("ecr", 0, 2, library.ECRGate),
|
117
|
+
qasm2.CustomInstruction("rzx", 1, 2, library.RZXGate),
|
118
|
+
]
|
119
|
+
|
120
|
+
loaded = qasm2.loads(dumped, custom_instructions=custom)
|
92
121
|
"""
|
93
122
|
|
94
123
|
name: str
|
qiskit/qasm3/exporter.py
CHANGED
@@ -140,9 +140,16 @@ class Exporter:
|
|
140
140
|
):
|
141
141
|
"""
|
142
142
|
Args:
|
143
|
-
includes: the filenames that should be emitted as includes.
|
144
|
-
|
145
|
-
|
143
|
+
includes: the filenames that should be emitted as includes.
|
144
|
+
|
145
|
+
.. note::
|
146
|
+
|
147
|
+
At present, only the standard-library file ``stdgates.inc`` is properly
|
148
|
+
understood by the exporter, in the sense that it knows the gates it defines.
|
149
|
+
You can specify other includes, but you will need to pass the names of the gates
|
150
|
+
they define in the ``basis_gates`` argument to avoid the exporter outputting a
|
151
|
+
separate ``gate`` definition.
|
152
|
+
|
146
153
|
basis_gates: the basic defined gate set of the backend.
|
147
154
|
disable_constants: if ``True``, always emit floating-point constants for numeric
|
148
155
|
parameter values. If ``False`` (the default), then values close to multiples of
|
@@ -626,7 +633,13 @@ class QASM3Builder:
|
|
626
633
|
if builtin in _BUILTIN_GATES:
|
627
634
|
# It's built into the langauge; we don't need to re-add it.
|
628
635
|
continue
|
629
|
-
|
636
|
+
try:
|
637
|
+
self.symbols.register_gate_without_definition(builtin, None)
|
638
|
+
except QASM3ExporterError as exc:
|
639
|
+
raise QASM3ExporterError(
|
640
|
+
f"Cannot use '{builtin}' as a basis gate for the reason in the prior exception."
|
641
|
+
" Consider renaming the gate if needed, or omitting this basis gate if not."
|
642
|
+
) from exc
|
630
643
|
|
631
644
|
header = ast.Header(ast.Version("3.0"), list(self.build_includes()))
|
632
645
|
|
@@ -669,9 +682,9 @@ class QASM3Builder:
|
|
669
682
|
def build_includes(self):
|
670
683
|
"""Builds a list of included files."""
|
671
684
|
for filename in self.includes:
|
672
|
-
|
673
|
-
|
674
|
-
for name, gate in
|
685
|
+
# Note: unknown include files have a corresponding `include` statement generated, but do
|
686
|
+
# not actually define any gates; we rely on the user to pass those in `basis_gates`.
|
687
|
+
for name, gate in _KNOWN_INCLUDES.get(filename, {}).items():
|
675
688
|
self.symbols.register_gate_without_definition(name, gate)
|
676
689
|
yield ast.Include(filename)
|
677
690
|
|
qiskit/qpy/__init__.py
CHANGED
@@ -774,7 +774,7 @@ In addition, new payload MAP_ITEM is defined to implement the :ref:`qpy_mapping`
|
|
774
774
|
|
775
775
|
With the support of :class:`.~ScheduleBlock`, now :class:`~.QuantumCircuit` can be
|
776
776
|
serialized together with :attr:`~.QuantumCircuit.calibrations`, or
|
777
|
-
`Pulse Gates <https://docs.quantum.ibm.com/
|
777
|
+
`Pulse Gates <https://docs.quantum.ibm.com/guides/pulse>`_.
|
778
778
|
In QPY version 5 and above, :ref:`qpy_circuit_calibrations` payload is
|
779
779
|
packed after the :ref:`qpy_instructions` block.
|
780
780
|
|
@@ -55,6 +55,30 @@ class Operator(LinearOp):
|
|
55
55
|
.. math::
|
56
56
|
|
57
57
|
\rho \mapsto M \rho M^\dagger.
|
58
|
+
|
59
|
+
For example, the following operator :math:`M = X` applied to the zero state
|
60
|
+
:math:`|\psi\rangle=|0\rangle (\rho = |0\rangle\langle 0|)` changes it to the
|
61
|
+
one state :math:`|\psi\rangle=|1\rangle (\rho = |1\rangle\langle 1|)`:
|
62
|
+
|
63
|
+
.. code-block:: python
|
64
|
+
|
65
|
+
>>> import numpy as np
|
66
|
+
>>> from qiskit.quantum_info import Operator
|
67
|
+
>>> op = Operator(np.array([[0.0, 1.0], [1.0, 0.0]])) # Represents Pauli X operator
|
68
|
+
|
69
|
+
>>> from qiskit.quantum_info import Statevector
|
70
|
+
>>> sv = Statevector(np.array([1.0, 0.0]))
|
71
|
+
>>> sv.evolve(op)
|
72
|
+
Statevector([0.+0.j, 1.+0.j],
|
73
|
+
dims=(2,))
|
74
|
+
|
75
|
+
>>> from qiskit.quantum_info import DensityMatrix
|
76
|
+
>>> dm = DensityMatrix(np.array([[1.0, 0.0], [0.0, 0.0]]))
|
77
|
+
>>> dm.evolve(op)
|
78
|
+
DensityMatrix([[0.+0.j, 0.+0.j],
|
79
|
+
[0.+0.j, 1.+0.j]],
|
80
|
+
dims=(2,))
|
81
|
+
|
58
82
|
"""
|
59
83
|
|
60
84
|
def __init__(
|
@@ -792,6 +792,8 @@ class SparsePauliOp(LinearOp):
|
|
792
792
|
|
793
793
|
.. code-block:: python
|
794
794
|
|
795
|
+
from qiskit.quantum_info import SparsePauliOp
|
796
|
+
|
795
797
|
# via tuples and the full Pauli string
|
796
798
|
op = SparsePauliOp.from_list([("XIIZI", 1), ("IYIIY", 2)])
|
797
799
|
|
@@ -856,6 +858,8 @@ class SparsePauliOp(LinearOp):
|
|
856
858
|
|
857
859
|
.. code-block:: python
|
858
860
|
|
861
|
+
from qiskit.quantum_info import SparsePauliOp
|
862
|
+
|
859
863
|
# via triples and local Paulis with indices
|
860
864
|
op = SparsePauliOp.from_sparse_list([("ZX", [1, 4], 1), ("YY", [0, 3], 2)], num_qubits=5)
|
861
865
|
|
@@ -937,7 +941,7 @@ class SparsePauliOp(LinearOp):
|
|
937
941
|
array (the default).
|
938
942
|
force_serial: if ``True``, use an unthreaded implementation, regardless of the state of
|
939
943
|
the `Qiskit threading-control environment variables
|
940
|
-
<https://docs.quantum.ibm.com/
|
944
|
+
<https://docs.quantum.ibm.com/guides/configure-qiskit-local#environment-variables>`__.
|
941
945
|
By default, this will use threaded parallelism over the available CPUs.
|
942
946
|
|
943
947
|
Returns:
|
@@ -1051,6 +1055,7 @@ class SparsePauliOp(LinearOp):
|
|
1051
1055
|
|
1052
1056
|
.. code-block:: python
|
1053
1057
|
|
1058
|
+
>>> from qiskit.quantum_info import SparsePauliOp
|
1054
1059
|
>>> op = SparsePauliOp.from_list([("XX", 2), ("YY", 1), ("IZ",2j), ("ZZ",1j)])
|
1055
1060
|
>>> op.group_commuting()
|
1056
1061
|
[SparsePauliOp(["IZ", "ZZ"], coeffs=[0.+2.j, 0.+1j]),
|
@@ -41,7 +41,7 @@ def synth_clifford_bm(clifford: Clifford) -> QuantumCircuit:
|
|
41
41
|
`arXiv:2003.09412 [quant-ph] <https://arxiv.org/abs/2003.09412>`_
|
42
42
|
"""
|
43
43
|
circuit = QuantumCircuit._from_circuit_data(
|
44
|
-
synth_clifford_bm_inner(clifford.tableau.astype(bool))
|
44
|
+
synth_clifford_bm_inner(clifford.tableau.astype(bool)), add_regs=True
|
45
45
|
)
|
46
46
|
circuit.name = str(clifford)
|
47
47
|
return circuit
|
@@ -51,7 +51,7 @@ def synth_clifford_greedy(clifford: Clifford) -> QuantumCircuit:
|
|
51
51
|
`arXiv:2105.02291 [quant-ph] <https://arxiv.org/abs/2105.02291>`_
|
52
52
|
"""
|
53
53
|
circuit = QuantumCircuit._from_circuit_data(
|
54
|
-
synth_clifford_greedy_inner(clifford.tableau.astype(bool))
|
54
|
+
synth_clifford_greedy_inner(clifford.tableau.astype(bool)), add_regs=True
|
55
55
|
)
|
56
56
|
circuit.name = str(clifford)
|
57
57
|
return circuit
|
@@ -42,7 +42,7 @@ def synth_permutation_basic(pattern: list[int] | np.ndarray[int]) -> QuantumCirc
|
|
42
42
|
Returns:
|
43
43
|
The synthesized quantum circuit.
|
44
44
|
"""
|
45
|
-
return QuantumCircuit._from_circuit_data(_synth_permutation_basic(pattern))
|
45
|
+
return QuantumCircuit._from_circuit_data(_synth_permutation_basic(pattern), add_regs=True)
|
46
46
|
|
47
47
|
|
48
48
|
def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircuit:
|
@@ -75,4 +75,4 @@ def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircui
|
|
75
75
|
*Routing Permutations on Graphs Via Matchings.*,
|
76
76
|
`(Full paper) <https://www.cs.tau.ac.il/~nogaa/PDFS/r.pdf>`_
|
77
77
|
"""
|
78
|
-
return QuantumCircuit._from_circuit_data(_synth_permutation_acg(pattern))
|
78
|
+
return QuantumCircuit._from_circuit_data(_synth_permutation_acg(pattern), add_regs=True)
|
@@ -49,4 +49,6 @@ def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> Qua
|
|
49
49
|
# In the permutation synthesis code below the notation is opposite:
|
50
50
|
# [2, 4, 3, 0, 1] means that 0 maps to 2, 1 to 3, 2 to 3, 3 to 0, and 4 to 1.
|
51
51
|
# This is why we invert the pattern.
|
52
|
-
return QuantumCircuit._from_circuit_data(
|
52
|
+
return QuantumCircuit._from_circuit_data(
|
53
|
+
_synth_permutation_depth_lnn_kms(pattern), add_regs=True
|
54
|
+
)
|
@@ -233,7 +233,7 @@ class TwoQubitWeylDecomposition:
|
|
233
233
|
circuit_data = self._inner_decomposition.circuit(
|
234
234
|
euler_basis=euler_basis, simplify=simplify, atol=atol
|
235
235
|
)
|
236
|
-
return QuantumCircuit._from_circuit_data(circuit_data)
|
236
|
+
return QuantumCircuit._from_circuit_data(circuit_data, add_regs=True)
|
237
237
|
|
238
238
|
def actual_fidelity(self, **kwargs) -> float:
|
239
239
|
"""Calculates the actual fidelity of the decomposed circuit to the input unitary."""
|
@@ -671,7 +671,7 @@ class TwoQubitBasisDecomposer:
|
|
671
671
|
approximate,
|
672
672
|
_num_basis_uses=_num_basis_uses,
|
673
673
|
)
|
674
|
-
return QuantumCircuit._from_circuit_data(circ_data)
|
674
|
+
return QuantumCircuit._from_circuit_data(circ_data, add_regs=True)
|
675
675
|
else:
|
676
676
|
sequence = self._inner_decomposer(
|
677
677
|
np.asarray(unitary, dtype=complex),
|
qiskit/transpiler/__init__.py
CHANGED
@@ -106,8 +106,9 @@ also add initial logical optimization prior to routing, you would do something l
|
|
106
106
|
.. code-block:: python
|
107
107
|
|
108
108
|
import numpy as np
|
109
|
+
from qiskit.providers.fake_provider import GenericBackendV2
|
109
110
|
from qiskit.circuit.library import HGate, PhaseGate, RXGate, TdgGate, TGate, XGate
|
110
|
-
from qiskit.transpiler import PassManager
|
111
|
+
from qiskit.transpiler import PassManager, generate_preset_pass_manager
|
111
112
|
from qiskit.transpiler.passes import (
|
112
113
|
ALAPScheduleAnalysis,
|
113
114
|
CXCancellation,
|
@@ -115,6 +116,7 @@ also add initial logical optimization prior to routing, you would do something l
|
|
115
116
|
PadDynamicalDecoupling,
|
116
117
|
)
|
117
118
|
|
119
|
+
backend = GenericBackendV2(num_qubits=5)
|
118
120
|
dd_sequence = [XGate(), XGate()]
|
119
121
|
scheduling_pm = PassManager(
|
120
122
|
[
|
@@ -135,6 +137,9 @@ also add initial logical optimization prior to routing, you would do something l
|
|
135
137
|
]
|
136
138
|
)
|
137
139
|
|
140
|
+
pass_manager = generate_preset_pass_manager(
|
141
|
+
optimization_level=0
|
142
|
+
)
|
138
143
|
|
139
144
|
# Add pre-layout stage to run extra logical optimization
|
140
145
|
pass_manager.pre_layout = logical_opt
|
@@ -18,6 +18,7 @@ import qiskit.circuit
|
|
18
18
|
from qiskit.circuit import Barrier, Delay, Instruction, ParameterExpression
|
19
19
|
from qiskit.circuit.duration import duration_in_dt
|
20
20
|
from qiskit.providers import Backend
|
21
|
+
from qiskit.providers.backend import BackendV2
|
21
22
|
from qiskit.transpiler.exceptions import TranspilerError
|
22
23
|
from qiskit.utils.units import apply_prefix
|
23
24
|
|
@@ -75,6 +76,9 @@ class InstructionDurations:
|
|
75
76
|
TranspilerError: If dt and dtm is different in the backend.
|
76
77
|
"""
|
77
78
|
# All durations in seconds in gate_length
|
79
|
+
if isinstance(backend, BackendV2):
|
80
|
+
return backend.target.durations()
|
81
|
+
|
78
82
|
instruction_durations = []
|
79
83
|
backend_properties = backend.properties()
|
80
84
|
if hasattr(backend_properties, "_gates"):
|
@@ -71,6 +71,7 @@ Optimizations
|
|
71
71
|
Collect1qRuns
|
72
72
|
Collect2qBlocks
|
73
73
|
CollectMultiQBlocks
|
74
|
+
CollectAndCollapse
|
74
75
|
CollectLinearFunctions
|
75
76
|
CollectCliffords
|
76
77
|
ConsolidateBlocks
|
@@ -238,6 +239,7 @@ from .optimization import HoareOptimizer
|
|
238
239
|
from .optimization import TemplateOptimization
|
239
240
|
from .optimization import InverseCancellation
|
240
241
|
from .optimization import EchoRZXWeylDecomposition
|
242
|
+
from .optimization import CollectAndCollapse
|
241
243
|
from .optimization import CollectLinearFunctions
|
242
244
|
from .optimization import CollectCliffords
|
243
245
|
from .optimization import ResetAfterMeasureSimplification
|
@@ -162,7 +162,8 @@ class BasisTranslator(TransformationPass):
|
|
162
162
|
# If the source basis is a subset of the target basis and we have no circuit
|
163
163
|
# instructions on qargs that have non-global operations there is nothing to
|
164
164
|
# translate and we can exit early.
|
165
|
-
|
165
|
+
source_basis_names = {x[0] for x in source_basis}
|
166
|
+
if source_basis_names.issubset(target_basis) and not qargs_local_source_basis:
|
166
167
|
return dag
|
167
168
|
|
168
169
|
logger.info(
|
@@ -45,7 +45,7 @@ class RXCalibrationBuilder(CalibrationBuilder):
|
|
45
45
|
from qiskit.circuit.library import QuantumVolume
|
46
46
|
from qiskit.circuit.library.standard_gates import RXGate
|
47
47
|
|
48
|
-
from
|
48
|
+
from qiskit.transpiler.passes import RXCalibrationBuilder
|
49
49
|
|
50
50
|
qv = QuantumVolume(4, 4, seed=1004)
|
51
51
|
|
@@ -28,6 +28,7 @@ from qiskit.transpiler.passmanager import PassManager
|
|
28
28
|
from qiskit.transpiler.passes.synthesis import unitary_synthesis
|
29
29
|
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
30
30
|
from qiskit._accelerate.convert_2q_block_matrix import blocks_to_matrix
|
31
|
+
from qiskit.exceptions import QiskitError
|
31
32
|
|
32
33
|
from .collect_1q_runs import Collect1qRuns
|
33
34
|
from .collect_2q_blocks import Collect2qBlocks
|
@@ -125,7 +126,12 @@ class ConsolidateBlocks(TransformationPass):
|
|
125
126
|
qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
|
126
127
|
unitary = UnitaryGate(Operator(qc), check_input=False)
|
127
128
|
else:
|
128
|
-
|
129
|
+
try:
|
130
|
+
matrix = blocks_to_matrix(block, block_index_map)
|
131
|
+
except QiskitError:
|
132
|
+
# If building a matrix for the block fails we should not consolidate it
|
133
|
+
# because there is nothing we can do with it.
|
134
|
+
continue
|
129
135
|
unitary = UnitaryGate(matrix, check_input=False)
|
130
136
|
|
131
137
|
max_2q_depth = 20 # If depth > 20, there will be 1q gates to consolidate.
|
@@ -96,8 +96,8 @@ class ElidePermutations(TransformationPass):
|
|
96
96
|
elif isinstance(node.op, PermutationGate):
|
97
97
|
starting_indices = [qubit_mapping[dag.find_bit(qarg).index] for qarg in node.qargs]
|
98
98
|
pattern = node.op.params[0]
|
99
|
-
|
100
|
-
for i, j in zip(starting_indices,
|
99
|
+
updated_indices = [starting_indices[idx] for idx in pattern]
|
100
|
+
for i, j in zip(starting_indices, updated_indices):
|
101
101
|
qubit_mapping[i] = j
|
102
102
|
input_qubit_mapping = {qubit: index for index, qubit in enumerate(dag.qubits)}
|
103
103
|
self.property_set["original_layout"] = Layout(input_qubit_mapping)
|
@@ -203,20 +203,24 @@ class HoareOptimizer(TransformationPass):
|
|
203
203
|
"""
|
204
204
|
import z3
|
205
205
|
|
206
|
-
|
206
|
+
# Pre-generate all DAG nodes, since we later iterate over them, while
|
207
|
+
# potentially modifying and removing some of them.
|
208
|
+
nodes = list(dag.topological_op_nodes())
|
209
|
+
for node in nodes:
|
207
210
|
gate = node.op
|
208
|
-
|
211
|
+
_, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node)
|
209
212
|
|
210
213
|
ctrl_ones = z3.And(*ctrlvar)
|
211
214
|
|
212
|
-
remove_ctrl, new_dag,
|
215
|
+
remove_ctrl, new_dag, _ = self._remove_control(gate, ctrlvar, trgtvar)
|
213
216
|
|
214
217
|
if remove_ctrl:
|
215
|
-
|
216
|
-
|
217
|
-
node
|
218
|
-
|
219
|
-
node
|
218
|
+
# We are replacing a node by a new node over a smaller number of qubits.
|
219
|
+
# This can be done using substitute_node_with_dag, which furthermore returns
|
220
|
+
# a mapping from old node ids to new nodes.
|
221
|
+
mapped_nodes = dag.substitute_node_with_dag(node, new_dag)
|
222
|
+
node = next(iter(mapped_nodes.values()))
|
223
|
+
gate = node.op
|
220
224
|
_, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node)
|
221
225
|
|
222
226
|
ctrl_ones = z3.And(*ctrlvar)
|
@@ -9,8 +9,8 @@
|
|
9
9
|
# Any modifications or derivative works of this code must retain this
|
10
10
|
# copyright notice, and modified files need to carry a notice indicating
|
11
11
|
# that they have been altered from the originals.
|
12
|
+
|
12
13
|
"""Splits each two-qubit gate in the `dag` into two single-qubit gates, if possible without error."""
|
13
|
-
from typing import Optional
|
14
14
|
|
15
15
|
from qiskit.transpiler.basepasses import TransformationPass
|
16
16
|
from qiskit.circuit.quantumcircuitdata import CircuitInstruction
|
@@ -20,37 +20,33 @@ from qiskit.synthesis.two_qubit.two_qubit_decompose import TwoQubitWeylDecomposi
|
|
20
20
|
|
21
21
|
|
22
22
|
class Split2QUnitaries(TransformationPass):
|
23
|
-
"""Attempt to splits two-qubit
|
23
|
+
"""Attempt to splits two-qubit unitaries in a :class:`.DAGCircuit` into two single-qubit gates.
|
24
24
|
|
25
|
-
This pass will analyze all
|
26
|
-
matrix
|
27
|
-
|
28
|
-
|
29
|
-
:class:`.UnitaryGate`.
|
25
|
+
This pass will analyze all :class:`.UnitaryGate` instances and determine whether the
|
26
|
+
matrix is actually a product of 2 single qubit gates. In these cases the 2q gate can be
|
27
|
+
simplified into two single qubit gates and this pass will perform this optimization and will
|
28
|
+
replace the two qubit gate with two single qubit :class:`.UnitaryGate`.
|
30
29
|
"""
|
31
30
|
|
32
|
-
def __init__(self, fidelity:
|
33
|
-
"""
|
34
|
-
|
31
|
+
def __init__(self, fidelity: float = 1.0 - 1e-16):
|
32
|
+
"""
|
35
33
|
Args:
|
36
|
-
fidelity
|
34
|
+
fidelity: Allowed tolerance for splitting two-qubit unitaries and gate decompositions.
|
37
35
|
"""
|
38
36
|
super().__init__()
|
39
37
|
self.requested_fidelity = fidelity
|
40
38
|
|
41
|
-
def run(self, dag: DAGCircuit):
|
39
|
+
def run(self, dag: DAGCircuit) -> DAGCircuit:
|
42
40
|
"""Run the Split2QUnitaries pass on `dag`."""
|
41
|
+
|
43
42
|
for node in dag.topological_op_nodes():
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
or node.matrix is None
|
49
|
-
or node.is_parameterized()
|
50
|
-
):
|
43
|
+
# We only attempt to split UnitaryGate objects, but this could be extended in future
|
44
|
+
# -- however we need to ensure that we can compile the resulting single-qubit unitaries
|
45
|
+
# to the supported basis gate set.
|
46
|
+
if not (len(node.qargs) == 2 and node.op.name == "unitary"):
|
51
47
|
continue
|
52
48
|
|
53
|
-
decomp = TwoQubitWeylDecomposition(node.
|
49
|
+
decomp = TwoQubitWeylDecomposition(node.matrix, fidelity=self.requested_fidelity)
|
54
50
|
if (
|
55
51
|
decomp._inner_decomposition.specialization
|
56
52
|
== TwoQubitWeylDecomposition._specializations.IdEquiv
|
@@ -31,7 +31,7 @@ class ValidatePulseGates(AnalysisPass):
|
|
31
31
|
|
32
32
|
In Qiskit SDK, we can define the pulse-level implementation of custom quantum gate
|
33
33
|
instructions, as a `pulse gate
|
34
|
-
<https://docs.quantum.ibm.com/
|
34
|
+
<https://docs.quantum.ibm.com/guides/pulse>`__,
|
35
35
|
thus user gates should satisfy all waveform memory constraints imposed by the backend.
|
36
36
|
|
37
37
|
This pass validates all attached calibration entries and raises ``TranspilerError`` to
|
@@ -20,7 +20,7 @@ from qiskit.circuit import Gate, ParameterExpression, Qubit
|
|
20
20
|
from qiskit.circuit.delay import Delay
|
21
21
|
from qiskit.circuit.library.standard_gates import IGate, UGate, U3Gate
|
22
22
|
from qiskit.circuit.reset import Reset
|
23
|
-
from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGInNode, DAGOpNode
|
23
|
+
from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGInNode, DAGOpNode, DAGOutNode
|
24
24
|
from qiskit.quantum_info.operators.predicates import matrix_equal
|
25
25
|
from qiskit.synthesis.one_qubit import OneQubitEulerDecomposer
|
26
26
|
from qiskit.transpiler.exceptions import TranspilerError
|
@@ -331,8 +331,7 @@ class PadDynamicalDecoupling(BasePadding):
|
|
331
331
|
if time_interval % self._alignment != 0:
|
332
332
|
raise TranspilerError(
|
333
333
|
f"Time interval {time_interval} is not divisible by alignment {self._alignment} "
|
334
|
-
f"between
|
335
|
-
f"on qargs {next_node.qargs}."
|
334
|
+
f"between {_format_node(prev_node)} and {_format_node(next_node)}."
|
336
335
|
)
|
337
336
|
|
338
337
|
if not self.__is_dd_qubit(dag.qubits.index(qubit)):
|
@@ -430,3 +429,10 @@ class PadDynamicalDecoupling(BasePadding):
|
|
430
429
|
else:
|
431
430
|
params.append(p)
|
432
431
|
return tuple(params)
|
432
|
+
|
433
|
+
|
434
|
+
def _format_node(node: DAGNode) -> str:
|
435
|
+
"""Util to format the DAGNode, DAGInNode, and DAGOutNode."""
|
436
|
+
if isinstance(node, (DAGInNode, DAGOutNode)):
|
437
|
+
return f"{node.__class__.__name__} on qarg {node.wire}"
|
438
|
+
return f"DAGNode {node.name} on qargs {node.qargs}"
|
@@ -27,6 +27,9 @@ class PadDelay(BasePadding):
|
|
27
27
|
|
28
28
|
.. code-block:: python
|
29
29
|
|
30
|
+
from qiskit import QuantumCircuit
|
31
|
+
from qiskit.transpiler import InstructionDurations
|
32
|
+
|
30
33
|
durations = InstructionDurations([("x", None, 160), ("cx", None, 800)])
|
31
34
|
|
32
35
|
qc = QuantumCircuit(2)
|