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.
Files changed (67) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/_accelerate.abi3.so +0 -0
  3. qiskit/circuit/__init__.py +15 -2
  4. qiskit/circuit/library/basis_change/qft.py +3 -1
  5. qiskit/circuit/library/data_preparation/initializer.py +5 -2
  6. qiskit/circuit/library/data_preparation/state_preparation.py +2 -2
  7. qiskit/circuit/library/pauli_evolution.py +1 -0
  8. qiskit/circuit/library/standard_gates/__init__.py +32 -25
  9. qiskit/circuit/quantumcircuit.py +43 -18
  10. qiskit/compiler/transpiler.py +1 -1
  11. qiskit/dagcircuit/dagcircuit.py +1 -1
  12. qiskit/primitives/base/base_estimator.py +2 -2
  13. qiskit/primitives/containers/data_bin.py +9 -1
  14. qiskit/providers/basic_provider/basic_simulator.py +1 -1
  15. qiskit/providers/fake_provider/fake_openpulse_2q.py +3 -3
  16. qiskit/providers/fake_provider/fake_openpulse_3q.py +2 -3
  17. qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
  18. qiskit/providers/fake_provider/fake_qasm_backend.py +2 -1
  19. qiskit/providers/fake_provider/generic_backend_v2.py +434 -18
  20. qiskit/providers/models/__init__.py +47 -21
  21. qiskit/pulse/builder.py +16 -7
  22. qiskit/pulse/instructions/directives.py +5 -0
  23. qiskit/pulse/library/symbolic_pulses.py +4 -3
  24. qiskit/pulse/schedule.py +5 -9
  25. qiskit/pulse/transforms/alignments.py +3 -1
  26. qiskit/pulse/transforms/dag.py +7 -0
  27. qiskit/qasm2/parse.py +29 -0
  28. qiskit/qasm3/exporter.py +20 -7
  29. qiskit/qpy/__init__.py +1 -1
  30. qiskit/quantum_info/operators/operator.py +24 -0
  31. qiskit/quantum_info/operators/symplectic/pauli.py +2 -0
  32. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +6 -1
  33. qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -1
  34. qiskit/synthesis/clifford/clifford_decompose_greedy.py +1 -1
  35. qiskit/synthesis/linear/cnot_synth.py +1 -1
  36. qiskit/synthesis/one_qubit/one_qubit_decompose.py +2 -1
  37. qiskit/synthesis/permutation/permutation_full.py +2 -2
  38. qiskit/synthesis/permutation/permutation_lnn.py +3 -1
  39. qiskit/synthesis/two_qubit/two_qubit_decompose.py +2 -2
  40. qiskit/transpiler/__init__.py +6 -1
  41. qiskit/transpiler/instruction_durations.py +4 -0
  42. qiskit/transpiler/passes/__init__.py +2 -0
  43. qiskit/transpiler/passes/basis/basis_translator.py +2 -1
  44. qiskit/transpiler/passes/calibration/rx_builder.py +1 -1
  45. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  46. qiskit/transpiler/passes/optimization/consolidate_blocks.py +7 -1
  47. qiskit/transpiler/passes/optimization/elide_permutations.py +2 -2
  48. qiskit/transpiler/passes/optimization/hoare_opt.py +12 -8
  49. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +16 -20
  50. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +1 -1
  51. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +9 -3
  52. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +3 -0
  53. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +16 -6
  54. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +1 -1
  55. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +12 -55
  56. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +9 -0
  57. qiskit/utils/optionals.py +173 -150
  58. qiskit/visualization/bloch.py +44 -1
  59. qiskit/visualization/dag_visualization.py +10 -3
  60. qiskit/visualization/gate_map.py +28 -6
  61. qiskit/visualization/pass_manager_visualization.py +3 -14
  62. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/METADATA +20 -20
  63. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/RECORD +67 -67
  64. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/WHEEL +1 -1
  65. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/LICENSE.txt +0 -0
  66. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.2.dist-info}/entry_points.txt +0 -0
  67. {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
- Now you assign the inner pulse program to this reference.
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 subroutine:
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.
@@ -338,8 +338,10 @@ class AlignFunc(AlignmentKind):
338
338
 
339
339
  .. code-block:: python
340
340
 
341
+ import numpy as np
342
+
341
343
  def udd10_pos(j):
342
- return np.sin(np.pi*j/(2*10 + 2))**2
344
+ return np.sin(np.pi*j/(2*10 + 2))**2
343
345
 
344
346
  .. note::
345
347
 
@@ -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. These files will be parsed
144
- for gates, and any objects dumped from this exporter will use those definitions
145
- where possible.
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
- self.symbols.register_gate_without_definition(builtin, None)
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
- if (definitions := _KNOWN_INCLUDES.get(filename)) is None:
673
- raise QASM3ExporterError(f"Unknown OpenQASM 3 include file: '{filename}'")
674
- for name, gate in definitions.items():
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/build/pulse>`_.
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__(
@@ -144,6 +144,8 @@ class Pauli(BasePauli):
144
144
 
145
145
  .. code-block:: python
146
146
 
147
+ from qiskit.quantum_info import Pauli
148
+
147
149
  P = Pauli('-iXYZ')
148
150
 
149
151
  print('P[0] =', repr(P[0]))
@@ -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/start/configure-qiskit-local#environment-variables>`__.
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
@@ -66,4 +66,4 @@ def synth_cnot_count_full_pmh(
66
66
  circuit_data = fast_pmh(normalized, section_size)
67
67
 
68
68
  # construct circuit from the data
69
- return QuantumCircuit._from_circuit_data(circuit_data)
69
+ return QuantumCircuit._from_circuit_data(circuit_data, add_regs=True)
@@ -224,7 +224,8 @@ class OneQubitEulerDecomposer:
224
224
  return QuantumCircuit._from_circuit_data(
225
225
  euler_one_qubit_decomposer.unitary_to_circuit(
226
226
  unitary, [self.basis], 0, None, simplify, atol
227
- )
227
+ ),
228
+ add_regs=True,
228
229
  )
229
230
 
230
231
  @property
@@ -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(_synth_permutation_depth_lnn_kms(pattern))
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),
@@ -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
- if source_basis.issubset(target_basis) and not qargs_local_source_basis:
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 calibration.rx_builder import RXCalibrationBuilder
48
+ from qiskit.transpiler.passes import RXCalibrationBuilder
49
49
 
