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,1478 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2017, 2020.
|
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
|
+
"""The n-local circuit class."""
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import collections
|
18
|
+
import itertools
|
19
|
+
import typing
|
20
|
+
from collections.abc import Callable, Mapping, Sequence, Iterable
|
21
|
+
|
22
|
+
import numpy
|
23
|
+
from qiskit.circuit.gate import Gate
|
24
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit, ParameterValueType
|
25
|
+
from qiskit.circuit.parametervector import ParameterVector, ParameterVectorElement
|
26
|
+
from qiskit.circuit import QuantumRegister
|
27
|
+
from qiskit.circuit import (
|
28
|
+
Instruction,
|
29
|
+
Parameter,
|
30
|
+
ParameterExpression,
|
31
|
+
CircuitInstruction,
|
32
|
+
)
|
33
|
+
from qiskit.exceptions import QiskitError
|
34
|
+
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
|
35
|
+
from qiskit.utils.deprecation import deprecate_func
|
36
|
+
|
37
|
+
from qiskit._accelerate.circuit_library import (
|
38
|
+
Block,
|
39
|
+
py_n_local,
|
40
|
+
get_entangler_map as fast_entangler_map,
|
41
|
+
)
|
42
|
+
|
43
|
+
from ..blueprintcircuit import BlueprintCircuit
|
44
|
+
|
45
|
+
|
46
|
+
if typing.TYPE_CHECKING:
|
47
|
+
import qiskit # pylint: disable=cyclic-import
|
48
|
+
|
49
|
+
# entanglement for an individual block, e.g. if the block is CXGate() and we have
|
50
|
+
# 3 qubits, this could be [(0, 1), (1, 2), (2, 0)]
|
51
|
+
BlockEntanglement = typing.Union[str, Iterable[Iterable[int]]]
|
52
|
+
|
53
|
+
|
54
|
+
def n_local(
|
55
|
+
num_qubits: int,
|
56
|
+
rotation_blocks: str | Gate | Iterable[str | Gate],
|
57
|
+
entanglement_blocks: str | Gate | Iterable[str | Gate],
|
58
|
+
entanglement: (
|
59
|
+
BlockEntanglement
|
60
|
+
| Iterable[BlockEntanglement]
|
61
|
+
| Callable[[int], BlockEntanglement | Iterable[BlockEntanglement]]
|
62
|
+
) = "full",
|
63
|
+
reps: int = 3,
|
64
|
+
insert_barriers: bool = False,
|
65
|
+
parameter_prefix: str = "θ",
|
66
|
+
overwrite_block_parameters: bool = True,
|
67
|
+
skip_final_rotation_layer: bool = False,
|
68
|
+
skip_unentangled_qubits: bool = False,
|
69
|
+
name: str | None = "nlocal",
|
70
|
+
) -> QuantumCircuit:
|
71
|
+
r"""Construct an n-local variational circuit.
|
72
|
+
|
73
|
+
The structure of the n-local circuit are alternating rotation and entanglement layers.
|
74
|
+
In both layers, parameterized circuit-blocks act on the circuit in a defined way.
|
75
|
+
In the rotation layer, the blocks are applied stacked on top of each other, while in the
|
76
|
+
entanglement layer according to the ``entanglement`` strategy.
|
77
|
+
The circuit blocks can have arbitrary sizes (smaller equal to the number of qubits in the
|
78
|
+
circuit). Each layer is repeated ``reps`` times, and by default a final rotation layer is
|
79
|
+
appended.
|
80
|
+
|
81
|
+
For instance, a rotation block on 2 qubits and an entanglement block on 4 qubits using
|
82
|
+
``"linear"`` entanglement yields the following circuit.
|
83
|
+
|
84
|
+
.. parsed-literal::
|
85
|
+
|
86
|
+
┌──────┐ ░ ┌──────┐ ░ ┌──────┐
|
87
|
+
┤0 ├─░─┤0 ├──────────────── ... ─░─┤0 ├
|
88
|
+
│ Rot │ ░ │ │┌──────┐ ░ │ Rot │
|
89
|
+
┤1 ├─░─┤1 ├┤0 ├──────── ... ─░─┤1 ├
|
90
|
+
├──────┤ ░ │ Ent ││ │┌──────┐ ░ ├──────┤
|
91
|
+
┤0 ├─░─┤2 ├┤1 ├┤0 ├ ... ─░─┤0 ├
|
92
|
+
│ Rot │ ░ │ ││ Ent ││ │ ░ │ Rot │
|
93
|
+
┤1 ├─░─┤3 ├┤2 ├┤1 ├ ... ─░─┤1 ├
|
94
|
+
├──────┤ ░ └──────┘│ ││ Ent │ ░ ├──────┤
|
95
|
+
┤0 ├─░─────────┤3 ├┤2 ├ ... ─░─┤0 ├
|
96
|
+
│ Rot │ ░ └──────┘│ │ ░ │ Rot │
|
97
|
+
┤1 ├─░─────────────────┤3 ├ ... ─░─┤1 ├
|
98
|
+
└──────┘ ░ └──────┘ ░ └──────┘
|
99
|
+
|
100
|
+
| |
|
101
|
+
+---------------------------------+
|
102
|
+
repeated reps times
|
103
|
+
|
104
|
+
Entanglement:
|
105
|
+
|
106
|
+
The entanglement describes the connections of the gates in the entanglement layer.
|
107
|
+
For a two-qubit gate for example, the entanglement contains pairs of qubits on which the
|
108
|
+
gate should acts, e.g. ``[[ctrl0, target0], [ctrl1, target1], ...]``.
|
109
|
+
A set of default entanglement strategies is provided and can be selected by name:
|
110
|
+
|
111
|
+
* ``"full"`` entanglement is each qubit is entangled with all the others.
|
112
|
+
* ``"linear"`` entanglement is qubit :math:`i` entangled with qubit :math:`i + 1`,
|
113
|
+
for all :math:`i \in \{0, 1, ... , n - 2\}`, where :math:`n` is the total number of qubits.
|
114
|
+
* ``"reverse_linear"`` entanglement is qubit :math:`i` entangled with qubit :math:`i + 1`,
|
115
|
+
for all :math:`i \in \{n-2, n-3, ... , 1, 0\}`, where :math:`n` is the total number of qubits.
|
116
|
+
Note that if ``entanglement_blocks=="cx"`` then this option provides the same unitary as
|
117
|
+
``"full"`` with fewer entangling gates.
|
118
|
+
* ``"pairwise"`` entanglement is one layer where qubit :math:`i` is entangled with qubit
|
119
|
+
:math:`i + 1`, for all even values of :math:`i`, and then a second layer where qubit :math:`i`
|
120
|
+
is entangled with qubit :math:`i + 1`, for all odd values of :math:`i`.
|
121
|
+
* ``"circular"`` entanglement is linear entanglement but with an additional entanglement of the
|
122
|
+
first and last qubit before the linear part.
|
123
|
+
* ``"sca"`` (shifted-circular-alternating) entanglement is a generalized and modified version
|
124
|
+
of the proposed circuit 14 in `Sim et al. <https://arxiv.org/abs/1905.10876>`__.
|
125
|
+
It consists of circular entanglement where the "long" entanglement connecting the first with
|
126
|
+
the last qubit is shifted by one each block. Furthermore the role of control and target
|
127
|
+
qubits are swapped every block (therefore alternating).
|
128
|
+
|
129
|
+
If an entanglement layer contains multiple blocks, then the entanglement should be
|
130
|
+
given as list of entanglements for each block. For example::
|
131
|
+
|
132
|
+
entanglement_blocks = ["rxx", "ryy"]
|
133
|
+
entanglement = ["full", "linear"] # full for rxx and linear for ryy
|
134
|
+
|
135
|
+
or::
|
136
|
+
|
137
|
+
structure_rxx = [[0, 1], [2, 3]]
|
138
|
+
structure_ryy = [[0, 2]]
|
139
|
+
entanglement = [structure_rxx, structure_ryy]
|
140
|
+
|
141
|
+
Finally, the entanglement can vary in each repetition of the circuit. For this, we
|
142
|
+
support passing a callable that takes as input the layer index and returns the entanglement
|
143
|
+
for the layer in the above format. See the examples below for a concrete example.
|
144
|
+
|
145
|
+
Examples:
|
146
|
+
|
147
|
+
The rotation and entanglement gates can be specified via single strings, if they
|
148
|
+
are made up of a single block per layer:
|
149
|
+
|
150
|
+
.. plot::
|
151
|
+
:alt: Circuit diagram output by the previous code.
|
152
|
+
:include-source:
|
153
|
+
:context:
|
154
|
+
|
155
|
+
from qiskit.circuit.library import n_local
|
156
|
+
|
157
|
+
circuit = n_local(3, "ry", "cx", "linear", reps=2, insert_barriers=True)
|
158
|
+
circuit.draw("mpl")
|
159
|
+
|
160
|
+
Multiple gates per layer can be set by passing a list. Here, for example, we use
|
161
|
+
Pauli-Y and Pauli-Z rotations in the rotation layer:
|
162
|
+
|
163
|
+
.. plot::
|
164
|
+
:alt: Circuit diagram output by the previous code.
|
165
|
+
:include-source:
|
166
|
+
:context: close-figs
|
167
|
+
|
168
|
+
circuit = n_local(3, ["ry", "rz"], "cz", "full", reps=1, insert_barriers=True)
|
169
|
+
circuit.draw("mpl")
|
170
|
+
|
171
|
+
To omit rotation or entanglement layers, the block can be set to an empty list:
|
172
|
+
|
173
|
+
.. plot::
|
174
|
+
:alt: Circuit diagram output by the previous code.
|
175
|
+
:include-source:
|
176
|
+
:context: close-figs
|
177
|
+
|
178
|
+
circuit = n_local(4, [], "cry", reps=2)
|
179
|
+
circuit.draw("mpl")
|
180
|
+
|
181
|
+
The entanglement can be set explicitly via the ``entanglement`` argument:
|
182
|
+
|
183
|
+
.. plot::
|
184
|
+
:alt: Circuit diagram output by the previous code.
|
185
|
+
:include-source:
|
186
|
+
:context: close-figs
|
187
|
+
|
188
|
+
entangler_map = [[0, 1], [2, 0]]
|
189
|
+
circuit = n_local(3, "x", "crx", entangler_map, reps=2)
|
190
|
+
circuit.draw("mpl")
|
191
|
+
|
192
|
+
We can set different entanglements per layer, by specifing a callable that takes
|
193
|
+
as input the current layer index, and returns the entanglement structure. For example,
|
194
|
+
the following uses different entanglements for odd and even layers:
|
195
|
+
|
196
|
+
.. plot::
|
197
|
+
:alt: Circuit diagram output by the previous code.
|
198
|
+
:include-source:
|
199
|
+
:context: close-figs
|
200
|
+
|
201
|
+
def entanglement(layer_index):
|
202
|
+
if layer_index % 2 == 0:
|
203
|
+
return [[0, 1], [0, 2]]
|
204
|
+
return [[1, 2]]
|
205
|
+
|
206
|
+
circuit = n_local(3, "x", "cx", entanglement, reps=3, insert_barriers=True)
|
207
|
+
circuit.draw("mpl")
|
208
|
+
|
209
|
+
|
210
|
+
Args:
|
211
|
+
num_qubits: The number of qubits of the circuit.
|
212
|
+
rotation_blocks: The blocks used in the rotation layers. If multiple are passed,
|
213
|
+
these will be applied one after another (like new sub-layers).
|
214
|
+
entanglement_blocks: The blocks used in the entanglement layers. If multiple are passed,
|
215
|
+
these will be applied one after another.
|
216
|
+
entanglement: The indices specifying on which qubits the input blocks act. This is
|
217
|
+
specified by string describing an entanglement strategy (see the additional info)
|
218
|
+
or a list of qubit connections.
|
219
|
+
If a list of entanglement blocks is passed, different entanglement for each block can
|
220
|
+
be specified by passing a list of entanglements. To specify varying entanglement for
|
221
|
+
each repetition, pass a callable that takes as input the layer and returns the
|
222
|
+
entanglement for that layer.
|
223
|
+
Defaults to ``"full"``, meaning an all-to-all entanglement structure.
|
224
|
+
reps: Specifies how often the rotation blocks and entanglement blocks are repeated.
|
225
|
+
insert_barriers: If ``True``, barriers are inserted in between each layer. If ``False``,
|
226
|
+
no barriers are inserted.
|
227
|
+
parameter_prefix: The prefix used if default parameters are generated.
|
228
|
+
overwrite_block_parameters: If the parameters in the added blocks should be overwritten.
|
229
|
+
If ``False``, the parameters in the blocks are not changed.
|
230
|
+
skip_final_rotation_layer: Whether a final rotation layer is added to the circuit.
|
231
|
+
skip_unentangled_qubits: If ``True``, the rotation gates act only on qubits that
|
232
|
+
are entangled. If ``False``, the rotation gates act on all qubits.
|
233
|
+
name: The name of the circuit.
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
An n-local circuit.
|
237
|
+
"""
|
238
|
+
if reps < 0:
|
239
|
+
# this is an important check, since we cast this to an unsigned integer Rust-side
|
240
|
+
raise ValueError(f"reps must be non-negative, but is {reps}")
|
241
|
+
|
242
|
+
supported_gates = get_standard_gate_name_mapping()
|
243
|
+
rotation_blocks = _normalize_blocks(
|
244
|
+
rotation_blocks, supported_gates, overwrite_block_parameters
|
245
|
+
)
|
246
|
+
entanglement_blocks = _normalize_blocks(
|
247
|
+
entanglement_blocks, supported_gates, overwrite_block_parameters
|
248
|
+
)
|
249
|
+
|
250
|
+
entanglement = _normalize_entanglement(entanglement, len(entanglement_blocks))
|
251
|
+
|
252
|
+
data = py_n_local(
|
253
|
+
num_qubits=num_qubits,
|
254
|
+
rotation_blocks=rotation_blocks,
|
255
|
+
entanglement_blocks=entanglement_blocks,
|
256
|
+
entanglement=entanglement,
|
257
|
+
reps=reps,
|
258
|
+
insert_barriers=insert_barriers,
|
259
|
+
parameter_prefix=parameter_prefix,
|
260
|
+
skip_final_rotation_layer=skip_final_rotation_layer,
|
261
|
+
skip_unentangled_qubits=skip_unentangled_qubits,
|
262
|
+
)
|
263
|
+
circuit = QuantumCircuit._from_circuit_data(data, add_regs=True, name=name)
|
264
|
+
|
265
|
+
return circuit
|
266
|
+
|
267
|
+
|
268
|
+
class NLocal(BlueprintCircuit):
|
269
|
+
"""The n-local circuit class.
|
270
|
+
|
271
|
+
The structure of the n-local circuit are alternating rotation and entanglement layers.
|
272
|
+
In both layers, parameterized circuit-blocks act on the circuit in a defined way.
|
273
|
+
In the rotation layer, the blocks are applied stacked on top of each other, while in the
|
274
|
+
entanglement layer according to the ``entanglement`` strategy.
|
275
|
+
The circuit blocks can have arbitrary sizes (smaller equal to the number of qubits in the
|
276
|
+
circuit). Each layer is repeated ``reps`` times, and by default a final rotation layer is
|
277
|
+
appended.
|
278
|
+
|
279
|
+
For instance, a rotation block on 2 qubits and an entanglement block on 4 qubits using
|
280
|
+
``'linear'`` entanglement yields the following circuit.
|
281
|
+
|
282
|
+
.. code-block:: text
|
283
|
+
|
284
|
+
┌──────┐ ░ ┌──────┐ ░ ┌──────┐
|
285
|
+
┤0 ├─░─┤0 ├──────────────── ... ─░─┤0 ├
|
286
|
+
│ Rot │ ░ │ │┌──────┐ ░ │ Rot │
|
287
|
+
┤1 ├─░─┤1 ├┤0 ├──────── ... ─░─┤1 ├
|
288
|
+
├──────┤ ░ │ Ent ││ │┌──────┐ ░ ├──────┤
|
289
|
+
┤0 ├─░─┤2 ├┤1 ├┤0 ├ ... ─░─┤0 ├
|
290
|
+
│ Rot │ ░ │ ││ Ent ││ │ ░ │ Rot │
|
291
|
+
┤1 ├─░─┤3 ├┤2 ├┤1 ├ ... ─░─┤1 ├
|
292
|
+
├──────┤ ░ └──────┘│ ││ Ent │ ░ ├──────┤
|
293
|
+
┤0 ├─░─────────┤3 ├┤2 ├ ... ─░─┤0 ├
|
294
|
+
│ Rot │ ░ └──────┘│ │ ░ │ Rot │
|
295
|
+
┤1 ├─░─────────────────┤3 ├ ... ─░─┤1 ├
|
296
|
+
└──────┘ ░ └──────┘ ░ └──────┘
|
297
|
+
|
298
|
+
| |
|
299
|
+
+---------------------------------+
|
300
|
+
repeated reps times
|
301
|
+
|
302
|
+
If specified, barriers can be inserted in between every block.
|
303
|
+
If an initial state object is provided, it is added in front of the NLocal.
|
304
|
+
|
305
|
+
.. seealso::
|
306
|
+
|
307
|
+
The :func:`.n_local` function constructs a functionally equivalent circuit, but faster.
|
308
|
+
|
309
|
+
"""
|
310
|
+
|
311
|
+
@deprecate_func(
|
312
|
+
since="2.1",
|
313
|
+
additional_msg="This applies to NLocal subclasses too. Use the corresponding function "
|
314
|
+
"from the module qiskit.circuit.library.n_local instead.",
|
315
|
+
removal_timeline="in Qiskit 3.0",
|
316
|
+
)
|
317
|
+
def __init__(
|
318
|
+
self,
|
319
|
+
num_qubits: int | None = None,
|
320
|
+
rotation_blocks: (
|
321
|
+
QuantumCircuit
|
322
|
+
| list[QuantumCircuit]
|
323
|
+
| qiskit.circuit.Instruction
|
324
|
+
| list[qiskit.circuit.Instruction]
|
325
|
+
| None
|
326
|
+
) = None,
|
327
|
+
entanglement_blocks: (
|
328
|
+
QuantumCircuit
|
329
|
+
| list[QuantumCircuit]
|
330
|
+
| qiskit.circuit.Instruction
|
331
|
+
| list[qiskit.circuit.Instruction]
|
332
|
+
| None
|
333
|
+
) = None,
|
334
|
+
entanglement: list[int] | list[list[int]] | None = None,
|
335
|
+
reps: int = 1,
|
336
|
+
insert_barriers: bool = False,
|
337
|
+
parameter_prefix: str = "θ",
|
338
|
+
overwrite_block_parameters: bool | list[list[Parameter]] = True,
|
339
|
+
skip_final_rotation_layer: bool = False,
|
340
|
+
skip_unentangled_qubits: bool = False,
|
341
|
+
initial_state: QuantumCircuit | None = None,
|
342
|
+
name: str | None = "nlocal",
|
343
|
+
flatten: bool | None = None,
|
344
|
+
) -> None:
|
345
|
+
"""
|
346
|
+
Args:
|
347
|
+
num_qubits: The number of qubits of the circuit.
|
348
|
+
rotation_blocks: The blocks used in the rotation layers. If multiple are passed,
|
349
|
+
these will be applied one after another (like new sub-layers).
|
350
|
+
entanglement_blocks: The blocks used in the entanglement layers. If multiple are passed,
|
351
|
+
these will be applied one after another. To use different entanglements for
|
352
|
+
the sub-layers, see :meth:`get_entangler_map`.
|
353
|
+
entanglement: The indices specifying on which qubits the input blocks act. If ``None``, the
|
354
|
+
entanglement blocks are applied at the top of the circuit.
|
355
|
+
reps: Specifies how often the rotation blocks and entanglement blocks are repeated.
|
356
|
+
insert_barriers: If ``True``, barriers are inserted in between each layer. If ``False``,
|
357
|
+
no barriers are inserted.
|
358
|
+
parameter_prefix: The prefix used if default parameters are generated.
|
359
|
+
overwrite_block_parameters: If the parameters in the added blocks should be overwritten.
|
360
|
+
If ``False``, the parameters in the blocks are not changed.
|
361
|
+
skip_final_rotation_layer: Whether a final rotation layer is added to the circuit.
|
362
|
+
skip_unentangled_qubits: If ``True``, the rotation gates act only on qubits that
|
363
|
+
are entangled. If ``False``, the rotation gates act on all qubits.
|
364
|
+
initial_state: A :class:`.QuantumCircuit` object which can be used to describe an initial
|
365
|
+
state prepended to the NLocal circuit.
|
366
|
+
name: The name of the circuit.
|
367
|
+
flatten: Set this to ``True`` to output a flat circuit instead of nesting it inside multiple
|
368
|
+
layers of gate objects. By default currently the contents of
|
369
|
+
the output circuit will be wrapped in nested objects for
|
370
|
+
cleaner visualization. However, if you're using this circuit
|
371
|
+
for anything besides visualization its **strongly** recommended
|
372
|
+
to set this flag to ``True`` to avoid a large performance
|
373
|
+
overhead for parameter binding.
|
374
|
+
|
375
|
+
Raises:
|
376
|
+
ValueError: If ``reps`` parameter is less than or equal to 0.
|
377
|
+
TypeError: If ``reps`` parameter is not an int value.
|
378
|
+
"""
|
379
|
+
super().__init__(name=name)
|
380
|
+
|
381
|
+
self._num_qubits: int | None = None
|
382
|
+
self._insert_barriers = insert_barriers
|
383
|
+
self._reps = reps
|
384
|
+
self._entanglement_blocks: list[QuantumCircuit] = []
|
385
|
+
self._rotation_blocks: list[QuantumCircuit] = []
|
386
|
+
self._prepended_blocks: list[QuantumCircuit] = []
|
387
|
+
self._prepended_entanglement: list[list[list[int]] | str] = []
|
388
|
+
self._appended_blocks: list[QuantumCircuit] = []
|
389
|
+
self._appended_entanglement: list[list[list[int]] | str] = []
|
390
|
+
self._entanglement = None
|
391
|
+
self._entangler_maps = None
|
392
|
+
self._ordered_parameters: ParameterVector | list[Parameter] = ParameterVector(
|
393
|
+
name=parameter_prefix
|
394
|
+
)
|
395
|
+
self._overwrite_block_parameters = overwrite_block_parameters
|
396
|
+
self._skip_final_rotation_layer = skip_final_rotation_layer
|
397
|
+
self._skip_unentangled_qubits = skip_unentangled_qubits
|
398
|
+
self._initial_state: QuantumCircuit | None = None
|
399
|
+
self._initial_state_circuit: QuantumCircuit | None = None
|
400
|
+
self._bounds: list[tuple[float | None, float | None]] | None = None
|
401
|
+
self._flatten = flatten
|
402
|
+
|
403
|
+
# During the build, if a subclass hasn't overridden our parametrization methods, we can use
|
404
|
+
# a newer fast-path method to parametrise the rotation and entanglement blocks if internally
|
405
|
+
# those are just simple stdlib gates that have been promoted to circuits. We don't
|
406
|
+
# precalculate the fast-path layers themselves because there's far too much that can be
|
407
|
+
# overridden between object construction and build, and far too many subclasses of `NLocal`
|
408
|
+
# that override bits and bobs of the internal private methods, so it'd be too hard to keep
|
409
|
+
# everything in sync.
|
410
|
+
self._allow_fast_path_parametrization = (
|
411
|
+
getattr(self._parameter_generator, "__func__", None) is NLocal._parameter_generator
|
412
|
+
)
|
413
|
+
|
414
|
+
if int(reps) != reps:
|
415
|
+
raise TypeError("The value of reps should be int")
|
416
|
+
|
417
|
+
if reps < 0:
|
418
|
+
raise ValueError("The value of reps should be larger than or equal to 0")
|
419
|
+
|
420
|
+
if num_qubits is not None:
|
421
|
+
self.num_qubits = num_qubits
|
422
|
+
|
423
|
+
if entanglement_blocks is not None:
|
424
|
+
self.entanglement_blocks = entanglement_blocks
|
425
|
+
|
426
|
+
if rotation_blocks is not None:
|
427
|
+
self.rotation_blocks = rotation_blocks
|
428
|
+
|
429
|
+
if entanglement is not None:
|
430
|
+
self.entanglement = entanglement
|
431
|
+
|
432
|
+
if initial_state is not None:
|
433
|
+
self.initial_state = initial_state
|
434
|
+
|
435
|
+
@property
|
436
|
+
def num_qubits(self) -> int:
|
437
|
+
"""Returns the number of qubits in this circuit.
|
438
|
+
|
439
|
+
Returns:
|
440
|
+
The number of qubits.
|
441
|
+
"""
|
442
|
+
return self._num_qubits if self._num_qubits is not None else 0
|
443
|
+
|
444
|
+
@num_qubits.setter
|
445
|
+
def num_qubits(self, num_qubits: int) -> None:
|
446
|
+
"""Set the number of qubits for the n-local circuit.
|
447
|
+
|
448
|
+
Args:
|
449
|
+
The new number of qubits.
|
450
|
+
"""
|
451
|
+
if self._num_qubits != num_qubits:
|
452
|
+
# invalidate the circuit
|
453
|
+
self._invalidate()
|
454
|
+
self._num_qubits = num_qubits
|
455
|
+
self.qregs = [QuantumRegister(num_qubits, name="q")]
|
456
|
+
|
457
|
+
@property
|
458
|
+
def flatten(self) -> bool:
|
459
|
+
"""Returns whether the circuit is wrapped in nested gates/instructions or flattened."""
|
460
|
+
return bool(self._flatten)
|
461
|
+
|
462
|
+
@flatten.setter
|
463
|
+
def flatten(self, flatten: bool) -> None:
|
464
|
+
self._invalidate()
|
465
|
+
self._flatten = flatten
|
466
|
+
|
467
|
+
def _convert_to_block(self, layer: typing.Any) -> QuantumCircuit:
|
468
|
+
"""Try to convert ``layer`` to a QuantumCircuit.
|
469
|
+
|
470
|
+
Args:
|
471
|
+
layer: The object to be converted to an NLocal block / Instruction.
|
472
|
+
|
473
|
+
Returns:
|
474
|
+
The layer converted to a circuit.
|
475
|
+
|
476
|
+
Raises:
|
477
|
+
TypeError: If the input cannot be converted to a circuit.
|
478
|
+
"""
|
479
|
+
if isinstance(layer, QuantumCircuit):
|
480
|
+
return layer
|
481
|
+
|
482
|
+
if isinstance(layer, Instruction):
|
483
|
+
circuit = QuantumCircuit(layer.num_qubits)
|
484
|
+
circuit.append(layer, list(range(layer.num_qubits)))
|
485
|
+
return circuit
|
486
|
+
|
487
|
+
try:
|
488
|
+
circuit = QuantumCircuit(layer.num_qubits)
|
489
|
+
circuit.append(layer.to_instruction(), list(range(layer.num_qubits)))
|
490
|
+
return circuit
|
491
|
+
except AttributeError:
|
492
|
+
pass
|
493
|
+
|
494
|
+
raise TypeError(f"Adding a {type(layer)} to an NLocal is not supported.")
|
495
|
+
|
496
|
+
@property
|
497
|
+
def rotation_blocks(self) -> list[QuantumCircuit]:
|
498
|
+
"""The blocks in the rotation layers.
|
499
|
+
|
500
|
+
Returns:
|
501
|
+
The blocks in the rotation layers.
|
502
|
+
"""
|
503
|
+
return self._rotation_blocks
|
504
|
+
|
505
|
+
@rotation_blocks.setter
|
506
|
+
def rotation_blocks(
|
507
|
+
self, blocks: QuantumCircuit | list[QuantumCircuit] | Instruction | list[Instruction]
|
508
|
+
) -> None:
|
509
|
+
"""Set the blocks in the rotation layers.
|
510
|
+
|
511
|
+
Args:
|
512
|
+
blocks: The new blocks for the rotation layers.
|
513
|
+
"""
|
514
|
+
# cannot check for the attribute ``'__len__'`` because a circuit also has this attribute
|
515
|
+
if not isinstance(blocks, (list, numpy.ndarray)):
|
516
|
+
blocks = [blocks]
|
517
|
+
|
518
|
+
self._invalidate()
|
519
|
+
self._rotation_blocks = [self._convert_to_block(block) for block in blocks]
|
520
|
+
|
521
|
+
@property
|
522
|
+
def entanglement_blocks(self) -> list[QuantumCircuit]:
|
523
|
+
"""The blocks in the entanglement layers.
|
524
|
+
|
525
|
+
Returns:
|
526
|
+
The blocks in the entanglement layers.
|
527
|
+
"""
|
528
|
+
return self._entanglement_blocks
|
529
|
+
|
530
|
+
@entanglement_blocks.setter
|
531
|
+
def entanglement_blocks(
|
532
|
+
self, blocks: QuantumCircuit | list[QuantumCircuit] | Instruction | list[Instruction]
|
533
|
+
) -> None:
|
534
|
+
"""Set the blocks in the entanglement layers.
|
535
|
+
|
536
|
+
Args:
|
537
|
+
blocks: The new blocks for the entanglement layers.
|
538
|
+
"""
|
539
|
+
# cannot check for the attribute ``'__len__'`` because a circuit also has this attribute
|
540
|
+
if not isinstance(blocks, (list, numpy.ndarray)):
|
541
|
+
blocks = [blocks]
|
542
|
+
|
543
|
+
self._invalidate()
|
544
|
+
self._entanglement_blocks = [self._convert_to_block(block) for block in blocks]
|
545
|
+
|
546
|
+
@property
|
547
|
+
def entanglement(
|
548
|
+
self,
|
549
|
+
) -> (
|
550
|
+
str
|
551
|
+
| list[str]
|
552
|
+
| list[list[str]]
|
553
|
+
| list[int]
|
554
|
+
| list[list[int]]
|
555
|
+
| list[list[list[int]]]
|
556
|
+
| list[list[list[list[int]]]]
|
557
|
+
| Callable[[int], str]
|
558
|
+
| Callable[[int], list[list[int]]]
|
559
|
+
):
|
560
|
+
"""Get the entanglement strategy.
|
561
|
+
|
562
|
+
Returns:
|
563
|
+
The entanglement strategy, see :meth:`get_entangler_map` for more detail on how the
|
564
|
+
format is interpreted.
|
565
|
+
"""
|
566
|
+
return self._entanglement
|
567
|
+
|
568
|
+
@entanglement.setter
|
569
|
+
def entanglement(
|
570
|
+
self,
|
571
|
+
entanglement: (
|
572
|
+
str
|
573
|
+
| list[str]
|
574
|
+
| list[list[str]]
|
575
|
+
| list[int]
|
576
|
+
| list[list[int]]
|
577
|
+
| list[list[list[int]]]
|
578
|
+
| list[list[list[list[int]]]]
|
579
|
+
| Callable[[int], str]
|
580
|
+
| Callable[[int], list[list[int]]]
|
581
|
+
| None
|
582
|
+
),
|
583
|
+
) -> None:
|
584
|
+
"""Set the entanglement strategy.
|
585
|
+
|
586
|
+
Args:
|
587
|
+
entanglement: The entanglement strategy. See :meth:`get_entangler_map` for more detail
|
588
|
+
on the supported formats.
|
589
|
+
"""
|
590
|
+
self._invalidate()
|
591
|
+
self._entanglement = entanglement
|
592
|
+
|
593
|
+
@property
|
594
|
+
def num_layers(self) -> int:
|
595
|
+
"""Return the number of layers in the n-local circuit.
|
596
|
+
|
597
|
+
Returns:
|
598
|
+
The number of layers in the circuit.
|
599
|
+
"""
|
600
|
+
return 2 * self._reps + int(not self._skip_final_rotation_layer)
|
601
|
+
|
602
|
+
def _check_configuration(self, raise_on_failure: bool = True) -> bool:
|
603
|
+
"""Check if the configuration of the NLocal class is valid.
|
604
|
+
|
605
|
+
Args:
|
606
|
+
raise_on_failure: Whether to raise on failure.
|
607
|
+
|
608
|
+
Returns:
|
609
|
+
True, if the configuration is valid and the circuit can be constructed. Otherwise
|
610
|
+
an ValueError is raised.
|
611
|
+
|
612
|
+
Raises:
|
613
|
+
ValueError: If the blocks are not set.
|
614
|
+
ValueError: If the number of repetitions is not set.
|
615
|
+
ValueError: If the qubit indices are not set.
|
616
|
+
ValueError: If the number of qubit indices does not match the number of blocks.
|
617
|
+
ValueError: If an index in the repetitions list exceeds the number of blocks.
|
618
|
+
ValueError: If the number of repetitions does not match the number of block-wise
|
619
|
+
parameters.
|
620
|
+
ValueError: If a specified qubit index is larger than the (manually set) number of
|
621
|
+
qubits.
|
622
|
+
"""
|
623
|
+
valid = True
|
624
|
+
if self.num_qubits is None:
|
625
|
+
valid = False
|
626
|
+
if raise_on_failure:
|
627
|
+
raise ValueError("No number of qubits specified.")
|
628
|
+
|
629
|
+
# check no needed parameters are None
|
630
|
+
if self.entanglement_blocks is None and self.rotation_blocks is None:
|
631
|
+
valid = False
|
632
|
+
if raise_on_failure:
|
633
|
+
raise ValueError("The blocks are not set.")
|
634
|
+
|
635
|
+
return valid
|
636
|
+
|
637
|
+
@property
|
638
|
+
def ordered_parameters(self) -> list[Parameter]:
|
639
|
+
"""The parameters used in the underlying circuit.
|
640
|
+
|
641
|
+
This includes float values and duplicates.
|
642
|
+
|
643
|
+
Examples:
|
644
|
+
|
645
|
+
>>> # prepare circuit ...
|
646
|
+
>>> print(nlocal)
|
647
|
+
┌───────┐┌──────────┐┌──────────┐┌──────────┐
|
648
|
+
q_0: ┤ Ry(1) ├┤ Ry(θ[1]) ├┤ Ry(θ[1]) ├┤ Ry(θ[3]) ├
|
649
|
+
└───────┘└──────────┘└──────────┘└──────────┘
|
650
|
+
>>> nlocal.parameters
|
651
|
+
{Parameter(θ[1]), Parameter(θ[3])}
|
652
|
+
>>> nlocal.ordered_parameters
|
653
|
+
[1, Parameter(θ[1]), Parameter(θ[1]), Parameter(θ[3])]
|
654
|
+
|
655
|
+
Returns:
|
656
|
+
The parameters objects used in the circuit.
|
657
|
+
"""
|
658
|
+
if isinstance(self._ordered_parameters, ParameterVector):
|
659
|
+
self._ordered_parameters.resize(self.num_parameters_settable)
|
660
|
+
return list(self._ordered_parameters)
|
661
|
+
|
662
|
+
return self._ordered_parameters
|
663
|
+
|
664
|
+
@ordered_parameters.setter
|
665
|
+
def ordered_parameters(self, parameters: ParameterVector | list[Parameter]) -> None:
|
666
|
+
"""Set the parameters used in the underlying circuit.
|
667
|
+
|
668
|
+
Args:
|
669
|
+
The parameters to be used in the underlying circuit.
|
670
|
+
|
671
|
+
Raises:
|
672
|
+
ValueError: If the length of ordered parameters does not match the number of
|
673
|
+
parameters in the circuit and they are not a ``ParameterVector`` (which could
|
674
|
+
be resized to fit the number of parameters).
|
675
|
+
"""
|
676
|
+
if (
|
677
|
+
not isinstance(parameters, ParameterVector)
|
678
|
+
and len(parameters) != self.num_parameters_settable
|
679
|
+
):
|
680
|
+
raise ValueError(
|
681
|
+
"The length of ordered parameters must be equal to the number of "
|
682
|
+
f"settable parameters in the circuit ({self.num_parameters_settable}),"
|
683
|
+
f" but is {len(parameters)}"
|
684
|
+
)
|
685
|
+
self._ordered_parameters = parameters
|
686
|
+
self._invalidate()
|
687
|
+
|
688
|
+
@property
|
689
|
+
def insert_barriers(self) -> bool:
|
690
|
+
"""If barriers are inserted in between the layers or not.
|
691
|
+
|
692
|
+
Returns:
|
693
|
+
``True``, if barriers are inserted in between the layers, ``False`` if not.
|
694
|
+
"""
|
695
|
+
return self._insert_barriers
|
696
|
+
|
697
|
+
@insert_barriers.setter
|
698
|
+
def insert_barriers(self, insert_barriers: bool) -> None:
|
699
|
+
"""Specify whether barriers should be inserted in between the layers or not.
|
700
|
+
|
701
|
+
Args:
|
702
|
+
insert_barriers: If True, barriers are inserted, if False not.
|
703
|
+
"""
|
704
|
+
# if insert_barriers changes, we have to invalidate the circuit definition,
|
705
|
+
# if it is the same as before we can leave the NLocal instance as it is
|
706
|
+
if insert_barriers is not self._insert_barriers:
|
707
|
+
self._invalidate()
|
708
|
+
self._insert_barriers = insert_barriers
|
709
|
+
|
710
|
+
def get_unentangled_qubits(self) -> set[int]:
|
711
|
+
"""Get the indices of unentangled qubits in a set.
|
712
|
+
|
713
|
+
Returns:
|
714
|
+
The unentangled qubits.
|
715
|
+
"""
|
716
|
+
entangled_qubits = set()
|
717
|
+
for i in range(self._reps):
|
718
|
+
for j, block in enumerate(self.entanglement_blocks):
|
719
|
+
entangler_map = self.get_entangler_map(i, j, block.num_qubits)
|
720
|
+
entangled_qubits.update([idx for indices in entangler_map for idx in indices])
|
721
|
+
unentangled_qubits = set(range(self.num_qubits)) - entangled_qubits
|
722
|
+
|
723
|
+
return unentangled_qubits
|
724
|
+
|
725
|
+
@property
|
726
|
+
def num_parameters_settable(self) -> int:
|
727
|
+
"""The number of total parameters that can be set to distinct values.
|
728
|
+
|
729
|
+
This does not change when the parameters are bound or exchanged for same parameters,
|
730
|
+
and therefore is different from ``num_parameters`` which counts the number of unique
|
731
|
+
:class:`~qiskit.circuit.Parameter` objects currently in the circuit.
|
732
|
+
|
733
|
+
Returns:
|
734
|
+
The number of parameters originally available in the circuit.
|
735
|
+
|
736
|
+
Note:
|
737
|
+
This quantity does not require the circuit to be built yet.
|
738
|
+
"""
|
739
|
+
num = 0
|
740
|
+
|
741
|
+
for i in range(self._reps):
|
742
|
+
for j, block in enumerate(self.entanglement_blocks):
|
743
|
+
entangler_map = self.get_entangler_map(i, j, block.num_qubits)
|
744
|
+
num += len(entangler_map) * len(get_parameters(block))
|
745
|
+
|
746
|
+
if self._skip_unentangled_qubits:
|
747
|
+
unentangled_qubits = self.get_unentangled_qubits()
|
748
|
+
|
749
|
+
num_rot = 0
|
750
|
+
for block in self.rotation_blocks:
|
751
|
+
block_indices = [
|
752
|
+
list(range(j * block.num_qubits, (j + 1) * block.num_qubits))
|
753
|
+
for j in range(self.num_qubits // block.num_qubits)
|
754
|
+
]
|
755
|
+
if self._skip_unentangled_qubits:
|
756
|
+
block_indices = [
|
757
|
+
indices
|
758
|
+
for indices in block_indices
|
759
|
+
if set(indices).isdisjoint(unentangled_qubits)
|
760
|
+
]
|
761
|
+
num_rot += len(block_indices) * len(get_parameters(block))
|
762
|
+
|
763
|
+
num += num_rot * (self._reps + int(not self._skip_final_rotation_layer))
|
764
|
+
|
765
|
+
return num
|
766
|
+
|
767
|
+
@property
|
768
|
+
def reps(self) -> int:
|
769
|
+
"""The number of times rotation and entanglement block are repeated.
|
770
|
+
|
771
|
+
Returns:
|
772
|
+
The number of repetitions.
|
773
|
+
"""
|
774
|
+
return self._reps
|
775
|
+
|
776
|
+
@reps.setter
|
777
|
+
def reps(self, repetitions: int) -> None:
|
778
|
+
"""Set the repetitions.
|
779
|
+
|
780
|
+
If the repetitions are `0`, only one rotation layer with no entanglement
|
781
|
+
layers is applied (unless ``self.skip_final_rotation_layer`` is set to ``True``).
|
782
|
+
|
783
|
+
Args:
|
784
|
+
repetitions: The new repetitions.
|
785
|
+
|
786
|
+
Raises:
|
787
|
+
ValueError: If reps setter has parameter repetitions < 0.
|
788
|
+
"""
|
789
|
+
if repetitions < 0:
|
790
|
+
raise ValueError("The repetitions should be larger than or equal to 0")
|
791
|
+
if repetitions != self._reps:
|
792
|
+
self._invalidate()
|
793
|
+
self._reps = repetitions
|
794
|
+
|
795
|
+
def print_settings(self) -> str:
|
796
|
+
"""Returns information about the setting.
|
797
|
+
|
798
|
+
Returns:
|
799
|
+
The class name and the attributes/parameters of the instance as ``str``.
|
800
|
+
"""
|
801
|
+
ret = f"NLocal: {self.__class__.__name__}\n"
|
802
|
+
params = ""
|
803
|
+
for key, value in self.__dict__.items():
|
804
|
+
if key[0] == "_":
|
805
|
+
params += f"-- {key[1:]}: {value}\n"
|
806
|
+
ret += f"{params}"
|
807
|
+
return ret
|
808
|
+
|
809
|
+
@property
|
810
|
+
def preferred_init_points(self) -> list[float] | None:
|
811
|
+
"""The initial points for the parameters. Can be stored as initial guess in optimization.
|
812
|
+
|
813
|
+
Returns:
|
814
|
+
The initial values for the parameters, or None, if none have been set.
|
815
|
+
"""
|
816
|
+
return None
|
817
|
+
|
818
|
+
# pylint: disable=too-many-return-statements
|
819
|
+
def get_entangler_map(
|
820
|
+
self, rep_num: int, block_num: int, num_block_qubits: int
|
821
|
+
) -> Sequence[Sequence[int]]:
|
822
|
+
"""Get the entangler map for in the repetition ``rep_num`` and the block ``block_num``.
|
823
|
+
|
824
|
+
The entangler map for the current block is derived from the value of ``self.entanglement``.
|
825
|
+
Below the different cases are listed, where ``i`` and ``j`` denote the repetition number
|
826
|
+
and the block number, respectively, and ``n`` the number of qubits in the block.
|
827
|
+
|
828
|
+
=================================== ========================================================
|
829
|
+
entanglement type entangler map
|
830
|
+
=================================== ========================================================
|
831
|
+
``None`` ``[[0, ..., n - 1]]``
|
832
|
+
``str`` (e.g ``'full'``) the specified connectivity on ``n`` qubits
|
833
|
+
``List[int]`` [``entanglement``]
|
834
|
+
``List[List[int]]`` ``entanglement``
|
835
|
+
``List[List[List[int]]]`` ``entanglement[i]``
|
836
|
+
``List[List[List[List[int]]]]`` ``entanglement[i][j]``
|
837
|
+
``List[str]`` the connectivity specified in ``entanglement[i]``
|
838
|
+
``List[List[str]]`` the connectivity specified in ``entanglement[i][j]``
|
839
|
+
``Callable[int, str]`` same as ``List[str]``
|
840
|
+
``Callable[int, List[List[int]]]`` same as ``List[List[List[int]]]``
|
841
|
+
=================================== ========================================================
|
842
|
+
|
843
|
+
|
844
|
+
Note that all indices are to be taken modulo the length of the array they act on, i.e.
|
845
|
+
no out-of-bounds index error will be raised but we re-iterate from the beginning of the
|
846
|
+
list.
|
847
|
+
|
848
|
+
Args:
|
849
|
+
rep_num: The current repetition we are in.
|
850
|
+
block_num: The block number within the entanglement layers.
|
851
|
+
num_block_qubits: The number of qubits in the block.
|
852
|
+
|
853
|
+
Returns:
|
854
|
+
The entangler map for the current block in the current repetition.
|
855
|
+
|
856
|
+
Raises:
|
857
|
+
ValueError: If the value of ``entanglement`` could not be cast to a corresponding
|
858
|
+
entangler map.
|
859
|
+
"""
|
860
|
+
i, j, n = rep_num, block_num, num_block_qubits
|
861
|
+
entanglement = self._entanglement
|
862
|
+
|
863
|
+
# entanglement is None
|
864
|
+
if entanglement is None:
|
865
|
+
return [list(range(n))]
|
866
|
+
|
867
|
+
# entanglement is callable
|
868
|
+
if callable(entanglement):
|
869
|
+
entanglement = entanglement(i)
|
870
|
+
|
871
|
+
# entanglement is str
|
872
|
+
if isinstance(entanglement, str):
|
873
|
+
return get_entangler_map(n, self.num_qubits, entanglement, offset=i)
|
874
|
+
|
875
|
+
# check if entanglement is list of something
|
876
|
+
if not isinstance(entanglement, (tuple, list)):
|
877
|
+
raise ValueError(f"Invalid value of entanglement: {entanglement}")
|
878
|
+
num_i = len(entanglement)
|
879
|
+
|
880
|
+
# entanglement is List[str]
|
881
|
+
if all(isinstance(en, str) for en in entanglement):
|
882
|
+
return get_entangler_map(n, self.num_qubits, entanglement[i % num_i], offset=i)
|
883
|
+
|
884
|
+
# entanglement is List[int]
|
885
|
+
if all(isinstance(en, (int, numpy.integer)) for en in entanglement):
|
886
|
+
return [[int(en) for en in entanglement]]
|
887
|
+
|
888
|
+
# check if entanglement is List[List]
|
889
|
+
if not all(isinstance(en, (tuple, list)) for en in entanglement):
|
890
|
+
raise ValueError(f"Invalid value of entanglement: {entanglement}")
|
891
|
+
num_j = len(entanglement[i % num_i])
|
892
|
+
|
893
|
+
# entanglement is List[List[str]]
|
894
|
+
if all(isinstance(e2, str) for en in entanglement for e2 in en):
|
895
|
+
return get_entangler_map(
|
896
|
+
n, self.num_qubits, entanglement[i % num_i][j % num_j], offset=i
|
897
|
+
)
|
898
|
+
|
899
|
+
# entanglement is List[List[int]]
|
900
|
+
if all(isinstance(e2, (int, numpy.int32, numpy.int64)) for en in entanglement for e2 in en):
|
901
|
+
for ind, en in enumerate(entanglement):
|
902
|
+
entanglement[ind] = tuple(map(int, en))
|
903
|
+
return entanglement
|
904
|
+
|
905
|
+
# check if entanglement is List[List[List]]
|
906
|
+
if not all(isinstance(e2, (tuple, list)) for en in entanglement for e2 in en):
|
907
|
+
raise ValueError(f"Invalid value of entanglement: {entanglement}")
|
908
|
+
|
909
|
+
# entanglement is List[List[List[int]]]
|
910
|
+
if all(
|
911
|
+
isinstance(e3, (int, numpy.int32, numpy.int64))
|
912
|
+
for en in entanglement
|
913
|
+
for e2 in en
|
914
|
+
for e3 in e2
|
915
|
+
):
|
916
|
+
for en in entanglement:
|
917
|
+
for ind, e2 in enumerate(en):
|
918
|
+
en[ind] = tuple(map(int, e2))
|
919
|
+
return entanglement[i % num_i]
|
920
|
+
|
921
|
+
# check if entanglement is List[List[List[List]]]
|
922
|
+
if not all(isinstance(e3, (tuple, list)) for en in entanglement for e2 in en for e3 in e2):
|
923
|
+
raise ValueError(f"Invalid value of entanglement: {entanglement}")
|
924
|
+
|
925
|
+
# entanglement is List[List[List[List[int]]]]
|
926
|
+
if all(
|
927
|
+
isinstance(e4, (int, numpy.int32, numpy.int64))
|
928
|
+
for en in entanglement
|
929
|
+
for e2 in en
|
930
|
+
for e3 in e2
|
931
|
+
for e4 in e3
|
932
|
+
):
|
933
|
+
for en in entanglement:
|
934
|
+
for e2 in en:
|
935
|
+
for ind, e3 in enumerate(e2):
|
936
|
+
e2[ind] = tuple(map(int, e3))
|
937
|
+
return entanglement[i % num_i][j % num_j]
|
938
|
+
|
939
|
+
raise ValueError(f"Invalid value of entanglement: {entanglement}")
|
940
|
+
|
941
|
+
@property
|
942
|
+
def initial_state(self) -> QuantumCircuit:
|
943
|
+
"""Return the initial state that is added in front of the n-local circuit.
|
944
|
+
|
945
|
+
Returns:
|
946
|
+
The initial state.
|
947
|
+
"""
|
948
|
+
return self._initial_state
|
949
|
+
|
950
|
+
@initial_state.setter
|
951
|
+
def initial_state(self, initial_state: QuantumCircuit) -> None:
|
952
|
+
"""Set the initial state.
|
953
|
+
|
954
|
+
Args:
|
955
|
+
initial_state: The new initial state.
|
956
|
+
|
957
|
+
Raises:
|
958
|
+
ValueError: If the number of qubits has been set before and the initial state
|
959
|
+
does not match the number of qubits.
|
960
|
+
"""
|
961
|
+
self._initial_state = initial_state
|
962
|
+
self._invalidate()
|
963
|
+
|
964
|
+
@property
|
965
|
+
def parameter_bounds(self) -> list[tuple[float, float]] | None:
|
966
|
+
"""The parameter bounds for the unbound parameters in the circuit.
|
967
|
+
|
968
|
+
Returns:
|
969
|
+
A list of pairs indicating the bounds, as (lower, upper). None indicates an unbounded
|
970
|
+
parameter in the corresponding direction. If ``None`` is returned, problem is fully
|
971
|
+
unbounded.
|
972
|
+
"""
|
973
|
+
if not self._is_built:
|
974
|
+
self._build()
|
975
|
+
return self._bounds
|
976
|
+
|
977
|
+
@parameter_bounds.setter
|
978
|
+
def parameter_bounds(self, bounds: list[tuple[float, float]]) -> None:
|
979
|
+
"""Set the parameter bounds.
|
980
|
+
|
981
|
+
Args:
|
982
|
+
bounds: The new parameter bounds.
|
983
|
+
"""
|
984
|
+
self._bounds = bounds
|
985
|
+
|
986
|
+
def add_layer(
|
987
|
+
self,
|
988
|
+
other: QuantumCircuit | qiskit.circuit.Instruction,
|
989
|
+
entanglement: list[int] | str | list[list[int]] | None = None,
|
990
|
+
front: bool = False,
|
991
|
+
) -> "NLocal":
|
992
|
+
"""Append another layer to the NLocal.
|
993
|
+
|
994
|
+
Args:
|
995
|
+
other: The layer to compose, can be another NLocal, an Instruction or Gate,
|
996
|
+
or a QuantumCircuit.
|
997
|
+
entanglement: The entanglement or qubit indices.
|
998
|
+
front: If True, ``other`` is appended to the front, else to the back.
|
999
|
+
|
1000
|
+
Returns:
|
1001
|
+
self, such that chained composes are possible.
|
1002
|
+
|
1003
|
+
Raises:
|
1004
|
+
TypeError: If `other` is not compatible, i.e. is no Instruction and does not have a
|
1005
|
+
`to_instruction` method.
|
1006
|
+
"""
|
1007
|
+
block = self._convert_to_block(other)
|
1008
|
+
|
1009
|
+
if entanglement is None:
|
1010
|
+
entanglement = [list(range(block.num_qubits))]
|
1011
|
+
elif isinstance(entanglement, list) and not isinstance(entanglement[0], list):
|
1012
|
+
entanglement = [entanglement]
|
1013
|
+
if front:
|
1014
|
+
self._prepended_blocks += [block]
|
1015
|
+
self._prepended_entanglement += [entanglement]
|
1016
|
+
else:
|
1017
|
+
self._appended_blocks += [block]
|
1018
|
+
self._appended_entanglement += [entanglement]
|
1019
|
+
|
1020
|
+
if isinstance(entanglement, list):
|
1021
|
+
num_qubits = 1 + max(max(indices) for indices in entanglement)
|
1022
|
+
if num_qubits > self.num_qubits:
|
1023
|
+
self._invalidate() # rebuild circuit
|
1024
|
+
self.num_qubits = num_qubits
|
1025
|
+
|
1026
|
+
# modify the circuit accordingly
|
1027
|
+
if front is False and self._is_built:
|
1028
|
+
if self._insert_barriers and len(self.data) > 0:
|
1029
|
+
self.barrier()
|
1030
|
+
|
1031
|
+
if isinstance(entanglement, str):
|
1032
|
+
entangler_map: Sequence[Sequence[int]] = get_entangler_map(
|
1033
|
+
block.num_qubits, self.num_qubits, entanglement
|
1034
|
+
)
|
1035
|
+
else:
|
1036
|
+
entangler_map = entanglement
|
1037
|
+
|
1038
|
+
for i in entangler_map:
|
1039
|
+
params = self.ordered_parameters[-len(get_parameters(block)) :]
|
1040
|
+
parameterized_block = self._parameterize_block(block, params=params)
|
1041
|
+
self.compose(parameterized_block, i, inplace=True, copy=False)
|
1042
|
+
else:
|
1043
|
+
# cannot prepend a block currently, just rebuild
|
1044
|
+
self._invalidate()
|
1045
|
+
|
1046
|
+
return self
|
1047
|
+
|
1048
|
+
def assign_parameters(
|
1049
|
+
self,
|
1050
|
+
parameters: (
|
1051
|
+
Mapping[Parameter, ParameterExpression | float] | Sequence[ParameterExpression | float]
|
1052
|
+
),
|
1053
|
+
inplace: bool = False,
|
1054
|
+
**kwargs,
|
1055
|
+
) -> QuantumCircuit | None:
|
1056
|
+
"""Assign parameters to the n-local circuit.
|
1057
|
+
|
1058
|
+
This method also supports passing a list instead of a dictionary. If a list
|
1059
|
+
is passed, the list must have the same length as the number of unbound parameters in
|
1060
|
+
the circuit. The parameters are assigned in the order of the parameters in
|
1061
|
+
:meth:`ordered_parameters`.
|
1062
|
+
|
1063
|
+
Returns:
|
1064
|
+
A copy of the NLocal circuit with the specified parameters.
|
1065
|
+
|
1066
|
+
Raises:
|
1067
|
+
AttributeError: If the parameters are given as list and do not match the number
|
1068
|
+
of parameters.
|
1069
|
+
"""
|
1070
|
+
if parameters is None or len(parameters) == 0:
|
1071
|
+
return self
|
1072
|
+
|
1073
|
+
if not self._is_built:
|
1074
|
+
self._build()
|
1075
|
+
|
1076
|
+
return super().assign_parameters(parameters, inplace=inplace, **kwargs)
|
1077
|
+
|
1078
|
+
def _parameterize_block(
|
1079
|
+
self, block, param_iter=None, rep_num=None, block_num=None, indices=None, params=None
|
1080
|
+
):
|
1081
|
+
"""Convert ``block`` to a circuit of correct width and parameterized using the iterator."""
|
1082
|
+
if self._overwrite_block_parameters:
|
1083
|
+
# check if special parameters should be used
|
1084
|
+
# pylint: disable=assignment-from-none
|
1085
|
+
if params is None:
|
1086
|
+
params = self._parameter_generator(rep_num, block_num, indices)
|
1087
|
+
if params is None:
|
1088
|
+
params = [next(param_iter) for _ in range(len(get_parameters(block)))]
|
1089
|
+
|
1090
|
+
update = dict(zip(block.parameters, params))
|
1091
|
+
return block.assign_parameters(update)
|
1092
|
+
|
1093
|
+
return block.copy()
|
1094
|
+
|
1095
|
+
def _build_rotation_layer(self, circuit, param_iter, i):
|
1096
|
+
"""Build a rotation layer."""
|
1097
|
+
# if the unentangled qubits are skipped, compute the set of qubits that are not entangled
|
1098
|
+
if self._skip_unentangled_qubits:
|
1099
|
+
skipped_qubits = self.get_unentangled_qubits()
|
1100
|
+
else:
|
1101
|
+
skipped_qubits = set()
|
1102
|
+
|
1103
|
+
target_qubits = circuit.qubits
|
1104
|
+
|
1105
|
+
# iterate over all rotation blocks
|
1106
|
+
for j, block in enumerate(self.rotation_blocks):
|
1107
|
+
skipped_blocks = {qubit // block.num_qubits for qubit in skipped_qubits}
|
1108
|
+
if (
|
1109
|
+
self._allow_fast_path_parametrization
|
1110
|
+
and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
|
1111
|
+
):
|
1112
|
+
all_qubits = (
|
1113
|
+
tuple(target_qubits[k * block.num_qubits : (k + 1) * block.num_qubits])
|
1114
|
+
for k in range(self.num_qubits // block.num_qubits)
|
1115
|
+
if k not in skipped_blocks
|
1116
|
+
)
|
1117
|
+
for qubits in all_qubits:
|
1118
|
+
instr = CircuitInstruction(
|
1119
|
+
simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
|
1120
|
+
qubits,
|
1121
|
+
)
|
1122
|
+
circuit._append(instr)
|
1123
|
+
else:
|
1124
|
+
block_indices = [
|
1125
|
+
list(range(k * block.num_qubits, (k + 1) * block.num_qubits))
|
1126
|
+
for k in range(self.num_qubits // block.num_qubits)
|
1127
|
+
if k not in skipped_blocks
|
1128
|
+
]
|
1129
|
+
# apply the operations in the layer
|
1130
|
+
for indices in block_indices:
|
1131
|
+
parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
|
1132
|
+
circuit.compose(parameterized_block, indices, inplace=True, copy=False)
|
1133
|
+
|
1134
|
+
def _build_entanglement_layer(self, circuit, param_iter, i):
|
1135
|
+
"""Build an entanglement layer."""
|
1136
|
+
# iterate over all entanglement blocks
|
1137
|
+
target_qubits = circuit.qubits
|
1138
|
+
for j, block in enumerate(self.entanglement_blocks):
|
1139
|
+
entangler_map = self.get_entangler_map(i, j, block.num_qubits)
|
1140
|
+
if (
|
1141
|
+
self._allow_fast_path_parametrization
|
1142
|
+
and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
|
1143
|
+
):
|
1144
|
+
for indices in entangler_map:
|
1145
|
+
# It's actually nontrivially faster to use a listcomp and pass that to `tuple`
|
1146
|
+
# than to pass a generator expression directly.
|
1147
|
+
# pylint: disable=consider-using-generator
|
1148
|
+
instr = CircuitInstruction(
|
1149
|
+
simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
|
1150
|
+
tuple([target_qubits[i] for i in indices]),
|
1151
|
+
)
|
1152
|
+
circuit._append(instr)
|
1153
|
+
else:
|
1154
|
+
# apply the operations in the layer
|
1155
|
+
for indices in entangler_map:
|
1156
|
+
parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
|
1157
|
+
circuit.compose(parameterized_block, indices, inplace=True, copy=False)
|
1158
|
+
|
1159
|
+
def _build_additional_layers(self, circuit, which):
|
1160
|
+
if which == "appended":
|
1161
|
+
blocks = self._appended_blocks
|
1162
|
+
entanglements = self._appended_entanglement
|
1163
|
+
elif which == "prepended":
|
1164
|
+
blocks = reversed(self._prepended_blocks)
|
1165
|
+
entanglements = reversed(self._prepended_entanglement)
|
1166
|
+
else:
|
1167
|
+
raise ValueError("`which` must be either `appended` or `prepended`.")
|
1168
|
+
|
1169
|
+
for block, ent in zip(blocks, entanglements):
|
1170
|
+
if isinstance(ent, str):
|
1171
|
+
ent = get_entangler_map(block.num_qubits, self.num_qubits, ent)
|
1172
|
+
for indices in ent:
|
1173
|
+
circuit.compose(block, indices, inplace=True, copy=False)
|
1174
|
+
|
1175
|
+
def _build(self) -> None:
|
1176
|
+
"""If not already built, build the circuit."""
|
1177
|
+
if self._is_built:
|
1178
|
+
return
|
1179
|
+
|
1180
|
+
super()._build()
|
1181
|
+
|
1182
|
+
if self.num_qubits == 0:
|
1183
|
+
return
|
1184
|
+
|
1185
|
+
if not self._flatten:
|
1186
|
+
circuit = QuantumCircuit(*self.qregs, name=self.name)
|
1187
|
+
else:
|
1188
|
+
circuit = self
|
1189
|
+
|
1190
|
+
# use the initial state as starting circuit, if it is set
|
1191
|
+
if self.initial_state:
|
1192
|
+
circuit.compose(self.initial_state.copy(), inplace=True, copy=False)
|
1193
|
+
|
1194
|
+
param_iter = iter(self.ordered_parameters)
|
1195
|
+
|
1196
|
+
# build the prepended layers
|
1197
|
+
self._build_additional_layers(circuit, "prepended")
|
1198
|
+
|
1199
|
+
# main loop to build the entanglement and rotation layers
|
1200
|
+
for i in range(self.reps):
|
1201
|
+
# insert barrier if specified and there is a preceding layer
|
1202
|
+
if self._insert_barriers and (i > 0 or len(self._prepended_blocks) > 0):
|
1203
|
+
circuit.barrier()
|
1204
|
+
|
1205
|
+
# build the rotation layer
|
1206
|
+
self._build_rotation_layer(circuit, param_iter, i)
|
1207
|
+
|
1208
|
+
# barrier in between rotation and entanglement layer
|
1209
|
+
if self._insert_barriers and len(self._rotation_blocks) > 0:
|
1210
|
+
circuit.barrier()
|
1211
|
+
|
1212
|
+
# build the entanglement layer
|
1213
|
+
self._build_entanglement_layer(circuit, param_iter, i)
|
1214
|
+
|
1215
|
+
# add the final rotation layer
|
1216
|
+
if not self._skip_final_rotation_layer:
|
1217
|
+
if self.insert_barriers and self.reps > 0:
|
1218
|
+
circuit.barrier()
|
1219
|
+
self._build_rotation_layer(circuit, param_iter, self.reps)
|
1220
|
+
|
1221
|
+
# add the appended layers
|
1222
|
+
self._build_additional_layers(circuit, "appended")
|
1223
|
+
|
1224
|
+
# cast global phase to float if it has no free parameters
|
1225
|
+
if isinstance(circuit.global_phase, ParameterExpression):
|
1226
|
+
try:
|
1227
|
+
circuit.global_phase = float(circuit.global_phase)
|
1228
|
+
except TypeError:
|
1229
|
+
# expression contains free parameters
|
1230
|
+
pass
|
1231
|
+
|
1232
|
+
if not self._flatten:
|
1233
|
+
try:
|
1234
|
+
block = circuit.to_gate()
|
1235
|
+
except QiskitError:
|
1236
|
+
block = circuit.to_instruction()
|
1237
|
+
|
1238
|
+
self.append(block, self.qubits, copy=False)
|
1239
|
+
|
1240
|
+
# pylint: disable=unused-argument
|
1241
|
+
def _parameter_generator(self, rep: int, block: int, indices: list[int]) -> Parameter | None:
|
1242
|
+
"""If certain blocks should use certain parameters this method can be overridden."""
|
1243
|
+
return None
|
1244
|
+
|
1245
|
+
|
1246
|
+
def get_parameters(block: QuantumCircuit | Instruction) -> list[Parameter]:
|
1247
|
+
"""Return the list of Parameters objects inside a circuit or instruction.
|
1248
|
+
|
1249
|
+
This is required since, in a standard gate the parameters are not necessarily Parameter
|
1250
|
+
objects (e.g. U3Gate(0.1, 0.2, 0.3).params == [0.1, 0.2, 0.3]) and instructions and
|
1251
|
+
circuits do not have the same interface for parameters.
|
1252
|
+
"""
|
1253
|
+
if isinstance(block, QuantumCircuit):
|
1254
|
+
return list(block.parameters)
|
1255
|
+
else:
|
1256
|
+
return [p for p in block.params if isinstance(p, ParameterExpression)]
|
1257
|
+
|
1258
|
+
|
1259
|
+
def get_entangler_map(
|
1260
|
+
num_block_qubits: int, num_circuit_qubits: int, entanglement: str, offset: int = 0
|
1261
|
+
) -> Sequence[tuple[int, ...]]:
|
1262
|
+
"""Get an entangler map for an arbitrary number of qubits.
|
1263
|
+
|
1264
|
+
Args:
|
1265
|
+
num_block_qubits: The number of qubits of the entangling block.
|
1266
|
+
num_circuit_qubits: The number of qubits of the circuit.
|
1267
|
+
entanglement: The entanglement strategy.
|
1268
|
+
offset: The block offset, can be used if the entanglements differ per block.
|
1269
|
+
See mode ``sca`` for instance.
|
1270
|
+
|
1271
|
+
Returns:
|
1272
|
+
The entangler map using mode ``entanglement`` to scatter a block of ``num_block_qubits``
|
1273
|
+
qubits on ``num_circuit_qubits`` qubits.
|
1274
|
+
|
1275
|
+
Raises:
|
1276
|
+
ValueError: If the entanglement mode ist not supported.
|
1277
|
+
"""
|
1278
|
+
try:
|
1279
|
+
return fast_entangler_map(num_circuit_qubits, num_block_qubits, entanglement, offset)
|
1280
|
+
except Exception as exc:
|
1281
|
+
# need this as Rust is now raising a QiskitError, where this function was raising ValueError
|
1282
|
+
raise ValueError("Something went wrong in Rust space, here's the error:") from exc
|
1283
|
+
|
1284
|
+
|
1285
|
+
_StdlibGateResult = collections.namedtuple("_StdlibGateResult", ("gate", "num_params"))
|
1286
|
+
_STANDARD_GATE_MAPPING = get_standard_gate_name_mapping()
|
1287
|
+
|
1288
|
+
|
1289
|
+
def _stdlib_gate_from_simple_block(block: QuantumCircuit) -> _StdlibGateResult | None:
|
1290
|
+
if block.global_phase != 0.0 or len(block) != 1:
|
1291
|
+
return None
|
1292
|
+
instruction = block.data[0]
|
1293
|
+
# If the single instruction isn't a standard-library gate that spans the full width of the block
|
1294
|
+
# in the correct order, we're not simple. If the gate isn't fully parametrized with pure,
|
1295
|
+
# unique `Parameter` instances (expressions are too complex) that are in order, we're not
|
1296
|
+
# simple.
|
1297
|
+
if (
|
1298
|
+
instruction.clbits
|
1299
|
+
or tuple(instruction.qubits) != tuple(block.qubits)
|
1300
|
+
or (
|
1301
|
+
getattr(_STANDARD_GATE_MAPPING.get(instruction.operation.name), "base_class", None)
|
1302
|
+
is not instruction.operation.base_class
|
1303
|
+
)
|
1304
|
+
or tuple(instruction.operation.params) != tuple(block.parameters)
|
1305
|
+
):
|
1306
|
+
return None
|
1307
|
+
return _StdlibGateResult(instruction.operation.base_class, len(instruction.operation.params))
|
1308
|
+
|
1309
|
+
|
1310
|
+
def _normalize_entanglement(
|
1311
|
+
entanglement: (
|
1312
|
+
BlockEntanglement
|
1313
|
+
| Iterable[BlockEntanglement]
|
1314
|
+
| Callable[[int], BlockEntanglement | Iterable[BlockEntanglement]]
|
1315
|
+
),
|
1316
|
+
num_entanglement_blocks: int,
|
1317
|
+
) -> list[str | list[tuple[int]]] | Callable[[int], list[str | list[tuple[int]]]]:
|
1318
|
+
"""If the entanglement is Iterable[Iterable], normalize to list[tuple]."""
|
1319
|
+
if isinstance(entanglement, str):
|
1320
|
+
return [entanglement] * num_entanglement_blocks
|
1321
|
+
|
1322
|
+
if callable(entanglement):
|
1323
|
+
return lambda offset: _normalize_entanglement(entanglement(offset), num_entanglement_blocks)
|
1324
|
+
|
1325
|
+
# here, entanglement is an Iterable
|
1326
|
+
if len(entanglement) == 0:
|
1327
|
+
# handle edge cases when entanglement is set to an empty list
|
1328
|
+
return [[]]
|
1329
|
+
|
1330
|
+
# if the entanglement is Iterable[Iterable[int]], normalize to Iterable[Iterable[Iterable[int]]]
|
1331
|
+
try:
|
1332
|
+
# if users e.g. gave Iterable[int] this in invalid and will raise a TypeError
|
1333
|
+
if isinstance(entanglement[0][0], (int, numpy.integer)):
|
1334
|
+
entanglement = [entanglement]
|
1335
|
+
except TypeError as exc:
|
1336
|
+
raise TypeError(f"Invalid entanglement type: {entanglement}.") from exc
|
1337
|
+
|
1338
|
+
# ensure the number of block entanglements matches the number of blocks
|
1339
|
+
if len(entanglement) != num_entanglement_blocks:
|
1340
|
+
raise QiskitError(
|
1341
|
+
f"Number of block-entanglements ({len(entanglement)}) must match number of "
|
1342
|
+
f"entanglement blocks ({num_entanglement_blocks})!"
|
1343
|
+
)
|
1344
|
+
|
1345
|
+
# normalize the data: str remains, and Iterable[Iterable[int]] becomes list[tuple[int]]
|
1346
|
+
normalized = []
|
1347
|
+
for block in entanglement:
|
1348
|
+
if isinstance(block, str):
|
1349
|
+
normalized.append(block)
|
1350
|
+
else:
|
1351
|
+
normalized.append([tuple(connections) for connections in block])
|
1352
|
+
|
1353
|
+
return normalized
|
1354
|
+
|
1355
|
+
|
1356
|
+
def _normalize_blocks(
|
1357
|
+
blocks: str | Gate | Iterable[str | Gate],
|
1358
|
+
supported_gates: dict[str, Gate],
|
1359
|
+
overwrite_block_parameters: bool,
|
1360
|
+
) -> list[Block]:
|
1361
|
+
# normalize the input into an iterable -- we add an extra check for a circuit as
|
1362
|
+
# courtesy to the users, since the NLocal class used to accept circuits
|
1363
|
+
if isinstance(blocks, (str, Gate, QuantumCircuit)):
|
1364
|
+
blocks = [blocks]
|
1365
|
+
|
1366
|
+
normalized = []
|
1367
|
+
for block in blocks:
|
1368
|
+
# since the NLocal circuit accepted circuits as inputs, we raise a warning here
|
1369
|
+
# to simplify the transition (even though, strictly speaking, quantum circuits are
|
1370
|
+
# not a supported input type)
|
1371
|
+
if isinstance(block, QuantumCircuit):
|
1372
|
+
raise ValueError(
|
1373
|
+
"The blocks should be of type Gate or str, but you passed a QuantumCircuit. "
|
1374
|
+
"You can call .to_gate() on the circuit to turn it into a Gate object."
|
1375
|
+
)
|
1376
|
+
|
1377
|
+
is_standard = False
|
1378
|
+
if isinstance(block, str):
|
1379
|
+
if block not in supported_gates:
|
1380
|
+
raise ValueError(f"Unsupported gate: {block}")
|
1381
|
+
block = supported_gates[block]
|
1382
|
+
is_standard = True
|
1383
|
+
elif isinstance(block, Gate) and getattr(block, "_standard_gate", None) is not None:
|
1384
|
+
if len(block.params) == 0:
|
1385
|
+
is_standard = True
|
1386
|
+
# the fast path will always overwrite block parameters
|
1387
|
+
elif overwrite_block_parameters:
|
1388
|
+
# if all parameters are plain Parameter objects, this is a plain
|
1389
|
+
# standard gate we do not need to propagate parameterizations for
|
1390
|
+
is_standard = all(isinstance(p, Parameter) for p in block.params)
|
1391
|
+
|
1392
|
+
if is_standard:
|
1393
|
+
block = Block.from_standard_gate(block._standard_gate)
|
1394
|
+
else:
|
1395
|
+
if overwrite_block_parameters:
|
1396
|
+
num_parameters, builder = _get_gate_builder(block)
|
1397
|
+
else:
|
1398
|
+
num_parameters, builder = _trivial_builder(block)
|
1399
|
+
|
1400
|
+
block = Block.from_callable(block.num_qubits, num_parameters, builder)
|
1401
|
+
|
1402
|
+
normalized.append(block)
|
1403
|
+
|
1404
|
+
return normalized
|
1405
|
+
|
1406
|
+
|
1407
|
+
def _trivial_builder(
|
1408
|
+
gate: Gate,
|
1409
|
+
) -> tuple[int, Callable[list[Parameter], tuple[Gate, list[ParameterValueType]]]]:
|
1410
|
+
|
1411
|
+
def builder(_):
|
1412
|
+
copied = gate.copy()
|
1413
|
+
return copied, copied.params
|
1414
|
+
|
1415
|
+
return 0, builder
|
1416
|
+
|
1417
|
+
|
1418
|
+
def _get_gate_builder(
|
1419
|
+
gate: Gate,
|
1420
|
+
) -> tuple[int, Callable[list[Parameter], tuple[Gate, list[ParameterValueType]]]]:
|
1421
|
+
"""Construct a callable that handles parameter-rebinding.
|
1422
|
+
|
1423
|
+
For a given gate, this return the number of free parameters and a callable that can be
|
1424
|
+
used to obtain a re-parameterized version of the gate. For example::
|
1425
|
+
|
1426
|
+
x, y = Parameter("x"), Parameter("y")
|
1427
|
+
gate = CUGate(x, 2 * y, 0.5, 0.)
|
1428
|
+
|
1429
|
+
num_parameters, builder = _build_gate(gate)
|
1430
|
+
print(num_parameters) # prints 2
|
1431
|
+
|
1432
|
+
a, b = Parameter("a"), Parameter("b")
|
1433
|
+
new_gate, new_params = builder([a, b])
|
1434
|
+
print(new_gate) # CUGate(a, 2 * b, 0.5, 0)
|
1435
|
+
print(new_params) # [a, 2 * b, 0.5, 0]
|
1436
|
+
|
1437
|
+
"""
|
1438
|
+
free_parameters = set()
|
1439
|
+
for p in gate.params:
|
1440
|
+
if isinstance(p, ParameterExpression):
|
1441
|
+
free_parameters |= set(p.parameters)
|
1442
|
+
|
1443
|
+
num_parameters = len(free_parameters)
|
1444
|
+
|
1445
|
+
sorted_parameters = _sort_parameters(free_parameters)
|
1446
|
+
|
1447
|
+
def builder(new_parameters):
|
1448
|
+
out = gate.copy()
|
1449
|
+
|
1450
|
+
# re-bind the ``Gate.params`` attribute
|
1451
|
+
param_dict = dict(zip(sorted_parameters, new_parameters))
|
1452
|
+
bound_params = gate.params.copy()
|
1453
|
+
for i, expr in enumerate(gate.params):
|
1454
|
+
if isinstance(expr, ParameterExpression):
|
1455
|
+
for parameter in expr.parameters:
|
1456
|
+
expr = expr.assign(parameter, param_dict[parameter])
|
1457
|
+
bound_params[i] = expr
|
1458
|
+
|
1459
|
+
out.params = bound_params
|
1460
|
+
|
1461
|
+
# if the definition exists, rebind it
|
1462
|
+
if out._definition is not None:
|
1463
|
+
out._definition.assign_parameters(param_dict, inplace=True)
|
1464
|
+
|
1465
|
+
return out, bound_params
|
1466
|
+
|
1467
|
+
return num_parameters, builder
|
1468
|
+
|
1469
|
+
|
1470
|
+
def _sort_parameters(parameters):
|
1471
|
+
"""Sort a list of Parameter objects."""
|
1472
|
+
|
1473
|
+
def key(parameter):
|
1474
|
+
if isinstance(parameter, ParameterVectorElement):
|
1475
|
+
return (parameter.vector.name, parameter.index)
|
1476
|
+
return (parameter.name,)
|
1477
|
+
|
1478
|
+
return sorted(parameters, key=key)
|