qiskit 2.1.0rc1__cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.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 -0
- qiskit/__init__.py +159 -0
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/circuit/__init__.py +1335 -0
- qiskit/circuit/_add_control.py +338 -0
- qiskit/circuit/_classical_resource_map.py +154 -0
- qiskit/circuit/_standard_gates_commutations.py +3849 -0
- qiskit/circuit/_utils.py +167 -0
- qiskit/circuit/annotated_operation.py +279 -0
- qiskit/circuit/annotation.py +404 -0
- qiskit/circuit/barrier.py +46 -0
- qiskit/circuit/classical/__init__.py +41 -0
- qiskit/circuit/classical/expr/__init__.py +266 -0
- qiskit/circuit/classical/expr/constructors.py +764 -0
- qiskit/circuit/classical/expr/expr.py +156 -0
- qiskit/circuit/classical/expr/visitors.py +381 -0
- qiskit/circuit/classical/types/__init__.py +113 -0
- qiskit/circuit/classical/types/ordering.py +229 -0
- qiskit/circuit/classical/types/types.py +30 -0
- qiskit/circuit/commutation_checker.py +133 -0
- qiskit/circuit/commutation_library.py +20 -0
- qiskit/circuit/controlflow/__init__.py +59 -0
- qiskit/circuit/controlflow/_builder_utils.py +211 -0
- qiskit/circuit/controlflow/box.py +188 -0
- qiskit/circuit/controlflow/break_loop.py +56 -0
- qiskit/circuit/controlflow/builder.py +791 -0
- qiskit/circuit/controlflow/continue_loop.py +56 -0
- qiskit/circuit/controlflow/control_flow.py +94 -0
- qiskit/circuit/controlflow/for_loop.py +218 -0
- qiskit/circuit/controlflow/if_else.py +498 -0
- qiskit/circuit/controlflow/switch_case.py +411 -0
- qiskit/circuit/controlflow/while_loop.py +166 -0
- qiskit/circuit/controlledgate.py +274 -0
- qiskit/circuit/delay.py +159 -0
- qiskit/circuit/duration.py +80 -0
- qiskit/circuit/equivalence.py +94 -0
- qiskit/circuit/equivalence_library.py +18 -0
- qiskit/circuit/exceptions.py +19 -0
- qiskit/circuit/gate.py +261 -0
- qiskit/circuit/instruction.py +564 -0
- qiskit/circuit/instructionset.py +132 -0
- qiskit/circuit/library/__init__.py +984 -0
- qiskit/circuit/library/arithmetic/__init__.py +40 -0
- qiskit/circuit/library/arithmetic/adders/__init__.py +18 -0
- qiskit/circuit/library/arithmetic/adders/adder.py +235 -0
- qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +123 -0
- qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +129 -0
- qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +95 -0
- qiskit/circuit/library/arithmetic/exact_reciprocal.py +131 -0
- qiskit/circuit/library/arithmetic/functional_pauli_rotations.py +114 -0
- qiskit/circuit/library/arithmetic/integer_comparator.py +200 -0
- qiskit/circuit/library/arithmetic/linear_amplitude_function.py +363 -0
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +243 -0
- qiskit/circuit/library/arithmetic/multipliers/__init__.py +17 -0
- qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +145 -0
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +201 -0
- qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +108 -0
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +506 -0
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +395 -0
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +501 -0
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +389 -0
- qiskit/circuit/library/arithmetic/quadratic_form.py +370 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +428 -0
- qiskit/circuit/library/basis_change/__init__.py +15 -0
- qiskit/circuit/library/basis_change/qft.py +316 -0
- qiskit/circuit/library/bit_flip_oracle.py +130 -0
- qiskit/circuit/library/blueprintcircuit.py +322 -0
- qiskit/circuit/library/boolean_logic/__init__.py +18 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +157 -0
- qiskit/circuit/library/boolean_logic/quantum_and.py +204 -0
- qiskit/circuit/library/boolean_logic/quantum_or.py +206 -0
- qiskit/circuit/library/boolean_logic/quantum_xor.py +167 -0
- qiskit/circuit/library/data_preparation/__init__.py +57 -0
- qiskit/circuit/library/data_preparation/_z_feature_map.py +115 -0
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +150 -0
- qiskit/circuit/library/data_preparation/initializer.py +107 -0
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +656 -0
- qiskit/circuit/library/data_preparation/state_preparation.py +336 -0
- qiskit/circuit/library/fourier_checking.py +160 -0
- qiskit/circuit/library/generalized_gates/__init__.py +30 -0
- qiskit/circuit/library/generalized_gates/diagonal.py +163 -0
- qiskit/circuit/library/generalized_gates/gms.py +179 -0
- qiskit/circuit/library/generalized_gates/gr.py +219 -0
- qiskit/circuit/library/generalized_gates/isometry.py +370 -0
- qiskit/circuit/library/generalized_gates/linear_function.py +318 -0
- qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +143 -0
- qiskit/circuit/library/generalized_gates/mcmt.py +316 -0
- qiskit/circuit/library/generalized_gates/pauli.py +84 -0
- qiskit/circuit/library/generalized_gates/permutation.py +202 -0
- qiskit/circuit/library/generalized_gates/rv.py +96 -0
- qiskit/circuit/library/generalized_gates/uc.py +303 -0
- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +164 -0
- qiskit/circuit/library/generalized_gates/ucrx.py +32 -0
- qiskit/circuit/library/generalized_gates/ucry.py +32 -0
- qiskit/circuit/library/generalized_gates/ucrz.py +32 -0
- qiskit/circuit/library/generalized_gates/unitary.py +236 -0
- qiskit/circuit/library/graph_state.py +172 -0
- qiskit/circuit/library/grover_operator.py +583 -0
- qiskit/circuit/library/hamiltonian_gate.py +142 -0
- qiskit/circuit/library/hidden_linear_function.py +163 -0
- qiskit/circuit/library/iqp.py +180 -0
- qiskit/circuit/library/n_local/__init__.py +45 -0
- qiskit/circuit/library/n_local/efficient_su2.py +282 -0
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +520 -0
- qiskit/circuit/library/n_local/excitation_preserving.py +301 -0
- qiskit/circuit/library/n_local/n_local.py +1478 -0
- qiskit/circuit/library/n_local/pauli_two_design.py +246 -0
- qiskit/circuit/library/n_local/qaoa_ansatz.py +367 -0
- qiskit/circuit/library/n_local/real_amplitudes.py +312 -0
- qiskit/circuit/library/n_local/two_local.py +289 -0
- qiskit/circuit/library/overlap.py +183 -0
- qiskit/circuit/library/pauli_evolution.py +202 -0
- qiskit/circuit/library/phase_estimation.py +177 -0
- qiskit/circuit/library/phase_oracle.py +239 -0
- qiskit/circuit/library/quantum_volume.py +179 -0
- qiskit/circuit/library/standard_gates/__init__.py +141 -0
- qiskit/circuit/library/standard_gates/dcx.py +76 -0
- qiskit/circuit/library/standard_gates/ecr.py +126 -0
- qiskit/circuit/library/standard_gates/equivalence_library.py +1936 -0
- qiskit/circuit/library/standard_gates/global_phase.py +83 -0
- qiskit/circuit/library/standard_gates/h.py +230 -0
- qiskit/circuit/library/standard_gates/i.py +76 -0
- qiskit/circuit/library/standard_gates/iswap.py +115 -0
- qiskit/circuit/library/standard_gates/p.py +415 -0
- qiskit/circuit/library/standard_gates/r.py +108 -0
- qiskit/circuit/library/standard_gates/rx.py +269 -0
- qiskit/circuit/library/standard_gates/rxx.py +165 -0
- qiskit/circuit/library/standard_gates/ry.py +268 -0
- qiskit/circuit/library/standard_gates/ryy.py +165 -0
- qiskit/circuit/library/standard_gates/rz.py +290 -0
- qiskit/circuit/library/standard_gates/rzx.py +211 -0
- qiskit/circuit/library/standard_gates/rzz.py +181 -0
- qiskit/circuit/library/standard_gates/s.py +424 -0
- qiskit/circuit/library/standard_gates/swap.py +268 -0
- qiskit/circuit/library/standard_gates/sx.py +303 -0
- qiskit/circuit/library/standard_gates/t.py +169 -0
- qiskit/circuit/library/standard_gates/u.py +379 -0
- qiskit/circuit/library/standard_gates/u1.py +466 -0
- qiskit/circuit/library/standard_gates/u2.py +145 -0
- qiskit/circuit/library/standard_gates/u3.py +412 -0
- qiskit/circuit/library/standard_gates/x.py +1335 -0
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +164 -0
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +197 -0
- qiskit/circuit/library/standard_gates/y.py +253 -0
- qiskit/circuit/library/standard_gates/z.py +331 -0
- qiskit/circuit/library/templates/__init__.py +92 -0
- qiskit/circuit/library/templates/clifford/__init__.py +33 -0
- qiskit/circuit/library/templates/clifford/clifford_2_1.py +34 -0
- qiskit/circuit/library/templates/clifford/clifford_2_2.py +35 -0
- qiskit/circuit/library/templates/clifford/clifford_2_3.py +34 -0
- qiskit/circuit/library/templates/clifford/clifford_2_4.py +34 -0
- qiskit/circuit/library/templates/clifford/clifford_3_1.py +35 -0
- qiskit/circuit/library/templates/clifford/clifford_4_1.py +38 -0
- qiskit/circuit/library/templates/clifford/clifford_4_2.py +37 -0
- qiskit/circuit/library/templates/clifford/clifford_4_3.py +38 -0
- qiskit/circuit/library/templates/clifford/clifford_4_4.py +37 -0
- qiskit/circuit/library/templates/clifford/clifford_5_1.py +40 -0
- qiskit/circuit/library/templates/clifford/clifford_6_1.py +40 -0
- qiskit/circuit/library/templates/clifford/clifford_6_2.py +40 -0
- qiskit/circuit/library/templates/clifford/clifford_6_3.py +40 -0
- qiskit/circuit/library/templates/clifford/clifford_6_4.py +38 -0
- qiskit/circuit/library/templates/clifford/clifford_6_5.py +40 -0
- qiskit/circuit/library/templates/clifford/clifford_8_1.py +42 -0
- qiskit/circuit/library/templates/clifford/clifford_8_2.py +42 -0
- qiskit/circuit/library/templates/clifford/clifford_8_3.py +41 -0
- qiskit/circuit/library/templates/nct/__init__.py +67 -0
- qiskit/circuit/library/templates/nct/template_nct_2a_1.py +34 -0
- qiskit/circuit/library/templates/nct/template_nct_2a_2.py +35 -0
- qiskit/circuit/library/templates/nct/template_nct_2a_3.py +37 -0
- qiskit/circuit/library/templates/nct/template_nct_4a_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_4a_2.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_4a_3.py +39 -0
- qiskit/circuit/library/templates/nct/template_nct_4b_1.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_4b_2.py +39 -0
- qiskit/circuit/library/templates/nct/template_nct_5a_1.py +40 -0
- qiskit/circuit/library/templates/nct/template_nct_5a_2.py +40 -0
- qiskit/circuit/library/templates/nct/template_nct_5a_3.py +40 -0
- qiskit/circuit/library/templates/nct/template_nct_5a_4.py +39 -0
- qiskit/circuit/library/templates/nct/template_nct_6a_1.py +40 -0
- qiskit/circuit/library/templates/nct/template_nct_6a_2.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_6a_3.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_6a_4.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_6b_1.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_6b_2.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_6c_1.py +41 -0
- qiskit/circuit/library/templates/nct/template_nct_7a_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_7b_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_7c_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_7d_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_7e_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_9a_1.py +45 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_10.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_11.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_12.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_2.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_3.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_4.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_5.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_6.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_7.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_8.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9c_9.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_1.py +43 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_10.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_2.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_3.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_4.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_5.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_6.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_7.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_8.py +44 -0
- qiskit/circuit/library/templates/nct/template_nct_9d_9.py +44 -0
- qiskit/circuit/library/templates/rzx/__init__.py +25 -0
- qiskit/circuit/library/templates/rzx/rzx_cy.py +47 -0
- qiskit/circuit/library/templates/rzx/rzx_xz.py +54 -0
- qiskit/circuit/library/templates/rzx/rzx_yz.py +45 -0
- qiskit/circuit/library/templates/rzx/rzx_zz1.py +69 -0
- qiskit/circuit/library/templates/rzx/rzx_zz2.py +59 -0
- qiskit/circuit/library/templates/rzx/rzx_zz3.py +59 -0
- qiskit/circuit/measure.py +53 -0
- qiskit/circuit/operation.py +68 -0
- qiskit/circuit/parameter.py +188 -0
- qiskit/circuit/parameterexpression.py +737 -0
- qiskit/circuit/parametertable.py +119 -0
- qiskit/circuit/parametervector.py +140 -0
- qiskit/circuit/quantumcircuit.py +7610 -0
- qiskit/circuit/quantumcircuitdata.py +137 -0
- qiskit/circuit/random/__init__.py +50 -0
- qiskit/circuit/random/utils.py +755 -0
- qiskit/circuit/reset.py +37 -0
- qiskit/circuit/singleton.py +600 -0
- qiskit/circuit/store.py +89 -0
- qiskit/circuit/tools/__init__.py +16 -0
- qiskit/circuit/tools/pi_check.py +185 -0
- qiskit/circuit/twirling.py +145 -0
- qiskit/compiler/__init__.py +27 -0
- qiskit/compiler/transpiler.py +375 -0
- qiskit/converters/__init__.py +74 -0
- qiskit/converters/circuit_to_dag.py +80 -0
- qiskit/converters/circuit_to_dagdependency.py +49 -0
- qiskit/converters/circuit_to_dagdependency_v2.py +46 -0
- qiskit/converters/circuit_to_gate.py +107 -0
- qiskit/converters/circuit_to_instruction.py +142 -0
- qiskit/converters/dag_to_circuit.py +79 -0
- qiskit/converters/dag_to_dagdependency.py +54 -0
- qiskit/converters/dag_to_dagdependency_v2.py +43 -0
- qiskit/converters/dagdependency_to_circuit.py +40 -0
- qiskit/converters/dagdependency_to_dag.py +48 -0
- qiskit/dagcircuit/__init__.py +44 -0
- qiskit/dagcircuit/collect_blocks.py +403 -0
- qiskit/dagcircuit/dagcircuit.py +24 -0
- qiskit/dagcircuit/dagdependency.py +612 -0
- qiskit/dagcircuit/dagdependency_v2.py +566 -0
- qiskit/dagcircuit/dagdepnode.py +160 -0
- qiskit/dagcircuit/dagnode.py +193 -0
- qiskit/dagcircuit/exceptions.py +42 -0
- qiskit/exceptions.py +153 -0
- qiskit/passmanager/__init__.py +258 -0
- qiskit/passmanager/base_tasks.py +230 -0
- qiskit/passmanager/compilation_status.py +74 -0
- qiskit/passmanager/exceptions.py +19 -0
- qiskit/passmanager/flow_controllers.py +116 -0
- qiskit/passmanager/passmanager.py +353 -0
- qiskit/primitives/__init__.py +490 -0
- qiskit/primitives/backend_estimator_v2.py +530 -0
- qiskit/primitives/backend_sampler_v2.py +339 -0
- qiskit/primitives/base/__init__.py +20 -0
- qiskit/primitives/base/base_estimator.py +247 -0
- qiskit/primitives/base/base_primitive_job.py +78 -0
- qiskit/primitives/base/base_primitive_v1.py +45 -0
- qiskit/primitives/base/base_result_v1.py +65 -0
- qiskit/primitives/base/base_sampler.py +196 -0
- qiskit/primitives/base/estimator_result_v1.py +46 -0
- qiskit/primitives/base/sampler_result_v1.py +45 -0
- qiskit/primitives/base/validation_v1.py +250 -0
- qiskit/primitives/containers/__init__.py +26 -0
- qiskit/primitives/containers/bindings_array.py +391 -0
- qiskit/primitives/containers/bit_array.py +764 -0
- qiskit/primitives/containers/data_bin.py +172 -0
- qiskit/primitives/containers/estimator_pub.py +222 -0
- qiskit/primitives/containers/object_array.py +94 -0
- qiskit/primitives/containers/observables_array.py +380 -0
- qiskit/primitives/containers/primitive_result.py +53 -0
- qiskit/primitives/containers/pub_result.py +51 -0
- qiskit/primitives/containers/sampler_pub.py +193 -0
- qiskit/primitives/containers/sampler_pub_result.py +74 -0
- qiskit/primitives/containers/shape.py +129 -0
- qiskit/primitives/primitive_job.py +100 -0
- qiskit/primitives/statevector_estimator.py +175 -0
- qiskit/primitives/statevector_sampler.py +290 -0
- qiskit/primitives/utils.py +72 -0
- qiskit/providers/__init__.py +677 -0
- qiskit/providers/backend.py +364 -0
- qiskit/providers/basic_provider/__init__.py +47 -0
- qiskit/providers/basic_provider/basic_provider.py +121 -0
- qiskit/providers/basic_provider/basic_provider_job.py +65 -0
- qiskit/providers/basic_provider/basic_provider_tools.py +218 -0
- qiskit/providers/basic_provider/basic_simulator.py +693 -0
- qiskit/providers/basic_provider/exceptions.py +30 -0
- qiskit/providers/exceptions.py +33 -0
- qiskit/providers/fake_provider/__init__.py +69 -0
- qiskit/providers/fake_provider/generic_backend_v2.py +376 -0
- qiskit/providers/fake_provider/utils/__init__.py +15 -0
- qiskit/providers/job.py +147 -0
- qiskit/providers/jobstatus.py +30 -0
- qiskit/providers/options.py +273 -0
- qiskit/providers/providerutils.py +110 -0
- qiskit/qasm/libs/dummy/stdgates.inc +75 -0
- qiskit/qasm/libs/qelib1.inc +266 -0
- qiskit/qasm/libs/stdgates.inc +82 -0
- qiskit/qasm2/__init__.py +669 -0
- qiskit/qasm2/exceptions.py +27 -0
- qiskit/qasm2/export.py +364 -0
- qiskit/qasm2/parse.py +438 -0
- qiskit/qasm3/__init__.py +466 -0
- qiskit/qasm3/ast.py +796 -0
- qiskit/qasm3/exceptions.py +27 -0
- qiskit/qasm3/experimental.py +70 -0
- qiskit/qasm3/exporter.py +1363 -0
- qiskit/qasm3/printer.py +620 -0
- qiskit/qpy/__init__.py +2141 -0
- qiskit/qpy/binary_io/__init__.py +35 -0
- qiskit/qpy/binary_io/circuits.py +1687 -0
- qiskit/qpy/binary_io/parse_sympy_repr.py +126 -0
- qiskit/qpy/binary_io/schedules.py +288 -0
- qiskit/qpy/binary_io/value.py +1183 -0
- qiskit/qpy/common.py +361 -0
- qiskit/qpy/exceptions.py +53 -0
- qiskit/qpy/formats.py +458 -0
- qiskit/qpy/interface.py +384 -0
- qiskit/qpy/type_keys.py +415 -0
- qiskit/quantum_info/__init__.py +172 -0
- qiskit/quantum_info/analysis/__init__.py +17 -0
- qiskit/quantum_info/analysis/average.py +47 -0
- qiskit/quantum_info/analysis/distance.py +104 -0
- qiskit/quantum_info/analysis/make_observable.py +44 -0
- qiskit/quantum_info/analysis/z2_symmetries.py +484 -0
- qiskit/quantum_info/operators/__init__.py +29 -0
- qiskit/quantum_info/operators/base_operator.py +145 -0
- qiskit/quantum_info/operators/channel/__init__.py +29 -0
- qiskit/quantum_info/operators/channel/chi.py +191 -0
- qiskit/quantum_info/operators/channel/choi.py +218 -0
- qiskit/quantum_info/operators/channel/kraus.py +337 -0
- qiskit/quantum_info/operators/channel/ptm.py +204 -0
- qiskit/quantum_info/operators/channel/quantum_channel.py +348 -0
- qiskit/quantum_info/operators/channel/stinespring.py +296 -0
- qiskit/quantum_info/operators/channel/superop.py +373 -0
- qiskit/quantum_info/operators/channel/transformations.py +490 -0
- qiskit/quantum_info/operators/custom_iterator.py +48 -0
- qiskit/quantum_info/operators/dihedral/__init__.py +18 -0
- qiskit/quantum_info/operators/dihedral/dihedral.py +511 -0
- qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +216 -0
- qiskit/quantum_info/operators/dihedral/polynomial.py +313 -0
- qiskit/quantum_info/operators/dihedral/random.py +64 -0
- qiskit/quantum_info/operators/linear_op.py +25 -0
- qiskit/quantum_info/operators/measures.py +418 -0
- qiskit/quantum_info/operators/mixins/__init__.py +52 -0
- qiskit/quantum_info/operators/mixins/adjoint.py +52 -0
- qiskit/quantum_info/operators/mixins/group.py +171 -0
- qiskit/quantum_info/operators/mixins/linear.py +84 -0
- qiskit/quantum_info/operators/mixins/multiply.py +62 -0
- qiskit/quantum_info/operators/mixins/tolerances.py +72 -0
- qiskit/quantum_info/operators/op_shape.py +525 -0
- qiskit/quantum_info/operators/operator.py +869 -0
- qiskit/quantum_info/operators/operator_utils.py +76 -0
- qiskit/quantum_info/operators/predicates.py +183 -0
- qiskit/quantum_info/operators/random.py +154 -0
- qiskit/quantum_info/operators/scalar_op.py +254 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +24 -0
- qiskit/quantum_info/operators/symplectic/base_pauli.py +719 -0
- qiskit/quantum_info/operators/symplectic/clifford.py +1032 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +584 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +755 -0
- qiskit/quantum_info/operators/symplectic/pauli_list.py +1242 -0
- qiskit/quantum_info/operators/symplectic/pauli_utils.py +40 -0
- qiskit/quantum_info/operators/symplectic/random.py +117 -0
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1239 -0
- qiskit/quantum_info/operators/utils/__init__.py +20 -0
- qiskit/quantum_info/operators/utils/anti_commutator.py +36 -0
- qiskit/quantum_info/operators/utils/commutator.py +36 -0
- qiskit/quantum_info/operators/utils/double_commutator.py +76 -0
- qiskit/quantum_info/quaternion.py +156 -0
- qiskit/quantum_info/random.py +26 -0
- qiskit/quantum_info/states/__init__.py +28 -0
- qiskit/quantum_info/states/densitymatrix.py +857 -0
- qiskit/quantum_info/states/measures.py +288 -0
- qiskit/quantum_info/states/quantum_state.py +503 -0
- qiskit/quantum_info/states/random.py +157 -0
- qiskit/quantum_info/states/stabilizerstate.py +805 -0
- qiskit/quantum_info/states/statevector.py +977 -0
- qiskit/quantum_info/states/utils.py +247 -0
- qiskit/result/__init__.py +61 -0
- qiskit/result/counts.py +189 -0
- qiskit/result/distributions/__init__.py +17 -0
- qiskit/result/distributions/probability.py +100 -0
- qiskit/result/distributions/quasi.py +154 -0
- qiskit/result/exceptions.py +40 -0
- qiskit/result/models.py +241 -0
- qiskit/result/postprocess.py +239 -0
- qiskit/result/result.py +385 -0
- qiskit/result/sampled_expval.py +76 -0
- qiskit/result/utils.py +294 -0
- qiskit/synthesis/__init__.py +250 -0
- qiskit/synthesis/arithmetic/__init__.py +18 -0
- qiskit/synthesis/arithmetic/adders/__init__.py +18 -0
- qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +154 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +107 -0
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +161 -0
- qiskit/synthesis/arithmetic/comparators/__init__.py +16 -0
- qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
- qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
- qiskit/synthesis/arithmetic/multipliers/__init__.py +16 -0
- qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +103 -0
- qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +100 -0
- qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
- qiskit/synthesis/boolean/__init__.py +13 -0
- qiskit/synthesis/boolean/boolean_expression.py +231 -0
- qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
- qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
- qiskit/synthesis/clifford/__init__.py +19 -0
- qiskit/synthesis/clifford/clifford_decompose_ag.py +178 -0
- qiskit/synthesis/clifford/clifford_decompose_bm.py +46 -0
- qiskit/synthesis/clifford/clifford_decompose_full.py +64 -0
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +58 -0
- qiskit/synthesis/clifford/clifford_decompose_layers.py +447 -0
- qiskit/synthesis/cnotdihedral/__init__.py +17 -0
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +52 -0
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +141 -0
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_two_qubits.py +266 -0
- qiskit/synthesis/discrete_basis/__init__.py +16 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +53 -0
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +280 -0
- qiskit/synthesis/evolution/__init__.py +21 -0
- qiskit/synthesis/evolution/evolution_synthesis.py +48 -0
- qiskit/synthesis/evolution/lie_trotter.py +123 -0
- qiskit/synthesis/evolution/matrix_synthesis.py +47 -0
- qiskit/synthesis/evolution/pauli_network.py +80 -0
- qiskit/synthesis/evolution/product_formula.py +316 -0
- qiskit/synthesis/evolution/qdrift.py +133 -0
- qiskit/synthesis/evolution/suzuki_trotter.py +227 -0
- qiskit/synthesis/linear/__init__.py +26 -0
- qiskit/synthesis/linear/cnot_synth.py +69 -0
- qiskit/synthesis/linear/linear_circuits_utils.py +128 -0
- qiskit/synthesis/linear/linear_depth_lnn.py +61 -0
- qiskit/synthesis/linear/linear_matrix_utils.py +27 -0
- qiskit/synthesis/linear_phase/__init__.py +17 -0
- qiskit/synthesis/linear_phase/cnot_phase_synth.py +206 -0
- qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +61 -0
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +58 -0
- qiskit/synthesis/multi_controlled/__init__.py +29 -0
- qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +583 -0
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +205 -0
- qiskit/synthesis/one_qubit/__init__.py +15 -0
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +288 -0
- qiskit/synthesis/permutation/__init__.py +18 -0
- qiskit/synthesis/permutation/permutation_full.py +78 -0
- qiskit/synthesis/permutation/permutation_lnn.py +54 -0
- qiskit/synthesis/permutation/permutation_reverse_lnn.py +93 -0
- qiskit/synthesis/permutation/permutation_utils.py +16 -0
- qiskit/synthesis/qft/__init__.py +16 -0
- qiskit/synthesis/qft/qft_decompose_full.py +97 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +61 -0
- qiskit/synthesis/stabilizer/__init__.py +16 -0
- qiskit/synthesis/stabilizer/stabilizer_circuit.py +149 -0
- qiskit/synthesis/stabilizer/stabilizer_decompose.py +194 -0
- qiskit/synthesis/two_qubit/__init__.py +20 -0
- qiskit/synthesis/two_qubit/local_invariance.py +63 -0
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +583 -0
- qiskit/synthesis/two_qubit/xx_decompose/__init__.py +19 -0
- qiskit/synthesis/two_qubit/xx_decompose/circuits.py +300 -0
- qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +324 -0
- qiskit/synthesis/two_qubit/xx_decompose/embodiments.py +163 -0
- qiskit/synthesis/two_qubit/xx_decompose/paths.py +412 -0
- qiskit/synthesis/two_qubit/xx_decompose/polytopes.py +262 -0
- qiskit/synthesis/two_qubit/xx_decompose/utilities.py +40 -0
- qiskit/synthesis/two_qubit/xx_decompose/weyl.py +133 -0
- qiskit/synthesis/unitary/__init__.py +13 -0
- qiskit/synthesis/unitary/aqc/__init__.py +177 -0
- qiskit/synthesis/unitary/aqc/approximate.py +116 -0
- qiskit/synthesis/unitary/aqc/aqc.py +175 -0
- qiskit/synthesis/unitary/aqc/cnot_structures.py +300 -0
- qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py +103 -0
- qiskit/synthesis/unitary/aqc/cnot_unit_objective.py +299 -0
- qiskit/synthesis/unitary/aqc/elementary_operations.py +108 -0
- qiskit/synthesis/unitary/aqc/fast_gradient/__init__.py +164 -0
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py +237 -0
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +226 -0
- qiskit/synthesis/unitary/aqc/fast_gradient/layer.py +370 -0
- qiskit/synthesis/unitary/aqc/fast_gradient/pmatrix.py +312 -0
- qiskit/synthesis/unitary/qsd.py +359 -0
- qiskit/transpiler/__init__.py +1352 -0
- qiskit/transpiler/basepasses.py +190 -0
- qiskit/transpiler/coupling.py +500 -0
- qiskit/transpiler/exceptions.py +59 -0
- qiskit/transpiler/instruction_durations.py +263 -0
- qiskit/transpiler/layout.py +740 -0
- qiskit/transpiler/passes/__init__.py +278 -0
- qiskit/transpiler/passes/analysis/__init__.py +23 -0
- qiskit/transpiler/passes/analysis/count_ops.py +30 -0
- qiskit/transpiler/passes/analysis/count_ops_longest_path.py +26 -0
- qiskit/transpiler/passes/analysis/dag_longest_path.py +24 -0
- qiskit/transpiler/passes/analysis/depth.py +33 -0
- qiskit/transpiler/passes/analysis/num_qubits.py +26 -0
- qiskit/transpiler/passes/analysis/num_tensor_factors.py +26 -0
- qiskit/transpiler/passes/analysis/resource_estimation.py +41 -0
- qiskit/transpiler/passes/analysis/size.py +36 -0
- qiskit/transpiler/passes/analysis/width.py +27 -0
- qiskit/transpiler/passes/basis/__init__.py +19 -0
- qiskit/transpiler/passes/basis/basis_translator.py +138 -0
- qiskit/transpiler/passes/basis/decompose.py +137 -0
- qiskit/transpiler/passes/basis/translate_parameterized.py +175 -0
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +84 -0
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +110 -0
- qiskit/transpiler/passes/layout/__init__.py +26 -0
- qiskit/transpiler/passes/layout/_csp_custom_solver.py +65 -0
- qiskit/transpiler/passes/layout/apply_layout.py +128 -0
- qiskit/transpiler/passes/layout/csp_layout.py +132 -0
- qiskit/transpiler/passes/layout/dense_layout.py +197 -0
- qiskit/transpiler/passes/layout/disjoint_utils.py +54 -0
- qiskit/transpiler/passes/layout/enlarge_with_ancilla.py +49 -0
- qiskit/transpiler/passes/layout/full_ancilla_allocation.py +116 -0
- qiskit/transpiler/passes/layout/layout_2q_distance.py +77 -0
- qiskit/transpiler/passes/layout/sabre_layout.py +525 -0
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +225 -0
- qiskit/transpiler/passes/layout/set_layout.py +69 -0
- qiskit/transpiler/passes/layout/trivial_layout.py +66 -0
- qiskit/transpiler/passes/layout/vf2_layout.py +292 -0
- qiskit/transpiler/passes/layout/vf2_post_layout.py +376 -0
- qiskit/transpiler/passes/layout/vf2_utils.py +245 -0
- qiskit/transpiler/passes/optimization/__init__.py +42 -0
- qiskit/transpiler/passes/optimization/_gate_extension.py +80 -0
- qiskit/transpiler/passes/optimization/collect_1q_runs.py +31 -0
- qiskit/transpiler/passes/optimization/collect_2q_blocks.py +35 -0
- qiskit/transpiler/passes/optimization/collect_and_collapse.py +117 -0
- qiskit/transpiler/passes/optimization/collect_cliffords.py +109 -0
- qiskit/transpiler/passes/optimization/collect_linear_functions.py +85 -0
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +242 -0
- qiskit/transpiler/passes/optimization/commutation_analysis.py +44 -0
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +82 -0
- qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +140 -0
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +176 -0
- qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
- qiskit/transpiler/passes/optimization/elide_permutations.py +91 -0
- qiskit/transpiler/passes/optimization/hoare_opt.py +420 -0
- qiskit/transpiler/passes/optimization/inverse_cancellation.py +95 -0
- qiskit/transpiler/passes/optimization/light_cone.py +135 -0
- qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +267 -0
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +251 -0
- qiskit/transpiler/passes/optimization/optimize_1q_gates.py +384 -0
- qiskit/transpiler/passes/optimization/optimize_annotated.py +449 -0
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/optimize_cliffords.py +89 -0
- qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +71 -0
- qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py +41 -0
- qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
- qiskit/transpiler/passes/optimization/remove_identity_equiv.py +70 -0
- qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py +37 -0
- qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +50 -0
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +63 -0
- qiskit/transpiler/passes/optimization/template_matching/__init__.py +19 -0
- qiskit/transpiler/passes/optimization/template_matching/backward_match.py +749 -0
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +452 -0
- qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py +77 -0
- qiskit/transpiler/passes/optimization/template_matching/template_matching.py +370 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +633 -0
- qiskit/transpiler/passes/optimization/template_optimization.py +158 -0
- qiskit/transpiler/passes/routing/__init__.py +21 -0
- qiskit/transpiler/passes/routing/algorithms/__init__.py +33 -0
- qiskit/transpiler/passes/routing/algorithms/token_swapper.py +105 -0
- qiskit/transpiler/passes/routing/algorithms/types.py +46 -0
- qiskit/transpiler/passes/routing/algorithms/util.py +103 -0
- qiskit/transpiler/passes/routing/basic_swap.py +166 -0
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/__init__.py +25 -0
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_block.py +60 -0
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +397 -0
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py +145 -0
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +306 -0
- qiskit/transpiler/passes/routing/layout_transformation.py +119 -0
- qiskit/transpiler/passes/routing/lookahead_swap.py +390 -0
- qiskit/transpiler/passes/routing/sabre_swap.py +465 -0
- qiskit/transpiler/passes/routing/star_prerouting.py +433 -0
- qiskit/transpiler/passes/routing/utils.py +35 -0
- qiskit/transpiler/passes/scheduling/__init__.py +21 -0
- qiskit/transpiler/passes/scheduling/alignments/__init__.py +79 -0
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +70 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +251 -0
- qiskit/transpiler/passes/scheduling/padding/__init__.py +17 -0
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +284 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +415 -0
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +90 -0
- qiskit/transpiler/passes/scheduling/scheduling/__init__.py +17 -0
- qiskit/transpiler/passes/scheduling/scheduling/alap.py +93 -0
- qiskit/transpiler/passes/scheduling/scheduling/asap.py +100 -0
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +88 -0
- qiskit/transpiler/passes/scheduling/scheduling/set_io_latency.py +64 -0
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +237 -0
- qiskit/transpiler/passes/synthesis/__init__.py +21 -0
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +153 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +429 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +2338 -0
- qiskit/transpiler/passes/synthesis/linear_functions_synthesis.py +41 -0
- qiskit/transpiler/passes/synthesis/plugin.py +738 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +318 -0
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +425 -0
- qiskit/transpiler/passes/utils/__init__.py +32 -0
- qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +41 -0
- qiskit/transpiler/passes/utils/check_gate_direction.py +60 -0
- qiskit/transpiler/passes/utils/check_map.py +78 -0
- qiskit/transpiler/passes/utils/contains_instruction.py +45 -0
- qiskit/transpiler/passes/utils/control_flow.py +61 -0
- qiskit/transpiler/passes/utils/dag_fixed_point.py +36 -0
- qiskit/transpiler/passes/utils/error.py +69 -0
- qiskit/transpiler/passes/utils/filter_op_nodes.py +66 -0
- qiskit/transpiler/passes/utils/fixed_point.py +48 -0
- qiskit/transpiler/passes/utils/gate_direction.py +93 -0
- qiskit/transpiler/passes/utils/gates_basis.py +51 -0
- qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +163 -0
- qiskit/transpiler/passes/utils/minimum_point.py +118 -0
- qiskit/transpiler/passes/utils/remove_barriers.py +50 -0
- qiskit/transpiler/passes/utils/remove_final_measurements.py +121 -0
- qiskit/transpiler/passes/utils/unroll_forloops.py +81 -0
- qiskit/transpiler/passmanager.py +503 -0
- qiskit/transpiler/passmanager_config.py +154 -0
- qiskit/transpiler/preset_passmanagers/__init__.py +93 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +1114 -0
- qiskit/transpiler/preset_passmanagers/common.py +773 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +443 -0
- qiskit/transpiler/preset_passmanagers/level0.py +104 -0
- qiskit/transpiler/preset_passmanagers/level1.py +108 -0
- qiskit/transpiler/preset_passmanagers/level2.py +109 -0
- qiskit/transpiler/preset_passmanagers/level3.py +110 -0
- qiskit/transpiler/preset_passmanagers/plugin.py +346 -0
- qiskit/transpiler/target.py +905 -0
- qiskit/transpiler/timing_constraints.py +59 -0
- qiskit/user_config.py +266 -0
- qiskit/utils/__init__.py +90 -0
- qiskit/utils/classtools.py +146 -0
- qiskit/utils/deprecation.py +382 -0
- qiskit/utils/lazy_tester.py +363 -0
- qiskit/utils/optionals.py +355 -0
- qiskit/utils/parallel.py +318 -0
- qiskit/utils/units.py +146 -0
- qiskit/version.py +84 -0
- qiskit/visualization/__init__.py +290 -0
- qiskit/visualization/array.py +207 -0
- qiskit/visualization/bloch.py +778 -0
- qiskit/visualization/circuit/__init__.py +15 -0
- qiskit/visualization/circuit/_utils.py +677 -0
- qiskit/visualization/circuit/circuit_visualization.py +735 -0
- qiskit/visualization/circuit/latex.py +668 -0
- qiskit/visualization/circuit/matplotlib.py +2041 -0
- qiskit/visualization/circuit/qcstyle.py +130 -0
- qiskit/visualization/circuit/styles/__init__.py +13 -0
- qiskit/visualization/circuit/styles/bw.json +202 -0
- qiskit/visualization/circuit/styles/clifford.json +202 -0
- qiskit/visualization/circuit/styles/iqp-dark.json +214 -0
- qiskit/visualization/circuit/styles/iqp.json +214 -0
- qiskit/visualization/circuit/styles/textbook.json +202 -0
- qiskit/visualization/circuit/text.py +1849 -0
- qiskit/visualization/circuit_visualization.py +19 -0
- qiskit/visualization/counts_visualization.py +487 -0
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +389 -0
- qiskit/visualization/exceptions.py +21 -0
- qiskit/visualization/gate_map.py +1424 -0
- qiskit/visualization/library.py +40 -0
- qiskit/visualization/pass_manager_visualization.py +312 -0
- qiskit/visualization/state_visualization.py +1546 -0
- qiskit/visualization/style.py +223 -0
- qiskit/visualization/timeline/__init__.py +21 -0
- qiskit/visualization/timeline/core.py +495 -0
- qiskit/visualization/timeline/drawings.py +260 -0
- qiskit/visualization/timeline/generators.py +506 -0
- qiskit/visualization/timeline/interface.py +444 -0
- qiskit/visualization/timeline/layouts.py +115 -0
- qiskit/visualization/timeline/plotters/__init__.py +16 -0
- qiskit/visualization/timeline/plotters/base_plotter.py +58 -0
- qiskit/visualization/timeline/plotters/matplotlib.py +195 -0
- qiskit/visualization/timeline/stylesheet.py +301 -0
- qiskit/visualization/timeline/types.py +148 -0
- qiskit/visualization/transition_visualization.py +369 -0
- qiskit/visualization/utils.py +49 -0
- qiskit-2.1.0rc1.dist-info/METADATA +221 -0
- qiskit-2.1.0rc1.dist-info/RECORD +699 -0
- qiskit-2.1.0rc1.dist-info/WHEEL +6 -0
- qiskit-2.1.0rc1.dist-info/entry_points.txt +88 -0
- qiskit-2.1.0rc1.dist-info/licenses/LICENSE.txt +203 -0
- qiskit-2.1.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2338 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2022, 2023.
|
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
|
+
|
14
|
+
"""
|
15
|
+
|
16
|
+
High Level Synthesis Plugins
|
17
|
+
-----------------------------
|
18
|
+
|
19
|
+
Clifford Synthesis
|
20
|
+
''''''''''''''''''
|
21
|
+
|
22
|
+
.. list-table:: Plugins for :class:`qiskit.quantum_info.Clifford` (key = ``"clifford"``)
|
23
|
+
:header-rows: 1
|
24
|
+
|
25
|
+
* - Plugin name
|
26
|
+
- Plugin class
|
27
|
+
- Targeted connectivity
|
28
|
+
- Description
|
29
|
+
* - ``"ag"``
|
30
|
+
- :class:`~.AGSynthesisClifford`
|
31
|
+
- all-to-all
|
32
|
+
- greedily optimizes CX-count
|
33
|
+
* - ``"bm"``
|
34
|
+
- :class:`~.BMSynthesisClifford`
|
35
|
+
- all-to-all
|
36
|
+
- optimal count for `n=2,3`; used in ``"default"`` for `n=2,3`
|
37
|
+
* - ``"greedy"``
|
38
|
+
- :class:`~.GreedySynthesisClifford`
|
39
|
+
- all-to-all
|
40
|
+
- greedily optimizes CX-count; used in ``"default"`` for `n>=4`
|
41
|
+
* - ``"layers"``
|
42
|
+
- :class:`~.LayerSynthesisClifford`
|
43
|
+
- all-to-all
|
44
|
+
-
|
45
|
+
* - ``"lnn"``
|
46
|
+
- :class:`~.LayerLnnSynthesisClifford`
|
47
|
+
- linear
|
48
|
+
- many CX-gates but guarantees CX-depth of at most `7*n+2`
|
49
|
+
* - ``"default"``
|
50
|
+
- :class:`~.DefaultSynthesisClifford`
|
51
|
+
- all-to-all
|
52
|
+
- usually best for optimizing CX-count (and optimal CX-count for `n=2,3`)
|
53
|
+
|
54
|
+
.. autosummary::
|
55
|
+
:toctree: ../stubs/
|
56
|
+
|
57
|
+
AGSynthesisClifford
|
58
|
+
BMSynthesisClifford
|
59
|
+
GreedySynthesisClifford
|
60
|
+
LayerSynthesisClifford
|
61
|
+
LayerLnnSynthesisClifford
|
62
|
+
DefaultSynthesisClifford
|
63
|
+
|
64
|
+
|
65
|
+
Linear Function Synthesis
|
66
|
+
'''''''''''''''''''''''''
|
67
|
+
|
68
|
+
.. list-table:: Plugins for :class:`.LinearFunction` (key = ``"linear"``)
|
69
|
+
:header-rows: 1
|
70
|
+
|
71
|
+
* - Plugin name
|
72
|
+
- Plugin class
|
73
|
+
- Targeted connectivity
|
74
|
+
- Description
|
75
|
+
* - ``"kms"``
|
76
|
+
- :class:`~.KMSSynthesisLinearFunction`
|
77
|
+
- linear
|
78
|
+
- many CX-gates but guarantees CX-depth of at most `5*n`
|
79
|
+
* - ``"pmh"``
|
80
|
+
- :class:`~.PMHSynthesisLinearFunction`
|
81
|
+
- all-to-all
|
82
|
+
- greedily optimizes CX-count; used in ``"default"``
|
83
|
+
* - ``"default"``
|
84
|
+
- :class:`~.DefaultSynthesisLinearFunction`
|
85
|
+
- all-to-all
|
86
|
+
- best for optimizing CX-count
|
87
|
+
|
88
|
+
.. autosummary::
|
89
|
+
:toctree: ../stubs/
|
90
|
+
|
91
|
+
KMSSynthesisLinearFunction
|
92
|
+
PMHSynthesisLinearFunction
|
93
|
+
DefaultSynthesisLinearFunction
|
94
|
+
|
95
|
+
|
96
|
+
Permutation Synthesis
|
97
|
+
'''''''''''''''''''''
|
98
|
+
|
99
|
+
.. list-table:: Plugins for :class:`.PermutationGate` (key = ``"permutation"``)
|
100
|
+
:header-rows: 1
|
101
|
+
|
102
|
+
* - Plugin name
|
103
|
+
- Plugin class
|
104
|
+
- Targeted connectivity
|
105
|
+
- Description
|
106
|
+
* - ``"basic"``
|
107
|
+
- :class:`~.BasicSynthesisPermutation`
|
108
|
+
- all-to-all
|
109
|
+
- optimal SWAP-count; used in ``"default"``
|
110
|
+
* - ``"acg"``
|
111
|
+
- :class:`~.ACGSynthesisPermutation`
|
112
|
+
- all-to-all
|
113
|
+
- guarantees SWAP-depth of at most `2`
|
114
|
+
* - ``"kms"``
|
115
|
+
- :class:`~.KMSSynthesisPermutation`
|
116
|
+
- linear
|
117
|
+
- many SWAP-gates, but guarantees SWAP-depth of at most `n`
|
118
|
+
* - ``"token_swapper"``
|
119
|
+
- :class:`~.TokenSwapperSynthesisPermutation`
|
120
|
+
- any
|
121
|
+
- greedily optimizes SWAP-count for arbitrary connectivity
|
122
|
+
* - ``"default"``
|
123
|
+
- :class:`~.BasicSynthesisPermutation`
|
124
|
+
- all-to-all
|
125
|
+
- best for optimizing SWAP-count
|
126
|
+
|
127
|
+
.. autosummary::
|
128
|
+
:toctree: ../stubs/
|
129
|
+
|
130
|
+
BasicSynthesisPermutation
|
131
|
+
ACGSynthesisPermutation
|
132
|
+
KMSSynthesisPermutation
|
133
|
+
TokenSwapperSynthesisPermutation
|
134
|
+
|
135
|
+
|
136
|
+
QFT Synthesis
|
137
|
+
'''''''''''''
|
138
|
+
|
139
|
+
.. list-table:: Plugins for :class:`.QFTGate` (key = ``"qft"``)
|
140
|
+
:header-rows: 1
|
141
|
+
|
142
|
+
* - Plugin name
|
143
|
+
- Plugin class
|
144
|
+
- Targeted connectivity
|
145
|
+
* - ``"full"``
|
146
|
+
- :class:`~.QFTSynthesisFull`
|
147
|
+
- all-to-all
|
148
|
+
* - ``"line"``
|
149
|
+
- :class:`~.QFTSynthesisLine`
|
150
|
+
- linear
|
151
|
+
* - ``"default"``
|
152
|
+
- :class:`~.QFTSynthesisFull`
|
153
|
+
- all-to-all
|
154
|
+
|
155
|
+
.. autosummary::
|
156
|
+
:toctree: ../stubs/
|
157
|
+
|
158
|
+
QFTSynthesisFull
|
159
|
+
QFTSynthesisLine
|
160
|
+
|
161
|
+
|
162
|
+
MCX Synthesis
|
163
|
+
'''''''''''''
|
164
|
+
|
165
|
+
The following table lists synthesis plugins available for an :class:`.MCXGate` gate
|
166
|
+
with `k` control qubits. If the available number of clean/dirty auxiliary qubits is
|
167
|
+
not sufficient, the corresponding synthesis method will return `None`.
|
168
|
+
|
169
|
+
.. list-table:: Plugins for :class:`.MCXGate` (key = ``"mcx"``)
|
170
|
+
:header-rows: 1
|
171
|
+
|
172
|
+
* - Plugin name
|
173
|
+
- Plugin class
|
174
|
+
- Number of clean ancillas
|
175
|
+
- Number of dirty ancillas
|
176
|
+
- Description
|
177
|
+
* - ``"gray_code"``
|
178
|
+
- :class:`~.MCXSynthesisGrayCode`
|
179
|
+
- `0`
|
180
|
+
- `0`
|
181
|
+
- exponentially many CX gates; use only for small values of `k`
|
182
|
+
* - ``"noaux_v24"``
|
183
|
+
- :class:`~.MCXSynthesisNoAuxV24`
|
184
|
+
- `0`
|
185
|
+
- `0`
|
186
|
+
- quadratic number of CX gates; use instead of ``"gray_code"`` for large values of `k`
|
187
|
+
* - ``"n_clean_m15"``
|
188
|
+
- :class:`~.MCXSynthesisNCleanM15`
|
189
|
+
- `k-2`
|
190
|
+
- `0`
|
191
|
+
- at most `6*k-6` CX gates
|
192
|
+
* - ``"n_dirty_i15"``
|
193
|
+
- :class:`~.MCXSynthesisNDirtyI15`
|
194
|
+
- `0`
|
195
|
+
- `k-2`
|
196
|
+
- at most `8*k-6` CX gates
|
197
|
+
* - ``"2_clean_kg24"``
|
198
|
+
- :class:`~.MCXSynthesis2CleanKG24`
|
199
|
+
- `2`
|
200
|
+
- `0`
|
201
|
+
- at most `12*k-18` CX gates
|
202
|
+
* - ``"2_dirty_kg24"``
|
203
|
+
- :class:`~.MCXSynthesis2DirtyKG24`
|
204
|
+
- `0`
|
205
|
+
- `2`
|
206
|
+
- at most `24*k-48` CX gates
|
207
|
+
* - ``"1_clean_kg24"``
|
208
|
+
- :class:`~.MCXSynthesis1CleanKG24`
|
209
|
+
- `1`
|
210
|
+
- `0`
|
211
|
+
- at most `12*k-18` CX gates
|
212
|
+
* - ``"1_dirty_kg24"``
|
213
|
+
- :class:`~.MCXSynthesis1DirtyKG24`
|
214
|
+
- `0`
|
215
|
+
- `1`
|
216
|
+
- at most `24*k-48` CX gates
|
217
|
+
* - ``"1_clean_b95"``
|
218
|
+
- :class:`~.MCXSynthesis1CleanB95`
|
219
|
+
- `1`
|
220
|
+
- `0`
|
221
|
+
- at most `16*k-8` CX gates
|
222
|
+
* - ``"default"``
|
223
|
+
- :class:`~.MCXSynthesisDefault`
|
224
|
+
- any
|
225
|
+
- any
|
226
|
+
- chooses the best algorithm based on the ancillas available
|
227
|
+
|
228
|
+
.. autosummary::
|
229
|
+
:toctree: ../stubs/
|
230
|
+
|
231
|
+
MCXSynthesisGrayCode
|
232
|
+
MCXSynthesisNoAuxV24
|
233
|
+
MCXSynthesisNCleanM15
|
234
|
+
MCXSynthesisNDirtyI15
|
235
|
+
MCXSynthesis2CleanKG24
|
236
|
+
MCXSynthesis2DirtyKG24
|
237
|
+
MCXSynthesis1CleanKG24
|
238
|
+
MCXSynthesis1DirtyKG24
|
239
|
+
MCXSynthesis1CleanB95
|
240
|
+
MCXSynthesisDefault
|
241
|
+
|
242
|
+
|
243
|
+
MCMT Synthesis
|
244
|
+
''''''''''''''
|
245
|
+
|
246
|
+
.. list-table:: Plugins for :class:`.MCMTGate` (key = ``"mcmt"``)
|
247
|
+
:header-rows: 1
|
248
|
+
|
249
|
+
* - Plugin name
|
250
|
+
- Plugin class
|
251
|
+
- Number of clean ancillas
|
252
|
+
- Number of dirty ancillas
|
253
|
+
- Description
|
254
|
+
* - ``"vchain"``
|
255
|
+
- :class:`.MCMTSynthesisVChain`
|
256
|
+
- `k-1`
|
257
|
+
- `0`
|
258
|
+
- uses a linear number of Toffoli gates
|
259
|
+
* - ``"noaux"``
|
260
|
+
- :class:`~.MCMTSynthesisNoAux`
|
261
|
+
- `0`
|
262
|
+
- `0`
|
263
|
+
- uses Qiskit's standard control mechanism
|
264
|
+
* - ``"default"``
|
265
|
+
- :class:`~.MCMTSynthesisDefault`
|
266
|
+
- any
|
267
|
+
- any
|
268
|
+
- chooses the best algorithm based on the ancillas available
|
269
|
+
|
270
|
+
.. autosummary::
|
271
|
+
:toctree: ../stubs/
|
272
|
+
|
273
|
+
MCMTSynthesisVChain
|
274
|
+
MCMTSynthesisNoAux
|
275
|
+
MCMTSynthesisDefault
|
276
|
+
|
277
|
+
|
278
|
+
Integer comparators
|
279
|
+
'''''''''''''''''''
|
280
|
+
|
281
|
+
.. list-table:: Plugins for :class:`.IntegerComparatorGate` (key = ``"IntComp"``)
|
282
|
+
:header-rows: 1
|
283
|
+
|
284
|
+
* - Plugin name
|
285
|
+
- Plugin class
|
286
|
+
- Description
|
287
|
+
- Auxiliary qubits
|
288
|
+
* - ``"twos"``
|
289
|
+
- :class:`~.IntComparatorSynthesis2s`
|
290
|
+
- use addition with two's complement
|
291
|
+
- ``n - 1`` clean
|
292
|
+
* - ``"noaux"``
|
293
|
+
- :class:`~.IntComparatorSynthesisNoAux`
|
294
|
+
- flip the target controlled on all :math:`O(2^l)` allowed integer values
|
295
|
+
- none
|
296
|
+
* - ``"default"``
|
297
|
+
- :class:`~.IntComparatorSynthesisDefault`
|
298
|
+
- use the best algorithm depending on the available auxiliary qubits
|
299
|
+
- any
|
300
|
+
|
301
|
+
.. autosummary::
|
302
|
+
:toctree: ../stubs/
|
303
|
+
|
304
|
+
IntComparatorSynthesis2s
|
305
|
+
IntComparatorSynthesisNoAux
|
306
|
+
IntComparatorSynthesisDefault
|
307
|
+
|
308
|
+
|
309
|
+
Sums
|
310
|
+
''''
|
311
|
+
|
312
|
+
.. list-table:: Plugins for :class:`.WeightedSumGate` (key = ``"WeightedSum"``)
|
313
|
+
:header-rows: 1
|
314
|
+
|
315
|
+
* - Plugin name
|
316
|
+
- Plugin class
|
317
|
+
- Description
|
318
|
+
- Auxiliary qubits
|
319
|
+
* - ``"default"``
|
320
|
+
- :class:`.WeightedSumSynthesisDefault`
|
321
|
+
- use a V-chain based synthesis
|
322
|
+
- given ``s`` sum qubits, used ``s - 1 + int(s > 2)`` clean auxiliary qubits
|
323
|
+
|
324
|
+
.. autosummary::
|
325
|
+
:toctree: ../stubs/
|
326
|
+
|
327
|
+
WeightedSumSynthesisDefault
|
328
|
+
|
329
|
+
|
330
|
+
Pauli Evolution Synthesis
|
331
|
+
'''''''''''''''''''''''''
|
332
|
+
|
333
|
+
.. list-table:: Plugins for :class:`.PauliEvolutionGate` (key = ``"PauliEvolution"``)
|
334
|
+
:header-rows: 1
|
335
|
+
|
336
|
+
* - Plugin name
|
337
|
+
- Plugin class
|
338
|
+
- Description
|
339
|
+
- Targeted connectivity
|
340
|
+
* - ``"rustiq"``
|
341
|
+
- :class:`~.PauliEvolutionSynthesisRustiq`
|
342
|
+
- use the synthesis method from `Rustiq circuit synthesis library
|
343
|
+
<https://github.com/smartiel/rustiq-core>`_
|
344
|
+
- all-to-all
|
345
|
+
* - ``"default"``
|
346
|
+
- :class:`~.PauliEvolutionSynthesisDefault`
|
347
|
+
- use a diagonalizing Clifford per Pauli term
|
348
|
+
- all-to-all
|
349
|
+
|
350
|
+
.. autosummary::
|
351
|
+
:toctree: ../stubs/
|
352
|
+
|
353
|
+
PauliEvolutionSynthesisDefault
|
354
|
+
PauliEvolutionSynthesisRustiq
|
355
|
+
|
356
|
+
|
357
|
+
Modular Adder Synthesis
|
358
|
+
'''''''''''''''''''''''
|
359
|
+
|
360
|
+
.. list-table:: Plugins for :class:`.ModularAdderGate` (key = ``"ModularAdder"``)
|
361
|
+
:header-rows: 1
|
362
|
+
|
363
|
+
* - Plugin name
|
364
|
+
- Plugin class
|
365
|
+
- Number of clean ancillas
|
366
|
+
- Description
|
367
|
+
* - ``"ripple_cdkm"``
|
368
|
+
- :class:`.ModularAdderSynthesisC04`
|
369
|
+
- 1
|
370
|
+
- a ripple-carry adder
|
371
|
+
* - ``"ripple_vbe"``
|
372
|
+
- :class:`.ModularAdderSynthesisV95`
|
373
|
+
- :math:`n-1`, for :math:`n`-bit numbers
|
374
|
+
- a ripple-carry adder
|
375
|
+
* - ``"qft"``
|
376
|
+
- :class:`.ModularAdderSynthesisD00`
|
377
|
+
- 0
|
378
|
+
- a QFT-based adder
|
379
|
+
* - ``"default"``
|
380
|
+
- :class:`~.ModularAdderSynthesisDefault`
|
381
|
+
- any
|
382
|
+
- chooses the best algorithm based on the ancillas available
|
383
|
+
|
384
|
+
.. autosummary::
|
385
|
+
:toctree: ../stubs/
|
386
|
+
|
387
|
+
ModularAdderSynthesisC04
|
388
|
+
ModularAdderSynthesisD00
|
389
|
+
ModularAdderSynthesisV95
|
390
|
+
ModularAdderSynthesisDefault
|
391
|
+
|
392
|
+
Half Adder Synthesis
|
393
|
+
''''''''''''''''''''
|
394
|
+
|
395
|
+
.. list-table:: Plugins for :class:`.HalfAdderGate` (key = ``"HalfAdder"``)
|
396
|
+
:header-rows: 1
|
397
|
+
|
398
|
+
* - Plugin name
|
399
|
+
- Plugin class
|
400
|
+
- Number of clean ancillas
|
401
|
+
- Description
|
402
|
+
* - ``"ripple_cdkm"``
|
403
|
+
- :class:`.HalfAdderSynthesisC04`
|
404
|
+
- 1
|
405
|
+
- a ripple-carry adder
|
406
|
+
* - ``"ripple_r25"``
|
407
|
+
- :class:`.HalfAdderSynthesisR25`
|
408
|
+
- 0
|
409
|
+
- a ripple-carry adder with no ancillas
|
410
|
+
* - ``"ripple_vbe"``
|
411
|
+
- :class:`.HalfAdderSynthesisV95`
|
412
|
+
- :math:`n-1`, for :math:`n`-bit numbers
|
413
|
+
- a ripple-carry adder
|
414
|
+
* - ``"qft"``
|
415
|
+
- :class:`.HalfAdderSynthesisD00`
|
416
|
+
- 0
|
417
|
+
- a QFT-based adder
|
418
|
+
* - ``"default"``
|
419
|
+
- :class:`~.HalfAdderSynthesisDefault`
|
420
|
+
- any
|
421
|
+
- chooses the best algorithm based on the ancillas available
|
422
|
+
|
423
|
+
.. autosummary::
|
424
|
+
:toctree: ../stubs/
|
425
|
+
|
426
|
+
HalfAdderSynthesisC04
|
427
|
+
HalfAdderSynthesisD00
|
428
|
+
HalfAdderSynthesisV95
|
429
|
+
HalfAdderSynthesisR25
|
430
|
+
HalfAdderSynthesisDefault
|
431
|
+
|
432
|
+
Full Adder Synthesis
|
433
|
+
''''''''''''''''''''
|
434
|
+
|
435
|
+
.. list-table:: Plugins for :class:`.FullAdderGate` (key = ``"FullAdder"``)
|
436
|
+
:header-rows: 1
|
437
|
+
|
438
|
+
* - Plugin name
|
439
|
+
- Plugin class
|
440
|
+
- Number of clean ancillas
|
441
|
+
- Description
|
442
|
+
* - ``"ripple_cdkm"``
|
443
|
+
- :class:`.FullAdderSynthesisC04`
|
444
|
+
- 0
|
445
|
+
- a ripple-carry adder
|
446
|
+
* - ``"ripple_vbe"``
|
447
|
+
- :class:`.FullAdderSynthesisV95`
|
448
|
+
- :math:`n-1`, for :math:`n`-bit numbers
|
449
|
+
- a ripple-carry adder
|
450
|
+
* - ``"default"``
|
451
|
+
- :class:`~.FullAdderSynthesisDefault`
|
452
|
+
- any
|
453
|
+
- chooses the best algorithm based on the ancillas available
|
454
|
+
|
455
|
+
.. autosummary::
|
456
|
+
:toctree: ../stubs/
|
457
|
+
|
458
|
+
FullAdderSynthesisC04
|
459
|
+
FullAdderSynthesisV95
|
460
|
+
FullAdderSynthesisDefault
|
461
|
+
|
462
|
+
|
463
|
+
Multiplier Synthesis
|
464
|
+
''''''''''''''''''''
|
465
|
+
|
466
|
+
.. list-table:: Plugins for :class:`.MultiplierGate` (key = ``"Multiplier"``)
|
467
|
+
:header-rows: 1
|
468
|
+
|
469
|
+
* - Plugin name
|
470
|
+
- Plugin class
|
471
|
+
- Number of clean ancillas
|
472
|
+
- Description
|
473
|
+
* - ``"cumulative"``
|
474
|
+
- :class:`.MultiplierSynthesisH18`
|
475
|
+
- depending on the :class:`.AdderGate` used
|
476
|
+
- a cumulative adder based on controlled adders
|
477
|
+
* - ``"qft"``
|
478
|
+
- :class:`.MultiplierSynthesisR17`
|
479
|
+
- 0
|
480
|
+
- a QFT-based multiplier
|
481
|
+
|
482
|
+
.. autosummary::
|
483
|
+
:toctree: ../stubs/
|
484
|
+
|
485
|
+
MultiplierSynthesisH18
|
486
|
+
MultiplierSynthesisR17
|
487
|
+
|
488
|
+
"""
|
489
|
+
|
490
|
+
from __future__ import annotations
|
491
|
+
|
492
|
+
import warnings
|
493
|
+
import numpy as np
|
494
|
+
import rustworkx as rx
|
495
|
+
|
496
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
497
|
+
from qiskit.circuit.operation import Operation
|
498
|
+
from qiskit.circuit.library import (
|
499
|
+
LinearFunction,
|
500
|
+
QFTGate,
|
501
|
+
MCXGate,
|
502
|
+
C3XGate,
|
503
|
+
C4XGate,
|
504
|
+
PauliEvolutionGate,
|
505
|
+
PermutationGate,
|
506
|
+
MCMTGate,
|
507
|
+
ModularAdderGate,
|
508
|
+
HalfAdderGate,
|
509
|
+
FullAdderGate,
|
510
|
+
MultiplierGate,
|
511
|
+
WeightedSumGate,
|
512
|
+
GlobalPhaseGate,
|
513
|
+
)
|
514
|
+
from qiskit.circuit.annotated_operation import (
|
515
|
+
AnnotatedOperation,
|
516
|
+
Modifier,
|
517
|
+
ControlModifier,
|
518
|
+
InverseModifier,
|
519
|
+
PowerModifier,
|
520
|
+
_canonicalize_modifiers,
|
521
|
+
)
|
522
|
+
from qiskit.transpiler.coupling import CouplingMap
|
523
|
+
|
524
|
+
from qiskit.synthesis.arithmetic import (
|
525
|
+
synth_integer_comparator_2s,
|
526
|
+
synth_integer_comparator_greedy,
|
527
|
+
synth_weighted_sum_carry,
|
528
|
+
)
|
529
|
+
from qiskit.synthesis.clifford import (
|
530
|
+
synth_clifford_full,
|
531
|
+
synth_clifford_layers,
|
532
|
+
synth_clifford_depth_lnn,
|
533
|
+
synth_clifford_greedy,
|
534
|
+
synth_clifford_ag,
|
535
|
+
synth_clifford_bm,
|
536
|
+
)
|
537
|
+
from qiskit.synthesis.linear import (
|
538
|
+
synth_cnot_count_full_pmh,
|
539
|
+
synth_cnot_depth_line_kms,
|
540
|
+
calc_inverse_matrix,
|
541
|
+
)
|
542
|
+
from qiskit.synthesis.linear.linear_circuits_utils import transpose_cx_circ
|
543
|
+
from qiskit.synthesis.permutation import (
|
544
|
+
synth_permutation_basic,
|
545
|
+
synth_permutation_acg,
|
546
|
+
synth_permutation_depth_lnn_kms,
|
547
|
+
)
|
548
|
+
from qiskit.synthesis.qft import (
|
549
|
+
synth_qft_full,
|
550
|
+
synth_qft_line,
|
551
|
+
)
|
552
|
+
from qiskit.synthesis.multi_controlled import (
|
553
|
+
synth_mcx_n_dirty_i15,
|
554
|
+
synth_mcx_2_dirty_kg24,
|
555
|
+
synth_mcx_1_dirty_kg24,
|
556
|
+
synth_mcx_n_clean_m15,
|
557
|
+
synth_mcx_2_clean_kg24,
|
558
|
+
synth_mcx_1_clean_kg24,
|
559
|
+
synth_mcx_1_clean_b95,
|
560
|
+
synth_mcx_gray_code,
|
561
|
+
synth_mcx_noaux_v24,
|
562
|
+
synth_mcmt_vchain,
|
563
|
+
)
|
564
|
+
from qiskit.synthesis.evolution import ProductFormula, synth_pauli_network_rustiq
|
565
|
+
from qiskit.synthesis.arithmetic import (
|
566
|
+
adder_ripple_c04,
|
567
|
+
adder_qft_d00,
|
568
|
+
adder_ripple_v95,
|
569
|
+
adder_ripple_r25,
|
570
|
+
multiplier_qft_r17,
|
571
|
+
multiplier_cumulative_h18,
|
572
|
+
)
|
573
|
+
from qiskit.quantum_info.operators import Clifford
|
574
|
+
from qiskit.transpiler.passes.routing.algorithms import ApproximateTokenSwapper
|
575
|
+
from qiskit.transpiler.exceptions import TranspilerError
|
576
|
+
from qiskit.circuit._add_control import EFFICIENTLY_CONTROLLED_GATES
|
577
|
+
|
578
|
+
from qiskit._accelerate.high_level_synthesis import synthesize_operation, HighLevelSynthesisData
|
579
|
+
from .plugin import HighLevelSynthesisPlugin
|
580
|
+
|
581
|
+
|
582
|
+
class DefaultSynthesisClifford(HighLevelSynthesisPlugin):
|
583
|
+
"""The default clifford synthesis plugin.
|
584
|
+
|
585
|
+
For N <= 3 qubits this is the optimal CX cost decomposition by Bravyi, Maslov.
|
586
|
+
For N > 3 qubits this is done using the general non-optimal greedy compilation
|
587
|
+
routine from reference by Bravyi, Hu, Maslov, Shaydulin.
|
588
|
+
|
589
|
+
This plugin name is :``clifford.default`` which can be used as the key on
|
590
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
591
|
+
"""
|
592
|
+
|
593
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
594
|
+
"""Run synthesis for the given Clifford."""
|
595
|
+
if not isinstance(high_level_object, Clifford):
|
596
|
+
return None
|
597
|
+
|
598
|
+
decomposition = synth_clifford_full(high_level_object)
|
599
|
+
return decomposition
|
600
|
+
|
601
|
+
|
602
|
+
class AGSynthesisClifford(HighLevelSynthesisPlugin):
|
603
|
+
"""Clifford synthesis plugin based on the Aaronson-Gottesman method.
|
604
|
+
|
605
|
+
This plugin name is :``clifford.ag`` which can be used as the key on
|
606
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
607
|
+
"""
|
608
|
+
|
609
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
610
|
+
"""Run synthesis for the given Clifford."""
|
611
|
+
if not isinstance(high_level_object, Clifford):
|
612
|
+
return None
|
613
|
+
|
614
|
+
decomposition = synth_clifford_ag(high_level_object)
|
615
|
+
return decomposition
|
616
|
+
|
617
|
+
|
618
|
+
class BMSynthesisClifford(HighLevelSynthesisPlugin):
|
619
|
+
"""Clifford synthesis plugin based on the Bravyi-Maslov method.
|
620
|
+
|
621
|
+
The method only works on Cliffords with at most 3 qubits, for which it
|
622
|
+
constructs the optimal CX cost decomposition.
|
623
|
+
|
624
|
+
This plugin name is :``clifford.bm`` which can be used as the key on
|
625
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
626
|
+
"""
|
627
|
+
|
628
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
629
|
+
"""Run synthesis for the given Clifford."""
|
630
|
+
if not isinstance(high_level_object, Clifford):
|
631
|
+
return None
|
632
|
+
|
633
|
+
if high_level_object.num_qubits <= 3:
|
634
|
+
decomposition = synth_clifford_bm(high_level_object)
|
635
|
+
else:
|
636
|
+
decomposition = None
|
637
|
+
|
638
|
+
return decomposition
|
639
|
+
|
640
|
+
|
641
|
+
class GreedySynthesisClifford(HighLevelSynthesisPlugin):
|
642
|
+
"""Clifford synthesis plugin based on the greedy synthesis
|
643
|
+
Bravyi-Hu-Maslov-Shaydulin method.
|
644
|
+
|
645
|
+
This plugin name is :``clifford.greedy`` which can be used as the key on
|
646
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
647
|
+
"""
|
648
|
+
|
649
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
650
|
+
"""Run synthesis for the given Clifford."""
|
651
|
+
if not isinstance(high_level_object, Clifford):
|
652
|
+
return None
|
653
|
+
|
654
|
+
decomposition = synth_clifford_greedy(high_level_object)
|
655
|
+
return decomposition
|
656
|
+
|
657
|
+
|
658
|
+
class LayerSynthesisClifford(HighLevelSynthesisPlugin):
|
659
|
+
"""Clifford synthesis plugin based on the Bravyi-Maslov method
|
660
|
+
to synthesize Cliffords into layers.
|
661
|
+
|
662
|
+
This plugin name is :``clifford.layers`` which can be used as the key on
|
663
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
664
|
+
"""
|
665
|
+
|
666
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
667
|
+
"""Run synthesis for the given Clifford."""
|
668
|
+
if not isinstance(high_level_object, Clifford):
|
669
|
+
return None
|
670
|
+
|
671
|
+
decomposition = synth_clifford_layers(high_level_object)
|
672
|
+
return decomposition
|
673
|
+
|
674
|
+
|
675
|
+
class LayerLnnSynthesisClifford(HighLevelSynthesisPlugin):
|
676
|
+
"""Clifford synthesis plugin based on the Bravyi-Maslov method
|
677
|
+
to synthesize Cliffords into layers, with each layer synthesized
|
678
|
+
adhering to LNN connectivity.
|
679
|
+
|
680
|
+
This plugin name is :``clifford.lnn`` which can be used as the key on
|
681
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
682
|
+
"""
|
683
|
+
|
684
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
685
|
+
"""Run synthesis for the given Clifford."""
|
686
|
+
if not isinstance(high_level_object, Clifford):
|
687
|
+
return None
|
688
|
+
|
689
|
+
decomposition = synth_clifford_depth_lnn(high_level_object)
|
690
|
+
return decomposition
|
691
|
+
|
692
|
+
|
693
|
+
class DefaultSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
694
|
+
"""The default linear function synthesis plugin.
|
695
|
+
|
696
|
+
This plugin name is :``linear_function.default`` which can be used as the key on
|
697
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
698
|
+
"""
|
699
|
+
|
700
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
701
|
+
"""Run synthesis for the given LinearFunction."""
|
702
|
+
if not isinstance(high_level_object, LinearFunction):
|
703
|
+
return None
|
704
|
+
|
705
|
+
decomposition = synth_cnot_count_full_pmh(high_level_object.linear)
|
706
|
+
return decomposition
|
707
|
+
|
708
|
+
|
709
|
+
class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
710
|
+
"""Linear function synthesis plugin based on the Kutin-Moulton-Smithline method.
|
711
|
+
|
712
|
+
This plugin name is :``linear_function.kms`` which can be used as the key on
|
713
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
714
|
+
|
715
|
+
The plugin supports the following plugin-specific options:
|
716
|
+
|
717
|
+
* use_inverted: Indicates whether to run the algorithm on the inverse matrix
|
718
|
+
and to invert the synthesized circuit.
|
719
|
+
In certain cases this provides a better decomposition than the direct approach.
|
720
|
+
* use_transposed: Indicates whether to run the algorithm on the transposed matrix
|
721
|
+
and to invert the order of CX gates in the synthesized circuit.
|
722
|
+
In certain cases this provides a better decomposition than the direct approach.
|
723
|
+
|
724
|
+
"""
|
725
|
+
|
726
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
727
|
+
"""Run synthesis for the given LinearFunction."""
|
728
|
+
if not isinstance(high_level_object, LinearFunction):
|
729
|
+
return None
|
730
|
+
|
731
|
+
use_inverted = options.get("use_inverted", False)
|
732
|
+
use_transposed = options.get("use_transposed", False)
|
733
|
+
|
734
|
+
mat = high_level_object.linear.astype(bool, copy=False)
|
735
|
+
|
736
|
+
if use_transposed:
|
737
|
+
mat = np.transpose(mat)
|
738
|
+
if use_inverted:
|
739
|
+
mat = calc_inverse_matrix(mat)
|
740
|
+
|
741
|
+
decomposition = synth_cnot_depth_line_kms(mat)
|
742
|
+
|
743
|
+
if use_transposed:
|
744
|
+
decomposition = transpose_cx_circ(decomposition)
|
745
|
+
if use_inverted:
|
746
|
+
decomposition = decomposition.inverse()
|
747
|
+
|
748
|
+
return decomposition
|
749
|
+
|
750
|
+
|
751
|
+
class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
752
|
+
"""Linear function synthesis plugin based on the Patel-Markov-Hayes method.
|
753
|
+
|
754
|
+
This plugin name is :``linear_function.pmh`` which can be used as the key on
|
755
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
756
|
+
|
757
|
+
The plugin supports the following plugin-specific options:
|
758
|
+
|
759
|
+
* section size: The size of each section used in the Patel–Markov–Hayes algorithm [1].
|
760
|
+
* use_inverted: Indicates whether to run the algorithm on the inverse matrix
|
761
|
+
and to invert the synthesized circuit.
|
762
|
+
In certain cases this provides a better decomposition than the direct approach.
|
763
|
+
* use_transposed: Indicates whether to run the algorithm on the transposed matrix
|
764
|
+
and to invert the order of CX gates in the synthesized circuit.
|
765
|
+
In certain cases this provides a better decomposition than the direct approach.
|
766
|
+
|
767
|
+
References:
|
768
|
+
1. Patel, Ketan N., Igor L. Markov, and John P. Hayes,
|
769
|
+
*Optimal synthesis of linear reversible circuits*,
|
770
|
+
Quantum Information & Computation 8.3 (2008): 282-294.
|
771
|
+
`arXiv:quant-ph/0302002 [quant-ph] <https://arxiv.org/abs/quant-ph/0302002>`_
|
772
|
+
"""
|
773
|
+
|
774
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
775
|
+
"""Run synthesis for the given LinearFunction."""
|
776
|
+
if not isinstance(high_level_object, LinearFunction):
|
777
|
+
return None
|
778
|
+
|
779
|
+
section_size = options.get("section_size", 2)
|
780
|
+
use_inverted = options.get("use_inverted", False)
|
781
|
+
use_transposed = options.get("use_transposed", False)
|
782
|
+
|
783
|
+
mat = high_level_object.linear.astype(bool, copy=False)
|
784
|
+
|
785
|
+
if use_transposed:
|
786
|
+
mat = np.transpose(mat)
|
787
|
+
if use_inverted:
|
788
|
+
mat = calc_inverse_matrix(mat)
|
789
|
+
|
790
|
+
decomposition = synth_cnot_count_full_pmh(mat, section_size=section_size)
|
791
|
+
|
792
|
+
if use_transposed:
|
793
|
+
decomposition = transpose_cx_circ(decomposition)
|
794
|
+
if use_inverted:
|
795
|
+
decomposition = decomposition.inverse()
|
796
|
+
|
797
|
+
return decomposition
|
798
|
+
|
799
|
+
|
800
|
+
class KMSSynthesisPermutation(HighLevelSynthesisPlugin):
|
801
|
+
"""The permutation synthesis plugin based on the Kutin, Moulton, Smithline method.
|
802
|
+
|
803
|
+
This plugin name is :``permutation.kms`` which can be used as the key on
|
804
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
805
|
+
"""
|
806
|
+
|
807
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
808
|
+
"""Run synthesis for the given Permutation."""
|
809
|
+
if not isinstance(high_level_object, PermutationGate):
|
810
|
+
return None
|
811
|
+
|
812
|
+
decomposition = synth_permutation_depth_lnn_kms(high_level_object.pattern)
|
813
|
+
return decomposition
|
814
|
+
|
815
|
+
|
816
|
+
class BasicSynthesisPermutation(HighLevelSynthesisPlugin):
|
817
|
+
"""The permutation synthesis plugin based on sorting.
|
818
|
+
|
819
|
+
This plugin name is :``permutation.basic`` which can be used as the key on
|
820
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
821
|
+
"""
|
822
|
+
|
823
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
824
|
+
"""Run synthesis for the given Permutation."""
|
825
|
+
if not isinstance(high_level_object, PermutationGate):
|
826
|
+
return None
|
827
|
+
|
828
|
+
decomposition = synth_permutation_basic(high_level_object.pattern)
|
829
|
+
return decomposition
|
830
|
+
|
831
|
+
|
832
|
+
class ACGSynthesisPermutation(HighLevelSynthesisPlugin):
|
833
|
+
"""The permutation synthesis plugin based on the Alon, Chung, Graham method.
|
834
|
+
|
835
|
+
This plugin name is :``permutation.acg`` which can be used as the key on
|
836
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
837
|
+
"""
|
838
|
+
|
839
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
840
|
+
"""Run synthesis for the given Permutation."""
|
841
|
+
if not isinstance(high_level_object, PermutationGate):
|
842
|
+
return None
|
843
|
+
|
844
|
+
decomposition = synth_permutation_acg(high_level_object.pattern)
|
845
|
+
return decomposition
|
846
|
+
|
847
|
+
|
848
|
+
class QFTSynthesisFull(HighLevelSynthesisPlugin):
|
849
|
+
"""Synthesis plugin for QFT gates using all-to-all connectivity.
|
850
|
+
|
851
|
+
This plugin name is :``qft.full`` which can be used as the key on
|
852
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
853
|
+
|
854
|
+
Note that the plugin mechanism is not applied if the gate is called ``qft`` but
|
855
|
+
is not an instance of ``QFTGate``. This allows users to create custom gates with
|
856
|
+
name ``qft``.
|
857
|
+
|
858
|
+
The plugin supports the following additional options:
|
859
|
+
|
860
|
+
* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
|
861
|
+
which is the default) or the "QFT-with-reversal" operation (if ``True``).
|
862
|
+
Some implementation of the ``QFTGate`` include a layer of swap gates at the end
|
863
|
+
of the synthesized circuit, which can in principle be dropped if the ``QFTGate``
|
864
|
+
itself is the last gate in the circuit.
|
865
|
+
* approximation_degree (int): The degree of approximation (0 for no approximation).
|
866
|
+
It is possible to implement the QFT approximately by ignoring
|
867
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
868
|
+
in more detail in [1] or [2].
|
869
|
+
* insert_barriers (bool): If True, barriers are inserted as visualization improvement.
|
870
|
+
* inverse (bool): If True, the inverse Fourier transform is constructed.
|
871
|
+
* name (str): The name of the circuit.
|
872
|
+
|
873
|
+
References:
|
874
|
+
1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä,
|
875
|
+
*Approximate Quantum Fourier Transform and Decoherence*,
|
876
|
+
Physical Review A (1996).
|
877
|
+
`arXiv:quant-ph/9601018 [quant-ph] <https://arxiv.org/abs/quant-ph/9601018>`_
|
878
|
+
2. Donny Cheung,
|
879
|
+
*Improved Bounds for the Approximate QFT* (2004),
|
880
|
+
`arXiv:quant-ph/0403071 [quant-ph] <https://https://arxiv.org/abs/quant-ph/0403071>`_
|
881
|
+
"""
|
882
|
+
|
883
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
884
|
+
"""Run synthesis for the given QFTGate."""
|
885
|
+
|
886
|
+
# Even though the gate is called "qft", it's not a QFTGate,
|
887
|
+
# and we should not synthesize it using the plugin.
|
888
|
+
if not isinstance(high_level_object, QFTGate):
|
889
|
+
return None
|
890
|
+
|
891
|
+
reverse_qubits = options.get("reverse_qubits", False)
|
892
|
+
approximation_degree = options.get("approximation_degree", 0)
|
893
|
+
insert_barriers = options.get("insert_barriers", False)
|
894
|
+
inverse = options.get("inverse", False)
|
895
|
+
name = options.get("name", None)
|
896
|
+
|
897
|
+
decomposition = synth_qft_full(
|
898
|
+
num_qubits=high_level_object.num_qubits,
|
899
|
+
do_swaps=not reverse_qubits,
|
900
|
+
approximation_degree=approximation_degree,
|
901
|
+
insert_barriers=insert_barriers,
|
902
|
+
inverse=inverse,
|
903
|
+
name=name,
|
904
|
+
)
|
905
|
+
return decomposition
|
906
|
+
|
907
|
+
|
908
|
+
class QFTSynthesisLine(HighLevelSynthesisPlugin):
|
909
|
+
"""Synthesis plugin for QFT gates using linear connectivity.
|
910
|
+
|
911
|
+
This plugin name is :``qft.line`` which can be used as the key on
|
912
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
913
|
+
|
914
|
+
Note that the plugin mechanism is not applied if the gate is called ``qft`` but
|
915
|
+
is not an instance of ``QFTGate``. This allows users to create custom gates with
|
916
|
+
name ``qft``.
|
917
|
+
|
918
|
+
The plugin supports the following additional options:
|
919
|
+
|
920
|
+
* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
|
921
|
+
which is the default) or the "QFT-with-reversal" operation (if ``True``).
|
922
|
+
Some implementation of the ``QFTGate`` include a layer of swap gates at the end
|
923
|
+
of the synthesized circuit, which can in principle be dropped if the ``QFTGate``
|
924
|
+
itself is the last gate in the circuit.
|
925
|
+
* approximation_degree (int): the degree of approximation (0 for no approximation).
|
926
|
+
It is possible to implement the QFT approximately by ignoring
|
927
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
928
|
+
in more detail in [1] or [2].
|
929
|
+
|
930
|
+
References:
|
931
|
+
1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä,
|
932
|
+
*Approximate Quantum Fourier Transform and Decoherence*,
|
933
|
+
Physical Review A (1996).
|
934
|
+
`arXiv:quant-ph/9601018 [quant-ph] <https://arxiv.org/abs/quant-ph/9601018>`_
|
935
|
+
2. Donny Cheung,
|
936
|
+
*Improved Bounds for the Approximate QFT* (2004),
|
937
|
+
`arXiv:quant-ph/0403071 [quant-ph] <https://https://arxiv.org/abs/quant-ph/0403071>`_
|
938
|
+
"""
|
939
|
+
|
940
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
941
|
+
"""Run synthesis for the given QFTGate."""
|
942
|
+
|
943
|
+
# Even though the gate is called "qft", it's not a QFTGate,
|
944
|
+
# and we should not synthesize it using the plugin.
|
945
|
+
if not isinstance(high_level_object, QFTGate):
|
946
|
+
return None
|
947
|
+
|
948
|
+
reverse_qubits = options.get("reverse_qubits", False)
|
949
|
+
approximation_degree = options.get("approximation_degree", 0)
|
950
|
+
|
951
|
+
decomposition = synth_qft_line(
|
952
|
+
num_qubits=high_level_object.num_qubits,
|
953
|
+
do_swaps=not reverse_qubits,
|
954
|
+
approximation_degree=approximation_degree,
|
955
|
+
)
|
956
|
+
return decomposition
|
957
|
+
|
958
|
+
|
959
|
+
class TokenSwapperSynthesisPermutation(HighLevelSynthesisPlugin):
|
960
|
+
"""The permutation synthesis plugin based on the token swapper algorithm.
|
961
|
+
|
962
|
+
This plugin name is :``permutation.token_swapper`` which can be used as the key on
|
963
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
964
|
+
|
965
|
+
In more detail, this plugin is used to synthesize objects of type `PermutationGate`.
|
966
|
+
When synthesis succeeds, the plugin outputs a quantum circuit consisting only of swap
|
967
|
+
gates. When synthesis does not succeed, the plugin outputs `None`.
|
968
|
+
|
969
|
+
If either `coupling_map` or `qubits` is None, then the synthesized circuit
|
970
|
+
is not required to adhere to connectivity constraints, as is the case
|
971
|
+
when the synthesis is done before layout/routing.
|
972
|
+
|
973
|
+
On the other hand, if both `coupling_map` and `qubits` are specified, the synthesized
|
974
|
+
circuit is supposed to adhere to connectivity constraints. At the moment, the
|
975
|
+
plugin only creates swap gates between qubits in `qubits`, i.e. it does not use
|
976
|
+
any other qubits in the coupling map (if such synthesis is not possible, the
|
977
|
+
plugin outputs `None`).
|
978
|
+
|
979
|
+
The plugin supports the following plugin-specific options:
|
980
|
+
|
981
|
+
* trials: The number of trials for the token swapper to perform the mapping. The
|
982
|
+
circuit with the smallest number of SWAPs is returned.
|
983
|
+
* seed: The argument to the token swapper specifying the seed for random trials.
|
984
|
+
* parallel_threshold: The argument to the token swapper specifying the number of nodes
|
985
|
+
in the graph beyond which the algorithm will use parallel processing.
|
986
|
+
|
987
|
+
For more details on the token swapper algorithm, see to the paper:
|
988
|
+
`arXiv:1902.09102 <https://arxiv.org/abs/1902.09102>`__.
|
989
|
+
"""
|
990
|
+
|
991
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
992
|
+
"""Run synthesis for the given Permutation."""
|
993
|
+
|
994
|
+
if not isinstance(high_level_object, PermutationGate):
|
995
|
+
return None
|
996
|
+
|
997
|
+
trials = options.get("trials", 5)
|
998
|
+
seed = options.get("seed", 0)
|
999
|
+
parallel_threshold = options.get("parallel_threshold", 50)
|
1000
|
+
|
1001
|
+
pattern = high_level_object.pattern
|
1002
|
+
pattern_as_dict = {j: i for i, j in enumerate(pattern)}
|
1003
|
+
|
1004
|
+
# When the plugin is called from the HighLevelSynthesis transpiler pass,
|
1005
|
+
# the coupling map already takes target into account.
|
1006
|
+
if coupling_map is None or qubits is None:
|
1007
|
+
# The abstract synthesis uses a fully connected coupling map, allowing
|
1008
|
+
# arbitrary connections between qubits.
|
1009
|
+
used_coupling_map = CouplingMap.from_full(len(pattern))
|
1010
|
+
else:
|
1011
|
+
# The concrete synthesis uses the coupling map restricted to the set of
|
1012
|
+
# qubits over which the permutation gate is defined. If we allow using other
|
1013
|
+
# qubits in the coupling map, replacing the node in the DAGCircuit that
|
1014
|
+
# defines this PermutationGate by the DAG corresponding to the constructed
|
1015
|
+
# decomposition becomes problematic. Note that we allow the reduced
|
1016
|
+
# coupling map to be disconnected.
|
1017
|
+
used_coupling_map = coupling_map.reduce(qubits, check_if_connected=False)
|
1018
|
+
|
1019
|
+
graph = used_coupling_map.graph.to_undirected()
|
1020
|
+
swapper = ApproximateTokenSwapper(graph, seed=seed)
|
1021
|
+
|
1022
|
+
try:
|
1023
|
+
swapper_result = swapper.map(
|
1024
|
+
pattern_as_dict, trials, parallel_threshold=parallel_threshold
|
1025
|
+
)
|
1026
|
+
except rx.InvalidMapping:
|
1027
|
+
swapper_result = None
|
1028
|
+
|
1029
|
+
if swapper_result is not None:
|
1030
|
+
decomposition = QuantumCircuit(len(graph.node_indices()))
|
1031
|
+
for swap in swapper_result:
|
1032
|
+
decomposition.swap(*swap)
|
1033
|
+
return decomposition
|
1034
|
+
|
1035
|
+
return None
|
1036
|
+
|
1037
|
+
|
1038
|
+
class MCXSynthesisNDirtyI15(HighLevelSynthesisPlugin):
|
1039
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper
|
1040
|
+
by Iten et al. (2016).
|
1041
|
+
|
1042
|
+
See [1] for details.
|
1043
|
+
|
1044
|
+
This plugin name is :``mcx.n_dirty_i15`` which can be used as the key on
|
1045
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1046
|
+
|
1047
|
+
For a multi-controlled X gate with :math:`k\ge 4` control qubits this synthesis
|
1048
|
+
method requires :math:`k - 2` additional dirty auxiliary qubits. The synthesized
|
1049
|
+
circuit consists of :math:`2 * k - 1` qubits and at most :math:`8 * k - 6` CX gates.
|
1050
|
+
For :math:`k\le 3` explicit efficient circuits are used instead.
|
1051
|
+
|
1052
|
+
The plugin supports the following plugin-specific options:
|
1053
|
+
|
1054
|
+
* num_clean_ancillas: The number of clean auxiliary qubits available.
|
1055
|
+
* num_dirty_ancillas: The number of dirty auxiliary qubits available.
|
1056
|
+
* relative_phase: When set to ``True``, the method applies the optimized multi-controlled
|
1057
|
+
X gate up to a relative phase, in a way that, by lemma 8 of [1], the relative
|
1058
|
+
phases of the ``action part`` cancel out with the phases of the ``reset part``.
|
1059
|
+
* action_only: when set to ``True``, the method applies only the ``action part``
|
1060
|
+
of lemma 8 of [1].
|
1061
|
+
|
1062
|
+
References:
|
1063
|
+
1. Iten et. al., *Quantum Circuits for Isometries*, Phys. Rev. A 93, 032318 (2016),
|
1064
|
+
`arXiv:1501.06911 <http://arxiv.org/abs/1501.06911>`_
|
1065
|
+
"""
|
1066
|
+
|
1067
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1068
|
+
"""Run synthesis for the given MCX gate."""
|
1069
|
+
|
1070
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1071
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1072
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1073
|
+
# to return None in this case, since HLS would proceed to examine
|
1074
|
+
# their definition as it should.
|
1075
|
+
return None
|
1076
|
+
|
1077
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1078
|
+
num_clean_ancillas = options.get("num_clean_ancillas", 0)
|
1079
|
+
num_dirty_ancillas = options.get("num_dirty_ancillas", 0)
|
1080
|
+
relative_phase = options.get("relative_phase", False)
|
1081
|
+
action_only = options.get("actions_only", False)
|
1082
|
+
|
1083
|
+
if num_ctrl_qubits >= 3 and num_dirty_ancillas + num_clean_ancillas < num_ctrl_qubits - 2:
|
1084
|
+
# This synthesis method is not applicable as there are not enough ancilla qubits
|
1085
|
+
return None
|
1086
|
+
|
1087
|
+
decomposition = synth_mcx_n_dirty_i15(num_ctrl_qubits, relative_phase, action_only)
|
1088
|
+
return decomposition
|
1089
|
+
|
1090
|
+
|
1091
|
+
class MCXSynthesisNCleanM15(HighLevelSynthesisPlugin):
|
1092
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by
|
1093
|
+
Maslov (2016).
|
1094
|
+
|
1095
|
+
See [1] for details.
|
1096
|
+
|
1097
|
+
This plugin name is :``mcx.n_clean_m15`` which can be used as the key on
|
1098
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1099
|
+
|
1100
|
+
For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis
|
1101
|
+
method requires :math:`k - 2` additional clean auxiliary qubits. The synthesized
|
1102
|
+
circuit consists of :math:`2 * k - 1` qubits and at most :math:`6 * k - 6` CX gates.
|
1103
|
+
|
1104
|
+
The plugin supports the following plugin-specific options:
|
1105
|
+
|
1106
|
+
* num_clean_ancillas: The number of clean auxiliary qubits available.
|
1107
|
+
|
1108
|
+
References:
|
1109
|
+
1. Maslov., Phys. Rev. A 93, 022311 (2016),
|
1110
|
+
`arXiv:1508.03273 <https://arxiv.org/pdf/1508.03273>`_
|
1111
|
+
"""
|
1112
|
+
|
1113
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1114
|
+
"""Run synthesis for the given MCX gate."""
|
1115
|
+
|
1116
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1117
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1118
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1119
|
+
# to return None in this case, since HLS would proceed to examine
|
1120
|
+
# their definition as it should.
|
1121
|
+
return None
|
1122
|
+
|
1123
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1124
|
+
num_clean_ancillas = options.get("num_clean_ancillas", 0)
|
1125
|
+
|
1126
|
+
if num_ctrl_qubits >= 3 and num_clean_ancillas < num_ctrl_qubits - 2:
|
1127
|
+
# This synthesis method is not applicable as there are not enough ancilla qubits
|
1128
|
+
return None
|
1129
|
+
|
1130
|
+
decomposition = synth_mcx_n_clean_m15(num_ctrl_qubits)
|
1131
|
+
return decomposition
|
1132
|
+
|
1133
|
+
|
1134
|
+
class MCXSynthesis1CleanB95(HighLevelSynthesisPlugin):
|
1135
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by
|
1136
|
+
Barenco et al. (1995).
|
1137
|
+
|
1138
|
+
See [1] for details.
|
1139
|
+
|
1140
|
+
This plugin name is :``mcx.1_clean_b95`` which can be used as the key on
|
1141
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1142
|
+
|
1143
|
+
For a multi-controlled X gate with :math:`k\ge 5` control qubits this synthesis
|
1144
|
+
method requires a single additional clean auxiliary qubit. The synthesized
|
1145
|
+
circuit consists of :math:`k + 2` qubits and at most :math:`16 * k - 24` CX gates.
|
1146
|
+
|
1147
|
+
The plugin supports the following plugin-specific options:
|
1148
|
+
|
1149
|
+
* num_clean_ancillas: The number of clean auxiliary qubits available.
|
1150
|
+
|
1151
|
+
References:
|
1152
|
+
1. Barenco et. al., *Elementary gates for quantum computation*, Phys.Rev. A52 3457 (1995),
|
1153
|
+
`arXiv:quant-ph/9503016 <https://arxiv.org/abs/quant-ph/9503016>`_
|
1154
|
+
"""
|
1155
|
+
|
1156
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1157
|
+
"""Run synthesis for the given MCX gate."""
|
1158
|
+
|
1159
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1160
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1161
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1162
|
+
# to return None in this case, since HLS would proceed to examine
|
1163
|
+
# their definition as it should.
|
1164
|
+
return None
|
1165
|
+
|
1166
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1167
|
+
|
1168
|
+
if num_ctrl_qubits <= 2:
|
1169
|
+
# The method requires at least 3 control qubits
|
1170
|
+
return None
|
1171
|
+
|
1172
|
+
num_clean_ancillas = options.get("num_clean_ancillas", 0)
|
1173
|
+
|
1174
|
+
if num_ctrl_qubits >= 5 and num_clean_ancillas == 0:
|
1175
|
+
# This synthesis method is not applicable as there are not enough ancilla qubits
|
1176
|
+
return None
|
1177
|
+
|
1178
|
+
decomposition = synth_mcx_1_clean_b95(num_ctrl_qubits)
|
1179
|
+
return decomposition
|
1180
|
+
|
1181
|
+
|
1182
|
+
class MCXSynthesis2CleanKG24(HighLevelSynthesisPlugin):
|
1183
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by Khattar and
|
1184
|
+
Gidney (2024).
|
1185
|
+
|
1186
|
+
See [1] for details.
|
1187
|
+
|
1188
|
+
The plugin name is :``mcx.2_clean_kg24`` which can be used as the key on an :class:`~.HLSConfig`
|
1189
|
+
object to use this method with :class:`~.HighLevelSynthesis`.
|
1190
|
+
|
1191
|
+
For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis method requires
|
1192
|
+
:math:`2` additional clean ancillary qubits. The synthesized circuit consists of :math:`k + 2`
|
1193
|
+
qubits and at most :math:`12 * k - 18` CX gates.
|
1194
|
+
|
1195
|
+
The plugin supports the following plugin-specific options:
|
1196
|
+
|
1197
|
+
* num_clean_ancillas: The number of clean ancillary qubits available.
|
1198
|
+
|
1199
|
+
References:
|
1200
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
1201
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
1202
|
+
"""
|
1203
|
+
|
1204
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1205
|
+
"""Run synthesis for the given MCX gate."""
|
1206
|
+
|
1207
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1208
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1209
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1210
|
+
# to return None in this case, since HLS would proceed to examine
|
1211
|
+
# their definition as it should.
|
1212
|
+
return None
|
1213
|
+
|
1214
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1215
|
+
num_clean_ancillas = options.get("num_clean_ancillas", 0)
|
1216
|
+
|
1217
|
+
if num_clean_ancillas < 2:
|
1218
|
+
return None
|
1219
|
+
|
1220
|
+
decomposition = synth_mcx_2_clean_kg24(num_ctrl_qubits)
|
1221
|
+
return decomposition
|
1222
|
+
|
1223
|
+
|
1224
|
+
class MCXSynthesis2DirtyKG24(HighLevelSynthesisPlugin):
|
1225
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by Khattar and
|
1226
|
+
Gidney (2024).
|
1227
|
+
|
1228
|
+
See [1] for details.
|
1229
|
+
|
1230
|
+
The plugin name is :``mcx.2_dirty_kg24`` which can be used as the key on an :class:`~.HLSConfig`
|
1231
|
+
object to use this method with :class:`~.HighLevelSynthesis`.
|
1232
|
+
|
1233
|
+
For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis method requires
|
1234
|
+
:math:`2` additional dirty ancillary qubits. The synthesized circuit consists of :math:`k + 2`
|
1235
|
+
qubits and at most :math:`24 * k - 48` CX gates.
|
1236
|
+
|
1237
|
+
The plugin supports the following plugin-specific options:
|
1238
|
+
|
1239
|
+
* num_clean_ancillas: The number of clean ancillary qubits available.
|
1240
|
+
|
1241
|
+
References:
|
1242
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
1243
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
1244
|
+
"""
|
1245
|
+
|
1246
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1247
|
+
"""Run synthesis for the given MCX gate."""
|
1248
|
+
|
1249
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1250
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1251
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1252
|
+
# to return None in this case, since HLS would proceed to examine
|
1253
|
+
# their definition as it should.
|
1254
|
+
return None
|
1255
|
+
|
1256
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1257
|
+
num_dirty_ancillas = options.get("num_dirty_ancillas", 0)
|
1258
|
+
|
1259
|
+
if num_dirty_ancillas < 2:
|
1260
|
+
return None
|
1261
|
+
|
1262
|
+
decomposition = synth_mcx_2_dirty_kg24(num_ctrl_qubits)
|
1263
|
+
return decomposition
|
1264
|
+
|
1265
|
+
|
1266
|
+
class MCXSynthesis1CleanKG24(HighLevelSynthesisPlugin):
|
1267
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by Khattar and
|
1268
|
+
Gidney (2024).
|
1269
|
+
|
1270
|
+
See [1] for details.
|
1271
|
+
|
1272
|
+
The plugin name is :``mcx.1_clean_kg24`` which can be used as the key on an :class:`~.HLSConfig`
|
1273
|
+
object to use this method with :class:`~.HighLevelSynthesis`.
|
1274
|
+
|
1275
|
+
For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis method requires
|
1276
|
+
:math:`1` additional clean ancillary qubit. The synthesized circuit consists of :math:`k + 2`
|
1277
|
+
qubits and at most :math:`12 * k - 18` CX gates.
|
1278
|
+
|
1279
|
+
The plugin supports the following plugin-specific options:
|
1280
|
+
|
1281
|
+
* num_clean_ancillas: The number of clean ancillary qubits available.
|
1282
|
+
|
1283
|
+
References:
|
1284
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
1285
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
1286
|
+
"""
|
1287
|
+
|
1288
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1289
|
+
"""Run synthesis for the given MCX gate."""
|
1290
|
+
|
1291
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1292
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1293
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1294
|
+
# to return None in this case, since HLS would proceed to examine
|
1295
|
+
# their definition as it should.
|
1296
|
+
return None
|
1297
|
+
|
1298
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1299
|
+
num_clean_ancillas = options.get("num_clean_ancillas", 0)
|
1300
|
+
|
1301
|
+
if num_clean_ancillas < 1:
|
1302
|
+
return None
|
1303
|
+
|
1304
|
+
decomposition = synth_mcx_1_clean_kg24(num_ctrl_qubits)
|
1305
|
+
return decomposition
|
1306
|
+
|
1307
|
+
|
1308
|
+
class MCXSynthesis1DirtyKG24(HighLevelSynthesisPlugin):
|
1309
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the paper by Khattar and
|
1310
|
+
Gidney (2024).
|
1311
|
+
|
1312
|
+
See [1] for details.
|
1313
|
+
|
1314
|
+
The plugin name is :``mcx.1_dirty_kg24`` which can be used as the key on an :class:`~.HLSConfig`
|
1315
|
+
object to use this method with :class:`~.HighLevelSynthesis`.
|
1316
|
+
|
1317
|
+
For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis method requires
|
1318
|
+
:math:`1` additional dirty ancillary qubit. The synthesized circuit consists of :math:`k + 2`
|
1319
|
+
qubits and at most :math:`24 * k - 48` CX gates.
|
1320
|
+
|
1321
|
+
The plugin supports the following plugin-specific options:
|
1322
|
+
|
1323
|
+
* num_clean_ancillas: The number of clean ancillary qubits available.
|
1324
|
+
|
1325
|
+
References:
|
1326
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
1327
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
1328
|
+
"""
|
1329
|
+
|
1330
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1331
|
+
"""Run synthesis for the given MCX gate."""
|
1332
|
+
|
1333
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1334
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1335
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1336
|
+
# to return None in this case, since HLS would proceed to examine
|
1337
|
+
# their definition as it should.
|
1338
|
+
return None
|
1339
|
+
|
1340
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1341
|
+
num_dirty_ancillas = options.get("num_dirty_ancillas", 0)
|
1342
|
+
|
1343
|
+
if num_dirty_ancillas < 1:
|
1344
|
+
return None
|
1345
|
+
|
1346
|
+
decomposition = synth_mcx_1_dirty_kg24(num_ctrl_qubits)
|
1347
|
+
return decomposition
|
1348
|
+
|
1349
|
+
|
1350
|
+
class MCXSynthesisGrayCode(HighLevelSynthesisPlugin):
|
1351
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the Gray code.
|
1352
|
+
|
1353
|
+
This plugin name is :``mcx.gray_code`` which can be used as the key on
|
1354
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1355
|
+
|
1356
|
+
For a multi-controlled X gate with :math:`k` control qubits this synthesis
|
1357
|
+
method requires no additional clean auxiliary qubits. The synthesized
|
1358
|
+
circuit consists of :math:`k + 1` qubits.
|
1359
|
+
|
1360
|
+
It is not recommended to use this method for large values of :math:`k + 1`
|
1361
|
+
as it produces exponentially many gates.
|
1362
|
+
"""
|
1363
|
+
|
1364
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1365
|
+
"""Run synthesis for the given MCX gate."""
|
1366
|
+
|
1367
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1368
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1369
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1370
|
+
# to return None in this case, since HLS would proceed to examine
|
1371
|
+
# their definition as it should.
|
1372
|
+
return None
|
1373
|
+
|
1374
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1375
|
+
decomposition = synth_mcx_gray_code(num_ctrl_qubits)
|
1376
|
+
return decomposition
|
1377
|
+
|
1378
|
+
|
1379
|
+
class MCXSynthesisNoAuxV24(HighLevelSynthesisPlugin):
|
1380
|
+
r"""Synthesis plugin for a multi-controlled X gate based on the
|
1381
|
+
implementation for MCPhaseGate, which is in turn based on the
|
1382
|
+
paper by Vale et al. (2024).
|
1383
|
+
|
1384
|
+
See [1] for details.
|
1385
|
+
|
1386
|
+
This plugin name is :``mcx.noaux_v24`` which can be used as the key on
|
1387
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1388
|
+
|
1389
|
+
For a multi-controlled X gate with :math:`k` control qubits this synthesis
|
1390
|
+
method requires no additional clean auxiliary qubits. The synthesized
|
1391
|
+
circuit consists of :math:`k + 1` qubits.
|
1392
|
+
|
1393
|
+
References:
|
1394
|
+
1. Vale et. al., *Circuit Decomposition of Multicontrolled Special Unitary
|
1395
|
+
Single-Qubit Gates*, IEEE TCAD 43(3) (2024),
|
1396
|
+
`arXiv:2302.06377 <https://arxiv.org/abs/2302.06377>`_
|
1397
|
+
"""
|
1398
|
+
|
1399
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1400
|
+
"""Run synthesis for the given MCX gate."""
|
1401
|
+
|
1402
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1403
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1404
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1405
|
+
# to return None in this case, since HLS would proceed to examine
|
1406
|
+
# their definition as it should.
|
1407
|
+
return None
|
1408
|
+
|
1409
|
+
num_ctrl_qubits = high_level_object.num_ctrl_qubits
|
1410
|
+
decomposition = synth_mcx_noaux_v24(num_ctrl_qubits)
|
1411
|
+
return decomposition
|
1412
|
+
|
1413
|
+
|
1414
|
+
class MCXSynthesisDefault(HighLevelSynthesisPlugin):
|
1415
|
+
r"""The default synthesis plugin for a multi-controlled X gate.
|
1416
|
+
|
1417
|
+
This plugin name is :``mcx.default`` which can be used as the key on
|
1418
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1419
|
+
"""
|
1420
|
+
|
1421
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1422
|
+
"""Run synthesis for the given MCX gate."""
|
1423
|
+
|
1424
|
+
if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)):
|
1425
|
+
# Unfortunately we occasionally have custom instructions called "mcx"
|
1426
|
+
# which get wrongly caught by the plugin interface. A simple solution is
|
1427
|
+
# to return None in this case, since HLS would proceed to examine
|
1428
|
+
# their definition as it should.
|
1429
|
+
return None
|
1430
|
+
|
1431
|
+
# Iteratively run other synthesis methods available
|
1432
|
+
|
1433
|
+
for synthesis_method in [
|
1434
|
+
MCXSynthesis2CleanKG24,
|
1435
|
+
MCXSynthesis1CleanKG24,
|
1436
|
+
MCXSynthesisNCleanM15,
|
1437
|
+
MCXSynthesisNDirtyI15,
|
1438
|
+
MCXSynthesis2DirtyKG24,
|
1439
|
+
MCXSynthesis1DirtyKG24,
|
1440
|
+
MCXSynthesis1CleanB95,
|
1441
|
+
]:
|
1442
|
+
if (
|
1443
|
+
decomposition := synthesis_method().run(
|
1444
|
+
high_level_object, coupling_map, target, qubits, **options
|
1445
|
+
)
|
1446
|
+
) is not None:
|
1447
|
+
return decomposition
|
1448
|
+
|
1449
|
+
# If no synthesis method was successful, fall back to the default
|
1450
|
+
return MCXSynthesisNoAuxV24().run(
|
1451
|
+
high_level_object, coupling_map, target, qubits, **options
|
1452
|
+
)
|
1453
|
+
|
1454
|
+
|
1455
|
+
class MCMTSynthesisDefault(HighLevelSynthesisPlugin):
|
1456
|
+
"""A default decomposition for MCMT gates."""
|
1457
|
+
|
1458
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1459
|
+
# first try to use the V-chain synthesis if enough auxiliary qubits are available
|
1460
|
+
if not isinstance(high_level_object, MCMTGate):
|
1461
|
+
return None
|
1462
|
+
|
1463
|
+
if (
|
1464
|
+
decomposition := MCMTSynthesisVChain().run(
|
1465
|
+
high_level_object, coupling_map, target, qubits, **options
|
1466
|
+
)
|
1467
|
+
) is not None:
|
1468
|
+
return decomposition
|
1469
|
+
|
1470
|
+
return MCMTSynthesisNoAux().run(high_level_object, coupling_map, target, qubits, **options)
|
1471
|
+
|
1472
|
+
|
1473
|
+
class MCMTSynthesisNoAux(HighLevelSynthesisPlugin):
|
1474
|
+
"""A V-chain based synthesis for ``MCMTGate``."""
|
1475
|
+
|
1476
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1477
|
+
if not isinstance(high_level_object, MCMTGate):
|
1478
|
+
return None
|
1479
|
+
|
1480
|
+
base_gate = high_level_object.base_gate
|
1481
|
+
ctrl_state = options.get("ctrl_state", None)
|
1482
|
+
|
1483
|
+
if high_level_object.num_target_qubits == 1:
|
1484
|
+
# no broadcasting needed (makes for better circuit diagrams)
|
1485
|
+
circuit = QuantumCircuit(high_level_object.num_qubits)
|
1486
|
+
circuit.append(
|
1487
|
+
base_gate.control(high_level_object.num_ctrl_qubits, ctrl_state=ctrl_state),
|
1488
|
+
circuit.qubits,
|
1489
|
+
)
|
1490
|
+
|
1491
|
+
else:
|
1492
|
+
base = QuantumCircuit(high_level_object.num_target_qubits, name=high_level_object.label)
|
1493
|
+
for i in range(high_level_object.num_target_qubits):
|
1494
|
+
base.append(base_gate, [i], [])
|
1495
|
+
|
1496
|
+
circuit = base.control(high_level_object.num_ctrl_qubits, ctrl_state=ctrl_state)
|
1497
|
+
|
1498
|
+
return circuit.decompose()
|
1499
|
+
|
1500
|
+
|
1501
|
+
class MCMTSynthesisVChain(HighLevelSynthesisPlugin):
|
1502
|
+
"""A V-chain based synthesis for ``MCMTGate``."""
|
1503
|
+
|
1504
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1505
|
+
if not isinstance(high_level_object, MCMTGate):
|
1506
|
+
return None
|
1507
|
+
|
1508
|
+
if options.get("num_clean_ancillas", 0) < high_level_object.num_ctrl_qubits - 1:
|
1509
|
+
return None # insufficient number of auxiliary qubits
|
1510
|
+
|
1511
|
+
ctrl_state = options.get("ctrl_state", None)
|
1512
|
+
|
1513
|
+
return synth_mcmt_vchain(
|
1514
|
+
high_level_object.base_gate,
|
1515
|
+
high_level_object.num_ctrl_qubits,
|
1516
|
+
high_level_object.num_target_qubits,
|
1517
|
+
ctrl_state,
|
1518
|
+
)
|
1519
|
+
|
1520
|
+
|
1521
|
+
class IntComparatorSynthesisDefault(HighLevelSynthesisPlugin):
|
1522
|
+
"""The default synthesis for ``IntegerComparatorGate``.
|
1523
|
+
|
1524
|
+
Currently this is only supporting an ancilla-based decomposition.
|
1525
|
+
"""
|
1526
|
+
|
1527
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1528
|
+
num_state_qubits = high_level_object.num_qubits - 1
|
1529
|
+
num_aux = num_state_qubits - 1
|
1530
|
+
if options.get("num_clean_ancillas", 0) < num_aux:
|
1531
|
+
return synth_integer_comparator_greedy(
|
1532
|
+
num_state_qubits, high_level_object.value, high_level_object.geq
|
1533
|
+
)
|
1534
|
+
|
1535
|
+
return synth_integer_comparator_2s(
|
1536
|
+
num_state_qubits, high_level_object.value, high_level_object.geq
|
1537
|
+
)
|
1538
|
+
|
1539
|
+
|
1540
|
+
class IntComparatorSynthesisNoAux(HighLevelSynthesisPlugin):
|
1541
|
+
"""A potentially exponentially expensive comparison w/o auxiliary qubits."""
|
1542
|
+
|
1543
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1544
|
+
return synth_integer_comparator_greedy(
|
1545
|
+
high_level_object.num_state_qubits, high_level_object.value, high_level_object.geq
|
1546
|
+
)
|
1547
|
+
|
1548
|
+
|
1549
|
+
class IntComparatorSynthesis2s(HighLevelSynthesisPlugin):
|
1550
|
+
"""An integer comparison based on 2s complement."""
|
1551
|
+
|
1552
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1553
|
+
num_aux = high_level_object.num_state_qubits - 1
|
1554
|
+
if options.get("num_clean_ancillas", 0) < num_aux:
|
1555
|
+
return None
|
1556
|
+
|
1557
|
+
return synth_integer_comparator_2s(
|
1558
|
+
high_level_object.num_state_qubits, high_level_object.value, high_level_object.geq
|
1559
|
+
)
|
1560
|
+
|
1561
|
+
|
1562
|
+
class ModularAdderSynthesisDefault(HighLevelSynthesisPlugin):
|
1563
|
+
"""The default modular adder (no carry in, no carry out qubit) synthesis.
|
1564
|
+
|
1565
|
+
This plugin name is:``ModularAdder.default`` which can be used as the key on
|
1566
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1567
|
+
|
1568
|
+
If at least one clean auxiliary qubit is available, the :class:`ModularAdderSynthesisC04`
|
1569
|
+
is used, otherwise :class:`ModularAdderSynthesisD00`.
|
1570
|
+
|
1571
|
+
The plugin supports the following plugin-specific options:
|
1572
|
+
|
1573
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1574
|
+
|
1575
|
+
"""
|
1576
|
+
|
1577
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1578
|
+
if not isinstance(high_level_object, ModularAdderGate):
|
1579
|
+
return None
|
1580
|
+
|
1581
|
+
# For up to 5 qubits, the QFT-based adder is best
|
1582
|
+
if high_level_object.num_state_qubits <= 5:
|
1583
|
+
decomposition = ModularAdderSynthesisD00().run(
|
1584
|
+
high_level_object, coupling_map, target, qubits, **options
|
1585
|
+
)
|
1586
|
+
if decomposition is not None:
|
1587
|
+
return decomposition
|
1588
|
+
|
1589
|
+
# Otherwise, the following decomposition is best (if there are enough ancillas)
|
1590
|
+
if (
|
1591
|
+
decomposition := ModularAdderSynthesisC04().run(
|
1592
|
+
high_level_object, coupling_map, target, qubits, **options
|
1593
|
+
)
|
1594
|
+
) is not None:
|
1595
|
+
return decomposition
|
1596
|
+
|
1597
|
+
# Otherwise, use the QFT-adder again
|
1598
|
+
return ModularAdderSynthesisD00().run(
|
1599
|
+
high_level_object, coupling_map, target, qubits, **options
|
1600
|
+
)
|
1601
|
+
|
1602
|
+
|
1603
|
+
class ModularAdderSynthesisC04(HighLevelSynthesisPlugin):
|
1604
|
+
r"""A ripple-carry adder, modulo :math:`2^n`.
|
1605
|
+
|
1606
|
+
This plugin name is:``ModularAdder.ripple_c04`` which can be used as the key on
|
1607
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1608
|
+
|
1609
|
+
This plugin requires at least one clean auxiliary qubit.
|
1610
|
+
|
1611
|
+
The plugin supports the following plugin-specific options:
|
1612
|
+
|
1613
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1614
|
+
|
1615
|
+
"""
|
1616
|
+
|
1617
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1618
|
+
if not isinstance(high_level_object, ModularAdderGate):
|
1619
|
+
return None
|
1620
|
+
|
1621
|
+
# unless we implement the full adder, this implementation needs an ancilla qubit
|
1622
|
+
if options.get("num_clean_ancillas", 0) < 1:
|
1623
|
+
return None
|
1624
|
+
|
1625
|
+
return adder_ripple_c04(high_level_object.num_state_qubits, kind="fixed")
|
1626
|
+
|
1627
|
+
|
1628
|
+
class ModularAdderSynthesisV95(HighLevelSynthesisPlugin):
|
1629
|
+
r"""A ripple-carry adder, modulo :math:`2^n`.
|
1630
|
+
|
1631
|
+
This plugin name is:``ModularAdder.ripple_v95`` which can be used as the key on
|
1632
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1633
|
+
|
1634
|
+
For an adder on 2 registers with :math:`n` qubits each, this plugin requires at
|
1635
|
+
least :math:`n-1` clean auxiliary qubit.
|
1636
|
+
|
1637
|
+
The plugin supports the following plugin-specific options:
|
1638
|
+
|
1639
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1640
|
+
|
1641
|
+
"""
|
1642
|
+
|
1643
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1644
|
+
if not isinstance(high_level_object, ModularAdderGate):
|
1645
|
+
return None
|
1646
|
+
|
1647
|
+
num_state_qubits = high_level_object.num_state_qubits
|
1648
|
+
|
1649
|
+
# The synthesis method needs n-1 clean ancilla qubits
|
1650
|
+
if num_state_qubits - 1 > options.get("num_clean_ancillas", 0):
|
1651
|
+
return None
|
1652
|
+
|
1653
|
+
return adder_ripple_v95(num_state_qubits, kind="fixed")
|
1654
|
+
|
1655
|
+
|
1656
|
+
class ModularAdderSynthesisD00(HighLevelSynthesisPlugin):
|
1657
|
+
r"""A QFT-based adder, modulo :math:`2^n`.
|
1658
|
+
|
1659
|
+
This plugin name is:``ModularAdder.qft_d00`` which can be used as the key on
|
1660
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1661
|
+
"""
|
1662
|
+
|
1663
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1664
|
+
if not isinstance(high_level_object, ModularAdderGate):
|
1665
|
+
return None
|
1666
|
+
|
1667
|
+
return adder_qft_d00(high_level_object.num_state_qubits, kind="fixed", annotated=True)
|
1668
|
+
|
1669
|
+
|
1670
|
+
class HalfAdderSynthesisDefault(HighLevelSynthesisPlugin):
|
1671
|
+
r"""The default half-adder (no carry in, but a carry out qubit) synthesis.
|
1672
|
+
|
1673
|
+
If we have an auxiliary qubit available, the Cuccaro ripple-carry adder uses
|
1674
|
+
:math:`O(n)` CX gates and 1 auxiliary qubit, whereas the Vedral ripple-carry uses more CX
|
1675
|
+
and :math:`n-1` auxiliary qubits. The QFT-based adder uses no auxiliary qubits, but
|
1676
|
+
:math:`O(n^2)`, hence it is only used if no auxiliary qubits are available.
|
1677
|
+
|
1678
|
+
This plugin name is:``HalfAdder.default`` which can be used as the key on
|
1679
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1680
|
+
|
1681
|
+
If at least one clean auxiliary qubit is available, the :class:`HalfAdderSynthesisC04`
|
1682
|
+
is used, otherwise :class:`HalfAdderSynthesisD00`.
|
1683
|
+
|
1684
|
+
The plugin supports the following plugin-specific options:
|
1685
|
+
|
1686
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1687
|
+
|
1688
|
+
"""
|
1689
|
+
|
1690
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1691
|
+
if not isinstance(high_level_object, HalfAdderGate):
|
1692
|
+
return None
|
1693
|
+
|
1694
|
+
# For up to 3 qubits, ripple_r25 is better
|
1695
|
+
if (
|
1696
|
+
high_level_object.num_state_qubits <= 3
|
1697
|
+
and (
|
1698
|
+
decomposition := HalfAdderSynthesisR25().run(
|
1699
|
+
high_level_object, coupling_map, target, qubits, **options
|
1700
|
+
)
|
1701
|
+
)
|
1702
|
+
is not None
|
1703
|
+
):
|
1704
|
+
return decomposition
|
1705
|
+
|
1706
|
+
# The next best option is to use ripple_c04 (if there are enough ancilla qubits)
|
1707
|
+
if (
|
1708
|
+
decomposition := HalfAdderSynthesisC04().run(
|
1709
|
+
high_level_object, coupling_map, target, qubits, **options
|
1710
|
+
)
|
1711
|
+
) is not None:
|
1712
|
+
return decomposition
|
1713
|
+
|
1714
|
+
# The ripple_rv_25 adder does not require ancilla qubits and should always succeed
|
1715
|
+
return HalfAdderSynthesisR25().run(
|
1716
|
+
high_level_object, coupling_map, target, qubits, **options
|
1717
|
+
)
|
1718
|
+
|
1719
|
+
|
1720
|
+
class HalfAdderSynthesisC04(HighLevelSynthesisPlugin):
|
1721
|
+
"""A ripple-carry adder with a carry-out bit.
|
1722
|
+
|
1723
|
+
This plugin name is:``HalfAdder.ripple_c04`` which can be used as the key on
|
1724
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1725
|
+
|
1726
|
+
This plugin requires at least one clean auxiliary qubit.
|
1727
|
+
|
1728
|
+
The plugin supports the following plugin-specific options:
|
1729
|
+
|
1730
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1731
|
+
|
1732
|
+
"""
|
1733
|
+
|
1734
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1735
|
+
if not isinstance(high_level_object, HalfAdderGate):
|
1736
|
+
return None
|
1737
|
+
|
1738
|
+
# unless we implement the full adder, this implementation needs an ancilla qubit
|
1739
|
+
if options.get("num_clean_ancillas", 0) < 1:
|
1740
|
+
return None
|
1741
|
+
|
1742
|
+
return adder_ripple_c04(high_level_object.num_state_qubits, kind="half")
|
1743
|
+
|
1744
|
+
|
1745
|
+
class HalfAdderSynthesisV95(HighLevelSynthesisPlugin):
|
1746
|
+
"""A ripple-carry adder with a carry-out bit.
|
1747
|
+
|
1748
|
+
This plugin name is:``HalfAdder.ripple_v95`` which can be used as the key on
|
1749
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1750
|
+
|
1751
|
+
For an adder on 2 registers with :math:`n` qubits each, this plugin requires at
|
1752
|
+
least :math:`n-1` clean auxiliary qubit.
|
1753
|
+
|
1754
|
+
The plugin supports the following plugin-specific options:
|
1755
|
+
|
1756
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1757
|
+
"""
|
1758
|
+
|
1759
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1760
|
+
if not isinstance(high_level_object, HalfAdderGate):
|
1761
|
+
return None
|
1762
|
+
|
1763
|
+
num_state_qubits = high_level_object.num_state_qubits
|
1764
|
+
|
1765
|
+
# The synthesis method needs n-1 clean ancilla qubits
|
1766
|
+
if num_state_qubits - 1 > options.get("num_clean_ancillas", 0):
|
1767
|
+
return None
|
1768
|
+
|
1769
|
+
return adder_ripple_v95(num_state_qubits, kind="half")
|
1770
|
+
|
1771
|
+
|
1772
|
+
class HalfAdderSynthesisR25(HighLevelSynthesisPlugin):
|
1773
|
+
"""A ripple-carry adder with a carry-out bit with no ancillary qubits.
|
1774
|
+
|
1775
|
+
This plugin name is:``HalfAdder.ripple_r25`` which can be used as the key on an
|
1776
|
+
:class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1777
|
+
|
1778
|
+
"""
|
1779
|
+
|
1780
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1781
|
+
if not isinstance(high_level_object, HalfAdderGate):
|
1782
|
+
return None
|
1783
|
+
|
1784
|
+
num_state_qubits = high_level_object.num_state_qubits
|
1785
|
+
return adder_ripple_r25(num_state_qubits)
|
1786
|
+
|
1787
|
+
|
1788
|
+
class HalfAdderSynthesisD00(HighLevelSynthesisPlugin):
|
1789
|
+
"""A QFT-based adder with a carry-in and a carry-out bit.
|
1790
|
+
|
1791
|
+
This plugin name is:``HalfAdder.qft_d00`` which can be used as the key on
|
1792
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1793
|
+
"""
|
1794
|
+
|
1795
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1796
|
+
if not isinstance(high_level_object, HalfAdderGate):
|
1797
|
+
return None
|
1798
|
+
|
1799
|
+
return adder_qft_d00(high_level_object.num_state_qubits, kind="half", annotated=True)
|
1800
|
+
|
1801
|
+
|
1802
|
+
class FullAdderSynthesisDefault(HighLevelSynthesisPlugin):
|
1803
|
+
"""A ripple-carry adder with a carry-in and a carry-out bit.
|
1804
|
+
|
1805
|
+
This plugin name is:``FullAdder.default`` which can be used as the key on
|
1806
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1807
|
+
"""
|
1808
|
+
|
1809
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1810
|
+
if not isinstance(high_level_object, FullAdderGate):
|
1811
|
+
return None
|
1812
|
+
|
1813
|
+
# FullAdderSynthesisC04 requires no ancilla qubits and returns better results
|
1814
|
+
# than FullAdderSynthesisV95 in all cases except for n=1.
|
1815
|
+
if high_level_object.num_state_qubits == 1:
|
1816
|
+
decomposition = FullAdderSynthesisV95().run(
|
1817
|
+
high_level_object, coupling_map, target, qubits, **options
|
1818
|
+
)
|
1819
|
+
if decomposition is not None:
|
1820
|
+
return decomposition
|
1821
|
+
|
1822
|
+
return FullAdderSynthesisC04().run(
|
1823
|
+
high_level_object, coupling_map, target, qubits, **options
|
1824
|
+
)
|
1825
|
+
|
1826
|
+
|
1827
|
+
class FullAdderSynthesisC04(HighLevelSynthesisPlugin):
|
1828
|
+
"""A ripple-carry adder with a carry-in and a carry-out bit.
|
1829
|
+
|
1830
|
+
This plugin name is:``FullAdder.ripple_c04`` which can be used as the key on
|
1831
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1832
|
+
|
1833
|
+
This plugin requires no auxiliary qubits.
|
1834
|
+
"""
|
1835
|
+
|
1836
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1837
|
+
if not isinstance(high_level_object, FullAdderGate):
|
1838
|
+
return None
|
1839
|
+
|
1840
|
+
return adder_ripple_c04(high_level_object.num_state_qubits, kind="full")
|
1841
|
+
|
1842
|
+
|
1843
|
+
class FullAdderSynthesisV95(HighLevelSynthesisPlugin):
|
1844
|
+
"""A ripple-carry adder with a carry-in and a carry-out bit.
|
1845
|
+
|
1846
|
+
This plugin name is:``FullAdder.ripple_v95`` which can be used as the key on
|
1847
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1848
|
+
|
1849
|
+
For an adder on 2 registers with :math:`n` qubits each, this plugin requires at
|
1850
|
+
least :math:`n-1` clean auxiliary qubits.
|
1851
|
+
|
1852
|
+
The plugin supports the following plugin-specific options:
|
1853
|
+
|
1854
|
+
* ``num_clean_ancillas``: The number of clean auxiliary qubits available.
|
1855
|
+
"""
|
1856
|
+
|
1857
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1858
|
+
if not isinstance(high_level_object, FullAdderGate):
|
1859
|
+
return None
|
1860
|
+
|
1861
|
+
num_state_qubits = high_level_object.num_state_qubits
|
1862
|
+
|
1863
|
+
# The synthesis method needs n-1 clean ancilla qubits
|
1864
|
+
if num_state_qubits - 1 > options.get("num_clean_ancillas", 0):
|
1865
|
+
return None
|
1866
|
+
|
1867
|
+
return adder_ripple_v95(num_state_qubits, kind="full")
|
1868
|
+
|
1869
|
+
|
1870
|
+
class MultiplierSynthesisH18(HighLevelSynthesisPlugin):
|
1871
|
+
"""A cumulative multiplier based on controlled adders.
|
1872
|
+
|
1873
|
+
This plugin name is:``Multiplier.cumulative_h18`` which can be used as the key on
|
1874
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1875
|
+
"""
|
1876
|
+
|
1877
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1878
|
+
if not isinstance(high_level_object, MultiplierGate):
|
1879
|
+
return None
|
1880
|
+
|
1881
|
+
return multiplier_cumulative_h18(
|
1882
|
+
high_level_object.num_state_qubits, high_level_object.num_result_qubits
|
1883
|
+
)
|
1884
|
+
|
1885
|
+
|
1886
|
+
class MultiplierSynthesisR17(HighLevelSynthesisPlugin):
|
1887
|
+
"""A QFT-based multiplier.
|
1888
|
+
|
1889
|
+
This plugin name is:``Multiplier.qft_r17`` which can be used as the key on
|
1890
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1891
|
+
"""
|
1892
|
+
|
1893
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1894
|
+
if not isinstance(high_level_object, MultiplierGate):
|
1895
|
+
return None
|
1896
|
+
|
1897
|
+
return multiplier_qft_r17(
|
1898
|
+
high_level_object.num_state_qubits, high_level_object.num_result_qubits
|
1899
|
+
)
|
1900
|
+
|
1901
|
+
|
1902
|
+
class PauliEvolutionSynthesisDefault(HighLevelSynthesisPlugin):
|
1903
|
+
"""Synthesize a :class:`.PauliEvolutionGate` using the default synthesis algorithm.
|
1904
|
+
|
1905
|
+
This plugin name is:``PauliEvolution.default`` which can be used as the key on
|
1906
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1907
|
+
|
1908
|
+
The following plugin option can be set:
|
1909
|
+
|
1910
|
+
* preserve_order: If ``False``, allow re-ordering the Pauli terms in the Hamiltonian to
|
1911
|
+
reduce the circuit depth of the decomposition.
|
1912
|
+
|
1913
|
+
"""
|
1914
|
+
|
1915
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1916
|
+
if not isinstance(high_level_object, PauliEvolutionGate):
|
1917
|
+
# Don't do anything if a gate is called "evolution" but is not an
|
1918
|
+
# actual PauliEvolutionGate
|
1919
|
+
return None
|
1920
|
+
algo = high_level_object.synthesis
|
1921
|
+
|
1922
|
+
original_preserve_order = algo.preserve_order
|
1923
|
+
if "preserve_order" in options and isinstance(algo, ProductFormula):
|
1924
|
+
algo.preserve_order = options["preserve_order"]
|
1925
|
+
|
1926
|
+
synth_object = algo.synthesize(high_level_object)
|
1927
|
+
algo.preserve_order = original_preserve_order
|
1928
|
+
return synth_object
|
1929
|
+
|
1930
|
+
|
1931
|
+
class PauliEvolutionSynthesisRustiq(HighLevelSynthesisPlugin):
|
1932
|
+
"""Synthesize a :class:`.PauliEvolutionGate` using Rustiq.
|
1933
|
+
|
1934
|
+
This plugin name is :``PauliEvolution.rustiq`` which can be used as the key on
|
1935
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1936
|
+
|
1937
|
+
The Rustiq synthesis algorithm is described in [1], and is implemented in
|
1938
|
+
Rust-based quantum circuit synthesis library available at
|
1939
|
+
https://github.com/smartiel/rustiq-core.
|
1940
|
+
|
1941
|
+
On large circuits the plugin may take a significant runtime.
|
1942
|
+
|
1943
|
+
The plugin supports the following additional options:
|
1944
|
+
|
1945
|
+
* optimize_count (bool): if `True` the synthesis algorithm will try to optimize
|
1946
|
+
the 2-qubit gate count; and if `False` then the 2-qubit depth.
|
1947
|
+
* preserve_order (bool): whether the order of paulis should be preserved, up to
|
1948
|
+
commutativity.
|
1949
|
+
* upto_clifford (bool): if `True`, the final Clifford operator is not synthesized.
|
1950
|
+
* upto_phase (bool): if `True`, the global phase of the returned circuit may
|
1951
|
+
differ from the global phase of the given pauli network.
|
1952
|
+
* resynth_clifford_method (int): describes the strategy to synthesize the final
|
1953
|
+
Clifford operator. Allowed values are `0` (naive approach), `1` (qiskit
|
1954
|
+
greedy synthesis), `2` (rustiq isometry synthesis).
|
1955
|
+
|
1956
|
+
References:
|
1957
|
+
1. Timothée Goubault de Brugière and Simon Martiel,
|
1958
|
+
*Faster and shorter synthesis of Hamiltonian simulation circuits*,
|
1959
|
+
`arXiv:2404.03280 [quant-ph] <https://arxiv.org/abs/2404.03280>`_
|
1960
|
+
|
1961
|
+
"""
|
1962
|
+
|
1963
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1964
|
+
if not isinstance(high_level_object, PauliEvolutionGate):
|
1965
|
+
# Don't do anything if a gate is called "evolution" but is not an
|
1966
|
+
# actual PauliEvolutionGate
|
1967
|
+
return None
|
1968
|
+
|
1969
|
+
algo = high_level_object.synthesis
|
1970
|
+
|
1971
|
+
if not isinstance(algo, ProductFormula):
|
1972
|
+
warnings.warn(
|
1973
|
+
"Cannot apply Rustiq if the evolution synthesis does not implement ``expand``. ",
|
1974
|
+
stacklevel=2,
|
1975
|
+
category=RuntimeWarning,
|
1976
|
+
)
|
1977
|
+
return None
|
1978
|
+
|
1979
|
+
original_preserve_order = algo.preserve_order
|
1980
|
+
if "preserve_order" in options:
|
1981
|
+
algo.preserve_order = options["preserve_order"]
|
1982
|
+
|
1983
|
+
num_qubits = high_level_object.num_qubits
|
1984
|
+
pauli_network = algo.expand(high_level_object)
|
1985
|
+
|
1986
|
+
optimize_count = options.get("optimize_count", True)
|
1987
|
+
preserve_order = options.get("preserve_order", True)
|
1988
|
+
upto_clifford = options.get("upto_clifford", False)
|
1989
|
+
upto_phase = options.get("upto_phase", False)
|
1990
|
+
resynth_clifford_method = options.get("resynth_clifford_method", 1)
|
1991
|
+
|
1992
|
+
synth_object = synth_pauli_network_rustiq(
|
1993
|
+
num_qubits=num_qubits,
|
1994
|
+
pauli_network=pauli_network,
|
1995
|
+
optimize_count=optimize_count,
|
1996
|
+
preserve_order=preserve_order,
|
1997
|
+
upto_clifford=upto_clifford,
|
1998
|
+
upto_phase=upto_phase,
|
1999
|
+
resynth_clifford_method=resynth_clifford_method,
|
2000
|
+
)
|
2001
|
+
algo.preserve_order = original_preserve_order
|
2002
|
+
return synth_object
|
2003
|
+
|
2004
|
+
|
2005
|
+
class AnnotatedSynthesisDefault(HighLevelSynthesisPlugin):
|
2006
|
+
"""Synthesize an :class:`.AnnotatedOperation` using the default synthesis algorithm.
|
2007
|
+
|
2008
|
+
This plugin name is:``annotated.default`` which can be used as the key on
|
2009
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
2010
|
+
"""
|
2011
|
+
|
2012
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
2013
|
+
# The plugin is triggered based on the name (i.e. for operations called "annotated").
|
2014
|
+
# However, we should only do something when the operation is truthfully an AnnotatedOperation.
|
2015
|
+
if not isinstance(high_level_object, AnnotatedOperation):
|
2016
|
+
return None
|
2017
|
+
|
2018
|
+
# Combine the modifiers. If there were no modifiers, or the modifiers magically canceled out,
|
2019
|
+
# return the quantum circuit containing the base operation.
|
2020
|
+
high_level_object = self._canonicalize_op(high_level_object)
|
2021
|
+
if not isinstance(high_level_object, AnnotatedOperation):
|
2022
|
+
return self._instruction_to_circuit(high_level_object)
|
2023
|
+
|
2024
|
+
operation = high_level_object
|
2025
|
+
modifiers = high_level_object.modifiers
|
2026
|
+
|
2027
|
+
# The plugin needs additional information that is not yet passed via the run's method
|
2028
|
+
# arguments: namely high-level-synthesis data and options, the global qubits over which
|
2029
|
+
# the operation is defined, and the initial state of each global qubit.
|
2030
|
+
tracker = options.get("qubit_tracker", None)
|
2031
|
+
data = options.get("hls_data", None)
|
2032
|
+
input_qubits = options.get("input_qubits", None)
|
2033
|
+
|
2034
|
+
if data is None or input_qubits is None:
|
2035
|
+
raise TranspilerError(
|
2036
|
+
"The AnnotatedSynthesisDefault plugin should receive data and input_qubits via options."
|
2037
|
+
)
|
2038
|
+
|
2039
|
+
# The synthesis consists of two steps:
|
2040
|
+
# - First, we synthesize the base operation.
|
2041
|
+
# - Second, we apply modifiers to this circuit.
|
2042
|
+
#
|
2043
|
+
# An important optimization (similar to the code in ``add_control.py``) is to synthesize
|
2044
|
+
# the base operation with respect to a larger set of "basis" gates, to which the control
|
2045
|
+
# logic can be added more efficiently. In addition, we add annotated operations to be
|
2046
|
+
# in this larger set, exploiting the fact that adding control to annotated operations
|
2047
|
+
# returns a new annotated operation with an extended list of modifiers.
|
2048
|
+
#
|
2049
|
+
# Note that it is fine for this function to return a circuit with high-level objects
|
2050
|
+
# (including annotated operations) as the HighLevelSynthesis transpiler pass will
|
2051
|
+
# recursively re-synthesize this circuit, However, we should always guarantee that some
|
2052
|
+
# progress is made.
|
2053
|
+
basis = set(EFFICIENTLY_CONTROLLED_GATES + ["annotated", "mcx", "qft"])
|
2054
|
+
|
2055
|
+
base_synthesis_data = HighLevelSynthesisData(
|
2056
|
+
hls_config=data.hls_config,
|
2057
|
+
hls_plugin_manager=data.hls_plugin_manager,
|
2058
|
+
coupling_map=None,
|
2059
|
+
target=None,
|
2060
|
+
equivalence_library=data.equivalence_library,
|
2061
|
+
hls_op_names=data.hls_op_names,
|
2062
|
+
device_insts=basis,
|
2063
|
+
use_physical_indices=data.use_physical_indices,
|
2064
|
+
min_qubits=0,
|
2065
|
+
unroll_definitions=data.unroll_definitions,
|
2066
|
+
)
|
2067
|
+
|
2068
|
+
num_ctrl = sum(mod.num_ctrl_qubits for mod in modifiers if isinstance(mod, ControlModifier))
|
2069
|
+
power = sum(mod.power for mod in modifiers if isinstance(mod, PowerModifier))
|
2070
|
+
is_inverted = sum(1 for mod in modifiers if isinstance(mod, InverseModifier)) % 2
|
2071
|
+
|
2072
|
+
# First, synthesize the base operation of this annotated operation.
|
2073
|
+
# As this step cannot use any control qubits as auxiliary qubits, we use a dedicated
|
2074
|
+
# tracker (annotated_tracker).
|
2075
|
+
# The logic is as follows:
|
2076
|
+
# - annotated_tracker.disable control qubits
|
2077
|
+
# - if have power or inverse modifiers, annotated_tracker.set_dirty(base_qubits)
|
2078
|
+
# - synthesize the base operation using annotated tracker
|
2079
|
+
# - main_tracker.set_dirty(base_qubits)
|
2080
|
+
#
|
2081
|
+
# Note that we need to set the base_qubits to dirty if we have power or inverse
|
2082
|
+
# modifiers. For power: even if the power is a positive integer (that is, we need
|
2083
|
+
# to repeat the same circuit multiple times), even if the target is initially at |0>,
|
2084
|
+
# it will generally not be at |0> after one iteration. For inverse: as we
|
2085
|
+
# flip the order of operations, we cannot exploit which qubits are at |0> as "viewed from
|
2086
|
+
# the back of the circuit". If we just have control modifiers, we can use the state
|
2087
|
+
# of base qubits when synthesizing the controlled operation.
|
2088
|
+
#
|
2089
|
+
# In addition, all of the other global qubits that are not a part of the annotated
|
2090
|
+
# operation can be used as they are in all cases, since we are assuming that all of
|
2091
|
+
# the synthesis methods preserve the states of ancilla qubits.
|
2092
|
+
annotated_tracker = tracker.copy()
|
2093
|
+
control_qubits = input_qubits[:num_ctrl]
|
2094
|
+
base_qubits = input_qubits[num_ctrl:]
|
2095
|
+
annotated_tracker.disable(control_qubits) # do not access control qubits
|
2096
|
+
if power != 0 or is_inverted:
|
2097
|
+
annotated_tracker.set_dirty(base_qubits)
|
2098
|
+
|
2099
|
+
# Note that synthesize_operation also returns the output qubits on which the
|
2100
|
+
# operation is defined, however currently the plugin mechanism has no way
|
2101
|
+
# to return these (and instead the upstream code greedily grabs some ancilla
|
2102
|
+
# qubits from the circuit). We should refactor the plugin "run" iterface to
|
2103
|
+
# return the actual ancilla qubits used.
|
2104
|
+
synthesized_base_op_result = synthesize_operation(
|
2105
|
+
operation.base_op, base_qubits, base_synthesis_data, annotated_tracker
|
2106
|
+
)
|
2107
|
+
|
2108
|
+
# The base operation does not need to be synthesized.
|
2109
|
+
# For simplicity, we wrap the instruction into a circuit. Note that
|
2110
|
+
# this should not deteriorate the quality of the result.
|
2111
|
+
if synthesized_base_op_result is None:
|
2112
|
+
synthesized_base_op = self._instruction_to_circuit(operation.base_op)
|
2113
|
+
else:
|
2114
|
+
synthesized_base_op = QuantumCircuit._from_circuit_data(synthesized_base_op_result[0])
|
2115
|
+
tracker.set_dirty(base_qubits)
|
2116
|
+
|
2117
|
+
# As one simple optimization, we apply conjugate decomposition to the circuit obtained
|
2118
|
+
# while synthesizing the base operator.
|
2119
|
+
conjugate_decomp = self._conjugate_decomposition(synthesized_base_op)
|
2120
|
+
|
2121
|
+
if conjugate_decomp is None:
|
2122
|
+
# Apply annotations to the whole circuit.
|
2123
|
+
# This step currently does not introduce ancilla qubits. However it makes
|
2124
|
+
# a lot of sense to allow this in the future.
|
2125
|
+
synthesized = self._apply_annotations(synthesized_base_op, operation.modifiers)
|
2126
|
+
else:
|
2127
|
+
# Apply annotations only to the middle part of the circuit.
|
2128
|
+
(front, middle, back) = conjugate_decomp
|
2129
|
+
synthesized = QuantumCircuit(operation.num_qubits)
|
2130
|
+
synthesized.compose(
|
2131
|
+
front, synthesized.qubits[num_ctrl : operation.num_qubits], inplace=True
|
2132
|
+
)
|
2133
|
+
synthesized.compose(
|
2134
|
+
self._apply_annotations(middle, operation.modifiers),
|
2135
|
+
synthesized.qubits,
|
2136
|
+
inplace=True,
|
2137
|
+
)
|
2138
|
+
synthesized.compose(
|
2139
|
+
back, synthesized.qubits[num_ctrl : operation.num_qubits], inplace=True
|
2140
|
+
)
|
2141
|
+
|
2142
|
+
return synthesized
|
2143
|
+
|
2144
|
+
@staticmethod
|
2145
|
+
def _apply_annotations(circuit: QuantumCircuit, modifiers: list[Modifier]) -> QuantumCircuit:
|
2146
|
+
"""
|
2147
|
+
Applies modifiers to a quantum circuit.
|
2148
|
+
"""
|
2149
|
+
for modifier in modifiers:
|
2150
|
+
if isinstance(modifier, InverseModifier):
|
2151
|
+
circuit = circuit.inverse()
|
2152
|
+
|
2153
|
+
elif isinstance(modifier, ControlModifier):
|
2154
|
+
if circuit.num_clbits > 0:
|
2155
|
+
raise TranspilerError(
|
2156
|
+
"AnnotatedSynthesisDefault: cannot control a circuit with classical bits."
|
2157
|
+
)
|
2158
|
+
|
2159
|
+
# Apply the control modifier to each gate in the circuit.
|
2160
|
+
controlled_circuit = QuantumCircuit(modifier.num_ctrl_qubits + circuit.num_qubits)
|
2161
|
+
if circuit.global_phase != 0:
|
2162
|
+
controlled_op = GlobalPhaseGate(circuit.global_phase).control(
|
2163
|
+
num_ctrl_qubits=modifier.num_ctrl_qubits,
|
2164
|
+
label=None,
|
2165
|
+
ctrl_state=modifier.ctrl_state,
|
2166
|
+
annotated=False,
|
2167
|
+
)
|
2168
|
+
controlled_qubits = list(range(0, modifier.num_ctrl_qubits))
|
2169
|
+
controlled_circuit.append(controlled_op, controlled_qubits)
|
2170
|
+
for inst in circuit:
|
2171
|
+
inst_op = inst.operation
|
2172
|
+
inst_qubits = inst.qubits
|
2173
|
+
controlled_op = inst_op.control(
|
2174
|
+
num_ctrl_qubits=modifier.num_ctrl_qubits,
|
2175
|
+
label=None,
|
2176
|
+
ctrl_state=modifier.ctrl_state,
|
2177
|
+
annotated=False,
|
2178
|
+
)
|
2179
|
+
controlled_qubits = list(range(0, modifier.num_ctrl_qubits)) + [
|
2180
|
+
modifier.num_ctrl_qubits + circuit.find_bit(q).index for q in inst_qubits
|
2181
|
+
]
|
2182
|
+
controlled_circuit.append(controlled_op, controlled_qubits)
|
2183
|
+
|
2184
|
+
circuit = controlled_circuit
|
2185
|
+
|
2186
|
+
if isinstance(circuit, AnnotatedOperation):
|
2187
|
+
raise TranspilerError(
|
2188
|
+
"AnnotatedSynthesisDefault: failed to synthesize the control modifier."
|
2189
|
+
)
|
2190
|
+
|
2191
|
+
elif isinstance(modifier, PowerModifier):
|
2192
|
+
circuit = circuit.power(modifier.power)
|
2193
|
+
|
2194
|
+
else:
|
2195
|
+
raise TranspilerError(f"AnnotatedSynthesisDefault: Unknown modifier {modifier}.")
|
2196
|
+
|
2197
|
+
return circuit
|
2198
|
+
|
2199
|
+
@staticmethod
|
2200
|
+
def _instruction_to_circuit(op: Operation) -> QuantumCircuit:
|
2201
|
+
"""Wraps a single operation into a quantum circuit."""
|
2202
|
+
circuit = QuantumCircuit(op.num_qubits, op.num_clbits)
|
2203
|
+
circuit.append(op, circuit.qubits, circuit.clbits)
|
2204
|
+
return circuit
|
2205
|
+
|
2206
|
+
@staticmethod
|
2207
|
+
def _instruction_to_circuit(op: Operation) -> QuantumCircuit:
|
2208
|
+
"""Wraps a single operation into a quantum circuit."""
|
2209
|
+
circuit = QuantumCircuit(op.num_qubits, op.num_clbits)
|
2210
|
+
circuit.append(op, circuit.qubits, circuit.clbits)
|
2211
|
+
return circuit
|
2212
|
+
|
2213
|
+
@staticmethod
|
2214
|
+
def _canonicalize_op(op: Operation) -> Operation:
|
2215
|
+
"""
|
2216
|
+
Combines recursive annotated operations and canonicalizes modifiers.
|
2217
|
+
"""
|
2218
|
+
cur = op
|
2219
|
+
all_modifiers = []
|
2220
|
+
|
2221
|
+
while isinstance(cur, AnnotatedOperation):
|
2222
|
+
all_modifiers.append(cur.modifiers)
|
2223
|
+
cur = cur.base_op
|
2224
|
+
|
2225
|
+
new_modifiers = []
|
2226
|
+
for modifiers in all_modifiers[::-1]:
|
2227
|
+
new_modifiers.extend(modifiers)
|
2228
|
+
|
2229
|
+
canonical_modifiers = _canonicalize_modifiers(new_modifiers)
|
2230
|
+
|
2231
|
+
if not canonical_modifiers:
|
2232
|
+
return cur
|
2233
|
+
|
2234
|
+
return AnnotatedOperation(cur, canonical_modifiers)
|
2235
|
+
|
2236
|
+
@staticmethod
|
2237
|
+
def _are_inverse_ops(inst1: "CircuitInstruction", inst2: "CircuitInstruction"):
|
2238
|
+
"""A very naive function that checks whether two circuit instructions are inverse of
|
2239
|
+
each other. The main use-case covered is a ``QFTGate`` and its inverse, represented as
|
2240
|
+
an ``AnnotatedOperation`` with a single ``InverseModifier``.
|
2241
|
+
"""
|
2242
|
+
res = False
|
2243
|
+
|
2244
|
+
if (
|
2245
|
+
inst1.qubits != inst2.qubits
|
2246
|
+
or inst1.clbits != inst2.clbits
|
2247
|
+
or len(inst1.params) != len(inst2.params)
|
2248
|
+
):
|
2249
|
+
return False
|
2250
|
+
|
2251
|
+
op1 = inst1.operation
|
2252
|
+
op2 = inst2.operation
|
2253
|
+
|
2254
|
+
ann1 = isinstance(op1, AnnotatedOperation)
|
2255
|
+
ann2 = isinstance(op2, AnnotatedOperation)
|
2256
|
+
|
2257
|
+
if not ann1 and not ann2:
|
2258
|
+
res = op1 == op2.inverse()
|
2259
|
+
elif not ann1 and ann2 and op2.modifiers == [InverseModifier()]:
|
2260
|
+
res = op1 == op2.base_op
|
2261
|
+
elif not ann2 and ann1 and op1.modifiers == [InverseModifier()]:
|
2262
|
+
res = op1.base_op == op2
|
2263
|
+
|
2264
|
+
return res
|
2265
|
+
|
2266
|
+
@staticmethod
|
2267
|
+
def _conjugate_decomposition(
|
2268
|
+
circuit: QuantumCircuit,
|
2269
|
+
) -> tuple[QuantumCircuit, QuantumCircuit, QuantumCircuit] | None:
|
2270
|
+
"""
|
2271
|
+
Decomposes a circuit ``A`` into 3 sub-circuits ``P``, ``Q``, ``R`` such that
|
2272
|
+
``A = P -- Q -- R`` and ``R = P^{-1}``.
|
2273
|
+
|
2274
|
+
This is accomplished by iteratively finding inverse nodes at the front and at the back of the
|
2275
|
+
circuit.
|
2276
|
+
|
2277
|
+
The function returns ``None`` when ``P`` and ``R`` are empty.
|
2278
|
+
"""
|
2279
|
+
num_gates = circuit.size()
|
2280
|
+
|
2281
|
+
idx = 0
|
2282
|
+
ridx = num_gates - 1
|
2283
|
+
|
2284
|
+
while True:
|
2285
|
+
if idx >= ridx:
|
2286
|
+
break
|
2287
|
+
if AnnotatedSynthesisDefault._are_inverse_ops(circuit[idx], circuit[ridx]):
|
2288
|
+
idx += 1
|
2289
|
+
ridx -= 1
|
2290
|
+
else:
|
2291
|
+
break
|
2292
|
+
|
2293
|
+
if idx == 0:
|
2294
|
+
return None
|
2295
|
+
|
2296
|
+
front_circuit = circuit.copy_empty_like()
|
2297
|
+
front_circuit.global_phase = 0
|
2298
|
+
for i in range(0, idx):
|
2299
|
+
front_circuit.append(circuit[i])
|
2300
|
+
middle_circuit = circuit.copy_empty_like() # inherits the global phase
|
2301
|
+
for i in range(idx, ridx + 1):
|
2302
|
+
middle_circuit.append(circuit[i])
|
2303
|
+
back_circuit = circuit.copy_empty_like()
|
2304
|
+
back_circuit.global_phase = 0
|
2305
|
+
for i in range(ridx + 1, num_gates):
|
2306
|
+
back_circuit.append(circuit[i])
|
2307
|
+
return (front_circuit, middle_circuit, back_circuit)
|
2308
|
+
|
2309
|
+
|
2310
|
+
class WeightedSumSynthesisDefault(HighLevelSynthesisPlugin):
|
2311
|
+
"""Synthesize a :class:`.WeightedSumGate` using the default synthesis algorithm.
|
2312
|
+
|
2313
|
+
This plugin name is:``WeightedSum.default`` which can be used as the key on
|
2314
|
+
an :class:`.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
2315
|
+
|
2316
|
+
.. note::
|
2317
|
+
|
2318
|
+
This default plugin requires auxiliary qubits. There is currently no implementation
|
2319
|
+
available without auxiliary qubits.
|
2320
|
+
|
2321
|
+
"""
|
2322
|
+
|
2323
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
2324
|
+
if not isinstance(high_level_object, WeightedSumGate):
|
2325
|
+
return None
|
2326
|
+
|
2327
|
+
required_auxiliaries = (
|
2328
|
+
high_level_object.num_sum_qubits - 1 + int(high_level_object.num_sum_qubits > 2)
|
2329
|
+
)
|
2330
|
+
if (num_clean := options.get("num_clean_ancillas", 0)) < required_auxiliaries:
|
2331
|
+
warnings.warn(
|
2332
|
+
f"Cannot synthesize a WeightedSumGate on {high_level_object.num_state_qubits} state "
|
2333
|
+
f"qubits with less than {required_auxiliaries} clean auxiliary qubits. Only "
|
2334
|
+
f"{num_clean} are available. This will likely lead to a error in HighLevelSynthesis."
|
2335
|
+
)
|
2336
|
+
return None
|
2337
|
+
|
2338
|
+
return synth_weighted_sum_carry(high_level_object)
|