50
50
  qv = QuantumVolume(4, 4, seed=1004)
51
51
 
@@ -39,3 +39,4 @@ from .elide_permutations import ElidePermutations
39
39
  from .normalize_rx_angle import NormalizeRXAngle
40
40
  from .optimize_annotated import OptimizeAnnotated
41
41
  from .split_2q_unitaries import Split2QUnitaries
42
+ from .collect_and_collapse import CollectAndCollapse
@@ -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
- matrix = blocks_to_matrix(block, block_index_map)
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
- pattern_indices = [qubit_mapping[idx] for idx in pattern]
100
- for i, j in zip(starting_indices, pattern_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
- for node in dag.topological_op_nodes():
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
- ctrlqb, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node)
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, qb_idx = self._remove_control(gate, ctrlvar, trgtvar)
215
+ remove_ctrl, new_dag, _ = self._remove_control(gate, ctrlvar, trgtvar)
213
216
 
214
217
  if remove_ctrl:
215
- dag.substitute_node_with_dag(node, new_dag)
216
- gate = gate.base_gate
217
- node.op = gate.to_mutable()
218
- node.name = gate.name
219
- node.qargs = tuple((ctrlqb + trgtqb)[qi] for qi in qb_idx)
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 gates in a :class:`.DAGCircuit` into two single-qubit gates
23
+ """Attempt to splits two-qubit unitaries in a :class:`.DAGCircuit` into two single-qubit gates.
24
24
 
25
- This pass will analyze all the two qubit gates in the circuit and analyze the gate's unitary
26
- matrix to determine if the gate is actually a product of 2 single qubit gates. In these
27
- cases the 2q gate can be simplified into two single qubit gates and this pass will
28
- perform this optimization and will replace the two qubit gate with two single qubit
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: Optional[float] = 1.0 - 1e-16):
33
- """Split2QUnitaries initializer.
34
-
31
+ def __init__(self, fidelity: float = 1.0 - 1e-16):
32
+ """
35
33
  Args:
36
- fidelity (float): Allowed tolerance for splitting two-qubit unitaries and gate decompositions
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
- # skip operations without two-qubits and for which we can not determine a potential 1q split
45
- if (
46
- len(node.cargs) > 0
47
- or len(node.qargs) != 2
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.op, fidelity=self.requested_fidelity)
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/build/pulse>`__,
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 DAGNode {prev_node.name} on qargs {prev_node.qargs} and {next_node.name} "
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)