qiskit 1.3.0b1__cp39-abi3-win32.whl → 1.3.0rc2__cp39-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 +20 -1
- qiskit/_accelerate.pyd +0 -0
- qiskit/assembler/assemble_schedules.py +2 -0
- qiskit/circuit/__init__.py +44 -1
- qiskit/circuit/_standard_gates_commutations.py +585 -0
- qiskit/circuit/barrier.py +2 -0
- qiskit/circuit/controlflow/builder.py +3 -3
- qiskit/circuit/controlflow/if_else.py +13 -5
- qiskit/circuit/controlflow/while_loop.py +10 -2
- qiskit/circuit/delay.py +20 -3
- qiskit/circuit/equivalence.py +13 -214
- qiskit/circuit/gate.py +3 -1
- qiskit/circuit/instruction.py +32 -11
- qiskit/circuit/instructionset.py +2 -0
- qiskit/circuit/library/__init__.py +110 -14
- qiskit/circuit/library/arithmetic/__init__.py +9 -2
- qiskit/circuit/library/arithmetic/adders/__init__.py +1 -0
- qiskit/circuit/library/arithmetic/adders/adder.py +154 -2
- qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +20 -56
- qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +14 -1
- qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +21 -91
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/multipliers/__init__.py +1 -0
- qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +8 -1
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +94 -3
- qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +8 -1
- qiskit/circuit/library/arithmetic/weighted_adder.py +1 -1
- qiskit/circuit/library/basis_change/qft.py +20 -38
- qiskit/circuit/library/blueprintcircuit.py +64 -0
- qiskit/circuit/library/boolean_logic/__init__.py +4 -4
- qiskit/circuit/library/boolean_logic/inner_product.py +81 -4
- qiskit/circuit/library/boolean_logic/quantum_and.py +107 -4
- qiskit/circuit/library/boolean_logic/quantum_or.py +107 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +97 -3
- qiskit/circuit/library/data_preparation/__init__.py +6 -3
- qiskit/circuit/library/data_preparation/{z_feature_map.py → _z_feature_map.py} +45 -34
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +150 -0
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +342 -29
- qiskit/circuit/library/fourier_checking.py +72 -11
- qiskit/circuit/library/generalized_gates/__init__.py +1 -1
- qiskit/circuit/library/generalized_gates/diagonal.py +45 -51
- qiskit/circuit/library/generalized_gates/gms.py +67 -14
- qiskit/circuit/library/generalized_gates/gr.py +4 -4
- qiskit/circuit/library/generalized_gates/isometry.py +2 -2
- qiskit/circuit/library/generalized_gates/linear_function.py +12 -6
- qiskit/circuit/library/generalized_gates/mcmt.py +167 -107
- qiskit/circuit/library/generalized_gates/permutation.py +8 -6
- qiskit/circuit/library/generalized_gates/rv.py +8 -9
- qiskit/circuit/library/graph_state.py +93 -10
- qiskit/circuit/library/grover_operator.py +270 -2
- qiskit/circuit/library/hidden_linear_function.py +83 -20
- qiskit/circuit/library/iqp.py +99 -20
- qiskit/circuit/library/n_local/__init__.py +19 -7
- qiskit/circuit/library/n_local/efficient_su2.py +118 -5
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +259 -0
- qiskit/circuit/library/n_local/excitation_preserving.py +130 -6
- qiskit/circuit/library/n_local/n_local.py +406 -5
- qiskit/circuit/library/n_local/pauli_two_design.py +106 -4
- qiskit/circuit/library/n_local/qaoa_ansatz.py +80 -1
- qiskit/circuit/library/n_local/real_amplitudes.py +127 -7
- qiskit/circuit/library/n_local/two_local.py +14 -7
- qiskit/circuit/library/overlap.py +91 -26
- qiskit/circuit/library/pauli_evolution.py +17 -15
- qiskit/circuit/library/phase_estimation.py +80 -4
- qiskit/circuit/library/quantum_volume.py +72 -20
- qiskit/circuit/library/standard_gates/__init__.py +20 -1
- qiskit/circuit/library/standard_gates/dcx.py +2 -1
- qiskit/circuit/library/standard_gates/ecr.py +2 -2
- qiskit/circuit/library/standard_gates/h.py +4 -3
- qiskit/circuit/library/standard_gates/i.py +2 -1
- qiskit/circuit/library/standard_gates/iswap.py +2 -2
- qiskit/circuit/library/standard_gates/p.py +20 -12
- qiskit/circuit/library/standard_gates/r.py +1 -1
- qiskit/circuit/library/standard_gates/rx.py +4 -3
- qiskit/circuit/library/standard_gates/rxx.py +2 -2
- qiskit/circuit/library/standard_gates/ry.py +4 -3
- qiskit/circuit/library/standard_gates/ryy.py +2 -2
- qiskit/circuit/library/standard_gates/rz.py +13 -12
- qiskit/circuit/library/standard_gates/rzx.py +6 -6
- qiskit/circuit/library/standard_gates/rzz.py +1 -1
- qiskit/circuit/library/standard_gates/s.py +4 -4
- qiskit/circuit/library/standard_gates/swap.py +3 -3
- qiskit/circuit/library/standard_gates/sx.py +4 -3
- qiskit/circuit/library/standard_gates/t.py +2 -2
- qiskit/circuit/library/standard_gates/u.py +11 -3
- qiskit/circuit/library/standard_gates/u1.py +65 -15
- qiskit/circuit/library/standard_gates/u2.py +4 -1
- qiskit/circuit/library/standard_gates/u3.py +31 -3
- qiskit/circuit/library/standard_gates/x.py +7 -5
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -2
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -2
- qiskit/circuit/library/standard_gates/y.py +4 -3
- qiskit/circuit/library/standard_gates/z.py +3 -3
- qiskit/circuit/library/templates/clifford/clifford_2_1.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_2_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_2_3.py +9 -7
- qiskit/circuit/library/templates/clifford/clifford_2_4.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_3_1.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_4_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_3.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_4.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_5_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_3.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_4.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_6_5.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_3.py +10 -9
- qiskit/circuit/library/templates/nct/template_nct_2a_1.py +9 -7
- qiskit/circuit/library/templates/nct/template_nct_2a_2.py +10 -8
- qiskit/circuit/library/templates/nct/template_nct_2a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_4a_1.py +16 -14
- qiskit/circuit/library/templates/nct/template_nct_4a_2.py +14 -12
- qiskit/circuit/library/templates/nct/template_nct_4a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_4b_1.py +14 -12
- qiskit/circuit/library/templates/nct/template_nct_4b_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_4.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_6a_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_6a_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6a_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6b_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6b_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6c_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_7a_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7b_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7c_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7d_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7e_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_9a_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_9c_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_9c_10.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_11.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_12.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_5.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_6.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_7.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_8.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_9.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_9d_10.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_5.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_6.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_7.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_8.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_9.py +12 -10
- qiskit/circuit/library/templates/rzx/rzx_cy.py +11 -10
- qiskit/circuit/library/templates/rzx/rzx_xz.py +16 -15
- qiskit/circuit/library/templates/rzx/rzx_yz.py +12 -10
- qiskit/circuit/library/templates/rzx/rzx_zz1.py +22 -20
- qiskit/circuit/library/templates/rzx/rzx_zz2.py +16 -15
- qiskit/circuit/library/templates/rzx/rzx_zz3.py +17 -15
- qiskit/circuit/parameter.py +4 -0
- qiskit/circuit/parameterexpression.py +167 -34
- qiskit/circuit/quantumcircuit.py +162 -126
- qiskit/circuit/singleton.py +2 -0
- qiskit/circuit/store.py +2 -0
- qiskit/circuit/twirling.py +145 -0
- qiskit/compiler/assembler.py +17 -4
- qiskit/compiler/scheduler.py +2 -0
- qiskit/compiler/sequencer.py +2 -0
- qiskit/compiler/transpiler.py +81 -26
- qiskit/converters/circuit_to_dag.py +2 -2
- qiskit/converters/circuit_to_dagdependency.py +1 -1
- qiskit/converters/circuit_to_dagdependency_v2.py +1 -1
- qiskit/converters/circuit_to_instruction.py +1 -1
- qiskit/converters/dag_to_circuit.py +7 -5
- qiskit/converters/dag_to_dagdependency.py +1 -1
- qiskit/converters/dag_to_dagdependency_v2.py +1 -1
- qiskit/converters/dagdependency_to_circuit.py +5 -1
- qiskit/converters/dagdependency_to_dag.py +6 -1
- qiskit/dagcircuit/collect_blocks.py +3 -3
- qiskit/dagcircuit/dagdependency.py +18 -5
- qiskit/dagcircuit/dagdependency_v2.py +1 -1
- qiskit/dagcircuit/dagnode.py +2 -2
- qiskit/passmanager/__init__.py +2 -2
- qiskit/primitives/backend_estimator.py +5 -2
- qiskit/primitives/backend_sampler_v2.py +61 -18
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +9 -1
- qiskit/primitives/statevector_sampler.py +1 -1
- qiskit/primitives/utils.py +1 -1
- qiskit/providers/__init__.py +3 -3
- qiskit/providers/backend.py +12 -1
- qiskit/providers/backend_compat.py +23 -3
- qiskit/providers/basic_provider/basic_simulator.py +12 -2
- qiskit/providers/fake_provider/fake_pulse_backend.py +6 -1
- qiskit/providers/fake_provider/generic_backend_v2.py +46 -30
- qiskit/providers/models/pulsedefaults.py +2 -0
- qiskit/pulse/builder.py +59 -18
- qiskit/pulse/calibration_entries.py +4 -1
- qiskit/pulse/channels.py +2 -0
- qiskit/pulse/exceptions.py +2 -0
- qiskit/pulse/instruction_schedule_map.py +21 -6
- qiskit/pulse/instructions/acquire.py +2 -0
- qiskit/pulse/instructions/delay.py +2 -0
- qiskit/pulse/instructions/directives.py +8 -0
- qiskit/pulse/instructions/frequency.py +3 -0
- qiskit/pulse/instructions/instruction.py +2 -0
- qiskit/pulse/instructions/phase.py +3 -0
- qiskit/pulse/instructions/play.py +2 -0
- qiskit/pulse/instructions/reference.py +2 -0
- qiskit/pulse/instructions/snapshot.py +2 -0
- qiskit/pulse/library/pulse.py +2 -0
- qiskit/pulse/library/symbolic_pulses.py +28 -0
- qiskit/pulse/library/waveform.py +2 -0
- qiskit/pulse/macros.py +1 -1
- qiskit/pulse/schedule.py +12 -13
- qiskit/pulse/transforms/alignments.py +5 -3
- qiskit/pulse/transforms/dag.py +7 -0
- qiskit/qasm2/export.py +5 -3
- qiskit/qasm2/parse.py +46 -2
- qiskit/qasm3/__init__.py +1 -0
- qiskit/qasm3/ast.py +123 -15
- qiskit/qasm3/exporter.py +103 -77
- qiskit/qobj/converters/pulse_instruction.py +6 -4
- qiskit/qpy/__init__.py +181 -0
- qiskit/qpy/binary_io/circuits.py +20 -5
- qiskit/qpy/binary_io/schedules.py +3 -4
- qiskit/qpy/binary_io/value.py +310 -13
- qiskit/qpy/common.py +46 -2
- qiskit/qpy/formats.py +7 -0
- qiskit/qpy/interface.py +40 -4
- qiskit/quantum_info/__init__.py +4 -0
- qiskit/quantum_info/operators/channel/transformations.py +28 -21
- qiskit/quantum_info/operators/dihedral/dihedral.py +1 -1
- qiskit/quantum_info/operators/operator.py +54 -8
- qiskit/quantum_info/operators/symplectic/base_pauli.py +11 -19
- qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +1 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -0
- qiskit/quantum_info/operators/symplectic/pauli_list.py +4 -4
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +23 -2
- qiskit/quantum_info/states/densitymatrix.py +5 -5
- qiskit/quantum_info/states/stabilizerstate.py +1 -1
- qiskit/quantum_info/states/statevector.py +6 -6
- qiskit/result/mitigation/base_readout_mitigator.py +1 -1
- qiskit/result/mitigation/correlated_readout_mitigator.py +9 -1
- qiskit/result/mitigation/local_readout_mitigator.py +9 -1
- qiskit/result/mitigation/utils.py +57 -0
- qiskit/scheduler/config.py +2 -0
- qiskit/scheduler/methods/basic.py +3 -0
- qiskit/scheduler/schedule_circuit.py +2 -0
- qiskit/scheduler/sequence.py +2 -0
- qiskit/synthesis/__init__.py +25 -0
- qiskit/synthesis/arithmetic/__init__.py +16 -0
- qiskit/synthesis/arithmetic/adders/__init__.py +17 -0
- qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +154 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +103 -0
- qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +161 -0
- qiskit/synthesis/arithmetic/multipliers/__init__.py +16 -0
- qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +102 -0
- qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +99 -0
- qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -2
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +3 -2
- qiskit/synthesis/clifford/clifford_decompose_layers.py +2 -1
- qiskit/synthesis/evolution/__init__.py +1 -0
- qiskit/synthesis/evolution/lie_trotter.py +16 -42
- qiskit/synthesis/evolution/pauli_network.py +80 -0
- qiskit/synthesis/evolution/product_formula.py +165 -238
- qiskit/synthesis/evolution/qdrift.py +36 -29
- qiskit/synthesis/evolution/suzuki_trotter.py +87 -27
- qiskit/synthesis/multi_controlled/__init__.py +1 -0
- qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
- qiskit/synthesis/qft/qft_decompose_full.py +19 -1
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -1
- qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -1
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +4 -63
- qiskit/synthesis/unitary/qsd.py +5 -5
- qiskit/transpiler/__init__.py +21 -14
- qiskit/transpiler/basepasses.py +1 -1
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +9 -565
- qiskit/transpiler/passes/basis/decompose.py +45 -12
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/pulse_gate.py +4 -2
- qiskit/transpiler/passes/calibration/rx_builder.py +11 -7
- qiskit/transpiler/passes/calibration/rzx_builder.py +46 -30
- qiskit/transpiler/passes/layout/disjoint_utils.py +15 -13
- qiskit/transpiler/passes/layout/sabre_layout.py +7 -2
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +5 -0
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/collect_cliffords.py +19 -3
- qiskit/transpiler/passes/optimization/collect_linear_functions.py +1 -1
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +48 -131
- qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +4 -2
- qiskit/transpiler/passes/optimization/elide_permutations.py +9 -32
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +5 -11
- qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +1 -1
- qiskit/transpiler/passes/optimization/remove_identity_equiv.py +69 -0
- qiskit/transpiler/passes/optimization/template_matching/backward_match.py +5 -5
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +4 -4
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +2 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +1 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +7 -3
- qiskit/transpiler/passes/routing/star_prerouting.py +2 -2
- qiskit/transpiler/passes/scheduling/alap.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +2 -2
- qiskit/transpiler/passes/scheduling/asap.py +1 -1
- qiskit/transpiler/passes/scheduling/base_scheduler.py +14 -12
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +9 -4
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +16 -5
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +4 -1
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +6 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +9 -4
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +262 -99
- qiskit/transpiler/passes/synthesis/hls_plugins.py +637 -7
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +3 -3
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +55 -34
- qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +2 -56
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +5 -0
- qiskit/transpiler/passes/utils/gate_direction.py +12 -275
- qiskit/transpiler/passes/utils/gates_basis.py +7 -30
- qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +2 -1
- qiskit/transpiler/passmanager_config.py +22 -4
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +40 -14
- qiskit/transpiler/preset_passmanagers/common.py +5 -3
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +125 -42
- qiskit/transpiler/preset_passmanagers/plugin.py +1 -1
- qiskit/transpiler/target.py +74 -16
- qiskit/utils/deprecate_pulse.py +119 -0
- qiskit/visualization/circuit/_utils.py +2 -2
- qiskit/visualization/circuit/circuit_visualization.py +3 -2
- qiskit/visualization/circuit/matplotlib.py +1 -1
- qiskit/visualization/dag_visualization.py +1 -1
- qiskit/visualization/pass_manager_visualization.py +3 -14
- qiskit/visualization/pulse_v2/interface.py +3 -1
- qiskit/visualization/timeline/core.py +25 -2
- qiskit/visualization/timeline/interface.py +12 -0
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/METADATA +9 -8
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/RECORD +357 -346
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/WHEEL +1 -1
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/entry_points.txt +19 -0
- qiskit/circuit/library/data_preparation/zz_feature_map.py +0 -118
- qiskit/synthesis/two_qubit/weyl.py +0 -97
- qiskit/transpiler/passes/synthesis/qubit_tracker.py +0 -132
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/top_level.txt +0 -0
@@ -15,17 +15,26 @@
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
17
|
import inspect
|
18
|
-
|
19
|
-
from
|
20
|
-
from
|
18
|
+
import itertools
|
19
|
+
from collections.abc import Callable, Sequence
|
20
|
+
from collections import defaultdict
|
21
|
+
from itertools import combinations
|
22
|
+
import typing
|
21
23
|
import numpy as np
|
24
|
+
import rustworkx as rx
|
22
25
|
from qiskit.circuit.parameterexpression import ParameterExpression
|
23
|
-
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
26
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit, ParameterValueType
|
24
27
|
from qiskit.quantum_info import SparsePauliOp, Pauli
|
25
28
|
from qiskit.utils.deprecation import deprecate_arg
|
29
|
+
from qiskit._accelerate.circuit_library import pauli_evolution
|
26
30
|
|
27
31
|
from .evolution_synthesis import EvolutionSynthesis
|
28
32
|
|
33
|
+
if typing.TYPE_CHECKING:
|
34
|
+
from qiskit.circuit.library import PauliEvolutionGate
|
35
|
+
|
36
|
+
SparsePauliLabel = typing.Tuple[str, list[int], ParameterValueType]
|
37
|
+
|
29
38
|
|
30
39
|
class ProductFormula(EvolutionSynthesis):
|
31
40
|
"""Product formula base class for the decomposition of non-commuting operator exponentials.
|
@@ -60,6 +69,7 @@ class ProductFormula(EvolutionSynthesis):
|
|
60
69
|
| None
|
61
70
|
) = None,
|
62
71
|
wrap: bool = False,
|
72
|
+
preserve_order: bool = True,
|
63
73
|
) -> None:
|
64
74
|
"""
|
65
75
|
Args:
|
@@ -78,24 +88,31 @@ class ProductFormula(EvolutionSynthesis):
|
|
78
88
|
Alternatively, the function can also take Pauli operator and evolution time as
|
79
89
|
inputs and returns the circuit that will be appended to the overall circuit being
|
80
90
|
built.
|
81
|
-
wrap: Whether to wrap the atomic evolutions into custom gate objects.
|
82
|
-
|
91
|
+
wrap: Whether to wrap the atomic evolutions into custom gate objects. Note that setting
|
92
|
+
this to ``True`` is slower than ``False``. This only takes effect when
|
93
|
+
``atomic_evolution is None``.
|
94
|
+
preserve_order: If ``False``, allows reordering the terms of the operator to
|
95
|
+
potentially yield a shallower evolution circuit. Not relevant
|
96
|
+
when synthesizing operator with a single term.
|
83
97
|
"""
|
84
98
|
super().__init__()
|
85
99
|
self.order = order
|
86
100
|
self.reps = reps
|
87
101
|
self.insert_barriers = insert_barriers
|
102
|
+
self.preserve_order = preserve_order
|
88
103
|
|
89
104
|
# user-provided atomic evolution, stored for serialization
|
90
105
|
self._atomic_evolution = atomic_evolution
|
106
|
+
|
107
|
+
if cx_structure not in ["chain", "fountain"]:
|
108
|
+
raise ValueError(f"Unsupported CX structure: {cx_structure}")
|
109
|
+
|
91
110
|
self._cx_structure = cx_structure
|
92
111
|
self._wrap = wrap
|
93
112
|
|
94
113
|
# if atomic evolution is not provided, set a default
|
95
114
|
if atomic_evolution is None:
|
96
|
-
self.atomic_evolution =
|
97
|
-
_default_atomic_evolution, cx_structure=cx_structure, wrap=wrap
|
98
|
-
)
|
115
|
+
self.atomic_evolution = None
|
99
116
|
|
100
117
|
elif len(inspect.signature(atomic_evolution).parameters) == 2:
|
101
118
|
|
@@ -108,8 +125,50 @@ class ProductFormula(EvolutionSynthesis):
|
|
108
125
|
else:
|
109
126
|
self.atomic_evolution = atomic_evolution
|
110
127
|
|
128
|
+
def expand(
|
129
|
+
self, evolution: PauliEvolutionGate
|
130
|
+
) -> list[tuple[str, tuple[int], ParameterValueType]]:
|
131
|
+
"""Apply the product formula to expand the Hamiltonian in the evolution gate.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
evolution: The :class:`.PauliEvolutionGate`, whose Hamiltonian we expand.
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
A list of Pauli rotations in a sparse format, where each element is
|
138
|
+
``(paulistring, qubits, coefficient)``. For example, the Lie-Trotter expansion
|
139
|
+
of ``H = XI + ZZ`` would return ``[("X", [1], 1), ("ZZ", [0, 1], 1)]``.
|
140
|
+
"""
|
141
|
+
raise NotImplementedError(
|
142
|
+
f"The method ``expand`` is not implemented for {self.__class__}. Implement it to "
|
143
|
+
f"automatically enable the call to {self.__class__}.synthesize."
|
144
|
+
)
|
145
|
+
|
146
|
+
def synthesize(self, evolution: PauliEvolutionGate) -> QuantumCircuit:
|
147
|
+
"""Synthesize a :class:`.PauliEvolutionGate`.
|
148
|
+
|
149
|
+
Args:
|
150
|
+
evolution: The evolution gate to synthesize.
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
QuantumCircuit: A circuit implementing the evolution.
|
154
|
+
"""
|
155
|
+
pauli_rotations = self.expand(evolution)
|
156
|
+
num_qubits = evolution.num_qubits
|
157
|
+
|
158
|
+
if self._wrap or self._atomic_evolution is not None:
|
159
|
+
# this is the slow path, where each Pauli evolution is constructed in Rust
|
160
|
+
# separately and then wrapped into a gate object
|
161
|
+
circuit = self._custom_evolution(num_qubits, pauli_rotations)
|
162
|
+
else:
|
163
|
+
# this is the fast path, where the whole evolution is constructed Rust-side
|
164
|
+
cx_fountain = self._cx_structure == "fountain"
|
165
|
+
data = pauli_evolution(num_qubits, pauli_rotations, self.insert_barriers, cx_fountain)
|
166
|
+
circuit = QuantumCircuit._from_circuit_data(data, add_regs=True)
|
167
|
+
|
168
|
+
return circuit
|
169
|
+
|
111
170
|
@property
|
112
|
-
def settings(self) -> dict[str, Any]:
|
171
|
+
def settings(self) -> dict[str, typing.Any]:
|
113
172
|
"""Return the settings in a dictionary, which can be used to reconstruct the object.
|
114
173
|
|
115
174
|
Returns:
|
@@ -129,256 +188,124 @@ class ProductFormula(EvolutionSynthesis):
|
|
129
188
|
"insert_barriers": self.insert_barriers,
|
130
189
|
"cx_structure": self._cx_structure,
|
131
190
|
"wrap": self._wrap,
|
191
|
+
"preserve_order": self.preserve_order,
|
132
192
|
}
|
133
193
|
|
194
|
+
def _normalize_coefficients(
|
195
|
+
self, paulis: list[str | list[int], float | complex | ParameterExpression]
|
196
|
+
) -> list[str | list[int] | ParameterValueType]:
|
197
|
+
"""Ensure the coefficients are real (or parameter expressions)."""
|
198
|
+
return [[(op, qubits, real_or_fail(coeff)) for op, qubits, coeff in ops] for ops in paulis]
|
134
199
|
|
135
|
-
def
|
136
|
-
|
137
|
-
pauli: Pauli,
|
138
|
-
time: float | ParameterExpression = 1.0,
|
139
|
-
cx_structure: str = "chain",
|
140
|
-
wrap: bool = False,
|
141
|
-
label: str | None = None,
|
142
|
-
) -> None:
|
143
|
-
r"""Construct a circuit implementing the time evolution of a single Pauli string.
|
144
|
-
|
145
|
-
For a Pauli string :math:`P = \{I, X, Y, Z\}^{\otimes n}` on :math:`n` qubits and an
|
146
|
-
evolution time :math:`t`, the returned circuit implements the unitary operation
|
147
|
-
|
148
|
-
.. math::
|
149
|
-
|
150
|
-
U(t) = e^{-itP}.
|
151
|
-
|
152
|
-
Since only a single Pauli string is evolved the circuit decomposition is exact.
|
153
|
-
|
154
|
-
Args:
|
155
|
-
output: The circuit object to which to append the evolved Pauli.
|
156
|
-
pauli: The Pauli to evolve.
|
157
|
-
time: The evolution time.
|
158
|
-
cx_structure: Determine the structure of CX gates, can be either ``"chain"`` for
|
159
|
-
next-neighbor connections or ``"fountain"`` to connect directly to the top qubit.
|
160
|
-
wrap: Whether to wrap the single Pauli evolutions into custom gate objects.
|
161
|
-
label: A label for the gate.
|
162
|
-
"""
|
163
|
-
num_non_identity = len([label for label in pauli.to_label() if label != "I"])
|
164
|
-
|
165
|
-
# first check, if the Pauli is only the identity, in which case the evolution only
|
166
|
-
# adds a global phase
|
167
|
-
if num_non_identity == 0:
|
168
|
-
output.global_phase -= time
|
169
|
-
# if we evolve on a single qubit, if yes use the corresponding qubit rotation
|
170
|
-
elif num_non_identity == 1:
|
171
|
-
_single_qubit_evolution(output, pauli, time, wrap)
|
172
|
-
# same for two qubits, use Qiskit's native rotations
|
173
|
-
elif num_non_identity == 2:
|
174
|
-
_two_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
175
|
-
# otherwise do basis transformation and CX chains
|
176
|
-
else:
|
177
|
-
_multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
178
|
-
|
179
|
-
|
180
|
-
def _single_qubit_evolution(output, pauli, time, wrap):
|
181
|
-
dest = QuantumCircuit(1) if wrap else output
|
182
|
-
# Note that all phases are removed from the pauli label and are only in the coefficients.
|
183
|
-
# That's because the operators we evolved have all been translated to a SparsePauliOp.
|
184
|
-
qubits = []
|
185
|
-
label = ""
|
186
|
-
for i, pauli_i in enumerate(reversed(pauli.to_label())):
|
187
|
-
idx = 0 if wrap else i
|
188
|
-
if pauli_i == "X":
|
189
|
-
dest.rx(2 * time, idx)
|
190
|
-
qubits.append(i)
|
191
|
-
label += "X"
|
192
|
-
elif pauli_i == "Y":
|
193
|
-
dest.ry(2 * time, idx)
|
194
|
-
qubits.append(i)
|
195
|
-
label += "Y"
|
196
|
-
elif pauli_i == "Z":
|
197
|
-
dest.rz(2 * time, idx)
|
198
|
-
qubits.append(i)
|
199
|
-
label += "Z"
|
200
|
-
|
201
|
-
if wrap:
|
202
|
-
gate = dest.to_gate(label=f"exp(it {label})")
|
203
|
-
qubits = [output.qubits[q] for q in qubits]
|
204
|
-
output.append(gate, qargs=qubits, copy=False)
|
205
|
-
|
206
|
-
|
207
|
-
def _two_qubit_evolution(output, pauli, time, cx_structure, wrap):
|
208
|
-
# Get the Paulis and the qubits they act on.
|
209
|
-
# Note that all phases are removed from the pauli label and are only in the coefficients.
|
210
|
-
# That's because the operators we evolved have all been translated to a SparsePauliOp.
|
211
|
-
labels_as_array = np.array(list(reversed(pauli.to_label())))
|
212
|
-
qubits = np.where(labels_as_array != "I")[0]
|
213
|
-
indices = [0, 1] if wrap else qubits
|
214
|
-
labels = np.array([labels_as_array[idx] for idx in qubits])
|
215
|
-
|
216
|
-
dest = QuantumCircuit(2) if wrap else output
|
217
|
-
|
218
|
-
# go through all cases we have implemented in Qiskit
|
219
|
-
if all(labels == "X"): # RXX
|
220
|
-
dest.rxx(2 * time, indices[0], indices[1])
|
221
|
-
elif all(labels == "Y"): # RYY
|
222
|
-
dest.ryy(2 * time, indices[0], indices[1])
|
223
|
-
elif all(labels == "Z"): # RZZ
|
224
|
-
dest.rzz(2 * time, indices[0], indices[1])
|
225
|
-
elif labels[0] == "Z" and labels[1] == "X": # RZX
|
226
|
-
dest.rzx(2 * time, indices[0], indices[1])
|
227
|
-
elif labels[0] == "X" and labels[1] == "Z": # RXZ
|
228
|
-
dest.rzx(2 * time, indices[1], indices[0])
|
229
|
-
else: # all the others are not native in Qiskit, so use default the decomposition
|
230
|
-
_multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
231
|
-
return
|
232
|
-
|
233
|
-
if wrap:
|
234
|
-
gate = dest.to_gate(label=f"exp(it {''.join(labels)})")
|
235
|
-
qubits = [output.qubits[q] for q in qubits]
|
236
|
-
output.append(gate, qargs=qubits, copy=False)
|
237
|
-
|
238
|
-
|
239
|
-
def _multi_qubit_evolution(output, pauli, time, cx_structure, wrap):
|
240
|
-
# get diagonalizing clifford
|
241
|
-
cliff = diagonalizing_clifford(pauli)
|
242
|
-
|
243
|
-
# get CX chain to reduce the evolution to the top qubit
|
244
|
-
if cx_structure == "chain":
|
245
|
-
chain = cnot_chain(pauli)
|
246
|
-
else:
|
247
|
-
chain = cnot_fountain(pauli)
|
248
|
-
|
249
|
-
# determine qubit to do the rotation on
|
250
|
-
target = None
|
251
|
-
# Note that all phases are removed from the pauli label and are only in the coefficients.
|
252
|
-
# That's because the operators we evolved have all been translated to a SparsePauliOp.
|
253
|
-
for i, pauli_i in enumerate(reversed(pauli.to_label())):
|
254
|
-
if pauli_i != "I":
|
255
|
-
target = i
|
256
|
-
break
|
257
|
-
|
258
|
-
# build the evolution as: diagonalization, reduction, 1q evolution, followed by inverses
|
259
|
-
dest = QuantumCircuit(pauli.num_qubits) if wrap else output
|
260
|
-
dest.compose(cliff, inplace=True)
|
261
|
-
dest.compose(chain, inplace=True)
|
262
|
-
dest.rz(2 * time, target)
|
263
|
-
dest.compose(chain.inverse(), inplace=True)
|
264
|
-
dest.compose(cliff.inverse(), inplace=True)
|
265
|
-
|
266
|
-
if wrap:
|
267
|
-
gate = dest.to_gate(label=f"exp(it {pauli.to_label()})")
|
268
|
-
output.append(gate, qargs=output.qubits, copy=False)
|
269
|
-
|
270
|
-
|
271
|
-
def diagonalizing_clifford(pauli: Pauli) -> QuantumCircuit:
|
272
|
-
"""Get the clifford circuit to diagonalize the Pauli operator.
|
200
|
+
def _custom_evolution(self, num_qubits, pauli_rotations):
|
201
|
+
"""Implement the evolution for the non-standard path.
|
273
202
|
|
274
|
-
|
275
|
-
|
203
|
+
This is either because a user-defined atomic evolution is given, or because the evolution
|
204
|
+
of individual Paulis needs to be wrapped in gates.
|
205
|
+
"""
|
206
|
+
circuit = QuantumCircuit(num_qubits)
|
207
|
+
cx_fountain = self._cx_structure == "fountain"
|
276
208
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
cliff.sdg(i)
|
284
|
-
if pauli_i in ["X", "Y"]:
|
285
|
-
cliff.h(i)
|
209
|
+
num_paulis = len(pauli_rotations)
|
210
|
+
for i, pauli_rotation in enumerate(pauli_rotations):
|
211
|
+
if self._atomic_evolution is not None:
|
212
|
+
# use the user-provided evolution with a global operator
|
213
|
+
operator = SparsePauliOp.from_sparse_list([pauli_rotation], num_qubits)
|
214
|
+
self.atomic_evolution(circuit, operator, time=1) # time is inside the Pauli coeff
|
286
215
|
|
287
|
-
|
216
|
+
else: # this means self._wrap is True
|
217
|
+
# we create a local sparse Pauli representation such that the operator
|
218
|
+
# does not span over all qubits of the circuit
|
219
|
+
pauli_string, qubits, coeff = pauli_rotation
|
220
|
+
local_pauli = (pauli_string, list(range(len(qubits))), coeff)
|
288
221
|
|
222
|
+
# build the circuit Rust-side
|
223
|
+
data = pauli_evolution(
|
224
|
+
len(qubits),
|
225
|
+
[local_pauli],
|
226
|
+
False,
|
227
|
+
cx_fountain,
|
228
|
+
)
|
229
|
+
evo = QuantumCircuit._from_circuit_data(data)
|
289
230
|
|
290
|
-
|
291
|
-
|
231
|
+
# and append it to the circuit with the correct label
|
232
|
+
gate = evo.to_gate(label=f"exp(it {pauli_string})")
|
233
|
+
circuit.append(gate, qubits)
|
292
234
|
|
293
|
-
|
235
|
+
if self.insert_barriers and i < num_paulis - 1:
|
236
|
+
circuit.barrier()
|
294
237
|
|
295
|
-
|
238
|
+
return circuit
|
296
239
|
|
297
|
-
┌───┐
|
298
|
-
q_0: ──────────┤ X ├
|
299
|
-
└─┬─┘
|
300
|
-
q_1: ────────────┼──
|
301
|
-
┌───┐ │
|
302
|
-
q_2: ─────┤ X ├──■──
|
303
|
-
┌───┐└─┬─┘
|
304
|
-
q_3: ┤ X ├──■───────
|
305
|
-
└─┬─┘
|
306
|
-
q_4: ──■────────────
|
307
240
|
|
308
|
-
|
309
|
-
|
241
|
+
def real_or_fail(value, tol=100):
|
242
|
+
"""Return real if close, otherwise fail. Unbound parameters are left unchanged.
|
310
243
|
|
311
|
-
|
312
|
-
A circuit implementing the CX chain.
|
244
|
+
Based on NumPy's ``real_if_close``, i.e. ``tol`` is in terms of machine precision for float.
|
313
245
|
"""
|
246
|
+
if isinstance(value, ParameterExpression):
|
247
|
+
return value
|
314
248
|
|
315
|
-
|
316
|
-
|
249
|
+
abstol = tol * np.finfo(float).eps
|
250
|
+
if abs(np.imag(value)) < abstol:
|
251
|
+
return np.real(value)
|
317
252
|
|
318
|
-
|
319
|
-
for i, pauli_i in enumerate(pauli.to_label()):
|
320
|
-
i = pauli.num_qubits - i - 1
|
321
|
-
if pauli_i != "I":
|
322
|
-
if control is None:
|
323
|
-
control = i
|
324
|
-
else:
|
325
|
-
target = i
|
253
|
+
raise ValueError(f"Encountered complex value {value}, but expected real.")
|
326
254
|
|
327
|
-
if control is not None and target is not None:
|
328
|
-
chain.cx(control, target)
|
329
|
-
control = i
|
330
|
-
target = None
|
331
255
|
|
332
|
-
|
256
|
+
def reorder_paulis(
|
257
|
+
paulis: Sequence[SparsePauliLabel],
|
258
|
+
strategy: rx.ColoringStrategy = rx.ColoringStrategy.Saturation,
|
259
|
+
) -> list[SparsePauliLabel]:
|
260
|
+
r"""
|
261
|
+
Creates an equivalent operator by reordering terms in order to yield a
|
262
|
+
shallower circuit after evolution synthesis. The original operator remains
|
263
|
+
unchanged.
|
333
264
|
|
265
|
+
This method works in three steps. First, a graph is constructed, where the
|
266
|
+
nodes are the terms of the operator and where two nodes are connected if
|
267
|
+
their terms act on the same qubit (for example, the terms :math:`IXX` and
|
268
|
+
:math:`IYI` would be connected, but not :math:`IXX` and :math:`YII`). Then,
|
269
|
+
the graph is colored. Two terms with the same color thus do not act on the
|
270
|
+
same qubit, and in particular, their evolution subcircuits can be run in
|
271
|
+
parallel in the greater evolution circuit of ``paulis``.
|
334
272
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
For example, for the Pauli with the label 'XYZIX'.
|
339
|
-
|
340
|
-
.. parsed-literal::
|
341
|
-
|
342
|
-
┌───┐┌───┐┌───┐
|
343
|
-
q_0: ┤ X ├┤ X ├┤ X ├
|
344
|
-
└─┬─┘└─┬─┘└─┬─┘
|
345
|
-
q_1: ──┼────┼────┼──
|
346
|
-
│ │ │
|
347
|
-
q_2: ──■────┼────┼──
|
348
|
-
│ │
|
349
|
-
q_3: ───────■────┼──
|
350
|
-
│
|
351
|
-
q_4: ────────────■──
|
273
|
+
This method is deterministic and invariant under permutation of the Pauli
|
274
|
+
term in ``paulis``.
|
352
275
|
|
353
276
|
Args:
|
354
|
-
|
277
|
+
paulis: The operator whose terms to reorder.
|
278
|
+
strategy: The coloring heuristic to use, see ``ColoringStrategy`` [#].
|
279
|
+
Default is ``ColoringStrategy.Saturation``.
|
280
|
+
|
281
|
+
.. [#] https://www.rustworkx.org/apiref/rustworkx.ColoringStrategy.html#coloringstrategy
|
355
282
|
|
356
|
-
Returns:
|
357
|
-
A circuit implementing the CX chain.
|
358
283
|
"""
|
359
284
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
285
|
+
def _term_sort_key(term: SparsePauliLabel) -> typing.Any:
|
286
|
+
# sort by index, then by pauli
|
287
|
+
return (term[1], term[0])
|
288
|
+
|
289
|
+
# Do nothing in trivial cases
|
290
|
+
if len(paulis) <= 1:
|
291
|
+
return paulis
|
292
|
+
|
293
|
+
terms = sorted(paulis, key=_term_sort_key)
|
294
|
+
graph = rx.PyGraph()
|
295
|
+
graph.add_nodes_from(terms)
|
296
|
+
indexed_nodes = list(enumerate(graph.nodes()))
|
297
|
+
for (idx1, (_, ind1, _)), (idx2, (_, ind2, _)) in combinations(indexed_nodes, 2):
|
298
|
+
# Add an edge between two terms if they touch the same qubit
|
299
|
+
if len(set(ind1).intersection(ind2)) > 0:
|
300
|
+
graph.add_edge(idx1, idx2, None)
|
301
|
+
|
302
|
+
# rx.graph_greedy_color is supposed to be deterministic
|
303
|
+
coloring = rx.graph_greedy_color(graph, strategy=strategy)
|
304
|
+
terms_by_color = defaultdict(list)
|
305
|
+
|
306
|
+
for term_idx, color in sorted(coloring.items()):
|
307
|
+
term = graph.nodes()[term_idx]
|
308
|
+
terms_by_color[color].append(term)
|
309
|
+
|
310
|
+
terms = list(itertools.chain(*terms_by_color.values()))
|
311
|
+
return terms
|
@@ -16,14 +16,19 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
import inspect
|
18
18
|
import math
|
19
|
+
import typing
|
20
|
+
from itertools import chain
|
19
21
|
from collections.abc import Callable
|
20
22
|
import numpy as np
|
21
23
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
22
24
|
from qiskit.quantum_info.operators import SparsePauliOp, Pauli
|
23
25
|
from qiskit.utils.deprecation import deprecate_arg
|
26
|
+
from qiskit.exceptions import QiskitError
|
24
27
|
|
25
|
-
from .product_formula import ProductFormula
|
26
|
-
|
28
|
+
from .product_formula import ProductFormula, reorder_paulis
|
29
|
+
|
30
|
+
if typing.TYPE_CHECKING:
|
31
|
+
from qiskit.circuit.library import PauliEvolutionGate
|
27
32
|
|
28
33
|
|
29
34
|
class QDrift(ProductFormula):
|
@@ -63,6 +68,7 @@ class QDrift(ProductFormula):
|
|
63
68
|
) = None,
|
64
69
|
seed: int | None = None,
|
65
70
|
wrap: bool = False,
|
71
|
+
preserve_order: bool = True,
|
66
72
|
) -> None:
|
67
73
|
r"""
|
68
74
|
Args:
|
@@ -83,49 +89,50 @@ class QDrift(ProductFormula):
|
|
83
89
|
seed: An optional seed for reproducibility of the random sampling process.
|
84
90
|
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
85
91
|
effect when ``atomic_evolution is None``.
|
92
|
+
preserve_order: If ``False``, allows reordering the terms of the operator to
|
93
|
+
potentially yield a shallower evolution circuit. Not relevant
|
94
|
+
when synthesizing operator with a single term.
|
86
95
|
"""
|
87
|
-
super().__init__(
|
96
|
+
super().__init__(
|
97
|
+
1, reps, insert_barriers, cx_structure, atomic_evolution, wrap, preserve_order
|
98
|
+
)
|
88
99
|
self.sampled_ops = None
|
89
100
|
self.rng = np.random.default_rng(seed)
|
90
101
|
|
91
|
-
def
|
92
|
-
# get operators and time to evolve
|
102
|
+
def expand(self, evolution: PauliEvolutionGate) -> list[tuple[str, tuple[int], float]]:
|
93
103
|
operators = evolution.operator
|
94
|
-
time = evolution.time
|
104
|
+
time = evolution.time # used to determine the number of gates
|
95
105
|
|
96
|
-
|
97
|
-
|
98
|
-
|
106
|
+
# QDrift is based on first-order Lie-Trotter, hence we can just concatenate all
|
107
|
+
# Pauli terms and ignore commutations
|
108
|
+
if isinstance(operators, list):
|
109
|
+
paulis = list(chain.from_iterable([op.to_sparse_list() for op in operators]))
|
99
110
|
else:
|
100
|
-
|
101
|
-
|
111
|
+
paulis = operators.to_sparse_list()
|
112
|
+
|
113
|
+
try:
|
114
|
+
coeffs = [float(np.real_if_close(coeff)) for _, _, coeff in paulis]
|
115
|
+
except TypeError as exc:
|
116
|
+
raise QiskitError("QDrift requires bound, real coefficients.") from exc
|
102
117
|
|
103
118
|
# We artificially make the weights positive
|
104
119
|
weights = np.abs(coeffs)
|
105
120
|
lambd = np.sum(weights)
|
106
121
|
|
107
122
|
num_gates = math.ceil(2 * (lambd**2) * (time**2) * self.reps)
|
123
|
+
|
108
124
|
# The protocol calls for the removal of the individual coefficients,
|
109
125
|
# and multiplication by a constant evolution time.
|
110
|
-
|
111
|
-
|
112
|
-
self.sampled_ops = self.rng.choice(
|
113
|
-
np.array(pauli_list, dtype=object),
|
114
|
-
size=(num_gates,),
|
115
|
-
p=weights / lambd,
|
126
|
+
sampled = self.rng.choice(
|
127
|
+
np.array(paulis, dtype=object), size=(num_gates,), p=weights / lambd
|
116
128
|
)
|
117
129
|
|
118
|
-
|
119
|
-
|
130
|
+
rescaled_time = 2 * lambd / num_gates * time
|
131
|
+
sampled_paulis = [
|
132
|
+
(pauli[0], pauli[1], np.real(np.sign(pauli[2])) * rescaled_time) for pauli in sampled
|
133
|
+
]
|
120
134
|
|
121
|
-
|
122
|
-
|
123
|
-
insert_barriers=self.insert_barriers, atomic_evolution=self.atomic_evolution
|
124
|
-
)
|
125
|
-
evolution_circuit = PauliEvolutionGate(
|
126
|
-
sum(SparsePauliOp(np.sign(coeff) * op) for op, coeff in self.sampled_ops),
|
127
|
-
time=evolution_time,
|
128
|
-
synthesis=lie_trotter,
|
129
|
-
).definition
|
135
|
+
if not self.preserve_order:
|
136
|
+
sampled_paulis = reorder_paulis(sampled_paulis)
|
130
137
|
|
131
|
-
return
|
138
|
+
return sampled_paulis
|