qiskit 1.2.0__cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl → 1.2.1__cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.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 (31) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/_accelerate.abi3.so +0 -0
  3. qiskit/circuit/__init__.py +10 -0
  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/standard_gates/__init__.py +32 -25
  8. qiskit/circuit/quantumcircuit.py +39 -14
  9. qiskit/pulse/library/symbolic_pulses.py +4 -3
  10. qiskit/quantum_info/operators/operator.py +24 -0
  11. qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -1
  12. qiskit/synthesis/clifford/clifford_decompose_greedy.py +1 -1
  13. qiskit/synthesis/linear/cnot_synth.py +1 -1
  14. qiskit/synthesis/one_qubit/one_qubit_decompose.py +2 -1
  15. qiskit/synthesis/permutation/permutation_full.py +2 -2
  16. qiskit/synthesis/permutation/permutation_lnn.py +3 -1
  17. qiskit/synthesis/two_qubit/two_qubit_decompose.py +2 -2
  18. qiskit/transpiler/instruction_durations.py +4 -0
  19. qiskit/transpiler/passes/__init__.py +2 -0
  20. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  21. qiskit/transpiler/passes/optimization/hoare_opt.py +12 -8
  22. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +16 -20
  23. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +9 -0
  24. qiskit/utils/optionals.py +173 -150
  25. qiskit/visualization/gate_map.py +28 -6
  26. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/METADATA +1 -1
  27. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/RECORD +688 -688
  28. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/LICENSE.txt +0 -0
  29. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/WHEEL +0 -0
  30. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/entry_points.txt +0 -0
  31. {qiskit-1.2.0.dist-info → qiskit-1.2.1.dist-info}/top_level.txt +0 -0
qiskit/VERSION.txt CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.2.1
Binary file
@@ -580,6 +580,16 @@ The :class:`Store` instruction is particularly special, in that it allows writin
580
580
  :class:`Qubit` nor :class:`Clbit` operands, but has an explicit :attr:`~Store.lvalue` and
581
581
  :attr:`~Store.rvalue`.
582
582
 
583
+ For example, to determine the parity of a bitstring ``cr`` and store it in another register ``creg``,
584
+ the :class:`Store` instruction can be used in the following way::
585
+
586
+ parity = expr.lift(cr[0])
587
+ for i in range(1,n):
588
+ parity = expr.bit_xor(cr[i], parity)
589
+ qc.store(creg[0], parity)
590
+
591
+
592
+
583
593
  .. autoclass:: Store
584
594
  :show-inheritance:
585
595
  :members:
@@ -315,8 +315,10 @@ class QFTGate(Gate):
315
315
  """
316
316
  super().__init__(name="qft", num_qubits=num_qubits, params=[])
317
317
 
318
- def __array__(self, dtype=complex):
318
+ def __array__(self, dtype=complex, copy=None):
319
319
  """Return a numpy array for the QFTGate."""
320
+ if copy is False:
321
+ raise ValueError("unable to avoid copy while creating an array as requested")
320
322
  n = self.num_qubits
321
323
  nums = np.arange(2**n)
322
324
  outer = np.outer(nums, nums)
@@ -21,6 +21,7 @@ import typing
21
21
  from qiskit.circuit.quantumcircuit import QuantumCircuit
22
22
  from qiskit.circuit.quantumregister import QuantumRegister
23
23
  from qiskit.circuit.instruction import Instruction
24
+ from qiskit.circuit.library.generalized_gates import Isometry
24
25
  from .state_preparation import StatePreparation
25
26
 
26
27
  if typing.TYPE_CHECKING:
@@ -86,9 +87,11 @@ class Initialize(Instruction):
86
87
  """Call to create a circuit with gates that take the desired vector to zero.
87
88
 
88
89
  Returns:
