qiskit 2.0.3__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 +141 -0
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/circuit/__init__.py +1343 -0
- qiskit/circuit/_add_control.py +312 -0
- qiskit/circuit/_classical_resource_map.py +150 -0
- qiskit/circuit/_standard_gates_commutations.py +3849 -0
- qiskit/circuit/_utils.py +167 -0
- qiskit/circuit/annotated_operation.py +279 -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 +498 -0
- qiskit/circuit/classical/expr/visitors.py +375 -0
- qiskit/circuit/classical/types/__init__.py +113 -0
- qiskit/circuit/classical/types/ordering.py +229 -0
- qiskit/circuit/classical/types/types.py +153 -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 +163 -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 +157 -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 +502 -0
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +387 -0
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +493 -0
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +389 -0
- qiskit/circuit/library/arithmetic/quadratic_form.py +364 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +409 -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 +316 -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 +159 -0
- qiskit/circuit/library/generalized_gates/gms.py +175 -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 +198 -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 +217 -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 +303 -0
- qiskit/circuit/library/n_local/n_local.py +1477 -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 +201 -0
- qiskit/circuit/library/phase_estimation.py +177 -0
- qiskit/circuit/library/phase_oracle.py +239 -0
- qiskit/circuit/library/quantum_volume.py +180 -0
- qiskit/circuit/library/standard_gates/__init__.py +141 -0
- qiskit/circuit/library/standard_gates/dcx.py +77 -0
- qiskit/circuit/library/standard_gates/ecr.py +129 -0
- qiskit/circuit/library/standard_gates/equivalence_library.py +1800 -0
- qiskit/circuit/library/standard_gates/global_phase.py +84 -0
- qiskit/circuit/library/standard_gates/h.py +253 -0
- qiskit/circuit/library/standard_gates/i.py +76 -0
- qiskit/circuit/library/standard_gates/iswap.py +133 -0
- qiskit/circuit/library/standard_gates/p.py +422 -0
- qiskit/circuit/library/standard_gates/r.py +114 -0
- qiskit/circuit/library/standard_gates/rx.py +293 -0
- qiskit/circuit/library/standard_gates/rxx.py +180 -0
- qiskit/circuit/library/standard_gates/ry.py +286 -0
- qiskit/circuit/library/standard_gates/ryy.py +180 -0
- qiskit/circuit/library/standard_gates/rz.py +307 -0
- qiskit/circuit/library/standard_gates/rzx.py +226 -0
- qiskit/circuit/library/standard_gates/rzz.py +193 -0
- qiskit/circuit/library/standard_gates/s.py +419 -0
- qiskit/circuit/library/standard_gates/swap.py +281 -0
- qiskit/circuit/library/standard_gates/sx.py +310 -0
- qiskit/circuit/library/standard_gates/t.py +178 -0
- qiskit/circuit/library/standard_gates/u.py +395 -0
- qiskit/circuit/library/standard_gates/u1.py +490 -0
- qiskit/circuit/library/standard_gates/u2.py +145 -0
- qiskit/circuit/library/standard_gates/u3.py +428 -0
- qiskit/circuit/library/standard_gates/x.py +1481 -0
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +202 -0
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +236 -0
- qiskit/circuit/library/standard_gates/y.py +257 -0
- qiskit/circuit/library/standard_gates/z.py +338 -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 +179 -0
- qiskit/circuit/parameterexpression.py +703 -0
- qiskit/circuit/parametertable.py +119 -0
- qiskit/circuit/parametervector.py +140 -0
- qiskit/circuit/quantumcircuit.py +7540 -0
- qiskit/circuit/quantumcircuitdata.py +136 -0
- qiskit/circuit/random/__init__.py +15 -0
- qiskit/circuit/random/utils.py +366 -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 +193 -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 +55 -0
- qiskit/dagcircuit/collect_blocks.py +407 -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 +188 -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 +175 -0
- qiskit/primitives/containers/estimator_pub.py +222 -0
- qiskit/primitives/containers/object_array.py +94 -0
- qiskit/primitives/containers/observables_array.py +296 -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 +81 -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 +374 -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 +372 -0
- qiskit/qasm3/ast.py +782 -0
- qiskit/qasm3/exceptions.py +27 -0
- qiskit/qasm3/experimental.py +70 -0
- qiskit/qasm3/exporter.py +1340 -0
- qiskit/qasm3/printer.py +608 -0
- qiskit/qpy/__init__.py +1965 -0
- qiskit/qpy/binary_io/__init__.py +35 -0
- qiskit/qpy/binary_io/circuits.py +1455 -0
- qiskit/qpy/binary_io/parse_sympy_repr.py +121 -0
- qiskit/qpy/binary_io/schedules.py +308 -0
- qiskit/qpy/binary_io/value.py +1165 -0
- qiskit/qpy/common.py +353 -0
- qiskit/qpy/exceptions.py +53 -0
- qiskit/qpy/formats.py +442 -0
- qiskit/qpy/interface.py +344 -0
- qiskit/qpy/type_keys.py +409 -0
- qiskit/quantum_info/__init__.py +162 -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 +28 -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 +23 -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 +558 -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 +74 -0
- qiskit/result/utils.py +294 -0
- qiskit/synthesis/__init__.py +240 -0
- qiskit/synthesis/arithmetic/__init__.py +18 -0
- qiskit/synthesis/arithmetic/adders/__init__.py +17 -0
- qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +154 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +103 -0
- qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +161 -0
- qiskit/synthesis/arithmetic/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/commutator_decompose.py +265 -0
- qiskit/synthesis/discrete_basis/gate_sequence.py +421 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +165 -0
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +240 -0
- qiskit/synthesis/evolution/__init__.py +21 -0
- qiskit/synthesis/evolution/evolution_synthesis.py +48 -0
- qiskit/synthesis/evolution/lie_trotter.py +120 -0
- qiskit/synthesis/evolution/matrix_synthesis.py +47 -0
- qiskit/synthesis/evolution/pauli_network.py +80 -0
- qiskit/synthesis/evolution/product_formula.py +313 -0
- qiskit/synthesis/evolution/qdrift.py +130 -0
- qiskit/synthesis/evolution/suzuki_trotter.py +224 -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 +25 -0
- qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +359 -0
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -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 +79 -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 +288 -0
- qiskit/transpiler/__init__.py +1345 -0
- qiskit/transpiler/basepasses.py +190 -0
- qiskit/transpiler/coupling.py +500 -0
- qiskit/transpiler/exceptions.py +59 -0
- qiskit/transpiler/instruction_durations.py +281 -0
- qiskit/transpiler/layout.py +740 -0
- qiskit/transpiler/passes/__init__.py +276 -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 +177 -0
- qiskit/transpiler/passes/layout/disjoint_utils.py +219 -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 +506 -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 +256 -0
- qiskit/transpiler/passes/layout/vf2_post_layout.py +376 -0
- qiskit/transpiler/passes/layout/vf2_utils.py +235 -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 +250 -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_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 +639 -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 +463 -0
- qiskit/transpiler/passes/routing/star_prerouting.py +408 -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 +16 -0
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +284 -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 +20 -0
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +153 -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 +1963 -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 +313 -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 +151 -0
- qiskit/transpiler/preset_passmanagers/__init__.py +93 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +993 -0
- qiskit/transpiler/preset_passmanagers/common.py +672 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +437 -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 +354 -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 +675 -0
- qiskit/visualization/circuit/circuit_visualization.py +735 -0
- qiskit/visualization/circuit/latex.py +661 -0
- qiskit/visualization/circuit/matplotlib.py +2019 -0
- qiskit/visualization/circuit/qcstyle.py +278 -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_visualization.py +318 -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/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.0.3.dist-info/METADATA +220 -0
- qiskit-2.0.3.dist-info/RECORD +690 -0
- qiskit-2.0.3.dist-info/WHEEL +6 -0
- qiskit-2.0.3.dist-info/entry_points.txt +82 -0
- qiskit-2.0.3.dist-info/licenses/LICENSE.txt +203 -0
- qiskit-2.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1032 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2017--2023
|
4
|
+
#
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
+
#
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
11
|
+
# that they have been altered from the originals.
|
12
|
+
"""
|
13
|
+
Clifford operator class.
|
14
|
+
"""
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import functools
|
18
|
+
import itertools
|
19
|
+
import math
|
20
|
+
import re
|
21
|
+
from typing import Literal
|
22
|
+
|
23
|
+
import numpy as np
|
24
|
+
|
25
|
+
from qiskit.circuit import Instruction, QuantumCircuit
|
26
|
+
from qiskit.circuit.library.standard_gates import HGate, IGate, SGate, XGate, YGate, ZGate
|
27
|
+
from qiskit.circuit.operation import Operation
|
28
|
+
from qiskit.exceptions import QiskitError
|
29
|
+
from qiskit.quantum_info.operators.base_operator import BaseOperator
|
30
|
+
from qiskit.quantum_info.operators.mixins import AdjointMixin, generate_apidocs
|
31
|
+
from qiskit.quantum_info.operators.operator import Operator
|
32
|
+
from qiskit.quantum_info.operators.scalar_op import ScalarOp
|
33
|
+
from qiskit.quantum_info.operators.symplectic.base_pauli import _count_y
|
34
|
+
|
35
|
+
from .base_pauli import BasePauli
|
36
|
+
from .clifford_circuits import _append_circuit, _append_operation
|
37
|
+
|
38
|
+
|
39
|
+
class Clifford(BaseOperator, AdjointMixin, Operation):
|
40
|
+
r"""
|
41
|
+
An N-qubit unitary operator from the Clifford group.
|
42
|
+
|
43
|
+
An N-qubit Clifford operator takes Paulis to Paulis via conjugation
|
44
|
+
(up to a global phase). More precisely, the Clifford group :math:`\mathcal{C}_N`
|
45
|
+
is defined as
|
46
|
+
|
47
|
+
.. math::
|
48
|
+
|
49
|
+
\mathcal{C}_N = \{ U \in U(2^N) | U \mathcal{P}_N U^{\dagger} = \mathcal{P}_N \} / U(1)
|
50
|
+
|
51
|
+
where :math:`\mathcal{P}_N` is the Pauli group on :math:`N` qubits
|
52
|
+
that is generated by single-qubit Pauli operators,
|
53
|
+
and :math:`U` is a unitary operator in the unitary group
|
54
|
+
:math:`U(2^N)` representing operations on :math:`N` qubits.
|
55
|
+
:math:`\mathcal{C}_N` is the quotient group by the subgroup of
|
56
|
+
scalar unitary matrices :math:`U(1)`.
|
57
|
+
|
58
|
+
**Representation**
|
59
|
+
|
60
|
+
An *N*-qubit Clifford operator is stored as a length *2N × (2N+1)*
|
61
|
+
boolean tableau using the convention from reference [1].
|
62
|
+
|
63
|
+
* Rows 0 to *N-1* are the *destabilizer* group generators
|
64
|
+
* Rows *N* to *2N-1* are the *stabilizer* group generators.
|
65
|
+
|
66
|
+
The internal boolean tableau for the Clifford
|
67
|
+
can be accessed using the :attr:`tableau` attribute. The destabilizer or
|
68
|
+
stabilizer rows can each be accessed as a length-N Stabilizer table using
|
69
|
+
:attr:`destab` and :attr:`stab` attributes.
|
70
|
+
|
71
|
+
A more easily human readable representation of the Clifford operator can
|
72
|
+
be obtained by calling the :meth:`to_dict` method. This representation is
|
73
|
+
also used if a Clifford object is printed as in the following example
|
74
|
+
|
75
|
+
.. plot::
|
76
|
+
:include-source:
|
77
|
+
:nofigs:
|
78
|
+
|
79
|
+
from qiskit import QuantumCircuit
|
80
|
+
from qiskit.quantum_info import Clifford
|
81
|
+
|
82
|
+
# Bell state generation circuit
|
83
|
+
qc = QuantumCircuit(2)
|
84
|
+
qc.h(0)
|
85
|
+
qc.cx(0, 1)
|
86
|
+
cliff = Clifford(qc)
|
87
|
+
|
88
|
+
# Print the Clifford
|
89
|
+
print(cliff)
|
90
|
+
|
91
|
+
# Print the Clifford destabilizer rows
|
92
|
+
print(cliff.to_labels(mode="D"))
|
93
|
+
|
94
|
+
# Print the Clifford stabilizer rows
|
95
|
+
print(cliff.to_labels(mode="S"))
|
96
|
+
|
97
|
+
.. code-block:: text
|
98
|
+
|
99
|
+
Clifford: Stabilizer = ['+XX', '+ZZ'], Destabilizer = ['+IZ', '+XI']
|
100
|
+
['+IZ', '+XI']
|
101
|
+
['+XX', '+ZZ']
|
102
|
+
|
103
|
+
**Circuit Conversion**
|
104
|
+
|
105
|
+
Clifford operators can be initialized from circuits containing *only* the
|
106
|
+
following Clifford gates: :class:`~qiskit.circuit.library.IGate`,
|
107
|
+
:class:`~qiskit.circuit.library.XGate`, :class:`~qiskit.circuit.library.YGate`,
|
108
|
+
:class:`~qiskit.circuit.library.ZGate`, :class:`~qiskit.circuit.library.HGate`,
|
109
|
+
:class:`~qiskit.circuit.library.SGate`, :class:`~qiskit.circuit.library.SdgGate`,
|
110
|
+
:class:`~qiskit.circuit.library.SXGate`, :class:`~qiskit.circuit.library.SXdgGate`,
|
111
|
+
:class:`~qiskit.circuit.library.CXGate`, :class:`~qiskit.circuit.library.CZGate`,
|
112
|
+
:class:`~qiskit.circuit.library.CYGate`, :class:`~qiskit.circuit.library.DCXGate`,
|
113
|
+
:class:`~qiskit.circuit.library.SwapGate`, :class:`~qiskit.circuit.library.iSwapGate`,
|
114
|
+
:class:`~qiskit.circuit.library.ECRGate`, :class:`~qiskit.circuit.library.LinearFunction`,
|
115
|
+
:class:`~qiskit.circuit.library.PermutationGate`.
|
116
|
+
They can be converted back into a :class:`~qiskit.circuit.QuantumCircuit`,
|
117
|
+
or :class:`~qiskit.circuit.Gate` object using the :meth:`~Clifford.to_circuit`
|
118
|
+
or :meth:`~Clifford.to_instruction` methods respectively. Note that this
|
119
|
+
decomposition is not necessarily optimal in terms of number of gates.
|
120
|
+
|
121
|
+
.. note::
|
122
|
+
|
123
|
+
A minimally generating set of gates for Clifford circuits is
|
124
|
+
the :class:`~qiskit.circuit.library.HGate` and
|
125
|
+
:class:`~qiskit.circuit.library.SGate` gate and *either* the
|
126
|
+
:class:`~qiskit.circuit.library.CXGate` or
|
127
|
+
:class:`~qiskit.circuit.library.CZGate` two-qubit gate.
|
128
|
+
|
129
|
+
Clifford operators can also be converted to
|
130
|
+
:class:`~qiskit.quantum_info.Operator` objects using the
|
131
|
+
:meth:`to_operator` method. This is done via decomposing to a circuit, and then
|
132
|
+
simulating the circuit as a unitary operator.
|
133
|
+
|
134
|
+
References:
|
135
|
+
1. S. Aaronson, D. Gottesman, *Improved Simulation of Stabilizer Circuits*,
|
136
|
+
Phys. Rev. A 70, 052328 (2004).
|
137
|
+
`arXiv:quant-ph/0406196 <https://arxiv.org/abs/quant-ph/0406196>`_
|
138
|
+
"""
|
139
|
+
|
140
|
+
_COMPOSE_PHASE_LOOKUP = None
|
141
|
+
_COMPOSE_1Q_LOOKUP = None
|
142
|
+
|
143
|
+
def __array__(self, dtype=None, copy=None):
|
144
|
+
if copy is False:
|
145
|
+
raise ValueError("unable to avoid copy while creating an array as requested")
|
146
|
+
arr = self.to_matrix()
|
147
|
+
return arr if dtype is None else arr.astype(dtype, copy=False)
|
148
|
+
|
149
|
+
def __init__(self, data, validate=True, copy=True):
|
150
|
+
"""Initialize an operator object."""
|
151
|
+
|
152
|
+
# pylint: disable=cyclic-import
|
153
|
+
from qiskit.circuit.library import LinearFunction, PermutationGate
|
154
|
+
|
155
|
+
# Initialize from another Clifford
|
156
|
+
if isinstance(data, Clifford):
|
157
|
+
num_qubits = data.num_qubits
|
158
|
+
self.tableau = data.tableau.copy() if copy else data.tableau
|
159
|
+
|
160
|
+
# Initialize from ScalarOp as N-qubit identity discarding any global phase
|
161
|
+
elif isinstance(data, ScalarOp):
|
162
|
+
if not data.num_qubits or not data.is_unitary():
|
163
|
+
raise QiskitError("Can only initialize from N-qubit identity ScalarOp.")
|
164
|
+
num_qubits = data.num_qubits
|
165
|
+
self.tableau = np.fromfunction(
|
166
|
+
lambda i, j: i == j, (2 * num_qubits, 2 * num_qubits + 1)
|
167
|
+
).astype(bool)
|
168
|
+
|
169
|
+
# Initialize from LinearFunction
|
170
|
+
elif isinstance(data, LinearFunction):
|
171
|
+
num_qubits = len(data.linear)
|
172
|
+
self.tableau = self.from_linear_function(data)
|
173
|
+
|
174
|
+
# Initialize from PermutationGate
|
175
|
+
elif isinstance(data, PermutationGate):
|
176
|
+
num_qubits = len(data.pattern)
|
177
|
+
self.tableau = self.from_permutation(data)
|
178
|
+
|
179
|
+
# Initialize from a QuantumCircuit or Instruction object
|
180
|
+
elif isinstance(data, (QuantumCircuit, Instruction)):
|
181
|
+
num_qubits = data.num_qubits
|
182
|
+
self.tableau = Clifford.from_circuit(data).tableau
|
183
|
+
|
184
|
+
# Initialize StabilizerTable directly from the data
|
185
|
+
else:
|
186
|
+
if (
|
187
|
+
isinstance(data, (list, np.ndarray))
|
188
|
+
and (data_asarray := np.asarray(data, dtype=bool)).ndim == 2
|
189
|
+
):
|
190
|
+
# This little dance is to avoid Numpy 1/2 incompatibilities between the availability
|
191
|
+
# and meaning of the 'copy' argument in 'array' and 'asarray', when the input needs
|
192
|
+
# its dtype converting. 'asarray' prefers to return 'self' if possible in both.
|
193
|
+
if copy and np.may_share_memory(data, data_asarray):
|
194
|
+
data = data_asarray.copy()
|
195
|
+
else:
|
196
|
+
data = data_asarray
|
197
|
+
if data.shape[0] == data.shape[1]:
|
198
|
+
self.tableau = self._stack_table_phase(
|
199
|
+
data, np.zeros(data.shape[0], dtype=bool)
|
200
|
+
)
|
201
|
+
num_qubits = data.shape[0] // 2
|
202
|
+
elif data.shape[0] + 1 == data.shape[1]:
|
203
|
+
self.tableau = data
|
204
|
+
num_qubits = data.shape[0] // 2
|
205
|
+
else:
|
206
|
+
raise QiskitError("")
|
207
|
+
else:
|
208
|
+
n_paulis = len(data)
|
209
|
+
symp = self._from_label(data[0])
|
210
|
+
num_qubits = len(symp) // 2
|
211
|
+
tableau = np.zeros((n_paulis, len(symp)), dtype=bool)
|
212
|
+
tableau[0] = symp
|
213
|
+
for i in range(1, n_paulis):
|
214
|
+
tableau[i] = self._from_label(data[i])
|
215
|
+
self.tableau = tableau
|
216
|
+
|
217
|
+
# Validate table is a symplectic matrix
|
218
|
+
if validate and not Clifford._is_symplectic(self.symplectic_matrix):
|
219
|
+
raise QiskitError(
|
220
|
+
"Invalid Clifford. Input StabilizerTable is not a valid symplectic matrix."
|
221
|
+
)
|
222
|
+
|
223
|
+
# Initialize BaseOperator
|
224
|
+
super().__init__(num_qubits=num_qubits)
|
225
|
+
|
226
|
+
@property
|
227
|
+
def name(self):
|
228
|
+
"""Unique string identifier for operation type."""
|
229
|
+
return "clifford"
|
230
|
+
|
231
|
+
@property
|
232
|
+
def num_clbits(self):
|
233
|
+
"""Number of classical bits."""
|
234
|
+
return 0
|
235
|
+
|
236
|
+
def __repr__(self):
|
237
|
+
return f"Clifford({repr(self.tableau)})"
|
238
|
+
|
239
|
+
def __str__(self):
|
240
|
+
return (
|
241
|
+
f'Clifford: Stabilizer = {self.to_labels(mode="S")}, '
|
242
|
+
f'Destabilizer = {self.to_labels(mode="D")}'
|
243
|
+
)
|
244
|
+
|
245
|
+
def __eq__(self, other):
|
246
|
+
"""Check if two Clifford tables are equal"""
|
247
|
+
return super().__eq__(other) and (self.tableau == other.tableau).all()
|
248
|
+
|
249
|
+
def copy(self):
|
250
|
+
return type(self)(self, validate=False, copy=True)
|
251
|
+
|
252
|
+
# ---------------------------------------------------------------------
|
253
|
+
# Attributes
|
254
|
+
# ---------------------------------------------------------------------
|
255
|
+
|
256
|
+
# pylint: disable=bad-docstring-quotes
|
257
|
+
|
258
|
+
@property
|
259
|
+
def symplectic_matrix(self):
|
260
|
+
"""Return boolean symplectic matrix."""
|
261
|
+
return self.tableau[:, :-1]
|
262
|
+
|
263
|
+
@symplectic_matrix.setter
|
264
|
+
def symplectic_matrix(self, value):
|
265
|
+
self.tableau[:, :-1] = value
|
266
|
+
|
267
|
+
@property
|
268
|
+
def phase(self):
|
269
|
+
"""Return phase with boolean representation."""
|
270
|
+
return self.tableau[:, -1]
|
271
|
+
|
272
|
+
@phase.setter
|
273
|
+
def phase(self, value):
|
274
|
+
self.tableau[:, -1] = value
|
275
|
+
|
276
|
+
@property
|
277
|
+
def x(self):
|
278
|
+
"""The x array for the symplectic representation."""
|
279
|
+
return self.tableau[:, 0 : self.num_qubits]
|
280
|
+
|
281
|
+
@x.setter
|
282
|
+
def x(self, value):
|
283
|
+
self.tableau[:, 0 : self.num_qubits] = value
|
284
|
+
|
285
|
+
@property
|
286
|
+
def z(self):
|
287
|
+
"""The z array for the symplectic representation."""
|
288
|
+
return self.tableau[:, self.num_qubits : 2 * self.num_qubits]
|
289
|
+
|
290
|
+
@z.setter
|
291
|
+
def z(self, value):
|
292
|
+
self.tableau[:, self.num_qubits : 2 * self.num_qubits] = value
|
293
|
+
|
294
|
+
@property
|
295
|
+
def destab(self):
|
296
|
+
"""The destabilizer array for the symplectic representation."""
|
297
|
+
return self.tableau[: self.num_qubits, :]
|
298
|
+
|
299
|
+
@destab.setter
|
300
|
+
def destab(self, value):
|
301
|
+
self.tableau[: self.num_qubits, :] = value
|
302
|
+
|
303
|
+
@property
|
304
|
+
def destab_x(self):
|
305
|
+
"""The destabilizer x array for the symplectic representation."""
|
306
|
+
return self.tableau[: self.num_qubits, : self.num_qubits]
|
307
|
+
|
308
|
+
@destab_x.setter
|
309
|
+
def destab_x(self, value):
|
310
|
+
self.tableau[: self.num_qubits, : self.num_qubits] = value
|
311
|
+
|
312
|
+
@property
|
313
|
+
def destab_z(self):
|
314
|
+
"""The destabilizer z array for the symplectic representation."""
|
315
|
+
return self.tableau[: self.num_qubits, self.num_qubits : 2 * self.num_qubits]
|
316
|
+
|
317
|
+
@destab_z.setter
|
318
|
+
def destab_z(self, value):
|
319
|
+
self.tableau[: self.num_qubits, self.num_qubits : 2 * self.num_qubits] = value
|
320
|
+
|
321
|
+
@property
|
322
|
+
def destab_phase(self):
|
323
|
+
"""Return phase of destabilizer with boolean representation."""
|
324
|
+
return self.tableau[: self.num_qubits, -1]
|
325
|
+
|
326
|
+
@destab_phase.setter
|
327
|
+
def destab_phase(self, value):
|
328
|
+
self.tableau[: self.num_qubits, -1] = value
|
329
|
+
|
330
|
+
@property
|
331
|
+
def stab(self):
|
332
|
+
"""The stabilizer array for the symplectic representation."""
|
333
|
+
return self.tableau[self.num_qubits :, :]
|
334
|
+
|
335
|
+
@stab.setter
|
336
|
+
def stab(self, value):
|
337
|
+
self.tableau[self.num_qubits :, :] = value
|
338
|
+
|
339
|
+
@property
|
340
|
+
def stab_x(self):
|
341
|
+
"""The stabilizer x array for the symplectic representation."""
|
342
|
+
return self.tableau[self.num_qubits :, : self.num_qubits]
|
343
|
+
|
344
|
+
@stab_x.setter
|
345
|
+
def stab_x(self, value):
|
346
|
+
self.tableau[self.num_qubits :, : self.num_qubits] = value
|
347
|
+
|
348
|
+
@property
|
349
|
+
def stab_z(self):
|
350
|
+
"""The stabilizer array for the symplectic representation."""
|
351
|
+
return self.tableau[self.num_qubits :, self.num_qubits : 2 * self.num_qubits]
|
352
|
+
|
353
|
+
@stab_z.setter
|
354
|
+
def stab_z(self, value):
|
355
|
+
self.tableau[self.num_qubits :, self.num_qubits : 2 * self.num_qubits] = value
|
356
|
+
|
357
|
+
@property
|
358
|
+
def stab_phase(self):
|
359
|
+
"""Return phase of stabilizer with boolean representation."""
|
360
|
+
return self.tableau[self.num_qubits :, -1]
|
361
|
+
|
362
|
+
@stab_phase.setter
|
363
|
+
def stab_phase(self, value):
|
364
|
+
self.tableau[self.num_qubits :, -1] = value
|
365
|
+
|
366
|
+
# ---------------------------------------------------------------------
|
367
|
+
# Utility Operator methods
|
368
|
+
# ---------------------------------------------------------------------
|
369
|
+
|
370
|
+
def is_unitary(self):
|
371
|
+
"""Return True if the Clifford table is valid."""
|
372
|
+
# A valid Clifford is always unitary, so this function is really
|
373
|
+
# checking that the underlying Stabilizer table array is a valid
|
374
|
+
# Clifford array.
|
375
|
+
return Clifford._is_symplectic(self.symplectic_matrix)
|
376
|
+
|
377
|
+
# ---------------------------------------------------------------------
|
378
|
+
# BaseOperator Abstract Methods
|
379
|
+
# ---------------------------------------------------------------------
|
380
|
+
|
381
|
+
def conjugate(self):
|
382
|
+
return Clifford._conjugate_transpose(self, "C")
|
383
|
+
|
384
|
+
def adjoint(self):
|
385
|
+
return Clifford._conjugate_transpose(self, "A")
|
386
|
+
|
387
|
+
def transpose(self):
|
388
|
+
return Clifford._conjugate_transpose(self, "T")
|
389
|
+
|
390
|
+
def tensor(self, other: Clifford) -> Clifford:
|
391
|
+
if not isinstance(other, Clifford):
|
392
|
+
other = Clifford(other)
|
393
|
+
return self._tensor(self, other)
|
394
|
+
|
395
|
+
def expand(self, other: Clifford) -> Clifford:
|
396
|
+
if not isinstance(other, Clifford):
|
397
|
+
other = Clifford(other)
|
398
|
+
return self._tensor(other, self)
|
399
|
+
|
400
|
+
@classmethod
|
401
|
+
def _tensor(cls, a, b):
|
402
|
+
n = a.num_qubits + b.num_qubits
|
403
|
+
tableau = np.zeros((2 * n, 2 * n + 1), dtype=bool)
|
404
|
+
clifford = cls(tableau, validate=False)
|
405
|
+
clifford.destab_x[: b.num_qubits, : b.num_qubits] = b.destab_x
|
406
|
+
clifford.destab_x[b.num_qubits :, b.num_qubits :] = a.destab_x
|
407
|
+
clifford.destab_z[: b.num_qubits, : b.num_qubits] = b.destab_z
|
408
|
+
clifford.destab_z[b.num_qubits :, b.num_qubits :] = a.destab_z
|
409
|
+
clifford.stab_x[: b.num_qubits, : b.num_qubits] = b.stab_x
|
410
|
+
clifford.stab_x[b.num_qubits :, b.num_qubits :] = a.stab_x
|
411
|
+
clifford.stab_z[: b.num_qubits, : b.num_qubits] = b.stab_z
|
412
|
+
clifford.stab_z[b.num_qubits :, b.num_qubits :] = a.stab_z
|
413
|
+
clifford.phase[: b.num_qubits] = b.destab_phase
|
414
|
+
clifford.phase[b.num_qubits : n] = a.destab_phase
|
415
|
+
clifford.phase[n : n + b.num_qubits] = b.stab_phase
|
416
|
+
clifford.phase[n + b.num_qubits :] = a.stab_phase
|
417
|
+
return clifford
|
418
|
+
|
419
|
+
def compose(
|
420
|
+
self,
|
421
|
+
other: Clifford | QuantumCircuit | Instruction,
|
422
|
+
qargs: list | None = None,
|
423
|
+
front: bool = False,
|
424
|
+
) -> Clifford:
|
425
|
+
if qargs is None:
|
426
|
+
qargs = getattr(other, "qargs", None)
|
427
|
+
# If other is a QuantumCircuit we can more efficiently compose
|
428
|
+
# using the _append_circuit method to update each gate recursively
|
429
|
+
# to the current Clifford, rather than converting to a Clifford first
|
430
|
+
# and then doing the composition of tables.
|
431
|
+
if not front:
|
432
|
+
if isinstance(other, QuantumCircuit):
|
433
|
+
return _append_circuit(self.copy(), other, qargs=qargs)
|
434
|
+
if isinstance(other, Instruction):
|
435
|
+
return _append_operation(self.copy(), other, qargs=qargs)
|
436
|
+
|
437
|
+
if not isinstance(other, Clifford):
|
438
|
+
# Not copying is safe since we're going to drop our only reference to `other` at the end
|
439
|
+
# of the function.
|
440
|
+
other = Clifford(other, copy=False)
|
441
|
+
|
442
|
+
# Validate compose dimensions
|
443
|
+
self._op_shape.compose(other._op_shape, qargs, front)
|
444
|
+
|
445
|
+
# Pad other with identities if composing on subsystem
|
446
|
+
other = self._pad_with_identity(other, qargs)
|
447
|
+
|
448
|
+
left, right = (self, other) if front else (other, self)
|
449
|
+
|
450
|
+
if self.num_qubits == 1:
|
451
|
+
return self._compose_1q(left, right)
|
452
|
+
return self._compose_general(left, right)
|
453
|
+
|
454
|
+
@classmethod
|
455
|
+
def _compose_general(cls, first, second):
|
456
|
+
# Correcting for phase due to Pauli multiplication. Start with factors of -i from XZ = -iY
|
457
|
+
# on individual qubits, and then handle multiplication between each qubitwise pair.
|
458
|
+
ifacts = np.sum(second.x & second.z, axis=1, dtype=int)
|
459
|
+
|
460
|
+
x1, z1 = first.x.astype(np.uint8), first.z.astype(np.uint8)
|
461
|
+
lookup = cls._compose_lookup()
|
462
|
+
|
463
|
+
# The loop is over 2*n_qubits entries, and the entire loop is cubic in the number of qubits.
|
464
|
+
for k, row2 in enumerate(second.symplectic_matrix):
|
465
|
+
x1_select = x1[row2]
|
466
|
+
z1_select = z1[row2]
|
467
|
+
x1_accum = np.logical_xor.accumulate(x1_select, axis=0).astype(np.uint8)
|
468
|
+
z1_accum = np.logical_xor.accumulate(z1_select, axis=0).astype(np.uint8)
|
469
|
+
indexer = (x1_select[1:], z1_select[1:], x1_accum[:-1], z1_accum[:-1])
|
470
|
+
ifacts[k] += np.sum(lookup[indexer])
|
471
|
+
p = np.mod(ifacts, 4) // 2
|
472
|
+
|
473
|
+
phase = (
|
474
|
+
(np.matmul(second.symplectic_matrix, first.phase, dtype=int) + second.phase + p) % 2
|
475
|
+
).astype(bool)
|
476
|
+
data = cls._stack_table_phase(
|
477
|
+
(np.matmul(second.symplectic_matrix, first.symplectic_matrix, dtype=int) % 2).astype(
|
478
|
+
bool
|
479
|
+
),
|
480
|
+
phase,
|
481
|
+
)
|
482
|
+
return Clifford(data, validate=False, copy=False)
|
483
|
+
|
484
|
+
@classmethod
|
485
|
+
def _compose_1q(cls, first, second):
|
486
|
+
# 1-qubit composition can be done with a simple lookup table; there are 24 elements in the
|
487
|
+
# 1q Clifford group, so 576 possible combinations, which is small enough to look up.
|
488
|
+
if cls._COMPOSE_1Q_LOOKUP is None:
|
489
|
+
# The valid tables for 1q Cliffords.
|
490
|
+
tables_1q = np.array(
|
491
|
+
[
|
492
|
+
[[False, True], [True, False]],
|
493
|
+
[[False, True], [True, True]],
|
494
|
+
[[True, False], [False, True]],
|
495
|
+
[[True, False], [True, True]],
|
496
|
+
[[True, True], [False, True]],
|
497
|
+
[[True, True], [True, False]],
|
498
|
+
]
|
499
|
+
)
|
500
|
+
phases_1q = np.array([[False, False], [False, True], [True, False], [True, True]])
|
501
|
+
# Build the lookup table.
|
502
|
+
cliffords = [
|
503
|
+
cls(cls._stack_table_phase(table, phase), validate=False, copy=False)
|
504
|
+
for table, phase in itertools.product(tables_1q, phases_1q)
|
505
|
+
]
|
506
|
+
cls._COMPOSE_1Q_LOOKUP = {
|
507
|
+
(cls._hash(left), cls._hash(right)): cls._compose_general(left, right)
|
508
|
+
for left, right in itertools.product(cliffords, repeat=2)
|
509
|
+
}
|
510
|
+
return cls._COMPOSE_1Q_LOOKUP[cls._hash(first), cls._hash(second)].copy()
|
511
|
+
|
512
|
+
@classmethod
|
513
|
+
def _compose_lookup(
|
514
|
+
cls,
|
515
|
+
):
|
516
|
+
if cls._COMPOSE_PHASE_LOOKUP is None:
|
517
|
+
# A lookup table for calculating phases. The indices are
|
518
|
+
# current_x, current_z, running_x_count, running_z_count
|
519
|
+
# where all counts taken modulo 2.
|
520
|
+
lookup = np.zeros((2, 2, 2, 2), dtype=int)
|
521
|
+
lookup[0, 1, 1, 0] = lookup[1, 0, 1, 1] = lookup[1, 1, 0, 1] = -1
|
522
|
+
lookup[0, 1, 1, 1] = lookup[1, 0, 0, 1] = lookup[1, 1, 1, 0] = 1
|
523
|
+
lookup.setflags(write=False)
|
524
|
+
cls._COMPOSE_PHASE_LOOKUP = lookup
|
525
|
+
return cls._COMPOSE_PHASE_LOOKUP
|
526
|
+
|
527
|
+
# ---------------------------------------------------------------------
|
528
|
+
# Representation conversions
|
529
|
+
# ---------------------------------------------------------------------
|
530
|
+
|
531
|
+
def to_dict(self):
|
532
|
+
"""Return dictionary representation of Clifford object."""
|
533
|
+
return {
|
534
|
+
"stabilizer": self.to_labels(mode="S"),
|
535
|
+
"destabilizer": self.to_labels(mode="D"),
|
536
|
+
}
|
537
|
+
|
538
|
+
@classmethod
|
539
|
+
def from_dict(cls, obj):
|
540
|
+
"""Load a Clifford from a dictionary"""
|
541
|
+
labels = obj.get("destabilizer") + obj.get("stabilizer")
|
542
|
+
n_paulis = len(labels)
|
543
|
+
symp = cls._from_label(labels[0])
|
544
|
+
tableau = np.zeros((n_paulis, len(symp)), dtype=bool)
|
545
|
+
tableau[0] = symp
|
546
|
+
for i in range(1, n_paulis):
|
547
|
+
tableau[i] = cls._from_label(labels[i])
|
548
|
+
return cls(tableau)
|
549
|
+
|
550
|
+
def to_matrix(self):
|
551
|
+
"""Convert operator to Numpy matrix."""
|
552
|
+
return self.to_operator().data
|
553
|
+
|
554
|
+
@classmethod
|
555
|
+
def from_matrix(cls, matrix: np.ndarray) -> Clifford:
|
556
|
+
"""Create a Clifford from a unitary matrix.
|
557
|
+
|
558
|
+
Note that this function takes exponentially long time w.r.t. the number of qubits.
|
559
|
+
|
560
|
+
Args:
|
561
|
+
matrix (np.array): A unitary matrix representing a Clifford to be converted.
|
562
|
+
|
563
|
+
Returns:
|
564
|
+
Clifford: the Clifford object for the unitary matrix.
|
565
|
+
|
566
|
+
Raises:
|
567
|
+
QiskitError: if the input is not a Clifford matrix.
|
568
|
+
"""
|
569
|
+
tableau = cls._unitary_matrix_to_tableau(matrix)
|
570
|
+
if tableau is None:
|
571
|
+
raise QiskitError("Non-Clifford matrix is not convertible")
|
572
|
+
return cls(tableau)
|
573
|
+
|
574
|
+
@classmethod
|
575
|
+
def from_linear_function(cls, linear_function):
|
576
|
+
"""Create a Clifford from a Linear Function.
|
577
|
+
|
578
|
+
If the linear function is represented by a nxn binary invertible matrix A,
|
579
|
+
then the corresponding Clifford has symplectic matrix [[A^t, 0], [0, A^{-1}]].
|
580
|
+
|
581
|
+
Args:
|
582
|
+
linear_function (LinearFunction): A linear function to be converted.
|
583
|
+
|
584
|
+
Returns:
|
585
|
+
Clifford: the Clifford object for this linear function.
|
586
|
+
"""
|
587
|
+
from qiskit.synthesis.linear import calc_inverse_matrix # pylint: disable=cyclic-import
|
588
|
+
|
589
|
+
mat = linear_function.linear
|
590
|
+
mat_t = np.transpose(mat)
|
591
|
+
mat_i = calc_inverse_matrix(mat)
|
592
|
+
|
593
|
+
dim = len(mat)
|
594
|
+
zero = np.zeros((dim, dim), dtype=int)
|
595
|
+
symplectic_mat = np.block([[mat_t, zero], [zero, mat_i]])
|
596
|
+
phase = np.zeros(2 * dim, dtype=int)
|
597
|
+
tableau = cls._stack_table_phase(symplectic_mat, phase)
|
598
|
+
return tableau
|
599
|
+
|
600
|
+
@classmethod
|
601
|
+
def from_permutation(cls, permutation_gate):
|
602
|
+
"""Create a Clifford from a PermutationGate.
|
603
|
+
|
604
|
+
Args:
|
605
|
+
permutation_gate (PermutationGate): A permutation to be converted.
|
606
|
+
|
607
|
+
Returns:
|
608
|
+
Clifford: the Clifford object for this permutation.
|
609
|
+
"""
|
610
|
+
|
611
|
+
pat = permutation_gate.pattern
|
612
|
+
dim = len(pat)
|
613
|
+
symplectic_mat = np.zeros((2 * dim, 2 * dim), dtype=int)
|
614
|
+
for i, j in enumerate(pat):
|
615
|
+
symplectic_mat[j, i] = True
|
616
|
+
symplectic_mat[j + dim, i + dim] = True
|
617
|
+
phase = np.zeros(2 * dim, dtype=bool)
|
618
|
+
tableau = cls._stack_table_phase(symplectic_mat, phase)
|
619
|
+
return tableau
|
620
|
+
|
621
|
+
def to_operator(self) -> Operator:
|
622
|
+
"""Convert to an Operator object."""
|
623
|
+
return Operator(self.to_instruction())
|
624
|
+
|
625
|
+
@classmethod
|
626
|
+
def from_operator(cls, operator: Operator) -> Clifford:
|
627
|
+
"""Create a Clifford from a operator.
|
628
|
+
|
629
|
+
Note that this function takes exponentially long time w.r.t. the number of qubits.
|
630
|
+
|
631
|
+
Args:
|
632
|
+
operator (Operator): An operator representing a Clifford to be converted.
|
633
|
+
|
634
|
+
Returns:
|
635
|
+
Clifford: the Clifford object for the operator.
|
636
|
+
|
637
|
+
Raises:
|
638
|
+
QiskitError: if the input is not a Clifford operator.
|
639
|
+
"""
|
640
|
+
tableau = cls._unitary_matrix_to_tableau(operator.to_matrix())
|
641
|
+
if tableau is None:
|
642
|
+
raise QiskitError("Non-Clifford operator is not convertible")
|
643
|
+
return cls(tableau)
|
644
|
+
|
645
|
+
def to_circuit(self):
|
646
|
+
"""Return a QuantumCircuit implementing the Clifford.
|
647
|
+
|
648
|
+
For N <= 3 qubits this is based on optimal CX cost decomposition
|
649
|
+
from reference [1]. For N > 3 qubits this is done using the general
|
650
|
+
non-optimal compilation routine from reference [2].
|
651
|
+
|
652
|
+
Return:
|
653
|
+
QuantumCircuit: a circuit implementation of the Clifford.
|
654
|
+
|
655
|
+
References:
|
656
|
+
1. S. Bravyi, D. Maslov, *Hadamard-free circuits expose the
|
657
|
+
structure of the Clifford group*,
|
658
|
+
`arXiv:2003.09412 [quant-ph] <https://arxiv.org/abs/2003.09412>`_
|
659
|
+
|
660
|
+
2. S. Aaronson, D. Gottesman, *Improved Simulation of Stabilizer Circuits*,
|
661
|
+
Phys. Rev. A 70, 052328 (2004).
|
662
|
+
`arXiv:quant-ph/0406196 <https://arxiv.org/abs/quant-ph/0406196>`_
|
663
|
+
"""
|
664
|
+
from qiskit.synthesis.clifford import synth_clifford_full # pylint: disable=cyclic-import
|
665
|
+
|
666
|
+
return synth_clifford_full(self)
|
667
|
+
|
668
|
+
def to_instruction(self):
|
669
|
+
"""Return a Gate instruction implementing the Clifford."""
|
670
|
+
return self.to_circuit().to_gate()
|
671
|
+
|
672
|
+
@staticmethod
|
673
|
+
def from_circuit(circuit: QuantumCircuit | Instruction) -> Clifford:
|
674
|
+
"""Initialize from a QuantumCircuit or Instruction.
|
675
|
+
|
676
|
+
Args:
|
677
|
+
circuit (QuantumCircuit or ~qiskit.circuit.Instruction):
|
678
|
+
instruction to initialize.
|
679
|
+
|
680
|
+
Returns:
|
681
|
+
Clifford: the Clifford object for the instruction.
|
682
|
+
|
683
|
+
Raises:
|
684
|
+
QiskitError: if the input instruction is non-Clifford or contains
|
685
|
+
classical register instruction.
|
686
|
+
"""
|
687
|
+
if not isinstance(circuit, (QuantumCircuit, Instruction)):
|
688
|
+
raise QiskitError("Input must be a QuantumCircuit or Instruction")
|
689
|
+
|
690
|
+
# Initialize an identity Clifford
|
691
|
+
clifford = Clifford(np.eye(2 * circuit.num_qubits), validate=False)
|
692
|
+
if isinstance(circuit, QuantumCircuit):
|
693
|
+
clifford = _append_circuit(clifford, circuit)
|
694
|
+
else:
|
695
|
+
clifford = _append_operation(clifford, circuit)
|
696
|
+
return clifford
|
697
|
+
|
698
|
+
@staticmethod
|
699
|
+
def from_label(label: str) -> Clifford:
|
700
|
+
"""Return a tensor product of single-qubit Clifford gates.
|
701
|
+
|
702
|
+
Args:
|
703
|
+
label (string): single-qubit operator string.
|
704
|
+
|
705
|
+
Returns:
|
706
|
+
Clifford: The N-qubit Clifford operator.
|
707
|
+
|
708
|
+
Raises:
|
709
|
+
QiskitError: if the label contains invalid characters.
|
710
|
+
|
711
|
+
Additional Information:
|
712
|
+
The labels correspond to the single-qubit Cliffords are
|
713
|
+
|
714
|
+
* - Label
|
715
|
+
- Stabilizer
|
716
|
+
- Destabilizer
|
717
|
+
* - ``"I"``
|
718
|
+
- +Z
|
719
|
+
- +X
|
720
|
+
* - ``"X"``
|
721
|
+
- -Z
|
722
|
+
- +X
|
723
|
+
* - ``"Y"``
|
724
|
+
- -Z
|
725
|
+
- -X
|
726
|
+
* - ``"Z"``
|
727
|
+
- +Z
|
728
|
+
- -X
|
729
|
+
* - ``"H"``
|
730
|
+
- +X
|
731
|
+
- +Z
|
732
|
+
* - ``"S"``
|
733
|
+
- +Z
|
734
|
+
- +Y
|
735
|
+
"""
|
736
|
+
# Check label is valid
|
737
|
+
label_gates = {
|
738
|
+
"I": IGate(),
|
739
|
+
"X": XGate(),
|
740
|
+
"Y": YGate(),
|
741
|
+
"Z": ZGate(),
|
742
|
+
"H": HGate(),
|
743
|
+
"S": SGate(),
|
744
|
+
}
|
745
|
+
if re.match(r"^[IXYZHS\-+]+$", label) is None:
|
746
|
+
raise QiskitError("Label contains invalid characters.")
|
747
|
+
# Initialize an identity matrix and apply each gate
|
748
|
+
num_qubits = len(label)
|
749
|
+
op = Clifford(np.eye(2 * num_qubits, dtype=bool))
|
750
|
+
for qubit, char in enumerate(reversed(label)):
|
751
|
+
op = _append_operation(op, label_gates[char], qargs=[qubit])
|
752
|
+
return op
|
753
|
+
|
754
|
+
def to_labels(self, array: bool = False, mode: Literal["S", "D", "B"] = "B"):
|
755
|
+
r"""Convert a Clifford to a list Pauli (de)stabilizer string labels.
|
756
|
+
|
757
|
+
For large Clifford converting using the ``array=True``
|
758
|
+
kwarg will be more efficient since it allocates memory for
|
759
|
+
the full Numpy array of labels in advance.
|
760
|
+
|
761
|
+
.. list-table:: Stabilizer Representations
|
762
|
+
:header-rows: 1
|
763
|
+
|
764
|
+
* - Label
|
765
|
+
- Phase
|
766
|
+
- Symplectic
|
767
|
+
- Matrix
|
768
|
+
- Pauli
|
769
|
+
* - ``"+I"``
|
770
|
+
- 0
|
771
|
+
- :math:`[0, 0]`
|
772
|
+
- :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}`
|
773
|
+
- :math:`I`
|
774
|
+
* - ``"-I"``
|
775
|
+
- 1
|
776
|
+
- :math:`[0, 0]`
|
777
|
+
- :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}`
|
778
|
+
- :math:`-I`
|
779
|
+
* - ``"X"``
|
780
|
+
- 0
|
781
|
+
- :math:`[1, 0]`
|
782
|
+
- :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}`
|
783
|
+
- :math:`X`
|
784
|
+
* - ``"-X"``
|
785
|
+
- 1
|
786
|
+
- :math:`[1, 0]`
|
787
|
+
- :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0 \end{bmatrix}`
|
788
|
+
- :math:`-X`
|
789
|
+
* - ``"Y"``
|
790
|
+
- 0
|
791
|
+
- :math:`[1, 1]`
|
792
|
+
- :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix}`
|
793
|
+
- :math:`iY`
|
794
|
+
* - ``"-Y"``
|
795
|
+
- 1
|
796
|
+
- :math:`[1, 1]`
|
797
|
+
- :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}`
|
798
|
+
- :math:`-iY`
|
799
|
+
* - ``"Z"``
|
800
|
+
- 0
|
801
|
+
- :math:`[0, 1]`
|
802
|
+
- :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}`
|
803
|
+
- :math:`Z`
|
804
|
+
* - ``"-Z"``
|
805
|
+
- 1
|
806
|
+
- :math:`[0, 1]`
|
807
|
+
- :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}`
|
808
|
+
- :math:`-Z`
|
809
|
+
|
810
|
+
Args:
|
811
|
+
array (bool): return a Numpy array if True, otherwise
|
812
|
+
return a list (Default: False).
|
813
|
+
mode (Literal["S", "D", "B"]): return both stabilizer and destabilizer if "B",
|
814
|
+
return only stabilizer if "S" and return only destabilizer if "D".
|
815
|
+
|
816
|
+
Returns:
|
817
|
+
list or array: The rows of the StabilizerTable in label form.
|
818
|
+
Raises:
|
819
|
+
QiskitError: if stabilizer and destabilizer are both False.
|
820
|
+
"""
|
821
|
+
if mode not in ("S", "B", "D"):
|
822
|
+
raise QiskitError("mode must be B, S, or D.")
|
823
|
+
size = 2 * self.num_qubits if mode == "B" else self.num_qubits
|
824
|
+
offset = self.num_qubits if mode == "S" else 0
|
825
|
+
ret = np.zeros(size, dtype=f"<U{1 + self.num_qubits}")
|
826
|
+
for i in range(size):
|
827
|
+
z = self.tableau[i + offset, self.num_qubits : 2 * self.num_qubits]
|
828
|
+
x = self.tableau[i + offset, 0 : self.num_qubits]
|
829
|
+
phase = int(self.tableau[i + offset, -1]) * 2
|
830
|
+
label = BasePauli._to_label(z, x, phase, group_phase=True)
|
831
|
+
if label[0] != "-":
|
832
|
+
label = "+" + label
|
833
|
+
ret[i] = label
|
834
|
+
if array:
|
835
|
+
return ret
|
836
|
+
return ret.tolist()
|
837
|
+
|
838
|
+
# ---------------------------------------------------------------------
|
839
|
+
# Internal helper functions
|
840
|
+
# ---------------------------------------------------------------------
|
841
|
+
|
842
|
+
def _hash(self):
|
843
|
+
"""Produce a hashable value that is unique for each different Clifford. This should only be
|
844
|
+
used internally when the classes being hashed are under our control, because classes of this
|
845
|
+
type are mutable."""
|
846
|
+
return np.packbits(self.tableau).tobytes()
|
847
|
+
|
848
|
+
@staticmethod
|
849
|
+
def _is_symplectic(mat):
|
850
|
+
"""Return True if input is symplectic matrix."""
|
851
|
+
# Condition is
|
852
|
+
# table.T * [[0, 1], [1, 0]] * table = [[0, 1], [1, 0]]
|
853
|
+
# where we are block matrix multiplying using symplectic product
|
854
|
+
|
855
|
+
dim = len(mat) // 2
|
856
|
+
if mat.shape != (2 * dim, 2 * dim):
|
857
|
+
return False
|
858
|
+
|
859
|
+
one = np.eye(dim, dtype=int)
|
860
|
+
zero = np.zeros((dim, dim), dtype=int)
|
861
|
+
seye = np.block([[zero, one], [one, zero]])
|
862
|
+
arr = mat.astype(int)
|
863
|
+
return np.array_equal(np.mod(arr.T.dot(seye).dot(arr), 2), seye)
|
864
|
+
|
865
|
+
@staticmethod
|
866
|
+
def _conjugate_transpose(clifford, method):
|
867
|
+
"""Return the adjoint, conjugate, or transpose of the Clifford.
|
868
|
+
|
869
|
+
Args:
|
870
|
+
clifford (Clifford): a clifford object.
|
871
|
+
method (str): what function to apply 'A', 'C', or 'T'.
|
872
|
+
|
873
|
+
Returns:
|
874
|
+
Clifford: the modified clifford.
|
875
|
+
"""
|
876
|
+
ret = clifford.copy()
|
877
|
+
if method in ["A", "T"]:
|
878
|
+
# Apply inverse
|
879
|
+
# Update table
|
880
|
+
tmp = ret.destab_x.copy()
|
881
|
+
ret.destab_x = ret.stab_z.T
|
882
|
+
ret.destab_z = ret.destab_z.T
|
883
|
+
ret.stab_x = ret.stab_x.T
|
884
|
+
ret.stab_z = tmp.T
|
885
|
+
# Update phase
|
886
|
+
ret.phase ^= clifford.dot(ret).phase
|
887
|
+
if method in ["C", "T"]:
|
888
|
+
# Apply conjugate
|
889
|
+
ret.phase ^= np.mod(_count_y(ret.x, ret.z), 2).astype(bool)
|
890
|
+
return ret
|
891
|
+
|
892
|
+
def _pad_with_identity(self, clifford, qargs):
|
893
|
+
"""Pad Clifford with identities on other subsystems."""
|
894
|
+
if qargs is None:
|
895
|
+
return clifford
|
896
|
+
|
897
|
+
padded = Clifford(np.eye(2 * self.num_qubits, dtype=bool), validate=False, copy=False)
|
898
|
+
inds = list(qargs) + [self.num_qubits + i for i in qargs]
|
899
|
+
|
900
|
+
# Pad Pauli array
|
901
|
+
for i, pos in enumerate(qargs):
|
902
|
+
padded.tableau[inds, pos] = clifford.tableau[:, i]
|
903
|
+
padded.tableau[inds, self.num_qubits + pos] = clifford.tableau[
|
904
|
+
:, clifford.num_qubits + i
|
905
|
+
]
|
906
|
+
|
907
|
+
# Pad phase
|
908
|
+
padded.phase[inds] = clifford.phase
|
909
|
+
|
910
|
+
return padded
|
911
|
+
|
912
|
+
@staticmethod
|
913
|
+
def _stack_table_phase(table, phase):
|
914
|
+
return np.hstack((table, phase.reshape(len(phase), 1)))
|
915
|
+
|
916
|
+
@staticmethod
|
917
|
+
def _from_label(label):
|
918
|
+
phase = False
|
919
|
+
if label[0] in ("-", "+"):
|
920
|
+
phase = label[0] == "-"
|
921
|
+
label = label[1:]
|
922
|
+
num_qubits = len(label)
|
923
|
+
symp = np.zeros(2 * num_qubits + 1, dtype=bool)
|
924
|
+
xs = symp[0:num_qubits]
|
925
|
+
zs = symp[num_qubits : 2 * num_qubits]
|
926
|
+
for i, char in enumerate(label):
|
927
|
+
if char not in ["I", "X", "Y", "Z"]:
|
928
|
+
raise QiskitError(
|
929
|
+
f"Pauli string contains invalid character: {char} not in ['I', 'X', 'Y', 'Z']."
|
930
|
+
)
|
931
|
+
if char in ("X", "Y"):
|
932
|
+
xs[num_qubits - 1 - i] = True
|
933
|
+
if char in ("Z", "Y"):
|
934
|
+
zs[num_qubits - 1 - i] = True
|
935
|
+
symp[-1] = phase
|
936
|
+
return symp
|
937
|
+
|
938
|
+
@staticmethod
|
939
|
+
def _pauli_matrix_to_row(mat, num_qubits):
|
940
|
+
"""Generate a binary vector (a row of tableau representation) from a Pauli matrix.
|
941
|
+
Return None if the non-Pauli matrix is supplied."""
|
942
|
+
# pylint: disable=too-many-return-statements
|
943
|
+
decimals = 6
|
944
|
+
|
945
|
+
def find_one_index(x):
|
946
|
+
indices = np.where(np.round(np.abs(x), decimals=decimals) == 1)
|
947
|
+
return indices[0][0] if len(indices[0]) == 1 else None
|
948
|
+
|
949
|
+
def bitvector(n, num_bits):
|
950
|
+
return np.array([int(digit) for digit in format(n, f"0{num_bits}b")], dtype=bool)[::-1]
|
951
|
+
|
952
|
+
# compute x-bits
|
953
|
+
xint = find_one_index(mat[0, :])
|
954
|
+
if xint is None:
|
955
|
+
return None
|
956
|
+
xbits = bitvector(xint, num_qubits)
|
957
|
+
|
958
|
+
# extract non-zero elements from matrix (each must be 1, -1, 1j or -1j for Pauli matrix)
|
959
|
+
entries = np.empty(len(mat), dtype=complex)
|
960
|
+
for i, row in enumerate(mat):
|
961
|
+
index = find_one_index(row)
|
962
|
+
if index is None:
|
963
|
+
return None
|
964
|
+
expected = xint ^ i
|
965
|
+
if index != expected:
|
966
|
+
return None
|
967
|
+
entries[i] = np.round(mat[i, index], decimals=decimals)
|
968
|
+
if entries[i] not in {1, -1, 1j, -1j}:
|
969
|
+
return None
|
970
|
+
|
971
|
+
# compute z-bits
|
972
|
+
zbits = np.empty(num_qubits, dtype=bool)
|
973
|
+
for k in range(num_qubits):
|
974
|
+
sign = np.round(entries[2**k] / entries[0])
|
975
|
+
if sign == 1:
|
976
|
+
zbits[k] = False
|
977
|
+
elif sign == -1:
|
978
|
+
zbits[k] = True
|
979
|
+
else:
|
980
|
+
return None
|
981
|
+
|
982
|
+
# compute phase
|
983
|
+
phase = None
|
984
|
+
num_y = sum(xbits & zbits)
|
985
|
+
positive_phase = (-1j) ** num_y
|
986
|
+
if entries[0] == positive_phase:
|
987
|
+
phase = False
|
988
|
+
elif entries[0] == -1 * positive_phase:
|
989
|
+
phase = True
|
990
|
+
if phase is None:
|
991
|
+
return None
|
992
|
+
|
993
|
+
# validate all non-zero elements
|
994
|
+
coef = ((-1) ** phase) * positive_phase
|
995
|
+
ivec, zvec = np.ones(2), np.array([1, -1])
|
996
|
+
expected = coef * functools.reduce(np.kron, [zvec if z else ivec for z in zbits[::-1]])
|
997
|
+
if not np.allclose(entries, expected):
|
998
|
+
return None
|
999
|
+
|
1000
|
+
return np.hstack([xbits, zbits, phase])
|
1001
|
+
|
1002
|
+
@staticmethod
|
1003
|
+
def _unitary_matrix_to_tableau(matrix):
|
1004
|
+
# pylint: disable=invalid-name
|
1005
|
+
num_qubits = int(math.log2(len(matrix)))
|
1006
|
+
|
1007
|
+
stab = np.empty((num_qubits, 2 * num_qubits + 1), dtype=bool)
|
1008
|
+
for i in range(num_qubits):
|
1009
|
+
label = "I" * (num_qubits - i - 1) + "X" + "I" * i
|
1010
|
+
Xi = Operator.from_label(label).to_matrix()
|
1011
|
+
target = matrix @ Xi @ np.conj(matrix).T
|
1012
|
+
row = Clifford._pauli_matrix_to_row(target, num_qubits)
|
1013
|
+
if row is None:
|
1014
|
+
return None
|
1015
|
+
stab[i] = row
|
1016
|
+
|
1017
|
+
destab = np.empty((num_qubits, 2 * num_qubits + 1), dtype=bool)
|
1018
|
+
for i in range(num_qubits):
|
1019
|
+
label = "I" * (num_qubits - i - 1) + "Z" + "I" * i
|
1020
|
+
Zi = Operator.from_label(label).to_matrix()
|
1021
|
+
target = matrix @ Zi @ np.conj(matrix).T
|
1022
|
+
row = Clifford._pauli_matrix_to_row(target, num_qubits)
|
1023
|
+
if row is None:
|
1024
|
+
return None
|
1025
|
+
destab[i] = row
|
1026
|
+
|
1027
|
+
tableau = np.vstack([stab, destab])
|
1028
|
+
return tableau
|
1029
|
+
|
1030
|
+
|
1031
|
+
# Update docstrings for API docs
|
1032
|
+
generate_apidocs(Clifford)
|