qiskit 1.2.0rc1__cp38-abi3-win32.whl → 1.2.1__cp38-abi3-win32.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 (50) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/_accelerate.pyd +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/standard_gates/__init__.py +32 -25
  8. qiskit/circuit/quantumcircuit.py +43 -18
  9. qiskit/compiler/transpiler.py +1 -1
  10. qiskit/providers/basic_provider/basic_simulator.py +1 -1
  11. qiskit/providers/fake_provider/fake_openpulse_2q.py +3 -3
  12. qiskit/providers/fake_provider/fake_openpulse_3q.py +2 -3
  13. qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
  14. qiskit/providers/fake_provider/fake_qasm_backend.py +2 -1
  15. qiskit/providers/fake_provider/generic_backend_v2.py +434 -18
  16. qiskit/providers/models/__init__.py +47 -21
  17. qiskit/pulse/library/symbolic_pulses.py +4 -3
  18. qiskit/qasm3/exporter.py +7 -1
  19. qiskit/qpy/__init__.py +1 -1
  20. qiskit/quantum_info/operators/operator.py +24 -0
  21. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
  22. qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -1
  23. qiskit/synthesis/clifford/clifford_decompose_greedy.py +1 -1
  24. qiskit/synthesis/linear/cnot_synth.py +1 -1
  25. qiskit/synthesis/one_qubit/one_qubit_decompose.py +2 -1
  26. qiskit/synthesis/permutation/permutation_full.py +2 -2
  27. qiskit/synthesis/permutation/permutation_lnn.py +3 -1
  28. qiskit/synthesis/two_qubit/two_qubit_decompose.py +2 -2
  29. qiskit/transpiler/instruction_durations.py +4 -0
  30. qiskit/transpiler/passes/__init__.py +2 -0
  31. qiskit/transpiler/passes/basis/basis_translator.py +2 -1
  32. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  33. qiskit/transpiler/passes/optimization/consolidate_blocks.py +7 -1
  34. qiskit/transpiler/passes/optimization/hoare_opt.py +12 -8
  35. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +16 -20
  36. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +1 -1
  37. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +9 -3
  38. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +1 -1
  39. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +10 -54
  40. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +9 -0
  41. qiskit/utils/optionals.py +173 -150
  42. qiskit/visualization/bloch.py +44 -1
  43. qiskit/visualization/dag_visualization.py +10 -3
  44. qiskit/visualization/gate_map.py +28 -6
  45. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/METADATA +20 -20
  46. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/RECORD +50 -50
  47. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/WHEEL +1 -1
  48. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/LICENSE.txt +0 -0
  49. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/entry_points.txt +0 -0
  50. {qiskit-1.2.0rc1.dist-info → qiskit-1.2.1.dist-info}/top_level.txt +0 -0
@@ -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
@@ -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(
@@ -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.
@@ -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}"
@@ -54,7 +54,7 @@ from qiskit.circuit.library.standard_gates import (
54
54
  from qiskit.converters import circuit_to_dag, dag_to_circuit
55
55
  from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode
56
56
  from qiskit.exceptions import QiskitError
57
- from qiskit.providers.models import BackendProperties
57
+ from qiskit.providers.models.backendproperties import BackendProperties
58
58
  from qiskit.quantum_info import Operator
59
59
  from qiskit.synthesis.one_qubit import one_qubit_decompose
60
60
  from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments
@@ -14,7 +14,6 @@
14
14
 
15
15
  import os
16
16
 
17
- from qiskit.circuit import Instruction
18
17
  from qiskit.transpiler.passes.optimization.split_2q_unitaries import Split2QUnitaries
19
18
  from qiskit.transpiler.passmanager import PassManager
20
19
  from qiskit.transpiler.exceptions import TranspilerError
@@ -66,7 +65,6 @@ from qiskit.circuit.library.standard_gates import (
66
65
  CYGate,
67
66
  SXGate,
68
67
  SXdgGate,
69
- get_standard_gate_name_mapping,
70
68
  )
71
69
  from qiskit.utils.parallel import CPU_COUNT
72
70
  from qiskit import user_config
@@ -173,58 +171,16 @@ class DefaultInitPassManager(PassManagerStagePlugin):
173
171
  )
174
172
  )
175
173
  init.append(CommutativeCancellation())
176
- # skip peephole optimization before routing if target basis gate set is discrete,
177
- # i.e. only consists of Cliffords that an user might want to keep
178
- # use rz, sx, x, cx as basis, rely on physical optimziation to fix everything later one
179
- stdgates = get_standard_gate_name_mapping()
180
-
181
- def _is_one_op_non_discrete(ops):
182
- """Checks if one operation in `ops` is not discrete, i.e. is parameterizable
183
- Args:
184
- ops (List(Operation)): list of operations to check
185
- Returns
186
- True if at least one operation in `ops` is not discrete, False otherwise
187
- """
188
- found_one_continuous_gate = False
189
- for op in ops:
190
- if isinstance(op, str):
191
- if op in _discrete_skipped_ops:
192
- continue
193
- op = stdgates.get(op, None)
194
-
195
- if op is not None and op.name in _discrete_skipped_ops:
196
- continue
197
-
198
- if op is None or not isinstance(op, Instruction):
199
- return False
200
-
201
- if len(op.params) > 0:
202
- found_one_continuous_gate = True
203
- return found_one_continuous_gate
204
-
205
- target = pass_manager_config.target
206
- basis = pass_manager_config.basis_gates
207
- # consolidate gates before routing if the user did not specify a discrete basis gate, i.e.
208
- # * no target or basis gate set has been specified
209
- # * target has been specified, and we have one non-discrete gate in the target's spec
210
- # * basis gates have been specified, and we have one non-discrete gate in that set
211
- do_consolidate_blocks_init = target is None and basis is None
212
- do_consolidate_blocks_init |= target is not None and _is_one_op_non_discrete(
213
- target.operations
214
- )
215
- do_consolidate_blocks_init |= basis is not None and _is_one_op_non_discrete(basis)
216
-
217
- if do_consolidate_blocks_init:
218
- init.append(Collect2qBlocks())
219
- init.append(ConsolidateBlocks())
220
- # If approximation degree is None that indicates a request to approximate up to the
221
- # error rates in the target. However, in the init stage we don't yet know the target
222
- # qubits being used to figure out the fidelity so just use the default fidelity parameter
223
- # in this case.
224
- if pass_manager_config.approximation_degree is not None:
225
- init.append(Split2QUnitaries(pass_manager_config.approximation_degree))
226
- else:
227
- init.append(Split2QUnitaries())
174
+ init.append(Collect2qBlocks())
175
+ init.append(ConsolidateBlocks())
176
+ # If approximation degree is None that indicates a request to approximate up to the
177
+ # error rates in the target. However, in the init stage we don't yet know the target
178
+ # qubits being used to figure out the fidelity so just use the default fidelity parameter
179
+ # in this case.
180
+ if pass_manager_config.approximation_degree is not None:
181
+ init.append(Split2QUnitaries(pass_manager_config.approximation_degree))
182
+ else:
183
+ init.append(Split2QUnitaries())
228
184
  else:
229
185
  raise TranspilerError(f"Invalid optimization level {optimization_level}")
230
186
  return init
@@ -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