89
- Circuit to take ``self.params`` vector to :math:`|{00\\ldots0}\\rangle`
90
+ QuantumCircuit: circuit to take ``self.params`` vector to :math:`|{00\\ldots0}\\rangle`
90
91
  """
91
- return self._stateprep._gates_to_uncompute()
92
+
93
+ isom = Isometry(self.params, 0, 0)
94
+ return isom._gates_to_uncompute()
92
95
 
93
96
  @property
94
97
  def params(self):
@@ -173,8 +173,8 @@ class StatePreparation(Gate):
173
173
  q = QuantumRegister(self.num_qubits, "q")
174
174
  initialize_circuit = QuantumCircuit(q, name="init_def")
175
175
 
176
- isom = Isometry(self._params_arg, 0, 0)
177
- initialize_circuit.append(isom, q[:])
176
+ isom = Isometry(self.params, 0, 0)
177
+ initialize_circuit.compose(isom.definition, copy=False, inplace=True)
178
178
 
179
179
  # invert the circuit to create the desired vector from zero (assuming
180
180
  # the qubits are in the zero state)
@@ -54,6 +54,13 @@ def get_standard_gate_name_mapping():
54
54
  from qiskit.circuit.delay import Delay
55
55
  from qiskit.circuit.reset import Reset
56
56
 
57
+ lambda_ = Parameter("λ")
58
+ theta = Parameter("ϴ")
59
+ phi = Parameter("φ")
60
+ gamma = Parameter("γ")
61
+ beta = Parameter("β")
62
+ time = Parameter("t")
63
+
57
64
  # Standard gates library mapping, multicontrolled gates not included since they're
58
65
  # variable width
59
66
  gates = [
@@ -61,38 +68,37 @@ def get_standard_gate_name_mapping():
61
68
  SXGate(),
62
69
  XGate(),
63
70
  CXGate(),
64
- RZGate(Parameter("λ")),
65
- RGate(Parameter("ϴ"), Parameter("φ")),
66
- Reset(),
71
+ RZGate(lambda_),
72
+ RGate(theta, phi),
67
73
  C3SXGate(),
68
74
  CCXGate(),
69
75
  DCXGate(),
70
76
  CHGate(),
71
- CPhaseGate(Parameter("ϴ")),
72
- CRXGate(Parameter("ϴ")),
73
- CRYGate(Parameter("ϴ")),
74
- CRZGate(Parameter("ϴ")),
77
+ CPhaseGate(theta),
78
+ CRXGate(theta),
79
+ CRYGate(theta),
80
+ CRZGate(theta),
75
81
  CSwapGate(),
76
82
  CSXGate(),
77
- CUGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ"), Parameter("γ")),
78
- CU1Gate(Parameter("λ")),
79
- CU3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
83
+ CUGate(theta, phi, lambda_, gamma),
84
+ CU1Gate(lambda_),
85
+ CU3Gate(theta, phi, lambda_),
80
86
  CYGate(),
81
87
  CZGate(),
82
88
  CCZGate(),
83
- GlobalPhaseGate(Parameter("ϴ")),
89
+ GlobalPhaseGate(theta),
84
90
  HGate(),
85
- PhaseGate(Parameter("ϴ")),
91
+ PhaseGate(theta),
86
92
  RCCXGate(),
87
93
  RC3XGate(),
88
- RXGate(Parameter("ϴ")),
89
- RXXGate(Parameter("ϴ")),
90
- RYGate(Parameter("ϴ")),
91
- RYYGate(Parameter("ϴ")),
92
- RZZGate(Parameter("ϴ")),
93
- RZXGate(Parameter("ϴ")),
94
- XXMinusYYGate(Parameter("ϴ"), Parameter("β")),
95
- XXPlusYYGate(Parameter("ϴ"), Parameter("β")),
94
+ RXGate(theta),
95
+ RXXGate(theta),
96
+ RYGate(theta),
97
+ RYYGate(theta),
98
+ RZZGate(theta),
99
+ RZXGate(theta),
100
+ XXMinusYYGate(theta, beta),
101
+ XXPlusYYGate(theta, beta),
96
102
  ECRGate(),
97
103
  SGate(),
98
104
  SdgGate(),
@@ -103,13 +109,14 @@ def get_standard_gate_name_mapping():
103
109
  SXdgGate(),
104
110
  TGate(),
105
111
  TdgGate(),
106
- UGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
107
- U1Gate(Parameter("λ")),
108
- U2Gate(Parameter("φ"), Parameter("λ")),
109
- U3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
112
+ UGate(theta, phi, lambda_),
113
+ U1Gate(lambda_),
114
+ U2Gate(phi, lambda_),
115
+ U3Gate(theta, phi, lambda_),
110
116
  YGate(),
111
117
  ZGate(),
112
- Delay(Parameter("t")),
118
+ Delay(time),
119
+ Reset(),
113
120
  Measure(),
114
121
  ]
115
122
  name_mapping = {gate.name: gate for gate in gates}
@@ -1152,17 +1152,41 @@ class QuantumCircuit:
1152
1152
  """The unit that :attr:`duration` is specified in."""
1153
1153
  self.metadata = {} if metadata is None else metadata
1154
1154
  """Arbitrary user-defined metadata for the circuit.
1155
-
1155
+
1156
1156
  Qiskit will not examine the content of this mapping, but it will pass it through the
