cirq-core 1.5.0.dev20250409225226__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.dev20250409225226.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.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
- cirq_core-1.5.0.dev20250409225226.dist-info/RECORD +0 -1216
- {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
|
@@ -12,9 +12,11 @@
|
|
|
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 itertools
|
|
16
18
|
from collections import defaultdict
|
|
17
|
-
from typing import Any, cast,
|
|
19
|
+
from typing import Any, cast, Iterable, Sequence, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
20
22
|
|
|
@@ -33,7 +35,7 @@ class _MeasurementQid(ops.Qid):
|
|
|
33
35
|
Exactly one qubit will be created per qubit in the measurement gate.
|
|
34
36
|
"""
|
|
35
37
|
|
|
36
|
-
def __init__(self, key:
|
|
38
|
+
def __init__(self, key: str | cirq.MeasurementKey, qid: cirq.Qid, index: int = 0):
|
|
37
39
|
"""Initializes the qubit.
|
|
38
40
|
|
|
39
41
|
Args:
|
|
@@ -63,8 +65,8 @@ class _MeasurementQid(ops.Qid):
|
|
|
63
65
|
|
|
64
66
|
@transformer_api.transformer
|
|
65
67
|
def defer_measurements(
|
|
66
|
-
circuit:
|
|
67
|
-
) ->
|
|
68
|
+
circuit: cirq.AbstractCircuit, *, context: cirq.TransformerContext | None = None
|
|
69
|
+
) -> cirq.Circuit:
|
|
68
70
|
"""Implements the Deferred Measurement Principle.
|
|
69
71
|
|
|
70
72
|
Uses the Deferred Measurement Principle to move all measurements to the
|
|
@@ -94,11 +96,9 @@ def defer_measurements(
|
|
|
94
96
|
|
|
95
97
|
circuit = transformer_primitives.unroll_circuit_op(circuit, deep=True, tags_to_check=None)
|
|
96
98
|
terminal_measurements = {op for _, op in find_terminal_measurements(circuit)}
|
|
97
|
-
measurement_qubits:
|
|
98
|
-
list
|
|
99
|
-
)
|
|
99
|
+
measurement_qubits: dict[cirq.MeasurementKey, list[tuple[cirq.Qid, ...]]] = defaultdict(list)
|
|
100
100
|
|
|
101
|
-
def defer(op:
|
|
101
|
+
def defer(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
102
102
|
if op in terminal_measurements:
|
|
103
103
|
return op
|
|
104
104
|
gate = op.gate
|
|
@@ -169,10 +169,10 @@ def defer_measurements(
|
|
|
169
169
|
|
|
170
170
|
|
|
171
171
|
def _all_possible_datastore_states(
|
|
172
|
-
keys: Iterable[
|
|
173
|
-
measurement_qubits:
|
|
174
|
-
) -> Iterable[
|
|
175
|
-
"""The
|
|
172
|
+
keys: Iterable[tuple[cirq.MeasurementKey, int]],
|
|
173
|
+
measurement_qubits: dict[cirq.MeasurementKey, list[tuple[cirq.Qid, ...]]],
|
|
174
|
+
) -> Iterable[cirq.ClassicalDataStoreReader]:
|
|
175
|
+
"""The Cartesian product of all possible DataStore states for the given keys."""
|
|
176
176
|
# First we get the list of all possible values. So if we have a key mapped to qubits of shape
|
|
177
177
|
# (2, 2) and a key mapped to a qutrit, the possible measurement values are:
|
|
178
178
|
# [((0, 0), (0,)),
|
|
@@ -214,10 +214,10 @@ def _all_possible_datastore_states(
|
|
|
214
214
|
|
|
215
215
|
@transformer_api.transformer
|
|
216
216
|
def dephase_measurements(
|
|
217
|
-
circuit:
|
|
217
|
+
circuit: cirq.AbstractCircuit,
|
|
218
218
|
*,
|
|
219
|
-
context:
|
|
220
|
-
) ->
|
|
219
|
+
context: cirq.TransformerContext | None = transformer_api.TransformerContext(deep=True),
|
|
220
|
+
) -> cirq.Circuit:
|
|
221
221
|
"""Changes all measurements to a dephase operation.
|
|
222
222
|
|
|
223
223
|
This transformer is useful when using a density matrix simulator, when
|
|
@@ -240,7 +240,7 @@ def dephase_measurements(
|
|
|
240
240
|
surprises.
|
|
241
241
|
"""
|
|
242
242
|
|
|
243
|
-
def dephase(op:
|
|
243
|
+
def dephase(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
244
244
|
gate = op.gate
|
|
245
245
|
if isinstance(gate, ops.MeasurementGate):
|
|
246
246
|
key = value.MeasurementKey.parse_serialized(gate.key)
|
|
@@ -257,10 +257,10 @@ def dephase_measurements(
|
|
|
257
257
|
|
|
258
258
|
@transformer_api.transformer
|
|
259
259
|
def drop_terminal_measurements(
|
|
260
|
-
circuit:
|
|
260
|
+
circuit: cirq.AbstractCircuit,
|
|
261
261
|
*,
|
|
262
|
-
context:
|
|
263
|
-
) ->
|
|
262
|
+
context: cirq.TransformerContext | None = transformer_api.TransformerContext(deep=True),
|
|
263
|
+
) -> cirq.Circuit:
|
|
264
264
|
"""Removes terminal measurements from a circuit.
|
|
265
265
|
|
|
266
266
|
This transformer is helpful when trying to capture the final state vector
|
|
@@ -289,7 +289,7 @@ def drop_terminal_measurements(
|
|
|
289
289
|
if not circuit.are_all_measurements_terminal():
|
|
290
290
|
raise ValueError('Circuit contains a non-terminal measurement.')
|
|
291
291
|
|
|
292
|
-
def flip_inversion(op:
|
|
292
|
+
def flip_inversion(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
293
293
|
if isinstance(op.gate, ops.MeasurementGate):
|
|
294
294
|
return [
|
|
295
295
|
(
|
|
@@ -426,20 +426,20 @@ class _ConfusionChannel(ops.Gate):
|
|
|
426
426
|
self._confusion_map = confusion_map.copy()
|
|
427
427
|
self._kraus = tuple(kraus)
|
|
428
428
|
|
|
429
|
-
def _qid_shape_(self) ->
|
|
429
|
+
def _qid_shape_(self) -> tuple[int, ...]:
|
|
430
430
|
return self._shape
|
|
431
431
|
|
|
432
|
-
def _kraus_(self) ->
|
|
432
|
+
def _kraus_(self) -> tuple[np.ndarray, ...]:
|
|
433
433
|
return self._kraus
|
|
434
434
|
|
|
435
|
-
def _apply_channel_(self, args:
|
|
436
|
-
configs:
|
|
435
|
+
def _apply_channel_(self, args: cirq.ApplyChannelArgs):
|
|
436
|
+
configs: list[transformations._BuildFromSlicesArgs] = []
|
|
437
437
|
for i in range(np.prod(self._shape) ** 2):
|
|
438
438
|
scale = cast(complex, self._confusion_map.flat[i])
|
|
439
439
|
if scale == 0:
|
|
440
440
|
continue
|
|
441
441
|
index: Any = np.unravel_index(i, self._shape * 2)
|
|
442
|
-
slices:
|
|
442
|
+
slices: list[transformations._SliceConfig] = []
|
|
443
443
|
axis_count = len(args.left_axes)
|
|
444
444
|
for j in range(axis_count):
|
|
445
445
|
s1 = transformations._SliceConfig(
|
|
@@ -469,20 +469,20 @@ class _ModAdd(ops.ArithmeticGate):
|
|
|
469
469
|
def __init__(self, dimension: int):
|
|
470
470
|
self._dimension = dimension
|
|
471
471
|
|
|
472
|
-
def registers(self) ->
|
|
472
|
+
def registers(self) -> tuple[tuple[int], tuple[int]]:
|
|
473
473
|
return (self._dimension,), (self._dimension,)
|
|
474
474
|
|
|
475
|
-
def with_registers(self, *new_registers) ->
|
|
475
|
+
def with_registers(self, *new_registers) -> _ModAdd:
|
|
476
476
|
raise NotImplementedError()
|
|
477
477
|
|
|
478
|
-
def apply(self, *register_values: int) ->
|
|
478
|
+
def apply(self, *register_values: int) -> tuple[int, int]:
|
|
479
479
|
return register_values[0], sum(register_values)
|
|
480
480
|
|
|
481
481
|
def _value_equality_values_(self) -> int:
|
|
482
482
|
return self._dimension
|
|
483
483
|
|
|
484
484
|
|
|
485
|
-
def _mod_add(source:
|
|
485
|
+
def _mod_add(source: cirq.Qid, target: cirq.Qid) -> cirq.Operation:
|
|
486
486
|
assert source.dimension == target.dimension
|
|
487
487
|
if source.dimension == 2:
|
|
488
488
|
# Use a CX gate in 2D case for simplicity.
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to merge connected components of k-qubit unitary operations."""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Callable, cast, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, ops, protocols
|
|
20
22
|
from cirq.transformers import transformer_api, transformer_primitives
|
|
@@ -24,16 +26,16 @@ if TYPE_CHECKING:
|
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def _rewrite_merged_k_qubit_unitaries(
|
|
27
|
-
circuit:
|
|
29
|
+
circuit: cirq.AbstractCircuit,
|
|
28
30
|
*,
|
|
29
|
-
context:
|
|
31
|
+
context: cirq.TransformerContext | None = None,
|
|
30
32
|
k: int = 0,
|
|
31
|
-
rewriter:
|
|
33
|
+
rewriter: Callable[[cirq.CircuitOperation], cirq.OP_TREE] | None = None,
|
|
32
34
|
merged_circuit_op_tag: str = "_merged_k_qubit_unitaries_component",
|
|
33
|
-
) ->
|
|
35
|
+
) -> cirq.Circuit:
|
|
34
36
|
deep = context.deep if context else False
|
|
35
37
|
|
|
36
|
-
def map_func(op:
|
|
38
|
+
def map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
37
39
|
op_untagged = op.untagged
|
|
38
40
|
if (
|
|
39
41
|
deep
|
|
@@ -66,12 +68,12 @@ def _rewrite_merged_k_qubit_unitaries(
|
|
|
66
68
|
|
|
67
69
|
@transformer_api.transformer
|
|
68
70
|
def merge_k_qubit_unitaries(
|
|
69
|
-
circuit:
|
|
71
|
+
circuit: cirq.AbstractCircuit,
|
|
70
72
|
*,
|
|
71
|
-
context:
|
|
73
|
+
context: cirq.TransformerContext | None = None,
|
|
72
74
|
k: int = 0,
|
|
73
|
-
rewriter:
|
|
74
|
-
) ->
|
|
75
|
+
rewriter: Callable[[cirq.CircuitOperation], cirq.OP_TREE] | None = None,
|
|
76
|
+
) -> cirq.Circuit:
|
|
75
77
|
"""Merges connected components of unitary operations, acting on <= k qubits.
|
|
76
78
|
|
|
77
79
|
Uses rewriter to convert a connected component of unitary operations acting on <= k-qubits
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from typing import List
|
|
15
|
+
from __future__ import annotations
|
|
18
16
|
|
|
19
17
|
import numpy as np
|
|
20
18
|
import pytest
|
|
@@ -24,7 +22,7 @@ import cirq
|
|
|
24
22
|
|
|
25
23
|
def assert_optimizes(optimized: cirq.AbstractCircuit, expected: cirq.AbstractCircuit):
|
|
26
24
|
# Ignore differences that would be caught by follow-up optimizations.
|
|
27
|
-
followup_transformers:
|
|
25
|
+
followup_transformers: list[cirq.TRANSFORMER] = [
|
|
28
26
|
cirq.drop_negligible_operations,
|
|
29
27
|
cirq.drop_empty_moments,
|
|
30
28
|
]
|
|
@@ -35,7 +33,7 @@ def assert_optimizes(optimized: cirq.AbstractCircuit, expected: cirq.AbstractCir
|
|
|
35
33
|
cirq.testing.assert_same_circuits(optimized, expected)
|
|
36
34
|
|
|
37
35
|
|
|
38
|
-
def test_merge_1q_unitaries():
|
|
36
|
+
def test_merge_1q_unitaries() -> None:
|
|
39
37
|
q, q2 = cirq.LineQubit.range(2)
|
|
40
38
|
# 1. Combines trivial 1q sequence.
|
|
41
39
|
c = cirq.Circuit(cirq.X(q) ** 0.5, cirq.Z(q) ** 0.5, cirq.X(q) ** -0.5)
|
|
@@ -55,7 +53,7 @@ def test_merge_1q_unitaries():
|
|
|
55
53
|
assert isinstance(c[-1][q].gate, cirq.MatrixGate)
|
|
56
54
|
|
|
57
55
|
|
|
58
|
-
def test_respects_nocompile_tags():
|
|
56
|
+
def test_respects_nocompile_tags() -> None:
|
|
59
57
|
q = cirq.NamedQubit("q")
|
|
60
58
|
c = cirq.Circuit(
|
|
61
59
|
[cirq.Z(q), cirq.H(q), cirq.X(q), cirq.H(q), cirq.X(q).with_tags("nocompile"), cirq.H(q)]
|
|
@@ -68,12 +66,12 @@ def test_respects_nocompile_tags():
|
|
|
68
66
|
assert isinstance(c[-1][q].gate, cirq.MatrixGate)
|
|
69
67
|
|
|
70
68
|
|
|
71
|
-
def test_ignores_2qubit_target():
|
|
69
|
+
def test_ignores_2qubit_target() -> None:
|
|
72
70
|
c = cirq.Circuit(cirq.CZ(*cirq.LineQubit.range(2)))
|
|
73
71
|
assert_optimizes(optimized=cirq.merge_k_qubit_unitaries(c, k=1), expected=c)
|
|
74
72
|
|
|
75
73
|
|
|
76
|
-
def test_ignore_unsupported_gate():
|
|
74
|
+
def test_ignore_unsupported_gate() -> None:
|
|
77
75
|
class UnsupportedExample(cirq.testing.SingleQubitGate):
|
|
78
76
|
pass
|
|
79
77
|
|
|
@@ -81,7 +79,7 @@ def test_ignore_unsupported_gate():
|
|
|
81
79
|
assert_optimizes(optimized=cirq.merge_k_qubit_unitaries(c, k=1), expected=c)
|
|
82
80
|
|
|
83
81
|
|
|
84
|
-
def test_1q_rewrite():
|
|
82
|
+
def test_1q_rewrite() -> None:
|
|
85
83
|
q0, q1 = cirq.LineQubit.range(2)
|
|
86
84
|
circuit = cirq.Circuit(
|
|
87
85
|
cirq.X(q0), cirq.Y(q0), cirq.X(q1), cirq.CZ(q0, q1), cirq.Y(q1), cirq.measure(q0, q1)
|
|
@@ -96,12 +94,12 @@ def test_1q_rewrite():
|
|
|
96
94
|
)
|
|
97
95
|
|
|
98
96
|
|
|
99
|
-
def test_merge_k_qubit_unitaries_raises():
|
|
97
|
+
def test_merge_k_qubit_unitaries_raises() -> None:
|
|
100
98
|
with pytest.raises(ValueError, match="k should be greater than or equal to 1"):
|
|
101
99
|
_ = cirq.merge_k_qubit_unitaries(cirq.Circuit())
|
|
102
100
|
|
|
103
101
|
|
|
104
|
-
def test_merge_complex_circuit_preserving_moment_structure():
|
|
102
|
+
def test_merge_complex_circuit_preserving_moment_structure() -> None:
|
|
105
103
|
q = cirq.LineQubit.range(3)
|
|
106
104
|
c_orig = cirq.Circuit(
|
|
107
105
|
cirq.Moment(cirq.H.on_each(*q)),
|
|
@@ -133,7 +131,7 @@ a: ═════════════════════════
|
|
|
133
131
|
)
|
|
134
132
|
component_id = 0
|
|
135
133
|
|
|
136
|
-
def rewriter_merge_to_circuit_op(op:
|
|
134
|
+
def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
137
135
|
nonlocal component_id
|
|
138
136
|
component_id = component_id + 1
|
|
139
137
|
return op.with_tags(f'{component_id}')
|
|
@@ -155,12 +153,13 @@ a: ═════════════════════════
|
|
|
155
153
|
│ │ ║
|
|
156
154
|
2: ───#2──────────────────────────────────────────────────────────────────X───────────[ 2: ───Z─── ][3]───M───────────────────────╫───
|
|
157
155
|
║ ║
|
|
158
|
-
a: ═══════════════════════════════════════════════════════════════════════════════════════════════════════@═══════════════════════^═══
|
|
156
|
+
a: ═══════════════════════════════════════════════════════════════════════════════════════════════════════@═══════════════════════^═══
|
|
157
|
+
''', # noqa: E501
|
|
159
158
|
)
|
|
160
159
|
|
|
161
160
|
component_id = 0
|
|
162
161
|
|
|
163
|
-
def rewriter_replace_with_decomp(op:
|
|
162
|
+
def rewriter_replace_with_decomp(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
164
163
|
nonlocal component_id
|
|
165
164
|
component_id = component_id + 1
|
|
166
165
|
tag = f'{component_id}'
|
|
@@ -185,11 +184,12 @@ a: ═════════════════════════
|
|
|
185
184
|
│ │ ║
|
|
186
185
|
2: ───T[1]───iSwap^0.5───T[1]─────────────────────────────X───────────T[3]────────M─────────────────────────╫───
|
|
187
186
|
║ ║
|
|
188
|
-
a: ═══════════════════════════════════════════════════════════════════════════════@═════════════════════════^═══
|
|
187
|
+
a: ═══════════════════════════════════════════════════════════════════════════════@═════════════════════════^═══
|
|
188
|
+
''', # noqa: E501
|
|
189
189
|
)
|
|
190
190
|
|
|
191
191
|
|
|
192
|
-
def test_merge_k_qubit_unitaries_deep():
|
|
192
|
+
def test_merge_k_qubit_unitaries_deep() -> None:
|
|
193
193
|
q = cirq.LineQubit.range(2)
|
|
194
194
|
h_cz_y = [cirq.H(q[0]), cirq.CZ(*q), cirq.Y(q[1])]
|
|
195
195
|
c_orig = cirq.Circuit(
|
|
@@ -220,7 +220,7 @@ def test_merge_k_qubit_unitaries_deep():
|
|
|
220
220
|
|
|
221
221
|
component_id = 0
|
|
222
222
|
|
|
223
|
-
def rewriter_merge_to_circuit_op(op:
|
|
223
|
+
def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
224
224
|
nonlocal component_id
|
|
225
225
|
component_id = component_id + 1
|
|
226
226
|
return op.with_tags(f'{component_id}')
|
|
@@ -251,7 +251,7 @@ def test_merge_k_qubit_unitaries_deep():
|
|
|
251
251
|
cirq.testing.assert_same_circuits(c_new_matrix, c_expected_matrix)
|
|
252
252
|
|
|
253
253
|
|
|
254
|
-
def test_merge_k_qubit_unitaries_deep_recurses_on_large_circuit_op():
|
|
254
|
+
def test_merge_k_qubit_unitaries_deep_recurses_on_large_circuit_op() -> None:
|
|
255
255
|
q = cirq.LineQubit.range(2)
|
|
256
256
|
c_orig = cirq.Circuit(
|
|
257
257
|
cirq.CircuitOperation(cirq.FrozenCircuit(cirq.X(q[0]), cirq.H(q[0]), cirq.CNOT(*q)))
|
|
@@ -14,23 +14,36 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer passes to combine adjacent single-qubit rotations."""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Callable, cast, Hashable, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, ops, protocols
|
|
20
|
-
from cirq.
|
|
22
|
+
from cirq.study.resolver import ParamResolver
|
|
23
|
+
from cirq.study.sweeps import dict_to_zip_sweep, ListSweep, ProductOrZipSweepLike, Sweep, Zip
|
|
24
|
+
from cirq.transformers import (
|
|
25
|
+
align,
|
|
26
|
+
merge_k_qubit_gates,
|
|
27
|
+
symbolize,
|
|
28
|
+
tag_transformers,
|
|
29
|
+
transformer_api,
|
|
30
|
+
transformer_primitives,
|
|
31
|
+
)
|
|
21
32
|
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
22
33
|
|
|
23
34
|
if TYPE_CHECKING:
|
|
35
|
+
import sympy
|
|
36
|
+
|
|
24
37
|
import cirq
|
|
25
38
|
|
|
26
39
|
|
|
27
40
|
@transformer_api.transformer
|
|
28
41
|
def merge_single_qubit_gates_to_phased_x_and_z(
|
|
29
|
-
circuit:
|
|
42
|
+
circuit: cirq.AbstractCircuit,
|
|
30
43
|
*,
|
|
31
|
-
context:
|
|
44
|
+
context: cirq.TransformerContext | None = None,
|
|
32
45
|
atol: float = 1e-8,
|
|
33
|
-
) ->
|
|
46
|
+
) -> cirq.Circuit:
|
|
34
47
|
"""Replaces runs of single qubit rotations with `cirq.PhasedXPowGate` and `cirq.ZPowGate`.
|
|
35
48
|
|
|
36
49
|
Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
|
|
@@ -46,7 +59,7 @@ def merge_single_qubit_gates_to_phased_x_and_z(
|
|
|
46
59
|
Copy of the transformed input circuit.
|
|
47
60
|
"""
|
|
48
61
|
|
|
49
|
-
def rewriter(op:
|
|
62
|
+
def rewriter(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
50
63
|
u = protocols.unitary(op)
|
|
51
64
|
if protocols.num_qubits(op) == 0:
|
|
52
65
|
return ops.GlobalPhaseGate(u[0, 0]).on()
|
|
@@ -62,11 +75,12 @@ def merge_single_qubit_gates_to_phased_x_and_z(
|
|
|
62
75
|
|
|
63
76
|
@transformer_api.transformer
|
|
64
77
|
def merge_single_qubit_gates_to_phxz(
|
|
65
|
-
circuit:
|
|
78
|
+
circuit: cirq.AbstractCircuit,
|
|
66
79
|
*,
|
|
67
|
-
context:
|
|
80
|
+
context: cirq.TransformerContext | None = None,
|
|
81
|
+
merge_tags_fn: Callable[[cirq.CircuitOperation], list[Hashable]] | None = None,
|
|
68
82
|
atol: float = 1e-8,
|
|
69
|
-
) ->
|
|
83
|
+
) -> cirq.Circuit:
|
|
70
84
|
"""Replaces runs of single qubit rotations with a single optional `cirq.PhasedXZGate`.
|
|
71
85
|
|
|
72
86
|
Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
|
|
@@ -75,6 +89,7 @@ def merge_single_qubit_gates_to_phxz(
|
|
|
75
89
|
Args:
|
|
76
90
|
circuit: Input circuit to transform. It will not be modified.
|
|
77
91
|
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
92
|
+
merge_tags_fn: A callable returns the tags to be added to the merged operation.
|
|
78
93
|
atol: Absolute tolerance to angle error. Larger values allow more negligible gates to be
|
|
79
94
|
dropped, smaller values increase accuracy.
|
|
80
95
|
|
|
@@ -82,12 +97,13 @@ def merge_single_qubit_gates_to_phxz(
|
|
|
82
97
|
Copy of the transformed input circuit.
|
|
83
98
|
"""
|
|
84
99
|
|
|
85
|
-
def rewriter(
|
|
86
|
-
u = protocols.unitary(
|
|
87
|
-
if protocols.num_qubits(
|
|
100
|
+
def rewriter(circuit_op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
101
|
+
u = protocols.unitary(circuit_op)
|
|
102
|
+
if protocols.num_qubits(circuit_op) == 0:
|
|
88
103
|
return ops.GlobalPhaseGate(u[0, 0]).on()
|
|
89
|
-
gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(u, atol)
|
|
90
|
-
|
|
104
|
+
gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(u, atol) or ops.I
|
|
105
|
+
phxz_op = gate.on(circuit_op.qubits[0])
|
|
106
|
+
return phxz_op.with_tags(*merge_tags_fn(circuit_op)) if merge_tags_fn else phxz_op
|
|
91
107
|
|
|
92
108
|
return merge_k_qubit_gates.merge_k_qubit_unitaries(
|
|
93
109
|
circuit, k=1, context=context, rewriter=rewriter
|
|
@@ -96,11 +112,11 @@ def merge_single_qubit_gates_to_phxz(
|
|
|
96
112
|
|
|
97
113
|
@transformer_api.transformer
|
|
98
114
|
def merge_single_qubit_moments_to_phxz(
|
|
99
|
-
circuit:
|
|
115
|
+
circuit: cirq.AbstractCircuit,
|
|
100
116
|
*,
|
|
101
|
-
context:
|
|
117
|
+
context: cirq.TransformerContext | None = None,
|
|
102
118
|
atol: float = 1e-8,
|
|
103
|
-
) ->
|
|
119
|
+
) -> cirq.Circuit:
|
|
104
120
|
"""Merges adjacent moments with only 1-qubit rotations to a single moment with PhasedXZ gates.
|
|
105
121
|
|
|
106
122
|
Args:
|
|
@@ -114,15 +130,15 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
114
130
|
"""
|
|
115
131
|
tags_to_ignore = set(context.tags_to_ignore) if context else set()
|
|
116
132
|
|
|
117
|
-
def can_merge_moment(m:
|
|
133
|
+
def can_merge_moment(m: cirq.Moment):
|
|
118
134
|
return all(
|
|
119
|
-
protocols.num_qubits(op)
|
|
135
|
+
protocols.num_qubits(op) <= 1
|
|
120
136
|
and protocols.has_unitary(op)
|
|
121
137
|
and tags_to_ignore.isdisjoint(op.tags)
|
|
122
138
|
for op in m
|
|
123
139
|
)
|
|
124
140
|
|
|
125
|
-
def merge_func(m1:
|
|
141
|
+
def merge_func(m1: cirq.Moment, m2: cirq.Moment) -> cirq.Moment | None:
|
|
126
142
|
if not (can_merge_moment(m1) and can_merge_moment(m2)):
|
|
127
143
|
return None
|
|
128
144
|
ret_ops = []
|
|
@@ -144,6 +160,10 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
144
160
|
)
|
|
145
161
|
if gate:
|
|
146
162
|
ret_ops.append(gate(q))
|
|
163
|
+
# Transfer global phase
|
|
164
|
+
for op in m1.operations + m2.operations:
|
|
165
|
+
if protocols.num_qubits(op) == 0:
|
|
166
|
+
ret_ops.append(op)
|
|
147
167
|
return circuits.Moment(ret_ops)
|
|
148
168
|
|
|
149
169
|
return transformer_primitives.merge_moments(
|
|
@@ -152,3 +172,160 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
152
172
|
deep=context.deep if context else False,
|
|
153
173
|
tags_to_ignore=tuple(tags_to_ignore),
|
|
154
174
|
).unfreeze(copy=False)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _sweep_on_symbols(sweep: Sweep, symbols: set[sympy.Symbol]) -> Sweep:
|
|
178
|
+
new_resolvers: list[cirq.ParamResolver] = []
|
|
179
|
+
for resolver in sweep:
|
|
180
|
+
param_dict: cirq.ParamMappingType = {s: resolver.value_of(s) for s in symbols}
|
|
181
|
+
new_resolvers.append(ParamResolver(param_dict))
|
|
182
|
+
return ListSweep(new_resolvers)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _calc_phxz_sweeps(
|
|
186
|
+
symbolized_circuit: cirq.Circuit, resolved_circuits: list[cirq.Circuit]
|
|
187
|
+
) -> Sweep:
|
|
188
|
+
"""Returns the phxz sweep of the symbolized_circuit on resolved_circuits.
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ValueError: Structural mismatch: A `resolved_circuit` contains an unexpected gate type.
|
|
192
|
+
Expected a `PhasedXZGate` or `IdentityGate` at a position corresponding to a
|
|
193
|
+
symbolic `PhasedXZGate` in the `symbolized_circuit`.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def _extract_axz(op: ops.Operation | None) -> tuple[float, float, float]:
|
|
197
|
+
if not op or not op.gate or not isinstance(op.gate, ops.IdentityGate | ops.PhasedXZGate):
|
|
198
|
+
raise ValueError(f"Expect a PhasedXZGate or IdentityGate on op {op}.")
|
|
199
|
+
if isinstance(op.gate, ops.IdentityGate):
|
|
200
|
+
return 0.0, 0.0, 0.0 # Identity gate's a, x, z in PhasedXZ
|
|
201
|
+
return op.gate.axis_phase_exponent, op.gate.x_exponent, op.gate.z_exponent
|
|
202
|
+
|
|
203
|
+
values_by_params: dict[sympy.Symbol, tuple[float, ...]] = {}
|
|
204
|
+
for mid, moment in enumerate(symbolized_circuit):
|
|
205
|
+
for op in moment.operations:
|
|
206
|
+
if op.gate and isinstance(op.gate, ops.PhasedXZGate) and protocols.is_parameterized(op):
|
|
207
|
+
sa, sx, sz = op.gate.axis_phase_exponent, op.gate.x_exponent, op.gate.z_exponent
|
|
208
|
+
values_by_params[sa], values_by_params[sx], values_by_params[sz] = zip(
|
|
209
|
+
*[_extract_axz(c[mid].operation_at(op.qubits[0])) for c in resolved_circuits]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
return dict_to_zip_sweep(cast(ProductOrZipSweepLike, values_by_params))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def merge_single_qubit_gates_to_phxz_symbolized(
|
|
216
|
+
circuit: cirq.AbstractCircuit,
|
|
217
|
+
*,
|
|
218
|
+
context: cirq.TransformerContext | None = None,
|
|
219
|
+
sweep: Sweep,
|
|
220
|
+
atol: float = 1e-8,
|
|
221
|
+
) -> tuple[cirq.Circuit, Sweep]:
|
|
222
|
+
"""Merges consecutive single qubit gates as PhasedXZ Gates. Symbolizes if any of
|
|
223
|
+
the consecutive gates is symbolized.
|
|
224
|
+
|
|
225
|
+
Example:
|
|
226
|
+
>>> q0, q1 = cirq.LineQubit.range(2)
|
|
227
|
+
>>> c = cirq.Circuit(\
|
|
228
|
+
cirq.X(q0),\
|
|
229
|
+
cirq.CZ(q0,q1)**sympy.Symbol("cz_exp"),\
|
|
230
|
+
cirq.Y(q0)**sympy.Symbol("y_exp"),\
|
|
231
|
+
cirq.X(q0))
|
|
232
|
+
>>> print(c)
|
|
233
|
+
0: ───X───@──────────Y^y_exp───X───
|
|
234
|
+
│
|
|
235
|
+
1: ───────@^cz_exp─────────────────
|
|
236
|
+
>>> new_circuit, new_sweep = cirq.merge_single_qubit_gates_to_phxz_symbolized(\
|
|
237
|
+
c, sweep=cirq.Zip(cirq.Points(key="cz_exp", points=[0, 1]),\
|
|
238
|
+
cirq.Points(key="y_exp", points=[0, 1])))
|
|
239
|
+
>>> print(new_circuit)
|
|
240
|
+
0: ───PhXZ(a=-1,x=1,z=0)───@──────────PhXZ(a=a0,x=x0,z=z0)───
|
|
241
|
+
│
|
|
242
|
+
1: ────────────────────────@^cz_exp──────────────────────────
|
|
243
|
+
>>> assert new_sweep[0] == cirq.ParamResolver({'a0': -1, 'x0': 1, 'z0': 0, 'cz_exp': 0})
|
|
244
|
+
>>> assert new_sweep[1] == cirq.ParamResolver({'a0': -0.5, 'x0': 0, 'z0': -1, 'cz_exp': 1})
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
circuit: Input circuit to transform. It will not be modified.
|
|
248
|
+
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
249
|
+
sweep: Sweep of the symbols in the input circuit. An updated Sweep will be returned
|
|
250
|
+
based on the transformation.
|
|
251
|
+
atol: Absolute tolerance to angle error. Larger values allow more negligible gates to be
|
|
252
|
+
dropped, smaller values increase accuracy.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
Copy of the transformed input circuit.
|
|
256
|
+
"""
|
|
257
|
+
deep = context.deep if context else False
|
|
258
|
+
|
|
259
|
+
# Tag symbolized single-qubit op.
|
|
260
|
+
symbolized_single_tag = "_tmp_symbolize_tag"
|
|
261
|
+
|
|
262
|
+
circuit_tagged = transformer_primitives.map_operations(
|
|
263
|
+
circuit,
|
|
264
|
+
lambda op, _: (
|
|
265
|
+
op.with_tags(symbolized_single_tag)
|
|
266
|
+
if protocols.is_parameterized(op) and len(op.qubits) == 1
|
|
267
|
+
else op
|
|
268
|
+
),
|
|
269
|
+
deep=deep,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Step 0, isolate single qubit symbols and resolve the circuit on them.
|
|
273
|
+
single_qubit_gate_symbols: set[sympy.Symbol] = set().union(
|
|
274
|
+
*[
|
|
275
|
+
protocols.parameter_symbols(op) if symbolized_single_tag in op.tags else set()
|
|
276
|
+
for op in circuit_tagged.all_operations()
|
|
277
|
+
]
|
|
278
|
+
)
|
|
279
|
+
# Remaining symbols, e.g., 2 qubit gates' symbols. Sweep of those symbols keeps unchanged.
|
|
280
|
+
remaining_symbols: set[sympy.Symbol] = set(
|
|
281
|
+
protocols.parameter_symbols(circuit) - single_qubit_gate_symbols
|
|
282
|
+
)
|
|
283
|
+
# If all single qubit gates are not parameterized, call the non-parameterized version of
|
|
284
|
+
# the transformer.
|
|
285
|
+
if not single_qubit_gate_symbols:
|
|
286
|
+
return (merge_single_qubit_gates_to_phxz(circuit, context=context, atol=atol), sweep)
|
|
287
|
+
sweep_of_single: Sweep = _sweep_on_symbols(sweep, single_qubit_gate_symbols)
|
|
288
|
+
# Get all resolved circuits from all sets of resolvers in sweep_of_single.
|
|
289
|
+
resolved_circuits = [
|
|
290
|
+
protocols.resolve_parameters(circuit_tagged, resolver) for resolver in sweep_of_single
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
# Step 1, merge single qubit gates per resolved circuit, preserving
|
|
294
|
+
# the symbolized_single_tag to indicate the operator is a merged one.
|
|
295
|
+
merged_circuits: list[cirq.Circuit] = [
|
|
296
|
+
merge_single_qubit_gates_to_phxz(
|
|
297
|
+
c,
|
|
298
|
+
context=context,
|
|
299
|
+
merge_tags_fn=lambda circuit_op: (
|
|
300
|
+
[symbolized_single_tag]
|
|
301
|
+
if any(
|
|
302
|
+
symbolized_single_tag in set(op.tags)
|
|
303
|
+
for op in circuit_op.circuit.all_operations()
|
|
304
|
+
)
|
|
305
|
+
else []
|
|
306
|
+
),
|
|
307
|
+
atol=atol,
|
|
308
|
+
)
|
|
309
|
+
for c in resolved_circuits
|
|
310
|
+
]
|
|
311
|
+
|
|
312
|
+
# Step 2, get the new symbolized circuit by symbolizing on indexed symbolized_single_tag.
|
|
313
|
+
new_circuit = tag_transformers.remove_tags( # remove the temp tags used to track merges
|
|
314
|
+
symbolize.symbolize_single_qubit_gates_by_indexed_tags(
|
|
315
|
+
tag_transformers.index_tags( # index all 1-qubit-ops merged from ops with symbols
|
|
316
|
+
merged_circuits[0],
|
|
317
|
+
context=transformer_api.TransformerContext(deep=deep),
|
|
318
|
+
target_tags={symbolized_single_tag},
|
|
319
|
+
),
|
|
320
|
+
symbolize_tag=symbolize.SymbolizeTag(prefix=symbolized_single_tag),
|
|
321
|
+
),
|
|
322
|
+
remove_if=lambda tag: str(tag).startswith(symbolized_single_tag),
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Step 3, get N sets of parameterizations as new_sweep.
|
|
326
|
+
new_sweep = Zip(
|
|
327
|
+
_calc_phxz_sweeps(new_circuit, merged_circuits), # phxz sweeps
|
|
328
|
+
_sweep_on_symbols(sweep, remaining_symbols), # remaining sweeps
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
return align.align_right(new_circuit), new_sweep
|