cirq-core 1.5.0.dev20250409222543__py3-none-any.whl → 1.6.0__py3-none-any.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.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/__init__.py +16 -17
- cirq/_compat.py +21 -20
- cirq/_compat_test.py +14 -34
- cirq/_doc.py +4 -2
- cirq/_import.py +8 -6
- cirq/_import_test.py +4 -2
- cirq/_version.py +6 -6
- cirq/_version_test.py +2 -2
- cirq/circuits/_block_diagram_drawer.py +11 -10
- cirq/circuits/_block_diagram_drawer_test.py +8 -6
- cirq/circuits/_box_drawing_character_data.py +8 -8
- cirq/circuits/_box_drawing_character_data_test.py +3 -1
- cirq/circuits/_bucket_priority_queue.py +9 -7
- cirq/circuits/_bucket_priority_queue_test.py +22 -20
- cirq/circuits/circuit.py +248 -172
- cirq/circuits/circuit_operation.py +73 -83
- cirq/circuits/circuit_operation_test.py +128 -90
- cirq/circuits/circuit_test.py +211 -151
- cirq/circuits/frozen_circuit.py +23 -60
- cirq/circuits/frozen_circuit_test.py +31 -8
- cirq/circuits/insert_strategy.py +7 -5
- cirq/circuits/insert_strategy_test.py +4 -2
- cirq/circuits/moment.py +88 -40
- cirq/circuits/moment_test.py +128 -51
- cirq/circuits/optimization_pass.py +5 -5
- cirq/circuits/optimization_pass_test.py +10 -10
- cirq/circuits/qasm_output.py +11 -11
- cirq/circuits/qasm_output_test.py +25 -22
- cirq/circuits/text_diagram_drawer.py +23 -38
- cirq/circuits/text_diagram_drawer_test.py +19 -17
- cirq/conftest.py +4 -3
- cirq/contrib/__init__.py +4 -4
- cirq/contrib/acquaintance/__init__.py +1 -1
- cirq/contrib/acquaintance/bipartite.py +5 -8
- cirq/contrib/acquaintance/bipartite_test.py +18 -13
- cirq/contrib/acquaintance/devices.py +2 -2
- cirq/contrib/acquaintance/devices_test.py +5 -3
- cirq/contrib/acquaintance/executor.py +5 -5
- cirq/contrib/acquaintance/executor_test.py +13 -9
- cirq/contrib/acquaintance/gates.py +18 -28
- cirq/contrib/acquaintance/gates_test.py +24 -20
- cirq/contrib/acquaintance/inspection_utils.py +8 -4
- cirq/contrib/acquaintance/inspection_utils_test.py +4 -2
- cirq/contrib/acquaintance/mutation_utils.py +4 -4
- cirq/contrib/acquaintance/mutation_utils_test.py +4 -2
- cirq/contrib/acquaintance/optimizers.py +4 -4
- cirq/contrib/acquaintance/optimizers_test.py +4 -1
- cirq/contrib/acquaintance/permutation.py +15 -27
- cirq/contrib/acquaintance/permutation_test.py +26 -17
- cirq/contrib/acquaintance/shift.py +4 -4
- cirq/contrib/acquaintance/shift_swap_network.py +4 -4
- cirq/contrib/acquaintance/shift_swap_network_test.py +9 -6
- cirq/contrib/acquaintance/shift_test.py +8 -6
- cirq/contrib/acquaintance/strategies/cubic.py +2 -2
- cirq/contrib/acquaintance/strategies/cubic_test.py +4 -2
- cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
- cirq/contrib/acquaintance/strategies/quartic_paired_test.py +10 -6
- cirq/contrib/acquaintance/testing.py +2 -0
- cirq/contrib/acquaintance/topological_sort.py +2 -2
- cirq/contrib/acquaintance/topological_sort_test.py +3 -1
- cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
- cirq/contrib/bayesian_network/bayesian_network_gate_test.py +14 -9
- cirq/contrib/circuitdag/circuit_dag.py +4 -4
- cirq/contrib/circuitdag/circuit_dag_test.py +17 -15
- cirq/contrib/custom_simulators/custom_state_simulator.py +5 -5
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +22 -17
- cirq/contrib/graph_device/graph_device.py +12 -11
- cirq/contrib/graph_device/graph_device_test.py +18 -14
- cirq/contrib/graph_device/hypergraph.py +16 -14
- cirq/contrib/graph_device/hypergraph_test.py +13 -11
- cirq/contrib/graph_device/uniform_graph_device.py +6 -4
- cirq/contrib/graph_device/uniform_graph_device_test.py +11 -3
- cirq/contrib/hacks/disable_validation.py +6 -1
- cirq/contrib/hacks/disable_validation_test.py +3 -1
- cirq/contrib/json.py +31 -5
- cirq/contrib/json_test.py +6 -3
- cirq/contrib/json_test_data/DampedReadoutNoiseModel.json +12 -0
- cirq/contrib/json_test_data/DampedReadoutNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/DepolarizingNoiseModel.json +12 -0
- cirq/contrib/json_test_data/DepolarizingNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.json +6 -0
- cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.repr +1 -0
- cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.json +5 -0
- cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.repr +1 -0
- cirq/contrib/json_test_data/ReadoutNoiseModel.json +12 -0
- cirq/contrib/json_test_data/ReadoutNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/__init__.py +17 -0
- cirq/contrib/json_test_data/spec.py +32 -0
- cirq/contrib/noise_models/noise_models.py +119 -5
- cirq/contrib/noise_models/noise_models_test.py +37 -9
- cirq/contrib/paulistring/clifford_optimize.py +6 -4
- cirq/contrib/paulistring/clifford_optimize_test.py +6 -5
- cirq/contrib/paulistring/clifford_target_gateset.py +10 -10
- cirq/contrib/paulistring/clifford_target_gateset_test.py +13 -11
- cirq/contrib/paulistring/optimize.py +2 -0
- cirq/contrib/paulistring/optimize_test.py +4 -3
- cirq/contrib/paulistring/pauli_string_dag.py +2 -0
- cirq/contrib/paulistring/pauli_string_dag_test.py +3 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +255 -120
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +398 -19
- cirq/contrib/paulistring/pauli_string_optimize.py +7 -1
- cirq/contrib/paulistring/pauli_string_optimize_test.py +5 -3
- cirq/contrib/paulistring/recombine.py +6 -4
- cirq/contrib/paulistring/recombine_test.py +3 -1
- cirq/contrib/paulistring/separate.py +9 -6
- cirq/contrib/paulistring/separate_test.py +3 -1
- cirq/contrib/qasm_import/_lexer.py +3 -2
- cirq/contrib/qasm_import/_lexer_test.py +49 -13
- cirq/contrib/qasm_import/_parser.py +547 -83
- cirq/contrib/qasm_import/_parser_test.py +988 -97
- cirq/contrib/qasm_import/exception.py +2 -0
- cirq/contrib/qasm_import/qasm.py +8 -2
- cirq/contrib/qasm_import/qasm_test.py +7 -4
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +5 -5
- cirq/contrib/qcircuit/qcircuit_diagram_info_test.py +4 -1
- cirq/contrib/qcircuit/qcircuit_pdf.py +7 -3
- cirq/contrib/qcircuit/qcircuit_pdf_test.py +3 -1
- cirq/contrib/qcircuit/qcircuit_test.py +10 -8
- cirq/contrib/quantum_volume/quantum_volume.py +31 -27
- cirq/contrib/quantum_volume/quantum_volume_test.py +19 -16
- cirq/contrib/quimb/density_matrix.py +15 -14
- cirq/contrib/quimb/density_matrix_test.py +10 -7
- cirq/contrib/quimb/grid_circuits.py +5 -2
- cirq/contrib/quimb/grid_circuits_test.py +3 -0
- cirq/contrib/quimb/mps_simulator.py +20 -20
- cirq/contrib/quimb/mps_simulator_test.py +3 -0
- cirq/contrib/quimb/state_vector.py +12 -11
- cirq/contrib/quimb/state_vector_test.py +3 -0
- cirq/contrib/quirk/export_to_quirk.py +5 -3
- cirq/contrib/quirk/export_to_quirk_test.py +18 -16
- cirq/contrib/quirk/linearize_circuit.py +2 -0
- cirq/contrib/quirk/quirk_gate.py +18 -17
- cirq/contrib/routing/device.py +5 -3
- cirq/contrib/routing/device_test.py +2 -0
- cirq/contrib/routing/greedy.py +10 -21
- cirq/contrib/routing/greedy_test.py +4 -2
- cirq/contrib/routing/initialization.py +2 -2
- cirq/contrib/routing/initialization_test.py +5 -3
- cirq/contrib/routing/router.py +9 -5
- cirq/contrib/routing/router_test.py +2 -0
- cirq/contrib/routing/swap_network.py +3 -3
- cirq/contrib/routing/swap_network_test.py +3 -1
- cirq/contrib/routing/utils.py +2 -2
- cirq/contrib/routing/utils_test.py +3 -0
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +15 -9
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +3 -0
- cirq/contrib/svg/svg.py +3 -3
- cirq/contrib/svg/svg_test.py +8 -5
- cirq/devices/device.py +4 -4
- cirq/devices/device_test.py +7 -4
- cirq/devices/grid_device_metadata.py +10 -10
- cirq/devices/grid_device_metadata_test.py +3 -0
- cirq/devices/grid_qubit.py +29 -21
- cirq/devices/grid_qubit_test.py +3 -0
- cirq/devices/insertion_noise_model.py +7 -7
- cirq/devices/insertion_noise_model_test.py +7 -5
- cirq/devices/line_qubit.py +13 -13
- cirq/devices/line_qubit_test.py +2 -0
- cirq/devices/named_topologies.py +18 -29
- cirq/devices/named_topologies_test.py +13 -10
- cirq/devices/noise_model.py +3 -3
- cirq/devices/noise_model_test.py +19 -15
- cirq/devices/noise_properties.py +15 -6
- cirq/devices/noise_properties_test.py +34 -3
- cirq/devices/noise_utils.py +11 -9
- cirq/devices/noise_utils_test.py +2 -0
- cirq/devices/superconducting_qubits_noise_properties.py +23 -22
- cirq/devices/superconducting_qubits_noise_properties_test.py +6 -6
- cirq/devices/thermal_noise_model.py +107 -37
- cirq/devices/thermal_noise_model_test.py +21 -0
- cirq/devices/unconstrained_device.py +5 -3
- cirq/devices/unconstrained_device_test.py +2 -0
- cirq/experiments/__init__.py +4 -2
- cirq/experiments/benchmarking/__init__.py +17 -0
- cirq/experiments/benchmarking/parallel_xeb.py +677 -0
- cirq/experiments/benchmarking/parallel_xeb_test.py +447 -0
- cirq/experiments/fidelity_estimation.py +14 -8
- cirq/experiments/fidelity_estimation_test.py +3 -0
- cirq/experiments/n_qubit_tomography.py +17 -16
- cirq/experiments/n_qubit_tomography_test.py +8 -5
- cirq/experiments/purity_estimation.py +2 -0
- cirq/experiments/purity_estimation_test.py +2 -0
- cirq/experiments/qubit_characterizations.py +207 -103
- cirq/experiments/qubit_characterizations_test.py +40 -12
- cirq/experiments/random_quantum_circuit_generation.py +56 -70
- cirq/experiments/random_quantum_circuit_generation_test.py +11 -8
- cirq/experiments/readout_confusion_matrix.py +24 -22
- cirq/experiments/readout_confusion_matrix_test.py +2 -0
- cirq/experiments/single_qubit_readout_calibration.py +30 -15
- cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
- cirq/experiments/t1_decay_experiment.py +9 -7
- cirq/experiments/t1_decay_experiment_test.py +13 -11
- cirq/experiments/t2_decay_experiment.py +16 -13
- cirq/experiments/t2_decay_experiment_test.py +2 -0
- cirq/experiments/two_qubit_xeb.py +64 -57
- cirq/experiments/two_qubit_xeb_test.py +10 -6
- cirq/experiments/xeb_fitting.py +39 -35
- cirq/experiments/xeb_sampling.py +37 -44
- cirq/experiments/xeb_sampling_test.py +3 -0
- cirq/experiments/xeb_simulation.py +14 -10
- cirq/experiments/xeb_simulation_test.py +5 -5
- cirq/experiments/z_phase_calibration.py +32 -29
- cirq/experiments/z_phase_calibration_test.py +3 -4
- cirq/interop/quirk/cells/__init__.py +1 -1
- cirq/interop/quirk/cells/all_cells.py +7 -2
- cirq/interop/quirk/cells/arithmetic_cells.py +29 -41
- cirq/interop/quirk/cells/arithmetic_cells_test.py +17 -14
- cirq/interop/quirk/cells/cell.py +19 -28
- cirq/interop/quirk/cells/cell_test.py +3 -0
- cirq/interop/quirk/cells/composite_cell.py +13 -28
- cirq/interop/quirk/cells/composite_cell_test.py +2 -0
- cirq/interop/quirk/cells/control_cells.py +15 -15
- cirq/interop/quirk/cells/control_cells_test.py +7 -5
- cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
- cirq/interop/quirk/cells/frequency_space_cells_test.py +3 -1
- cirq/interop/quirk/cells/ignored_cells.py +3 -0
- cirq/interop/quirk/cells/ignored_cells_test.py +3 -1
- cirq/interop/quirk/cells/input_cells.py +7 -5
- cirq/interop/quirk/cells/input_cells_test.py +7 -5
- cirq/interop/quirk/cells/input_rotation_cells.py +15 -13
- cirq/interop/quirk/cells/input_rotation_cells_test.py +9 -7
- cirq/interop/quirk/cells/measurement_cells.py +5 -2
- cirq/interop/quirk/cells/measurement_cells_test.py +3 -1
- cirq/interop/quirk/cells/parse.py +22 -23
- cirq/interop/quirk/cells/parse_test.py +12 -10
- cirq/interop/quirk/cells/qubit_permutation_cells.py +5 -3
- cirq/interop/quirk/cells/qubit_permutation_cells_test.py +9 -7
- cirq/interop/quirk/cells/scalar_cells.py +4 -1
- cirq/interop/quirk/cells/scalar_cells_test.py +3 -1
- cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
- cirq/interop/quirk/cells/single_qubit_rotation_cells_test.py +5 -3
- cirq/interop/quirk/cells/swap_cell.py +8 -6
- cirq/interop/quirk/cells/swap_cell_test.py +6 -4
- cirq/interop/quirk/cells/testing.py +6 -6
- cirq/interop/quirk/cells/testing_test.py +8 -6
- cirq/interop/quirk/cells/unsupported_cells.py +3 -0
- cirq/interop/quirk/cells/unsupported_cells_test.py +4 -2
- cirq/interop/quirk/url_to_circuit.py +23 -36
- cirq/interop/quirk/url_to_circuit_test.py +4 -1
- cirq/json_resolver_cache.py +14 -12
- cirq/linalg/__init__.py +4 -6
- cirq/linalg/combinators.py +7 -5
- cirq/linalg/combinators_test.py +10 -7
- cirq/linalg/decompositions.py +24 -35
- cirq/linalg/decompositions_test.py +3 -1
- cirq/linalg/diagonalize.py +6 -4
- cirq/linalg/diagonalize_test.py +15 -14
- cirq/linalg/operator_spaces.py +14 -14
- cirq/linalg/operator_spaces_test.py +13 -11
- cirq/linalg/predicates.py +18 -9
- cirq/linalg/predicates_test.py +5 -0
- cirq/linalg/tolerance.py +6 -3
- cirq/linalg/tolerance_test.py +6 -4
- cirq/linalg/transformations.py +23 -20
- cirq/linalg/transformations_test.py +73 -43
- cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
- cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +3 -1
- cirq/neutral_atoms/neutral_atom_devices.py +2 -0
- cirq/ops/__init__.py +2 -0
- cirq/ops/arithmetic_operation.py +21 -21
- cirq/ops/arithmetic_operation_test.py +7 -8
- cirq/ops/boolean_hamiltonian.py +23 -22
- cirq/ops/boolean_hamiltonian_test.py +12 -9
- cirq/ops/classically_controlled_operation.py +31 -36
- cirq/ops/classically_controlled_operation_test.py +121 -117
- cirq/ops/clifford_gate.py +98 -81
- cirq/ops/clifford_gate_test.py +72 -57
- cirq/ops/common_channels.py +44 -44
- cirq/ops/common_channels_test.py +83 -81
- cirq/ops/common_gate_families.py +9 -7
- cirq/ops/common_gate_families_test.py +11 -7
- cirq/ops/common_gates.py +164 -183
- cirq/ops/common_gates_test.py +135 -95
- cirq/ops/control_values.py +23 -26
- cirq/ops/control_values_test.py +22 -20
- cirq/ops/controlled_gate.py +64 -112
- cirq/ops/controlled_gate_test.py +130 -35
- cirq/ops/controlled_operation.py +24 -35
- cirq/ops/controlled_operation_test.py +8 -6
- cirq/ops/dense_pauli_string.py +38 -49
- cirq/ops/dense_pauli_string_test.py +4 -2
- cirq/ops/diagonal_gate.py +18 -31
- cirq/ops/diagonal_gate_test.py +13 -13
- cirq/ops/eigen_gate.py +29 -29
- cirq/ops/eigen_gate_test.py +45 -28
- cirq/ops/fourier_transform.py +14 -20
- cirq/ops/fourier_transform_test.py +15 -12
- cirq/ops/fsim_gate.py +43 -42
- cirq/ops/fsim_gate_test.py +29 -29
- cirq/ops/gate_features.py +2 -0
- cirq/ops/gate_features_test.py +5 -3
- cirq/ops/gate_operation.py +43 -65
- cirq/ops/gate_operation_test.py +46 -42
- cirq/ops/gateset.py +28 -40
- cirq/ops/gateset_test.py +4 -2
- cirq/ops/global_phase_op.py +45 -20
- cirq/ops/global_phase_op_test.py +44 -20
- cirq/ops/greedy_qubit_manager.py +10 -8
- cirq/ops/greedy_qubit_manager_test.py +5 -3
- cirq/ops/identity.py +14 -12
- cirq/ops/identity_test.py +24 -20
- cirq/ops/kraus_channel.py +11 -8
- cirq/ops/kraus_channel_test.py +14 -11
- cirq/ops/linear_combinations.py +65 -77
- cirq/ops/linear_combinations_test.py +14 -9
- cirq/ops/matrix_gates.py +21 -18
- cirq/ops/matrix_gates_test.py +16 -0
- cirq/ops/measure_util.py +15 -20
- cirq/ops/measure_util_test.py +2 -0
- cirq/ops/measurement_gate.py +26 -37
- cirq/ops/measurement_gate_test.py +2 -0
- cirq/ops/mixed_unitary_channel.py +12 -9
- cirq/ops/mixed_unitary_channel_test.py +14 -11
- cirq/ops/named_qubit.py +16 -13
- cirq/ops/named_qubit_test.py +15 -13
- cirq/ops/op_tree.py +9 -7
- cirq/ops/op_tree_test.py +22 -19
- cirq/ops/parallel_gate.py +15 -17
- cirq/ops/parallel_gate_test.py +18 -16
- cirq/ops/parity_gates.py +23 -25
- cirq/ops/parity_gates_test.py +36 -32
- cirq/ops/pauli_gates.py +22 -21
- cirq/ops/pauli_gates_test.py +29 -20
- cirq/ops/pauli_interaction_gate.py +15 -19
- cirq/ops/pauli_interaction_gate_test.py +10 -8
- cirq/ops/pauli_measurement_gate.py +23 -35
- cirq/ops/pauli_measurement_gate_test.py +2 -0
- cirq/ops/pauli_string.py +92 -120
- cirq/ops/pauli_string_phasor.py +52 -45
- cirq/ops/pauli_string_phasor_test.py +4 -5
- cirq/ops/pauli_string_raw_types.py +9 -7
- cirq/ops/pauli_string_raw_types_test.py +2 -0
- cirq/ops/pauli_string_test.py +31 -154
- cirq/ops/pauli_sum_exponential.py +12 -12
- cirq/ops/pauli_sum_exponential_test.py +12 -10
- cirq/ops/permutation_gate.py +8 -6
- cirq/ops/permutation_gate_test.py +10 -8
- cirq/ops/phased_iswap_gate.py +16 -16
- cirq/ops/phased_iswap_gate_test.py +17 -15
- cirq/ops/phased_x_gate.py +16 -17
- cirq/ops/phased_x_gate_test.py +18 -16
- cirq/ops/phased_x_z_gate.py +24 -22
- cirq/ops/phased_x_z_gate_test.py +17 -11
- cirq/ops/projector.py +16 -11
- cirq/ops/projector_test.py +19 -16
- cirq/ops/qid_util.py +7 -5
- cirq/ops/qid_util_test.py +2 -0
- cirq/ops/qubit_manager.py +11 -9
- cirq/ops/qubit_manager_test.py +6 -4
- cirq/ops/qubit_order.py +11 -14
- cirq/ops/qubit_order_or_list.py +4 -2
- cirq/ops/qubit_order_test.py +12 -10
- cirq/ops/random_gate_channel.py +12 -10
- cirq/ops/random_gate_channel_test.py +14 -11
- cirq/ops/raw_types.py +109 -129
- cirq/ops/raw_types_test.py +63 -57
- cirq/ops/state_preparation_channel.py +7 -7
- cirq/ops/state_preparation_channel_test.py +11 -9
- cirq/ops/swap_gates.py +13 -15
- cirq/ops/swap_gates_test.py +19 -17
- cirq/ops/tags.py +5 -3
- cirq/ops/tags_test.py +4 -2
- cirq/ops/three_qubit_gates.py +43 -76
- cirq/ops/three_qubit_gates_test.py +19 -17
- cirq/ops/two_qubit_diagonal_gate.py +13 -13
- cirq/ops/two_qubit_diagonal_gate_test.py +10 -8
- cirq/ops/uniform_superposition_gate.py +5 -3
- cirq/ops/uniform_superposition_gate_test.py +5 -3
- cirq/ops/wait_gate.py +17 -14
- cirq/ops/wait_gate_test.py +9 -6
- cirq/protocols/__init__.py +0 -3
- cirq/protocols/act_on_protocol.py +8 -6
- cirq/protocols/act_on_protocol_test.py +15 -12
- cirq/protocols/apply_channel_protocol.py +10 -14
- cirq/protocols/apply_channel_protocol_test.py +2 -0
- cirq/protocols/apply_mixture_protocol.py +13 -42
- cirq/protocols/apply_mixture_protocol_test.py +7 -5
- cirq/protocols/apply_unitary_protocol.py +39 -34
- cirq/protocols/apply_unitary_protocol_test.py +4 -1
- cirq/protocols/approximate_equality_protocol.py +2 -0
- cirq/protocols/approximate_equality_protocol_test.py +2 -0
- cirq/protocols/circuit_diagram_info_protocol.py +58 -42
- cirq/protocols/circuit_diagram_info_protocol_test.py +70 -12
- cirq/protocols/commutes_protocol.py +8 -7
- cirq/protocols/commutes_protocol_test.py +2 -0
- cirq/protocols/control_key_protocol.py +6 -4
- cirq/protocols/control_key_protocol_test.py +3 -1
- cirq/protocols/decompose_protocol.py +49 -48
- cirq/protocols/decompose_protocol_test.py +27 -16
- cirq/protocols/equal_up_to_global_phase_protocol.py +2 -0
- cirq/protocols/equal_up_to_global_phase_protocol_test.py +9 -6
- cirq/protocols/has_stabilizer_effect_protocol.py +7 -5
- cirq/protocols/has_stabilizer_effect_protocol_test.py +7 -5
- cirq/protocols/has_unitary_protocol.py +10 -6
- cirq/protocols/has_unitary_protocol_test.py +13 -8
- cirq/protocols/hash_from_pickle_test.py +2 -11
- cirq/protocols/inverse_protocol.py +13 -16
- cirq/protocols/inverse_protocol_test.py +5 -3
- cirq/protocols/json_serialization.py +35 -54
- cirq/protocols/json_serialization_test.py +14 -21
- cirq/protocols/json_test_data/CXSWAP.json +46 -0
- cirq/protocols/json_test_data/CXSWAP.repr +13 -0
- cirq/protocols/json_test_data/CZSWAP.json +46 -0
- cirq/protocols/json_test_data/CZSWAP.repr +13 -0
- cirq/protocols/json_test_data/CircuitOperation.json +6 -3
- cirq/protocols/json_test_data/CircuitOperation.repr_inward +4 -2
- cirq/protocols/json_test_data/Moment.json +24 -1
- cirq/protocols/json_test_data/Moment.repr +6 -1
- cirq/protocols/json_test_data/ThermalNoiseModel.json +32 -0
- cirq/protocols/json_test_data/ThermalNoiseModel.repr +1 -0
- cirq/protocols/json_test_data/spec.py +6 -2
- cirq/protocols/kraus_protocol.py +47 -7
- cirq/protocols/kraus_protocol_test.py +86 -12
- cirq/protocols/measurement_key_protocol.py +15 -16
- cirq/protocols/measurement_key_protocol_test.py +13 -11
- cirq/protocols/mixture_protocol.py +7 -5
- cirq/protocols/mixture_protocol_test.py +4 -2
- cirq/protocols/mul_protocol.py +2 -3
- cirq/protocols/mul_protocol_test.py +2 -0
- cirq/protocols/pauli_expansion_protocol.py +6 -3
- cirq/protocols/pauli_expansion_protocol_test.py +5 -3
- cirq/protocols/phase_protocol.py +2 -0
- cirq/protocols/phase_protocol_test.py +3 -1
- cirq/protocols/pow_protocol.py +11 -16
- cirq/protocols/pow_protocol_test.py +2 -0
- cirq/protocols/qasm.py +14 -20
- cirq/protocols/qasm_test.py +6 -3
- cirq/protocols/qid_shape_protocol.py +8 -8
- cirq/protocols/qid_shape_protocol_test.py +3 -1
- cirq/protocols/resolve_parameters.py +5 -3
- cirq/protocols/resolve_parameters_test.py +8 -7
- cirq/protocols/trace_distance_bound.py +6 -4
- cirq/protocols/trace_distance_bound_test.py +3 -1
- cirq/protocols/unitary_protocol.py +17 -7
- cirq/protocols/unitary_protocol_test.py +12 -2
- cirq/qis/channels.py +6 -2
- cirq/qis/channels_test.py +20 -16
- cirq/qis/clifford_tableau.py +21 -19
- cirq/qis/clifford_tableau_test.py +2 -2
- cirq/qis/entropy.py +14 -3
- cirq/qis/entropy_test.py +3 -1
- cirq/qis/measures.py +13 -13
- cirq/qis/measures_test.py +20 -14
- cirq/qis/noise_utils.py +2 -0
- cirq/qis/noise_utils_test.py +9 -7
- cirq/qis/quantum_state_representation.py +7 -8
- cirq/qis/states.py +58 -56
- cirq/qis/states_test.py +2 -0
- cirq/sim/classical_simulator.py +23 -22
- cirq/sim/classical_simulator_test.py +2 -0
- cirq/sim/clifford/clifford_simulator.py +23 -21
- cirq/sim/clifford/clifford_simulator_test.py +7 -4
- cirq/sim/clifford/clifford_tableau_simulation_state.py +10 -7
- cirq/sim/clifford/clifford_tableau_simulation_state_test.py +5 -5
- cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +8 -6
- cirq/sim/clifford/stabilizer_ch_form_simulation_state_test.py +8 -6
- cirq/sim/clifford/stabilizer_sampler.py +9 -7
- cirq/sim/clifford/stabilizer_sampler_test.py +4 -2
- cirq/sim/clifford/stabilizer_simulation_state.py +14 -13
- cirq/sim/clifford/stabilizer_simulation_state_test.py +6 -4
- cirq/sim/clifford/stabilizer_state_ch_form.py +13 -11
- cirq/sim/clifford/stabilizer_state_ch_form_test.py +4 -2
- cirq/sim/density_matrix_simulation_state.py +26 -27
- cirq/sim/density_matrix_simulation_state_test.py +10 -8
- cirq/sim/density_matrix_simulator.py +30 -28
- cirq/sim/density_matrix_simulator_test.py +48 -48
- cirq/sim/density_matrix_utils.py +13 -11
- cirq/sim/density_matrix_utils_test.py +38 -36
- cirq/sim/mux.py +33 -31
- cirq/sim/mux_test.py +3 -0
- cirq/sim/simulation_product_state.py +15 -15
- cirq/sim/simulation_product_state_test.py +29 -26
- cirq/sim/simulation_state.py +29 -38
- cirq/sim/simulation_state_base.py +21 -32
- cirq/sim/simulation_state_test.py +15 -13
- cirq/sim/simulation_utils.py +5 -2
- cirq/sim/simulation_utils_test.py +5 -2
- cirq/sim/simulator.py +90 -106
- cirq/sim/simulator_base.py +33 -45
- cirq/sim/simulator_base_test.py +20 -15
- cirq/sim/simulator_test.py +23 -14
- cirq/sim/sparse_simulator.py +19 -17
- cirq/sim/sparse_simulator_test.py +41 -40
- cirq/sim/state_vector.py +15 -12
- cirq/sim/state_vector_simulation_state.py +31 -31
- cirq/sim/state_vector_simulation_state_test.py +16 -14
- cirq/sim/state_vector_simulator.py +17 -14
- cirq/sim/state_vector_simulator_test.py +2 -0
- cirq/sim/state_vector_test.py +6 -3
- cirq/study/flatten_expressions.py +16 -15
- cirq/study/flatten_expressions_test.py +13 -11
- cirq/study/resolver.py +18 -17
- cirq/study/resolver_test.py +22 -20
- cirq/study/result.py +17 -27
- cirq/study/result_test.py +2 -0
- cirq/study/sweepable.py +12 -10
- cirq/study/sweepable_test.py +3 -0
- cirq/study/sweeps.py +42 -61
- cirq/study/sweeps_test.py +33 -0
- cirq/testing/__init__.py +7 -11
- cirq/testing/_compat_test_data/module_a/__init__.py +1 -0
- cirq/testing/_compat_test_data/module_a/module_b/__init__.py +1 -0
- cirq/testing/_compat_test_data/module_a/sub/__init__.py +1 -0
- cirq/testing/circuit_compare.py +8 -17
- cirq/testing/circuit_compare_test.py +2 -0
- cirq/testing/consistent_act_on.py +13 -11
- cirq/testing/consistent_act_on_test.py +5 -3
- cirq/testing/consistent_channels.py +2 -0
- cirq/testing/consistent_channels_test.py +10 -8
- cirq/testing/consistent_controlled_gate_op.py +5 -5
- cirq/testing/consistent_controlled_gate_op_test.py +18 -18
- cirq/testing/consistent_decomposition.py +2 -2
- cirq/testing/consistent_decomposition_test.py +4 -2
- cirq/testing/consistent_pauli_expansion.py +2 -0
- cirq/testing/consistent_pauli_expansion_test.py +3 -1
- cirq/testing/consistent_phase_by.py +2 -0
- cirq/testing/consistent_phase_by_test.py +3 -1
- cirq/testing/consistent_protocols.py +14 -20
- cirq/testing/consistent_protocols_test.py +13 -11
- cirq/testing/consistent_qasm.py +6 -4
- cirq/testing/consistent_qasm_test.py +7 -7
- cirq/testing/consistent_resolve_parameters.py +2 -0
- cirq/testing/consistent_specified_has_unitary.py +2 -2
- cirq/testing/consistent_specified_has_unitary_test.py +6 -4
- cirq/testing/consistent_unitary.py +1 -0
- cirq/testing/consistent_unitary_test.py +4 -2
- cirq/testing/deprecation.py +5 -2
- cirq/testing/deprecation_test.py +5 -2
- cirq/testing/devices.py +7 -4
- cirq/testing/devices_test.py +7 -4
- cirq/testing/equals_tester.py +4 -2
- cirq/testing/equals_tester_test.py +21 -17
- cirq/testing/equivalent_basis_map.py +6 -4
- cirq/testing/equivalent_basis_map_test.py +6 -4
- cirq/testing/equivalent_repr_eval.py +6 -4
- cirq/testing/equivalent_repr_eval_test.py +5 -3
- cirq/testing/gate_features.py +2 -0
- cirq/testing/gate_features_test.py +7 -5
- cirq/testing/json.py +19 -15
- cirq/testing/json_test.py +5 -3
- cirq/testing/lin_alg_utils.py +10 -11
- cirq/testing/lin_alg_utils_test.py +14 -12
- cirq/testing/logs.py +7 -6
- cirq/testing/logs_test.py +9 -7
- cirq/testing/no_identifier_qubit.py +4 -2
- cirq/testing/no_identifier_qubit_test.py +5 -3
- cirq/testing/op_tree.py +2 -0
- cirq/testing/op_tree_test.py +4 -1
- cirq/testing/order_tester.py +2 -0
- cirq/testing/order_tester_test.py +8 -6
- cirq/testing/pytest_utils.py +2 -0
- cirq/testing/pytest_utils_test.py +4 -2
- cirq/testing/random_circuit.py +21 -20
- cirq/testing/random_circuit_test.py +12 -9
- cirq/testing/repr_pretty_tester.py +1 -0
- cirq/testing/repr_pretty_tester_test.py +5 -3
- cirq/testing/routing_devices.py +4 -1
- cirq/testing/routing_devices_test.py +9 -6
- cirq/testing/sample_circuits.py +4 -1
- cirq/testing/sample_circuits_test.py +3 -1
- cirq/testing/sample_gates.py +3 -0
- cirq/testing/sample_gates_test.py +5 -2
- cirq/transformers/__init__.py +11 -4
- cirq/transformers/align.py +9 -7
- cirq/transformers/align_test.py +2 -0
- cirq/transformers/analytical_decompositions/__init__.py +3 -6
- cirq/transformers/analytical_decompositions/clifford_decomposition.py +18 -16
- cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +2 -0
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +19 -16
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
- cirq/transformers/analytical_decompositions/cphase_to_fsim.py +11 -9
- cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +5 -3
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +5 -3
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +5 -3
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +141 -44
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +35 -1
- cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +8 -7
- cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +2 -0
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +7 -4
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +3 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +11 -19
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +8 -33
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +9 -11
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -0
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +91 -27
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +36 -7
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +20 -21
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +8 -6
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +13 -15
- cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +3 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +39 -41
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -0
- cirq/transformers/drop_empty_moments.py +5 -3
- cirq/transformers/drop_empty_moments_test.py +4 -2
- cirq/transformers/drop_negligible_operations.py +7 -5
- cirq/transformers/drop_negligible_operations_test.py +2 -0
- cirq/transformers/dynamical_decoupling.py +49 -42
- cirq/transformers/dynamical_decoupling_test.py +223 -205
- cirq/transformers/eject_phased_paulis.py +28 -26
- cirq/transformers/eject_phased_paulis_test.py +12 -9
- cirq/transformers/eject_z.py +12 -12
- cirq/transformers/eject_z_test.py +2 -2
- cirq/transformers/expand_composite.py +6 -4
- cirq/transformers/expand_composite_test.py +3 -1
- cirq/transformers/gauge_compiling/__init__.py +3 -1
- cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
- cirq/transformers/gauge_compiling/cphase_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +2 -0
- cirq/transformers/gauge_compiling/cz_gauge_test.py +1 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +45 -41
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +2 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +1 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +5 -1
- cirq/transformers/gauge_compiling/iswap_gauge.py +2 -0
- cirq/transformers/gauge_compiling/iswap_gauge_test.py +1 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +7 -6
- cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +2 -0
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +6 -3
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +3 -0
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +12 -9
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +9 -7
- cirq/transformers/insertion_sort.py +8 -6
- cirq/transformers/insertion_sort_test.py +3 -1
- cirq/transformers/measurement_transformers.py +29 -29
- cirq/transformers/measurement_transformers_test.py +2 -0
- cirq/transformers/merge_k_qubit_gates.py +12 -10
- cirq/transformers/merge_k_qubit_gates_test.py +18 -18
- cirq/transformers/merge_single_qubit_gates.py +197 -20
- cirq/transformers/merge_single_qubit_gates_test.py +177 -5
- cirq/transformers/noise_adding.py +5 -3
- cirq/transformers/noise_adding_test.py +2 -0
- cirq/transformers/optimize_for_target_gateset.py +19 -17
- cirq/transformers/optimize_for_target_gateset_test.py +11 -8
- cirq/transformers/qubit_management_transformers.py +13 -11
- cirq/transformers/qubit_management_transformers_test.py +5 -3
- cirq/transformers/randomized_measurements.py +16 -14
- cirq/transformers/randomized_measurements_test.py +10 -4
- cirq/transformers/routing/initial_mapper.py +6 -4
- cirq/transformers/routing/initial_mapper_test.py +2 -0
- cirq/transformers/routing/line_initial_mapper.py +16 -14
- cirq/transformers/routing/line_initial_mapper_test.py +9 -7
- cirq/transformers/routing/mapping_manager.py +10 -10
- cirq/transformers/routing/mapping_manager_test.py +2 -0
- cirq/transformers/routing/route_circuit_cqc.py +33 -31
- cirq/transformers/routing/route_circuit_cqc_test.py +15 -13
- cirq/transformers/routing/visualize_routed_circuit.py +8 -7
- cirq/transformers/routing/visualize_routed_circuit_test.py +4 -2
- cirq/transformers/stratify.py +17 -15
- cirq/transformers/stratify_test.py +3 -0
- cirq/transformers/symbolize.py +103 -0
- cirq/transformers/symbolize_test.py +62 -0
- cirq/transformers/synchronize_terminal_measurements.py +10 -10
- cirq/transformers/synchronize_terminal_measurements_test.py +12 -10
- cirq/transformers/tag_transformers.py +97 -0
- cirq/transformers/tag_transformers_test.py +103 -0
- cirq/transformers/target_gatesets/compilation_target_gateset.py +21 -19
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +20 -16
- cirq/transformers/target_gatesets/cz_gateset.py +7 -5
- cirq/transformers/target_gatesets/cz_gateset_test.py +21 -19
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +9 -7
- cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +25 -25
- cirq/transformers/transformer_api.py +34 -47
- cirq/transformers/transformer_api_test.py +9 -8
- cirq/transformers/transformer_primitives.py +39 -49
- cirq/transformers/transformer_primitives_test.py +10 -17
- cirq/value/abc_alt.py +6 -4
- cirq/value/abc_alt_test.py +5 -3
- cirq/value/angle.py +11 -12
- cirq/value/angle_test.py +5 -3
- cirq/value/classical_data.py +27 -27
- cirq/value/classical_data_test.py +11 -8
- cirq/value/condition.py +26 -24
- cirq/value/condition_test.py +2 -0
- cirq/value/digits.py +14 -11
- cirq/value/digits_test.py +2 -0
- cirq/value/duration.py +23 -20
- cirq/value/duration_test.py +2 -0
- cirq/value/linear_dict.py +25 -30
- cirq/value/linear_dict_test.py +10 -8
- cirq/value/measurement_key.py +12 -12
- cirq/value/measurement_key_test.py +2 -0
- cirq/value/periodic_value.py +4 -4
- cirq/value/periodic_value_test.py +11 -7
- cirq/value/probability.py +3 -1
- cirq/value/probability_test.py +4 -2
- cirq/value/product_state.py +15 -13
- cirq/value/product_state_test.py +4 -1
- cirq/value/random_state.py +2 -0
- cirq/value/random_state_test.py +5 -3
- cirq/value/timestamp.py +11 -7
- cirq/value/timestamp_test.py +14 -12
- cirq/value/type_alias.py +4 -4
- cirq/value/value_equality_attr.py +8 -9
- cirq/value/value_equality_attr_test.py +14 -11
- cirq/vis/density_matrix.py +3 -3
- cirq/vis/density_matrix_test.py +20 -17
- cirq/vis/heatmap.py +24 -37
- cirq/vis/heatmap_test.py +3 -0
- cirq/vis/histogram.py +9 -6
- cirq/vis/histogram_test.py +5 -2
- cirq/vis/state_histogram.py +10 -8
- cirq/vis/state_histogram_test.py +7 -5
- cirq/vis/vis_utils.py +4 -1
- cirq/vis/vis_utils_test.py +4 -1
- cirq/work/collector.py +12 -18
- cirq/work/collector_test.py +15 -10
- cirq/work/observable_grouping.py +6 -7
- cirq/work/observable_grouping_test.py +10 -9
- cirq/work/observable_measurement.py +47 -45
- cirq/work/observable_measurement_data.py +22 -17
- cirq/work/observable_measurement_data_test.py +4 -1
- cirq/work/observable_measurement_test.py +48 -29
- cirq/work/observable_readout_calibration.py +5 -2
- cirq/work/observable_readout_calibration_test.py +5 -2
- cirq/work/observable_settings.py +13 -22
- cirq/work/observable_settings_test.py +9 -7
- cirq/work/pauli_sum_collector.py +12 -10
- cirq/work/pauli_sum_collector_test.py +9 -9
- cirq/work/sampler.py +42 -43
- cirq/work/sampler_test.py +31 -24
- cirq/work/zeros_sampler.py +6 -4
- cirq/work/zeros_sampler_test.py +7 -5
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/METADATA +7 -8
- cirq_core-1.6.0.dist-info/RECORD +1241 -0
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
- cirq_core-1.5.0.dev20250409222543.dist-info/RECORD +0 -1216
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
|
@@ -12,36 +12,43 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
"""Utility methods for decomposing arbitrary n-qubit (2^n x 2^n) unitary.
|
|
17
16
|
|
|
18
17
|
Based on:
|
|
19
18
|
Synthesis of Quantum Logic Circuits. Tech. rep. 2006,
|
|
20
19
|
https://arxiv.org/abs/quant-ph/0406176
|
|
21
20
|
"""
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from typing import Callable, cast, Iterable, TYPE_CHECKING
|
|
23
25
|
|
|
24
26
|
import numpy as np
|
|
27
|
+
from attr import define
|
|
25
28
|
from scipy.linalg import cossin
|
|
26
29
|
|
|
27
30
|
from cirq import ops
|
|
28
31
|
from cirq.circuits.frozen_circuit import FrozenCircuit
|
|
29
32
|
from cirq.linalg import decompositions, predicates
|
|
30
33
|
from cirq.protocols import unitary_protocol
|
|
31
|
-
from cirq.transformers.analytical_decompositions.three_qubit_decomposition import (
|
|
32
|
-
three_qubit_matrix_to_operations,
|
|
33
|
-
)
|
|
34
34
|
from cirq.transformers.analytical_decompositions.two_qubit_to_cz import (
|
|
35
35
|
two_qubit_matrix_to_cz_operations,
|
|
36
|
+
two_qubit_matrix_to_diagonal_and_cz_operations,
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
if TYPE_CHECKING:
|
|
39
40
|
import cirq
|
|
40
41
|
|
|
41
42
|
|
|
43
|
+
@define
|
|
44
|
+
class _TwoQubitGate:
|
|
45
|
+
location: int
|
|
46
|
+
matrix: np.ndarray
|
|
47
|
+
|
|
48
|
+
|
|
42
49
|
def quantum_shannon_decomposition(
|
|
43
|
-
qubits:
|
|
44
|
-
) -> Iterable[
|
|
50
|
+
qubits: list[cirq.Qid], u: np.ndarray, atol: float = 1e-8
|
|
51
|
+
) -> Iterable[cirq.Operation]:
|
|
45
52
|
"""Decomposes n-qubit unitary 1-q, 2-q and GlobalPhase gates, preserving global phase.
|
|
46
53
|
|
|
47
54
|
The gates used are CX/YPow/ZPow/CNOT/GlobalPhase/CZ/PhasedXZGate/PhasedXPowGate.
|
|
@@ -65,14 +72,12 @@ def quantum_shannon_decomposition(
|
|
|
65
72
|
1. _single_qubit_decomposition
|
|
66
73
|
OR
|
|
67
74
|
(Recursive Case)
|
|
68
|
-
1.
|
|
69
|
-
2. _multiplexed_cossin
|
|
70
|
-
3. _msb_demuxer
|
|
75
|
+
1. _recursive_decomposition
|
|
71
76
|
|
|
72
77
|
Yields:
|
|
73
78
|
A single 2-qubit or 1-qubit operations from OP TREE
|
|
74
79
|
composed from the set
|
|
75
|
-
{ CNOT, rz, ry, ZPowGate }
|
|
80
|
+
{ CNOT, CZ, rz, ry, ZPowGate }
|
|
76
81
|
|
|
77
82
|
Raises:
|
|
78
83
|
ValueError: If the u matrix is non-unitary
|
|
@@ -96,30 +101,92 @@ def quantum_shannon_decomposition(
|
|
|
96
101
|
yield from _single_qubit_decomposition(qubits[0], u)
|
|
97
102
|
return
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
# Collect all operations from the recursive decomposition
|
|
105
|
+
shannon_decomp: list[cirq.Operation | list[cirq.Operation]] = [
|
|
106
|
+
*_recursive_decomposition(qubits, u)
|
|
107
|
+
]
|
|
108
|
+
# Separate all 2-qubit generic gates while keeping track of location
|
|
109
|
+
two_qubit_gates = [
|
|
110
|
+
_TwoQubitGate(location=loc, matrix=unitary_protocol.unitary(o))
|
|
111
|
+
for loc, o in enumerate(cast(list[ops.Operation], shannon_decomp))
|
|
112
|
+
if isinstance(o.gate, ops.MatrixGate)
|
|
113
|
+
]
|
|
114
|
+
# Apply case A.2 from Shende et al.
|
|
115
|
+
q0 = qubits[-2]
|
|
116
|
+
q1 = qubits[-1]
|
|
117
|
+
for idx in range(len(two_qubit_gates) - 1, 0, -1):
|
|
118
|
+
diagonal, operations = two_qubit_matrix_to_diagonal_and_cz_operations(
|
|
119
|
+
q0,
|
|
120
|
+
q1,
|
|
121
|
+
two_qubit_gates[idx].matrix,
|
|
122
|
+
allow_partial_czs=True,
|
|
123
|
+
clean_operations=True,
|
|
124
|
+
atol=atol,
|
|
104
125
|
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
126
|
+
global_phase = _global_phase_difference(
|
|
127
|
+
two_qubit_gates[idx].matrix, [ops.MatrixGate(diagonal)(q0, q1), *operations]
|
|
128
|
+
)
|
|
129
|
+
if not np.isclose(global_phase, 0, atol=atol):
|
|
130
|
+
operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
|
|
131
|
+
# Replace the generic gate with ops from OP TREE
|
|
132
|
+
shannon_decomp[two_qubit_gates[idx].location] = operations
|
|
133
|
+
# Join the diagonal with the unitary to be decomposed in the next step
|
|
134
|
+
two_qubit_gates[idx - 1].matrix = diagonal @ two_qubit_gates[idx - 1].matrix
|
|
135
|
+
if len(two_qubit_gates) > 0:
|
|
136
|
+
operations = two_qubit_matrix_to_cz_operations(
|
|
137
|
+
q0,
|
|
138
|
+
q1,
|
|
139
|
+
two_qubit_gates[0].matrix,
|
|
140
|
+
allow_partial_czs=True,
|
|
141
|
+
clean_operations=True,
|
|
142
|
+
atol=atol,
|
|
143
|
+
)
|
|
144
|
+
global_phase = _global_phase_difference(two_qubit_gates[0].matrix, operations)
|
|
145
|
+
if not np.isclose(global_phase, 0, atol=atol):
|
|
146
|
+
operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
|
|
147
|
+
shannon_decomp[two_qubit_gates[0].location] = operations
|
|
148
|
+
# Yield the final operations in order
|
|
149
|
+
yield from cast(Iterable[ops.Operation], ops.flatten_op_tree(shannon_decomp))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _recursive_decomposition(qubits: list[cirq.Qid], u: np.ndarray) -> Iterable[cirq.Operation]:
|
|
153
|
+
"""Recursive step in the quantum shannon decomposition.
|
|
112
154
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
155
|
+
Decomposes n-qubit unitary into generic 2-qubit gates, CNOT, CZ and 1-qubit gates.
|
|
156
|
+
All generic 2-qubit gates are applied to the two least significant qubits and
|
|
157
|
+
are not decomposed further here.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
qubits: List of qubits in order of significance
|
|
161
|
+
u: Numpy array for unitary matrix representing gate to be decomposed
|
|
162
|
+
|
|
163
|
+
Calls:
|
|
164
|
+
1. _msb_demuxer
|
|
165
|
+
2. _multiplexed_cossin
|
|
166
|
+
3. _msb_demuxer
|
|
167
|
+
|
|
168
|
+
Yields:
|
|
169
|
+
Generic 2-qubit gates or operations from {ry,rz,CNOT,CZ}.
|
|
170
|
+
|
|
171
|
+
Raises:
|
|
172
|
+
ValueError: If the u matrix is not of shape (2^n,2^n)
|
|
173
|
+
ValueError: If the u matrix is not of size at least 4
|
|
174
|
+
"""
|
|
175
|
+
n = u.shape[0]
|
|
176
|
+
if n & (n - 1):
|
|
177
|
+
raise ValueError(
|
|
178
|
+
f"Expected input matrix u to be a (2^n x 2^n) shaped numpy array, \
|
|
179
|
+
but instead got shape {u.shape}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
if n <= 2:
|
|
183
|
+
raise ValueError(
|
|
184
|
+
f"Expected input matrix u for recursive step to have size at least 4, \
|
|
185
|
+
but it has size {n}"
|
|
116
186
|
)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
global_phase = np.angle(u[i, j]) - np.angle(new_unitary[i, j])
|
|
121
|
-
if np.abs(global_phase) > 1e-9:
|
|
122
|
-
yield ops.global_phase_operation(np.exp(1j * global_phase))
|
|
187
|
+
|
|
188
|
+
if n == 4:
|
|
189
|
+
yield ops.MatrixGate(u).on(*qubits)
|
|
123
190
|
return
|
|
124
191
|
|
|
125
192
|
# Perform a cosine-sine (linalg) decomposition on u
|
|
@@ -135,11 +202,31 @@ def quantum_shannon_decomposition(
|
|
|
135
202
|
# Yield ops from multiplexed Ry part
|
|
136
203
|
yield from _multiplexed_cossin(qubits, theta, ops.ry)
|
|
137
204
|
|
|
205
|
+
# Optimization A.1 in Shende et al. - the last CZ gate in the multiplexed Ry part
|
|
206
|
+
# is merged into the generic multiplexor (u1, u2)
|
|
207
|
+
# This gate is CZ(qubits[1], qubits[0]) = CZ(qubits[0], qubits[1])
|
|
208
|
+
# as CZ is symmetric.
|
|
209
|
+
# For the u1⊕u2 multiplexor operator:
|
|
210
|
+
# as u1 is the operator in case qubits[0] = |0>,
|
|
211
|
+
# and u2 is the operator in case qubits[0] = |1>
|
|
212
|
+
# we can represent the merge by phasing u2 with Z ⊗ I
|
|
213
|
+
cz_diag = np.concatenate((np.ones(n >> 2), np.full(n >> 2, -1)))
|
|
214
|
+
u2 = u2 @ np.diag(cz_diag)
|
|
215
|
+
|
|
138
216
|
# Yield ops from decomposition of multiplexed u1/u2 part
|
|
139
217
|
yield from _msb_demuxer(qubits, u1, u2)
|
|
140
218
|
|
|
141
219
|
|
|
142
|
-
def
|
|
220
|
+
def _global_phase_difference(u: np.ndarray, ops: list[cirq.Operation]) -> float:
|
|
221
|
+
"""Returns the difference in global phase between unitary u and
|
|
222
|
+
a list of operations computing u.
|
|
223
|
+
"""
|
|
224
|
+
i, j = np.unravel_index(np.argmax(np.abs(u)), u.shape)
|
|
225
|
+
new_unitary = unitary_protocol.unitary(FrozenCircuit.from_moments(*ops))
|
|
226
|
+
return np.angle(u[i, j]) - np.angle(new_unitary[i, j])
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _single_qubit_decomposition(qubit: cirq.Qid, u: np.ndarray) -> Iterable[cirq.Operation]:
|
|
143
230
|
"""Decomposes single-qubit gate, and returns list of operations, keeping phase invariant.
|
|
144
231
|
|
|
145
232
|
Args:
|
|
@@ -183,8 +270,8 @@ def _single_qubit_decomposition(qubit: 'cirq.Qid', u: np.ndarray) -> Iterable['c
|
|
|
183
270
|
|
|
184
271
|
|
|
185
272
|
def _msb_demuxer(
|
|
186
|
-
demux_qubits:
|
|
187
|
-
) -> Iterable[
|
|
273
|
+
demux_qubits: list[cirq.Qid], u1: np.ndarray, u2: np.ndarray
|
|
274
|
+
) -> Iterable[cirq.Operation]:
|
|
188
275
|
"""Demultiplexes a unitary matrix that is multiplexed in its most-significant-qubit.
|
|
189
276
|
|
|
190
277
|
Decomposition structure:
|
|
@@ -200,11 +287,14 @@ def _msb_demuxer(
|
|
|
200
287
|
u2: Lower-right quadrant of total unitary to be decomposed (see diagram)
|
|
201
288
|
|
|
202
289
|
Calls:
|
|
203
|
-
1.
|
|
290
|
+
1. _recursive_decomposition
|
|
204
291
|
2. _multiplexed_cossin
|
|
205
|
-
3.
|
|
292
|
+
3. _recursive_decomposition
|
|
206
293
|
|
|
207
|
-
Yields:
|
|
294
|
+
Yields:
|
|
295
|
+
Generic 2-qubit gates on the two least significant qubits,
|
|
296
|
+
CNOT gates with the target not on the two least significant qubits,
|
|
297
|
+
ry or rz
|
|
208
298
|
"""
|
|
209
299
|
# Perform a diagonalization to find values
|
|
210
300
|
u1 = u1.astype(np.complex128)
|
|
@@ -229,7 +319,7 @@ def _msb_demuxer(
|
|
|
229
319
|
# Last term is given by ( I ⊗ W ), demultiplexed
|
|
230
320
|
# Remove most-significant (demuxed) control-qubit
|
|
231
321
|
# Yield operations for QSD on W
|
|
232
|
-
yield from
|
|
322
|
+
yield from _recursive_decomposition(demux_qubits[1:], W)
|
|
233
323
|
|
|
234
324
|
# Use complex phase of d_i to give theta_i (so d_i* gives -theta_i)
|
|
235
325
|
# Observe that middle part looks like Σ_i( Rz(theta_i)⊗|i><i| )
|
|
@@ -237,7 +327,7 @@ def _msb_demuxer(
|
|
|
237
327
|
yield from _multiplexed_cossin(demux_qubits, -np.angle(d), ops.rz)
|
|
238
328
|
|
|
239
329
|
# Yield operations for QSD on V
|
|
240
|
-
yield from
|
|
330
|
+
yield from _recursive_decomposition(demux_qubits[1:], V)
|
|
241
331
|
|
|
242
332
|
|
|
243
333
|
def _nth_gray(n: int) -> int:
|
|
@@ -246,8 +336,8 @@ def _nth_gray(n: int) -> int:
|
|
|
246
336
|
|
|
247
337
|
|
|
248
338
|
def _multiplexed_cossin(
|
|
249
|
-
cossin_qubits:
|
|
250
|
-
) -> Iterable[
|
|
339
|
+
cossin_qubits: list[cirq.Qid], angles: list[float], rot_func: Callable = ops.ry
|
|
340
|
+
) -> Iterable[cirq.Operation]:
|
|
251
341
|
"""Performs a multiplexed rotation over all qubits in this unitary matrix,
|
|
252
342
|
|
|
253
343
|
Uses ry and rz multiplexing for quantum shannon decomposition
|
|
@@ -261,7 +351,7 @@ def _multiplexed_cossin(
|
|
|
261
351
|
Calls:
|
|
262
352
|
No major calls
|
|
263
353
|
|
|
264
|
-
Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT}
|
|
354
|
+
Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT,CZ}
|
|
265
355
|
"""
|
|
266
356
|
# Most significant qubit is main qubit with rotation function applied
|
|
267
357
|
main_qubit = cossin_qubits[0]
|
|
@@ -302,4 +392,11 @@ def _multiplexed_cossin(
|
|
|
302
392
|
yield rot_func(rotation).on(main_qubit)
|
|
303
393
|
|
|
304
394
|
# Add a CNOT from the select qubit to the main qubit
|
|
305
|
-
|
|
395
|
+
# Optimization A.1 in Shende et al. - use CZ instead of CNOT for ry rotations
|
|
396
|
+
if rot_func == ops.ry:
|
|
397
|
+
# Don't emit the last gate, as it will be merged into the generic multiplexor
|
|
398
|
+
# in the cosine-sine decomposition
|
|
399
|
+
if j < len(angles) - 1:
|
|
400
|
+
yield ops.CZ(control_qubits[select_qubit], main_qubit)
|
|
401
|
+
else:
|
|
402
|
+
yield ops.CNOT(control_qubits[select_qubit], main_qubit)
|
|
@@ -12,16 +12,20 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
import numpy as np
|
|
16
18
|
import pytest
|
|
17
19
|
from scipy.stats import unitary_group
|
|
18
20
|
|
|
19
21
|
import cirq
|
|
20
22
|
from cirq.ops import common_gates
|
|
23
|
+
from cirq.testing import random_two_qubit_circuit_with_czs
|
|
21
24
|
from cirq.transformers.analytical_decompositions.quantum_shannon_decomposition import (
|
|
22
25
|
_msb_demuxer,
|
|
23
26
|
_multiplexed_cossin,
|
|
24
27
|
_nth_gray,
|
|
28
|
+
_recursive_decomposition,
|
|
25
29
|
_single_qubit_decomposition,
|
|
26
30
|
quantum_shannon_decomposition,
|
|
27
31
|
)
|
|
@@ -47,6 +51,14 @@ def test_qsd_n_qubit_errors():
|
|
|
47
51
|
cirq.Circuit(quantum_shannon_decomposition(qubits, np.ones((8, 8))))
|
|
48
52
|
|
|
49
53
|
|
|
54
|
+
def test_recursive_decomposition_n_qubit_errors():
|
|
55
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(3)]
|
|
56
|
+
with pytest.raises(ValueError, match="shaped numpy array"):
|
|
57
|
+
cirq.Circuit(_recursive_decomposition(qubits, np.eye(9)))
|
|
58
|
+
with pytest.raises(ValueError, match="size at least 4"):
|
|
59
|
+
cirq.Circuit(_recursive_decomposition(qubits, np.eye(2)))
|
|
60
|
+
|
|
61
|
+
|
|
50
62
|
def test_random_single_qubit_decomposition():
|
|
51
63
|
U = unitary_group.rvs(2)
|
|
52
64
|
qubit = cirq.NamedQubit('q0')
|
|
@@ -78,10 +90,18 @@ def test_multiplexed_cossin():
|
|
|
78
90
|
multiplexed_ry = np.array(multiplexed_ry)
|
|
79
91
|
qubits = [cirq.NamedQubit(f'q{i}') for i in range(2)]
|
|
80
92
|
circuit = cirq.Circuit(_multiplexed_cossin(qubits, [angle_1, angle_2]))
|
|
93
|
+
# Add back the CZ gate removed by the A.1 optimization
|
|
94
|
+
circuit += cirq.CZ(qubits[1], qubits[0])
|
|
81
95
|
# Test return is equal to inital unitary
|
|
82
96
|
assert cirq.approx_eq(multiplexed_ry, circuit.unitary(), atol=1e-9)
|
|
83
97
|
# Test all operations in gate set
|
|
84
|
-
gates = (
|
|
98
|
+
gates = (
|
|
99
|
+
common_gates.Rz,
|
|
100
|
+
common_gates.Ry,
|
|
101
|
+
common_gates.ZPowGate,
|
|
102
|
+
common_gates.CXPowGate,
|
|
103
|
+
common_gates.CZPowGate,
|
|
104
|
+
)
|
|
85
105
|
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
86
106
|
|
|
87
107
|
|
|
@@ -201,3 +221,17 @@ def test_qft5():
|
|
|
201
221
|
)
|
|
202
222
|
new_unitary = cirq.unitary(shannon_circuit)
|
|
203
223
|
np.testing.assert_allclose(new_unitary, desired_unitary, atol=1e-6)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_random_circuit_decomposition():
|
|
227
|
+
qubits = cirq.LineQubit.range(3)
|
|
228
|
+
test_circuit = (
|
|
229
|
+
random_two_qubit_circuit_with_czs(3, qubits[0], qubits[1])
|
|
230
|
+
+ random_two_qubit_circuit_with_czs(3, qubits[1], qubits[2])
|
|
231
|
+
+ random_two_qubit_circuit_with_czs(3, qubits[0], qubits[2])
|
|
232
|
+
)
|
|
233
|
+
circuit = cirq.Circuit(quantum_shannon_decomposition(qubits, test_circuit.unitary()))
|
|
234
|
+
# Test return is equal to initial unitary
|
|
235
|
+
assert cirq.approx_eq(test_circuit.unitary(), circuit.unitary(), atol=1e-9)
|
|
236
|
+
# Test all operations have at most 2 qubits.
|
|
237
|
+
assert all(cirq.num_qubits(op) <= 2 for op in circuit.all_operations())
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Utility methods related to optimizing quantum circuits."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import math
|
|
18
|
-
from typing import List, Optional, Tuple
|
|
19
20
|
|
|
20
21
|
import numpy as np
|
|
21
22
|
import sympy
|
|
@@ -39,7 +40,7 @@ def _signed_mod_1(x: float) -> float:
|
|
|
39
40
|
|
|
40
41
|
def single_qubit_matrix_to_pauli_rotations(
|
|
41
42
|
mat: np.ndarray, atol: float = 0
|
|
42
|
-
) ->
|
|
43
|
+
) -> list[tuple[ops.Pauli, float]]:
|
|
43
44
|
"""Implements a single-qubit operation with few rotations.
|
|
44
45
|
|
|
45
46
|
Args:
|
|
@@ -98,7 +99,7 @@ def single_qubit_matrix_to_pauli_rotations(
|
|
|
98
99
|
return [(pauli, ht) for pauli, ht in rotation_list if not is_no_turn(ht)]
|
|
99
100
|
|
|
100
101
|
|
|
101
|
-
def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) ->
|
|
102
|
+
def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> list[ops.Gate]:
|
|
102
103
|
"""Implements a single-qubit operation with few gates.
|
|
103
104
|
|
|
104
105
|
Args:
|
|
@@ -114,7 +115,7 @@ def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> List[
|
|
|
114
115
|
return [pauli**ht for pauli, ht in rotations]
|
|
115
116
|
|
|
116
117
|
|
|
117
|
-
def single_qubit_op_to_framed_phase_form(mat: np.ndarray) ->
|
|
118
|
+
def single_qubit_op_to_framed_phase_form(mat: np.ndarray) -> tuple[np.ndarray, complex, complex]:
|
|
118
119
|
"""Decomposes a 2x2 unitary M into U^-1 * diag(1, r) * U * diag(g, g).
|
|
119
120
|
|
|
120
121
|
U translates the rotation axis of M to the Z axis.
|
|
@@ -141,7 +142,7 @@ def single_qubit_op_to_framed_phase_form(mat: np.ndarray) -> Tuple[np.ndarray, c
|
|
|
141
142
|
return u, r, g
|
|
142
143
|
|
|
143
144
|
|
|
144
|
-
def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) ->
|
|
145
|
+
def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> tuple[float, float, float]:
|
|
145
146
|
"""Breaks down a 2x2 unitary into gate parameters.
|
|
146
147
|
|
|
147
148
|
Args:
|
|
@@ -165,7 +166,7 @@ def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> Tuple[f
|
|
|
165
166
|
return (_signed_mod_1(xy_turn), _signed_mod_1(xy_phase_turn), _signed_mod_1(total_z_turn))
|
|
166
167
|
|
|
167
168
|
|
|
168
|
-
def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) ->
|
|
169
|
+
def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> list[ops.Gate]:
|
|
169
170
|
"""Implements a single-qubit operation with a PhasedX and Z gate.
|
|
170
171
|
|
|
171
172
|
If one of the gates isn't needed, it will be omitted.
|
|
@@ -196,7 +197,7 @@ def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> List[
|
|
|
196
197
|
return result
|
|
197
198
|
|
|
198
199
|
|
|
199
|
-
def single_qubit_matrix_to_phxz(mat: np.ndarray, atol: float = 0) ->
|
|
200
|
+
def single_qubit_matrix_to_phxz(mat: np.ndarray, atol: float = 0) -> ops.PhasedXZGate | None:
|
|
200
201
|
"""Implements a single-qubit operation with a PhasedXZ gate.
|
|
201
202
|
|
|
202
203
|
Under the hood, this uses deconstruct_single_qubit_matrix_into_angles which
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""Analytical decompositions for 2-qubit unitaries when one input qubit is in the |0> state."""
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
17
20
|
|
|
18
21
|
import numpy as np
|
|
19
22
|
|
|
@@ -25,13 +28,13 @@ if TYPE_CHECKING:
|
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
def two_qubit_matrix_to_cz_isometry(
|
|
28
|
-
q0:
|
|
29
|
-
q1:
|
|
31
|
+
q0: cirq.Qid,
|
|
32
|
+
q1: cirq.Qid,
|
|
30
33
|
mat: np.ndarray,
|
|
31
34
|
allow_partial_czs: bool = False,
|
|
32
35
|
atol: float = 1e-8,
|
|
33
36
|
clean_operations: bool = True,
|
|
34
|
-
) ->
|
|
37
|
+
) -> list[cirq.Operation]:
|
|
35
38
|
"""Decomposes a 2q operation into at-most 2 CZs + 1q rotations; assuming `q0` is initially |0>.
|
|
36
39
|
|
|
37
40
|
The method implements isometry from one to two qubits; assuming qubit `q0` is always in the |0>
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
14
17
|
import numpy as np
|
|
15
18
|
import pytest
|
|
16
19
|
|
|
@@ -14,9 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
"""Utility methods for decomposing three-qubit unitaries."""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Sequence
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
22
|
+
import scipy.linalg
|
|
20
23
|
|
|
21
24
|
import cirq
|
|
22
25
|
from cirq import ops, transformers as opt
|
|
@@ -24,7 +27,7 @@ from cirq import ops, transformers as opt
|
|
|
24
27
|
|
|
25
28
|
def three_qubit_matrix_to_operations(
|
|
26
29
|
q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, u: np.ndarray, atol: float = 1e-8
|
|
27
|
-
) ->
|
|
30
|
+
) -> list[ops.Operation]:
|
|
28
31
|
"""Returns operations for a 3 qubit unitary.
|
|
29
32
|
|
|
30
33
|
The algorithm is described in Shende et al.:
|
|
@@ -45,24 +48,13 @@ def three_qubit_matrix_to_operations(
|
|
|
45
48
|
|
|
46
49
|
Raises:
|
|
47
50
|
ValueError: If the u matrix is non-unitary or not of shape (8,8).
|
|
48
|
-
ImportError: If the decomposition cannot be done because the SciPy version is less than
|
|
49
|
-
1.5.0 and so does not contain the required `cossin` method.
|
|
50
51
|
"""
|
|
51
52
|
if np.shape(u) != (8, 8):
|
|
52
53
|
raise ValueError(f"Expected unitary matrix with shape (8,8) got {np.shape(u)}")
|
|
53
54
|
if not cirq.is_unitary(u, atol=atol):
|
|
54
55
|
raise ValueError(f"Matrix is not unitary: {u}")
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
from scipy.linalg import cossin
|
|
58
|
-
except ImportError: # pragma: no cover
|
|
59
|
-
raise ImportError(
|
|
60
|
-
"cirq.three_qubit_unitary_to_operations requires "
|
|
61
|
-
"SciPy 1.5.0+, as it uses the cossin function. Please"
|
|
62
|
-
" upgrade scipy in your environment to use this "
|
|
63
|
-
"function!"
|
|
64
|
-
)
|
|
65
|
-
(u1, u2), theta, (v1h, v2h) = cossin(u, 4, 4, separate=True)
|
|
57
|
+
(u1, u2), theta, (v1h, v2h) = scipy.linalg.cossin(u, 4, 4, separate=True)
|
|
66
58
|
|
|
67
59
|
cs_ops = _cs_to_ops(q0, q1, q2, theta)
|
|
68
60
|
if len(cs_ops) > 0 and cs_ops[-1] == cirq.CZ(q2, q0):
|
|
@@ -85,7 +77,7 @@ def three_qubit_matrix_to_operations(
|
|
|
85
77
|
return list(cirq.Circuit(vdh_ops + cs_ops + ud_ops).all_operations())
|
|
86
78
|
|
|
87
79
|
|
|
88
|
-
def _cs_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, theta: np.ndarray) ->
|
|
80
|
+
def _cs_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, theta: np.ndarray) -> list[ops.Operation]:
|
|
89
81
|
"""Converts theta angles based Cosine Sine matrix to operations.
|
|
90
82
|
|
|
91
83
|
Using the optimization as per Appendix A.1, it uses CZ gates instead of
|
|
@@ -124,9 +116,9 @@ def _two_qubit_multiplexor_to_ops(
|
|
|
124
116
|
u1: np.ndarray,
|
|
125
117
|
u2: np.ndarray,
|
|
126
118
|
shift_left: bool = True,
|
|
127
|
-
diagonal:
|
|
119
|
+
diagonal: np.ndarray | None = None,
|
|
128
120
|
atol: float = 1e-8,
|
|
129
|
-
) ->
|
|
121
|
+
) -> tuple[np.ndarray | None, list[ops.Operation]]:
|
|
130
122
|
r"""Converts a two qubit double multiplexor to circuit.
|
|
131
123
|
Input: U_1 ⊕ U_2, with select qubit a (i.e. a = |0> => U_1(b,c),
|
|
132
124
|
a = |1> => U_2(b,c).
|
|
@@ -185,7 +177,7 @@ def _two_qubit_multiplexor_to_ops(
|
|
|
185
177
|
|
|
186
178
|
w = d_v @ w
|
|
187
179
|
|
|
188
|
-
d_w:
|
|
180
|
+
d_w: np.ndarray | None
|
|
189
181
|
|
|
190
182
|
# if it's interesting to extract the diagonal then let's do it
|
|
191
183
|
if shift_left:
|
|
@@ -258,7 +250,7 @@ def _middle_multiplexor_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, eigvals: n
|
|
|
258
250
|
return _optimize_multiplexed_angles_circuit(ops)
|
|
259
251
|
|
|
260
252
|
|
|
261
|
-
def _multiplexed_angles(theta:
|
|
253
|
+
def _multiplexed_angles(theta: Sequence[float] | np.ndarray) -> np.ndarray:
|
|
262
254
|
"""Calculates the angles for a 4-way multiplexed rotation.
|
|
263
255
|
|
|
264
256
|
For example, if we want rz(theta[i]) if the select qubits are in state
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from random import random
|
|
16
|
-
from typing import Callable
|
|
17
18
|
|
|
18
19
|
import numpy as np
|
|
19
20
|
import pytest
|
|
@@ -29,20 +30,6 @@ from cirq.transformers.analytical_decompositions.three_qubit_decomposition impor
|
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
def _skip_if_scipy(*, version_is_greater_than_1_5_0: bool) -> Callable[[Callable], Callable]:
|
|
33
|
-
def decorator(func): # pragma: no cover
|
|
34
|
-
try:
|
|
35
|
-
# pylint: disable=unused-import
|
|
36
|
-
from scipy.linalg import cossin
|
|
37
|
-
|
|
38
|
-
return None if version_is_greater_than_1_5_0 else func
|
|
39
|
-
except ImportError:
|
|
40
|
-
return func if version_is_greater_than_1_5_0 else None
|
|
41
|
-
|
|
42
|
-
return decorator
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@_skip_if_scipy(version_is_greater_than_1_5_0=False)
|
|
46
33
|
@pytest.mark.parametrize(
|
|
47
34
|
"u",
|
|
48
35
|
[
|
|
@@ -52,7 +39,7 @@ def _skip_if_scipy(*, version_is_greater_than_1_5_0: bool) -> Callable[[Callable
|
|
|
52
39
|
cirq.CCX._unitary_(),
|
|
53
40
|
],
|
|
54
41
|
)
|
|
55
|
-
def test_three_qubit_matrix_to_operations(u):
|
|
42
|
+
def test_three_qubit_matrix_to_operations(u) -> None:
|
|
56
43
|
a, b, c = cirq.LineQubit.range(3)
|
|
57
44
|
operations = cirq.three_qubit_matrix_to_operations(a, b, c, u)
|
|
58
45
|
final_circuit = cirq.Circuit(operations)
|
|
@@ -68,8 +55,7 @@ def test_three_qubit_matrix_to_operations(u):
|
|
|
68
55
|
assert num_two_qubit_gates <= 20, f"expected at most 20 CZ/CNOTs got {num_two_qubit_gates}"
|
|
69
56
|
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
def test_three_qubit_matrix_to_operations_errors():
|
|
58
|
+
def test_three_qubit_matrix_to_operations_errors() -> None:
|
|
73
59
|
a, b, c = cirq.LineQubit.range(3)
|
|
74
60
|
with pytest.raises(ValueError, match="(8,8)"):
|
|
75
61
|
cirq.three_qubit_matrix_to_operations(a, b, c, np.eye(2))
|
|
@@ -77,17 +63,6 @@ def test_three_qubit_matrix_to_operations_errors():
|
|
|
77
63
|
cirq.three_qubit_matrix_to_operations(a, b, c, cirq.unitary(cirq.CCX) * 2)
|
|
78
64
|
|
|
79
65
|
|
|
80
|
-
# on environments with scipy <1.5.0 this will not be sufficient to cover the
|
|
81
|
-
# full three_qubit_matrix_to_operations method. In case we ever introduce a CI
|
|
82
|
-
# environment like that, we'll need to ignore the coverage somehow conditionally on
|
|
83
|
-
# the scipy version.
|
|
84
|
-
@_skip_if_scipy(version_is_greater_than_1_5_0=True)
|
|
85
|
-
def test_three_qubit_matrix_to_operations_scipy_error(): # pragma: no cover
|
|
86
|
-
a, b, c = cirq.LineQubit.range(3)
|
|
87
|
-
with pytest.raises(ImportError, match="three_qubit.*1.5.0+"):
|
|
88
|
-
cirq.three_qubit_matrix_to_operations(a, b, c, np.eye(8))
|
|
89
|
-
|
|
90
|
-
|
|
91
66
|
@pytest.mark.parametrize(
|
|
92
67
|
["theta", "num_czs"],
|
|
93
68
|
[
|
|
@@ -100,7 +75,7 @@ def test_three_qubit_matrix_to_operations_scipy_error(): # pragma: no cover
|
|
|
100
75
|
(np.array([0.3, 0.3, -0.3, -0.3]), 2),
|
|
101
76
|
],
|
|
102
77
|
)
|
|
103
|
-
def test_cs_to_ops(theta, num_czs):
|
|
78
|
+
def test_cs_to_ops(theta, num_czs) -> None:
|
|
104
79
|
a, b, c = cirq.LineQubit.range(3)
|
|
105
80
|
cs = _theta_to_cs(theta)
|
|
106
81
|
circuit_cs = cirq.Circuit(_cs_to_ops(a, b, c, theta))
|
|
@@ -126,7 +101,7 @@ def _theta_to_cs(theta: np.ndarray) -> np.ndarray:
|
|
|
126
101
|
return np.block([[c, -s], [s, c]])
|
|
127
102
|
|
|
128
103
|
|
|
129
|
-
def test_multiplexed_angles():
|
|
104
|
+
def test_multiplexed_angles() -> None:
|
|
130
105
|
theta = [random() * np.pi, random() * np.pi, random() * np.pi, random() * np.pi]
|
|
131
106
|
|
|
132
107
|
angles = _multiplexed_angles(theta)
|
|
@@ -190,7 +165,7 @@ def test_multiplexed_angles():
|
|
|
190
165
|
[([-0.3, 0.3, -0.3, -0.3]), 4],
|
|
191
166
|
],
|
|
192
167
|
)
|
|
193
|
-
def test_middle_multiplexor(angles, num_cnots):
|
|
168
|
+
def test_middle_multiplexor(angles, num_cnots) -> None:
|
|
194
169
|
a, b, c = cirq.LineQubit.range(3)
|
|
195
170
|
eigvals = np.exp(np.array(angles) * np.pi * 1j)
|
|
196
171
|
d = np.diag(np.sqrt(eigvals))
|
|
@@ -212,7 +187,7 @@ def test_middle_multiplexor(angles, num_cnots):
|
|
|
212
187
|
|
|
213
188
|
|
|
214
189
|
@pytest.mark.parametrize("shift_left", [True, False])
|
|
215
|
-
def test_two_qubit_multiplexor_to_circuit(shift_left):
|
|
190
|
+
def test_two_qubit_multiplexor_to_circuit(shift_left) -> None:
|
|
216
191
|
a, b, c = cirq.LineQubit.range(3)
|
|
217
192
|
u1 = cirq.testing.random_unitary(4)
|
|
218
193
|
u2 = cirq.testing.random_unitary(4)
|