qiskit 1.1.2__cp38-abi3-macosx_10_9_universal2.whl → 1.2.0__cp38-abi3-macosx_10_9_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +27 -24
- qiskit/_accelerate.abi3.so +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
@@ -33,9 +33,10 @@ from qiskit.synthesis.linear import (
|
|
33
33
|
from qiskit.synthesis.linear_phase import synth_cz_depth_line_mr, synth_cx_cz_depth_line_my
|
34
34
|
from qiskit.synthesis.linear.linear_matrix_utils import (
|
35
35
|
calc_inverse_matrix,
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
compute_rank,
|
37
|
+
gauss_elimination,
|
38
|
+
gauss_elimination_with_perm,
|
39
|
+
binary_matmul,
|
39
40
|
)
|
40
41
|
|
41
42
|
|
@@ -137,32 +138,32 @@ def synth_clifford_layers(
|
|
137
138
|
cz_func_reverse_qubits=cz_func_reverse_qubits,
|
138
139
|
)
|
139
140
|
|
140
|
-
layeredCircuit.append(S2_circ, qubit_list)
|
141
|
+
layeredCircuit.append(S2_circ, qubit_list, copy=False)
|
141
142
|
|
142
143
|
if cx_cz_synth_func is None:
|
143
|
-
layeredCircuit.append(CZ2_circ, qubit_list)
|
144
|
+
layeredCircuit.append(CZ2_circ, qubit_list, copy=False)
|
144
145
|
|
145
146
|
CXinv = CX_circ.copy().inverse()
|
146
|
-
layeredCircuit.append(CXinv, qubit_list)
|
147
|
+
layeredCircuit.append(CXinv, qubit_list, copy=False)
|
147
148
|
|
148
149
|
else:
|
149
150
|
# note that CZ2_circ is None and built into the CX_circ when
|
150
151
|
# cx_cz_synth_func is not None
|
151
|
-
layeredCircuit.append(CX_circ, qubit_list)
|
152
|
+
layeredCircuit.append(CX_circ, qubit_list, copy=False)
|
152
153
|
|
153
|
-
layeredCircuit.append(H2_circ, qubit_list)
|
154
|
-
layeredCircuit.append(S1_circ, qubit_list)
|
155
|
-
layeredCircuit.append(CZ1_circ, qubit_list)
|
154
|
+
layeredCircuit.append(H2_circ, qubit_list, copy=False)
|
155
|
+
layeredCircuit.append(S1_circ, qubit_list, copy=False)
|
156
|
+
layeredCircuit.append(CZ1_circ, qubit_list, copy=False)
|
156
157
|
|
157
158
|
if cz_func_reverse_qubits:
|
158
159
|
H1_circ = H1_circ.reverse_bits()
|
159
|
-
layeredCircuit.append(H1_circ, qubit_list)
|
160
|
+
layeredCircuit.append(H1_circ, qubit_list, copy=False)
|
160
161
|
|
161
162
|
# Add Pauli layer to fix the Clifford phase signs
|
162
163
|
|
163
164
|
clifford_target = Clifford(layeredCircuit)
|
164
165
|
pauli_circ = _calc_pauli_diff(cliff, clifford_target)
|
165
|
-
layeredCircuit.append(pauli_circ, qubit_list)
|
166
|
+
layeredCircuit.append(pauli_circ, qubit_list, copy=False)
|
166
167
|
|
167
168
|
return layeredCircuit
|
168
169
|
|
@@ -203,24 +204,25 @@ def _create_graph_state(cliff, validate=False):
|
|
203
204
|
"""
|
204
205
|
|
205
206
|
num_qubits = cliff.num_qubits
|
206
|
-
rank =
|
207
|
+
rank = compute_rank(np.asarray(cliff.stab_x, dtype=bool))
|
207
208
|
H1_circ = QuantumCircuit(num_qubits, name="H1")
|
208
209
|
cliffh = cliff.copy()
|
209
210
|
|
210
211
|
if rank < num_qubits:
|
211
212
|
stab = cliff.stab[:, :-1]
|
212
|
-
stab =
|
213
|
+
stab = stab.astype(bool, copy=True)
|
214
|
+
gauss_elimination(stab, num_qubits)
|
213
215
|
|
214
216
|
Cmat = stab[rank:num_qubits, num_qubits:]
|
215
217
|
Cmat = np.transpose(Cmat)
|
216
|
-
|
218
|
+
perm = gauss_elimination_with_perm(Cmat)
|
217
219
|
perm = perm[0 : num_qubits - rank]
|
218
220
|
|
219
221
|
# validate that the output matrix has the same rank
|
220
222
|
if validate:
|
221
|
-
if
|
223
|
+
if compute_rank(Cmat) != num_qubits - rank:
|
222
224
|
raise QiskitError("The matrix Cmat after Gauss elimination has wrong rank.")
|
223
|
-
if
|
225
|
+
if compute_rank(stab[:, 0:num_qubits]) != rank:
|
224
226
|
raise QiskitError("The matrix after Gauss elimination has wrong rank.")
|
225
227
|
# validate that we have a num_qubits - rank zero rows
|
226
228
|
for i in range(rank, num_qubits):
|
@@ -236,8 +238,8 @@ def _create_graph_state(cliff, validate=False):
|
|
236
238
|
|
237
239
|
# validate that a layer of Hadamard gates and then appending cliff, provides a graph state.
|
238
240
|
if validate:
|
239
|
-
stabh = cliffh.stab_x
|
240
|
-
if
|
241
|
+
stabh = (cliffh.stab_x).astype(bool, copy=False)
|
242
|
+
if compute_rank(stabh) != num_qubits:
|
241
243
|
raise QiskitError("The state is not a graph state.")
|
242
244
|
|
243
245
|
return H1_circ, cliffh
|
@@ -267,7 +269,7 @@ def _decompose_graph_state(cliff, validate, cz_synth_func):
|
|
267
269
|
"""
|
268
270
|
|
269
271
|
num_qubits = cliff.num_qubits
|
270
|
-
rank =
|
272
|
+
rank = compute_rank(np.asarray(cliff.stab_x, dtype=bool))
|
271
273
|
cliff_cpy = cliff.copy()
|
272
274
|
if rank < num_qubits:
|
273
275
|
raise QiskitError("The stabilizer state is not a graph state.")
|
@@ -278,7 +280,7 @@ def _decompose_graph_state(cliff, validate, cz_synth_func):
|
|
278
280
|
stabx = cliff.stab_x
|
279
281
|
stabz = cliff.stab_z
|
280
282
|
stabx_inv = calc_inverse_matrix(stabx, validate)
|
281
|
-
stabz_update =
|
283
|
+
stabz_update = binary_matmul(stabx_inv, stabz)
|
282
284
|
|
283
285
|
# Assert that stabz_update is a symmetric matrix.
|
284
286
|
if validate:
|
@@ -340,7 +342,7 @@ def _decompose_hadamard_free(
|
|
340
342
|
if not (stabx == np.zeros((num_qubits, num_qubits))).all():
|
341
343
|
raise QiskitError("The given Clifford is not Hadamard-free.")
|
342
344
|
|
343
|
-
destabz_update =
|
345
|
+
destabz_update = binary_matmul(calc_inverse_matrix(destabx), destabz)
|
344
346
|
# Assert that destabz_update is a symmetric matrix.
|
345
347
|
if validate:
|
346
348
|
if (destabz_update != destabz_update.T).any():
|
@@ -412,7 +414,7 @@ def _calc_pauli_diff(cliff, cliff_target):
|
|
412
414
|
|
413
415
|
|
414
416
|
def synth_clifford_depth_lnn(cliff):
|
415
|
-
"""Synthesis of a :class:`.Clifford` into layers for linear-nearest
|
417
|
+
"""Synthesis of a :class:`.Clifford` into layers for linear-nearest neighbor connectivity.
|
416
418
|
|
417
419
|
The depth of the synthesized n-qubit circuit is bounded by :math:`7n+2`, which is not optimal.
|
418
420
|
It should be replaced by a better algorithm that provides depth bounded by :math:`7n-4` [3].
|
@@ -40,7 +40,7 @@ def synth_cnotdihedral_full(elem: CNOTDihedral) -> QuantumCircuit:
|
|
40
40
|
with optimal number of two qubit gates*, `Quantum 4(369), 2020
|
41
41
|
<https://quantum-journal.org/papers/q-2020-12-07-369/>`_
|
42
42
|
2. Andrew W. Cross, Easwar Magesan, Lev S. Bishop, John A. Smolin and Jay M. Gambetta,
|
43
|
-
*Scalable
|
43
|
+
*Scalable randomized benchmarking of non-Clifford gates*,
|
44
44
|
npj Quantum Inf 2, 16012 (2016).
|
45
45
|
"""
|
46
46
|
|
@@ -38,7 +38,7 @@ def synth_cnotdihedral_general(elem: CNOTDihedral) -> QuantumCircuit:
|
|
38
38
|
|
39
39
|
References:
|
40
40
|
1. Andrew W. Cross, Easwar Magesan, Lev S. Bishop, John A. Smolin and Jay M. Gambetta,
|
41
|
-
*Scalable
|
41
|
+
*Scalable randomized benchmarking of non-Clifford gates*,
|
42
42
|
npj Quantum Inf 2, 16012 (2016).
|
43
43
|
"""
|
44
44
|
|
@@ -137,7 +137,7 @@ def generate_basic_approximations(
|
|
137
137
|
basis = []
|
138
138
|
for gate in basis_gates:
|
139
139
|
if isinstance(gate, str):
|
140
|
-
if gate not in _1q_gates
|
140
|
+
if gate not in _1q_gates:
|
141
141
|
raise ValueError(f"Invalid gate identifier: {gate}")
|
142
142
|
basis.append(gate)
|
143
143
|
else: # gate is a qiskit.circuit.Gate
|
@@ -119,7 +119,7 @@ class SolovayKitaevDecomposition:
|
|
119
119
|
gate_matrix_su2 = GateSequence.from_matrix(z * gate_matrix)
|
120
120
|
global_phase = np.arctan2(np.imag(z), np.real(z))
|
121
121
|
|
122
|
-
# get the
|
122
|
+
# get the decomposition as GateSequence type
|
123
123
|
decomposition = self._recurse(gate_matrix_su2, recursion_degree, check_input=check_input)
|
124
124
|
|
125
125
|
# simplify
|
@@ -190,7 +190,7 @@ def _remove_inverse_follows_gate(sequence):
|
|
190
190
|
while index < len(sequence.gates) - 1:
|
191
191
|
curr_gate = sequence.gates[index]
|
192
192
|
next_gate = sequence.gates[index + 1]
|
193
|
-
if curr_gate.name in _1q_inverses
|
193
|
+
if curr_gate.name in _1q_inverses:
|
194
194
|
remove = _1q_inverses[curr_gate.name] == next_gate.name
|
195
195
|
else:
|
196
196
|
remove = curr_gate.inverse() == next_gate
|
@@ -12,8 +12,10 @@
|
|
12
12
|
|
13
13
|
"""Evolution synthesis."""
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
from abc import ABC, abstractmethod
|
16
|
-
from typing import Any
|
18
|
+
from typing import Any
|
17
19
|
|
18
20
|
|
19
21
|
class EvolutionSynthesis(ABC):
|
@@ -32,7 +34,7 @@ class EvolutionSynthesis(ABC):
|
|
32
34
|
raise NotImplementedError
|
33
35
|
|
34
36
|
@property
|
35
|
-
def settings(self) ->
|
37
|
+
def settings(self) -> dict[str, Any]:
|
36
38
|
"""Return the settings in a dictionary, which can be used to reconstruct the object.
|
37
39
|
|
38
40
|
Returns:
|
@@ -12,10 +12,15 @@
|
|
12
12
|
|
13
13
|
"""The Lie-Trotter product formula."""
|
14
14
|
|
15
|
-
from
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import inspect
|
18
|
+
from collections.abc import Callable
|
19
|
+
from typing import Any
|
16
20
|
import numpy as np
|
17
21
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
18
22
|
from qiskit.quantum_info.operators import SparsePauliOp, Pauli
|
23
|
+
from qiskit.utils.deprecation import deprecate_arg
|
19
24
|
|
20
25
|
from .product_formula import ProductFormula
|
21
26
|
|
@@ -47,14 +52,32 @@ class LieTrotter(ProductFormula):
|
|
47
52
|
`arXiv:math-ph/0506007 <https://arxiv.org/pdf/math-ph/0506007.pdf>`_
|
48
53
|
"""
|
49
54
|
|
55
|
+
@deprecate_arg(
|
56
|
+
name="atomic_evolution",
|
57
|
+
since="1.2",
|
58
|
+
predicate=lambda callable: callable is not None
|
59
|
+
and len(inspect.signature(callable).parameters) == 2,
|
60
|
+
deprecation_description=(
|
61
|
+
"The 'Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]' signature of the "
|
62
|
+
"'atomic_evolution' argument"
|
63
|
+
),
|
64
|
+
additional_msg=(
|
65
|
+
"Instead you should update your 'atomic_evolution' function to be of the following "
|
66
|
+
"type: 'Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]'."
|
67
|
+
),
|
68
|
+
pending=True,
|
69
|
+
)
|
50
70
|
def __init__(
|
51
71
|
self,
|
52
72
|
reps: int = 1,
|
53
73
|
insert_barriers: bool = False,
|
54
74
|
cx_structure: str = "chain",
|
55
|
-
atomic_evolution:
|
56
|
-
Callable[[
|
57
|
-
|
75
|
+
atomic_evolution: (
|
76
|
+
Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]
|
77
|
+
| Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
78
|
+
| None
|
79
|
+
) = None,
|
80
|
+
wrap: bool = False,
|
58
81
|
) -> None:
|
59
82
|
"""
|
60
83
|
Args:
|
@@ -62,12 +85,20 @@ class LieTrotter(ProductFormula):
|
|
62
85
|
insert_barriers: Whether to insert barriers between the atomic evolutions.
|
63
86
|
cx_structure: How to arrange the CX gates for the Pauli evolutions, can be
|
64
87
|
``"chain"``, where next neighbor connections are used, or ``"fountain"``,
|
65
|
-
where all qubits are connected to one.
|
66
|
-
|
67
|
-
|
68
|
-
|
88
|
+
where all qubits are connected to one. This only takes effect when
|
89
|
+
``atomic_evolution is None``.
|
90
|
+
atomic_evolution: A function to apply the evolution of a single :class:`.Pauli`, or
|
91
|
+
:class:`.SparsePauliOp` of only commuting terms, to a circuit. The function takes in
|
92
|
+
three arguments: the circuit to append the evolution to, the Pauli operator to
|
93
|
+
evolve, and the evolution time. By default, a single Pauli evolution is decomposed
|
94
|
+
into a chain of ``CX`` gates and a single ``RZ`` gate.
|
95
|
+
Alternatively, the function can also take Pauli operator and evolution time as
|
96
|
+
inputs and returns the circuit that will be appended to the overall circuit being
|
97
|
+
built.
|
98
|
+
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
99
|
+
effect when ``atomic_evolution is None``.
|
69
100
|
"""
|
70
|
-
super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution)
|
101
|
+
super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution, wrap)
|
71
102
|
|
72
103
|
def synthesize(self, evolution):
|
73
104
|
# get operators and time to evolve
|
@@ -75,27 +106,22 @@ class LieTrotter(ProductFormula):
|
|
75
106
|
time = evolution.time
|
76
107
|
|
77
108
|
# construct the evolution circuit
|
78
|
-
|
109
|
+
single_rep = QuantumCircuit(operators[0].num_qubits)
|
79
110
|
|
80
111
|
if not isinstance(operators, list):
|
81
112
|
pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operators.to_list()]
|
82
113
|
else:
|
83
114
|
pauli_list = [(op, 1) for op in operators]
|
84
115
|
|
85
|
-
# if we only evolve a single Pauli we don't need to additionally wrap it
|
86
|
-
wrap = not (len(pauli_list) == 1 and self.reps == 1)
|
87
|
-
|
88
116
|
for i, (op, coeff) in enumerate(pauli_list):
|
89
|
-
|
90
|
-
self.atomic_evolution(op, coeff * time / self.reps), wrap=wrap, inplace=True
|
91
|
-
)
|
117
|
+
self.atomic_evolution(single_rep, op, coeff * time / self.reps)
|
92
118
|
if self.insert_barriers and i != len(pauli_list) - 1:
|
93
|
-
|
119
|
+
single_rep.barrier()
|
94
120
|
|
95
|
-
return
|
121
|
+
return single_rep.repeat(self.reps, insert_barriers=self.insert_barriers).decompose()
|
96
122
|
|
97
123
|
@property
|
98
|
-
def settings(self) ->
|
124
|
+
def settings(self) -> dict[str, Any]:
|
99
125
|
"""Return the settings in a dictionary, which can be used to reconstruct the object.
|
100
126
|
|
101
127
|
Returns:
|
@@ -113,4 +139,5 @@ class LieTrotter(ProductFormula):
|
|
113
139
|
"reps": self.reps,
|
114
140
|
"insert_barriers": self.insert_barriers,
|
115
141
|
"cx_structure": self._cx_structure,
|
142
|
+
"wrap": self._wrap,
|
116
143
|
}
|
@@ -12,12 +12,17 @@
|
|
12
12
|
|
13
13
|
"""A product formula base for decomposing non-commuting operator exponentials."""
|
14
14
|
|
15
|
-
from
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import inspect
|
18
|
+
from collections.abc import Callable
|
19
|
+
from typing import Any
|
16
20
|
from functools import partial
|
17
21
|
import numpy as np
|
18
22
|
from qiskit.circuit.parameterexpression import ParameterExpression
|
19
23
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
20
24
|
from qiskit.quantum_info import SparsePauliOp, Pauli
|
25
|
+
from qiskit.utils.deprecation import deprecate_arg
|
21
26
|
|
22
27
|
from .evolution_synthesis import EvolutionSynthesis
|
23
28
|
|
@@ -28,15 +33,33 @@ class ProductFormula(EvolutionSynthesis):
|
|
28
33
|
:obj:`.LieTrotter` and :obj:`.SuzukiTrotter` inherit from this class.
|
29
34
|
"""
|
30
35
|
|
36
|
+
@deprecate_arg(
|
37
|
+
name="atomic_evolution",
|
38
|
+
since="1.2",
|
39
|
+
predicate=lambda callable: callable is not None
|
40
|
+
and len(inspect.signature(callable).parameters) == 2,
|
41
|
+
deprecation_description=(
|
42
|
+
"The 'Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]' signature of the "
|
43
|
+
"'atomic_evolution' argument"
|
44
|
+
),
|
45
|
+
additional_msg=(
|
46
|
+
"Instead you should update your 'atomic_evolution' function to be of the following "
|
47
|
+
"type: 'Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]'."
|
48
|
+
),
|
49
|
+
pending=True,
|
50
|
+
)
|
31
51
|
def __init__(
|
32
52
|
self,
|
33
53
|
order: int,
|
34
54
|
reps: int = 1,
|
35
55
|
insert_barriers: bool = False,
|
36
56
|
cx_structure: str = "chain",
|
37
|
-
atomic_evolution:
|
38
|
-
Callable[[
|
39
|
-
|
57
|
+
atomic_evolution: (
|
58
|
+
Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]
|
59
|
+
| Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
60
|
+
| None
|
61
|
+
) = None,
|
62
|
+
wrap: bool = False,
|
40
63
|
) -> None:
|
41
64
|
"""
|
42
65
|
Args:
|
@@ -45,10 +68,18 @@ class ProductFormula(EvolutionSynthesis):
|
|
45
68
|
insert_barriers: Whether to insert barriers between the atomic evolutions.
|
46
69
|
cx_structure: How to arrange the CX gates for the Pauli evolutions, can be
|
47
70
|
``"chain"``, where next neighbor connections are used, or ``"fountain"``,
|
48
|
-
where all qubits are connected to one.
|
49
|
-
|
50
|
-
|
51
|
-
|
71
|
+
where all qubits are connected to one. This only takes effect when
|
72
|
+
``atomic_evolution is None``.
|
73
|
+
atomic_evolution: A function to apply the evolution of a single :class:`.Pauli`, or
|
74
|
+
:class:`.SparsePauliOp` of only commuting terms, to a circuit. The function takes in
|
75
|
+
three arguments: the circuit to append the evolution to, the Pauli operator to
|
76
|
+
evolve, and the evolution time. By default, a single Pauli evolution is decomposed
|
77
|
+
into a chain of ``CX`` gates and a single ``RZ`` gate.
|
78
|
+
Alternatively, the function can also take Pauli operator and evolution time as
|
79
|
+
inputs and returns the circuit that will be appended to the overall circuit being
|
80
|
+
built.
|
81
|
+
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
82
|
+
effect when ``atomic_evolution is None``.
|
52
83
|
"""
|
53
84
|
super().__init__()
|
54
85
|
self.order = order
|
@@ -58,15 +89,27 @@ class ProductFormula(EvolutionSynthesis):
|
|
58
89
|
# user-provided atomic evolution, stored for serialization
|
59
90
|
self._atomic_evolution = atomic_evolution
|
60
91
|
self._cx_structure = cx_structure
|
92
|
+
self._wrap = wrap
|
61
93
|
|
62
94
|
# if atomic evolution is not provided, set a default
|
63
95
|
if atomic_evolution is None:
|
64
|
-
atomic_evolution = partial(
|
96
|
+
self.atomic_evolution = partial(
|
97
|
+
_default_atomic_evolution, cx_structure=cx_structure, wrap=wrap
|
98
|
+
)
|
99
|
+
|
100
|
+
elif len(inspect.signature(atomic_evolution).parameters) == 2:
|
101
|
+
|
102
|
+
def wrap_atomic_evolution(output, operator, time):
|
103
|
+
definition = atomic_evolution(operator, time)
|
104
|
+
output.compose(definition, wrap=wrap, inplace=True)
|
105
|
+
|
106
|
+
self.atomic_evolution = wrap_atomic_evolution
|
65
107
|
|
66
|
-
|
108
|
+
else:
|
109
|
+
self.atomic_evolution = atomic_evolution
|
67
110
|
|
68
111
|
@property
|
69
|
-
def settings(self) ->
|
112
|
+
def settings(self) -> dict[str, Any]:
|
70
113
|
"""Return the settings in a dictionary, which can be used to reconstruct the object.
|
71
114
|
|
72
115
|
Returns:
|
@@ -85,15 +128,18 @@ class ProductFormula(EvolutionSynthesis):
|
|
85
128
|
"reps": self.reps,
|
86
129
|
"insert_barriers": self.insert_barriers,
|
87
130
|
"cx_structure": self._cx_structure,
|
131
|
+
"wrap": self._wrap,
|
88
132
|
}
|
89
133
|
|
90
134
|
|
91
135
|
def evolve_pauli(
|
136
|
+
output: QuantumCircuit,
|
92
137
|
pauli: Pauli,
|
93
|
-
time:
|
138
|
+
time: float | ParameterExpression = 1.0,
|
94
139
|
cx_structure: str = "chain",
|
95
|
-
|
96
|
-
|
140
|
+
wrap: bool = False,
|
141
|
+
label: str | None = None,
|
142
|
+
) -> None:
|
97
143
|
r"""Construct a circuit implementing the time evolution of a single Pauli string.
|
98
144
|
|
99
145
|
For a Pauli string :math:`P = \{I, X, Y, Z\}^{\otimes n}` on :math:`n` qubits and an
|
@@ -106,79 +152,91 @@ def evolve_pauli(
|
|
106
152
|
Since only a single Pauli string is evolved the circuit decomposition is exact.
|
107
153
|
|
108
154
|
Args:
|
155
|
+
output: The circuit object to which to append the evolved Pauli.
|
109
156
|
pauli: The Pauli to evolve.
|
110
157
|
time: The evolution time.
|
111
158
|
cx_structure: Determine the structure of CX gates, can be either ``"chain"`` for
|
112
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.
|
113
161
|
label: A label for the gate.
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
A quantum circuit implementing the time evolution of the Pauli.
|
117
162
|
"""
|
118
163
|
num_non_identity = len([label for label in pauli.to_label() if label != "I"])
|
119
164
|
|
120
165
|
# first check, if the Pauli is only the identity, in which case the evolution only
|
121
166
|
# adds a global phase
|
122
167
|
if num_non_identity == 0:
|
123
|
-
|
168
|
+
output.global_phase -= time
|
124
169
|
# if we evolve on a single qubit, if yes use the corresponding qubit rotation
|
125
170
|
elif num_non_identity == 1:
|
126
|
-
|
171
|
+
_single_qubit_evolution(output, pauli, time, wrap)
|
127
172
|
# same for two qubits, use Qiskit's native rotations
|
128
173
|
elif num_non_identity == 2:
|
129
|
-
|
174
|
+
_two_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
130
175
|
# otherwise do basis transformation and CX chains
|
131
176
|
else:
|
132
|
-
|
133
|
-
|
134
|
-
definition.name = f"exp(it {pauli.to_label()})"
|
177
|
+
_multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
135
178
|
|
136
|
-
return definition
|
137
179
|
|
138
|
-
|
139
|
-
|
140
|
-
definition = QuantumCircuit(pauli.num_qubits)
|
180
|
+
def _single_qubit_evolution(output, pauli, time, wrap):
|
181
|
+
dest = QuantumCircuit(1) if wrap else output
|
141
182
|
# Note that all phases are removed from the pauli label and are only in the coefficients.
|
142
183
|
# That's because the operators we evolved have all been translated to a SparsePauliOp.
|
184
|
+
qubits = []
|
185
|
+
label = ""
|
143
186
|
for i, pauli_i in enumerate(reversed(pauli.to_label())):
|
187
|
+
idx = 0 if wrap else i
|
144
188
|
if pauli_i == "X":
|
145
|
-
|
189
|
+
dest.rx(2 * time, idx)
|
190
|
+
qubits.append(i)
|
191
|
+
label += "X"
|
146
192
|
elif pauli_i == "Y":
|
147
|
-
|
193
|
+
dest.ry(2 * time, idx)
|
194
|
+
qubits.append(i)
|
195
|
+
label += "Y"
|
148
196
|
elif pauli_i == "Z":
|
149
|
-
|
197
|
+
dest.rz(2 * time, idx)
|
198
|
+
qubits.append(i)
|
199
|
+
label += "Z"
|
150
200
|
|
151
|
-
|
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)
|
152
205
|
|
153
206
|
|
154
|
-
def _two_qubit_evolution(pauli, time, cx_structure):
|
207
|
+
def _two_qubit_evolution(output, pauli, time, cx_structure, wrap):
|
155
208
|
# Get the Paulis and the qubits they act on.
|
156
209
|
# Note that all phases are removed from the pauli label and are only in the coefficients.
|
157
210
|
# That's because the operators we evolved have all been translated to a SparsePauliOp.
|
158
211
|
labels_as_array = np.array(list(reversed(pauli.to_label())))
|
159
212
|
qubits = np.where(labels_as_array != "I")[0]
|
213
|
+
indices = [0, 1] if wrap else qubits
|
160
214
|
labels = np.array([labels_as_array[idx] for idx in qubits])
|
161
215
|
|
162
|
-
|
216
|
+
dest = QuantumCircuit(2) if wrap else output
|
163
217
|
|
164
218
|
# go through all cases we have implemented in Qiskit
|
165
219
|
if all(labels == "X"): # RXX
|
166
|
-
|
220
|
+
dest.rxx(2 * time, indices[0], indices[1])
|
167
221
|
elif all(labels == "Y"): # RYY
|
168
|
-
|
222
|
+
dest.ryy(2 * time, indices[0], indices[1])
|
169
223
|
elif all(labels == "Z"): # RZZ
|
170
|
-
|
224
|
+
dest.rzz(2 * time, indices[0], indices[1])
|
171
225
|
elif labels[0] == "Z" and labels[1] == "X": # RZX
|
172
|
-
|
226
|
+
dest.rzx(2 * time, indices[0], indices[1])
|
173
227
|
elif labels[0] == "X" and labels[1] == "Z": # RXZ
|
174
|
-
|
228
|
+
dest.rzx(2 * time, indices[1], indices[0])
|
175
229
|
else: # all the others are not native in Qiskit, so use default the decomposition
|
176
|
-
|
230
|
+
_multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
|
231
|
+
return
|
177
232
|
|
178
|
-
|
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)
|
179
237
|
|
180
238
|
|
181
|
-
def _multi_qubit_evolution(pauli, time, cx_structure):
|
239
|
+
def _multi_qubit_evolution(output, pauli, time, cx_structure, wrap):
|
182
240
|
# get diagonalizing clifford
|
183
241
|
cliff = diagonalizing_clifford(pauli)
|
184
242
|
|
@@ -198,14 +256,16 @@ def _multi_qubit_evolution(pauli, time, cx_structure):
|
|
198
256
|
break
|
199
257
|
|
200
258
|
# build the evolution as: diagonalization, reduction, 1q evolution, followed by inverses
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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)
|
207
265
|
|
208
|
-
|
266
|
+
if wrap:
|
267
|
+
gate = dest.to_gate(label=f"exp(it {pauli.to_label()})")
|
268
|
+
output.append(gate, qargs=output.qubits, copy=False)
|
209
269
|
|
210
270
|
|
211
271
|
def diagonalizing_clifford(pauli: Pauli) -> QuantumCircuit:
|
@@ -313,16 +373,12 @@ def cnot_fountain(pauli: Pauli) -> QuantumCircuit:
|
|
313
373
|
return chain
|
314
374
|
|
315
375
|
|
316
|
-
def _default_atomic_evolution(operator, time, cx_structure):
|
376
|
+
def _default_atomic_evolution(output, operator, time, cx_structure, wrap):
|
317
377
|
if isinstance(operator, Pauli):
|
318
378
|
# single Pauli operator: just exponentiate it
|
319
|
-
|
379
|
+
evolve_pauli(output, operator, time, cx_structure, wrap)
|
320
380
|
else:
|
321
381
|
# sum of Pauli operators: exponentiate each term (this assumes they commute)
|
322
382
|
pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operator.to_list()]
|
323
|
-
name = f"exp(it {[pauli.to_label() for pauli, _ in pauli_list]})"
|
324
|
-
evolution_circuit = QuantumCircuit(operator.num_qubits, name=name)
|
325
383
|
for pauli, coeff in pauli_list:
|
326
|
-
|
327
|
-
|
328
|
-
return evolution_circuit
|
384
|
+
evolve_pauli(output, pauli, coeff * time, cx_structure, wrap)
|