qiskit 1.1.2__cp38-abi3-win32.whl → 1.2.0__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.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +27 -24
- qiskit/_accelerate.pyd +0 -0
- qiskit/_numpy_compat.py +1 -1
- qiskit/assembler/assemble_circuits.py +107 -64
- qiskit/assembler/assemble_schedules.py +5 -12
- qiskit/assembler/disassemble.py +10 -1
- qiskit/circuit/__init__.py +6 -3
- qiskit/circuit/_classical_resource_map.py +5 -5
- qiskit/circuit/_utils.py +0 -13
- qiskit/circuit/add_control.py +1 -1
- qiskit/circuit/annotated_operation.py +23 -1
- qiskit/circuit/classical/expr/expr.py +4 -4
- qiskit/circuit/classical/expr/visitors.py +1 -1
- qiskit/circuit/classical/types/__init__.py +1 -1
- qiskit/circuit/classical/types/types.py +2 -2
- qiskit/circuit/classicalfunction/boolean_expression.py +1 -1
- qiskit/circuit/classicalfunction/classical_function_visitor.py +5 -5
- qiskit/circuit/classicalfunction/utils.py +1 -1
- qiskit/circuit/classicalregister.py +1 -1
- qiskit/circuit/commutation_checker.py +83 -35
- qiskit/circuit/controlflow/_builder_utils.py +1 -1
- qiskit/circuit/controlflow/builder.py +10 -6
- qiskit/circuit/controlflow/if_else.py +2 -2
- qiskit/circuit/controlflow/switch_case.py +1 -1
- qiskit/circuit/delay.py +1 -1
- qiskit/circuit/duration.py +2 -2
- qiskit/circuit/equivalence.py +5 -7
- qiskit/circuit/gate.py +11 -8
- qiskit/circuit/instruction.py +31 -13
- qiskit/circuit/instructionset.py +2 -5
- qiskit/circuit/library/__init__.py +2 -1
- qiskit/circuit/library/arithmetic/linear_amplitude_function.py +1 -1
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +3 -3
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +1 -1
- qiskit/circuit/library/basis_change/__init__.py +1 -1
- qiskit/circuit/library/basis_change/qft.py +40 -6
- qiskit/circuit/library/blueprintcircuit.py +3 -5
- qiskit/circuit/library/data_preparation/__init__.py +9 -2
- qiskit/circuit/library/data_preparation/initializer.py +8 -0
- qiskit/circuit/library/data_preparation/state_preparation.py +98 -178
- qiskit/circuit/library/generalized_gates/isometry.py +8 -8
- qiskit/circuit/library/generalized_gates/linear_function.py +3 -2
- qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +4 -4
- qiskit/circuit/library/generalized_gates/permutation.py +8 -9
- qiskit/circuit/library/generalized_gates/uc.py +3 -3
- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +2 -2
- qiskit/circuit/library/generalized_gates/unitary.py +13 -11
- qiskit/circuit/library/graph_state.py +1 -1
- qiskit/circuit/library/hamiltonian_gate.py +1 -2
- qiskit/circuit/library/hidden_linear_function.py +1 -1
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -2
- qiskit/circuit/library/n_local/n_local.py +4 -5
- qiskit/circuit/library/n_local/pauli_two_design.py +1 -1
- qiskit/circuit/library/n_local/qaoa_ansatz.py +6 -8
- qiskit/circuit/library/n_local/two_local.py +1 -1
- qiskit/circuit/library/overlap.py +11 -5
- qiskit/circuit/library/pauli_evolution.py +7 -3
- qiskit/circuit/library/standard_gates/dcx.py +3 -0
- qiskit/circuit/library/standard_gates/ecr.py +3 -0
- qiskit/circuit/library/standard_gates/global_phase.py +3 -0
- qiskit/circuit/library/standard_gates/h.py +13 -5
- qiskit/circuit/library/standard_gates/i.py +3 -0
- qiskit/circuit/library/standard_gates/iswap.py +3 -0
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +19 -10
- qiskit/circuit/library/standard_gates/p.py +14 -9
- qiskit/circuit/library/standard_gates/r.py +3 -0
- qiskit/circuit/library/standard_gates/rx.py +21 -6
- qiskit/circuit/library/standard_gates/rxx.py +40 -1
- qiskit/circuit/library/standard_gates/ry.py +21 -6
- qiskit/circuit/library/standard_gates/ryy.py +40 -1
- qiskit/circuit/library/standard_gates/rz.py +22 -6
- qiskit/circuit/library/standard_gates/rzx.py +40 -1
- qiskit/circuit/library/standard_gates/rzz.py +41 -2
- qiskit/circuit/library/standard_gates/s.py +77 -0
- qiskit/circuit/library/standard_gates/swap.py +12 -5
- qiskit/circuit/library/standard_gates/sx.py +14 -5
- qiskit/circuit/library/standard_gates/t.py +5 -0
- qiskit/circuit/library/standard_gates/u.py +22 -7
- qiskit/circuit/library/standard_gates/u1.py +8 -3
- qiskit/circuit/library/standard_gates/u2.py +3 -0
- qiskit/circuit/library/standard_gates/u3.py +22 -7
- qiskit/circuit/library/standard_gates/x.py +156 -92
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +40 -1
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +52 -11
- qiskit/circuit/library/standard_gates/y.py +6 -1
- qiskit/circuit/library/standard_gates/z.py +8 -1
- qiskit/circuit/operation.py +1 -1
- qiskit/circuit/parameter.py +9 -10
- qiskit/circuit/parameterexpression.py +16 -13
- qiskit/circuit/parametertable.py +1 -190
- qiskit/circuit/parametervector.py +1 -1
- qiskit/circuit/quantumcircuit.py +395 -387
- qiskit/circuit/quantumcircuitdata.py +3 -5
- qiskit/circuit/quantumregister.py +1 -1
- qiskit/circuit/random/__init__.py +1 -1
- qiskit/circuit/random/utils.py +175 -26
- qiskit/circuit/register.py +5 -7
- qiskit/circuit/singleton.py +3 -3
- qiskit/circuit/tools/pi_check.py +4 -4
- qiskit/compiler/assembler.py +95 -24
- qiskit/compiler/scheduler.py +2 -2
- qiskit/compiler/transpiler.py +42 -128
- qiskit/converters/circuit_to_dag.py +4 -6
- qiskit/converters/circuit_to_gate.py +4 -8
- qiskit/converters/circuit_to_instruction.py +5 -17
- qiskit/converters/dag_to_circuit.py +2 -6
- qiskit/dagcircuit/collect_blocks.py +2 -2
- qiskit/dagcircuit/dagcircuit.py +190 -187
- qiskit/dagcircuit/dagdependency.py +4 -4
- qiskit/dagcircuit/dagdependency_v2.py +4 -4
- qiskit/dagcircuit/dagdepnode.py +1 -1
- qiskit/dagcircuit/dagnode.py +66 -157
- qiskit/passmanager/flow_controllers.py +1 -1
- qiskit/passmanager/passmanager.py +3 -3
- qiskit/primitives/__init__.py +1 -5
- qiskit/primitives/backend_estimator.py +25 -15
- qiskit/primitives/backend_estimator_v2.py +31 -7
- qiskit/primitives/backend_sampler.py +21 -12
- qiskit/primitives/backend_sampler_v2.py +12 -3
- qiskit/primitives/base/base_estimator.py +31 -4
- qiskit/primitives/base/base_primitive.py +2 -2
- qiskit/primitives/base/base_result.py +2 -2
- qiskit/primitives/base/base_sampler.py +26 -2
- qiskit/primitives/base/estimator_result.py +2 -2
- qiskit/primitives/base/sampler_result.py +2 -2
- qiskit/primitives/containers/__init__.py +0 -1
- qiskit/primitives/containers/bindings_array.py +2 -2
- qiskit/primitives/containers/bit_array.py +108 -10
- qiskit/primitives/containers/shape.py +3 -3
- qiskit/primitives/estimator.py +9 -2
- qiskit/primitives/primitive_job.py +1 -1
- qiskit/primitives/sampler.py +10 -3
- qiskit/primitives/statevector_estimator.py +5 -3
- qiskit/primitives/statevector_sampler.py +11 -5
- qiskit/primitives/utils.py +16 -0
- qiskit/providers/backend.py +15 -6
- qiskit/providers/backend_compat.py +7 -4
- qiskit/providers/basic_provider/basic_provider_tools.py +1 -1
- qiskit/providers/basic_provider/basic_simulator.py +33 -25
- qiskit/providers/fake_provider/fake_backend.py +10 -3
- qiskit/providers/fake_provider/fake_openpulse_2q.py +157 -149
- qiskit/providers/fake_provider/fake_openpulse_3q.py +228 -220
- qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
- qiskit/providers/fake_provider/fake_qasm_backend.py +7 -2
- qiskit/providers/fake_provider/generic_backend_v2.py +514 -68
- qiskit/providers/models/__init__.py +48 -11
- qiskit/providers/models/backendconfiguration.py +50 -4
- qiskit/providers/models/backendproperties.py +13 -2
- qiskit/providers/models/pulsedefaults.py +10 -11
- qiskit/providers/options.py +13 -13
- qiskit/providers/providerutils.py +3 -1
- qiskit/pulse/configuration.py +8 -12
- qiskit/pulse/instruction_schedule_map.py +3 -5
- qiskit/pulse/instructions/acquire.py +7 -8
- qiskit/pulse/instructions/instruction.py +2 -3
- qiskit/pulse/library/samplers/decorators.py +5 -9
- qiskit/pulse/library/symbolic_pulses.py +4 -7
- qiskit/pulse/library/waveform.py +2 -5
- qiskit/pulse/macros.py +11 -6
- qiskit/pulse/parser.py +8 -10
- qiskit/pulse/schedule.py +9 -17
- qiskit/pulse/transforms/alignments.py +1 -3
- qiskit/pulse/utils.py +1 -2
- qiskit/qasm/libs/stdgates.inc +35 -28
- qiskit/qasm2/__init__.py +7 -7
- qiskit/qasm2/export.py +5 -9
- qiskit/qasm2/parse.py +1 -1
- qiskit/qasm3/ast.py +9 -25
- qiskit/qasm3/exporter.py +582 -479
- qiskit/qasm3/printer.py +7 -16
- qiskit/qobj/common.py +10 -0
- qiskit/qobj/converters/lo_config.py +9 -0
- qiskit/qobj/converters/pulse_instruction.py +13 -6
- qiskit/qobj/pulse_qobj.py +69 -15
- qiskit/qobj/qasm_qobj.py +72 -20
- qiskit/qobj/utils.py +9 -0
- qiskit/qpy/__init__.py +1 -1
- qiskit/qpy/binary_io/circuits.py +8 -5
- qiskit/qpy/binary_io/schedules.py +1 -1
- qiskit/qpy/binary_io/value.py +3 -3
- qiskit/qpy/interface.py +3 -2
- qiskit/qpy/type_keys.py +2 -2
- qiskit/quantum_info/operators/channel/quantum_channel.py +3 -6
- qiskit/quantum_info/operators/channel/superop.py +2 -2
- qiskit/quantum_info/operators/channel/transformations.py +1 -1
- qiskit/quantum_info/operators/dihedral/dihedral.py +3 -4
- qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +1 -3
- qiskit/quantum_info/operators/dihedral/random.py +6 -3
- qiskit/quantum_info/operators/measures.py +2 -2
- qiskit/quantum_info/operators/op_shape.py +12 -20
- qiskit/quantum_info/operators/operator.py +14 -21
- qiskit/quantum_info/operators/predicates.py +1 -0
- qiskit/quantum_info/operators/symplectic/base_pauli.py +7 -11
- qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +3 -3
- qiskit/quantum_info/operators/symplectic/pauli_list.py +9 -10
- qiskit/quantum_info/operators/symplectic/random.py +1 -1
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +15 -17
- qiskit/quantum_info/quaternion.py +1 -1
- qiskit/quantum_info/states/densitymatrix.py +5 -8
- qiskit/quantum_info/states/stabilizerstate.py +128 -37
- qiskit/quantum_info/states/statevector.py +4 -8
- qiskit/result/counts.py +2 -2
- qiskit/result/mitigation/correlated_readout_mitigator.py +2 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -2
- qiskit/result/mitigation/utils.py +1 -3
- qiskit/result/models.py +17 -16
- qiskit/result/result.py +15 -20
- qiskit/scheduler/lowering.py +2 -2
- qiskit/synthesis/__init__.py +2 -1
- qiskit/synthesis/clifford/__init__.py +1 -1
- qiskit/synthesis/clifford/clifford_decompose_ag.py +2 -2
- qiskit/synthesis/clifford/clifford_decompose_bm.py +10 -240
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +9 -303
- qiskit/synthesis/clifford/clifford_decompose_layers.py +25 -23
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +1 -1
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +1 -1
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +1 -1
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +2 -2
- qiskit/synthesis/evolution/evolution_synthesis.py +4 -2
- qiskit/synthesis/evolution/lie_trotter.py +46 -19
- qiskit/synthesis/evolution/product_formula.py +111 -55
- qiskit/synthesis/evolution/qdrift.py +40 -10
- qiskit/synthesis/evolution/suzuki_trotter.py +43 -33
- qiskit/synthesis/linear/__init__.py +1 -0
- qiskit/synthesis/linear/cnot_synth.py +22 -96
- qiskit/synthesis/linear/linear_depth_lnn.py +8 -8
- qiskit/synthesis/linear/linear_matrix_utils.py +13 -161
- qiskit/synthesis/linear_phase/cnot_phase_synth.py +1 -1
- qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +3 -3
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +1 -1
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +29 -29
- qiskit/synthesis/permutation/permutation_full.py +5 -29
- qiskit/synthesis/permutation/permutation_lnn.py +2 -24
- qiskit/synthesis/permutation/permutation_utils.py +2 -59
- qiskit/synthesis/qft/__init__.py +1 -0
- qiskit/synthesis/qft/qft_decompose_full.py +79 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +17 -9
- qiskit/synthesis/stabilizer/stabilizer_circuit.py +6 -6
- qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -2
- qiskit/synthesis/two_qubit/local_invariance.py +8 -38
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +48 -129
- qiskit/synthesis/unitary/aqc/cnot_structures.py +1 -1
- qiskit/synthesis/unitary/qsd.py +5 -3
- qiskit/transpiler/__init__.py +1 -0
- qiskit/transpiler/basepasses.py +1 -1
- qiskit/transpiler/coupling.py +3 -3
- qiskit/transpiler/instruction_durations.py +1 -2
- qiskit/transpiler/layout.py +3 -3
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +84 -64
- qiskit/transpiler/passes/basis/translate_parameterized.py +3 -5
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +10 -10
- qiskit/transpiler/passes/calibration/rx_builder.py +3 -3
- qiskit/transpiler/passes/calibration/rzx_builder.py +3 -3
- qiskit/transpiler/passes/layout/apply_layout.py +13 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +10 -8
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +4 -1
- qiskit/transpiler/passes/layout/set_layout.py +2 -2
- qiskit/transpiler/passes/layout/vf2_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_utils.py +3 -3
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
- qiskit/transpiler/passes/optimization/commutation_analysis.py +7 -10
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +35 -19
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +17 -8
- qiskit/transpiler/passes/optimization/inverse_cancellation.py +6 -6
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +64 -41
- qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +83 -0
- qiskit/transpiler/passes/optimization/template_matching/backward_match.py +1 -1
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +2 -2
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
- qiskit/transpiler/passes/routing/layout_transformation.py +2 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +35 -26
- qiskit/transpiler/passes/routing/star_prerouting.py +80 -105
- qiskit/transpiler/passes/routing/stochastic_swap.py +1 -3
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +1 -1
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +5 -5
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +3 -3
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +20 -14
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +7 -6
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -3
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +211 -36
- qiskit/transpiler/passes/synthesis/plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +80 -40
- qiskit/transpiler/passes/utils/__init__.py +0 -1
- qiskit/transpiler/passes/utils/check_gate_direction.py +4 -4
- qiskit/transpiler/passes/utils/check_map.py +3 -6
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +3 -4
- qiskit/transpiler/passes/utils/error.py +2 -2
- qiskit/transpiler/passes/utils/fixed_point.py +3 -3
- qiskit/transpiler/passes/utils/gate_direction.py +1 -1
- qiskit/transpiler/passes/utils/gates_basis.py +1 -2
- qiskit/transpiler/passmanager.py +7 -6
- qiskit/transpiler/preset_passmanagers/__init__.py +4 -228
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +73 -18
- qiskit/transpiler/preset_passmanagers/common.py +3 -6
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +518 -0
- qiskit/transpiler/preset_passmanagers/level0.py +1 -1
- qiskit/transpiler/target.py +27 -8
- qiskit/user_config.py +29 -6
- qiskit/utils/classtools.py +3 -3
- qiskit/utils/deprecation.py +3 -2
- qiskit/utils/lazy_tester.py +2 -2
- qiskit/utils/optionals.py +8 -8
- qiskit/visualization/bloch.py +18 -23
- qiskit/visualization/circuit/_utils.py +34 -10
- qiskit/visualization/circuit/circuit_visualization.py +23 -16
- qiskit/visualization/circuit/latex.py +29 -27
- qiskit/visualization/circuit/matplotlib.py +4 -2
- qiskit/visualization/circuit/qcstyle.py +2 -2
- qiskit/visualization/circuit/text.py +9 -15
- qiskit/visualization/dag_visualization.py +2 -2
- qiskit/visualization/pulse_v2/core.py +1 -1
- qiskit/visualization/pulse_v2/events.py +1 -1
- qiskit/visualization/pulse_v2/generators/frame.py +3 -4
- qiskit/visualization/pulse_v2/generators/waveform.py +5 -9
- qiskit/visualization/pulse_v2/layouts.py +1 -5
- qiskit/visualization/pulse_v2/plotters/matplotlib.py +1 -2
- qiskit/visualization/state_visualization.py +5 -6
- qiskit/visualization/timeline/plotters/matplotlib.py +1 -2
- qiskit/visualization/transition_visualization.py +7 -2
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/METADATA +12 -12
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/RECORD +342 -340
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/entry_points.txt +3 -0
- qiskit/transpiler/passes/utils/block_to_matrix.py +0 -47
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/WHEEL +0 -0
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/top_level.txt +0 -0
@@ -187,7 +187,7 @@ class DAGDependency:
|
|
187
187
|
|
188
188
|
duplicate_qubits = set(self.qubits).intersection(qubits)
|
189
189
|
if duplicate_qubits:
|
190
|
-
raise DAGDependencyError("duplicate qubits
|
190
|
+
raise DAGDependencyError(f"duplicate qubits {duplicate_qubits}")
|
191
191
|
|
192
192
|
self.qubits.extend(qubits)
|
193
193
|
|
@@ -198,7 +198,7 @@ class DAGDependency:
|
|
198
198
|
|
199
199
|
duplicate_clbits = set(self.clbits).intersection(clbits)
|
200
200
|
if duplicate_clbits:
|
201
|
-
raise DAGDependencyError("duplicate clbits
|
201
|
+
raise DAGDependencyError(f"duplicate clbits {duplicate_clbits}")
|
202
202
|
|
203
203
|
self.clbits.extend(clbits)
|
204
204
|
|
@@ -207,7 +207,7 @@ class DAGDependency:
|
|
207
207
|
if not isinstance(qreg, QuantumRegister):
|
208
208
|
raise DAGDependencyError("not a QuantumRegister instance.")
|
209
209
|
if qreg.name in self.qregs:
|
210
|
-
raise DAGDependencyError("duplicate register
|
210
|
+
raise DAGDependencyError(f"duplicate register {qreg.name}")
|
211
211
|
self.qregs[qreg.name] = qreg
|
212
212
|
existing_qubits = set(self.qubits)
|
213
213
|
for j in range(qreg.size):
|
@@ -219,7 +219,7 @@ class DAGDependency:
|
|
219
219
|
if not isinstance(creg, ClassicalRegister):
|
220
220
|
raise DAGDependencyError("not a ClassicalRegister instance.")
|
221
221
|
if creg.name in self.cregs:
|
222
|
-
raise DAGDependencyError("duplicate register
|
222
|
+
raise DAGDependencyError(f"duplicate register {creg.name}")
|
223
223
|
self.cregs[creg.name] = creg
|
224
224
|
existing_clbits = set(self.clbits)
|
225
225
|
for j in range(creg.size):
|
@@ -247,7 +247,7 @@ class _DAGDependencyV2:
|
|
247
247
|
|
248
248
|
duplicate_qubits = set(self.qubits).intersection(qubits)
|
249
249
|
if duplicate_qubits:
|
250
|
-
raise DAGDependencyError("duplicate qubits
|
250
|
+
raise DAGDependencyError(f"duplicate qubits {duplicate_qubits}")
|
251
251
|
|
252
252
|
for qubit in qubits:
|
253
253
|
self.qubits.append(qubit)
|
@@ -260,7 +260,7 @@ class _DAGDependencyV2:
|
|
260
260
|
|
261
261
|
duplicate_clbits = set(self.clbits).intersection(clbits)
|
262
262
|
if duplicate_clbits:
|
263
|
-
raise DAGDependencyError("duplicate clbits
|
263
|
+
raise DAGDependencyError(f"duplicate clbits {duplicate_clbits}")
|
264
264
|
|
265
265
|
for clbit in clbits:
|
266
266
|
self.clbits.append(clbit)
|
@@ -271,7 +271,7 @@ class _DAGDependencyV2:
|
|
271
271
|
if not isinstance(qreg, QuantumRegister):
|
272
272
|
raise DAGDependencyError("not a QuantumRegister instance.")
|
273
273
|
if qreg.name in self.qregs:
|
274
|
-
raise DAGDependencyError("duplicate register
|
274
|
+
raise DAGDependencyError(f"duplicate register {qreg.name}")
|
275
275
|
self.qregs[qreg.name] = qreg
|
276
276
|
existing_qubits = set(self.qubits)
|
277
277
|
for j in range(qreg.size):
|
@@ -288,7 +288,7 @@ class _DAGDependencyV2:
|
|
288
288
|
if not isinstance(creg, ClassicalRegister):
|
289
289
|
raise DAGDependencyError("not a ClassicalRegister instance.")
|
290
290
|
if creg.name in self.cregs:
|
291
|
-
raise DAGDependencyError("duplicate register
|
291
|
+
raise DAGDependencyError(f"duplicate register {creg.name}")
|
292
292
|
self.cregs[creg.name] = creg
|
293
293
|
existing_clbits = set(self.clbits)
|
294
294
|
for j in range(creg.size):
|
qiskit/dagcircuit/dagdepnode.py
CHANGED
@@ -83,7 +83,7 @@ class DAGDepNode:
|
|
83
83
|
def op(self):
|
84
84
|
"""Returns the Instruction object corresponding to the op for the node, else None"""
|
85
85
|
if not self.type or self.type != "op":
|
86
|
-
raise QiskitError("The node
|
86
|
+
raise QiskitError(f"The node {str(self)} is not an op node")
|
87
87
|
return self._op
|
88
88
|
|
89
89
|
@op.setter
|
qiskit/dagcircuit/dagnode.py
CHANGED
@@ -14,14 +14,11 @@
|
|
14
14
|
"""Objects to represent the information at a node in the DAGCircuit."""
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
-
import itertools
|
18
17
|
import typing
|
19
18
|
import uuid
|
20
|
-
from collections.abc import Iterable
|
21
|
-
|
22
19
|
|
20
|
+
import qiskit._accelerate.circuit
|
23
21
|
from qiskit.circuit import (
|
24
|
-
Qubit,
|
25
22
|
Clbit,
|
26
23
|
ClassicalRegister,
|
27
24
|
ControlFlowOp,
|
@@ -30,7 +27,6 @@ from qiskit.circuit import (
|
|
30
27
|
SwitchCaseOp,
|
31
28
|
ForLoopOp,
|
32
29
|
Parameter,
|
33
|
-
Operation,
|
34
30
|
QuantumCircuit,
|
35
31
|
)
|
36
32
|
from qiskit.circuit.classical import expr
|
@@ -39,6 +35,12 @@ if typing.TYPE_CHECKING:
|
|
39
35
|
from qiskit.dagcircuit import DAGCircuit
|
40
36
|
|
41
37
|
|
38
|
+
DAGNode = qiskit._accelerate.circuit.DAGNode
|
39
|
+
DAGOpNode = qiskit._accelerate.circuit.DAGOpNode
|
40
|
+
DAGInNode = qiskit._accelerate.circuit.DAGInNode
|
41
|
+
DAGOutNode = qiskit._accelerate.circuit.DAGOutNode
|
42
|
+
|
43
|
+
|
42
44
|
def _legacy_condition_eq(cond1, cond2, bit_indices1, bit_indices2) -> bool:
|
43
45
|
if cond1 is cond2 is None:
|
44
46
|
return True
|
@@ -175,158 +177,65 @@ _SEMANTIC_EQ_CONTROL_FLOW = {
|
|
175
177
|
_SEMANTIC_EQ_SYMMETRIC = frozenset({"barrier", "swap", "break_loop", "continue_loop"})
|
176
178
|
|
177
179
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
return
|
197
|
-
|
198
|
-
@staticmethod
|
199
|
-
def semantic_eq(node1, node2, bit_indices1, bit_indices2):
|
200
|
-
"""
|
201
|
-
Check if DAG nodes are considered equivalent, e.g., as a node_match for
|
202
|
-
:func:`rustworkx.is_isomorphic_node_match`.
|
203
|
-
|
204
|
-
Args:
|
205
|
-
node1 (DAGOpNode, DAGInNode, DAGOutNode): A node to compare.
|
206
|
-
node2 (DAGOpNode, DAGInNode, DAGOutNode): The other node to compare.
|
207
|
-
bit_indices1 (dict): Dictionary mapping Bit instances to their index
|
208
|
-
within the circuit containing node1
|
209
|
-
bit_indices2 (dict): Dictionary mapping Bit instances to their index
|
210
|
-
within the circuit containing node2
|
211
|
-
|
212
|
-
Return:
|
213
|
-
Bool: If node1 == node2
|
214
|
-
"""
|
215
|
-
if not isinstance(node1, DAGOpNode) or not isinstance(node1, DAGOpNode):
|
216
|
-
return type(node1) is type(node2) and bit_indices1.get(node1.wire) == bit_indices2.get(
|
217
|
-
node2.wire
|
218
|
-
)
|
219
|
-
if isinstance(node1.op, ControlFlowOp) and isinstance(node2.op, ControlFlowOp):
|
220
|
-
# While control-flow operations aren't represented natively in the DAG, we have to do
|
221
|
-
# some unpleasant dispatching and very manual handling. Once they have more first-class
|
222
|
-
# support we'll still be dispatching, but it'll look more appropriate (like the dispatch
|
223
|
-
# based on `DAGOpNode`/`DAGInNode`/`DAGOutNode` that already exists) and less like we're
|
224
|
-
# duplicating code from the `ControlFlowOp` classes.
|
225
|
-
if type(node1.op) is not type(node2.op):
|
226
|
-
return False
|
227
|
-
comparer = _SEMANTIC_EQ_CONTROL_FLOW.get(type(node1.op))
|
228
|
-
if comparer is None: # pragma: no cover
|
229
|
-
raise RuntimeError(f"unhandled control-flow operation: {type(node1.op)}")
|
230
|
-
return comparer(node1, node2, bit_indices1, bit_indices2)
|
231
|
-
|
232
|
-
node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs]
|
233
|
-
node1_cargs = [bit_indices1[carg] for carg in node1.cargs]
|
234
|
-
|
235
|
-
node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs]
|
236
|
-
node2_cargs = [bit_indices2[carg] for carg in node2.cargs]
|
237
|
-
|
238
|
-
# For barriers, qarg order is not significant so compare as sets
|
239
|
-
if node1.op.name == node2.op.name and node1.name in _SEMANTIC_EQ_SYMMETRIC:
|
240
|
-
node1_qargs = set(node1_qargs)
|
241
|
-
node1_cargs = set(node1_cargs)
|
242
|
-
node2_qargs = set(node2_qargs)
|
243
|
-
node2_cargs = set(node2_cargs)
|
244
|
-
|
245
|
-
return (
|
246
|
-
node1_qargs == node2_qargs
|
247
|
-
and node1_cargs == node2_cargs
|
248
|
-
and _legacy_condition_eq(
|
249
|
-
getattr(node1.op, "condition", None),
|
250
|
-
getattr(node2.op, "condition", None),
|
251
|
-
bit_indices1,
|
252
|
-
bit_indices2,
|
253
|
-
)
|
254
|
-
and node1.op == node2.op
|
180
|
+
# Note: called from dag_node.rs.
|
181
|
+
def _semantic_eq(node1, node2, bit_indices1, bit_indices2):
|
182
|
+
"""
|
183
|
+
Check if DAG nodes are considered equivalent, e.g., as a node_match for
|
184
|
+
:func:`rustworkx.is_isomorphic_node_match`.
|
185
|
+
|
186
|
+
Args:
|
187
|
+
node1 (DAGOpNode, DAGInNode, DAGOutNode): A node to compare.
|
188
|
+
node2 (DAGOpNode, DAGInNode, DAGOutNode): The other node to compare.
|
189
|
+
bit_indices1 (dict): Dictionary mapping Bit instances to their index
|
190
|
+
within the circuit containing node1
|
191
|
+
bit_indices2 (dict): Dictionary mapping Bit instances to their index
|
192
|
+
within the circuit containing node2
|
193
|
+
|
194
|
+
Return:
|
195
|
+
Bool: If node1 == node2
|
196
|
+
"""
|
197
|
+
if not isinstance(node1, DAGOpNode) or not isinstance(node1, DAGOpNode):
|
198
|
+
return type(node1) is type(node2) and bit_indices1.get(node1.wire) == bit_indices2.get(
|
199
|
+
node2.wire
|
255
200
|
)
|
201
|
+
if isinstance(node1.op, ControlFlowOp) and isinstance(node2.op, ControlFlowOp):
|
202
|
+
# While control-flow operations aren't represented natively in the DAG, we have to do
|
203
|
+
# some unpleasant dispatching and very manual handling. Once they have more first-class
|
204
|
+
# support we'll still be dispatching, but it'll look more appropriate (like the dispatch
|
205
|
+
# based on `DAGOpNode`/`DAGInNode`/`DAGOutNode` that already exists) and less like we're
|
206
|
+
# duplicating code from the `ControlFlowOp` classes.
|
207
|
+
if type(node1.op) is not type(node2.op):
|
208
|
+
return False
|
209
|
+
comparer = _SEMANTIC_EQ_CONTROL_FLOW.get(type(node1.op))
|
210
|
+
if comparer is None: # pragma: no cover
|
211
|
+
raise RuntimeError(f"unhandled control-flow operation: {type(node1.op)}")
|
212
|
+
return comparer(node1, node2, bit_indices1, bit_indices2)
|
213
|
+
|
214
|
+
node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs]
|
215
|
+
node1_cargs = [bit_indices1[carg] for carg in node1.cargs]
|
216
|
+
|
217
|
+
node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs]
|
218
|
+
node2_cargs = [bit_indices2[carg] for carg in node2.cargs]
|
219
|
+
|
220
|
+
# For barriers, qarg order is not significant so compare as sets
|
221
|
+
if node1.op.name == node2.op.name and node1.name in _SEMANTIC_EQ_SYMMETRIC:
|
222
|
+
node1_qargs = set(node1_qargs)
|
223
|
+
node1_cargs = set(node1_cargs)
|
224
|
+
node2_qargs = set(node2_qargs)
|
225
|
+
node2_cargs = set(node2_cargs)
|
226
|
+
|
227
|
+
return (
|
228
|
+
node1_qargs == node2_qargs
|
229
|
+
and node1_cargs == node2_cargs
|
230
|
+
and _legacy_condition_eq(
|
231
|
+
getattr(node1.op, "condition", None),
|
232
|
+
getattr(node2.op, "condition", None),
|
233
|
+
bit_indices1,
|
234
|
+
bit_indices2,
|
235
|
+
)
|
236
|
+
and node1.op == node2.op
|
237
|
+
)
|
256
238
|
|
257
239
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
__slots__ = ["op", "qargs", "cargs", "sort_key"]
|
262
|
-
|
263
|
-
def __init__(
|
264
|
-
self, op: Operation, qargs: Iterable[Qubit] = (), cargs: Iterable[Clbit] = (), dag=None
|
265
|
-
):
|
266
|
-
"""Create an Instruction node"""
|
267
|
-
super().__init__()
|
268
|
-
self.op = op
|
269
|
-
self.qargs = tuple(qargs)
|
270
|
-
self.cargs = tuple(cargs)
|
271
|
-
if dag is not None:
|
272
|
-
cache_key = (self.qargs, self.cargs)
|
273
|
-
key = dag._key_cache.get(cache_key, None)
|
274
|
-
if key is not None:
|
275
|
-
self.sort_key = key
|
276
|
-
else:
|
277
|
-
self.sort_key = ",".join(
|
278
|
-
f"{dag.find_bit(q).index:04d}" for q in itertools.chain(*cache_key)
|
279
|
-
)
|
280
|
-
dag._key_cache[cache_key] = self.sort_key
|
281
|
-
else:
|
282
|
-
self.sort_key = str(self.qargs)
|
283
|
-
|
284
|
-
@property
|
285
|
-
def name(self):
|
286
|
-
"""Returns the Instruction name corresponding to the op for this node"""
|
287
|
-
return self.op.name
|
288
|
-
|
289
|
-
@name.setter
|
290
|
-
def name(self, new_name):
|
291
|
-
"""Sets the Instruction name corresponding to the op for this node"""
|
292
|
-
self.op.name = new_name
|
293
|
-
|
294
|
-
def __repr__(self):
|
295
|
-
"""Returns a representation of the DAGOpNode"""
|
296
|
-
return f"DAGOpNode(op={self.op}, qargs={self.qargs}, cargs={self.cargs})"
|
297
|
-
|
298
|
-
|
299
|
-
class DAGInNode(DAGNode):
|
300
|
-
"""Object to represent an incoming wire node in the DAGCircuit."""
|
301
|
-
|
302
|
-
__slots__ = ["wire", "sort_key"]
|
303
|
-
|
304
|
-
def __init__(self, wire):
|
305
|
-
"""Create an incoming node"""
|
306
|
-
super().__init__()
|
307
|
-
self.wire = wire
|
308
|
-
# TODO sort_key which is used in dagcircuit.topological_nodes
|
309
|
-
# only works as str([]) for DAGInNodes. Need to figure out why.
|
310
|
-
self.sort_key = str([])
|
311
|
-
|
312
|
-
def __repr__(self):
|
313
|
-
"""Returns a representation of the DAGInNode"""
|
314
|
-
return f"DAGInNode(wire={self.wire})"
|
315
|
-
|
316
|
-
|
317
|
-
class DAGOutNode(DAGNode):
|
318
|
-
"""Object to represent an outgoing wire node in the DAGCircuit."""
|
319
|
-
|
320
|
-
__slots__ = ["wire", "sort_key"]
|
321
|
-
|
322
|
-
def __init__(self, wire):
|
323
|
-
"""Create an outgoing node"""
|
324
|
-
super().__init__()
|
325
|
-
self.wire = wire
|
326
|
-
# TODO sort_key which is used in dagcircuit.topological_nodes
|
327
|
-
# only works as str([]) for DAGOutNodes. Need to figure out why.
|
328
|
-
self.sort_key = str([])
|
329
|
-
|
330
|
-
def __repr__(self):
|
331
|
-
"""Returns a representation of the DAGOutNode"""
|
332
|
-
return f"DAGOutNode(wire={self.wire})"
|
240
|
+
# Bind semantic_eq from Python to Rust implementation
|
241
|
+
DAGNode.semantic_eq = staticmethod(_semantic_eq)
|
@@ -84,7 +84,7 @@ class DoWhileController(BaseController):
|
|
84
84
|
return
|
85
85
|
# Remove stored tasks from the completed task collection for next loop
|
86
86
|
state.workflow_status.completed_passes.difference_update(self.tasks)
|
87
|
-
raise PassManagerError("Maximum iteration reached. max_iteration
|
87
|
+
raise PassManagerError(f"Maximum iteration reached. max_iteration={max_iteration}")
|
88
88
|
|
89
89
|
|
90
90
|
class ConditionalController(BaseController):
|
@@ -130,7 +130,7 @@ class BasePassManager(ABC):
|
|
130
130
|
return new_passmanager
|
131
131
|
except PassManagerError as ex:
|
132
132
|
raise TypeError(
|
133
|
-
"unsupported operand type + for
|
133
|
+
f"unsupported operand type + for {self.__class__} and {other.__class__}"
|
134
134
|
) from ex
|
135
135
|
|
136
136
|
@abstractmethod
|
@@ -225,7 +225,7 @@ class BasePassManager(ABC):
|
|
225
225
|
in_programs = [in_programs]
|
226
226
|
is_list = False
|
227
227
|
|
228
|
-
# If we're not going to run in parallel, we want to avoid spending time `dill`
|
228
|
+
# If we're not going to run in parallel, we want to avoid spending time `dill` serializing
|
229
229
|
# ourselves, since that can be quite expensive.
|
230
230
|
if len(in_programs) == 1 or not should_run_in_parallel(num_processes):
|
231
231
|
out = [
|
@@ -242,7 +242,7 @@ class BasePassManager(ABC):
|
|
242
242
|
# Pass manager may contain callable and we need to serialize through dill rather than pickle.
|
243
243
|
# See https://github.com/Qiskit/qiskit-terra/pull/3290
|
244
244
|
# Note that serialized object is deserialized as a different object.
|
245
|
-
# Thus, we can
|
245
|
+
# Thus, we can reuse the same manager without state collision, without building it per thread.
|
246
246
|
return parallel_map(
|
247
247
|
_run_workflow_in_new_process,
|
248
248
|
values=in_programs,
|
qiskit/primitives/__init__.py
CHANGED
@@ -420,7 +420,6 @@ Results V2
|
|
420
420
|
SamplerPubResult
|
421
421
|
BasePrimitiveJob
|
422
422
|
PrimitiveJob
|
423
|
-
Shaped
|
424
423
|
|
425
424
|
Estimator V1
|
426
425
|
------------
|
@@ -466,16 +465,13 @@ from .containers import (
|
|
466
465
|
DataBin,
|
467
466
|
PrimitiveResult,
|
468
467
|
PubResult,
|
469
|
-
SamplerPubResult,
|
470
468
|
EstimatorPubLike,
|
471
469
|
SamplerPubLike,
|
470
|
+
SamplerPubResult,
|
472
471
|
BindingsArrayLike,
|
473
472
|
ObservableLike,
|
474
473
|
ObservablesArrayLike,
|
475
|
-
Shaped,
|
476
474
|
)
|
477
|
-
|
478
|
-
|
479
475
|
from .estimator import Estimator
|
480
476
|
from .primitive_job import BasePrimitiveJob, PrimitiveJob
|
481
477
|
from .sampler import Sampler
|
@@ -9,9 +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
|
-
|
13
|
-
|
14
|
-
"""
|
12
|
+
|
13
|
+
"""Estimator V1 implementation for an arbitrary Backend object."""
|
15
14
|
|
16
15
|
from __future__ import annotations
|
17
16
|
|
@@ -35,6 +34,7 @@ from qiskit.transpiler.passes import (
|
|
35
34
|
Optimize1qGatesDecomposition,
|
36
35
|
SetLayout,
|
37
36
|
)
|
37
|
+
from qiskit.utils.deprecation import deprecate_func
|
38
38
|
|
39
39
|
from .base import BaseEstimator, EstimatorResult
|
40
40
|
from .primitive_job import PrimitiveJob
|
@@ -65,6 +65,8 @@ def _run_circuits(
|
|
65
65
|
max_circuits = getattr(backend.configuration(), "max_experiments", None)
|
66
66
|
elif isinstance(backend, BackendV2):
|
67
67
|
max_circuits = backend.max_circuits
|
68
|
+
else:
|
69
|
+
raise RuntimeError("Backend version not supported")
|
68
70
|
if max_circuits:
|
69
71
|
jobs = [
|
70
72
|
backend.run(circuits[pos : pos + max_circuits], **run_options)
|
@@ -90,18 +92,26 @@ class BackendEstimator(BaseEstimator[PrimitiveJob[EstimatorResult]]):
|
|
90
92
|
"""Evaluates expectation value using Pauli rotation gates.
|
91
93
|
|
92
94
|
The :class:`~.BackendEstimator` class is a generic implementation of the
|
93
|
-
:class:`~.BaseEstimator` interface that is used to wrap a :class:`~.BackendV2`
|
94
|
-
(or :class:`~.BackendV1`) object in the :class:`~.BaseEstimator` API. It
|
95
|
+
:class:`~.BaseEstimator` (V1) interface that is used to wrap a :class:`~.BackendV2`
|
96
|
+
(or :class:`~.BackendV1`) object in the :class:`~.BaseEstimator` V1 API. It
|
95
97
|
facilitates using backends that do not provide a native
|
96
|
-
:class:`~.BaseEstimator` implementation in places that work with
|
97
|
-
:class:`~.BaseEstimator
|
98
|
-
if you're using a provider that has a native implementation of
|
99
|
-
:class:`~.
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
:class:`~.BaseEstimator` V1 implementation in places that work with
|
99
|
+
:class:`~.BaseEstimator` V1.
|
100
|
+
However, if you're using a provider that has a native implementation of
|
101
|
+
:class:`~.BaseEstimatorV1` ( :class:`~.BaseEstimator`) or
|
102
|
+
:class:`~.BaseEstimatorV2`, it is a better
|
103
|
+
choice to leverage that native implementation as it will likely include
|
104
|
+
additional optimizations and be a more efficient implementation.
|
105
|
+
The generic nature of this class precludes doing any provider- or
|
106
|
+
backend-specific optimizations.
|
103
107
|
"""
|
104
108
|
|
109
|
+
@deprecate_func(
|
110
|
+
since="1.2",
|
111
|
+
additional_msg="All implementations of the `BaseEstimatorV1` interface "
|
112
|
+
"have been deprecated in favor of their V2 counterparts. "
|
113
|
+
"The V2 alternative for the `BackendEstimator` class is `BackendEstimatorV2`.",
|
114
|
+
)
|
105
115
|
def __init__(
|
106
116
|
self,
|
107
117
|
backend: BackendV1 | BackendV2,
|
@@ -110,10 +120,10 @@ class BackendEstimator(BaseEstimator[PrimitiveJob[EstimatorResult]]):
|
|
110
120
|
bound_pass_manager: PassManager | None = None,
|
111
121
|
skip_transpilation: bool = False,
|
112
122
|
):
|
113
|
-
"""Initialize a new BackendEstimator instance
|
123
|
+
"""Initialize a new BackendEstimator (V1) instance
|
114
124
|
|
115
125
|
Args:
|
116
|
-
backend:
|
126
|
+
backend: (required) the backend to run the primitive on
|
117
127
|
options: Default options.
|
118
128
|
abelian_grouping: Whether the observable should be grouped into
|
119
129
|
commuting
|
@@ -198,7 +208,7 @@ class BackendEstimator(BaseEstimator[PrimitiveJob[EstimatorResult]]):
|
|
198
208
|
transpiled_circuit = common_circuit.copy()
|
199
209
|
final_index_layout = list(range(common_circuit.num_qubits))
|
200
210
|
else:
|
201
|
-
transpiled_circuit = transpile(
|
211
|
+
transpiled_circuit = transpile( # pylint:disable=unexpected-keyword-arg
|
202
212
|
common_circuit, self.backend, **self.transpile_options.__dict__
|
203
213
|
)
|
204
214
|
if transpiled_circuit.layout is not None:
|
@@ -72,7 +72,7 @@ class _PreprocessedData:
|
|
72
72
|
|
73
73
|
|
74
74
|
class BackendEstimatorV2(BaseEstimatorV2):
|
75
|
-
"""Evaluates expectation values for provided quantum circuit and observable combinations
|
75
|
+
r"""Evaluates expectation values for provided quantum circuit and observable combinations.
|
76
76
|
|
77
77
|
The :class:`~.BackendEstimatorV2` class is a generic implementation of the
|
78
78
|
:class:`~.BaseEstimatorV2` interface that is used to wrap a :class:`~.BackendV2`
|
@@ -87,7 +87,19 @@ class BackendEstimatorV2(BaseEstimatorV2):
|
|
87
87
|
precludes doing any provider- or backend-specific optimizations.
|
88
88
|
|
89
89
|
This class does not perform any measurement or gate mitigation, and, presently, is only
|
90
|
-
compatible with Pauli-based observables.
|
90
|
+
compatible with Pauli-based observables. More formally, given an observable of the type
|
91
|
+
:math:`O=\sum_{i=1}^Na_iP_i`, where :math:`a_i` is a complex number and :math:`P_i` is a
|
92
|
+
Pauli operator, the estimator calculates the expectation :math:`\mathbb{E}(P_i)` of each
|
93
|
+
:math:`P_i` and finally calculates the expectation value of :math:`O` as
|
94
|
+
:math:`\mathbb{E}(O)=\sum_{i=1}^Na_i\mathbb{E}(P_i)`. The reported ``std`` is calculated
|
95
|
+
as
|
96
|
+
|
97
|
+
.. math::
|
98
|
+
|
99
|
+
\frac{\sum_{i=1}^{n}|a_i|\sqrt{\textrm{Var}\big(P_i\big)}}{\sqrt{N}}\:,
|
100
|
+
|
101
|
+
where :math:`\textrm{Var}(P_i)` is the variance of :math:`P_i`, :math:`N=O(\epsilon^{-2})` is
|
102
|
+
the number of shots, and :math:`\epsilon` is the target precision [1].
|
91
103
|
|
92
104
|
Each tuple of ``(circuit, observables, <optional> parameter values, <optional> precision)``,
|
93
105
|
called an estimator primitive unified bloc (PUB), produces its own array-based result. The
|
@@ -104,6 +116,12 @@ class BackendEstimatorV2(BaseEstimatorV2):
|
|
104
116
|
|
105
117
|
* ``seed_simulator``: The seed to use in the simulator. If None, a random seed will be used.
|
106
118
|
Default: None.
|
119
|
+
|
120
|
+
**Reference:**
|
121
|
+
|
122
|
+
[1] O. Crawford, B. van Straaten, D. Wang, T. Parks, E. Campbell, St. Brierley,
|
123
|
+
Efficient quantum measurement of Pauli operators in the presence of finite sampling error.
|
124
|
+
`Quantum 5, 385 <https://doi.org/10.22331/q-2021-01-20-385>`_
|
107
125
|
"""
|
108
126
|
|
109
127
|
def __init__(
|
@@ -172,7 +190,7 @@ class BackendEstimatorV2(BaseEstimatorV2):
|
|
172
190
|
# reconstruct the result of pubs
|
173
191
|
for i, pub_result in zip(lst, pub_results):
|
174
192
|
results[i] = pub_result
|
175
|
-
return PrimitiveResult(results)
|
193
|
+
return PrimitiveResult(results, metadata={"version": 2})
|
176
194
|
|
177
195
|
def _run_pubs(self, pubs: list[EstimatorPub], shots: int) -> list[PubResult]:
|
178
196
|
"""Compute results for pubs that all require the same value of ``shots``."""
|
@@ -220,7 +238,6 @@ class BackendEstimatorV2(BaseEstimatorV2):
|
|
220
238
|
param_indices = np.fromiter(np.ndindex(param_shape), dtype=object).reshape(param_shape)
|
221
239
|
bc_param_ind, bc_obs = np.broadcast_arrays(param_indices, observables)
|
222
240
|
|
223
|
-
# calculate expectation values for each pair of parameter value set and pauli
|
224
241
|
param_obs_map = defaultdict(set)
|
225
242
|
for index in np.ndindex(*bc_param_ind.shape):
|
226
243
|
param_index = bc_param_ind[index]
|
@@ -254,10 +271,17 @@ class BackendEstimatorV2(BaseEstimatorV2):
|
|
254
271
|
for pauli, coeff in bc_obs[index].items():
|
255
272
|
expval, variance = expval_map[param_index, pauli]
|
256
273
|
evs[index] += expval * coeff
|
257
|
-
variances[index] +=
|
258
|
-
stds = np.sqrt(
|
274
|
+
variances[index] += np.abs(coeff) * variance**0.5
|
275
|
+
stds = variances / np.sqrt(shots)
|
259
276
|
data_bin = DataBin(evs=evs, stds=stds, shape=evs.shape)
|
260
|
-
return PubResult(
|
277
|
+
return PubResult(
|
278
|
+
data_bin,
|
279
|
+
metadata={
|
280
|
+
"target_precision": pub.precision,
|
281
|
+
"shots": shots,
|
282
|
+
"circuit_metadata": pub.circuit.metadata,
|
283
|
+
},
|
284
|
+
)
|
261
285
|
|
262
286
|
def _bind_and_add_measurements(
|
263
287
|
self,
|
@@ -10,7 +10,7 @@
|
|
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
|
-
"""Sampler implementation for an arbitrary Backend object."""
|
13
|
+
"""Sampler V1 implementation for an arbitrary Backend object."""
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
@@ -23,6 +23,7 @@ from qiskit.providers.backend import BackendV1, BackendV2
|
|
23
23
|
from qiskit.providers.options import Options
|
24
24
|
from qiskit.result import QuasiDistribution, Result
|
25
25
|
from qiskit.transpiler.passmanager import PassManager
|
26
|
+
from qiskit.utils.deprecation import deprecate_func
|
26
27
|
|
27
28
|
from .backend_estimator import _prepare_counts, _run_circuits
|
28
29
|
from .base import BaseSampler, SamplerResult
|
@@ -31,21 +32,29 @@ from .utils import _circuit_key
|
|
31
32
|
|
32
33
|
|
33
34
|
class BackendSampler(BaseSampler[PrimitiveJob[SamplerResult]]):
|
34
|
-
"""A :class:`~.BaseSampler` implementation that provides
|
35
|
-
leveraging the
|
35
|
+
"""A :class:`~.BaseSampler` (V1) implementation that provides a wrapper for
|
36
|
+
leveraging the Sampler V1 interface from any backend.
|
36
37
|
|
37
38
|
This class provides a sampler interface from any backend and doesn't do
|
38
39
|
any measurement mitigation, it just computes the probability distribution
|
39
40
|
from the counts. It facilitates using backends that do not provide a
|
40
|
-
native :class:`~.BaseSampler` implementation in places that work with
|
41
|
-
:class:`~.BaseSampler
|
41
|
+
native :class:`~.BaseSampler` V1 implementation in places that work with
|
42
|
+
:class:`~.BaseSampler` V1.
|
42
43
|
However, if you're using a provider that has a native implementation of
|
43
|
-
:class:`~.
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
:class:`~.BaseSamplerV1` ( :class:`~.BaseSampler`) or
|
45
|
+
:class:`~.BaseESamplerV2`, it is a better
|
46
|
+
choice to leverage that native implementation as it will likely include
|
47
|
+
additional optimizations and be a more efficient implementation.
|
48
|
+
The generic nature of this class precludes doing any provider- or
|
49
|
+
backend-specific optimizations.
|
47
50
|
"""
|
48
51
|
|
52
|
+
@deprecate_func(
|
53
|
+
since="1.2",
|
54
|
+
additional_msg="All implementations of the `BaseSamplerV1` interface "
|
55
|
+
"have been deprecated in favor of their V2 counterparts. "
|
56
|
+
"The V2 alternative for the `BackendSampler` class is `BackendSamplerV2`.",
|
57
|
+
)
|
49
58
|
def __init__(
|
50
59
|
self,
|
51
60
|
backend: BackendV1 | BackendV2,
|
@@ -53,10 +62,10 @@ class BackendSampler(BaseSampler[PrimitiveJob[SamplerResult]]):
|
|
53
62
|
bound_pass_manager: PassManager | None = None,
|
54
63
|
skip_transpilation: bool = False,
|
55
64
|
):
|
56
|
-
"""Initialize a new BackendSampler
|
65
|
+
"""Initialize a new BackendSampler (V1) instance
|
57
66
|
|
58
67
|
Args:
|
59
|
-
backend:
|
68
|
+
backend: (required) the backend to run the sampler primitive on
|
60
69
|
options: Default options.
|
61
70
|
bound_pass_manager: An optional pass manager to run after
|
62
71
|
parameter binding.
|
@@ -176,7 +185,7 @@ class BackendSampler(BaseSampler[PrimitiveJob[SamplerResult]]):
|
|
176
185
|
|
177
186
|
start = len(self._transpiled_circuits)
|
178
187
|
self._transpiled_circuits.extend(
|
179
|
-
transpile(
|
188
|
+
transpile( # pylint:disable=unexpected-keyword-arg
|
180
189
|
self.preprocessed_circuits[start:],
|
181
190
|
self.backend,
|
182
191
|
**self.transpile_options.__dict__,
|