qiskit 1.1.1__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/__init__.py +8 -0
- 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 +158 -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 -385
- 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 +197 -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 +113 -12
- 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 +519 -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 +12 -20
- 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 +14 -12
- 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 +2 -2
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +24 -14
- 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 +6 -5
- qiskit/transpiler/basepasses.py +1 -1
- qiskit/transpiler/coupling.py +3 -3
- qiskit/transpiler/instruction_durations.py +1 -2
- qiskit/transpiler/layout.py +6 -6
- 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_cliffords.py +6 -15
- 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/pauli_2q_evolution_commutation.py +5 -1
- 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 +83 -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 +62 -24
- 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 +12 -5
- qiskit/visualization/pass_manager_visualization.py +9 -9
- 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.1.dist-info → qiskit-1.2.0.dist-info}/METADATA +28 -28
- {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/RECORD +346 -344
- {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/WHEEL +1 -1
- {qiskit-1.1.1.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.1.dist-info → qiskit-1.2.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/top_level.txt +0 -0
@@ -28,15 +28,15 @@ from qiskit.circuit import QuantumCircuit
|
|
28
28
|
from qiskit.synthesis.linear.linear_matrix_utils import (
|
29
29
|
calc_inverse_matrix,
|
30
30
|
check_invertible_binary_matrix,
|
31
|
-
|
32
|
-
|
31
|
+
col_op,
|
32
|
+
row_op,
|
33
33
|
)
|
34
34
|
|
35
35
|
|
36
36
|
def _row_op_update_instructions(cx_instructions, mat, a, b):
|
37
37
|
# Add a cx gate to the instructions and update the matrix mat
|
38
38
|
cx_instructions.append((a, b))
|
39
|
-
|
39
|
+
row_op(mat, a, b)
|
40
40
|
|
41
41
|
|
42
42
|
def _get_lower_triangular(n, mat, mat_inv):
|
@@ -62,7 +62,7 @@ def _get_lower_triangular(n, mat, mat_inv):
|
|
62
62
|
first_j = j
|
63
63
|
else:
|
64
64
|
# cx_instructions_cols (L instructions) are not needed
|
65
|
-
|
65
|
+
col_op(mat, j, first_j)
|
66
66
|
# Use row operations directed upwards to zero out all "1"s above the remaining "1" in row i
|
67
67
|
for k in reversed(range(0, i)):
|
68
68
|
if mat[k, first_j]:
|
@@ -70,8 +70,8 @@ def _get_lower_triangular(n, mat, mat_inv):
|
|
70
70
|
|
71
71
|
# Apply only U instructions to get the permuted L
|
72
72
|
for inst in cx_instructions_rows:
|
73
|
-
|
74
|
-
|
73
|
+
row_op(mat_t, inst[0], inst[1])
|
74
|
+
col_op(mat_inv_t, inst[0], inst[1])
|
75
75
|
return mat_t, mat_inv_t
|
76
76
|
|
77
77
|
|
@@ -210,7 +210,7 @@ def _north_west_to_identity(n, mat):
|
|
210
210
|
def _optimize_cx_circ_depth_5n_line(mat):
|
211
211
|
# Optimize CX circuit in depth bounded by 5n for LNN connectivity.
|
212
212
|
# The algorithm [1] has two steps:
|
213
|
-
# a) transform the
|
213
|
+
# a) transform the original matrix to a north-west matrix (m2nw),
|
214
214
|
# b) transform the north-west matrix to identity (nw2id).
|
215
215
|
#
|
216
216
|
# A square n-by-n matrix A is called north-west if A[i][j]=0 for all i+j>=n
|
@@ -222,7 +222,7 @@ def _optimize_cx_circ_depth_5n_line(mat):
|
|
222
222
|
|
223
223
|
# According to [1] the synthesis is done on the inverse matrix
|
224
224
|
# so the matrix mat is inverted at this step
|
225
|
-
mat_inv = mat.copy
|
225
|
+
mat_inv = mat.astype(bool, copy=True)
|
226
226
|
mat_cpy = calc_inverse_matrix(mat_inv)
|
227
227
|
|
228
228
|
n = len(mat_cpy)
|
@@ -12,164 +12,16 @@
|
|
12
12
|
|
13
13
|
"""Utility functions for handling binary matrices."""
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
"""
|
29
|
-
if len(mat.shape) != 2 or mat.shape[0] != mat.shape[1]:
|
30
|
-
return False
|
31
|
-
|
32
|
-
rank = _compute_rank(mat)
|
33
|
-
return rank == mat.shape[0]
|
34
|
-
|
35
|
-
|
36
|
-
def random_invertible_binary_matrix(
|
37
|
-
num_qubits: int, seed: Optional[Union[np.random.Generator, int]] = None
|
38
|
-
):
|
39
|
-
"""Generates a random invertible n x n binary matrix.
|
40
|
-
|
41
|
-
Args:
|
42
|
-
num_qubits: the matrix size.
|
43
|
-
seed: a random seed.
|
44
|
-
|
45
|
-
Returns:
|
46
|
-
np.ndarray: A random invertible binary matrix of size num_qubits.
|
47
|
-
"""
|
48
|
-
if isinstance(seed, np.random.Generator):
|
49
|
-
rng = seed
|
50
|
-
else:
|
51
|
-
rng = np.random.default_rng(seed)
|
52
|
-
|
53
|
-
rank = 0
|
54
|
-
while rank != num_qubits:
|
55
|
-
mat = rng.integers(2, size=(num_qubits, num_qubits))
|
56
|
-
rank = _compute_rank(mat)
|
57
|
-
return mat
|
58
|
-
|
59
|
-
|
60
|
-
def _gauss_elimination(mat, ncols=None, full_elim=False):
|
61
|
-
"""Gauss elimination of a matrix mat with m rows and n columns.
|
62
|
-
If full_elim = True, it allows full elimination of mat[:, 0 : ncols]
|
63
|
-
Returns the matrix mat."""
|
64
|
-
|
65
|
-
mat, _ = _gauss_elimination_with_perm(mat, ncols, full_elim)
|
66
|
-
return mat
|
67
|
-
|
68
|
-
|
69
|
-
def _gauss_elimination_with_perm(mat, ncols=None, full_elim=False):
|
70
|
-
"""Gauss elimination of a matrix mat with m rows and n columns.
|
71
|
-
If full_elim = True, it allows full elimination of mat[:, 0 : ncols]
|
72
|
-
Returns the matrix mat, and the permutation perm that was done on the rows during the process.
|
73
|
-
perm[0 : rank] represents the indices of linearly independent rows in the original matrix."""
|
74
|
-
|
75
|
-
# Treat the matrix A as containing integer values
|
76
|
-
mat = np.array(mat, dtype=int, copy=True)
|
77
|
-
|
78
|
-
m = mat.shape[0] # no. of rows
|
79
|
-
n = mat.shape[1] # no. of columns
|
80
|
-
if ncols is not None:
|
81
|
-
n = min(n, ncols) # no. of active columns
|
82
|
-
|
83
|
-
perm = np.array(range(m)) # permutation on the rows
|
84
|
-
|
85
|
-
r = 0 # current rank
|
86
|
-
k = 0 # current pivot column
|
87
|
-
while (r < m) and (k < n):
|
88
|
-
is_non_zero = False
|
89
|
-
new_r = r
|
90
|
-
for j in range(k, n):
|
91
|
-
for i in range(r, m):
|
92
|
-
if mat[i][j]:
|
93
|
-
is_non_zero = True
|
94
|
-
k = j
|
95
|
-
new_r = i
|
96
|
-
break
|
97
|
-
if is_non_zero:
|
98
|
-
break
|
99
|
-
if not is_non_zero:
|
100
|
-
return mat, perm # A is in the canonical form
|
101
|
-
|
102
|
-
if new_r != r:
|
103
|
-
mat[[r, new_r]] = mat[[new_r, r]]
|
104
|
-
perm[r], perm[new_r] = perm[new_r], perm[r]
|
105
|
-
|
106
|
-
if full_elim:
|
107
|
-
for i in range(0, r):
|
108
|
-
if mat[i][k]:
|
109
|
-
mat[i] = mat[i] ^ mat[r]
|
110
|
-
|
111
|
-
for i in range(r + 1, m):
|
112
|
-
if mat[i][k]:
|
113
|
-
mat[i] = mat[i] ^ mat[r]
|
114
|
-
r += 1
|
115
|
-
|
116
|
-
return mat, perm
|
117
|
-
|
118
|
-
|
119
|
-
def calc_inverse_matrix(mat: np.ndarray, verify: bool = False):
|
120
|
-
"""Given a square numpy(dtype=int) matrix mat, tries to compute its inverse.
|
121
|
-
|
122
|
-
Args:
|
123
|
-
mat: a boolean square matrix.
|
124
|
-
verify: if True asserts that the multiplication of mat and its inverse is the identity matrix.
|
125
|
-
|
126
|
-
Returns:
|
127
|
-
np.ndarray: the inverse matrix.
|
128
|
-
|
129
|
-
Raises:
|
130
|
-
QiskitError: if the matrix is not square.
|
131
|
-
QiskitError: if the matrix is not invertible.
|
132
|
-
"""
|
133
|
-
|
134
|
-
if mat.shape[0] != mat.shape[1]:
|
135
|
-
raise QiskitError("Matrix to invert is a non-square matrix.")
|
136
|
-
|
137
|
-
n = mat.shape[0]
|
138
|
-
# concatenate the matrix and identity
|
139
|
-
mat1 = np.concatenate((mat, np.eye(n, dtype=int)), axis=1)
|
140
|
-
mat1 = _gauss_elimination(mat1, None, full_elim=True)
|
141
|
-
|
142
|
-
r = _compute_rank_after_gauss_elim(mat1[:, 0:n])
|
143
|
-
|
144
|
-
if r < n:
|
145
|
-
raise QiskitError("The matrix is not invertible.")
|
146
|
-
|
147
|
-
matinv = mat1[:, n : 2 * n]
|
148
|
-
|
149
|
-
if verify:
|
150
|
-
mat2 = np.dot(mat, matinv) % 2
|
151
|
-
assert np.array_equal(mat2, np.eye(n))
|
152
|
-
|
153
|
-
return matinv
|
154
|
-
|
155
|
-
|
156
|
-
def _compute_rank_after_gauss_elim(mat):
|
157
|
-
"""Given a matrix A after Gaussian elimination, computes its rank
|
158
|
-
(i.e. simply the number of nonzero rows)"""
|
159
|
-
return np.sum(mat.any(axis=1))
|
160
|
-
|
161
|
-
|
162
|
-
def _compute_rank(mat):
|
163
|
-
"""Given a matrix A computes its rank"""
|
164
|
-
mat = _gauss_elimination(mat)
|
165
|
-
return np.sum(mat.any(axis=1))
|
166
|
-
|
167
|
-
|
168
|
-
def _row_op(mat, ctrl, trgt):
|
169
|
-
# Perform ROW operation on a matrix mat
|
170
|
-
mat[trgt] = mat[trgt] ^ mat[ctrl]
|
171
|
-
|
172
|
-
|
173
|
-
def _col_op(mat, ctrl, trgt):
|
174
|
-
# Perform COL operation on a matrix mat
|
175
|
-
mat[:, ctrl] = mat[:, trgt] ^ mat[:, ctrl]
|
15
|
+
# pylint: disable=unused-import
|
16
|
+
from qiskit._accelerate.synthesis.linear import (
|
17
|
+
gauss_elimination,
|
18
|
+
gauss_elimination_with_perm,
|
19
|
+
compute_rank_after_gauss_elim,
|
20
|
+
compute_rank,
|
21
|
+
calc_inverse_matrix,
|
22
|
+
binary_matmul,
|
23
|
+
random_invertible_binary_matrix,
|
24
|
+
check_invertible_binary_matrix,
|
25
|
+
row_op,
|
26
|
+
col_op,
|
27
|
+
)
|
@@ -123,7 +123,7 @@ def synth_cnot_phase_aam(
|
|
123
123
|
|
124
124
|
# Implementation of the pseudo-code (Algorithm 1) in the aforementioned paper
|
125
125
|
sta.append([cnots, range_list, epsilon])
|
126
|
-
while sta
|
126
|
+
while sta:
|
127
127
|
[cnots, ilist, qubit] = sta.pop()
|
128
128
|
if cnots == []:
|
129
129
|
continue
|
@@ -39,7 +39,7 @@ from qiskit.synthesis.linear.linear_depth_lnn import _optimize_cx_circ_depth_5n_
|
|
39
39
|
def _initialize_phase_schedule(mat_z):
|
40
40
|
"""
|
41
41
|
Given a CZ layer (represented as an n*n CZ matrix Mz)
|
42
|
-
Return a
|
42
|
+
Return a schedule of phase gates implementing Mz in a SWAP-only netwrok
|
43
43
|
(c.f. Alg 1, [2])
|
44
44
|
"""
|
45
45
|
n = len(mat_z)
|
@@ -173,7 +173,7 @@ def _apply_phase_to_nw_circuit(n, phase_schedule, seq, swap_plus):
|
|
173
173
|
of exactly n layers of boxes, each being either a SWAP or a SWAP+. That is,
|
174
174
|
each northwest diagonalization circuit can be uniquely represented by which
|
175
175
|
of its n(n-1)/2 boxes are SWAP+ and which are SWAP.
|
176
|
-
Return a QuantumCircuit that computes the phase
|
176
|
+
Return a QuantumCircuit that computes the phase schedule S inside CX
|
177
177
|
"""
|
178
178
|
cir = QuantumCircuit(n)
|
179
179
|
|
@@ -217,7 +217,7 @@ def _apply_phase_to_nw_circuit(n, phase_schedule, seq, swap_plus):
|
|
217
217
|
|
218
218
|
def synth_cx_cz_depth_line_my(mat_x: np.ndarray, mat_z: np.ndarray) -> QuantumCircuit:
|
219
219
|
"""
|
220
|
-
Joint synthesis of a -CZ-CX- circuit for linear nearest
|
220
|
+
Joint synthesis of a -CZ-CX- circuit for linear nearest neighbor (LNN) connectivity,
|
221
221
|
with 2-qubit depth at most 5n, based on Maslov and Yang.
|
222
222
|
This method computes the CZ circuit inside the CX circuit via phase gate insertions.
|
223
223
|
|
@@ -119,7 +119,7 @@ def _create_patterns(n):
|
|
119
119
|
|
120
120
|
|
121
121
|
def synth_cz_depth_line_mr(mat: np.ndarray) -> QuantumCircuit:
|
122
|
-
r"""Synthesis of a CZ circuit for linear nearest
|
122
|
+
r"""Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity,
|
123
123
|
based on Maslov and Roetteler.
|
124
124
|
|
125
125
|
Note that this method *reverts* the order of qubits in the circuit,
|
@@ -14,6 +14,7 @@
|
|
14
14
|
Decompose a single-qubit unitary via Euler angles.
|
15
15
|
"""
|
16
16
|
from __future__ import annotations
|
17
|
+
from typing import TYPE_CHECKING
|
17
18
|
import numpy as np
|
18
19
|
|
19
20
|
from qiskit._accelerate import euler_one_qubit_decomposer
|
@@ -37,6 +38,9 @@ from qiskit.quantum_info.operators.predicates import is_unitary_matrix
|
|
37
38
|
from qiskit.circuit.gate import Gate
|
38
39
|
from qiskit.quantum_info.operators.operator import Operator
|
39
40
|
|
41
|
+
if TYPE_CHECKING:
|
42
|
+
from qiskit.dagcircuit import DAGCircuit
|
43
|
+
|
40
44
|
DEFAULT_ATOL = 1e-12
|
41
45
|
|
42
46
|
ONE_QUBIT_EULER_BASIS_GATES = {
|
@@ -150,43 +154,33 @@ class OneQubitEulerDecomposer:
|
|
150
154
|
self.basis = basis # sets: self._basis, self._params, self._circuit
|
151
155
|
self.use_dag = use_dag
|
152
156
|
|
153
|
-
def build_circuit(self, gates, global_phase):
|
157
|
+
def build_circuit(self, gates, global_phase) -> QuantumCircuit | DAGCircuit:
|
154
158
|
"""Return the circuit or dag object from a list of gates."""
|
155
159
|
qr = [Qubit()]
|
156
160
|
lookup_gate = False
|
157
161
|
if len(gates) > 0 and isinstance(gates[0], tuple):
|
158
162
|
lookup_gate = True
|
159
163
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
return dag
|
174
|
-
else:
|
175
|
-
circuit = QuantumCircuit(qr, global_phase=global_phase)
|
176
|
-
for gate_entry in gates:
|
177
|
-
if lookup_gate:
|
178
|
-
gate = NAME_MAP[gate_entry[0]](*gate_entry[1])
|
179
|
-
else:
|
180
|
-
gate = gate_entry
|
181
|
-
circuit._append(gate, [qr[0]], [])
|
182
|
-
return circuit
|
164
|
+
from qiskit.dagcircuit import dagcircuit
|
165
|
+
|
166
|
+
dag = dagcircuit.DAGCircuit()
|
167
|
+
dag.global_phase = global_phase
|
168
|
+
dag.add_qubits(qr)
|
169
|
+
for gate_entry in gates:
|
170
|
+
if lookup_gate:
|
171
|
+
gate = NAME_MAP[gate_entry[0].name](*gate_entry[1])
|
172
|
+
else:
|
173
|
+
gate = gate_entry.name
|
174
|
+
|
175
|
+
dag.apply_operation_back(gate, (qr[0],), check=False)
|
176
|
+
return dag
|
183
177
|
|
184
178
|
def __call__(
|
185
179
|
self,
|
186
180
|
unitary: Operator | Gate | np.ndarray,
|
187
181
|
simplify: bool = True,
|
188
182
|
atol: float = DEFAULT_ATOL,
|
189
|
-
) -> QuantumCircuit:
|
183
|
+
) -> QuantumCircuit | DAGCircuit:
|
190
184
|
"""Decompose single qubit gate into a circuit.
|
191
185
|
|
192
186
|
Args:
|
@@ -221,11 +215,17 @@ class OneQubitEulerDecomposer:
|
|
221
215
|
return self._decompose(unitary, simplify=simplify, atol=atol)
|
222
216
|
|
223
217
|
def _decompose(self, unitary, simplify=True, atol=DEFAULT_ATOL):
|
224
|
-
|
225
|
-
|
218
|
+
if self.use_dag:
|
219
|
+
circuit_sequence = euler_one_qubit_decomposer.unitary_to_gate_sequence(
|
220
|
+
unitary, [self.basis], 0, None, simplify, atol
|
221
|
+
)
|
222
|
+
circuit = self.build_circuit(circuit_sequence, circuit_sequence.global_phase)
|
223
|
+
return circuit
|
224
|
+
return QuantumCircuit._from_circuit_data(
|
225
|
+
euler_one_qubit_decomposer.unitary_to_circuit(
|
226
|
+
unitary, [self.basis], 0, None, simplify, atol
|
227
|
+
)
|
226
228
|
)
|
227
|
-
circuit = self.build_circuit(circuit_sequence, circuit_sequence.global_phase)
|
228
|
-
return circuit
|
229
229
|
|
230
230
|
@property
|
231
231
|
def basis(self):
|
@@ -16,11 +16,9 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
import numpy as np
|
18
18
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
19
|
-
from .
|
20
|
-
|
21
|
-
|
22
|
-
_pattern_to_cycles,
|
23
|
-
_decompose_cycles,
|
19
|
+
from qiskit._accelerate.synthesis.permutation import (
|
20
|
+
_synth_permutation_basic,
|
21
|
+
_synth_permutation_acg,
|
24
22
|
)
|
25
23
|
|
26
24
|
|
@@ -44,17 +42,7 @@ def synth_permutation_basic(pattern: list[int] | np.ndarray[int]) -> QuantumCirc
|
|
44
42
|
Returns:
|
45
43
|
The synthesized quantum circuit.
|
46
44
|
"""
|
47
|
-
|
48
|
-
|
49
|
-
num_qubits = len(pattern)
|
50
|
-
qc = QuantumCircuit(num_qubits)
|
51
|
-
|
52
|
-
swaps = _get_ordered_swap(pattern)
|
53
|
-
|
54
|
-
for swap in swaps:
|
55
|
-
qc.swap(swap[0], swap[1])
|
56
|
-
|
57
|
-
return qc
|
45
|
+
return QuantumCircuit._from_circuit_data(_synth_permutation_basic(pattern))
|
58
46
|
|
59
47
|
|
60
48
|
def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircuit:
|
@@ -87,16 +75,4 @@ def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircui
|
|
87
75
|
*Routing Permutations on Graphs Via Matchings.*,
|
88
76
|
`(Full paper) <https://www.cs.tau.ac.il/~nogaa/PDFS/r.pdf>`_
|
89
77
|
"""
|
90
|
-
|
91
|
-
num_qubits = len(pattern)
|
92
|
-
qc = QuantumCircuit(num_qubits)
|
93
|
-
|
94
|
-
# invert pattern (Qiskit notation is opposite)
|
95
|
-
cur_pattern = _inverse_pattern(pattern)
|
96
|
-
cycles = _pattern_to_cycles(cur_pattern)
|
97
|
-
swaps = _decompose_cycles(cycles)
|
98
|
-
|
99
|
-
for swap in swaps:
|
100
|
-
qc.swap(swap[0], swap[1])
|
101
|
-
|
102
|
-
return qc
|
78
|
+
return QuantumCircuit._from_circuit_data(_synth_permutation_acg(pattern))
|
@@ -15,7 +15,7 @@
|
|
15
15
|
from __future__ import annotations
|
16
16
|
import numpy as np
|
17
17
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
18
|
-
from .
|
18
|
+
from qiskit._accelerate.synthesis.permutation import _synth_permutation_depth_lnn_kms
|
19
19
|
|
20
20
|
|
21
21
|
def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> QuantumCircuit:
|
@@ -49,26 +49,4 @@ def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> Qua
|
|
49
49
|
# In the permutation synthesis code below the notation is opposite:
|
50
50
|
# [2, 4, 3, 0, 1] means that 0 maps to 2, 1 to 3, 2 to 3, 3 to 0, and 4 to 1.
|
51
51
|
# This is why we invert the pattern.
|
52
|
-
|
53
|
-
|
54
|
-
num_qubits = len(cur_pattern)
|
55
|
-
qc = QuantumCircuit(num_qubits)
|
56
|
-
|
57
|
-
# add conditional odd-even swap layers
|
58
|
-
for i in range(num_qubits):
|
59
|
-
_create_swap_layer(qc, cur_pattern, i % 2)
|
60
|
-
|
61
|
-
return qc
|
62
|
-
|
63
|
-
|
64
|
-
def _create_swap_layer(qc, pattern, starting_point):
|
65
|
-
"""Implements a single swap layer, consisting of conditional swaps between each
|
66
|
-
neighboring couple. The starting_point is the first qubit to use (either 0 or 1
|
67
|
-
for even or odd layers respectively). Mutates both the quantum circuit ``qc``
|
68
|
-
and the permutation pattern ``pattern``.
|
69
|
-
"""
|
70
|
-
num_qubits = len(pattern)
|
71
|
-
for j in range(starting_point, num_qubits - 1, 2):
|
72
|
-
if pattern[j] > pattern[j + 1]:
|
73
|
-
qc.swap(j, j + 1)
|
74
|
-
pattern[j], pattern[j + 1] = pattern[j + 1], pattern[j]
|
52
|
+
return QuantumCircuit._from_circuit_data(_synth_permutation_depth_lnn_kms(pattern))
|
@@ -12,62 +12,5 @@
|
|
12
12
|
|
13
13
|
"""Utility functions for handling permutations."""
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
"""Sorts the input permutation by iterating through the permutation list
|
18
|
-
and putting each element to its correct position via a SWAP (if it's not
|
19
|
-
at the correct position already). If ``n`` is the length of the input
|
20
|
-
permutation, this requires at most ``n`` SWAPs.
|
21
|
-
|
22
|
-
More precisely, if the input permutation is a cycle of length ``m``,
|
23
|
-
then this creates a quantum circuit with ``m-1`` SWAPs (and of depth ``m-1``);
|
24
|
-
if the input permutation consists of several disjoint cycles, then each cycle
|
25
|
-
is essentially treated independently.
|
26
|
-
"""
|
27
|
-
permutation = list(permutation_in[:])
|
28
|
-
swap_list = []
|
29
|
-
index_map = _inverse_pattern(permutation_in)
|
30
|
-
for i, val in enumerate(permutation):
|
31
|
-
if val != i:
|
32
|
-
j = index_map[i]
|
33
|
-
swap_list.append((i, j))
|
34
|
-
permutation[i], permutation[j] = permutation[j], permutation[i]
|
35
|
-
index_map[val] = j
|
36
|
-
index_map[i] = i
|
37
|
-
swap_list.reverse()
|
38
|
-
return swap_list
|
39
|
-
|
40
|
-
|
41
|
-
def _inverse_pattern(pattern):
|
42
|
-
"""Finds inverse of a permutation pattern."""
|
43
|
-
b_map = {pos: idx for idx, pos in enumerate(pattern)}
|
44
|
-
return [b_map[pos] for pos in range(len(pattern))]
|
45
|
-
|
46
|
-
|
47
|
-
def _pattern_to_cycles(pattern):
|
48
|
-
"""Given a permutation pattern, creates its disjoint cycle decomposition."""
|
49
|
-
nq = len(pattern)
|
50
|
-
explored = [False] * nq
|
51
|
-
cycles = []
|
52
|
-
for i in pattern:
|
53
|
-
cycle = []
|
54
|
-
while not explored[i]:
|
55
|
-
cycle.append(i)
|
56
|
-
explored[i] = True
|
57
|
-
i = pattern[i]
|
58
|
-
if len(cycle) >= 2:
|
59
|
-
cycles.append(cycle)
|
60
|
-
return cycles
|
61
|
-
|
62
|
-
|
63
|
-
def _decompose_cycles(cycles):
|
64
|
-
"""Given a disjoint cycle decomposition, decomposes every cycle into a SWAP
|
65
|
-
circuit of depth 2."""
|
66
|
-
swap_list = []
|
67
|
-
for cycle in cycles:
|
68
|
-
m = len(cycle)
|
69
|
-
for i in range((m - 1) // 2):
|
70
|
-
swap_list.append((cycle[i - 1], cycle[m - 3 - i]))
|
71
|
-
for i in range(m // 2):
|
72
|
-
swap_list.append((cycle[i - 1], cycle[m - 2 - i]))
|
73
|
-
return swap_list
|
15
|
+
# pylint: disable=unused-import
|
16
|
+
from qiskit._accelerate.synthesis.permutation import _inverse_pattern, _validate_permutation
|
qiskit/synthesis/qft/__init__.py
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2024.
|
4
|
+
#
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
+
#
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
11
|
+
# that they have been altered from the originals.
|
12
|
+
"""
|
13
|
+
Circuit synthesis for a QFT circuit.
|
14
|
+
"""
|
15
|
+
|
16
|
+
from __future__ import annotations
|
17
|
+
import numpy as np
|
18
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
19
|
+
|
20
|
+
|
21
|
+
def synth_qft_full(
|
22
|
+
num_qubits: int,
|
23
|
+
do_swaps: bool = True,
|
24
|
+
approximation_degree: int = 0,
|
25
|
+
insert_barriers: bool = False,
|
26
|
+
inverse: bool = False,
|
27
|
+
name: str | None = None,
|
28
|
+
) -> QuantumCircuit:
|
29
|
+
"""Construct a circuit for the Quantum Fourier Transform using all-to-all connectivity.
|
30
|
+
|
31
|
+
.. note::
|
32
|
+
|
33
|
+
With the default value of ``do_swaps = True``, this synthesis algorithm creates a
|
34
|
+
circuit that faithfully implements the QFT operation. This circuit contains a sequence
|
35
|
+
of swap gates at the end, corresponding to reversing the order of its output qubits.
|
36
|
+
In some applications this reversal permutation can be avoided. Setting ``do_swaps = False``
|
37
|
+
creates a circuit without this reversal permutation, at the expense that this circuit
|
38
|
+
implements the "QFT-with-reversal" instead of QFT. Alternatively, the
|
39
|
+
:class:`~.ElidePermutations` transpiler pass is able to remove these swap gates.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
num_qubits: The number of qubits on which the Quantum Fourier Transform acts.
|
43
|
+
do_swaps: Whether to synthesize the "QFT" or the "QFT-with-reversal" operation.
|
44
|
+
approximation_degree: The degree of approximation (0 for no approximation).
|
45
|
+
It is possible to implement the QFT approximately by ignoring
|
46
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
47
|
+
in more detail in https://arxiv.org/abs/quant-ph/9601018 or
|
48
|
+
https://arxiv.org/abs/quant-ph/0403071.
|
49
|
+
insert_barriers: If ``True``, barriers are inserted for improved visualization.
|
50
|
+
inverse: If ``True``, the inverse Quantum Fourier Transform is constructed.
|
51
|
+
name: The name of the circuit.
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
A circuit implementing the QFT operation.
|
55
|
+
|
56
|
+
"""
|
57
|
+
|
58
|
+
circuit = QuantumCircuit(num_qubits, name=name)
|
59
|
+
|
60
|
+
for j in reversed(range(num_qubits)):
|
61
|
+
circuit.h(j)
|
62
|
+
num_entanglements = max(0, j - max(0, approximation_degree - (num_qubits - j - 1)))
|
63
|
+
for k in reversed(range(j - num_entanglements, j)):
|
64
|
+
# Use negative exponents so that the angle safely underflows to zero, rather than
|
65
|
+
# using a temporary variable that overflows to infinity in the worst case.
|
66
|
+
lam = np.pi * (2.0 ** (k - j))
|
67
|
+
circuit.cp(lam, j, k)
|
68
|
+
|
69
|
+
if insert_barriers:
|
70
|
+
circuit.barrier()
|
71
|
+
|
72
|
+
if do_swaps:
|
73
|
+
for i in range(num_qubits // 2):
|
74
|
+
circuit.swap(i, num_qubits - i - 1)
|
75
|
+
|
76
|
+
if inverse:
|
77
|
+
circuit = circuit.inverse()
|
78
|
+
|
79
|
+
return circuit
|
@@ -21,21 +21,29 @@ from qiskit.synthesis.permutation.permutation_reverse_lnn import _append_reverse
|
|
21
21
|
def synth_qft_line(
|
22
22
|
num_qubits: int, do_swaps: bool = True, approximation_degree: int = 0
|
23
23
|
) -> QuantumCircuit:
|
24
|
-
"""
|
25
|
-
|
24
|
+
"""Construct a circuit for the Quantum Fourier Transform using linear
|
25
|
+
neighbor connectivity.
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
The construction is based on Fig 2.b in Fowler et al. [1].
|
28
|
+
|
29
|
+
.. note::
|
30
|
+
|
31
|
+
With the default value of ``do_swaps = True``, this synthesis algorithm creates a
|
32
|
+
circuit that faithfully implements the QFT operation. When ``do_swaps = False``,
|
33
|
+
this synthesis algorithm creates a circuit that corresponds to "QFT-with-reversal":
|
34
|
+
applying the QFT and reversing the order of its output qubits.
|
31
35
|
|
32
36
|
Args:
|
33
|
-
num_qubits: The number of qubits on which the
|
37
|
+
num_qubits: The number of qubits on which the Quantum Fourier Transform acts.
|
34
38
|
approximation_degree: The degree of approximation (0 for no approximation).
|
35
|
-
|
39
|
+
It is possible to implement the QFT approximately by ignoring
|
40
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
41
|
+
in more detail in https://arxiv.org/abs/quant-ph/9601018 or
|
42
|
+
https://arxiv.org/abs/quant-ph/0403071.
|
43
|
+
do_swaps: Whether to synthesize the "QFT" or the "QFT-with-reversal" operation.
|
36
44
|
|
37
45
|
Returns:
|
38
|
-
A circuit
|
46
|
+
A circuit implementing the QFT operation.
|
39
47
|
|
40
48
|
References:
|
41
49
|
1. A. G. Fowler, S. J. Devitt, and L. C. L. Hollenberg,
|