1157
1157
  transpiler and reattach it to the output, so you can track your own metadata."""
1158
1158
 
1159
1159
  @classmethod
1160
- def _from_circuit_data(cls, data: CircuitData) -> typing.Self:
1160
+ def _from_circuit_data(cls, data: CircuitData, add_regs: bool = False) -> typing.Self:
1161
1161
  """A private constructor from rust space circuit data."""
1162
1162
  out = QuantumCircuit()
1163
+
1164
+ if data.num_qubits > 0:
1165
+ if add_regs:
1166
+ qr = QuantumRegister(name="q", bits=data.qubits)
1167
+ out.qregs = [qr]
1168
+ out._qubit_indices = {
1169
+ bit: BitLocations(index, [(qr, index)]) for index, bit in enumerate(data.qubits)
1170
+ }
1171
+ else:
1172
+ out._qubit_indices = {
1173
+ bit: BitLocations(index, []) for index, bit in enumerate(data.qubits)
1174
+ }
1175
+
1176
+ if data.num_clbits > 0:
1177
+ if add_regs:
1178
+ cr = ClassicalRegister(name="c", bits=data.clbits)
1179
+ out.cregs = [cr]
1180
+ out._clbit_indices = {
1181
+ bit: BitLocations(index, [(cr, index)]) for index, bit in enumerate(data.clbits)
1182
+ }
1183
+ else:
1184
+ out._clbit_indices = {
1185
+ bit: BitLocations(index, []) for index, bit in enumerate(data.clbits)
1186
+ }
1187
+
1163
1188
  out._data = data
1164
- out._qubit_indices = {bit: BitLocations(index, []) for index, bit in enumerate(data.qubits)}
1165
- out._clbit_indices = {bit: BitLocations(index, []) for index, bit in enumerate(data.clbits)}
1189
+
1166
1190
  return out
1167
1191
 
1168
1192
  @staticmethod
@@ -3013,16 +3037,7 @@ class QuantumCircuit:
3013
3037
  self._ancillas.append(bit)
3014
3038
 
3015
3039
  if isinstance(register, QuantumRegister):
3016
- self.qregs.append(register)
3017
-
3018
- for idx, bit in enumerate(register):
3019
- if bit in self._qubit_indices:
3020
- self._qubit_indices[bit].registers.append((register, idx))
3021
- else:
3022
- self._data.add_qubit(bit)
3023
- self._qubit_indices[bit] = BitLocations(
3024
- self._data.num_qubits - 1, [(register, idx)]
3025
- )
3040
+ self._add_qreg(register)
3026
3041
 
3027
3042
  elif isinstance(register, ClassicalRegister):
3028
3043
  self.cregs.append(register)
@@ -3041,6 +3056,16 @@ class QuantumCircuit:
3041
3056
  else:
3042
3057
  raise CircuitError("expected a register")
3043
3058
 
3059
+ def _add_qreg(self, qreg: QuantumRegister) -> None:
3060
+ self.qregs.append(qreg)
3061
+
3062
+ for idx, bit in enumerate(qreg):
3063
+ if bit in self._qubit_indices:
3064
+ self._qubit_indices[bit].registers.append((qreg, idx))
3065
+ else:
3066
+ self._data.add_qubit(bit)
3067
+ self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [(qreg, idx)])
3068
+
3044
3069
  def add_bits(self, bits: Iterable[Bit]) -> None:
3045
3070
  """Add Bits to the circuit."""
3046
3071
  duplicate_bits = {
@@ -1773,12 +1773,13 @@ def Square(
1773
1773
  is the sign function with the convention :math:`\\text{sign}\\left(0\\right)=1`.
1774
1774
 
1775
1775
  Args:
1776
- duration: Pulse length in terms of the sampling period `dt`.
1777
- amp: The magnitude of the amplitude of the square wave. Wave range is [-`amp`,`amp`].
1776
+ duration: Pulse length in terms of the sampling period ``dt``.
1777
+ amp: The magnitude of the amplitude of the square wave. Wave range is
1778
+ :math:`\\left[-\\texttt{amp},\\texttt{amp}\\right]`.
1778
1779
  phase: The phase of the square wave (note that this is not equivalent to the angle of
1779
1780
  the complex amplitude).
1780
1781
  freq: The frequency of the square wave, in terms of 1 over sampling period.
1781
- If not provided defaults to a single cycle (i.e :math:'\\frac{1}{\\text{duration}}').
1782
+ If not provided defaults to a single cycle (i.e :math:`\\frac{1}{\\text{duration}}`).
1782
1783
  The frequency is limited to the range :math:`\\left(0,0.5\\right]` (the Nyquist frequency).
1783
1784
  angle: The angle in radians of the complex phase factor uniformly
1784
1785
  scaling the pulse. Default value 0.
@@ -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__(
@@ -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),
@@ -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
@@ -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
@@ -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
@@ -343,6 +343,7 @@ def generate_preset_pass_manager(
343
343
  # Parse non-target dependent pm options
344
344
  initial_layout = _parse_initial_layout(initial_layout)
345
345
  approximation_degree = _parse_approximation_degree(approximation_degree)
346
+ seed_transpiler = _parse_seed_transpiler(seed_transpiler)
346
347
 
347
348
  pm_options = {
348
349
  "target": target,
@@ -516,3 +517,11 @@ def _parse_approximation_degree(approximation_degree):
516
517
  if approximation_degree < 0.0 or approximation_degree > 1.0:
517
518
  raise TranspilerError("Approximation degree must be in [0.0, 1.0]")
518
519
  return approximation_degree
520
+
521
+
522
+ def _parse_seed_transpiler(seed_transpiler):
523
+ if seed_transpiler is None:
524
+ return None
525
+ if not isinstance(seed_transpiler, int) or seed_transpiler < 0:
526
+ raise ValueError("Expected non-negative integer as seed for transpiler.")
527
+ return seed_transpiler